[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, ®s);
+
+ if (ptrace(PTRACE_SETREGS, pid, NULL, ®s)) {
+ 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