[CRIU] [PATCH 09/21] parasite: Switch parasite to daemon mode (v2)

Andrey Vagin avagin at openvz.org
Fri May 24 08:20:12 EDT 2013


Parasite daemon mode it quite tricky. One may consider
it as consisting of two parts

 - daemon mode for thread leader
 - daemon mode for regular threads

Thread leader daemon
--------------------

Once thread leader parasite code switched initialized,
it starts spinning on socket listening for commands
to handle.

If the command destination is the thread leader itself it
handles it and replies back the ack to the caller (iow
the main crtools code).

If the recepient is not thread leader but one of threads,
then thread leader wakes up the thread by futex and makes
it to handle the command waiting on futex for result. Once
result obtained, the ack is being sending back to caller.

Thread daemon
-------------

On initialization thread daemon starts waiting a command on futex.
The futex is triggered by thread leader daemon when command received.
Once command is received and handled, the result is reported back to
the thread leader daemon, which in turn send ack message.

Both thread-leader and regular threads require own stack to operate
on since they all are present in memory simultaneously. Thus we use
call_daemon_thread() helper which takes care of providing stack
to the callee.

TODO:

 - ARM requires own wrappers on damonize/trap low-level code,
   at moment x86-64 is only covered

v2: remove PARASITE_CMD_DAEMONIZED and s->ack
    parasite: use a propper command for getting ack

Fixed-by: Andrey Vagin <avagin at openvz.org>
Signed-off-by: Cyrill Gorcunov <gorcunov at openvz.org>
Signed-off-by: Andrey Vagin <avagin at openvz.org>
---
 include/parasite-syscall.h |   9 +-
 mem.c                      |  17 ++--
 parasite-syscall.c         | 230 ++++++++++++++++++++++++++++++++++++++++-----
 pie/parasite.c             | 230 ++++++++++++++++++++++++++++++++++++++-------
 4 files changed, 420 insertions(+), 66 deletions(-)

diff --git a/include/parasite-syscall.h b/include/parasite-syscall.h
index 543fa67..dab8ddf 100644
--- a/include/parasite-syscall.h
+++ b/include/parasite-syscall.h
@@ -10,6 +10,8 @@ struct parasite_thread_ctl
 	pid_t			tid;
 	user_regs_struct_t	regs_orig;				/* original registers */
 
+	bool			daemonized;
+
 	void			*rstack;
 };
 
@@ -45,8 +47,13 @@ extern int parasite_dump_sigacts_seized(struct parasite_ctl *ctl, struct cr_fdse
 extern int parasite_dump_itimers_seized(struct parasite_ctl *ctl, struct cr_fdset *cr_fdset);
 
 void *parasite_args_s(struct parasite_ctl *ctl, int args_size);
-int parasite_execute_trap(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_execute_daemon_by_id(unsigned int cmd,
+					struct parasite_ctl *ctl,
+					int id, bool wait_ack);
+int __parasite_execute_daemon_wait_ack(unsigned int cmd,
+					struct parasite_ctl *ctl, int id);
 
 struct parasite_dump_misc;
 struct vm_area_list;
diff --git a/mem.c b/mem.c
index 16f5177..eaf85b8 100644
--- a/mem.c
+++ b/mem.c
@@ -373,16 +373,19 @@ static int __parasite_dump_pages_seized(struct parasite_ctl *ctl,
 
 	args->off = 0;
 	list_for_each_entry(ppb, &pp->bufs, l) {
-		ret = parasite_send_fd(ctl, ppb->p[1]);
-		if (ret)
-			goto out_pp;
-
 		args->nr_segs = ppb->nr_segs;
 		args->nr_pages = ppb->pages_in;
 		pr_debug("PPB: %d pages %d segs %u pipe %d off\n",
 				args->nr_pages, args->nr_segs, ppb->pipe_size, args->off);
 
-		ret = parasite_execute_trap(PARASITE_CMD_DUMPPAGES, ctl);
+		ret = __parasite_execute_daemon_by_id(PARASITE_CMD_DUMPPAGES, ctl, 0, false);
+		if (ret < 0)
+			goto out_pp;
+		ret = parasite_send_fd(ctl, ppb->p[1]);
+		if (ret)
+			goto out_pp;
+
+		ret = __parasite_execute_daemon_wait_ack(PARASITE_CMD_DUMPPAGES, ctl, 0);
 		if (ret < 0)
 			goto out_pp;
 
@@ -448,7 +451,7 @@ int parasite_dump_pages_seized(struct parasite_ctl *ctl,
 	 */
 
 	pargs->add_prot = PROT_READ;
-	ret = parasite_execute_trap(PARASITE_CMD_MPROTECT_VMAS, ctl);
+	ret = parasite_execute_daemon(PARASITE_CMD_MPROTECT_VMAS, ctl);
 	if (ret) {
 		pr_err("Can't dump unprotect vmas with parasite\n");
 		return ret;
@@ -459,7 +462,7 @@ int parasite_dump_pages_seized(struct parasite_ctl *ctl,
 		pr_err("Can't dump page with parasite\n");
 
 	pargs->add_prot = 0;
-	ret = parasite_execute_trap(PARASITE_CMD_MPROTECT_VMAS, ctl);
+	ret = parasite_execute_daemon(PARASITE_CMD_MPROTECT_VMAS, ctl);
 	if (ret) {
 		pr_err("Can't rollback unprotected vmas with parasite\n");
 		ret = -1;
diff --git a/parasite-syscall.c b/parasite-syscall.c
index 9ab8a5b..6ba4fb4 100644
--- a/parasite-syscall.c
+++ b/parasite-syscall.c
@@ -222,11 +222,104 @@ static int parasite_execute_trap_by_id(unsigned int cmd, struct parasite_ctl *ct
 	return ret;
 }
 
-int parasite_execute_trap(unsigned int cmd, struct parasite_ctl *ctl)
+static int parasite_execute_trap(unsigned int cmd, struct parasite_ctl *ctl)
 {
 	return parasite_execute_trap_by_id(cmd, ctl, 0);
 }
 
+static int __parasite_send_cmd(int sockfd, struct ctl_msg *m)
+{
+	int ret;
+
+	ret = send(sockfd, m, sizeof(*m), 0);
+	if (ret == -1) {
+		pr_perror("Failed to send command %d to daemon %d\n", m->cmd, m->id);
+		return -1;
+	} else if (ret != sizeof(*m)) {
+		pr_err("Message to daemon is trimmed (%d/%d)\n",
+		       (int)sizeof(*m), ret);
+		return -1;
+	}
+
+	pr_debug("Sent msg to daemon %d %d %d %d\n", m->id, m->cmd, m->ack, m->err);
+	return 0;
+}
+
+static int parasite_wait_ack(int sockfd, int id, unsigned int cmd, struct ctl_msg *m)
+{
+	int ret;
+
+	pr_debug("Wait for ack %d-%d on daemon socket\n", id, cmd);
+
+	while (1) {
+		memzero(m, sizeof(*m));
+
+		ret = recv(sockfd, m, sizeof(*m), MSG_WAITALL);
+		if (ret == -1) {
+			pr_perror("Failed to read ack from %d", id);
+			return -1;
+		} else if (ret != sizeof(*m)) {
+			pr_err("Message reply from daemon is trimmed (%d/%d)\n",
+			       (int)sizeof(*m), ret);
+			return -1;
+		}
+		pr_debug("Fetched ack: %d %d %d %d\n",
+			 m->id, m->cmd, m->ack, m->err);
+
+		if (m->id != id || m->cmd != cmd || m->ack != cmd) {
+			pr_err("Communication error, this is not "
+			       "the ack we expected\n");
+			return -1;
+		}
+		return 0;
+	}
+
+	return -1;
+}
+
+int __parasite_execute_daemon_wait_ack(unsigned int cmd,
+					struct parasite_ctl *ctl, int id)
+{
+	struct ctl_msg m;
+
+	if (parasite_wait_ack(ctl->tsock, id, cmd, &m))
+		return -1;
+
+	if (m.err != 0) {
+		pr_err("Command %d for daemon %d failed with %d\n",
+		       cmd, id, m.err);
+		return -1;
+	}
+
+	return 0;
+}
+
+int __parasite_execute_daemon_by_id(unsigned int cmd,
+				struct parasite_ctl *ctl, int id, bool wait_ack)
+{
+	struct ctl_msg m;
+
+	m = ctl_msg_cmd(id, cmd);
+	if (__parasite_send_cmd(ctl->tsock, &m))
+		return -1;
+
+	if (wait_ack)
+		return __parasite_execute_daemon_wait_ack(cmd, ctl, id);
+
+	return 0;
+}
+
+static int parasite_execute_daemon_by_id(unsigned int cmd,
+					struct parasite_ctl *ctl, int id)
+{
+	return __parasite_execute_daemon_by_id(cmd, ctl, id, 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)
 {
 	unsigned long x;
@@ -347,6 +440,49 @@ err:
 	return -1;
 }
 
+static int parasite_daemonize(struct parasite_ctl *ctl, int id)
+{
+	struct parasite_thread_ctl *thread = &ctl->threads[id];
+	pid_t pid = thread->tid;
+	user_regs_struct_t regs;
+	struct ctl_msg m = { };
+	struct parasite_init_args *args;
+
+	*ctl->addr_cmd = PARASITE_CMD_DAEMONIZE;
+
+	args = parasite_args(ctl, struct parasite_init_args);
+	args->id = id;
+
+	regs = thread->regs_orig;
+	parasite_setup_regs(ctl->parasite_ip, thread->rstack, &regs);
+
+	if (ptrace(PTRACE_SETREGS, pid, NULL, &regs)) {
+		pr_perror("Can't set registers (pid: %d)", pid);
+		goto err;
+	}
+
+	if (ptrace(PTRACE_CONT, pid, NULL, NULL)) {
+		pr_perror("Can't continue (pid: %d)\n", pid);
+		ptrace(PTRACE_SETREGS, pid, NULL, thread->regs_orig);
+		goto err;
+	}
+
+	pr_info("Wait for parasite being daemonized...\n");
+
+	if (parasite_wait_ack(ctl->tsock, id, PARASITE_CMD_DAEMONIZE, &m)) {
+		pr_err("Can't switch parasite %d to daemon mode %d\n",
+		       pid, m.err);
+		goto err;
+	}
+
+	thread->daemonized = true;
+	pr_info("Parasite %d has been switched to daemon mode\n", pid);
+	return 0;
+
+err:
+	return -1;
+}
+
 int parasite_dump_thread_seized(struct parasite_ctl *ctl, int id,
 				struct pid *tid, CoreEntry *core)
 {
@@ -356,7 +492,7 @@ int parasite_dump_thread_seized(struct parasite_ctl *ctl, int id,
 	args = parasite_args(ctl, struct parasite_dump_thread);
 	args->id = id;
 
-	ret = parasite_execute_trap_by_id(PARASITE_CMD_DUMP_THREAD, ctl, id);
+	ret = parasite_execute_daemon_by_id(PARASITE_CMD_DUMP_THREAD, ctl, id);
 
 	memcpy(&core->thread_core->blk_sigset, &args->blocked, sizeof(args->blocked));
 	CORE_THREAD_ARCH_INFO(core)->clear_tid_addr = encode_pointer(args->tid_addr);
@@ -374,7 +510,7 @@ int parasite_dump_sigacts_seized(struct parasite_ctl *ctl, struct cr_fdset *cr_f
 
 	args = parasite_args(ctl, struct parasite_dump_sa_args);
 
-	ret = parasite_execute_trap(PARASITE_CMD_DUMP_SIGACTS, ctl);
+	ret = parasite_execute_daemon(PARASITE_CMD_DUMP_SIGACTS, ctl);
 	if (ret < 0)
 		return ret;
 
@@ -417,7 +553,7 @@ int parasite_dump_itimers_seized(struct parasite_ctl *ctl, struct cr_fdset *cr_f
 
 	args = parasite_args(ctl, struct parasite_dump_itimers_args);
 
-	ret = parasite_execute_trap(PARASITE_CMD_DUMP_ITIMERS, ctl);
+	ret = parasite_execute_daemon(PARASITE_CMD_DUMP_ITIMERS, ctl);
 	if (ret < 0)
 		return ret;
 
@@ -437,7 +573,7 @@ int parasite_dump_misc_seized(struct parasite_ctl *ctl, struct parasite_dump_mis
 	struct parasite_dump_misc *ma;
 
 	ma = parasite_args(ctl, struct parasite_dump_misc);
-	if (parasite_execute_trap(PARASITE_CMD_DUMP_MISC, ctl) < 0)
+	if (parasite_execute_daemon(PARASITE_CMD_DUMP_MISC, ctl) < 0)
 		return -1;
 
 	*misc = *ma;
@@ -451,7 +587,7 @@ struct parasite_tty_args *parasite_dump_tty(struct parasite_ctl *ctl, int fd)
 	p = parasite_args(ctl, struct parasite_tty_args);
 	p->fd = fd;
 
-	if (parasite_execute_trap(PARASITE_CMD_DUMP_TTY, ctl) < 0)
+	if (parasite_execute_daemon(PARASITE_CMD_DUMP_TTY, ctl) < 0)
 		return NULL;
 
 	return p;
@@ -462,7 +598,7 @@ int parasite_dump_creds(struct parasite_ctl *ctl, CredsEntry *ce)
 	struct parasite_dump_creds *pc;
 
 	pc = parasite_args(ctl, struct parasite_dump_creds);
-	if (parasite_execute_trap(PARASITE_CMD_DUMP_CREDS, ctl) < 0)
+	if (parasite_execute_daemon(PARASITE_CMD_DUMP_CREDS, ctl) < 0)
 		return -1;
 
 	ce->secbits = pc->secbits;
@@ -489,18 +625,18 @@ int parasite_drain_fds_seized(struct parasite_ctl *ctl,
 	args = parasite_args_s(ctl, size);
 	memcpy(args, dfds, size);
 
-	ret = parasite_execute_trap(PARASITE_CMD_DRAIN_FDS, ctl);
+	ret = __parasite_execute_daemon_by_id(PARASITE_CMD_DRAIN_FDS, ctl,
+					       0, false);
 	if (ret) {
 		pr_err("Parasite failed to drain descriptors\n");
 		goto err;
 	}
 
 	ret = recv_fds(ctl->tsock, lfds, dfds->nr_fds, opts);
-	if (ret) {
+	if (ret)
 		pr_err("Can't retrieve FDs from socket\n");
-		goto err;
-	}
 
+	ret |= __parasite_execute_daemon_wait_ack(PARASITE_CMD_DRAIN_FDS, ctl, 0);
 err:
 	return ret;
 }
@@ -509,16 +645,19 @@ int parasite_get_proc_fd_seized(struct parasite_ctl *ctl)
 {
 	int ret = -1, fd;
 
-	ret = parasite_execute_trap(PARASITE_CMD_GET_PROC_FD, ctl);
+	ret = __parasite_execute_daemon_by_id(PARASITE_CMD_GET_PROC_FD, ctl,
+					       0, false);
 	if (ret) {
 		pr_err("Parasite failed to get proc fd\n");
 		return ret;
 	}
 
 	fd = recv_fd(ctl->tsock);
-	if (fd < 0) {
+	if (fd < 0)
 		pr_err("Can't retrieve FD from socket\n");
-		return fd;
+	if (__parasite_execute_daemon_wait_ack(PARASITE_CMD_GET_PROC_FD, ctl, 0)) {
+		close(fd);
+		return -1;
 	}
 
 	return fd;
@@ -543,32 +682,39 @@ int parasite_init_threads_seized(struct parasite_ctl *ctl, struct pstree_item *i
 		ret = ptrace(PTRACE_GETREGS, tid, NULL, regs_orig);
 		if (ret) {
 			pr_perror("Can't obtain registers (pid: %d)", tid);
-			break;
+			goto err;
 		}
 
 		ret = parasite_execute_trap_by_id(PARASITE_CMD_INIT_THREAD, ctl, i);
 		if (ret) {
-			pr_err("Can't init thread in parasite %d\n",
-			       item->threads[i].real);
-			break;
+			pr_err("Can't init thread in parasite %d\n", tid);
+			goto err;
 		}
+
+		if (parasite_daemonize(ctl, i))
+			goto err;
 	}
 
-	return ret;
+	return 0;
+err:
+	return -1 ;
 }
 
 int parasite_fini_threads_seized(struct parasite_ctl *ctl)
 {
 	struct parasite_init_args *args;
-	int ret = 0, i;
+	int ret = 0, i, status;
 
 	args = parasite_args(ctl, struct parasite_init_args);
 
 	for (i = 1; i < ctl->nr_threads; i++) {
 		pid_t tid = ctl->threads[i].tid;
 
+		if (!ctl->threads[i].daemonized)
+			break;
+
 		args->id = i;
-		ret = parasite_execute_trap_by_id(PARASITE_CMD_FINI_THREAD, ctl, i);
+		ret = parasite_execute_daemon_by_id(PARASITE_CMD_FINI_THREAD, ctl, i);
 		/*
 		 * Note the thread's fini() can be called even when not
 		 * all threads were init()'ed, say we're rolling back from
@@ -584,6 +730,24 @@ int parasite_fini_threads_seized(struct parasite_ctl *ctl)
 		if (ret && ret != -ENOENT) {
 			pr_err("Can't fini thread in parasite %d\n", tid);
 			break;
+		} else if (ret == -ENOENT)
+			continue;
+
+		pr_debug("Waiting for %d to trap\n", tid);
+		if (wait4(tid, &status, __WALL, NULL) != tid) {
+			pr_perror("Waited pid mismatch (pid: %d)", tid);
+			break;
+		}
+
+		pr_debug("Daemon %d exited trapping\n", tid);
+		if (!WIFSTOPPED(status)) {
+			pr_err("Task is still running (pid: %d)\n", tid);
+			break;
+		}
+
+		if (ptrace(PTRACE_SETREGS, tid, NULL, &ctl->threads[i].regs_orig)) {
+			pr_perror("Can't restore registers (pid: %d)", tid);
+			return -1;
 		}
 	}
 
@@ -593,25 +757,38 @@ int parasite_fini_threads_seized(struct parasite_ctl *ctl)
 static int parasite_fini_seized(struct parasite_ctl *ctl)
 {
 	struct parasite_init_args *args;
+	int status, ret = 0;
 
 	args = parasite_args(ctl, struct parasite_init_args);
+
 	args->id = 0;
+	__parasite_execute_daemon_by_id(PARASITE_CMD_FINI, ctl, 0, false);
+
+	if (wait4(ctl->pid.real, &status, __WALL, NULL) != ctl->pid.real) {
+		pr_perror("Waited pid mismatch (pid: %d)", ctl->pid.real);
+		ret = -1;
+	}
+
+	if (!WIFSTOPPED(status)) {
+		pr_err("Task is still running (pid: %d)\n", ctl->pid.real);
+		ret = -1;
+	}
 
-	return parasite_execute_trap(PARASITE_CMD_FINI, ctl);
+	return ret;
 }
 
 int parasite_cure_remote(struct parasite_ctl *ctl)
 {
 	int ret = 0;
 
-	ctl->tsock = -1;
-
 	if (ctl->parasite_ip) {
 		ctl->signals_blocked = 0;
-		parasite_fini_threads_seized(ctl);
+		ret = parasite_fini_threads_seized(ctl);
 		parasite_fini_seized(ctl);
 	}
 
+	ctl->tsock = -1;
+
 	if (ctl->remote_map) {
 		if (munmap_seized(ctl, (void *)ctl->remote_map, ctl->map_length)) {
 			pr_err("munmap_seized failed (pid: %d)\n", ctl->pid.real);
@@ -815,6 +992,9 @@ struct parasite_ctl *parasite_infect_seized(pid_t pid, struct pstree_item *item,
 		goto err_restore;
 	}
 
+	if (parasite_daemonize(ctl, 0))
+		goto err_restore;
+
 	ret = parasite_init_threads_seized(ctl, item);
 	if (ret)
 		goto err_restore;
diff --git a/pie/parasite.c b/pie/parasite.c
index 070a995..76e6ee8 100644
--- a/pie/parasite.c
+++ b/pie/parasite.c
@@ -223,10 +223,8 @@ static int init_thread(struct parasite_init_args *args)
 	return ret;
 }
 
-static int fini_thread(struct parasite_init_args *args)
+static int fini_thread(struct tid_state_s *s)
 {
-	struct tid_state_s *s = &tid_state[args->id];
-
 	if (s->use_sig_blocked)
 		return sys_sigprocmask(SIG_SETMASK, &s->sig_blocked,
 				       NULL, sizeof(k_rtsigset_t));
@@ -401,17 +399,205 @@ static int parasite_cfg_log(struct parasite_log_args *args)
 	return ret;
 }
 
-static int fini(struct parasite_init_args *args)
+static int fini(struct tid_state_s *s)
 {
+	log_set_fd(-1);
+
+	return fini_thread(s);
+}
+
+static int __parasite_daemon_reply_ack(unsigned int id, unsigned int cmd, int err)
+{
+	struct ctl_msg m;
 	int ret;
 
-	ret = fini_thread(args);
+	m = ctl_msg_ack(id, cmd, err);
+	ret = sys_sendto(tsock, &m, sizeof(m), 0, NULL, 0);
+	if (ret != sizeof(m)) {
+		pr_err("Sent only %d bytes while %d expected\n",
+			ret, (int)sizeof(m));
+		return -1;
+	}
 
-	sys_munmap(tid_state, TID_STATE_SIZE(nr_tid_state));
-	log_set_fd(-1);
-	sys_close(tsock);
+	pr_debug("__sent ack msg: %d %d %d %d\n",
+		 m.id, m.cmd, m.ack, m.err);
 
-	return ret;
+	return 0;
+}
+
+static int __parasite_daemon_wait_msg(struct ctl_msg *m)
+{
+	int ret;
+
+	pr_debug("Daemon wais for command\n");
+
+	while (1) {
+		*m = (struct ctl_msg){ };
+		ret = sys_recvfrom(tsock, m, sizeof(*m), MSG_WAITALL, NULL, 0);
+		if (ret != sizeof(*m)) {
+			pr_err("Trimmed message received (%d/%d)\n",
+			       (int)sizeof(*m), ret);
+			return 0;
+		}
+
+		pr_debug("__fetched msg: %d %d %d %d\n",
+			 m->id, m->cmd, m->ack, m->err);
+		return 0;
+	}
+
+	return -1;
+}
+
+static int __parasite_daemon_thread_wait_cmd(struct tid_state_s *s)
+{
+	futex_wait_while_eq(&s->cmd, PARASITE_CMD_IDLE);
+	return futex_get(&s->cmd);
+}
+
+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 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:
+			__parasite_daemon_thread_ack(s, 0);
+			fini_thread(s);
+			return;
+		default:
+			pr_err("Unknown command in parasite daemon thread: %d\n", cmd);
+			ret = -1;
+			break;
+		}
+		__parasite_daemon_thread_ack(s, ret);
+	}
+
+	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 void noinline __used
+__parasite_daemon_thread_leader(void *args, struct tid_state_s *s)
+{
+	struct ctl_msg m = { };
+	int ret = -1;
+
+	pr_debug("Running daemon thread leader\n");
+
+	/* Reply we're alive */
+	if (__parasite_daemon_reply_ack(0, PARASITE_CMD_DAEMONIZE, 0))
+		return;
+
+	while (1) {
+		if (__parasite_daemon_wait_msg(&m))
+			break;
+
+		switch (m.cmd) {
+		case PARASITE_CMD_FINI:
+			ret = fini(s);
+			sys_close(tsock);
+			/*
+			 * No ACK here since we're getting out.
+			 */
+			break;
+		case PARASITE_CMD_FINI_THREAD:
+			ret = __parasite_execute_thread(&m);
+			break;
+		case PARASITE_CMD_DUMP_THREAD:
+			ret = __parasite_execute_thread(&m);
+			break;
+		case PARASITE_CMD_DUMPPAGES:
+			ret = dump_pages(args);
+			break;
+		case PARASITE_CMD_MPROTECT_VMAS:
+			ret = mprotect_vmas(args);
+			break;
+		case PARASITE_CMD_DUMP_SIGACTS:
+			ret = dump_sigact(args);
+			break;
+		case PARASITE_CMD_DUMP_ITIMERS:
+			ret = dump_itimers(args);
+			break;
+		case PARASITE_CMD_DUMP_MISC:
+			ret = dump_misc(args);
+			break;
+		case PARASITE_CMD_DUMP_CREDS:
+			ret = dump_creds(args);
+			break;
+		case PARASITE_CMD_DRAIN_FDS:
+			ret = drain_fds(args);
+			break;
+		case PARASITE_CMD_GET_PROC_FD:
+			ret = parasite_get_proc_fd();
+			break;
+		case PARASITE_CMD_DUMP_TTY:
+			ret = parasite_dump_tty(args);
+			break;
+		default:
+			pr_err("Unknown command in parasite daemon thread leader: %d\n", m.cmd);
+			ret = -1;
+			break;
+		}
+
+		if (__parasite_daemon_reply_ack(m.id, m.cmd, ret))
+			break;
+	}
+
+	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);
+
+	if (is_leader)
+		sys_munmap(tid_state, TID_STATE_SIZE(nr_tid_state));
+
+	return 0;
 }
 
 int __used parasite_service(unsigned int cmd, void *args)
@@ -423,32 +609,10 @@ int __used parasite_service(unsigned int cmd, void *args)
 		return init(args);
 	case PARASITE_CMD_INIT_THREAD:
 		return init_thread(args);
-	case PARASITE_CMD_FINI:
-		return fini(args);
-	case PARASITE_CMD_FINI_THREAD:
-		return fini_thread(args);
 	case PARASITE_CMD_CFG_LOG:
 		return parasite_cfg_log(args);
-	case PARASITE_CMD_DUMPPAGES:
-		return dump_pages(args);
-	case PARASITE_CMD_MPROTECT_VMAS:
-		return mprotect_vmas(args);
-	case PARASITE_CMD_DUMP_SIGACTS:
-		return dump_sigact(args);
-	case PARASITE_CMD_DUMP_ITIMERS:
-		return dump_itimers(args);
-	case PARASITE_CMD_DUMP_MISC:
-		return dump_misc(args);
-	case PARASITE_CMD_DUMP_CREDS:
-		return dump_creds(args);
-	case PARASITE_CMD_DUMP_THREAD:
-		return dump_thread(args);
-	case PARASITE_CMD_DRAIN_FDS:
-		return drain_fds(args);
-	case PARASITE_CMD_GET_PROC_FD:
-		return parasite_get_proc_fd();
-	case PARASITE_CMD_DUMP_TTY:
-		return parasite_dump_tty(args);
+	case PARASITE_CMD_DAEMONIZE:
+		return parasite_daemon(args);
 	}
 
 	pr_err("Unknown command to parasite: %d\n", cmd);
-- 
1.8.2



More information about the CRIU mailing list