mirror of
https://github.com/checkpoint-restore/criu
synced 2025-08-29 13:28:27 +00:00
rst: Introduce fine-grained pgid-restore synchronization
We can restore task's pgid which is not equal to its pid, only when the respective group leader is alive. To make restore reliable we wait for all group leaders to restore using separate restore stage. It's better to optimize this -- each task has a pointer on its group leader and waits for one to become such. Signed-off-by: Pavel Emelyanov <xemul@parallels.com>
This commit is contained in:
parent
656693503e
commit
f1edcb32f5
58
cr-restore.c
58
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;
|
||||
|
@ -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)
|
||||
|
@ -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,
|
||||
/*
|
||||
|
5
pstree.c
5
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);
|
||||
|
Loading…
x
Reference in New Issue
Block a user