Skip to content

Commit

Permalink
restore: TASK_HELPERs live until RESTORE stage ends
Browse files Browse the repository at this point in the history
In order to use TASK_HELPERS to open files from dead processes, they should
persist until criu is done restoring the filesystem, which happens in the
RESTORE stage. To do this, we need to pass each helper's PIDs to the restorer
blob, so that it can wait() on them when the restore stage is done.

This commit is in preparation for the remap_dead_pid commits.

v2: wait() on helpers after restore stage is over
v3: add CR_STATE_RESTORE_FS stage
v4: CR_STATE_RESTORE_FS waits for nr_tasks + nr_helpers, not nr_threads
v5: ditch CR_STATE_RESTORE_FS in favor of passing helpers to restorer blob

Signed-off-by: Tycho Andersen <[email protected]>
Signed-off-by: Pavel Emelyanov <[email protected]>
  • Loading branch information
Tycho Andersen authored and xemul committed Sep 19, 2014
1 parent 5a101d8 commit c09ba04
Show file tree
Hide file tree
Showing 3 changed files with 69 additions and 19 deletions.
48 changes: 29 additions & 19 deletions cr-restore.c
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,9 @@ static int prepare_posix_timers(int pid, CoreEntry *core);
static int prepare_signals(int pid, CoreEntry *core);

static int root_as_sibling;
static pid_t *helpers = NULL;
static unsigned long helpers_pos = 0;
static int n_helpers = 0;

static int crtools_prepare_shared(void)
{
Expand Down Expand Up @@ -698,30 +701,29 @@ static int prepare_sigactions(void)
return ret;
}

static int pstree_wait_helpers()
static int collect_helper_pids()
{
struct pstree_item *pi;

list_for_each_entry(pi, &current->children, sibling) {
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)\n", pi->pid.virt,
WEXITSTATUS(status), WTERMSIG(status));
return -1;
if (helpers) {
void *m;
m = rst_mem_alloc(sizeof(*helpers) * ++n_helpers, RM_PRIVATE);
if (!m)
return -1;
} else {
helpers_pos = rst_mem_cpos(RM_PRIVATE);
helpers = rst_mem_alloc(sizeof(*helpers), RM_PRIVATE);
if (!helpers)
return -1;
n_helpers = 1;
}

helpers[n_helpers - 1] = pi->pid.virt;
}

return 0;
Expand Down Expand Up @@ -770,9 +772,6 @@ static int restore_one_alive_task(int pid, CoreEntry *core)

rst_mem_switch_to_private();

if (pstree_wait_helpers())
return -1;

if (prepare_fds(current))
return -1;

Expand All @@ -794,6 +793,9 @@ static int restore_one_alive_task(int pid, CoreEntry *core)
if (prepare_rlimits(pid, core) < 0)
return -1;

if (collect_helper_pids() < 0)
return -1;

return sigreturn_restore(pid, core);
}

Expand Down Expand Up @@ -931,9 +933,10 @@ static int restore_one_task(int pid, CoreEntry *core)
ret = restore_one_alive_task(pid, core);
else if (current->state == TASK_DEAD)
ret = restore_one_zombie(pid, core);
else if (current->state == TASK_HELPER)
else if (current->state == TASK_HELPER) {
restore_finish_stage(CR_STATE_RESTORE);
ret = 0;
else {
} else {
pr_err("Unknown state in code %d\n", (int)core->tc->task_state);
ret = -1;
}
Expand Down Expand Up @@ -1496,6 +1499,7 @@ static inline int stage_participants(int next_stage)
case CR_STATE_FORKING:
return task_entries->nr_tasks + task_entries->nr_helpers;
case CR_STATE_RESTORE:
return task_entries->nr_threads + task_entries->nr_helpers;
case CR_STATE_RESTORE_SIGCHLD:
return task_entries->nr_threads;
case CR_STATE_RESTORE_CREDS:
Expand Down Expand Up @@ -2712,6 +2716,12 @@ static int sigreturn_restore(pid_t pid, CoreEntry *core)
task_args->tcp_socks_nr = rst_tcp_socks_nr;
task_args->tcp_socks = rst_mem_remap_ptr(tcp_socks, RM_PRIVATE);

task_args->n_helpers = n_helpers;
if (n_helpers > 0)
task_args->helpers = rst_mem_remap_ptr(helpers_pos, RM_PRIVATE);
else
task_args->helpers = NULL;

/*
* Arguments for task restoration.
*/
Expand Down
3 changes: 3 additions & 0 deletions include/restorer.h
Original file line number Diff line number Diff line change
Expand Up @@ -150,6 +150,9 @@ struct task_restore_args {

int fd_last_pid; /* sys.ns_last_pid for threads rst */

pid_t *helpers /* the TASK_HELPERS to wait on at the end of restore */;
int n_helpers;

#ifdef CONFIG_VDSO
unsigned long vdso_rt_size;
struct vdso_symtable vdso_sym_rt; /* runtime vdso symbols */
Expand Down
37 changes: 37 additions & 0 deletions pie/restorer.c
Original file line number Diff line number Diff line change
Expand Up @@ -51,13 +51,22 @@ static struct task_entries *task_entries;
static futex_t thread_inprogress;
static futex_t zombies_inprogress;
static int cap_last_cap;
static pid_t *helpers;
static int n_helpers;

extern void cr_restore_rt (void) asm ("__cr_restore_rt")
__attribute__ ((visibility ("hidden")));

static void sigchld_handler(int signal, siginfo_t *siginfo, void *data)
{
char *r;
int i;

/* We can ignore helpers that die, we expect them to after
* CR_STATE_RESTORE is finished. */
for (i = 0; i < n_helpers; i++)
if (siginfo->si_pid == helpers[i])
return;

if (futex_get(&task_entries->start) == CR_STATE_RESTORE_SIGCHLD) {
pr_debug("%ld: Collect a zombie with (pid %d, %d)\n",
Expand Down Expand Up @@ -702,6 +711,29 @@ static int unmap_old_vmas(void *premmapped_addr, unsigned long premmapped_len,
return 0;
}

static int wait_helpers(struct task_restore_args *task_args)
{
int i;

for (i = 0; i < task_args->n_helpers; i++) {
int status;
pid_t pid = task_args->helpers[i];

/* Check that a helper completed. */
if (sys_waitpid(pid, &status, 0, NULL) == -1) {
/* It has been waited in sigchld_handler */
continue;
}
if (!WIFEXITED(status) || WEXITSTATUS(status)) {
pr_err("%d exited with non-zero code (%d,%d)\n", pid,
WEXITSTATUS(status), WTERMSIG(status));
return -1;
}
}

return 0;
}

/*
* The main routine to restore task via sigreturn.
* This one is very special, we never return there
Expand Down Expand Up @@ -730,6 +762,8 @@ long __export_restore_task(struct task_restore_args *args)
#endif

task_entries = args->task_entries;
helpers = args->helpers;
n_helpers = args->n_helpers;

ksigfillset(&act.rt_sa_mask);
act.rt_sa_handler = sigchld_handler;
Expand Down Expand Up @@ -1020,6 +1054,9 @@ long __export_restore_task(struct task_restore_args *args)

futex_wait_while_gt(&zombies_inprogress, 0);

if (wait_helpers(args) < 0)
goto core_restore_end;

ksigfillset(&to_block);
ret = sys_sigprocmask(SIG_SETMASK, &to_block, NULL, sizeof(k_rtsigset_t));
if (ret) {
Expand Down

0 comments on commit c09ba04

Please sign in to comment.