diff --git a/cr-restore.c b/cr-restore.c index fd76aed03..b5078445b 100644 --- a/cr-restore.c +++ b/cr-restore.c @@ -1062,19 +1062,48 @@ static void restore_sid(void) static void restore_pgid(void) { - pid_t pgid; + /* + * Unlike sessions, process groups (a.k.a. pgids) can be joined + * by any task, provided the task with pid == pgid (group leader) + * exists. Thus, in order to restore pgid we must make sure that + * group leader was born and created the group, then join one. + * + * We do this _before_ finishing the forking stage to make sure + * helpers are still with us. + */ - pr_info("Restoring %d to %d pgid\n", current->pid.virt, current->pgid); + pid_t pgid, my_pgid = current->pgid; + + pr_info("Restoring %d to %d pgid\n", current->pid.virt, my_pgid); pgid = getpgrp(); - if (current->pgid == pgid) + if (my_pgid == pgid) return; + if (my_pgid != current->pid.virt) { + struct pstree_item *leader; + + /* + * Wait for leader to become such. + * Missing leader means we're going to crtools + * group (-j option). + */ + + leader = current->rst->pgrp_leader; + if (leader) { + BUG_ON(my_pgid != leader->pid.virt); + futex_wait_until(&leader->rst->pgrp_set, 1); + } + } + pr_info("\twill call setpgid, mine pgid is %d\n", pgid); - if (setpgid(0, current->pgid) != 0) { + if (setpgid(0, my_pgid) != 0) { pr_perror("Can't restore pgid (%d/%d->%d)", current->pid.virt, pgid, current->pgid); exit(1); } + + if (my_pgid == current->pid.virt) + futex_set_and_wake(¤t->rst->pgrp_set, 1); } static int mount_proc(void) @@ -1240,26 +1269,12 @@ static int restore_task_with_children(void *_arg) if (unmap_guard_pages()) exit(1); - /* - * Unlike sessions, process groups (a.k.a. pgids) can be joined - * by any task, provided the task with pid == pgid (group leader) - * exists. Thus, in order to restore pgid we must make sure that - * group leader was born (stage barrier below), created the group - * (the 1st restore_pgid below) and then join one (the 2nd call - * to restore_pgid). - */ - if (current->pgid == current->pid.virt) - restore_pgid(); + restore_pgid(); if (restore_finish_stage(CR_STATE_FORKING) < 0) exit(1); - if (current->pgid != current->pid.virt) - restore_pgid(); - - restore_finish_stage(CR_STATE_RESTORE_PGID); - if (current->state == TASK_HELPER) return 0; @@ -1274,7 +1289,6 @@ static inline int stage_participants(int next_stage) case CR_STATE_RESTORE_NS: return 1; case CR_STATE_FORKING: - case CR_STATE_RESTORE_PGID: return task_entries->nr_tasks + task_entries->nr_helpers; case CR_STATE_RESTORE: case CR_STATE_RESTORE_SIGCHLD: @@ -1472,10 +1486,6 @@ static int restore_root_task(struct pstree_item *init) timing_stop(TIME_FORK); - ret = restore_switch_stage(CR_STATE_RESTORE_PGID); - if (ret < 0) - goto out_kill; - ret = restore_switch_stage(CR_STATE_RESTORE); if (ret < 0) goto out_kill; diff --git a/include/crtools.h b/include/crtools.h index 76b4f6be2..149525e3d 100644 --- a/include/crtools.h +++ b/include/crtools.h @@ -182,6 +182,11 @@ struct rst_info { int service_fd_id; struct fdt *fdt; + + union { + struct pstree_item *pgrp_leader; + futex_t pgrp_set; + }; }; static inline int in_vma_area(struct vma_area *vma, unsigned long addr) diff --git a/include/restorer.h b/include/restorer.h index 9d9e7f4b7..18a82d89a 100644 --- a/include/restorer.h +++ b/include/restorer.h @@ -187,7 +187,6 @@ enum { CR_STATE_FAIL = -1, CR_STATE_RESTORE_NS = 0, /* is used for executing "setup-namespace" scripts */ CR_STATE_FORKING, - CR_STATE_RESTORE_PGID, CR_STATE_RESTORE, CR_STATE_RESTORE_SIGCHLD, /* diff --git a/pstree.c b/pstree.c index ebf106d1a..fbd69ffea 100644 --- a/pstree.c +++ b/pstree.c @@ -520,8 +520,10 @@ static int prepare_pstree_ids(void) break; } - if (gleader) + if (gleader) { + item->rst->pgrp_leader = gleader; continue; + } /* * If the PGID is eq to current one -- this @@ -541,6 +543,7 @@ static int prepare_pstree_ids(void) helper->parent = item; list_add(&helper->sibling, &item->children); task_entries->nr_helpers++; + item->rst->pgrp_leader = helper; pr_info("Add a helper %d for restoring PGID %d\n", helper->pid.virt, helper->pgid);