[CRIU] [PATCH 12/22] parasite: restore thread registers
Andrey Vagin
avagin at openvz.org
Wed May 8 09:28:39 EDT 2013
crtools dump should not be destructive.
We suppose that item->threads[0] is a thread leader.
Signed-off-by: Andrey Vagin <avagin at openvz.org>
---
arch/x86/crtools.c | 2 +-
cr-dump.c | 4 +-
cr-exec.c | 4 +-
include/parasite-syscall.h | 19 +++++--
parasite-syscall.c | 129 +++++++++++++++++++++++++--------------------
5 files changed, 93 insertions(+), 65 deletions(-)
diff --git a/arch/x86/crtools.c b/arch/x86/crtools.c
index 284f2c0..1fc0b63 100644
--- a/arch/x86/crtools.c
+++ b/arch/x86/crtools.c
@@ -86,7 +86,7 @@ int syscall_seized(struct parasite_ctl *ctl, int nr, unsigned long *ret,
unsigned long arg5,
unsigned long arg6)
{
- user_regs_struct_t regs = ctl->regs_orig;
+ user_regs_struct_t regs = ctl->threads[0].regs_orig;
int err;
regs.ax = (unsigned long)nr;
diff --git a/cr-dump.c b/cr-dump.c
index 2464a10..2ce4950 100644
--- a/cr-dump.c
+++ b/cr-dump.c
@@ -1457,7 +1457,7 @@ static int dump_one_task(struct pstree_item *item)
goto err;
}
- ret = parasite_cure_seized(parasite_ctl, item);
+ ret = parasite_cure_seized(parasite_ctl);
if (ret) {
pr_err("Can't cure (pid: %d) from parasite\n", pid);
goto err;
@@ -1504,7 +1504,7 @@ err_free:
err_cure:
close_cr_fdset(&cr_fdset);
err_cure_fdset:
- parasite_cure_seized(parasite_ctl, item);
+ parasite_cure_seized(parasite_ctl);
goto err;
}
diff --git a/cr-exec.c b/cr-exec.c
index 1b73da0..c2e3bea 100644
--- a/cr-exec.c
+++ b/cr-exec.c
@@ -110,7 +110,7 @@ int cr_exec(int pid, char **opt)
goto out_unseize;
}
- ctl = parasite_prep_ctl(pid, &vmas);
+ ctl = parasite_prep_ctl(pid, &vmas, 1);
if (!ctl) {
pr_err("Can't prep ctl %d\n", pid);
goto out_unseize;
@@ -120,7 +120,7 @@ int cr_exec(int pid, char **opt)
if (ret < 0)
pr_err("Can't execute syscall remotely\n");
- parasite_cure_seized(ctl, NULL);
+ parasite_cure_seized(ctl);
out_unseize:
unseize_task(pid, prev_state);
out:
diff --git a/include/parasite-syscall.h b/include/parasite-syscall.h
index 47dd8bb..9865014 100644
--- a/include/parasite-syscall.h
+++ b/include/parasite-syscall.h
@@ -5,6 +5,13 @@
#include "pstree.h"
+struct parasite_thread_ctl
+{
+ pid_t tid;
+ user_regs_struct_t regs_orig; /* original registers */
+ bool daemonized;
+};
+
/* parasite control block */
struct parasite_ctl {
struct pid pid;
@@ -13,7 +20,6 @@ struct parasite_ctl {
unsigned long map_length;
unsigned long parasite_ip; /* service routine start ip */
- user_regs_struct_t regs_orig; /* original registers */
unsigned long syscall_ip; /* entry point of infection */
u8 code_orig[BUILTIN_SYSCALL_SIZE];
@@ -23,6 +29,9 @@ struct parasite_ctl {
void *addr_args; /* address for arguments */
unsigned long args_size;
int tsock; /* transport socket for transfering fds */
+
+ int nr_threads;
+ struct parasite_thread_ctl threads[0];
};
struct cr_fdset;
@@ -63,19 +72,21 @@ extern int parasite_drain_fds_seized(struct parasite_ctl *ctl,
extern int parasite_get_proc_fd_seized(struct parasite_ctl *ctl);
struct pstree_item;
-extern int parasite_cure_seized(struct parasite_ctl *ctl, struct pstree_item *item);
+extern int parasite_cure_seized(struct parasite_ctl *ctl);
extern 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);
-extern struct parasite_ctl *parasite_prep_ctl(pid_t pid, struct vm_area_list *vma_area_list);
+extern struct parasite_ctl *parasite_prep_ctl(pid_t pid,
+ struct vm_area_list *vma_area_list,
+ unsigned int nr_threads);
extern int parasite_map_exchange(struct parasite_ctl *ctl, unsigned long size);
extern struct parasite_tty_args *parasite_dump_tty(struct parasite_ctl *ctl, int fd);
struct pstree_item;
extern int parasite_init_threads_seized(struct parasite_ctl *ctl, struct pstree_item *item);
-extern int parasite_fini_threads_seized(struct parasite_ctl *ctl, struct pstree_item *item);
+extern int parasite_fini_threads_seized(struct parasite_ctl *ctl);
int syscall_seized(struct parasite_ctl *ctl, int nr, unsigned long *ret,
unsigned long arg1,
diff --git a/parasite-syscall.c b/parasite-syscall.c
index 30af8e3..a0cc8a7 100644
--- a/parasite-syscall.c
+++ b/parasite-syscall.c
@@ -126,7 +126,7 @@ retry_signal:
* and retry.
*/
- if (ptrace(PTRACE_SETREGS, pid, NULL, &ctl->regs_orig)) {
+ if (ptrace(PTRACE_SETREGS, pid, NULL, &ctl->threads[0].regs_orig)) {
pr_perror("Can't set registers (pid: %d)", pid);
goto err;
}
@@ -169,7 +169,7 @@ retry_signal:
pr_perror("Can't obtain registers (pid: %d)", pid);
goto err;
}
- ctl->regs_orig = r;
+ ctl->threads[0].regs_orig = r;
}
goto again;
@@ -195,20 +195,12 @@ void *parasite_args_s(struct parasite_ctl *ctl, int args_size)
ctl->addr_args; \
})
-static int parasite_execute_trap_by_pid(unsigned int cmd, struct parasite_ctl *ctl, pid_t pid)
+static int parasite_execute_trap_by_pid(unsigned int cmd, struct parasite_ctl *ctl, int id)
{
+ struct parasite_thread_ctl *thread = &ctl->threads[id];
+ pid_t pid = thread->tid;
int ret;
- user_regs_struct_t regs_orig, regs;
-
- if (ctl->pid.real == pid)
- regs = ctl->regs_orig;
- else {
- if (ptrace(PTRACE_GETREGS, pid, NULL, ®s_orig)) {
- pr_perror("Can't obtain registers (pid: %d)", pid);
- return -1;
- }
- regs = regs_orig;
- }
+ user_regs_struct_t regs = thread->regs_orig;
*ctl->addr_cmd = cmd;
@@ -221,20 +213,18 @@ static int parasite_execute_trap_by_pid(unsigned int cmd, struct parasite_ctl *c
if (ret)
pr_err("Parasite exited with %d\n", ret);
- if (ctl->pid.real != pid) {
- pr_err("%d %d\n", ctl->pid.real, pid);
- if (ptrace(PTRACE_SETREGS, pid, NULL, ®s_orig)) {
+ if (ctl->pid.real != pid)
+ if (ptrace(PTRACE_SETREGS, pid, NULL, &thread->regs_orig)) {
pr_perror("Can't restore registers (pid: %d)", pid);
return -1;
}
- }
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_pid(cmd, ctl, ctl->pid.real);
+ return parasite_execute_trap_by_pid(cmd, ctl, 0);
}
static int __parasite_send_cmd(int sockfd, struct ctl_msg *m)
@@ -451,11 +441,15 @@ err:
return -1;
}
-static int parasite_daemonize(struct parasite_ctl *ctl, pid_t pid)
+static int parasite_daemonize(struct parasite_ctl *ctl, int id)
{
- user_regs_struct_t regs = ctl->regs_orig;
+ struct parasite_thread_ctl *thread = &ctl->threads[id];
+ pid_t pid = thread->tid;
+ user_regs_struct_t regs;
struct ctl_msg m = { };
+ regs = thread->regs_orig;
+
*ctl->addr_cmd = PARASITE_CMD_DAEMONIZE;
parasite_setup_regs(ctl->parasite_ip, ®s);
@@ -466,6 +460,7 @@ static int parasite_daemonize(struct parasite_ctl *ctl, pid_t pid)
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;
}
@@ -477,6 +472,7 @@ static int parasite_daemonize(struct parasite_ctl *ctl, pid_t pid)
goto err;
}
+ thread->daemonized = true;
pr_info("Parasite %d has been switched to daemon mode\n", pid);
return 0;
@@ -678,40 +674,51 @@ int parasite_init_threads_seized(struct parasite_ctl *ctl, struct pstree_item *i
args = parasite_args(ctl, struct parasite_init_args);
- for (i = 0; i < item->nr_threads; i++) {
+ for (i = 1; i < item->nr_threads; i++) {
pid_t tid = item->threads[i].real;
- if (item->pid.real == tid)
- continue;
+ ctl->threads[i].tid = tid;
+ ctl->nr_threads++;
args->real = tid;
- ret = parasite_execute_trap_by_pid(PARASITE_CMD_INIT_THREAD, ctl, tid);
+
+ ret = ptrace(PTRACE_GETREGS, tid, NULL, &ctl->threads[i].regs_orig);
if (ret) {
- pr_err("Can't init thread in parasite %d\n", tid);
- break;
+ pr_perror("Can't obtain registers (pid: %d)", tid);
+ goto err;
}
- if (parasite_daemonize(ctl, tid))
- break;
+ ret = parasite_execute_trap_by_pid(PARASITE_CMD_INIT_THREAD, ctl, i);
+ if (ret) {
+ pr_err("Can't init thread in parasite %d\n",
+ item->threads[i].real);
+ 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 pstree_item *item)
+int parasite_fini_threads_seized(struct parasite_ctl *ctl)
{
struct parasite_init_args *args;
int ret = 0, i, status;
args = parasite_args(ctl, struct parasite_init_args);
- for (i = 0; i < item->nr_threads; i++) {
- if (item->pid.real == item->threads[i].real)
- continue;
+ for (i = 1; i < ctl->nr_threads; i++) {
+ pid_t tid = ctl->threads[i].tid;
+
+ if (!ctl->threads[i].daemonized)
+ break;
- args->real = item->threads[i].real;
- ret = parasite_execute_daemon_by_pid(PARASITE_CMD_FINI_THREAD, ctl,
- item->threads[i].real);
+ args->real = tid;
+ ret = parasite_execute_daemon_by_pid(PARASITE_CMD_FINI_THREAD, ctl, tid);
/*
* Note the thread's fini() can be called even when not
* all threads were init()'ed, say we're rolling back from
@@ -725,23 +732,27 @@ int parasite_fini_threads_seized(struct parasite_ctl *ctl, struct pstree_item *i
* would change the code logic.
*/
if (ret && ret != -ENOENT) {
- pr_err("Can't fini thread in parasite %d\n",
- item->threads[i].real);
+ 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", item->threads[i].real);
- if (wait4(item->threads[i].real, &status, __WALL, NULL) != item->threads[i].real) {
- pr_perror("Waited pid mismatch (pid: %d)", item->threads[i].real);
+ 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", item->threads[i].real);
+ pr_debug("Daemon %d exited trapping\n", tid);
if (!WIFSTOPPED(status)) {
- pr_err("Task is still running (pid: %d)\n", item->threads[i].real);
+ 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;
+ }
}
return ret;
@@ -771,13 +782,13 @@ static int parasite_fini_seized(struct parasite_ctl *ctl)
return ret;
}
-int parasite_cure_seized(struct parasite_ctl *ctl, struct pstree_item *item)
+int parasite_cure_seized(struct parasite_ctl *ctl)
{
int ret = 0;
if (ctl->parasite_ip) {
ctl->signals_blocked = 0;
- ret = parasite_fini_threads_seized(ctl, item);
+ ret = parasite_fini_threads_seized(ctl);
parasite_fini_seized(ctl);
}
@@ -803,40 +814,44 @@ int parasite_cure_seized(struct parasite_ctl *ctl, struct pstree_item *item)
ret = -1;
}
- if (ptrace(PTRACE_SETREGS, ctl->pid.real, NULL, &ctl->regs_orig)) {
+ if (ptrace(PTRACE_SETREGS, ctl->pid.real, NULL, &ctl->threads[0].regs_orig)) {
pr_err("Can't restore registers (pid: %d)\n", ctl->pid.real);
ret = -1;
}
- free(ctl);
+ xfree(ctl);
return ret;
}
-struct parasite_ctl *parasite_prep_ctl(pid_t pid, struct vm_area_list *vma_area_list)
+struct parasite_ctl *parasite_prep_ctl(pid_t pid, struct vm_area_list *vma_area_list, unsigned int nr_threads)
{
struct parasite_ctl *ctl = NULL;
struct vma_area *vma_area;
+ BUG_ON(nr_threads == 0);
+
if (!arch_can_dump_task(pid))
goto err;
/*
* Control block early setup.
*/
- ctl = xzalloc(sizeof(*ctl));
+ ctl = xzalloc(sizeof(*ctl) + nr_threads * sizeof(ctl->threads[0]));
if (!ctl) {
pr_err("Parasite control block allocation failed (pid: %d)\n", pid);
goto err;
}
ctl->tsock = -1;
+ ctl->nr_threads = 1;
+ ctl->threads[0].tid = pid;
- if (ptrace(PTRACE_GETREGS, pid, NULL, &ctl->regs_orig)) {
+ if (ptrace(PTRACE_GETREGS, pid, NULL, &ctl->threads[0].regs_orig)) {
pr_err("Can't obtain registers (pid: %d)\n", pid);
goto err;
}
- vma_area = get_vma_by_ip(&vma_area_list->h, REG_IP(ctl->regs_orig));
+ vma_area = get_vma_by_ip(&vma_area_list->h, REG_IP(ctl->threads[0].regs_orig));
if (!vma_area) {
pr_err("No suitable VMA found to run parasite "
"bootstrap code (pid: %d)\n", pid);
@@ -914,7 +929,9 @@ struct parasite_ctl *parasite_infect_seized(pid_t pid, struct pstree_item *item,
int ret;
struct parasite_ctl *ctl;
- ctl = parasite_prep_ctl(pid, vma_area_list);
+ BUG_ON(item->threads[0].real != pid);
+
+ ctl = parasite_prep_ctl(pid, vma_area_list, item->nr_threads);
if (!ctl)
return NULL;
@@ -952,7 +969,7 @@ struct parasite_ctl *parasite_infect_seized(pid_t pid, struct pstree_item *item,
goto err_restore;
}
- if (parasite_daemonize(ctl, pid))
+ if (parasite_daemonize(ctl, 0))
goto err_restore;
ret = parasite_init_threads_seized(ctl, item);
@@ -962,7 +979,7 @@ struct parasite_ctl *parasite_infect_seized(pid_t pid, struct pstree_item *item,
return ctl;
err_restore:
- parasite_cure_seized(ctl, item);
+ parasite_cure_seized(ctl);
return NULL;
}
--
1.8.2
More information about the CRIU
mailing list