Commit 1675ac8b authored by Andrew Vagin's avatar Andrew Vagin Committed by Pavel Emelyanov

dump: don't call rollback actions from a signal handler

We can do this, but we need to be sure that all structures
are consistent in any moment and we need to block alarm when
they are inconsistent.

I don't think that we really want to do this now. I suggest to
interrupt a current syscall if an alarm signal is triggered.

v2: print an error message before exiting

Cc: Andrey Ryabinin <aryabinin@virtuozzo.com>
Signed-off-by: 's avatarAndrew Vagin <avagin@virtuozzo.com>
Reviewed-by: 's avatarAndrey Ryabinin <aryabinin@virtuozzo.com>
Signed-off-by: 's avatarPavel Emelyanov <xemul@virtuozzo.com>
parent 2fd16c39
...@@ -1381,13 +1381,30 @@ err_cure_imgset: ...@@ -1381,13 +1381,30 @@ err_cure_imgset:
goto err; goto err;
} }
typedef void (*sa_handler_t)(int); static int alarm_attempts = 0;
static int setup_alarm_handler(sa_handler_t handler) bool alarm_timeouted() {
return alarm_attempts > 0;
}
static void alarm_handler(int signo)
{
pr_err("Timeout reached. Try to interrupt: %d\n", alarm_attempts);
if (alarm_attempts++ < 5) {
alarm(1);
/* A curren syscall will be exited with EINTR */
return;
}
pr_err("FATAL: Unable to interrupt the current operation\n");
BUG();
}
static int setup_alarm_handler()
{ {
struct sigaction sa = { struct sigaction sa = {
.sa_handler = handler, .sa_handler = alarm_handler,
.sa_flags = 0, .sa_flags = 0, /* Don't restart syscalls */
}; };
sigemptyset(&sa.sa_mask); sigemptyset(&sa.sa_mask);
...@@ -1452,15 +1469,6 @@ static int cr_pre_dump_finish(struct list_head *ctls, int ret) ...@@ -1452,15 +1469,6 @@ static int cr_pre_dump_finish(struct list_head *ctls, int ret)
return ret; return ret;
} }
void pre_dump_alarm_handler(int signum)
{
LIST_HEAD(empty_list);
pr_err("Timeout reached\n");
cr_pre_dump_finish(&empty_list, -1);
exit(-1);
}
int cr_pre_dump_tasks(pid_t pid) int cr_pre_dump_tasks(pid_t pid)
{ {
struct pstree_item *item; struct pstree_item *item;
...@@ -1498,7 +1506,7 @@ int cr_pre_dump_tasks(pid_t pid) ...@@ -1498,7 +1506,7 @@ int cr_pre_dump_tasks(pid_t pid)
if (connect_to_page_server()) if (connect_to_page_server())
goto err; goto err;
if (setup_alarm_handler(pre_dump_alarm_handler)) if (setup_alarm_handler())
goto err; goto err;
if (collect_pstree(pid)) if (collect_pstree(pid))
...@@ -1600,13 +1608,6 @@ static int cr_dump_finish(int ret) ...@@ -1600,13 +1608,6 @@ static int cr_dump_finish(int ret)
return post_dump_ret ? : (ret != 0); return post_dump_ret ? : (ret != 0);
} }
void dump_alarm_handler(int signum)
{
pr_err("Timeout reached\n");
cr_dump_finish(-1);
exit(-1);
}
int cr_dump_tasks(pid_t pid) int cr_dump_tasks(pid_t pid)
{ {
InventoryEntry he = INVENTORY_ENTRY__INIT; InventoryEntry he = INVENTORY_ENTRY__INIT;
...@@ -1655,7 +1656,7 @@ int cr_dump_tasks(pid_t pid) ...@@ -1655,7 +1656,7 @@ int cr_dump_tasks(pid_t pid)
if (connect_to_page_server()) if (connect_to_page_server())
goto err; goto err;
if (setup_alarm_handler(dump_alarm_handler)) if (setup_alarm_handler())
goto err; goto err;
/* /*
......
...@@ -4,5 +4,6 @@ ...@@ -4,5 +4,6 @@
extern int collect_pstree(pid_t pid); extern int collect_pstree(pid_t pid);
extern void pstree_switch_state(struct pstree_item *root_item, int st); extern void pstree_switch_state(struct pstree_item *root_item, int st);
extern const char *get_real_freezer_state(void); extern const char *get_real_freezer_state(void);
extern bool alarm_timeouted(void);
#endif #endif
...@@ -297,6 +297,9 @@ static int freeze_processes(void) ...@@ -297,6 +297,9 @@ static int freeze_processes(void)
continue; continue;
} }
if (alarm_timeouted())
goto err;
timeout = 100000000 * (i + 1); /* 100 msec */ timeout = 100000000 * (i + 1); /* 100 msec */
req.tv_nsec = timeout % 1000000000; req.tv_nsec = timeout % 1000000000;
req.tv_sec = timeout / 1000000000; req.tv_sec = timeout / 1000000000;
...@@ -357,6 +360,11 @@ static int collect_children(struct pstree_item *item) ...@@ -357,6 +360,11 @@ static int collect_children(struct pstree_item *item)
nr_inprogress++; nr_inprogress++;
if (alarm_timeouted()) {
ret = -1;
goto free;
}
pr_info("Seized task %d, state %d\n", pid, ret); pr_info("Seized task %d, state %d\n", pid, ret);
c = alloc_pstree_item(); c = alloc_pstree_item();
...@@ -642,6 +650,13 @@ int collect_pstree(pid_t pid) ...@@ -642,6 +650,13 @@ int collect_pstree(pid_t pid)
timing_start(TIME_FREEZING); timing_start(TIME_FREEZING);
/*
* wait4() may hang for some reason. Enable timer and fire SIGALRM
* if timeout reached. SIGALRM handler will do the necessary
* cleanups and terminate current process.
*/
alarm(opts.timeout);
if (opts.freeze_cgroup && freeze_processes()) if (opts.freeze_cgroup && freeze_processes())
goto err; goto err;
...@@ -656,13 +671,6 @@ int collect_pstree(pid_t pid) ...@@ -656,13 +671,6 @@ int collect_pstree(pid_t pid)
goto err; goto err;
} }
/*
* wait4() may hang for some reason. Enable timer and fire SIGALRM
* if timeout reached. SIGALRM handler will do the necessary
* cleanups and terminate current process.
*/
alarm(opts.timeout);
ret = seize_wait_task(pid, -1, &dmpi(root_item)->pi_creds); ret = seize_wait_task(pid, -1, &dmpi(root_item)->pi_creds);
if (ret < 0) if (ret < 0)
goto err; goto err;
......
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