[CRIU] [PATCH 8/9] parasite: use only one command for executing parasite in a daemon mode

Andrey Vagin avagin at openvz.org
Fri Jun 21 00:01:14 EDT 2013


If a kernel supports PTRACE_SETSIGMASK, criu don't need to execute
PARASITE_CMD_INIT and PARASITE_CMD_DAEMONIZE, because the frist command
is used only for blocking signals. If criu crashes between these
commands, a process state will be corrupted, because all signals remain
blocked.

Signed-off-by: Andrey Vagin <avagin at openvz.org>
---
 include/parasite.h |  3 ++
 parasite-syscall.c | 95 ++++++++++++++++++++++++++++++++++++++++++++++++++++--
 pie/parasite.c     | 38 ++++++++++++++++++++++
 3 files changed, 134 insertions(+), 2 deletions(-)

diff --git a/include/parasite.h b/include/parasite.h
index 25bb7b9..18716b1 100644
--- a/include/parasite.h
+++ b/include/parasite.h
@@ -23,6 +23,7 @@ enum {
 
 	PARASITE_CMD_INIT,
 	PARASITE_CMD_INIT_THREAD,
+	PARASITE_CMD_INIT_DAEMON,
 
 	/*
 	 * These two must be greater than INITs.
@@ -66,6 +67,8 @@ struct parasite_init_args {
 	int			h_addr_len;
 	struct sockaddr_un	h_addr;
 
+	int log_level;
+
 	k_rtsigset_t		sig_blocked;
 
 	struct rt_sigframe	*sigframe;
diff --git a/parasite-syscall.c b/parasite-syscall.c
index bcbcf6b..1d4d72b 100644
--- a/parasite-syscall.c
+++ b/parasite-syscall.c
@@ -456,6 +456,72 @@ err:
 	return -1;
 }
 
+static int parasite_init_daemon(struct parasite_ctl *ctl)
+{
+	struct parasite_init_args *args;
+	pid_t pid = ctl->pid.real;
+	user_regs_struct_t regs;
+	struct ctl_msg m = { };
+	k_rtsigset_t blockall;
+
+	ksigfillset(&blockall);
+
+	*ctl->addr_cmd = PARASITE_CMD_INIT_DAEMON;
+
+	args = parasite_args(ctl, struct parasite_init_args);
+
+	args->sigframe = ctl->rsigframe;
+	args->log_level = log_get_loglevel();
+
+	if (prepare_tsock(ctl, pid, args))
+		goto err;;
+
+	regs = ctl->regs_orig;
+	parasite_setup_regs(ctl->parasite_ip, ctl->rstack, &regs);
+
+	if (ptrace(PTRACE_SETREGS, pid, NULL, &regs)) {
+		pr_perror("Can't set registers (pid: %d)", pid);
+		goto err;
+	}
+
+	if (ptrace(PTRACE_SETSIGMASK, pid, sizeof(k_rtsigset_t), &blockall)) {
+		pr_perror("Can't block signals");
+		goto err_regs;
+	}
+
+	if (ptrace(PTRACE_CONT, pid, NULL, NULL)) {
+		pr_perror("Can't continue (pid: %d)\n", pid);
+		goto err_mask;
+	}
+
+	ctl->tsock = accept_tsock();
+	if (ctl->tsock < 0)
+		goto err;
+
+	if (parasite_send_fd(ctl, log_get_fd()))
+		goto err;
+
+	pr_info("Wait for parasite being daemonized...\n");
+
+	if (parasite_wait_ack(ctl->tsock, PARASITE_CMD_DAEMONIZE, &m)) {
+		pr_err("Can't switch parasite %d to daemon mode %d\n",
+		       pid, m.err);
+		goto err;
+	}
+
+	ctl->daemonized = true;
+	pr_info("Parasite %d has been switched to daemon mode\n", pid);
+	return 0;
+
+err_mask:
+	ptrace(PTRACE_SETSIGMASK, pid, sizeof(k_rtsigset_t),
+				&RT_SIGFRAME_UC(ctl->sigframe).uc_sigmask);
+err_regs:
+	ptrace(PTRACE_SETREGS, pid, NULL, ctl->regs_orig);
+err:
+	return -1;
+}
+
 static int parasite_daemonize(struct parasite_ctl *ctl)
 {
 	pid_t pid = ctl->pid.real;
@@ -1093,6 +1159,26 @@ static int parasite_start_in_two_stages(struct parasite_ctl *ctl, struct pstree_
 	return 0;
 }
 
+static int parasite_start_in_one_stage(struct parasite_ctl *ctl, struct pstree_item *item)
+{
+	pid_t pid = ctl->pid.real;
+	int ret;
+
+	ret = get_task_regs(pid, ctl->regs_orig, item->core[0]);
+	if (ret) {
+		pr_err("Can't obtain regs for thread %d\n", pid);
+		return -1;
+	}
+
+	if (construct_sigframe(ctl->sigframe, ctl->rsigframe, item->core[0]))
+		return -1;
+
+	if (parasite_init_daemon(ctl))
+		return -1;;
+
+	return 0;
+}
+
 struct parasite_ctl *parasite_infect_seized(pid_t pid, struct pstree_item *item,
 		struct vm_area_list *vma_area_list, struct parasite_drain_fd *dfds)
 {
@@ -1160,8 +1246,13 @@ struct parasite_ctl *parasite_infect_seized(pid_t pid, struct pstree_item *item,
 		p += PARASITE_STACK_SIZE;
 	}
 
-	if (parasite_start_in_two_stages(ctl, item))
-		goto err_restore;
+	if (sigmask) {
+		if (parasite_start_in_one_stage(ctl, item))
+			goto err_restore;
+	} else {
+		if (parasite_start_in_two_stages(ctl, item))
+			goto err_restore;
+	}
 
 	return ctl;
 
diff --git a/pie/parasite.c b/pie/parasite.c
index 2644f87..bb63562 100644
--- a/pie/parasite.c
+++ b/pie/parasite.c
@@ -544,6 +544,42 @@ out:
 	return 0;
 }
 
+static noinline __used int parasite_init_daemon(void *data)
+{
+	struct parasite_init_args *args = data;
+	int ret;
+
+	sigframe = args->sigframe;
+
+	tsock = sys_socket(PF_UNIX, SOCK_STREAM, 0);
+	if (tsock < 0) {
+		pr_err("Can't create socket: %d\n", tsock);
+		goto err;
+	}
+
+	ret = sys_connect(tsock, (struct sockaddr *)&args->h_addr, args->h_addr_len);
+	if (ret < 0) {
+		pr_err("Can't connect the control socket\n");
+		goto err;
+	}
+
+	ret = recv_fd(tsock);
+	if (ret >= 0) {
+		log_set_fd(ret);
+		log_set_loglevel(args->log_level);
+		ret = 0;
+	} else
+		goto err;
+
+	parasite_daemon(data);
+
+err:
+	fini();
+	BUG();
+
+	return -1;
+}
+
 int __used parasite_service(unsigned int cmd, void *args)
 {
 	pr_info("Parasite cmd %d/%x process\n", cmd, cmd);
@@ -561,6 +597,8 @@ int __used parasite_service(unsigned int cmd, void *args)
 		return parasite_cfg_log(args);
 	case PARASITE_CMD_DAEMONIZE:
 		return parasite_daemon(args);
+	case PARASITE_CMD_INIT_DAEMON:
+		return parasite_init_daemon(args);
 	}
 
 	pr_err("Unknown command to parasite: %d\n", cmd);
-- 
1.8.2.1



More information about the CRIU mailing list