[CRIU] [PATCH RFC] seize: don't wory if a cgroup contains some extra tasks
Pavel Emelyanov
xemul at parallels.com
Thu Oct 29 06:50:49 PDT 2015
On 10/27/2015 07:19 PM, Andrey Vagin wrote:
> From: Andrew Vagin <avagin at openvz.org>
>
> A freezer cgroup can contain tasks which will be not dumped,
> criu unfreezes the group, so we need to freeze all extra
> task with ptrace like we do for target tasks.
>
> Currently we attache and send an interrupt signals to these tasks,
> but we don't call waitpid() for them, so then waitpid(-1, ...)
> returns these tasks where we don't expect to see them.
>
> Signed-off-by: Andrew Vagin <avagin at openvz.org>
> ---
> include/ptrace.h | 2 ++
> ptrace.c | 2 ++
> seize.c | 64 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
> 3 files changed, 68 insertions(+)
>
> diff --git a/include/ptrace.h b/include/ptrace.h
> index 079ad63..a3852ce 100644
> --- a/include/ptrace.h
> +++ b/include/ptrace.h
> @@ -67,6 +67,8 @@ struct ptrace_peeksiginfo_args {
>
> #define SI_EVENT(_si_code) (((_si_code) & 0xFFFF) >> 8)
>
> +extern int frozen_processes;
> +
> 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);
> diff --git a/ptrace.c b/ptrace.c
> index b28824b..922fc87 100644
> --- a/ptrace.c
> +++ b/ptrace.c
> @@ -120,6 +120,8 @@ int seize_wait_task(pid_t pid, pid_t ppid, struct proc_status_creds **creds)
> try_again:
>
> ret = wait4(pid, &status, __WALL, NULL);
> + if (ret > 0)
> + frozen_processes--;
What if we goto try_again() below and wait4 the same task twice?
> wait_errno = errno;
>
> ret2 = parse_pid_status(pid, &cr);
> diff --git a/seize.c b/seize.c
> index 20c0349..e3cd2b4 100644
> --- a/seize.c
> +++ b/seize.c
> @@ -84,6 +84,63 @@ int freeze_cgroup()
> return 0;
> }
>
> +/* A number of tasks in a freezer cgroup which are not going to be dumped */
> +int frozen_processes;
> +
> +/*
> + * A freezer cgroup can contain tasks which will not be dumped
> + * and we need to wait them, because the are interupted them by ptrace.
> + */
> +static int freezer_wait_processes()
> +{
> + int i;
> +
> + for (i = 0; i < frozen_processes; i++) {
> + int status;
> + pid_t pid;
> +
> + /*
> + * Here we are going to skip tasks which are already traced.
> + * Ptraced tasks looks like children for us, so if
> + * a task isn't ptraced yet, waitpid() will return a error.
> + */
> + pid = waitpid(-1, &status, 0);
> + if (pid < 0) {
> + pr_perror("Unable to wait processes");
> + return -1;
> + }
> + pr_warn("Unexpected process %d in the freezer cgroup (status 0x%x)\n", pid, status);
> + }
> +
> + return 0;
> +}
> +
> +static int freezer_detach(void)
> +{
> + char path[PATH_MAX];
> + FILE *f;
> +
> + if (!frozen_processes)
> + return 0;
> +
> + snprintf(path, sizeof(path), "%s/tasks", opts.freeze_cgroup);
> + f = fopen(path, "r");
> + if (f == NULL) {
> + pr_perror("Unable to open %s", path);
> + return -1;
> + }
> + while (fgets(path, sizeof(path), f)) {
> + pid_t pid;
> +
> + pid = atoi(path);
> +
> + if (ptrace(PTRACE_DETACH, pid, NULL, NULL))
> + pr_perror("Unable to detach from %d\n", pid);
Why do we need to manually detach from everybody?
> + }
> + fclose(f);
> + return 0;
> +}
> +
> static int freeze_processes(void)
> {
> int i, ret, fd, exit_code = -1;
> @@ -159,6 +216,7 @@ static int freeze_processes(void)
> fclose(f);
> goto err;
> }
> + frozen_processes++;
Why? Why does the ptrace attach failure result in frozen_processes++?
> }
> fclose(f);
>
> @@ -324,6 +382,9 @@ static void pstree_wait(struct pstree_item *root_item)
> }
> }
> }
> +
> + if (!opts.freeze_cgroup)
> + freezer_detach();
> pid = wait4(-1, &status, __WALL, NULL);
> if (pid > 0) {
> pr_err("Unexpected child %d\n", pid);
> @@ -536,6 +597,9 @@ int collect_pstree(pid_t pid)
> if (ret < 0)
> goto err;
>
> + if (opts.freeze_cgroup && freezer_wait_processes())
> + return -1;
> +
> timing_stop(TIME_FREEZING);
> timing_start(TIME_FROZEN);
>
>
More information about the CRIU
mailing list