[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