[CRIU] [crtools-bot for Pavel Emelyanov ] dump: Collect mem+regs+sigmask atomically

Cyrill Gorcunov gorcunov at openvz.org
Mon Feb 20 03:33:43 EST 2012


The commit is pushed to "master" and will appear on git://github.com/cyrillos/crtools.git
------>
commit 097bc0b9672cf97c87efc203de0e2cc33fa20f19
Author: Pavel Emelyanov <xemul at parallels.com>
Date:   Fri Feb 17 22:56:36 2012 +0400

    dump: Collect mem+regs+sigmask atomically
    
    The ptrace seize doesn't prevent signals from delivery. That said,
    we should block the signals in the target task before dumping
    anything which is signals-related, i.e. memory and registers.
    
    But once we've blocked signals, we should dump registers before
    unblocking them, since any postponed signal will screw things up.
    
    Signed-off-by: Pavel Emelyanov <xemul at parallels.com>
    Signed-off-by: Cyrill Gorcunov <gorcunov at openvz.org>
---
 cr-dump.c               |   72 +++++++++++++++++------------------------------
 include/parasite.h      |    1 +
 include/syscall-codes.h |    1 +
 include/syscall.h       |    7 ++++
 include/types.h         |   16 ++++++++++
 parasite.c              |   16 ++++++++++-
 6 files changed, 66 insertions(+), 47 deletions(-)

diff --git a/cr-dump.c b/cr-dump.c
index 66f44ba..642755e 100644
--- a/cr-dump.c
+++ b/cr-dump.c
@@ -481,32 +481,6 @@ static int dump_task_creds(pid_t pid,
 #define assign_reg(dst, src, e)		dst.e = (__typeof__(dst.e))src.e
 #define assign_array(dst, src, e)	memcpy(&dst.e, &src.e, sizeof(dst.e))
 
-static int get_task_sigmask(pid_t pid, u64 *task_sigset)
-{
-	FILE *file;
-	int ret = -1;
-
-	/*
-	 * Now signals.
-	 */
-	file = fopen_proc(pid, "status");
-	if (!file)
-		goto err;
-
-	while (fgets(loc_buf, sizeof(loc_buf), file)) {
-		if (!strncmp(loc_buf, "SigBlk:", 7)) {
-			char *end;
-			*task_sigset = strtol(&loc_buf[8], &end, 16);
-			ret = 0;
-			break;
-		}
-	}
-
-	fclose(file);
-err:
-	return ret;
-}
-
 static int get_task_auxv(pid_t pid, struct core_entry *core)
 {
 	int fd = open_proc(pid, "auxv");
@@ -558,15 +532,19 @@ err:
 	return ret;
 }
 
-static int get_task_regs(pid_t pid, struct core_entry *core)
+static int get_task_regs(pid_t pid, struct core_entry *core, struct parasite_ctl *ctl)
 {
 	user_fpregs_struct_t fpregs	= {-1};
 	user_regs_struct_t regs		= {-1};
 	int ret = -1;
 
-	if (ptrace(PTRACE_GETREGS, pid, NULL, &regs)) {
-		pr_err("Can't obtain GP registers for %d\n", pid);
-		goto err;
+	if (ctl)
+		regs = ctl->regs_orig;
+	else {
+		if (ptrace(PTRACE_GETREGS, pid, NULL, &regs)) {
+			pr_err("Can't obtain GP registers for %d\n", pid);
+			goto err;
+		}
 	}
 
 	if (ptrace(PTRACE_GETFPREGS, pid, NULL, &fpregs)) {
@@ -658,7 +636,8 @@ static int dump_task_core(struct core_entry *core, struct cr_fdset *fdset)
 }
 
 static int dump_task_core_all(pid_t pid, struct proc_pid_stat *stat,
-		struct parasite_dump_misc *misc, struct cr_fdset *cr_fdset)
+		struct parasite_dump_misc *misc, struct parasite_ctl *ctl,
+		struct cr_fdset *cr_fdset)
 {
 	struct core_entry *core		= xzalloc(sizeof(*core));
 	int ret				= -1;
@@ -672,7 +651,7 @@ static int dump_task_core_all(pid_t pid, struct proc_pid_stat *stat,
 		goto err;
 
 	pr_info("Dumping GP/FPU registers ... ");
-	ret = get_task_regs(pid, core);
+	ret = get_task_regs(pid, core, ctl);
 	if (ret)
 		goto err_free;
 	pr_info("OK\n");
@@ -699,11 +678,8 @@ static int dump_task_core_all(pid_t pid, struct proc_pid_stat *stat,
 
 	core->tc.mm_brk = misc->brk;
 
-	pr_info("Obtainting sigmask ... ");
-	ret = get_task_sigmask(pid, &core->tc.blk_sigset);
-	if (ret)
-		goto err_free;
-	pr_info("OK\n");
+	BUILD_BUG_ON(sizeof(core->tc.blk_sigset) != sizeof(k_rtsigset_t));
+	memcpy(&core->tc.blk_sigset, &misc->blocked, sizeof(k_rtsigset_t));
 
 	pr_info("Obtainting task auvx ... ");
 	ret = get_task_auxv(pid, core);
@@ -1066,7 +1042,7 @@ static int dump_task_thread(pid_t pid, struct cr_fdset *cr_fdset)
 		goto err;
 
 	pr_info("Dumping GP/FPU registers ... ");
-	ret = get_task_regs(pid, core);
+	ret = get_task_regs(pid, core, NULL);
 	if (ret)
 		goto err_free;
 	if (ptrace(PTRACE_GET_TID_ADDRESS, pid, NULL, &core->clear_tid_address)) {
@@ -1204,6 +1180,18 @@ static int dump_one_task(struct pstree_item *item, struct cr_fdset *cr_fdset)
 		goto err;
 	}
 
+	ret = dump_task_core_all(pid, &pps_buf, &misc, parasite_ctl, cr_fdset);
+	if (ret) {
+		pr_err("Dump core (pid: %d) failed with %d\n", pid, ret);
+		goto err;
+	}
+
+	ret = dump_task_threads(item);
+	if (ret) {
+		pr_err("Can't dump threads\n");
+		goto err;
+	}
+
 	ret = parasite_cure_seized(parasite_ctl);
 	if (ret) {
 		pr_err("Can't cure (pid: %d) from parasite\n", pid);
@@ -1228,12 +1216,6 @@ static int dump_one_task(struct pstree_item *item, struct cr_fdset *cr_fdset)
 		goto err;
 	}
 
-	ret = dump_task_core_all(pid, &pps_buf, &misc, cr_fdset);
-	if (ret) {
-		pr_err("Dump core (pid: %d) failed with %d\n", pid, ret);
-		goto err;
-	}
-
 	ret = finalize_core(pid, &vma_area_list, cr_fdset);
 	if (ret) {
 		pr_err("Finalizing core (pid: %d) failed with %d\n", pid, ret);
@@ -1242,8 +1224,6 @@ static int dump_one_task(struct pstree_item *item, struct cr_fdset *cr_fdset)
 
 	free_mappings(&vma_area_list);
 
-	ret = dump_task_threads(item);
-
 err:
 	close_pid_proc();
 err_free:
diff --git a/include/parasite.h b/include/parasite.h
index 96b78c1..59eff7d 100644
--- a/include/parasite.h
+++ b/include/parasite.h
@@ -87,6 +87,7 @@ struct parasite_dump_misc {
 
 	unsigned int		secbits;
 	unsigned long		brk;
+	k_rtsigset_t		blocked;
 };
 
 /*
diff --git a/include/syscall-codes.h b/include/syscall-codes.h
index 28def99..2a470c6 100644
--- a/include/syscall-codes.h
+++ b/include/syscall-codes.h
@@ -13,6 +13,7 @@
 #define __NR_munmap		11
 #define __NR_brk		12
 #define __NR_rt_sigaction	13
+#define __NR_rt_sigprocmask	14
 #define __NR_rt_sigreturn	15
 #define __NR_mincore		27
 #define __NR_shmat		30
diff --git a/include/syscall.h b/include/syscall.h
index 02e5ee6..f759587 100644
--- a/include/syscall.h
+++ b/include/syscall.h
@@ -241,6 +241,13 @@ static always_inline long sys_rt_sigreturn(void)
 	return syscall0(__NR_rt_sigreturn);
 }
 
+static always_inline long sys_sigprocmask(int how, k_rtsigset_t *set,
+		k_rtsigset_t *old)
+{
+	return syscall4(__NR_rt_sigprocmask, how, (unsigned long)set,
+			(unsigned long)old, (unsigned long)sizeof(k_rtsigset_t));
+}
+
 static always_inline long sys_set_thread_area(user_desc_t *info)
 {
 	return syscall1(__NR_set_thread_area, (long)info);
diff --git a/include/types.h b/include/types.h
index 5d93dac..dea51e1 100644
--- a/include/types.h
+++ b/include/types.h
@@ -98,6 +98,22 @@ typedef struct {
 	rt_sigset_t	rt_sa_mask;
 } rt_sigaction_t;
 
+#define _KNSIG           64
+# define _NSIG_BPW      64
+
+#define _KNSIG_WORDS     (_KNSIG / _NSIG_BPW) 
+
+typedef struct {
+	unsigned long sig[_KNSIG_WORDS];
+} k_rtsigset_t;
+
+static inline void ksigfillset(k_rtsigset_t *set)
+{
+	int i;
+	for (i = 0; i < _KNSIG_WORDS; i++)
+		set->sig[i] = (unsigned long)-1;
+}
+
 typedef struct {
 	unsigned int	entry_number;
 	unsigned int	base_addr;
diff --git a/parasite.c b/parasite.c
index a77a94f..d77a24a 100644
--- a/parasite.c
+++ b/parasite.c
@@ -358,12 +358,16 @@ err_close:
 	return ret;
 }
 
+static k_rtsigset_t old_blocked;
+static int reset_blocked = 0;
+
 static int dump_misc(struct parasite_dump_misc *args)
 {
 	parasite_status_t *st = &args->status;
 
 	args->secbits = sys_prctl(PR_GET_SECUREBITS, 0, 0, 0, 0);
 	args->brk = sys_brk(0);
+	args->blocked = old_blocked;
 
 	SET_PARASITE_STATUS(st, 0, 0);
 	return 0;
@@ -372,6 +376,7 @@ static int dump_misc(struct parasite_dump_misc *args)
 static int init(struct parasite_init_args *args)
 {
 	int ret;
+	k_rtsigset_t to_block;
 
 	tsock = sys_socket(PF_UNIX, SOCK_DGRAM, 0);
 	if (tsock < 0) {
@@ -383,7 +388,14 @@ static int init(struct parasite_init_args *args)
 		return -1;
 	}
 
-	return 0;
+	ksigfillset(&to_block);
+	ret = sys_sigprocmask(SIG_SETMASK, &to_block, &old_blocked);
+	if (ret < 0)
+		reset_blocked = ret;
+	else
+		reset_blocked = 1;
+
+	return ret;
 }
 
 static int set_logfd()
@@ -394,6 +406,8 @@ static int set_logfd()
 
 static int fini()
 {
+	if (reset_blocked == 1)
+		sys_sigprocmask(SIG_SETMASK, &old_blocked, NULL);
 	sys_close(logfd);
 	sys_close(tsock);
 	return 0;


More information about the CRIU mailing list