mirror of
https://github.com/checkpoint-restore/criu
synced 2025-08-22 09:58:09 +00:00
ptrace: split task_seize into seize_catch_task and seize_wait_task
It's preparation to use a freezer cgroup for freezing tasks. Signed-off-by: Andrey Vagin <avagin@openvz.org> Signed-off-by: Pavel Emelyanov <xemul@parallels.com>
This commit is contained in:
parent
46e8aeed12
commit
b9b0730cb1
@ -130,7 +130,10 @@ int cr_exec(int pid, char **opt)
|
|||||||
goto out;
|
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) {
|
if (ret < 0) {
|
||||||
pr_err("Can't seize task %d\n", pid);
|
pr_err("Can't seize task %d\n", pid);
|
||||||
goto out;
|
goto out;
|
||||||
|
@ -67,7 +67,8 @@ struct ptrace_peeksiginfo_args {
|
|||||||
|
|
||||||
#define SI_EVENT(_si_code) (((_si_code) & 0xFFFF) >> 8)
|
#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 suspend_seccomp(pid_t pid);
|
||||||
extern int unseize_task(pid_t pid, int orig_state, int state);
|
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);
|
extern int ptrace_peek_area(pid_t pid, void *dst, void *addr, long bytes);
|
||||||
|
65
ptrace.c
65
ptrace.c
@ -52,29 +52,21 @@ int suspend_seccomp(pid_t pid)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
int seize_catch_task(pid)
|
||||||
* This routine seizes task putting it into a special
|
|
||||||
* state where we can manipulate the task via ptrace
|
|
||||||
* interface, and finally we can detach ptrace out of
|
|
||||||
* 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)
|
|
||||||
{
|
{
|
||||||
siginfo_t si;
|
int ret;
|
||||||
int status;
|
|
||||||
int ret, ret2, ptrace_errno, wait_errno = 0;
|
|
||||||
struct proc_status_creds cr;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* For the comparison below, let's zero out any padding.
|
|
||||||
*/
|
|
||||||
memzero(&cr, sizeof(struct proc_status_creds));
|
|
||||||
|
|
||||||
ret = ptrace(PTRACE_SEIZE, pid, NULL, 0);
|
ret = ptrace(PTRACE_SEIZE, pid, NULL, 0);
|
||||||
ptrace_errno = errno;
|
if (ret) {
|
||||||
if (ret == 0) {
|
/*
|
||||||
|
* 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
|
* If we SEIZE-d the task stop it before going
|
||||||
* and reading its stat from proc. Otherwise task
|
* and reading its stat from proc. Otherwise task
|
||||||
@ -86,12 +78,32 @@ int seize_task(pid_t pid, pid_t ppid, struct proc_status_creds **creds)
|
|||||||
*/
|
*/
|
||||||
ret = ptrace(PTRACE_INTERRUPT, pid, NULL, NULL);
|
ret = ptrace(PTRACE_INTERRUPT, pid, NULL, NULL);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
pr_perror("SEIZE %d: can't interrupt task", pid);
|
pr_warn("SEIZE %d: can't interrupt task: %s", pid, strerror(errno));
|
||||||
ptrace(PTRACE_DETACH, pid, NULL, NULL);
|
ptrace(PTRACE_DETACH, pid, NULL, NULL);
|
||||||
goto err;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This routine seizes task putting it into a special
|
||||||
|
* state where we can manipulate the task via ptrace
|
||||||
|
* interface, and finally we can detach ptrace out of
|
||||||
|
* of it so the task would not know if it was saddled
|
||||||
|
* up with someone else.
|
||||||
|
*/
|
||||||
|
int seize_wait_task(pid_t pid, pid_t ppid, struct proc_status_creds **creds)
|
||||||
|
{
|
||||||
|
siginfo_t si;
|
||||||
|
int status;
|
||||||
|
int ret = 0, ret2, wait_errno = 0;
|
||||||
|
struct proc_status_creds cr;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* For the comparison below, let's zero out any padding.
|
||||||
|
*/
|
||||||
|
memzero(&cr, sizeof(struct proc_status_creds));
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* It's ugly, but the ptrace API doesn't allow to distinguish
|
* It's ugly, but the ptrace API doesn't allow to distinguish
|
||||||
* attaching to zombie from other errors. Thus we have to parse
|
* 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:
|
try_again:
|
||||||
if (!ret) {
|
|
||||||
ret = wait4(pid, &status, __WALL, NULL);
|
ret = wait4(pid, &status, __WALL, NULL);
|
||||||
wait_errno = errno;
|
wait_errno = errno;
|
||||||
}
|
|
||||||
|
|
||||||
ret2 = parse_pid_status(pid, &cr);
|
ret2 = parse_pid_status(pid, &cr);
|
||||||
if (ret2)
|
if (ret2)
|
||||||
@ -119,8 +130,8 @@ try_again:
|
|||||||
if (pid == getpid())
|
if (pid == getpid())
|
||||||
pr_err("The criu itself is within dumped tree.\n");
|
pr_err("The criu itself is within dumped tree.\n");
|
||||||
else
|
else
|
||||||
pr_err("Unseizable non-zombie %d found, state %c, err %d/%d/%d\n",
|
pr_err("Unseizable non-zombie %d found, state %c, err %d/%d\n",
|
||||||
pid, cr.state, ret, ptrace_errno, wait_errno);
|
pid, cr.state, ret, wait_errno);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
16
seize.c
16
seize.c
@ -58,7 +58,10 @@ static int collect_children(struct pstree_item *item)
|
|||||||
goto free;
|
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) {
|
if (ret < 0) {
|
||||||
/*
|
/*
|
||||||
* Here is a race window between parse_children() and seize(),
|
* 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",
|
pr_info("\tSeizing %d's %d thread\n",
|
||||||
item->pid.real, pid);
|
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) {
|
if (ret < 0) {
|
||||||
/*
|
/*
|
||||||
* Here is a race window between parse_threads() and seize(),
|
* Here is a race window between parse_threads() and seize(),
|
||||||
@ -316,7 +322,11 @@ int collect_pstree(pid_t pid)
|
|||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
root_item->pid.real = pid;
|
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)
|
if (ret < 0)
|
||||||
goto err;
|
goto err;
|
||||||
pr_info("Seized task %d, state %d\n", pid, ret);
|
pr_info("Seized task %d, state %d\n", pid, ret);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user