Commit f2674431 authored by Cyrill Gorcunov's avatar Cyrill Gorcunov Committed by Pavel Emelyanov

vdso: Implement vdso proxy on restore

When a task being restored we may meet two situations

 - vdso in image doesn't match the runtime vdso provided
   by a kernel. For this case we need to patch dumpee
   vdso redirecting calls to runtime vdso, thus dumpee
   vdso become a proxy.

 - vdso in image does match the runtime vdso, in this
   case we simply remap runtime vdso to address where
   dumpee vdso lives. Plain remapping here is quite
   important and allows us to save vdso pfn which will
   be used in parasite code later.

Note after this patch the restored task may have two
vdso in memory. Proper dumping of such situation will
be addressed in future patches.
Signed-off-by: 's avatarCyrill Gorcunov <gorcunov@openvz.org>
Signed-off-by: 's avatarPavel Emelyanov <xemul@parallels.com>
parent b051c66f
...@@ -5,8 +5,12 @@ ...@@ -5,8 +5,12 @@
struct vdso_symtable; struct vdso_symtable;
struct _VmaEntry;
typedef struct _VmaEntry VmaEntry;
extern int vdso_redirect_calls(void *base_to, void *base_from, struct vdso_symtable *to, struct vdso_symtable *from); extern int vdso_redirect_calls(void *base_to, void *base_from, struct vdso_symtable *to, struct vdso_symtable *from);
extern int vdso_fill_symtable(char *mem, size_t size,struct vdso_symtable *t); extern int vdso_fill_symtable(char *mem, size_t size,struct vdso_symtable *t);
extern int vdso_remap(char *who, unsigned long from, unsigned long to, size_t size); extern int vdso_remap(char *who, unsigned long from, unsigned long to, size_t size);
extern int vdso_proxify(char *who, struct vdso_symtable *sym_rt, VmaEntry *vma_entry, unsigned long vdso_rt_parked_at);
#endif /* __CR_ASM_VDSO_H__ */ #endif /* __CR_ASM_VDSO_H__ */
...@@ -24,3 +24,8 @@ int vdso_remap(char *who, unsigned long from, unsigned long to, size_t size) ...@@ -24,3 +24,8 @@ int vdso_remap(char *who, unsigned long from, unsigned long to, size_t size)
{ {
return 0; return 0;
} }
int vdso_proxify(char *who, struct vdso_symtable *sym_rt, VmaEntry *vma, unsigned long vdso_rt_parked_at)
{
return 0;
}
...@@ -5,8 +5,12 @@ ...@@ -5,8 +5,12 @@
struct vdso_symtable; struct vdso_symtable;
struct _VmaEntry;
typedef struct _VmaEntry VmaEntry;
extern int vdso_redirect_calls(void *base_to, void *base_from, struct vdso_symtable *to, struct vdso_symtable *from); extern int vdso_redirect_calls(void *base_to, void *base_from, struct vdso_symtable *to, struct vdso_symtable *from);
extern int vdso_fill_symtable(char *mem, size_t size,struct vdso_symtable *t); extern int vdso_fill_symtable(char *mem, size_t size,struct vdso_symtable *t);
extern int vdso_remap(char *who, unsigned long from, unsigned long to, size_t size); extern int vdso_remap(char *who, unsigned long from, unsigned long to, size_t size);
extern int vdso_proxify(char *who, struct vdso_symtable *sym_rt, VmaEntry *vma_entry, unsigned long vdso_rt_parked_at);
#endif /* __CR_ASM_VDSO_H__ */ #endif /* __CR_ASM_VDSO_H__ */
...@@ -240,3 +240,62 @@ int vdso_remap(char *who, unsigned long from, unsigned long to, size_t size) ...@@ -240,3 +240,62 @@ int vdso_remap(char *who, unsigned long from, unsigned long to, size_t size)
return 0; return 0;
} }
int vdso_proxify(char *who, struct vdso_symtable *sym_rt, VmaEntry *vma, unsigned long vdso_rt_parked_at)
{
struct vdso_symtable s = VDSO_SYMTABLE_INIT;
size_t size = vma_entry_len(vma);
bool remap_rt = true;
unsigned int i;
/*
* Find symbols in dumpee vdso.
*/
if (vdso_fill_symtable((void *)vma->start, size, &s))
return -1;
if (size == vdso_vma_size(sym_rt)) {
for (i = 0; i < ARRAY_SIZE(s.symbols); i++) {
if (s.symbols[i].offset != sym_rt->symbols[i].offset) {
remap_rt = false;
break;
}
}
} else
remap_rt = false;
/*
* Easy case -- the vdso from image has same offsets and size
* as runtime, so we simply remap runtime vdso to dumpee position
* without generating any proxy.
*/
if (remap_rt) {
pr_debug("Runtime vdso matches dumpee, remap inplace\n");
if (sys_munmap((void *)vma->start, size)) {
pr_err("Failed to unmap %s\n", who);
return -1;
}
if (vdso_remap(who, vdso_rt_parked_at,
vma->start, size))
return -1;
return 0;
}
/*
* Now complex case -- we need to proxify calls. We redirect
* calls from dumpee vdso to runtime vdso, making dumpee
* to operate as proxy vdso.
*/
pr_debug("Runtime vdso mismatches dumpee, generate proxy\n");
if (vdso_redirect_calls((void *)vdso_rt_parked_at,
(void *)vma->start,
sym_rt, &s)) {
pr_err("Failed to proxify dumpee contents\n");
return -1;
}
return 0;
}
...@@ -584,6 +584,12 @@ long __export_restore_task(struct task_restore_core_args *args) ...@@ -584,6 +584,12 @@ long __export_restore_task(struct task_restore_core_args *args)
if (vma_remap(vma_premmaped_start(vma_entry), if (vma_remap(vma_premmaped_start(vma_entry),
vma_entry->start, vma_entry_len(vma_entry))) vma_entry->start, vma_entry_len(vma_entry)))
goto core_restore_end; goto core_restore_end;
if (vma_entry_is(vma_entry, VMA_AREA_VDSO)) {
if (vdso_proxify("left dumpee", &args->vdso_sym_rt,
vma_entry, args->vdso_rt_parked_at))
goto core_restore_end;
}
} }
/* Shift private vma-s to the right */ /* Shift private vma-s to the right */
...@@ -604,6 +610,12 @@ long __export_restore_task(struct task_restore_core_args *args) ...@@ -604,6 +610,12 @@ long __export_restore_task(struct task_restore_core_args *args)
if (vma_remap(vma_premmaped_start(vma_entry), if (vma_remap(vma_premmaped_start(vma_entry),
vma_entry->start, vma_entry_len(vma_entry))) vma_entry->start, vma_entry_len(vma_entry)))
goto core_restore_end; goto core_restore_end;
if (vma_entry_is(vma_entry, VMA_AREA_VDSO)) {
if (vdso_proxify("right dumpee", &args->vdso_sym_rt,
vma_entry, args->vdso_rt_parked_at))
goto core_restore_end;
}
} }
/* /*
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment