Commit 5c2083ee authored by Pavel Emelyanov's avatar Pavel Emelyanov Committed by Cyrill Gorcunov

cr: Support zombie tasks

Dump the core-pid.img file only. On restore select the way of killing
task based on his exit_code -- exit or kill with a signal. Before dying
unblock all the handlers and set SIG_DFL to it (to make the dead signal
other than KILL be deliverable).
Signed-off-by: 's avatarPavel Emelyanov <xemul@parallels.com>
Signed-off-by: 's avatarCyrill Gorcunov <gorcunov@openvz.org>
parent 3822c079
...@@ -1032,6 +1032,35 @@ err: ...@@ -1032,6 +1032,35 @@ err:
return ret; return ret;
} }
static int dump_one_zombie(struct pstree_item *item, struct proc_pid_stat *pps,
struct cr_fdset *cr_fdset)
{
struct core_entry *core;
if (item->nr_children) {
pr_err("Zombie %d with kids?\n", item->pid);
return -1;
}
if (item->nr_threads > 1) {
pr_err("Zombie %d with threads.\n", item->pid);
return -1;
}
cr_fdset = cr_fdset_open(item->pid, CR_FD_DESC_CORE, cr_fdset);
if (cr_fdset == NULL)
return -1;
core = xzalloc(sizeof(*core));
if (core == NULL)
return -1;
core->tc.task_state = TASK_DEAD;
core->tc.exit_code = pps->exit_code;
return dump_task_core(core, cr_fdset);
}
static struct proc_pid_stat pps_buf; static struct proc_pid_stat pps_buf;
static int dump_task_threads(struct pstree_item *item) static int dump_task_threads(struct pstree_item *item)
...@@ -1088,6 +1117,8 @@ static int dump_one_task(struct pstree_item *item, struct cr_fdset *cr_fdset) ...@@ -1088,6 +1117,8 @@ static int dump_one_task(struct pstree_item *item, struct cr_fdset *cr_fdset)
goto err; goto err;
switch (pps_buf.state) { switch (pps_buf.state) {
case 'Z':
return dump_one_zombie(item, &pps_buf, cr_fdset);
case 'T': case 'T':
/* Stopped -- can dump one */ /* Stopped -- can dump one */
break; break;
......
...@@ -1072,7 +1072,7 @@ err_free: ...@@ -1072,7 +1072,7 @@ err_free:
return err; return err;
} }
static int restore_one_task(int pid) static int restore_one_alive_task(int pid)
{ {
pr_info("%d: Restoring resources\n", pid); pr_info("%d: Restoring resources\n", pid);
...@@ -1094,6 +1094,147 @@ static int restore_one_task(int pid) ...@@ -1094,6 +1094,147 @@ static int restore_one_task(int pid)
return prepare_and_sigreturn(pid); return prepare_and_sigreturn(pid);
} }
static void zombie_prepare_signals(void)
{
sigset_t blockmask;
int sig;
struct sigaction act;
sigfillset(&blockmask);
sigprocmask(SIG_UNBLOCK, &blockmask, NULL);
memset(&act, 0, sizeof(act));
act.sa_handler = SIG_DFL;
for (sig = 1; sig < SIGMAX; sig++)
sigaction(sig, &act, NULL);
}
#define SIG_FATAL_MASK ( \
(1 << SIGHUP) |\
(1 << SIGINT) |\
(1 << SIGQUIT) |\
(1 << SIGILL) |\
(1 << SIGTRAP) |\
(1 << SIGABRT) |\
(1 << SIGIOT) |\
(1 << SIGBUS) |\
(1 << SIGFPE) |\
(1 << SIGKILL) |\
(1 << SIGUSR1) |\
(1 << SIGSEGV) |\
(1 << SIGUSR2) |\
(1 << SIGPIPE) |\
(1 << SIGALRM) |\
(1 << SIGTERM) |\
(1 << SIGXCPU) |\
(1 << SIGXFSZ) |\
(1 << SIGVTALRM)|\
(1 << SIGPROF) |\
(1 << SIGPOLL) |\
(1 << SIGIO) |\
(1 << SIGSYS) |\
(1 << SIGUNUSED)|\
(1 << SIGSTKFLT)|\
(1 << SIGPWR) \
)
static inline int sig_fatal(int sig)
{
return (sig > 0) && (sig < SIGMAX) && (SIG_FATAL_MASK & (1 << sig));
}
static int restore_one_zobie(int pid, int exit_code)
{
pr_info("Restoring zombie with %d code\n", exit_code);
if (task_entries != NULL) {
struct task_entry *task_entry;
task_entry = task_get_entry(task_entries, pid);
cr_wait_dec(&task_entries->nr_in_progress);
cr_wait_set(&task_entry->done, 1);
cr_wait_while(&task_entries->start, CR_STATE_RESTORE);
zombie_prepare_signals();
cr_wait_dec(&task_entries->nr_in_progress);
cr_wait_while(&task_entries->start, CR_STATE_RESTORE_SIGCHLD);
}
if (exit_code & 0x7f) {
int signr;
signr = exit_code & 0x7F;
if (!sig_fatal(signr)) {
pr_warning("Exit with non fatal signal ignored\n");
signr = SIGABRT;
}
if (kill(pid, signr) < 0)
pr_perror("Can't kill myself, will just exit\n");
exit_code = 0;
}
exit(exit_code >> 8);
/* never reached */
BUG_ON(1);
return -1;
}
static int check_core_header(int pid, struct task_core_entry *tc)
{
int fd, ret;
struct image_header hdr;
fd = open_image_ro(CR_FD_CORE, pid);
if (fd < 0)
return -1;
if (read_img(fd, &hdr) < 0) {
close(fd);
return -1;
}
if (hdr.version != HEADER_VERSION) {
pr_err("Core version mismatch %d\n", (int)hdr.version);
close(fd);
return -1;
}
if (hdr.arch != HEADER_ARCH_X86_64) {
pr_err("Core arch mismatch %d\n", (int)hdr.arch);
close(fd);
return -1;
}
ret = read_img(fd, tc);
close(fd);
return ret < 0 ? ret : 0;
}
static int restore_one_task(int pid)
{
struct task_core_entry tc;
if (check_core_header(pid, &tc))
return -1;
switch ((int)tc.task_state) {
case TASK_ALIVE:
return restore_one_alive_task(pid);
case TASK_DEAD:
return restore_one_zobie(pid, tc.exit_code);
default:
pr_err("Unknown state in code %d\n", (int)tc.task_state);
return -1;
}
}
static inline int fork_with_pid(int pid) static inline int fork_with_pid(int pid)
{ {
int ret = -1, fd = -1; int ret = -1, fd = -1;
......
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