[CRIU] [PATCH 3/4] ptrace: split task_seize into seize_catch_task and seize_wait_task

Andrey Vagin avagin at openvz.org
Thu Aug 6 02:37:27 PDT 2015


It's preparation to use a freezer cgroup for freezing tasks.

Signed-off-by: Andrey Vagin <avagin at openvz.org>
---
 cr-exec.c        |  5 +++-
 include/ptrace.h |  3 ++-
 ptrace.c         | 69 ++++++++++++++++++++++++++++++++------------------------
 seize.c          | 16 ++++++++++---
 4 files changed, 59 insertions(+), 34 deletions(-)

diff --git a/cr-exec.c b/cr-exec.c
index f3d55f6..8beb80f 100644
--- a/cr-exec.c
+++ b/cr-exec.c
@@ -130,7 +130,10 @@ int cr_exec(int pid, char **opt)
 		goto out;
 	}
 
-	prev_state = ret = seize_task(pid, -1, &creds);
+	if (seize_catch_task(pid))
+		goto out;
+
+	prev_state = ret = seize_wait_task(pid, -1, &creds);
 	if (ret < 0) {
 		pr_err("Can't seize task %d\n", pid);
 		goto out;
diff --git a/include/ptrace.h b/include/ptrace.h
index 44b66c9..079ad63 100644
--- a/include/ptrace.h
+++ b/include/ptrace.h
@@ -67,7 +67,8 @@ struct ptrace_peeksiginfo_args {
 
 #define SI_EVENT(_si_code)	(((_si_code) & 0xFFFF) >> 8)
 
-extern int seize_task(pid_t pid, pid_t ppid, struct proc_status_creds **creds);
+extern int seize_catch_task(pid_t pid);
+extern int seize_wait_task(pid_t pid, pid_t ppid, struct proc_status_creds **creds);
 extern int suspend_seccomp(pid_t pid);
 extern int unseize_task(pid_t pid, int orig_state, int state);
 extern int ptrace_peek_area(pid_t pid, void *dst, void *addr, long bytes);
diff --git a/ptrace.c b/ptrace.c
index 905eaec..a302e56 100644
--- a/ptrace.c
+++ b/ptrace.c
@@ -52,6 +52,39 @@ int suspend_seccomp(pid_t pid)
 	return 0;
 }
 
+int seize_catch_task(pid)
+{
+	int ret;
+
+	ret = ptrace(PTRACE_SEIZE, pid, NULL, 0);
+	if (ret) {
+		/*
+		 * ptrace API doesn't allow to distinguish
+		 * attaching to zombie from other errors.
+		 * All errors will be handled in seize_wait_task().
+		 */
+		pr_warn("Unable to interrupt task: %d (%s)\n", pid, strerror(errno));
+		return ret;
+	}
+
+	/*
+	 * If we SEIZE-d the task stop it before going
+	 * and reading its stat from proc. Otherwise task
+	 * may die _while_ we're doing it and we'll have
+	 * inconsistent seize/state pair.
+	 *
+	 * If task dies after we seize it but before we
+	 * do this interrupt, we'll notice it via proc.
+	 */
+	ret = ptrace(PTRACE_INTERRUPT, pid, NULL, NULL);
+	if (ret < 0) {
+		pr_warn("SEIZE %d: can't interrupt task: %s", pid, strerror(errno));
+		ptrace(PTRACE_DETACH, pid, NULL, NULL);
+	}
+
+	return ret;
+}
+
 /*
  * This routine seizes task putting it into a special
  * state where we can manipulate the task via ptrace
@@ -59,12 +92,11 @@ int suspend_seccomp(pid_t pid)
  * of it so the task would not know if it was saddled
  * up with someone else.
  */
-
-int seize_task(pid_t pid, pid_t ppid, struct proc_status_creds **creds)
+int seize_wait_task(pid_t pid, pid_t ppid, struct proc_status_creds **creds)
 {
 	siginfo_t si;
 	int status;
-	int ret, ret2, ptrace_errno, wait_errno = 0;
+	int ret = 0, ret2, wait_errno = 0;
 	struct proc_status_creds cr;
 
 	/*
@@ -72,26 +104,6 @@ int seize_task(pid_t pid, pid_t ppid, struct proc_status_creds **creds)
 	 */
 	memzero(&cr, sizeof(struct proc_status_creds));
 
-	ret = ptrace(PTRACE_SEIZE, pid, NULL, 0);
-	ptrace_errno = errno;
-	if (ret == 0) {
-		/*
-		 * If we SEIZE-d the task stop it before going
-		 * and reading its stat from proc. Otherwise task
-		 * may die _while_ we're doing it and we'll have
-		 * inconsistent seize/state pair.
-		 *
-		 * If task dies after we seize it but before we
-		 * do this interrupt, we'll notice it via proc.
-		 */
-		ret = ptrace(PTRACE_INTERRUPT, pid, NULL, NULL);
-		if (ret < 0) {
-			pr_perror("SEIZE %d: can't interrupt task", pid);
-			ptrace(PTRACE_DETACH, pid, NULL, NULL);
-			goto err;
-		}
-	}
-
 	/*
 	 * It's ugly, but the ptrace API doesn't allow to distinguish
 	 * attaching to zombie from other errors. Thus we have to parse
@@ -100,10 +112,9 @@ int seize_task(pid_t pid, pid_t ppid, struct proc_status_creds **creds)
 	 */
 
 try_again:
-	if (!ret) {
-		ret = wait4(pid, &status, __WALL, NULL);
-		wait_errno = errno;
-	}
+
+	ret = wait4(pid, &status, __WALL, NULL);
+	wait_errno = errno;
 
 	ret2 = parse_pid_status(pid, &cr);
 	if (ret2)
@@ -119,8 +130,8 @@ try_again:
 			if (pid == getpid())
 				pr_err("The criu itself is within dumped tree.\n");
 			else
-				pr_err("Unseizable non-zombie %d found, state %c, err %d/%d/%d\n",
-						pid, cr.state, ret, ptrace_errno, wait_errno);
+				pr_err("Unseizable non-zombie %d found, state %c, err %d/%d\n",
+						pid, cr.state, ret, wait_errno);
 			return -1;
 		}
 
diff --git a/seize.c b/seize.c
index e9be332..86df3f0 100644
--- a/seize.c
+++ b/seize.c
@@ -58,7 +58,10 @@ static int collect_children(struct pstree_item *item)
 			goto free;
 		}
 
-		ret = seize_task(pid, item->pid.real, &dmpi(c)->pi_creds);
+		/* fails when meets a zombie */
+		seize_catch_task(pid);
+
+		ret = seize_wait_task(pid, item->pid.real, &dmpi(c)->pi_creds);
 		if (ret < 0) {
 			/*
 			 * Here is a race window between parse_children() and seize(),
@@ -207,7 +210,10 @@ static int collect_threads(struct pstree_item *item)
 		pr_info("\tSeizing %d's %d thread\n",
 				item->pid.real, pid);
 
-		ret = seize_task(pid, item_ppid(item), &dmpi(item)->pi_creds);
+		if (seize_catch_task(pid))
+			continue;
+
+		ret = seize_wait_task(pid, item_ppid(item), &dmpi(item)->pi_creds);
 		if (ret < 0) {
 			/*
 			 * Here is a race window between parse_threads() and seize(),
@@ -316,7 +322,11 @@ int collect_pstree(pid_t pid)
 		return -1;
 
 	root_item->pid.real = pid;
-	ret = seize_task(pid, -1, &dmpi(root_item)->pi_creds);
+
+	if (seize_catch_task(pid))
+		goto err;
+
+	ret = seize_wait_task(pid, -1, &dmpi(root_item)->pi_creds);
 	if (ret < 0)
 		goto err;
 	pr_info("Seized task %d, state %d\n", pid, ret);
-- 
2.1.0



More information about the CRIU mailing list