Commit eb9a6f20 authored by Andrey Vagin's avatar Andrey Vagin Committed by Pavel Emelyanov

restore: add interface for creating helper tasks (v3)

They will be used for restoring sid. For example, if a session
group leader is absent, a helper process is created with this id
and it will die after restoring all other tasks.

Before this patch restore failed if anyone exited.
Now we should skip helpers, which exited successfully. It's a bit tricky.
All children are collected in sigchld_handler, but we have a point,
where we want to wait all helpers. For that waitpit is used and ECHLD
is ignored, because it signs that a helper exited and has been waited in
sigchld_handler.

v2: check that me isn't NULL in the sig handler
v3: move code about waiting helpers in a separate function
Signed-off-by: 's avatarAndrey Vagin <avagin@openvz.org>
Signed-off-by: 's avatarPavel Emelyanov <xemul@parallels.com>
parent acacc604
...@@ -339,10 +339,42 @@ err: ...@@ -339,10 +339,42 @@ err:
return ret; return ret;
} }
static int pstree_wait_helpers()
{
struct pstree_item *pi;
list_for_each_entry(pi, &me->children, list) {
int status, ret;
if (pi->state != TASK_HELPER)
continue;
/* Check, that a helper completed. */
ret = waitpid(pi->pid.virt, &status, 0);
if (ret == -1) {
if (errno == ECHILD)
continue; /* It has been waited in sigchld_handler */
pr_err("waitpid(%d) failed\n", pi->pid.virt);
return -1;
}
if (!WIFEXITED(status) || WEXITSTATUS(status)) {
pr_err("%d exited with non-zero code (%d,%d)", pi->pid.virt,
WEXITSTATUS(status), WTERMSIG(status));
return -1;
}
}
return 0;
}
static int restore_one_alive_task(int pid) static int restore_one_alive_task(int pid)
{ {
pr_info("Restoring resources\n"); pr_info("Restoring resources\n");
if (pstree_wait_helpers())
return -1;
if (prepare_fds(me)) if (prepare_fds(me))
return -1; return -1;
...@@ -405,6 +437,13 @@ static inline int sig_fatal(int sig) ...@@ -405,6 +437,13 @@ static inline int sig_fatal(int sig)
return (sig > 0) && (sig < SIGMAX) && (SIG_FATAL_MASK & (1 << sig)); return (sig > 0) && (sig < SIGMAX) && (SIG_FATAL_MASK & (1 << sig));
} }
static int restore_one_fake(int pid)
{
/* We should wait here, otherwise last_pid will be changed. */
futex_wait_while(&task_entries->start, CR_STATE_FORKING);
return 0;
}
static int restore_one_zombie(int pid, int exit_code) static int restore_one_zombie(int pid, int exit_code)
{ {
pr_info("Restoring zombie with %d code\n", exit_code); pr_info("Restoring zombie with %d code\n", exit_code);
...@@ -473,6 +512,9 @@ static int restore_one_task(int pid) ...@@ -473,6 +512,9 @@ static int restore_one_task(int pid)
{ {
struct task_core_entry tc; struct task_core_entry tc;
if (me->state == TASK_HELPER)
return restore_one_fake(pid);
if (check_core_header(pid, &tc)) if (check_core_header(pid, &tc))
return -1; return -1;
...@@ -557,12 +599,43 @@ err: ...@@ -557,12 +599,43 @@ err:
static void sigchld_handler(int signal, siginfo_t *siginfo, void *data) static void sigchld_handler(int signal, siginfo_t *siginfo, void *data)
{ {
if (siginfo->si_code & CLD_EXITED) struct pstree_item *pi;
pr_err("%d exited, status=%d\n", pid_t pid = siginfo->si_pid;
siginfo->si_pid, siginfo->si_status); int status;
else if (siginfo->si_code & CLD_KILLED) int exit;
pr_err("%d killed by signal %d\n",
siginfo->si_pid, siginfo->si_status); exit = siginfo->si_code & CLD_EXITED;
status = siginfo->si_status;
if (!me || status)
goto err;
/* Skip a helper if it was completed successfully */
while (pid) {
pid = waitpid(-1, &status, WNOHANG);
if (pid <= 0)
return;
exit = WIFEXITED(status);
status = exit ? WEXITSTATUS(status) : WTERMSIG(status);
if (status)
break;
list_for_each_entry(pi, &me->children, list) {
if (pi->state != TASK_HELPER)
continue;
if (pi->pid.virt == siginfo->si_pid)
break;
}
if (&pi->list == &me->children)
break; /* The process is not a helper */
}
err:
if (exit)
pr_err("%d exited, status=%d\n", pid, status);
else
pr_err("%d killed by signal %d\n", pid, status);
futex_abort_and_wake(&task_entries->nr_in_progress); futex_abort_and_wake(&task_entries->nr_in_progress);
} }
...@@ -704,8 +777,11 @@ static int restore_root_task(struct pstree_item *init, struct cr_options *opts) ...@@ -704,8 +777,11 @@ static int restore_root_task(struct pstree_item *init, struct cr_options *opts)
return -1; return -1;
} }
act.sa_flags |= SA_NOCLDWAIT | SA_NOCLDSTOP | SA_SIGINFO | SA_RESTART; act.sa_flags |= SA_NOCLDSTOP | SA_SIGINFO | SA_RESTART;
act.sa_sigaction = sigchld_handler; act.sa_sigaction = sigchld_handler;
sigemptyset(&act.sa_mask);
sigaddset(&act.sa_mask, SIGCHLD);
ret = sigaction(SIGCHLD, &act, &old_act); ret = sigaction(SIGCHLD, &act, &old_act);
if (ret < 0) { if (ret < 0) {
perror("sigaction() failed\n"); perror("sigaction() failed\n");
......
...@@ -499,6 +499,7 @@ struct core_entry { ...@@ -499,6 +499,7 @@ struct core_entry {
#define TASK_ALIVE 0x1 #define TASK_ALIVE 0x1
#define TASK_DEAD 0x2 #define TASK_DEAD 0x2
#define TASK_STOPPED 0x3 /* FIXME - implement */ #define TASK_STOPPED 0x3 /* FIXME - implement */
#define TASK_HELPER 0x4
#endif /* CONFIG_X86_64 */ #endif /* CONFIG_X86_64 */
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment