mirror of
https://github.com/checkpoint-restore/criu
synced 2025-08-31 06:15:24 +00:00
parasite: remove code which used for daemonized threads
Signed-off-by: Andrey Vagin <avagin@openvz.org> Signed-off-by: Pavel Emelyanov <xemul@parallels.com>
This commit is contained in:
committed by
Pavel Emelyanov
parent
08377fe90b
commit
11d3adbf56
@@ -10,8 +10,6 @@ struct parasite_thread_ctl
|
|||||||
pid_t tid;
|
pid_t tid;
|
||||||
user_regs_struct_t regs_orig; /* original registers */
|
user_regs_struct_t regs_orig; /* original registers */
|
||||||
|
|
||||||
bool daemonized;
|
|
||||||
|
|
||||||
k_rtsigset_t sig_blocked;
|
k_rtsigset_t sig_blocked;
|
||||||
bool use_sig_blocked;
|
bool use_sig_blocked;
|
||||||
|
|
||||||
@@ -27,6 +25,8 @@ struct parasite_ctl {
|
|||||||
void *local_map;
|
void *local_map;
|
||||||
unsigned long map_length;
|
unsigned long map_length;
|
||||||
|
|
||||||
|
bool daemonized;
|
||||||
|
|
||||||
unsigned long parasite_ip; /* service routine start ip */
|
unsigned long parasite_ip; /* service routine start ip */
|
||||||
unsigned long syscall_ip; /* entry point of infection */
|
unsigned long syscall_ip; /* entry point of infection */
|
||||||
u8 code_orig[BUILTIN_SYSCALL_SIZE];
|
u8 code_orig[BUILTIN_SYSCALL_SIZE];
|
||||||
@@ -52,11 +52,10 @@ extern int parasite_dump_itimers_seized(struct parasite_ctl *ctl, struct cr_fdse
|
|||||||
void *parasite_args_s(struct parasite_ctl *ctl, int args_size);
|
void *parasite_args_s(struct parasite_ctl *ctl, int args_size);
|
||||||
int parasite_execute_daemon(unsigned int cmd, struct parasite_ctl *ctl);
|
int parasite_execute_daemon(unsigned int cmd, struct parasite_ctl *ctl);
|
||||||
int parasite_send_fd(struct parasite_ctl *ctl, int fd);
|
int parasite_send_fd(struct parasite_ctl *ctl, int fd);
|
||||||
int __parasite_execute_daemon_by_id(unsigned int cmd,
|
int __parasite_execute_daemon(unsigned int cmd,
|
||||||
struct parasite_ctl *ctl,
|
struct parasite_ctl *ctl, bool wait_ack);
|
||||||
int id, bool wait_ack);
|
|
||||||
int __parasite_execute_daemon_wait_ack(unsigned int cmd,
|
int __parasite_execute_daemon_wait_ack(unsigned int cmd,
|
||||||
struct parasite_ctl *ctl, int id);
|
struct parasite_ctl *ctl);
|
||||||
|
|
||||||
struct parasite_dump_misc;
|
struct parasite_dump_misc;
|
||||||
struct vm_area_list;
|
struct vm_area_list;
|
||||||
|
@@ -51,17 +51,16 @@ enum {
|
|||||||
};
|
};
|
||||||
|
|
||||||
struct ctl_msg {
|
struct ctl_msg {
|
||||||
unsigned int id; /* command recipient */
|
|
||||||
unsigned int cmd; /* command itself */
|
unsigned int cmd; /* command itself */
|
||||||
unsigned int ack; /* ack on command */
|
unsigned int ack; /* ack on command */
|
||||||
int err; /* error code on reply */
|
int err; /* error code on reply */
|
||||||
};
|
};
|
||||||
|
|
||||||
#define ctl_msg_cmd(_id, _cmd) \
|
#define ctl_msg_cmd(_cmd) \
|
||||||
(struct ctl_msg){ .id = _id, .cmd = _cmd, }
|
(struct ctl_msg){.cmd = _cmd, }
|
||||||
|
|
||||||
#define ctl_msg_ack(_id, _cmd, _err) \
|
#define ctl_msg_ack(_cmd, _err) \
|
||||||
(struct ctl_msg){ .id = _id, .cmd = _cmd, .ack = _cmd, .err = _err, }
|
(struct ctl_msg){.cmd = _cmd, .ack = _cmd, .err = _err, }
|
||||||
|
|
||||||
struct parasite_init_args {
|
struct parasite_init_args {
|
||||||
int id;
|
int id;
|
||||||
|
4
mem.c
4
mem.c
@@ -373,14 +373,14 @@ static int __parasite_dump_pages_seized(struct parasite_ctl *ctl,
|
|||||||
pr_debug("PPB: %d pages %d segs %u pipe %d off\n",
|
pr_debug("PPB: %d pages %d segs %u pipe %d off\n",
|
||||||
args->nr_pages, args->nr_segs, ppb->pipe_size, args->off);
|
args->nr_pages, args->nr_segs, ppb->pipe_size, args->off);
|
||||||
|
|
||||||
ret = __parasite_execute_daemon_by_id(PARASITE_CMD_DUMPPAGES, ctl, 0, false);
|
ret = __parasite_execute_daemon(PARASITE_CMD_DUMPPAGES, ctl, false);
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
goto out_pp;
|
goto out_pp;
|
||||||
ret = parasite_send_fd(ctl, ppb->p[1]);
|
ret = parasite_send_fd(ctl, ppb->p[1]);
|
||||||
if (ret)
|
if (ret)
|
||||||
goto out_pp;
|
goto out_pp;
|
||||||
|
|
||||||
ret = __parasite_execute_daemon_wait_ack(PARASITE_CMD_DUMPPAGES, ctl, 0);
|
ret = __parasite_execute_daemon_wait_ack(PARASITE_CMD_DUMPPAGES, ctl);
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
goto out_pp;
|
goto out_pp;
|
||||||
|
|
||||||
|
@@ -253,7 +253,7 @@ static int __parasite_send_cmd(int sockfd, struct ctl_msg *m)
|
|||||||
|
|
||||||
ret = send(sockfd, m, sizeof(*m), 0);
|
ret = send(sockfd, m, sizeof(*m), 0);
|
||||||
if (ret == -1) {
|
if (ret == -1) {
|
||||||
pr_perror("Failed to send command %d to daemon %d\n", m->cmd, m->id);
|
pr_perror("Failed to send command %d to daemon\n", m->cmd);
|
||||||
return -1;
|
return -1;
|
||||||
} else if (ret != sizeof(*m)) {
|
} else if (ret != sizeof(*m)) {
|
||||||
pr_err("Message to daemon is trimmed (%d/%d)\n",
|
pr_err("Message to daemon is trimmed (%d/%d)\n",
|
||||||
@@ -261,32 +261,32 @@ static int __parasite_send_cmd(int sockfd, struct ctl_msg *m)
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
pr_debug("Sent msg to daemon %d %d %d %d\n", m->id, m->cmd, m->ack, m->err);
|
pr_debug("Sent msg to daemon %d %d %d\n", m->cmd, m->ack, m->err);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int parasite_wait_ack(int sockfd, int id, unsigned int cmd, struct ctl_msg *m)
|
static int parasite_wait_ack(int sockfd, unsigned int cmd, struct ctl_msg *m)
|
||||||
{
|
{
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
pr_debug("Wait for ack %d-%d on daemon socket\n", id, cmd);
|
pr_debug("Wait for ack %d on daemon socket\n", cmd);
|
||||||
|
|
||||||
while (1) {
|
while (1) {
|
||||||
memzero(m, sizeof(*m));
|
memzero(m, sizeof(*m));
|
||||||
|
|
||||||
ret = recv(sockfd, m, sizeof(*m), MSG_WAITALL);
|
ret = recv(sockfd, m, sizeof(*m), MSG_WAITALL);
|
||||||
if (ret == -1) {
|
if (ret == -1) {
|
||||||
pr_perror("Failed to read ack from %d", id);
|
pr_perror("Failed to read ack");
|
||||||
return -1;
|
return -1;
|
||||||
} else if (ret != sizeof(*m)) {
|
} else if (ret != sizeof(*m)) {
|
||||||
pr_err("Message reply from daemon is trimmed (%d/%d)\n",
|
pr_err("Message reply from daemon is trimmed (%d/%d)\n",
|
||||||
(int)sizeof(*m), ret);
|
(int)sizeof(*m), ret);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
pr_debug("Fetched ack: %d %d %d %d\n",
|
pr_debug("Fetched ack: %d %d %d\n",
|
||||||
m->id, m->cmd, m->ack, m->err);
|
m->cmd, m->ack, m->err);
|
||||||
|
|
||||||
if (m->id != id || m->cmd != cmd || m->ack != cmd) {
|
if (m->cmd != cmd || m->ack != cmd) {
|
||||||
pr_err("Communication error, this is not "
|
pr_err("Communication error, this is not "
|
||||||
"the ack we expected\n");
|
"the ack we expected\n");
|
||||||
return -1;
|
return -1;
|
||||||
@@ -298,46 +298,41 @@ static int parasite_wait_ack(int sockfd, int id, unsigned int cmd, struct ctl_ms
|
|||||||
}
|
}
|
||||||
|
|
||||||
int __parasite_execute_daemon_wait_ack(unsigned int cmd,
|
int __parasite_execute_daemon_wait_ack(unsigned int cmd,
|
||||||
struct parasite_ctl *ctl, int id)
|
struct parasite_ctl *ctl)
|
||||||
{
|
{
|
||||||
struct ctl_msg m;
|
struct ctl_msg m;
|
||||||
|
|
||||||
if (parasite_wait_ack(ctl->tsock, id, cmd, &m))
|
if (parasite_wait_ack(ctl->tsock, cmd, &m))
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
if (m.err != 0) {
|
if (m.err != 0) {
|
||||||
pr_err("Command %d for daemon %d failed with %d\n",
|
pr_err("Command %d for daemon failed with %d\n",
|
||||||
cmd, id, m.err);
|
cmd, m.err);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int __parasite_execute_daemon_by_id(unsigned int cmd,
|
int __parasite_execute_daemon(unsigned int cmd,
|
||||||
struct parasite_ctl *ctl, int id, bool wait_ack)
|
struct parasite_ctl *ctl, bool wait_ack)
|
||||||
{
|
{
|
||||||
struct ctl_msg m;
|
struct ctl_msg m;
|
||||||
|
|
||||||
m = ctl_msg_cmd(id, cmd);
|
m = ctl_msg_cmd(cmd);
|
||||||
if (__parasite_send_cmd(ctl->tsock, &m))
|
if (__parasite_send_cmd(ctl->tsock, &m))
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
if (wait_ack)
|
if (wait_ack)
|
||||||
return __parasite_execute_daemon_wait_ack(cmd, ctl, id);
|
return __parasite_execute_daemon_wait_ack(cmd, ctl);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int parasite_execute_daemon_by_id(unsigned int cmd,
|
int parasite_execute_daemon(unsigned int cmd,
|
||||||
struct parasite_ctl *ctl, int id)
|
struct parasite_ctl *ctl)
|
||||||
{
|
{
|
||||||
return __parasite_execute_daemon_by_id(cmd, ctl, id, true);
|
return __parasite_execute_daemon(cmd, ctl, true);
|
||||||
}
|
|
||||||
|
|
||||||
int parasite_execute_daemon(unsigned int cmd, struct parasite_ctl *ctl)
|
|
||||||
{
|
|
||||||
return parasite_execute_daemon_by_id(cmd, ctl, 0);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int munmap_seized(struct parasite_ctl *ctl, void *addr, size_t length)
|
static int munmap_seized(struct parasite_ctl *ctl, void *addr, size_t length)
|
||||||
@@ -493,13 +488,13 @@ static int parasite_daemonize(struct parasite_ctl *ctl, int id)
|
|||||||
|
|
||||||
pr_info("Wait for parasite being daemonized...\n");
|
pr_info("Wait for parasite being daemonized...\n");
|
||||||
|
|
||||||
if (parasite_wait_ack(ctl->tsock, id, PARASITE_CMD_DAEMONIZE, &m)) {
|
if (parasite_wait_ack(ctl->tsock, PARASITE_CMD_DAEMONIZE, &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;
|
||||||
}
|
}
|
||||||
|
|
||||||
thread->daemonized = true;
|
ctl->daemonized = true;
|
||||||
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;
|
||||||
|
|
||||||
@@ -684,8 +679,7 @@ int parasite_drain_fds_seized(struct parasite_ctl *ctl,
|
|||||||
args = parasite_args_s(ctl, size);
|
args = parasite_args_s(ctl, size);
|
||||||
memcpy(args, dfds, size);
|
memcpy(args, dfds, size);
|
||||||
|
|
||||||
ret = __parasite_execute_daemon_by_id(PARASITE_CMD_DRAIN_FDS, ctl,
|
ret = __parasite_execute_daemon(PARASITE_CMD_DRAIN_FDS, ctl, false);
|
||||||
0, false);
|
|
||||||
if (ret) {
|
if (ret) {
|
||||||
pr_err("Parasite failed to drain descriptors\n");
|
pr_err("Parasite failed to drain descriptors\n");
|
||||||
goto err;
|
goto err;
|
||||||
@@ -695,7 +689,7 @@ int parasite_drain_fds_seized(struct parasite_ctl *ctl,
|
|||||||
if (ret)
|
if (ret)
|
||||||
pr_err("Can't retrieve FDs from socket\n");
|
pr_err("Can't retrieve FDs from socket\n");
|
||||||
|
|
||||||
ret |= __parasite_execute_daemon_wait_ack(PARASITE_CMD_DRAIN_FDS, ctl, 0);
|
ret |= __parasite_execute_daemon_wait_ack(PARASITE_CMD_DRAIN_FDS, ctl);
|
||||||
err:
|
err:
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
@@ -823,8 +817,7 @@ int parasite_get_proc_fd_seized(struct parasite_ctl *ctl)
|
|||||||
{
|
{
|
||||||
int ret = -1, fd;
|
int ret = -1, fd;
|
||||||
|
|
||||||
ret = __parasite_execute_daemon_by_id(PARASITE_CMD_GET_PROC_FD, ctl,
|
ret = __parasite_execute_daemon(PARASITE_CMD_GET_PROC_FD, ctl, false);
|
||||||
0, false);
|
|
||||||
if (ret) {
|
if (ret) {
|
||||||
pr_err("Parasite failed to get proc fd\n");
|
pr_err("Parasite failed to get proc fd\n");
|
||||||
return ret;
|
return ret;
|
||||||
@@ -833,7 +826,7 @@ int parasite_get_proc_fd_seized(struct parasite_ctl *ctl)
|
|||||||
fd = recv_fd(ctl->tsock);
|
fd = recv_fd(ctl->tsock);
|
||||||
if (fd < 0)
|
if (fd < 0)
|
||||||
pr_err("Can't retrieve FD from socket\n");
|
pr_err("Can't retrieve FD from socket\n");
|
||||||
if (__parasite_execute_daemon_wait_ack(PARASITE_CMD_GET_PROC_FD, ctl, 0)) {
|
if (__parasite_execute_daemon_wait_ack(PARASITE_CMD_GET_PROC_FD, ctl)) {
|
||||||
close(fd);
|
close(fd);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
@@ -890,15 +883,13 @@ err:
|
|||||||
|
|
||||||
static int parasite_fini_seized(struct parasite_ctl *ctl)
|
static int parasite_fini_seized(struct parasite_ctl *ctl)
|
||||||
{
|
{
|
||||||
int status, ret = 0, i, nr = 0, nr_dmnz = 0;
|
pid_t pid = ctl->pid.real;
|
||||||
|
int status, ret = 0;;
|
||||||
|
|
||||||
|
if (!ctl->daemonized)
|
||||||
|
return 0;
|
||||||
|
|
||||||
/* Start to trace syscalls for each thread */
|
/* Start to trace syscalls for each thread */
|
||||||
for (i = 0; i < ctl->nr_threads; i++) {
|
|
||||||
pid_t pid = ctl->threads[i].tid;
|
|
||||||
|
|
||||||
if (!ctl->threads[i].daemonized)
|
|
||||||
break;
|
|
||||||
|
|
||||||
ptrace(PTRACE_INTERRUPT, pid, NULL, NULL);
|
ptrace(PTRACE_INTERRUPT, pid, NULL, NULL);
|
||||||
|
|
||||||
pr_debug("Waiting for %d to trap\n", pid);
|
pr_debug("Waiting for %d to trap\n", pid);
|
||||||
@@ -919,10 +910,7 @@ static int parasite_fini_seized(struct parasite_ctl *ctl)
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
nr_dmnz++;
|
ret = __parasite_execute_daemon(PARASITE_CMD_FINI, ctl, false);
|
||||||
}
|
|
||||||
|
|
||||||
ret = __parasite_execute_daemon_by_id(PARASITE_CMD_FINI, ctl, 0, false);
|
|
||||||
if (ret)
|
if (ret)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
@@ -950,11 +938,8 @@ static int parasite_fini_seized(struct parasite_ctl *ctl)
|
|||||||
|
|
||||||
pr_debug("%d is going to execute the syscall %lx\n", pid, regs.orig_ax);
|
pr_debug("%d is going to execute the syscall %lx\n", pid, regs.orig_ax);
|
||||||
if (regs.orig_ax == __NR_rt_sigreturn) {
|
if (regs.orig_ax == __NR_rt_sigreturn) {
|
||||||
nr++;
|
|
||||||
pr_debug("%d was stopped\n", pid);
|
pr_debug("%d was stopped\n", pid);
|
||||||
if (nr == nr_dmnz)
|
|
||||||
break;
|
break;
|
||||||
continue;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = ptrace(PTRACE_SYSCALL, pid, NULL, NULL);
|
ret = ptrace(PTRACE_SYSCALL, pid, NULL, NULL);
|
||||||
@@ -964,14 +949,7 @@ static int parasite_fini_seized(struct parasite_ctl *ctl)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Stop all threads on the exit point from sys_rt_sigreturn */
|
ctl->threads[0].use_sig_blocked = false;
|
||||||
for (i = 0; i < ctl->nr_threads; i++) {
|
|
||||||
pid_t pid = ctl->threads[i].tid;
|
|
||||||
|
|
||||||
if (!ctl->threads[i].daemonized)
|
|
||||||
break;
|
|
||||||
|
|
||||||
ctl->threads[i].use_sig_blocked = false;
|
|
||||||
|
|
||||||
ret = ptrace(PTRACE_SYSCALL, pid, NULL, NULL);
|
ret = ptrace(PTRACE_SYSCALL, pid, NULL, NULL);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
@@ -989,7 +967,6 @@ static int parasite_fini_seized(struct parasite_ctl *ctl)
|
|||||||
pr_err("%d\n", status);
|
pr_err("%d\n", status);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
181
pie/parasite.c
181
pie/parasite.c
@@ -20,22 +20,7 @@
|
|||||||
|
|
||||||
static int tsock = -1;
|
static int tsock = -1;
|
||||||
|
|
||||||
static struct tid_state_s {
|
static struct rt_sigframe *sigframe;
|
||||||
int id;
|
|
||||||
|
|
||||||
futex_t cmd;
|
|
||||||
int ret;
|
|
||||||
|
|
||||||
struct rt_sigframe *sigframe;
|
|
||||||
} *tid_state;
|
|
||||||
|
|
||||||
static unsigned int nr_tid_state;
|
|
||||||
static unsigned int next_tid_state;
|
|
||||||
|
|
||||||
#define TID_STATE_SIZE(n) \
|
|
||||||
(ALIGN(sizeof(struct tid_state_s) * n, PAGE_SIZE))
|
|
||||||
|
|
||||||
#define thread_leader (&tid_state[0])
|
|
||||||
|
|
||||||
#ifndef SPLICE_F_GIFT
|
#ifndef SPLICE_F_GIFT
|
||||||
#define SPLICE_F_GIFT 0x08
|
#define SPLICE_F_GIFT 0x08
|
||||||
@@ -197,12 +182,6 @@ static int init_daemon_thread(struct parasite_init_args *args)
|
|||||||
k_rtsigset_t to_block;
|
k_rtsigset_t to_block;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
if (args->id != next_tid_state)
|
|
||||||
return -EINVAL;
|
|
||||||
|
|
||||||
if (next_tid_state >= nr_tid_state)
|
|
||||||
return -ENOMEM;
|
|
||||||
|
|
||||||
ksigfillset(&to_block);
|
ksigfillset(&to_block);
|
||||||
ret = sys_sigprocmask(SIG_SETMASK, &to_block,
|
ret = sys_sigprocmask(SIG_SETMASK, &to_block,
|
||||||
&args->sig_blocked,
|
&args->sig_blocked,
|
||||||
@@ -210,12 +189,7 @@ static int init_daemon_thread(struct parasite_init_args *args)
|
|||||||
if (ret)
|
if (ret)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
tid_state[next_tid_state].id = next_tid_state;
|
sigframe = args->sigframe;
|
||||||
tid_state[next_tid_state].sigframe = args->sigframe;
|
|
||||||
|
|
||||||
futex_set(&tid_state[next_tid_state].cmd, PARASITE_CMD_IDLE);
|
|
||||||
|
|
||||||
next_tid_state++;
|
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
@@ -254,45 +228,10 @@ static int fini_thread(struct parasite_dump_thread *args)
|
|||||||
NULL, sizeof(k_rtsigset_t));
|
NULL, sizeof(k_rtsigset_t));
|
||||||
}
|
}
|
||||||
|
|
||||||
static void __parasite_daemon_thread_ack(struct tid_state_s *s, int ret)
|
|
||||||
{
|
|
||||||
s->ret = ret;
|
|
||||||
futex_set_and_wake(&s->cmd, PARASITE_CMD_IDLE);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int fini_daemon_thread(struct tid_state_s *s)
|
|
||||||
{
|
|
||||||
unsigned long new_sp;
|
|
||||||
|
|
||||||
new_sp = (long)s->sigframe + SIGFRAME_OFFSET;
|
|
||||||
pr_debug("%ld: new_sp=%lx ip %lx\n", sys_gettid(),
|
|
||||||
new_sp, s->sigframe->uc.uc_mcontext.rip);
|
|
||||||
|
|
||||||
__parasite_daemon_thread_ack(s, 0);
|
|
||||||
|
|
||||||
ARCH_RT_SIGRETURN(new_sp);
|
|
||||||
|
|
||||||
BUG();
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int init(struct parasite_init_args *args)
|
static int init(struct parasite_init_args *args)
|
||||||
{
|
{
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
if (!args->nr_threads)
|
|
||||||
return -EINVAL;
|
|
||||||
|
|
||||||
tid_state = (void *)sys_mmap(NULL, TID_STATE_SIZE(args->nr_threads),
|
|
||||||
PROT_READ | PROT_WRITE,
|
|
||||||
MAP_PRIVATE | MAP_ANONYMOUS,
|
|
||||||
-1, 0);
|
|
||||||
if ((unsigned long)tid_state > TASK_SIZE)
|
|
||||||
return -ENOMEM;
|
|
||||||
|
|
||||||
nr_tid_state = args->nr_threads;
|
|
||||||
|
|
||||||
ret = init_daemon_thread(args);
|
ret = init_daemon_thread(args);
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
return ret;
|
return ret;
|
||||||
@@ -459,12 +398,12 @@ static int parasite_check_vdso_mark(struct parasite_vdso_vma_entry *args)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int __parasite_daemon_reply_ack(unsigned int id, unsigned int cmd, int err)
|
static int __parasite_daemon_reply_ack(unsigned int cmd, int err)
|
||||||
{
|
{
|
||||||
struct ctl_msg m;
|
struct ctl_msg m;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
m = ctl_msg_ack(id, cmd, err);
|
m = ctl_msg_ack(cmd, err);
|
||||||
ret = sys_sendto(tsock, &m, sizeof(m), 0, NULL, 0);
|
ret = sys_sendto(tsock, &m, sizeof(m), 0, NULL, 0);
|
||||||
if (ret != sizeof(m)) {
|
if (ret != sizeof(m)) {
|
||||||
pr_err("Sent only %d bytes while %d expected\n",
|
pr_err("Sent only %d bytes while %d expected\n",
|
||||||
@@ -472,8 +411,8 @@ static int __parasite_daemon_reply_ack(unsigned int id, unsigned int cmd, int er
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
pr_debug("__sent ack msg: %d %d %d %d\n",
|
pr_debug("__sent ack msg: %d %d %d\n",
|
||||||
m.id, m.cmd, m.ack, m.err);
|
m.cmd, m.ack, m.err);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -493,88 +432,25 @@ static int __parasite_daemon_wait_msg(struct ctl_msg *m)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
pr_debug("__fetched msg: %d %d %d %d\n",
|
pr_debug("__fetched msg: %d %d %d\n",
|
||||||
m->id, m->cmd, m->ack, m->err);
|
m->cmd, m->ack, m->err);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int __parasite_daemon_thread_wait_cmd(struct tid_state_s *s)
|
static int fini()
|
||||||
{
|
|
||||||
futex_wait_while_eq(&s->cmd, PARASITE_CMD_IDLE);
|
|
||||||
return futex_get(&s->cmd);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void noinline __used
|
|
||||||
__parasite_daemon_thread(void *args, struct tid_state_s *s)
|
|
||||||
{
|
|
||||||
pr_debug("Running daemon thread %d\n", s->id);
|
|
||||||
|
|
||||||
/* Reply we're alive */
|
|
||||||
if (__parasite_daemon_reply_ack(s->id, PARASITE_CMD_DAEMONIZE, 0))
|
|
||||||
return;
|
|
||||||
|
|
||||||
while (1) {
|
|
||||||
int ret, cmd;
|
|
||||||
|
|
||||||
cmd = __parasite_daemon_thread_wait_cmd(s);
|
|
||||||
|
|
||||||
pr_debug("Command %d in daemon thread %d\n", cmd, s->id);
|
|
||||||
|
|
||||||
switch (cmd) {
|
|
||||||
case PARASITE_CMD_DUMP_THREAD:
|
|
||||||
ret = dump_thread(args);
|
|
||||||
break;
|
|
||||||
case PARASITE_CMD_FINI_THREAD:
|
|
||||||
fini_daemon_thread(s);
|
|
||||||
return;
|
|
||||||
default:
|
|
||||||
pr_err("Unknown command in parasite daemon thread: %d\n", cmd);
|
|
||||||
ret = -1;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
__parasite_daemon_thread_ack(s, ret);
|
|
||||||
}
|
|
||||||
|
|
||||||
pr_err("The thread %d trys to escape!!!", s->id);
|
|
||||||
BUG();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int __parasite_execute_thread(struct ctl_msg *m)
|
|
||||||
{
|
|
||||||
struct tid_state_s *s = &tid_state[m->id];
|
|
||||||
|
|
||||||
pr_debug("Wake thread %d daemon with command %d\n", s->id, m->cmd);
|
|
||||||
futex_set_and_wake(&s->cmd, m->cmd);
|
|
||||||
|
|
||||||
pr_debug("Wait thread %d for PARASITE_CMD_IDLE\n", s->id);
|
|
||||||
futex_wait_until(&s->cmd, PARASITE_CMD_IDLE);
|
|
||||||
|
|
||||||
return s->ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int fini(struct tid_state_s *s)
|
|
||||||
{
|
{
|
||||||
unsigned long new_sp;
|
unsigned long new_sp;
|
||||||
int i;
|
|
||||||
|
|
||||||
for (i = 1; i < next_tid_state; i++) {
|
new_sp = (long)sigframe + SIGFRAME_OFFSET;
|
||||||
struct ctl_msg m = {.cmd = PARASITE_CMD_FINI_THREAD, .id = i};
|
|
||||||
__parasite_execute_thread(&m);
|
|
||||||
}
|
|
||||||
|
|
||||||
new_sp = (long)s->sigframe + SIGFRAME_OFFSET;
|
|
||||||
pr_debug("%ld: new_sp=%lx ip %lx\n", sys_gettid(),
|
pr_debug("%ld: new_sp=%lx ip %lx\n", sys_gettid(),
|
||||||
new_sp, s->sigframe->uc.uc_mcontext.rip);
|
new_sp, sigframe->uc.uc_mcontext.rip);
|
||||||
|
|
||||||
sys_close(tsock);
|
sys_close(tsock);
|
||||||
log_set_fd(-1);
|
log_set_fd(-1);
|
||||||
|
|
||||||
sys_munmap(tid_state, TID_STATE_SIZE(nr_tid_state));
|
|
||||||
|
|
||||||
ARCH_RT_SIGRETURN(new_sp);
|
ARCH_RT_SIGRETURN(new_sp);
|
||||||
|
|
||||||
BUG();
|
BUG();
|
||||||
@@ -582,8 +458,7 @@ static int fini(struct tid_state_s *s)
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void noinline __used
|
static noinline __used int noinline parasite_daemon(void *args)
|
||||||
__parasite_daemon_thread_leader(void *args, struct tid_state_s *s)
|
|
||||||
{
|
{
|
||||||
struct ctl_msg m = { };
|
struct ctl_msg m = { };
|
||||||
int ret = -1;
|
int ret = -1;
|
||||||
@@ -591,7 +466,7 @@ __parasite_daemon_thread_leader(void *args, struct tid_state_s *s)
|
|||||||
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(0, PARASITE_CMD_DAEMONIZE, 0))
|
if (__parasite_daemon_reply_ack(PARASITE_CMD_DAEMONIZE, 0))
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
while (1) {
|
while (1) {
|
||||||
@@ -600,17 +475,14 @@ __parasite_daemon_thread_leader(void *args, struct tid_state_s *s)
|
|||||||
|
|
||||||
switch (m.cmd) {
|
switch (m.cmd) {
|
||||||
case PARASITE_CMD_FINI:
|
case PARASITE_CMD_FINI:
|
||||||
ret = fini(s);
|
ret = fini();
|
||||||
sys_close(tsock);
|
sys_close(tsock);
|
||||||
/*
|
/*
|
||||||
* No ACK here since we're getting out.
|
* No ACK here since we're getting out.
|
||||||
*/
|
*/
|
||||||
break;
|
break;
|
||||||
case PARASITE_CMD_FINI_THREAD:
|
|
||||||
ret = __parasite_execute_thread(&m);
|
|
||||||
break;
|
|
||||||
case PARASITE_CMD_DUMP_THREAD:
|
case PARASITE_CMD_DUMP_THREAD:
|
||||||
ret = __parasite_execute_thread(&m);
|
ret = dump_thread(args);
|
||||||
break;
|
break;
|
||||||
case PARASITE_CMD_DUMPPAGES:
|
case PARASITE_CMD_DUMPPAGES:
|
||||||
ret = dump_pages(args);
|
ret = dump_pages(args);
|
||||||
@@ -648,31 +520,12 @@ __parasite_daemon_thread_leader(void *args, struct tid_state_s *s)
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (__parasite_daemon_reply_ack(m.id, m.cmd, ret))
|
if (__parasite_daemon_reply_ack(m.cmd, ret))
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
out:
|
out:
|
||||||
fini(&tid_state[0]);
|
fini();
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int noinline parasite_daemon(struct parasite_init_args *args)
|
|
||||||
{
|
|
||||||
struct tid_state_s *s;
|
|
||||||
bool is_leader = (args->id == 0);
|
|
||||||
|
|
||||||
s = &tid_state[args->id];
|
|
||||||
|
|
||||||
pr_info("Parasite entering daemon mode for %d\n", s->id);
|
|
||||||
|
|
||||||
if (is_leader)
|
|
||||||
__parasite_daemon_thread_leader(args, s);
|
|
||||||
else
|
|
||||||
__parasite_daemon_thread(args, s);
|
|
||||||
|
|
||||||
pr_info("Parasite leaving daemon mode for %d\n", s->id);
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user