[CRIU] [PATCH 07/20] parasite: introduced the multiarch support into the parasite.

alekskartashov at parallels.com alekskartashov at parallels.com
Wed Dec 12 08:34:17 EST 2012


From: Alexander Kartashov <alekskartashov at parallels.com>

* Introduced the TLS area retrieval in the routine parasite_dump_thread_seized
  since ARM requires saving/restoring it.
* Introduced the macro ARCH_SI_TRAP to abstract from behavior of breakpoints:
  they generate different values of the field siginfo.si_code on different architectures.
* Intruduced the macro REG_RES to reference the syscall return value register in
  the struct user_regs_struct_t.
* Provided machine-dependent implementations of the following routines:
  - parasite_setup_regs,
  - mmap_seized,
  - munmap_seized.

Signed-off-by: Alexander Kartashov <alekskartashov at parallels.com>
---
 include/parasite-syscall.h |   11 ++++-
 include/parasite.h         |   10 ++++
 parasite-syscall.c         |  110 +++++++++++++++++---------------------------
 pie/parasite.c             |   26 ++++++++---
 4 files changed, 82 insertions(+), 75 deletions(-)

diff --git a/include/parasite-syscall.h b/include/parasite-syscall.h
index f4586ef..9b96121 100644
--- a/include/parasite-syscall.h
+++ b/include/parasite-syscall.h
@@ -35,9 +35,17 @@ extern int parasite_dump_pages_seized(struct parasite_ctl *ctl,
 				      struct list_head *vma_area_list,
 				      struct cr_fdset *cr_fdset);
 struct parasite_dump_thread;
+
+#ifndef CONFIG_HAS_TLS
+extern int parasite_dump_thread_seized(struct parasite_ctl *ctl, pid_t pid,
+                                        unsigned int **tid_add, pid_t *tid,
+                                        void *blocked);
+#else
 extern int parasite_dump_thread_seized(struct parasite_ctl *ctl, pid_t pid,
 					unsigned int **tid_add, pid_t *tid,
-					void *blocked);
+					void *blocked,
+					u32* tls);
+#endif
 
 struct parasite_drain_fd;
 struct fd_opts;
@@ -48,6 +56,7 @@ 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 uint32_t parasite_get_tls_seized(struct parasite_ctl* ctl);
 extern struct parasite_ctl *parasite_infect_seized(pid_t pid,
 						   struct pstree_item *item,
 						   struct list_head *vma_area_list);
diff --git a/include/parasite.h b/include/parasite.h
index 3a586fc..d820d4c 100644
--- a/include/parasite.h
+++ b/include/parasite.h
@@ -37,6 +37,8 @@ enum {
 	PARASITE_CMD_GET_PROC_FD,
 	PARASITE_CMD_DUMP_TTY,
 
+	PARASITE_CMD_GET_TLS,
+
 	PARASITE_CMD_MAX,
 };
 
@@ -97,6 +99,10 @@ struct parasite_dump_thread {
 	unsigned int		*tid_addr;
 	pid_t			tid;
 	k_rtsigset_t		blocked;
+
+#ifdef CONFIG_HAS_TLS
+	u32			tls;
+#endif
 };
 
 #define PARASITE_MAX_FDS	(PAGE_SIZE / sizeof(int))
@@ -106,6 +112,10 @@ struct parasite_drain_fd {
 	int	fds[PARASITE_MAX_FDS];
 };
 
+struct parasite_get_tls_args {
+	uint32_t tls;
+};
+
 static inline int drain_fds_size(struct parasite_drain_fd *dfds)
 {
 	return sizeof(dfds->nr_fds) + dfds->nr_fds * sizeof(dfds->fds[0]);
diff --git a/parasite-syscall.c b/parasite-syscall.c
index 98d2e86..ca94c91 100644
--- a/parasite-syscall.c
+++ b/parasite-syscall.c
@@ -1,4 +1,5 @@
 #include <unistd.h>
+#include <inttypes.h>
 
 #include <sys/stat.h>
 #include <sys/wait.h>
@@ -22,9 +23,7 @@
 #include <string.h>
 #include <stdlib.h>
 
-#ifdef CONFIG_X86_64
-static const char code_syscall[] = {0x0f, 0x05, 0xcc, 0xcc,
-				    0xcc, 0xcc, 0xcc, 0xcc};
+#include <arch_parasite_syscall.h>
 
 #define code_syscall_size	(round_up(sizeof(code_syscall), sizeof(long)))
 #define parasite_size		(round_up(sizeof(parasite_blob), sizeof(long)))
@@ -57,18 +56,6 @@ static struct vma_area *get_vma_by_ip(struct list_head *vma_area_list, unsigned
 	return NULL;
 }
 
-/* Note it's destructive on @regs */
-static void parasite_setup_regs(unsigned long new_ip, user_regs_struct_t *regs)
-{
-	regs->ip = new_ip;
-
-	/* Avoid end of syscall processing */
-	regs->orig_ax = -1;
-
-	/* Make sure flags are in known state */
-	regs->flags &= ~(X86_EFLAGS_TF | X86_EFLAGS_DF | X86_EFLAGS_IF);
-}
-
 /* we run at @regs->ip */
 static int __parasite_execute(struct parasite_ctl *ctl, pid_t pid, user_regs_struct_t *regs)
 {
@@ -112,7 +99,7 @@ again:
 			goto err;
 	}
 
-	if (WSTOPSIG(status) != SIGTRAP || siginfo.si_code != SI_KERNEL) {
+	if (WSTOPSIG(status) != SIGTRAP || siginfo.si_code != ARCH_SI_TRAP) {
 retry_signal:
 		pr_debug("** delivering signal %d si_code=%d\n",
 			 siginfo.si_signo, siginfo.si_code);
@@ -225,7 +212,7 @@ static int parasite_execute_by_pid(unsigned int cmd, struct parasite_ctl *ctl, p
 
 	ret = __parasite_execute(ctl, pid, &regs);
 	if (ret == 0)
-		ret = (int)regs.ax;
+		ret = (int)REG_RES(regs);
 
 	if (ret)
 		pr_err("Parasite exited with %d\n", ret);
@@ -244,52 +231,6 @@ static int parasite_execute(unsigned int cmd, struct parasite_ctl *ctl)
 	return parasite_execute_by_pid(cmd, ctl, ctl->pid);
 }
 
-static void *mmap_seized(struct parasite_ctl *ctl,
-			 void *addr, size_t length, int prot,
-			 int flags, int fd, off_t offset)
-{
-	user_regs_struct_t regs = ctl->regs_orig;
-	void *map = NULL;
-	int ret;
-
-	regs.ax  = (unsigned long)__NR_mmap;	/* mmap		*/
-	regs.di  = (unsigned long)addr;		/* @addr	*/
-	regs.si  = (unsigned long)length;	/* @length	*/
-	regs.dx  = (unsigned long)prot;		/* @prot	*/
-	regs.r10 = (unsigned long)flags;	/* @flags	*/
-	regs.r8  = (unsigned long)fd;		/* @fd		*/
-	regs.r9  = (unsigned long)offset;	/* @offset	*/
-
-	parasite_setup_regs(ctl->syscall_ip, &regs);
-
-	ret = __parasite_execute(ctl, ctl->pid, &regs);
-	if (ret)
-		goto err;
-
-	if ((long)regs.ax > 0)
-		map = (void *)regs.ax;
-err:
-	return map;
-}
-
-static int munmap_seized(struct parasite_ctl *ctl, void *addr, size_t length)
-{
-	user_regs_struct_t regs = ctl->regs_orig;
-	int ret;
-
-	regs.ax = (unsigned long)__NR_munmap;	/* mmap		*/
-	regs.di = (unsigned long)addr;		/* @addr	*/
-	regs.si = (unsigned long)length;	/* @length	*/
-
-	parasite_setup_regs(ctl->syscall_ip, &regs);
-
-	ret = __parasite_execute(ctl, ctl->pid, &regs);
-	if (!ret)
-		ret = (int)regs.ax;
-
-	return ret;
-}
-
 static int gen_parasite_saddr(struct sockaddr_un *saddr, int key)
 {
 	int sun_len;
@@ -416,9 +357,17 @@ err:
 	return -1;
 }
 
+
+#ifndef CONFIG_HAS_TLS
 int parasite_dump_thread_seized(struct parasite_ctl *ctl, pid_t pid,
 					unsigned int **tid_addr, pid_t *tid,
 					void *blocked)
+#else
+int parasite_dump_thread_seized(struct parasite_ctl *ctl, pid_t pid,
+					unsigned int **tid_addr, pid_t *tid,
+					void *blocked,
+					u32* tls)
+#endif
 {
 	struct parasite_dump_thread *args;
 	int ret;
@@ -431,6 +380,10 @@ int parasite_dump_thread_seized(struct parasite_ctl *ctl, pid_t pid,
 	*tid_addr = args->tid_addr;
 	*tid = args->tid;
 
+#ifdef CONFIG_HAS_TLS
+	*tls = args->tls;
+#endif
+
 	return ret;
 }
 
@@ -602,13 +555,26 @@ int parasite_dump_pages_seized(struct parasite_ctl *ctl, struct list_head *vma_a
 			continue;
 		}
 
+		if (vma_area->vma.end > TASK_SIZE) {
+			continue;
+		}
+
 		ret = parasite_execute(PARASITE_CMD_DUMPPAGES, ctl);
+
 		if (ret) {
 			pr_err("Dumping pages failed with %d\n", ret);
+
+			pr_err("failed to dump vma %"PRIx64"-%"PRIx64": %lu pages %lu skipped %lu total\n",
+				vma_area->vma.start, vma_area->vma.end,
+				parasite_dumppages->nrpages_dumped,
+				parasite_dumppages->nrpages_skipped,
+				parasite_dumppages->nrpages_total);
+
+
 			goto out_fini;
 		}
 
-		pr_info("vma %lx-%lx  dumped: %lu pages %lu skipped %lu total\n",
+		pr_info("vma %"PRIx64"-%"PRIx64" dumped: %lu pages %lu skipped %lu total\n",
 				vma_area->vma.start, vma_area->vma.end,
 				parasite_dumppages->nrpages_dumped,
 				parasite_dumppages->nrpages_skipped,
@@ -730,6 +696,17 @@ int parasite_fini_threads_seized(struct parasite_ctl *ctl, struct pstree_item *i
 	return ret;
 }
 
+#ifdef CONFIG_HAS_TLS
+uint32_t parasite_get_tls_seized(struct parasite_ctl *ctl) {
+	struct parasite_get_tls_args *tls_args;
+
+	tls_args = (struct parasite_get_tls_args*)parasite_args_s(ctl, sizeof(*tls_args));
+	parasite_execute(PARASITE_CMD_GET_TLS, ctl);
+
+	return tls_args->tls;
+}
+#endif
+
 int parasite_cure_seized(struct parasite_ctl *ctl, struct pstree_item *item)
 {
 	int ret = 0;
@@ -793,7 +770,7 @@ struct parasite_ctl *parasite_infect_seized(pid_t pid, struct pstree_item *item,
 		goto err;
 	}
 
-	vma_area = get_vma_by_ip(vma_area_list, ctl->regs_orig.ip);
+	vma_area = get_vma_by_ip(vma_area_list, REG_IP(ctl->regs_orig));
 	if (!vma_area) {
 		pr_err("No suitable VMA found to run parasite "
 		       "bootstrap code (pid: %d)\n", pid);
@@ -885,6 +862,3 @@ err:
 	return NULL;
 }
 
-#else /* CONFIG_X86_64 */
-# error x86-32 is not yet implemented
-#endif /* CONFIG_X86_64 */
diff --git a/pie/parasite.c b/pie/parasite.c
index d9e2a1d..14bb28e 100644
--- a/pie/parasite.c
+++ b/pie/parasite.c
@@ -12,9 +12,7 @@
 
 #include <string.h>
 
-#ifndef CONFIG_X86_64
-#error non-x86-64 mode not yet implemented
-#endif
+#include <arch_parasite.h>
 
 static void *brk_start, *brk_end, *brk_tail;
 
@@ -192,14 +190,14 @@ static int dump_pages(struct parasite_dump_pages_args *args)
 
 	ret = 0;
 	for (pfn = 0; pfn < nrpages; pfn++) {
-		unsigned long vaddr;
+		size_t vaddr;
 
 		if (should_dump_page(&args->vma_entry, map[pfn])) {
 			/*
 			 * That's the optimized write of
 			 * page_entry structure, see image.h
 			 */
-			vaddr = (unsigned long)args->vma_entry.start + pfn * PAGE_SIZE;
+			vaddr = (size_t)args->vma_entry.start + pfn * PAGE_SIZE;
 
 			ret = sys_write_safe(fd_pages, &vaddr, sizeof(vaddr));
 			if (ret)
@@ -286,7 +284,7 @@ static int dump_misc(struct parasite_dump_misc *args)
 
 	args->pid = sys_getpid();
 	args->sid = sys_getsid();
-	args->pgid = sys_getpgid();
+	args->pgid = sys_getpgid(0);
 
 	return 0;
 }
@@ -373,6 +371,10 @@ static int dump_thread(struct parasite_dump_thread *args)
 	args->blocked = s->sig_blocked;
 	args->tid = tid;
 
+#ifdef CONFIG_HAS_TLS
+	args->tls = get_tls();
+#endif
+
 	return 0;
 }
 
@@ -584,6 +586,12 @@ static int parasite_cfg_log(struct parasite_log_args *args)
 	return ret;
 }
 
+#ifdef CONFIG_HAS_TLS
+static void parasite_get_tls(struct parasite_get_tls_args* args) {
+	args->tls = get_tls();
+}
+#endif
+
 static int fini(void)
 {
 	int ret;
@@ -635,6 +643,12 @@ int __used parasite_service(unsigned int cmd, void *args)
 		return parasite_get_proc_fd();
 	case PARASITE_CMD_DUMP_TTY:
 		return parasite_dump_tty(args);
+
+#ifdef CONFIG_HAS_TLS
+	case PARASITE_CMD_GET_TLS:
+		parasite_get_tls((struct parasite_get_tls_args*)args);
+		return 0;
+#endif
 	}
 
 	pr_err("Unknown command to parasite\n");
-- 
1.7.9.5



More information about the CRIU mailing list