[CRIU] [PATCH] ptrace: say to parasite_stop_on_syscall where is we now
Andrew Vagin
avagin at openvz.org
Fri Sep 19 12:08:44 PDT 2014
On restore parasite_stop_on_syscall() can be called after PTRACE_SYSCALL
and after a breakpoint. parasite_stop_on_syscall() must be called only
after PTRACE_SYSCALL, so all tests where is one process stuck.
Reported-by: Mr Jenkins
Signed-off-by: Andrew Vagin <avagin at openvz.org>
---
cr-restore.c | 19 +++++++++++++------
include/parasite-syscall.h | 14 +++++++++++++-
parasite-syscall.c | 46 ++++++++++++++++------------------------------
3 files changed, 42 insertions(+), 37 deletions(-)
diff --git a/cr-restore.c b/cr-restore.c
index 954e817..809564b 100644
--- a/cr-restore.c
+++ b/cr-restore.c
@@ -1540,7 +1540,7 @@ static int restore_switch_stage(int next_stage)
return restore_wait_inprogress_tasks();
}
-static int attach_to_tasks(bool root_seized)
+static int attach_to_tasks(bool root_seized, enum trace_flags *flag)
{
struct pstree_item *item;
@@ -1584,9 +1584,14 @@ static int attach_to_tasks(bool root_seized)
return -1;
/* A breakpoint was not set */
- if (ret == 0 && ptrace(PTRACE_SYSCALL, pid, NULL, NULL)) {
- pr_perror("Unable to start %d", pid);
- return -1;
+ if (ret > 0)
+ *flag = TRACE_EXIT;
+ else {
+ *flag = TRACE_ENTER;
+ if (ptrace(PTRACE_SYSCALL, pid, NULL, NULL)) {
+ pr_perror("Unable to start %d", pid);
+ return -1;
+ }
}
}
}
@@ -1644,6 +1649,7 @@ static void ignore_kids(void)
static int restore_root_task(struct pstree_item *init)
{
+ enum trace_flags flag = TRACE_ALL;
int ret, fd;
fd = open("/proc", O_DIRECTORY | O_RDONLY);
@@ -1760,13 +1766,14 @@ static int restore_root_task(struct pstree_item *init)
timing_stop(TIME_RESTORE);
- ret = attach_to_tasks(root_as_sibling);
+ ret = attach_to_tasks(root_as_sibling, &flag);
pr_info("Restore finished successfully. Resuming tasks.\n");
futex_set_and_wake(&task_entries->start, CR_STATE_COMPLETE);
if (ret == 0)
- ret = parasite_stop_on_syscall(task_entries->nr_threads, __NR_rt_sigreturn);
+ ret = parasite_stop_on_syscall(task_entries->nr_threads,
+ __NR_rt_sigreturn, flag);
/*
* finalize_restore() always detaches from processes and
diff --git a/include/parasite-syscall.h b/include/parasite-syscall.h
index fbc5614..5d2df08 100644
--- a/include/parasite-syscall.h
+++ b/include/parasite-syscall.h
@@ -125,7 +125,19 @@ extern int parasite_fixup_vdso(struct parasite_ctl *ctl, pid_t pid,
struct vm_area_list *vma_area_list);
#endif
-extern int parasite_stop_on_syscall(int tasks, int sys_nr);
+/*
+ * The PTRACE_SYSCALL will trap task twice -- on
+ * enter into and on exit from syscall. If we trace
+ * a single task, we may skip half of all getregs
+ * calls -- on exit we don't need them.
+ */
+enum trace_flags {
+ TRACE_ALL,
+ TRACE_ENTER,
+ TRACE_EXIT,
+};
+
+extern int parasite_stop_on_syscall(int tasks, int sys_nr, enum trace_flags trace);
extern int parasite_unmap(struct parasite_ctl *ctl, unsigned long addr);
#endif /* __CR_PARASITE_SYSCALL_H__ */
diff --git a/parasite-syscall.c b/parasite-syscall.c
index 88c9d42..37e9db0 100644
--- a/parasite-syscall.c
+++ b/parasite-syscall.c
@@ -827,6 +827,7 @@ static int parasite_fini_seized(struct parasite_ctl *ctl)
pid_t pid = ctl->pid.real;
user_regs_struct_t regs;
int status, ret = 0;
+ enum trace_flags flag;
/* stop getting chld from parasite -- we're about to step-by-step it */
if (restore_child_handler())
@@ -873,27 +874,20 @@ static int parasite_fini_seized(struct parasite_ctl *ctl)
ret = ptrace_set_breakpoint(pid, ctl->sigreturn_addr);
if (ret < 0)
return ret;
- if (ret > 0) {
- pid = wait4(pid, &status, __WALL, NULL);
- if (pid == -1) {
- pr_perror("wait4 failed");
- return -1;
- }
-
- if (!WIFSTOPPED(status) || WSTOPSIG(status) != SIGTRAP) {
- pr_err("Task is in unexpected state: %x\n", status);
- return -1;
+ if (ret > 0)
+ flag = TRACE_EXIT;
+ else {
+ /* Start tracing syscalls */
+ ret = ptrace(PTRACE_SYSCALL, pid, NULL, NULL);
+ if (ret) {
+ pr_perror("ptrace");
+ return -1;
}
- }
- /* Start tracing syscalls */
- ret = ptrace(PTRACE_SYSCALL, pid, NULL, NULL);
- if (ret) {
- pr_perror("ptrace");
- return -1;
+ flag = TRACE_ENTER;
}
- if (parasite_stop_on_syscall(1, __NR_rt_sigreturn))
+ if (parasite_stop_on_syscall(1, __NR_rt_sigreturn, flag))
return -1;
/*
@@ -905,28 +899,20 @@ static int parasite_fini_seized(struct parasite_ctl *ctl)
return 0;
}
-#define TRACE_ALL 1
-#define TRACE_ENTER 2
-#define TRACE_EXIT 3
-
/*
* Trap tasks on the exit from the specified syscall
*
* tasks - number of processes, which should be trapped
* sys_nr - the required syscall number
*/
-int parasite_stop_on_syscall(int tasks, const int sys_nr)
+int parasite_stop_on_syscall(int tasks, const int sys_nr, enum trace_flags trace)
{
user_regs_struct_t regs;
int status, ret;
pid_t pid;
- /*
- * The PTRACE_SYSCALL will trap task twice -- on
- * enter into and on exit from syscall. If we trace
- * a single task, we may skip half of all getregs
- * calls -- on exit we don't need them.
- */
- int trace = (tasks == 1 ? TRACE_ENTER : TRACE_ALL);
+
+ if (tasks > 1)
+ trace = TRACE_ALL;
/* Stop all threads on the enter point in sys_rt_sigreturn */
while (tasks) {
@@ -1061,7 +1047,7 @@ int parasite_unmap(struct parasite_ctl *ctl, unsigned long addr)
if (ret)
goto err;
- ret = parasite_stop_on_syscall(1, __NR_munmap);
+ ret = parasite_stop_on_syscall(1, __NR_munmap, TRACE_ENTER);
if (restore_thread_ctx(pid, &ctl->orig))
ret = -1;
--
1.9.3
More information about the CRIU
mailing list