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:
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 = {
.sa_handler = handler,
.sa_flags = 0,
.sa_handler = alarm_handler,
.sa_flags = 0, /* Don't restart syscalls */
};
sigemptyset(&sa.sa_mask);
......@@ -1452,15 +1469,6 @@ static int cr_pre_dump_finish(struct list_head *ctls, int 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)
{
struct pstree_item *item;
......@@ -1498,7 +1506,7 @@ int cr_pre_dump_tasks(pid_t pid)
if (connect_to_page_server())
goto err;
if (setup_alarm_handler(pre_dump_alarm_handler))
if (setup_alarm_handler())
goto err;
if (collect_pstree(pid))
......@@ -1600,13 +1608,6 @@ static int cr_dump_finish(int ret)
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)
{
InventoryEntry he = INVENTORY_ENTRY__INIT;
......@@ -1655,7 +1656,7 @@ int cr_dump_tasks(pid_t pid)
if (connect_to_page_server())
goto err;
if (setup_alarm_handler(dump_alarm_handler))
if (setup_alarm_handler())
goto err;
/*
......
......@@ -4,5 +4,6 @@
extern int collect_pstree(pid_t pid);
extern void pstree_switch_state(struct pstree_item *root_item, int st);
extern const char *get_real_freezer_state(void);
extern bool alarm_timeouted(void);
#endif
......@@ -297,6 +297,9 @@ static int freeze_processes(void)
continue;
}
if (alarm_timeouted())
goto err;
timeout = 100000000 * (i + 1); /* 100 msec */
req.tv_nsec = timeout % 1000000000;
req.tv_sec = timeout / 1000000000;
......@@ -357,6 +360,11 @@ static int collect_children(struct pstree_item *item)
nr_inprogress++;
if (alarm_timeouted()) {
ret = -1;
goto free;
}
pr_info("Seized task %d, state %d\n", pid, ret);
c = alloc_pstree_item();
......@@ -642,6 +650,13 @@ int collect_pstree(pid_t pid)
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())
goto err;
......@@ -656,13 +671,6 @@ int collect_pstree(pid_t pid)
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);
if (ret < 0)
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