[CRIU] [PATCH 09/13] crtools: restore pending signals (v2)
Andrey Vagin
avagin at openvz.org
Thu Dec 20 06:54:17 EST 2012
Read siginfo-s from images and send them to itself by sigqueueinfo.
v2: Don't remap task_args and thread_args
Signed-off-by: Andrey Vagin <avagin at openvz.org>
---
cr-restore.c | 113 +++++++++++++++++++++++++++++++++++++++++++++++++++--
include/restorer.h | 6 +++
pie/restorer.c | 54 ++++++++++++++++++++++++-
3 files changed, 169 insertions(+), 4 deletions(-)
diff --git a/cr-restore.c b/cr-restore.c
index cb4d943..1f53b8e 100644
--- a/cr-restore.c
+++ b/cr-restore.c
@@ -58,6 +58,7 @@
#include "protobuf/sa.pb-c.h"
#include "protobuf/itimer.pb-c.h"
#include "protobuf/vma.pb-c.h"
+#include "protobuf/siginfo.pb-c.h"
static struct pstree_item *current;
@@ -1581,6 +1582,58 @@ static int prep_sched_info(struct rst_sched_param *sp, ThreadCoreEntry *tc)
return 0;
}
+static int open_signal_image(int type, pid_t pid, siginfo_t **ptr,
+ unsigned long *size, int *nr)
+{
+ int fd, ret, n;
+
+ fd = open_image_ro(type, pid);
+ if (fd < 0)
+ return -1;
+
+ n = 0;
+
+ while (1) {
+ SiginfoEntry *sie;
+ siginfo_t *info;
+
+ ret = pb_read_one_eof(fd, &sie, PB_SIGINFO);
+ if (ret <= 0)
+ break;
+ if (sie->siginfo.len != sizeof(siginfo_t)) {
+ pr_err("Unknown image format");
+ BUG();
+ }
+ info = (siginfo_t *) sie->siginfo.data;
+
+ if ((*nr + 1) * sizeof(siginfo_t) > *size) {
+ unsigned long new_size = *size + PAGE_SIZE;
+
+ if (*ptr == NULL)
+ *ptr = mmap(NULL, new_size, PROT_READ | PROT_WRITE,
+ MAP_PRIVATE | MAP_ANON, 0, 0);
+ else
+ *ptr = mremap(*ptr, *size, new_size, MREMAP_MAYMOVE);
+ if (*ptr == MAP_FAILED) {
+ pr_perror("Can't allocate memory for siginfo-s\n");
+ return -1;
+ }
+
+ *size = new_size;
+ }
+
+ memcpy(*ptr + *nr, info, sizeof(*info));
+ (*nr)++;
+ n++;
+
+ siginfo_entry__free_unpacked(sie, NULL);
+ }
+
+ close(fd);
+
+ return ret ? : n;
+}
+
static int sigreturn_restore(pid_t pid, CoreEntry *core)
{
long restore_task_vma_len;
@@ -1596,6 +1649,11 @@ static int sigreturn_restore(pid_t pid, CoreEntry *core)
struct task_restore_core_args *task_args;
struct thread_restore_args *thread_args;
+ siginfo_t *siginfo_chunk = NULL;
+ int siginfo_nr = 0;
+ int siginfo_shared_nr = 0;
+ int *siginfo_priv_nr;
+ unsigned long siginfo_size = 0;
LIST_HEAD(self_vma_list);
int i;
@@ -1630,12 +1688,38 @@ static int sigreturn_restore(pid_t pid, CoreEntry *core)
current->nr_threads,
KBYTES(restore_thread_vma_len));
+ siginfo_priv_nr = xmalloc(sizeof(int) * current->nr_threads);
+ if (siginfo_priv_nr == NULL)
+ goto err;
+
+ ret = open_signal_image(CR_FD_SIGNAL, pid, &siginfo_chunk,
+ &siginfo_size, &siginfo_nr);
+ if (ret < 0) {
+ if (errno != ENOENT) /* backward compatiblity */
+ goto err;
+ ret = 0;
+ }
+ siginfo_shared_nr = ret;
+
+ for (i = 0; i < current->nr_threads; i++) {
+ ret = open_signal_image(CR_FD_PSIGNAL,
+ current->threads[i].virt, &siginfo_chunk,
+ &siginfo_size, &siginfo_nr);
+ if (ret < 0) {
+ if (errno != ENOENT) /* backward compatiblity */
+ goto err;
+ ret = 0;
+ }
+ siginfo_priv_nr[i] = ret;
+ }
+
restore_bootstrap_len = restorer_len +
restore_task_vma_len +
restore_thread_vma_len +
SHMEMS_SIZE + TASK_ENTRIES_SIZE +
self_vmas_len + vmas_len +
- rst_tcp_socks_size;
+ rst_tcp_socks_size +
+ siginfo_size;
/*
* Restorer is a blob (code + args) that will get mapped in some
@@ -1686,6 +1770,21 @@ static int sigreturn_restore(pid_t pid, CoreEntry *core)
task_args = mem;
thread_args = mem + restore_task_vma_len;
+ mem += restore_task_vma_len + restore_thread_vma_len;
+ if (siginfo_chunk) {
+ siginfo_chunk = mremap(siginfo_chunk, siginfo_size, siginfo_size,
+ MREMAP_FIXED | MREMAP_MAYMOVE, mem);
+ if (siginfo_chunk == MAP_FAILED) {
+ pr_perror("mremap");
+ goto err;
+ }
+ }
+
+ task_args->siginfo_size = siginfo_size;
+ task_args->siginfo_nr = siginfo_shared_nr;
+ task_args->siginfo = siginfo_chunk;
+ siginfo_chunk += task_args->siginfo_nr;
+
/*
* Adjust stack.
*/
@@ -1703,7 +1802,7 @@ static int sigreturn_restore(pid_t pid, CoreEntry *core)
* address.
*/
- mem += restore_task_vma_len + restore_thread_vma_len;
+ mem += siginfo_size;
ret = shmem_remap(rst_shmems, mem, SHMEMS_SIZE);
if (ret < 0)
goto err;
@@ -1796,8 +1895,16 @@ static int sigreturn_restore(pid_t pid, CoreEntry *core)
thread_args[i].pid = current->threads[i].virt;
/* skip self */
- if (thread_args[i].pid == pid)
+ if (thread_args[i].pid == pid) {
+ task_args->t.siginfo_nr = siginfo_priv_nr[i];
+ task_args->t.siginfo = siginfo_chunk;
+ siginfo_chunk += task_args->t.siginfo_nr;
continue;
+ }
+
+ thread_args[i].siginfo_nr = siginfo_priv_nr[i];
+ thread_args[i].siginfo = siginfo_chunk;
+ siginfo_chunk += thread_args[i].siginfo_nr;
fd_core = open_image_ro(CR_FD_CORE, thread_args[i].pid);
if (fd_core < 0) {
diff --git a/include/restorer.h b/include/restorer.h
index 2309a3d..f7a762d 100644
--- a/include/restorer.h
+++ b/include/restorer.h
@@ -79,6 +79,9 @@ struct thread_restore_args {
struct rst_sched_param sp;
struct task_restore_core_args *ta;
+
+ siginfo_t *siginfo;
+ unsigned int siginfo_nr;
} __aligned(sizeof(long));
struct task_restore_core_args {
@@ -98,6 +101,9 @@ struct task_restore_core_args {
struct task_entries *task_entries;
VmaEntry *self_vmas;
VmaEntry *tgt_vmas;
+ siginfo_t *siginfo;
+ unsigned int siginfo_nr;
+ unsigned long siginfo_size;
unsigned int nr_vmas;
unsigned long premmapped_addr;
unsigned long premmapped_len;
diff --git a/pie/restorer.c b/pie/restorer.c
index b89d31c..4d23619 100644
--- a/pie/restorer.c
+++ b/pie/restorer.c
@@ -188,6 +188,7 @@ static int restore_gpregs(struct rt_sigframe *f, UserX86RegsEntry *r)
return 0;
}
+static int restore_signals(siginfo_t *info, int nr, int group);
static int restore_thread_common(struct rt_sigframe *sigframe,
struct thread_restore_args *args)
{
@@ -236,8 +237,11 @@ long __export_restore_thread(struct thread_restore_args *args)
pr_info("%ld: Restored\n", sys_gettid());
restore_finish_stage(CR_STATE_RESTORE);
- restore_finish_stage(CR_STATE_RESTORE_SIGCHLD);
+ if (restore_signals(args->siginfo, args->siginfo_nr, 0))
+ goto core_restore_end;
+
+ restore_finish_stage(CR_STATE_RESTORE_SIGCHLD);
futex_dec_and_wake(&thread_inprogress);
new_sp = (long)rt_sigframe + 8;
@@ -251,6 +255,7 @@ long __export_restore_thread(struct thread_restore_args *args)
: "rax","rsp","memory");
core_restore_end:
pr_err("Restorer abnormal termination for %ld\n", sys_getpid());
+ futex_abort_and_wake(&task_entries->nr_in_progress);
sys_exit_group(1);
return -1;
}
@@ -399,6 +404,36 @@ static int vma_remap(unsigned long src, unsigned long dst, unsigned long len)
return 0;
}
+static int restore_signals(siginfo_t *ptr, int nr, int group)
+{
+ int ret, i;
+ k_rtsigset_t to_block;
+
+ ksigfillset(&to_block);
+ ret = sys_sigprocmask(SIG_SETMASK, &to_block, NULL, sizeof(k_rtsigset_t));
+ if (ret) {
+ pr_err("Unable to block signals %d", ret);
+ return -1;
+ }
+
+ for (i = 0; i < nr; i++) {
+ siginfo_t *info = ptr + i;
+
+ pr_info("Restore signal %d group %d\n", info->si_signo, group);
+ if (group)
+ ret = sys_rt_sigqueueinfo(sys_getpid(), info->si_signo, info);
+ else
+ ret = sys_rt_tgsigqueueinfo(sys_getpid(),
+ sys_gettid(), info->si_signo, info);
+ if (ret) {
+ pr_err("Unable to send siginfo %d %x with code %d\n",
+ info->si_signo, info->si_code, ret);
+ return -1;;
+ }
+ }
+
+ return 0;
+}
/*
* The main routine to restore task via sigreturn.
* This one is very special, we never return there
@@ -749,6 +784,14 @@ long __export_restore_task(struct task_restore_core_args *args)
sys_sigaction(SIGCHLD, &args->sigchld_act, NULL, sizeof(rt_sigset_t));
+ ret = restore_signals(args->siginfo, args->siginfo_nr, 1);
+ if (ret)
+ goto core_restore_end;
+
+ ret = restore_signals(args->t.siginfo, args->t.siginfo_nr, 0);
+ if (ret)
+ goto core_restore_end;
+
futex_set_and_wake(&thread_inprogress, args->nr_threads);
restore_finish_stage(CR_STATE_RESTORE_SIGCHLD);
@@ -756,6 +799,14 @@ long __export_restore_task(struct task_restore_core_args *args)
/* Wait until children stop to use args->task_entries */
futex_wait_while_gt(&thread_inprogress, 1);
+ if (args->siginfo_size) {
+ ret = sys_munmap(args->siginfo, args->siginfo_size);
+ if (ret < 0) {
+ pr_err("Can't unmap signals %ld\n", ret);
+ goto core_restore_failed;
+ }
+ }
+
rst_tcp_socks_all(args->rst_tcp_socks, args->rst_tcp_socks_size);
log_set_fd(-1);
@@ -802,6 +853,7 @@ long __export_restore_task(struct task_restore_core_args *args)
: "rax","rsp","memory");
core_restore_end:
+ futex_abort_and_wake(&task_entries->nr_in_progress);
pr_err("Restorer fail %ld\n", sys_getpid());
sys_exit_group(1);
return -1;
--
1.7.11.7
More information about the CRIU
mailing list