[CRIU] [PATCH 08/12] crtools: restore pending signals

Andrey Vagin avagin at openvz.org
Tue Dec 18 01:36:11 EST 2012


Read siginfo-s from images and send them to itself by sigqueueinfo.

Signed-off-by: Andrey Vagin <avagin at openvz.org>
---
 cr-restore.c       | 116 ++++++++++++++++++++++++++++++++++++++++++++++++++++-
 include/restorer.h |   6 +++
 pie/restorer.c     |  54 ++++++++++++++++++++++++-
 3 files changed, 173 insertions(+), 3 deletions(-)

diff --git a/cr-restore.c b/cr-restore.c
index 1b39f97..e6b7cdf 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,54 @@ 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;
+
+			*ptr = mremap(*ptr, *size, new_size, MREMAP_MAYMOVE);
+			if (*ptr == MAP_FAILED) {
+				pr_perror("mremap");
+				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 +1645,9 @@ 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;
+	int siginfo_nr = 0;
+	unsigned long siginfo_size = PAGE_SIZE;
 
 	LIST_HEAD(self_vma_list);
 	int i;
@@ -1644,12 +1696,55 @@ static int sigreturn_restore(pid_t pid, CoreEntry *core)
 	task_args	= mem;
 	thread_args	= mem + restore_task_vma_len;
 
+	siginfo_chunk = mmap(NULL, siginfo_size, PROT_READ | PROT_WRITE,
+						MAP_PRIVATE | MAP_ANON, 0, 0);
+	if (mem == MAP_FAILED) {
+		pr_err("Can't allocate memory for siginfo-s\n");
+		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;
+	}
+	task_args->siginfo_nr = ret;
+
+	ret = open_signal_image(CR_FD_PSIGNAL, pid, &siginfo_chunk,
+					&siginfo_size, &siginfo_nr);
+	if (ret < 0) {
+		if (errno != ENOENT) /* backward compatiblity */
+			goto err;
+		ret = 0;
+	}
+	task_args->t.siginfo_nr = ret;
+
+	for (i = 0; i < current->nr_threads; i++) {
+		thread_args[i].pid = current->threads[i].virt;
+		/* skip self */
+		if (thread_args[i].pid == pid)
+			continue;
+
+		ret = open_signal_image(CR_FD_PSIGNAL,
+					thread_args[i].pid, &siginfo_chunk,
+					&siginfo_size, &siginfo_nr);
+		if (ret < 0) {
+			if (errno != ENOENT) /* backward compatiblity */
+				goto err;
+			ret = 0;
+		}
+		thread_args[i].siginfo_nr = 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
@@ -1698,6 +1793,20 @@ 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;
+	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 = siginfo_chunk;
+	siginfo_chunk += task_args->siginfo_nr;
+	task_args->t.siginfo = siginfo_chunk;
+	siginfo_chunk += task_args->t.siginfo_nr;
+	task_args->siginfo_size = siginfo_size;
+
 	/*
 	 * Adjust stack.
 	 */
@@ -1715,7 +1824,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;
@@ -1811,6 +1920,9 @@ static int sigreturn_restore(pid_t pid, CoreEntry *core)
 		if (thread_args[i].pid == pid)
 			continue;
 
+		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) {
 			pr_err("Can't open core data for thread %d\n",
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