[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