mirror of
https://github.com/checkpoint-restore/criu.git
synced 2026-07-21 17:20:19 +00:00
vdso: Escape double dumping of rt-vdso if proxy present
In case if we have created vdso proxy the rt-vdso should not be dumped because it will be re-created on next restore anyway. Thus with help of parasite service routine find the rt-vdso and tear it off from VMAs list. Signed-off-by: Cyrill Gorcunov <gorcunov@openvz.org> Signed-off-by: Pavel Emelyanov <xemul@parallels.com>
This commit is contained in:
parent
528106a5dc
commit
0ae67a7743
6 changed files with 164 additions and 0 deletions
|
|
@ -61,6 +61,7 @@
|
|||
#include "kerndat.h"
|
||||
#include "stats.h"
|
||||
#include "mem.h"
|
||||
#include "vdso.h"
|
||||
#include "page-pipe.h"
|
||||
#include "vdso.h"
|
||||
|
||||
|
|
@ -1484,6 +1485,12 @@ static int dump_one_task(struct pstree_item *item)
|
|||
}
|
||||
}
|
||||
|
||||
ret = parasite_fixup_vdso(parasite_ctl, pid, &vmas);
|
||||
if (ret) {
|
||||
pr_err("Can't fixup vdso VMAs (pid: %d)\n", pid);
|
||||
goto err_cure_fdset;
|
||||
}
|
||||
|
||||
ret = parasite_dump_misc_seized(parasite_ctl, &misc);
|
||||
if (ret) {
|
||||
pr_err("Can't dump misc (pid: %d)\n", pid);
|
||||
|
|
|
|||
|
|
@ -84,4 +84,7 @@ int syscall_seized(struct parasite_ctl *ctl, int nr, unsigned long *ret,
|
|||
extern int __parasite_execute(struct parasite_ctl *ctl, pid_t pid, user_regs_struct_t *regs);
|
||||
extern bool arch_can_dump_task(pid_t pid);
|
||||
|
||||
extern int parasite_fixup_vdso(struct parasite_ctl *ctl, pid_t pid,
|
||||
struct vm_area_list *vma_area_list);
|
||||
|
||||
#endif /* __CR_PARASITE_SYSCALL_H__ */
|
||||
|
|
|
|||
|
|
@ -35,6 +35,7 @@ enum {
|
|||
PARASITE_CMD_DRAIN_FDS,
|
||||
PARASITE_CMD_GET_PROC_FD,
|
||||
PARASITE_CMD_DUMP_TTY,
|
||||
PARASITE_CMD_CHECK_VDSO_MARK,
|
||||
|
||||
PARASITE_CMD_MAX,
|
||||
};
|
||||
|
|
@ -60,6 +61,13 @@ struct parasite_vma_entry
|
|||
int prot;
|
||||
};
|
||||
|
||||
struct parasite_vdso_vma_entry {
|
||||
unsigned long start;
|
||||
unsigned long len;
|
||||
unsigned long proxy_addr;
|
||||
int is_marked;
|
||||
};
|
||||
|
||||
struct parasite_dump_pages_args {
|
||||
unsigned int nr_vmas;
|
||||
unsigned int add_prot;
|
||||
|
|
|
|||
|
|
@ -99,6 +99,13 @@ struct vdso_mark {
|
|||
#define INIT_VDSO_MARK(m) \
|
||||
*(m) = (struct vdso_mark)VDSO_MARK_INIT
|
||||
|
||||
static inline bool is_vdso_mark(void *addr)
|
||||
{
|
||||
struct vdso_mark *m = addr;
|
||||
|
||||
return m->signature == VDSO_MARK_SIGNATURE &&
|
||||
m->proxy_addr != VDSO_BAD_ADDR;
|
||||
}
|
||||
|
||||
extern struct vdso_symtable vdso_sym_rt;
|
||||
extern u64 vdso_pfn;
|
||||
|
|
|
|||
|
|
@ -20,9 +20,11 @@
|
|||
#include "parasite.h"
|
||||
#include "crtools.h"
|
||||
#include "namespaces.h"
|
||||
#include "kerndat.h"
|
||||
#include "pstree.h"
|
||||
#include "net.h"
|
||||
#include "mem.h"
|
||||
#include "vdso.h"
|
||||
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
|
|
@ -511,6 +513,125 @@ err:
|
|||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* Find out proxy vdso vma and drop it from the list. Also
|
||||
* fix vdso status on vmas if wrong status found.
|
||||
*/
|
||||
int parasite_fixup_vdso(struct parasite_ctl *ctl, pid_t pid,
|
||||
struct vm_area_list *vma_area_list)
|
||||
{
|
||||
unsigned long proxy_addr = VDSO_BAD_ADDR;
|
||||
struct parasite_vdso_vma_entry *args;
|
||||
struct vma_area *marked = NULL;
|
||||
struct vma_area *vma;
|
||||
int fd, ret = -1;
|
||||
off_t off;
|
||||
u64 pfn;
|
||||
|
||||
args = parasite_args(ctl, struct parasite_vdso_vma_entry);
|
||||
fd = open_proc(pid, "pagemap");
|
||||
if (fd < 0)
|
||||
return -1;
|
||||
|
||||
list_for_each_entry(vma, &vma_area_list->h, list) {
|
||||
if (!vma_area_is(vma, VMA_AREA_REGULAR))
|
||||
continue;
|
||||
|
||||
if ((vma->vma.prot & VDSO_PROT) != VDSO_PROT)
|
||||
continue;
|
||||
|
||||
/*
|
||||
* I need to poke every potentially marked vma,
|
||||
* otherwise if task never called for vdso functions
|
||||
* page frame number won't be reported.
|
||||
*/
|
||||
args->start = vma->vma.start;
|
||||
args->len = vma_area_len(vma);
|
||||
|
||||
if (parasite_execute(PARASITE_CMD_CHECK_VDSO_MARK, ctl)) {
|
||||
pr_err("vdso: Parasite failed to poke for mark\n");
|
||||
ret = -1;
|
||||
goto err;
|
||||
}
|
||||
|
||||
off = (vma->vma.start / PAGE_SIZE) * sizeof(u64);
|
||||
if (lseek(fd, off, SEEK_SET) != off) {
|
||||
pr_perror("Failed to seek address %lx\n", vma->vma.start);
|
||||
ret = -1;
|
||||
goto err;
|
||||
}
|
||||
|
||||
ret = read(fd, &pfn, sizeof(pfn));
|
||||
if (ret < 0 || ret != sizeof(pfn)) {
|
||||
pr_perror("Can't read pme for pid %d", pid);
|
||||
ret = -1;
|
||||
goto err;
|
||||
}
|
||||
|
||||
pfn = PME_PFRAME(pfn);
|
||||
BUG_ON(!pfn);
|
||||
|
||||
/*
|
||||
* Defer handling marked vdso.
|
||||
*/
|
||||
if (unlikely(args->is_marked)) {
|
||||
BUG_ON(args->proxy_addr == VDSO_BAD_ADDR);
|
||||
BUG_ON(marked);
|
||||
marked = vma;
|
||||
proxy_addr = args->proxy_addr;
|
||||
continue;
|
||||
}
|
||||
|
||||
/*
|
||||
* Set proper VMA statuses.
|
||||
*/
|
||||
if (pfn == vdso_pfn) {
|
||||
if (!vma_area_is(vma, VMA_AREA_VDSO)) {
|
||||
pr_debug("vdso: Restore status by pfn at %lx\n",
|
||||
(long)vma->vma.start);
|
||||
vma->vma.status |= VMA_AREA_VDSO;
|
||||
}
|
||||
} else {
|
||||
if (vma_area_is(vma, VMA_AREA_VDSO)) {
|
||||
pr_debug("vdso: Drop mishinted status at %lx\n",
|
||||
(long)vma->vma.start);
|
||||
vma->vma.status &= ~VMA_AREA_VDSO;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* There is marked vdso, it means such vdso is autogenerated
|
||||
* and must be dropped from vma list.
|
||||
*/
|
||||
if (marked) {
|
||||
pr_debug("vdso: Found marked at %lx (proxy at %lx)\n",
|
||||
(long)marked->vma.start, (long)proxy_addr);
|
||||
|
||||
/*
|
||||
* Don't forget to restore the proxy vdso status, since
|
||||
* it's being not recognized by the kernel as vdso.
|
||||
*/
|
||||
list_for_each_entry(vma, &vma_area_list->h, list) {
|
||||
if (vma->vma.start == proxy_addr) {
|
||||
vma->vma.status |= VMA_AREA_REGULAR | VMA_AREA_VDSO;
|
||||
pr_debug("vdso: Restore proxy status at %lx\n",
|
||||
(long)vma->vma.start);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
pr_debug("vdso: Droppping marked vdso at %lx\n",
|
||||
(long)vma->vma.start);
|
||||
list_del(&marked->list);
|
||||
xfree(marked);
|
||||
}
|
||||
ret = 0;
|
||||
err:
|
||||
close(fd);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int parasite_get_proc_fd_seized(struct parasite_ctl *ctl)
|
||||
{
|
||||
int ret = -1, fd;
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@
|
|||
|
||||
#include "syscall.h"
|
||||
#include "parasite.h"
|
||||
#include "vdso.h"
|
||||
#include "log.h"
|
||||
|
||||
#include <string.h>
|
||||
|
|
@ -415,6 +416,21 @@ static int parasite_cfg_log(struct parasite_log_args *args)
|
|||
return ret;
|
||||
}
|
||||
|
||||
static int parasite_check_vdso_mark(struct parasite_vdso_vma_entry *args)
|
||||
{
|
||||
struct vdso_mark *m = (void *)args->start;
|
||||
|
||||
if (is_vdso_mark(m)) {
|
||||
args->is_marked = 1;
|
||||
args->proxy_addr = m->proxy_addr;
|
||||
} else {
|
||||
args->is_marked = 0;
|
||||
args->proxy_addr = VDSO_BAD_ADDR;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int fini(void)
|
||||
{
|
||||
int ret;
|
||||
|
|
@ -463,6 +479,8 @@ int __used parasite_service(unsigned int cmd, void *args)
|
|||
return parasite_get_proc_fd();
|
||||
case PARASITE_CMD_DUMP_TTY:
|
||||
return parasite_dump_tty(args);
|
||||
case PARASITE_CMD_CHECK_VDSO_MARK:
|
||||
return parasite_check_vdso_mark(args);
|
||||
}
|
||||
|
||||
pr_err("Unknown command to parasite: %d\n", cmd);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue