Commit f3f72cd7 authored by Andrey Vagin's avatar Andrey Vagin Committed by Pavel Emelyanov

parasite: use only one command for executing parasite in a daemon mode

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: 's avatarAndrey Vagin <avagin@openvz.org>
Signed-off-by: 's avatarPavel Emelyanov <xemul@parallels.com>
parent 45ed5c0e
...@@ -23,16 +23,14 @@ enum { ...@@ -23,16 +23,14 @@ enum {
PARASITE_CMD_IDLE = 0, PARASITE_CMD_IDLE = 0,
PARASITE_CMD_ACK, PARASITE_CMD_ACK,
PARASITE_CMD_INIT, PARASITE_CMD_INIT_DAEMON,
PARASITE_CMD_DUMP_THREAD, PARASITE_CMD_DUMP_THREAD,
/* /*
* These two must be greater than INITs. * These two must be greater than INITs.
*/ */
PARASITE_CMD_DAEMONIZE,
PARASITE_CMD_DAEMONIZED, PARASITE_CMD_DAEMONIZED,
PARASITE_CMD_CFG_LOG,
PARASITE_CMD_FINI, PARASITE_CMD_FINI,
PARASITE_CMD_MPROTECT_VMAS, PARASITE_CMD_MPROTECT_VMAS,
...@@ -67,15 +65,11 @@ struct parasite_init_args { ...@@ -67,15 +65,11 @@ struct parasite_init_args {
int h_addr_len; int h_addr_len;
struct sockaddr_un h_addr; struct sockaddr_un h_addr;
k_rtsigset_t sig_blocked; int log_level;
struct rt_sigframe *sigframe; struct rt_sigframe *sigframe;
}; };
struct parasite_log_args {
int log_level;
};
struct parasite_vma_entry struct parasite_vma_entry
{ {
unsigned long start; unsigned long start;
......
...@@ -202,13 +202,6 @@ static int parasite_execute_trap_by_pid(unsigned int cmd, ...@@ -202,13 +202,6 @@ static int parasite_execute_trap_by_pid(unsigned int cmd,
return ret; return ret;
} }
static int parasite_execute_trap(unsigned int cmd, struct parasite_ctl *ctl)
{
return parasite_execute_trap_by_pid(cmd, ctl, ctl->pid.real,
&ctl->regs_orig, ctl->rstack,
&ctl->sig_blocked);
}
static int __parasite_send_cmd(int sockfd, struct ctl_msg *m) static int __parasite_send_cmd(int sockfd, struct ctl_msg *m)
{ {
int ret; int ret;
...@@ -328,25 +321,6 @@ int parasite_send_fd(struct parasite_ctl *ctl, int fd) ...@@ -328,25 +321,6 @@ int parasite_send_fd(struct parasite_ctl *ctl, int fd)
return 0; return 0;
} }
static int parasite_set_logfd(struct parasite_ctl *ctl, pid_t pid)
{
int ret;
struct parasite_log_args *a;
ret = parasite_send_fd(ctl, log_get_fd());
if (ret)
return ret;
a = parasite_args(ctl, struct parasite_log_args);
a->log_level = log_get_loglevel();
ret = parasite_execute_trap(PARASITE_CMD_CFG_LOG, ctl);
if (ret < 0)
return ret;
return 0;
}
static int ssock = -1; static int ssock = -1;
static int prepare_tsock(struct parasite_ctl *ctl, pid_t pid, static int prepare_tsock(struct parasite_ctl *ctl, pid_t pid,
...@@ -404,35 +378,9 @@ static int accept_tsock() ...@@ -404,35 +378,9 @@ static int accept_tsock()
return sock; return sock;
} }
static int parasite_init(struct parasite_ctl *ctl, pid_t pid, struct pstree_item *item) static int parasite_init_daemon(struct parasite_ctl *ctl)
{ {
struct parasite_init_args *args; struct parasite_init_args *args;
int sock;
args = parasite_args(ctl, struct parasite_init_args);
args->sigframe = ctl->rsigframe;
if (prepare_tsock(ctl, pid, args))
goto err;
if (parasite_execute_trap(PARASITE_CMD_INIT, ctl) < 0) {
pr_err("Can't init parasite\n");
goto err;
}
sock = accept_tsock();
if (sock < 0)
goto err;
ctl->tsock = sock;
return 0;
err:
return -1;
}
static int parasite_daemonize(struct parasite_ctl *ctl)
{
pid_t pid = ctl->pid.real; pid_t pid = ctl->pid.real;
user_regs_struct_t regs; user_regs_struct_t regs;
struct ctl_msg m = { }; struct ctl_msg m = { };
...@@ -440,7 +388,15 @@ static int parasite_daemonize(struct parasite_ctl *ctl) ...@@ -440,7 +388,15 @@ static int parasite_daemonize(struct parasite_ctl *ctl)
ksigfillset(&blockall); ksigfillset(&blockall);
*ctl->addr_cmd = PARASITE_CMD_DAEMONIZE; *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; regs = ctl->regs_orig;
parasite_setup_regs(ctl->parasite_ip, ctl->rstack, &regs); parasite_setup_regs(ctl->parasite_ip, ctl->rstack, &regs);
...@@ -452,18 +408,24 @@ static int parasite_daemonize(struct parasite_ctl *ctl) ...@@ -452,18 +408,24 @@ static int parasite_daemonize(struct parasite_ctl *ctl)
if (ptrace(PTRACE_SETSIGMASK, pid, sizeof(k_rtsigset_t), &blockall)) { if (ptrace(PTRACE_SETSIGMASK, pid, sizeof(k_rtsigset_t), &blockall)) {
pr_perror("Can't block signals"); pr_perror("Can't block signals");
goto err; goto err_regs;
} }
if (ptrace(PTRACE_CONT, pid, NULL, NULL)) { if (ptrace(PTRACE_CONT, pid, NULL, NULL)) {
pr_perror("Can't continue (pid: %d)\n", pid); pr_perror("Can't continue (pid: %d)\n", pid);
ptrace(PTRACE_SETREGS, pid, NULL, ctl->regs_orig); goto err_mask;
goto err;
} }
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"); pr_info("Wait for parasite being daemonized...\n");
if (parasite_wait_ack(ctl->tsock, PARASITE_CMD_DAEMONIZE, &m)) { if (parasite_wait_ack(ctl->tsock, PARASITE_CMD_INIT_DAEMON, &m)) {
pr_err("Can't switch parasite %d to daemon mode %d\n", pr_err("Can't switch parasite %d to daemon mode %d\n",
pid, m.err); pid, m.err);
goto err; goto err;
...@@ -473,10 +435,12 @@ static int parasite_daemonize(struct parasite_ctl *ctl) ...@@ -473,10 +435,12 @@ static int parasite_daemonize(struct parasite_ctl *ctl)
pr_info("Parasite %d has been switched to daemon mode\n", pid); pr_info("Parasite %d has been switched to daemon mode\n", pid);
return 0; 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: err:
if (ptrace(PTRACE_SETSIGMASK, pid, sizeof(k_rtsigset_t), ctl->sig_blocked))
pr_perror("Can't block signals");
return -1; return -1;
} }
...@@ -1000,6 +964,24 @@ static unsigned long parasite_args_size(struct vm_area_list *vmas, struct parasi ...@@ -1000,6 +964,24 @@ static unsigned long parasite_args_size(struct vm_area_list *vmas, struct parasi
return round_up(size, PAGE_SIZE); return round_up(size, PAGE_SIZE);
} }
static int parasite_start_daemon(struct parasite_ctl *ctl, struct pstree_item *item)
{
pid_t pid = ctl->pid.real;
if (get_task_regs(pid, ctl->regs_orig, item->core[0])) {
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 parasite_ctl *parasite_infect_seized(pid_t pid, struct pstree_item *item,
struct vm_area_list *vma_area_list, struct parasite_drain_fd *dfds, struct vm_area_list *vma_area_list, struct parasite_drain_fd *dfds,
int timer_n) int timer_n)
...@@ -1059,28 +1041,7 @@ struct parasite_ctl *parasite_infect_seized(pid_t pid, struct pstree_item *item, ...@@ -1059,28 +1041,7 @@ struct parasite_ctl *parasite_infect_seized(pid_t pid, struct pstree_item *item,
p += PARASITE_STACK_SIZE; p += PARASITE_STACK_SIZE;
} }
ret = parasite_init(ctl, pid, item); if (parasite_start_daemon(ctl, item))
if (ret) {
pr_err("%d: Can't create a transport socket\n", pid);
goto err_restore;
}
ret = get_task_regs(pid, ctl->regs_orig, item->core[0]);
if (ret) {
pr_err("Can't obtain regs for thread %d\n", pid);
goto err_restore;
}
ret = parasite_set_logfd(ctl, pid);
if (ret) {
pr_err("%d: Can't set a logging descriptor\n", pid);
goto err_restore;
}
if (construct_sigframe(ctl->sigframe, ctl->rsigframe, item->core[0]))
goto err_restore;
if (parasite_daemonize(ctl))
goto err_restore; goto err_restore;
return ctl; return ctl;
...@@ -1089,4 +1050,3 @@ err_restore: ...@@ -1089,4 +1050,3 @@ err_restore:
parasite_cure_seized(ctl); parasite_cure_seized(ctl);
return NULL; return NULL;
} }
...@@ -220,37 +220,6 @@ static int dump_thread(struct parasite_dump_thread *args) ...@@ -220,37 +220,6 @@ static int dump_thread(struct parasite_dump_thread *args)
return ret; return ret;
} }
static int init(struct parasite_init_args *args)
{
k_rtsigset_t to_block;
int ret;
sigframe = args->sigframe;
ksigfillset(&to_block);
ret = sys_sigprocmask(SIG_SETMASK, &to_block,
&args->sig_blocked,
sizeof(k_rtsigset_t));
if (ret)
return -1;
tsock = sys_socket(PF_UNIX, SOCK_STREAM, 0);
if (tsock < 0) {
ret = tsock;
goto err;
}
ret = sys_connect(tsock, (struct sockaddr *)&args->h_addr, args->h_addr_len);
if (ret < 0)
goto err;
return 0;
err:
sys_sigprocmask(SIG_SETMASK, &args->sig_blocked,
NULL, sizeof(k_rtsigset_t));
return ret;
}
static char proc_mountpoint[] = "proc.crtools"; static char proc_mountpoint[] = "proc.crtools";
static int parasite_get_proc_fd() static int parasite_get_proc_fd()
{ {
...@@ -369,20 +338,6 @@ err: ...@@ -369,20 +338,6 @@ err:
return 0; return 0;
} }
static int parasite_cfg_log(struct parasite_log_args *args)
{
int ret;
ret = recv_fd(tsock);
if (ret >= 0) {
log_set_fd(ret);
log_set_loglevel(args->log_level);
ret = 0;
}
return ret;
}
static int parasite_check_vdso_mark(struct parasite_vdso_vma_entry *args) static int parasite_check_vdso_mark(struct parasite_vdso_vma_entry *args)
{ {
struct vdso_mark *m = (void *)args->start; struct vdso_mark *m = (void *)args->start;
...@@ -471,7 +426,7 @@ static noinline __used int noinline parasite_daemon(void *args) ...@@ -471,7 +426,7 @@ static noinline __used int noinline parasite_daemon(void *args)
pr_debug("Running daemon thread leader\n"); pr_debug("Running daemon thread leader\n");
/* Reply we're alive */ /* Reply we're alive */
if (__parasite_daemon_reply_ack(PARASITE_CMD_DAEMONIZE, 0)) if (__parasite_daemon_reply_ack(PARASITE_CMD_INIT_DAEMON, 0))
goto out; goto out;
ret = 0; ret = 0;
...@@ -542,19 +497,51 @@ out: ...@@ -542,19 +497,51 @@ out:
return 0; 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) int __used parasite_service(unsigned int cmd, void *args)
{ {
pr_info("Parasite cmd %d/%x process\n", cmd, cmd); pr_info("Parasite cmd %d/%x process\n", cmd, cmd);
switch (cmd) { switch (cmd) {
case PARASITE_CMD_INIT:
return init(args);
case PARASITE_CMD_DUMP_THREAD: case PARASITE_CMD_DUMP_THREAD:
return dump_thread(args); return dump_thread(args);
case PARASITE_CMD_CFG_LOG: case PARASITE_CMD_INIT_DAEMON:
return parasite_cfg_log(args); return parasite_init_daemon(args);
case PARASITE_CMD_DAEMONIZE:
return parasite_daemon(args);
} }
pr_err("Unknown command to parasite: %d\n", cmd); pr_err("Unknown command to parasite: %d\n", cmd);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment