mirror of
https://github.com/checkpoint-restore/criu
synced 2025-08-31 06:15:24 +00:00
dump: rework freeze of threads
When we try to freeze threads, some of them can exit and a few new ones can be born. Currently we unfreeze process free int this case, so we have the same chance to failed in the next case. I suggest to not unfreeze frozen threads, just try to update thread list and freeze unfrozen threads. Signed-off-by: Andrey Vagin <avagin@openvz.org> Signed-off-by: Pavel Emelyanov <xemul@parallels.com>
This commit is contained in:
committed by
Pavel Emelyanov
parent
e2a0be63d4
commit
978badc196
116
cr-dump.c
116
cr-dump.c
@@ -74,6 +74,8 @@
|
||||
|
||||
#include "asm/dump.h"
|
||||
|
||||
#define NR_ATTEMPTS 5
|
||||
|
||||
static char loc_buf[PAGE_SIZE];
|
||||
|
||||
bool privately_dump_vma(struct vma_area *vma)
|
||||
@@ -682,31 +684,6 @@ err:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int get_threads(struct pstree_item *item)
|
||||
{
|
||||
return parse_threads(item->pid.real, &item->threads, &item->nr_threads);
|
||||
}
|
||||
|
||||
static int check_threads(const struct pstree_item *item)
|
||||
{
|
||||
struct pid *t = NULL;
|
||||
int nr, ret;
|
||||
|
||||
ret = parse_threads(item->pid.real, &t, &nr);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = ((nr == item->nr_threads) && !memcmp(t, item->threads, nr));
|
||||
xfree(t);
|
||||
|
||||
if (!ret) {
|
||||
pr_info("Threads set has changed while suspending\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int parse_children(pid_t pid, pid_t **_c, int *_n)
|
||||
{
|
||||
FILE *file;
|
||||
@@ -818,25 +795,55 @@ static pid_t item_ppid(const struct pstree_item *item)
|
||||
return item ? item->pid.real : -1;
|
||||
}
|
||||
|
||||
static int seize_threads(const struct pstree_item *item)
|
||||
static int seize_threads(struct pstree_item *item,
|
||||
struct pid *threads, int nr_threads)
|
||||
{
|
||||
int i = 0, ret;
|
||||
int i = 0, ret, j, nr_inprogress;
|
||||
|
||||
if ((item->state == TASK_DEAD) && (item->nr_threads > 1)) {
|
||||
if ((item->state == TASK_DEAD) && (nr_threads > 1)) {
|
||||
pr_err("Zombies with threads are not supported\n");
|
||||
goto err;
|
||||
}
|
||||
|
||||
for (i = 0; i < item->nr_threads; i++) {
|
||||
pid_t pid = item->threads[i].real;
|
||||
/* The number of threads can't be less than allready frozen */
|
||||
item->threads = xrealloc(item->threads, nr_threads * sizeof(struct pid));
|
||||
if (item->threads == NULL)
|
||||
return -1;
|
||||
|
||||
if (item->nr_threads == 0) {
|
||||
item->threads[0].real = item->pid.real;
|
||||
item->nr_threads = 1;
|
||||
}
|
||||
|
||||
nr_inprogress = 0;
|
||||
for (i = 0; i < nr_threads; i++) {
|
||||
pid_t pid = threads[i].real;
|
||||
if (item->pid.real == pid)
|
||||
continue;
|
||||
|
||||
for (j = 0; j < item->nr_threads; j++)
|
||||
if (pid == item->threads[j].real)
|
||||
break;
|
||||
|
||||
if (j != item->nr_threads)
|
||||
continue;
|
||||
nr_inprogress++;
|
||||
|
||||
pr_info("\tSeizing %d's %d thread\n",
|
||||
item->pid.real, pid);
|
||||
|
||||
ret = seize_task(pid, item_ppid(item), NULL, NULL);
|
||||
if (ret < 0)
|
||||
goto err;
|
||||
if (ret < 0) {
|
||||
/*
|
||||
* Skip an error, we will try to freeze it again
|
||||
* on the next attempt.
|
||||
*/
|
||||
continue;
|
||||
}
|
||||
|
||||
BUG_ON(item->nr_threads + 1 > nr_threads);
|
||||
item->threads[item->nr_threads].real = pid;
|
||||
item->nr_threads++;
|
||||
|
||||
if (ret == TASK_DEAD) {
|
||||
pr_err("Zombie thread not supported\n");
|
||||
@@ -849,30 +856,39 @@ static int seize_threads(const struct pstree_item *item)
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
return nr_inprogress;
|
||||
err:
|
||||
for (i--; i >= 0; i--) {
|
||||
if (item->pid.real == item->threads[i].real)
|
||||
continue;
|
||||
|
||||
unseize_task(item->threads[i].real, TASK_ALIVE);
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int collect_threads(struct pstree_item *item)
|
||||
{
|
||||
int ret;
|
||||
int ret, attempts = NR_ATTEMPTS;
|
||||
struct pid *t;
|
||||
int nr, nr_inprogress;
|
||||
|
||||
ret = get_threads(item);
|
||||
if (!ret)
|
||||
ret = seize_threads(item);
|
||||
if (!ret)
|
||||
ret = check_threads(item);
|
||||
nr_inprogress = 1;
|
||||
while (nr_inprogress > 0 && attempts) {
|
||||
attempts--;
|
||||
|
||||
return ret;
|
||||
t = NULL;
|
||||
nr = 0;
|
||||
|
||||
ret = parse_threads(item->pid.real, &t, &nr);
|
||||
if (ret < 0)
|
||||
break;
|
||||
|
||||
nr_inprogress = seize_threads(item, t, nr);
|
||||
xfree(t);
|
||||
if (nr_inprogress < 0)
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
if (nr_inprogress && attempts)
|
||||
return -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int collect_task(struct pstree_item *item)
|
||||
@@ -907,7 +923,7 @@ static int collect_task(struct pstree_item *item)
|
||||
|
||||
err_close:
|
||||
close_pid_proc();
|
||||
unseize_task(pid, item->state);
|
||||
unseize_task_and_threads(item, item->state);
|
||||
err:
|
||||
return -1;
|
||||
}
|
||||
@@ -982,7 +998,7 @@ static int collect_pstree_ids(void)
|
||||
|
||||
static int collect_pstree(pid_t pid)
|
||||
{
|
||||
int ret, attempts = 5;
|
||||
int ret, attempts = NR_ATTEMPTS;
|
||||
|
||||
timing_start(TIME_FREEZING);
|
||||
|
||||
|
Reference in New Issue
Block a user