[CRIU] [PATCH 03/22] pstree: Bind CoreEntry to pstree and fill it with registers early

Andrey Vagin avagin at openvz.org
Wed May 8 09:28:30 EDT 2013


From: Cyrill Gorcunov <gorcunov at openvz.org>

When parasite daemon mode will be implemented we get deprived of ability
to fetch registers at the late moment of dumping as we were, thus just
bind CoreEntry to pstree item and allocate CoreEntry'ies for every
thread found, once process tree is in seized state.

Then immediately fill CoreEntry'ies with registers. We use prctl
opcode for that but fetch a complete set of registers including
FPU state, and convert them into protobuf format.

Zombie tasks remains untouched, we allocate CoreEntry for them
right at moment of dumping becuase we don't need registers there
to be written on disk.

This way get_task_regs no longer need parasite_ctl argument
and it's zapped.

Still parasite_ctl has own copy of general registers set but
this is because we need them to be in cpu native format unlike
ones kept in CoreEntry.

Signed-off-by: Cyrill Gorcunov <gorcunov at openvz.org>
Signed-off-by: Andrey Vagin <avagin at openvz.org>
---
 arch/arm/crtools.c          |  12 ++---
 arch/arm/include/asm/dump.h |   2 +-
 arch/x86/crtools.c          |  12 ++---
 arch/x86/include/asm/dump.h |   2 +-
 cr-dump.c                   | 125 +++++++++++++++-----------------------------
 include/pstree.h            |   7 +++
 pstree.c                    |  80 ++++++++++++++++++++++++++++
 7 files changed, 139 insertions(+), 101 deletions(-)

diff --git a/arch/arm/crtools.c b/arch/arm/crtools.c
index d90d4db..e8129e4 100644
--- a/arch/arm/crtools.c
+++ b/arch/arm/crtools.c
@@ -85,7 +85,7 @@ int syscall_seized(struct parasite_ctl *ctl, int nr, unsigned long *ret,
 #define assign_reg(dst, src, e)		dst->e = (__typeof__(dst->e))src.ARM_##e
 
 #define PTRACE_GETVFPREGS 27
-int get_task_regs(pid_t pid, CoreEntry *core, const struct parasite_ctl *ctl)
+int get_task_regs(pid_t pid, CoreEntry *core)
 {
 	user_regs_struct_t regs = {{-1}};
 	struct user_vfp vfp;
@@ -93,13 +93,9 @@ int get_task_regs(pid_t pid, CoreEntry *core, const struct parasite_ctl *ctl)
 
 	pr_info("Dumping GP/FPU registers for %d\n", pid);
 
-	if (ctl)
-		regs = ctl->regs_orig;
-	else {
-		if (ptrace(PTRACE_GETREGS, pid, NULL, &regs)) {
-			pr_err("Can't obtain GP registers for %d\n", pid);
-			goto err;
-		}
+	if (ptrace(PTRACE_GETREGS, pid, NULL, &regs)) {
+		pr_err("Can't obtain GP registers for %d\n", pid);
+		goto err;
 	}
 
 	if (ptrace(PTRACE_GETVFPREGS, pid, NULL, &vfp)) {
diff --git a/arch/arm/include/asm/dump.h b/arch/arm/include/asm/dump.h
index ef8772a..1f20980 100644
--- a/arch/arm/include/asm/dump.h
+++ b/arch/arm/include/asm/dump.h
@@ -1,7 +1,7 @@
 #ifndef __CR_ASM_DUMP_H__
 #define __CR_ASM_DUMP_H__
 
-extern int get_task_regs(pid_t pid, CoreEntry *core, const struct parasite_ctl *ctl);
+extern int get_task_regs(pid_t pid, CoreEntry *core);
 extern int arch_alloc_thread_info(CoreEntry *core);
 extern void arch_free_thread_info(CoreEntry *core);
 
diff --git a/arch/x86/crtools.c b/arch/x86/crtools.c
index e7e9d63..eba6ad3 100644
--- a/arch/x86/crtools.c
+++ b/arch/x86/crtools.c
@@ -106,7 +106,7 @@ int syscall_seized(struct parasite_ctl *ctl, int nr, unsigned long *ret,
 	return 0;
 }
 
-int get_task_regs(pid_t pid, CoreEntry *core, const struct parasite_ctl *ctl)
+int get_task_regs(pid_t pid, CoreEntry *core)
 {
 	struct xsave_struct xsave	= {  };
 	user_regs_struct_t regs		= {-1};
@@ -116,13 +116,9 @@ int get_task_regs(pid_t pid, CoreEntry *core, const struct parasite_ctl *ctl)
 
 	pr_info("Dumping GP/FPU registers for %d\n", pid);
 
-	if (ctl)
-		regs = ctl->regs_orig;
-	else {
-		if (ptrace(PTRACE_GETREGS, pid, NULL, &regs)) {
-			pr_err("Can't obtain GP registers for %d\n", pid);
-			goto err;
-		}
+	if (ptrace(PTRACE_GETREGS, pid, NULL, &regs)) {
+		pr_err("Can't obtain GP registers for %d\n", pid);
+		goto err;
 	}
 
 	/* Did we come from a system call? */
diff --git a/arch/x86/include/asm/dump.h b/arch/x86/include/asm/dump.h
index 2333fec..1013981 100644
--- a/arch/x86/include/asm/dump.h
+++ b/arch/x86/include/asm/dump.h
@@ -1,7 +1,7 @@
 #ifndef __CR_ASM_DUMP_H__
 #define __CR_ASM_DUMP_H__
 
-extern int get_task_regs(pid_t pid, CoreEntry *core, const struct parasite_ctl *ctl);
+extern int get_task_regs(pid_t pid, CoreEntry *core);
 extern int arch_alloc_thread_info(CoreEntry *core);
 extern void arch_free_thread_info(CoreEntry *core);
 
diff --git a/cr-dump.c b/cr-dump.c
index 5743551..8a18a15 100644
--- a/cr-dump.c
+++ b/cr-dump.c
@@ -586,50 +586,6 @@ static int dump_task_kobj_ids(struct pstree_item *item)
 	return 0;
 }
 
-static void core_entry_free(CoreEntry *core)
-{
-	if (core) {
-		arch_free_thread_info(core);
-		xfree(core->thread_core);
-		xfree(core->tc);
-		xfree(core->ids);
-		xfree(core);
-	}
-}
-
-static CoreEntry *core_entry_alloc(int alloc_thread_info,
-				   int alloc_tc)
-{
-	CoreEntry *core;
-	TaskCoreEntry *tc;
-
-	core = xmalloc(sizeof(*core));
-	if (!core)
-		return NULL;
-	core_entry__init(core);
-
-	core->mtype = CORE_ENTRY__MARCH;
-
-	if (alloc_thread_info) {
-		if (arch_alloc_thread_info(core))
-			goto err;
-	}
-
-	if (alloc_tc) {
-		tc = xzalloc(sizeof(*tc) + TASK_COMM_LEN);
-		if (!tc)
-			goto err;
-		task_core_entry__init(tc);
-		tc->comm = (void *)tc + sizeof(*tc);
-		core->tc = tc;
-	}
-
-	return core;
-err:
-	core_entry_free(core);
-	return NULL;
-}
-
 int get_task_ids(struct pstree_item *item)
 {
 	int ret;
@@ -665,41 +621,33 @@ static int dump_task_ids(struct pstree_item *item, const struct cr_fdset *cr_fds
 }
 
 static int dump_task_core_all(struct parasite_ctl *ctl,
+		CoreEntry *core,
 		const struct proc_pid_stat *stat,
 		const struct parasite_dump_misc *misc,
 		struct vm_area_list *vma_area_list,
 		const struct cr_fdset *cr_fdset)
 {
 	int fd_core = fdset_fd(cr_fdset, CR_FD_CORE);
-	CoreEntry *core;
 	int ret = -1;
 	pid_t pid = ctl->pid.real;
 
-	core = core_entry_alloc(1, 1);
-	if (!core)
-		return -1;
-
 	pr_info("\n");
 	pr_info("Dumping core (pid: %d)\n", pid);
 	pr_info("----------------------------------------\n");
 
 	ret = dump_task_mm(ctl, stat, misc, cr_fdset);
 	if (ret)
-		goto err_free;
-
-	ret = get_task_regs(pid, core, ctl);
-	if (ret)
-		goto err_free;
+		goto err;
 
 	mark_stack_vma(CORE_THREAD_ARCH_INFO(core)->gpregs->sp, &vma_area_list->h);
 
 	ret = get_task_futex_robust_list(pid, core->thread_core);
 	if (ret)
-		goto err_free;
+		goto err;
 
 	ret = get_task_personality(pid, &core->tc->personality);
 	if (ret)
-		goto err_free;
+		goto err;
 
 	strncpy((char *)core->tc->comm, stat->comm, TASK_COMM_LEN);
 	core->tc->flags = stat->flags;
@@ -711,16 +659,15 @@ static int dump_task_core_all(struct parasite_ctl *ctl,
 
 	ret = dump_sched_info(pid, core->thread_core);
 	if (ret)
-		goto err_free;
+		goto err;
 
 	core_put_tls(core, misc->tls);
 
 	ret = pb_write_one(fd_core, core, PB_CORE);
 	if (ret < 0)
-		goto err_free;
+		goto err;
 
-err_free:
-	core_entry_free(core);
+err:
 	pr_info("----------------------------------------\n");
 
 	return ret;
@@ -1121,9 +1068,9 @@ static int collect_file_locks(const struct cr_options *opts)
 
 }
 
-static int dump_task_thread(struct parasite_ctl *parasite_ctl, struct pid *tid)
+static int dump_task_thread(struct parasite_ctl *parasite_ctl,
+			    struct pid *tid, CoreEntry *core)
 {
-	CoreEntry *core;
 	int ret = -1, fd_core;
 	pid_t pid = tid->real;
 
@@ -1131,39 +1078,29 @@ static int dump_task_thread(struct parasite_ctl *parasite_ctl, struct pid *tid)
 	pr_info("Dumping core for thread (pid: %d)\n", pid);
 	pr_info("----------------------------------------\n");
 
-	core = core_entry_alloc(1, 0);
-	if (!core)
-		goto err;
-
-	ret = get_task_regs(pid, core, NULL);
-	if (ret)
-		goto err_free;
-
 	ret = get_task_futex_robust_list(pid, core->thread_core);
 	if (ret)
-		goto err_free;
+		goto err;
 
 	ret = parasite_dump_thread_seized(parasite_ctl, tid, core);
 	if (ret) {
 		pr_err("Can't dump thread for pid %d\n", pid);
-		goto err_free;
+		goto err;
 	}
 
 	core->thread_core->has_blk_sigset = true;
 
 	ret = dump_sched_info(pid, core->thread_core);
 	if (ret)
-		goto err_free;
+		goto err;
 
 	fd_core = open_image(CR_FD_CORE, O_DUMP, tid->virt);
 	if (fd_core < 0)
-		goto err_free;
+		goto err;
 
 	ret = pb_write_one(fd_core, core, PB_CORE);
 
 	close(fd_core);
-err_free:
-	core_entry_free(core);
 err:
 	pr_info("----------------------------------------\n");
 	return ret;
@@ -1176,21 +1113,20 @@ static int dump_one_zombie(const struct pstree_item *item,
 	int ret = -1, fd_core;
 
 	core = core_entry_alloc(0, 1);
-	if (core == NULL)
-		goto err;
+	if (!core)
+		return -1;
 
 	core->tc->task_state = TASK_DEAD;
 	core->tc->exit_code = pps->exit_code;
 
 	fd_core = open_image(CR_FD_CORE, O_DUMP, item->pid.virt);
 	if (fd_core < 0)
-		goto err_free;
+		goto err;
 
 	ret = pb_write_one(fd_core, core, PB_CORE);
 	close(fd_core);
-err_free:
-	core_entry_free(core);
 err:
+	core_entry_free(core);
 	return ret;
 }
 
@@ -1263,7 +1199,7 @@ static int dump_task_threads(struct parasite_ctl *parasite_ctl,
 		if (item->pid.real == item->threads[i].real)
 			item->threads[i].virt = item->pid.virt;
 		else {
-			if (dump_task_thread(parasite_ctl, &item->threads[i]))
+			if (dump_task_thread(parasite_ctl, &item->threads[i], item->core[i]))
 				return -1;
 		}
 
@@ -1359,6 +1295,26 @@ err:
 	return ret;
 }
 
+static int collect_regs_seized(struct pstree_item *item)
+{
+	unsigned int i;
+	int ret;
+
+	if (pstree_alloc_cores(item))
+		return -1;
+
+	for (i = 0; i < item->nr_threads; i++) {
+		pid_t pid = item->threads[i].real;
+		ret = get_task_regs(pid, item->core[i]);
+		if (ret) {
+			pr_err("Can't obtain regs for thread %d\n", pid);
+			return -1;
+		}
+	}
+
+	return 0;
+}
+
 static int dump_one_task(struct pstree_item *item)
 {
 	pid_t pid = item->pid.real;
@@ -1381,6 +1337,9 @@ static int dump_one_task(struct pstree_item *item)
 	if (item->state == TASK_DEAD)
 		return 0;
 
+	if (collect_regs_seized(item))
+		return -1;
+
 	dfds = xmalloc(sizeof(*dfds));
 	if (!dfds)
 		goto err_free;
@@ -1481,7 +1440,7 @@ static int dump_one_task(struct pstree_item *item)
 		goto err_cure;
 	}
 
-	ret = dump_task_core_all(parasite_ctl, &pps_buf, &misc, &vmas, cr_fdset);
+	ret = dump_task_core_all(parasite_ctl, item->this_core, &pps_buf, &misc, &vmas, cr_fdset);
 	if (ret) {
 		pr_err("Dump core (pid: %d) failed with %d\n", pid, ret);
 		goto err_cure;
diff --git a/include/pstree.h b/include/pstree.h
index b024c3d..b9b3c87 100644
--- a/include/pstree.h
+++ b/include/pstree.h
@@ -41,7 +41,9 @@ struct pstree_item {
 
 	int			nr_threads;	/* number of threads */
 	struct pid		*threads;	/* array of threads */
+	CoreEntry		**core;
 	TaskKobjIdsEntry	*ids;
+	CoreEntry		*this_core;	/* for fast access to a leader */
 
 	struct rst_info		rst[0];
 };
@@ -76,4 +78,9 @@ extern struct task_entries *task_entries;
 int get_task_ids(struct pstree_item *);
 extern struct _TaskKobjIdsEntry *root_ids;
 
+extern void core_entry_free(CoreEntry *core);
+extern CoreEntry *core_entry_alloc(int alloc_thread_info, int alloc_tc);
+extern int pstree_alloc_cores(struct pstree_item *item);
+extern void pstree_free_cores(struct pstree_item *item);
+
 #endif /* __CR_PSTREE_H__ */
diff --git a/pstree.c b/pstree.c
index cb089dc..8623fc6 100644
--- a/pstree.c
+++ b/pstree.c
@@ -16,6 +16,85 @@
 
 struct pstree_item *root_item;
 
+void core_entry_free(CoreEntry *core)
+{
+	if (core) {
+		arch_free_thread_info(core);
+		xfree(core->thread_core);
+		xfree(core->tc);
+		xfree(core->ids);
+	}
+}
+
+CoreEntry *core_entry_alloc(int alloc_thread_info, int alloc_tc)
+{
+	CoreEntry *core;
+	TaskCoreEntry *tc;
+
+	core = xmalloc(sizeof(*core));
+	if (!core)
+		return NULL;
+	core_entry__init(core);
+
+	core->mtype = CORE_ENTRY__MARCH;
+
+	if (alloc_thread_info) {
+		if (arch_alloc_thread_info(core))
+			goto err;
+	}
+
+	if (alloc_tc) {
+		tc = xzalloc(sizeof(*tc) + TASK_COMM_LEN);
+		if (!tc)
+			goto err;
+		task_core_entry__init(tc);
+		tc->comm = (void *)tc + sizeof(*tc);
+		core->tc = tc;
+	}
+
+	return core;
+err:
+	core_entry_free(core);
+	return NULL;
+}
+
+int pstree_alloc_cores(struct pstree_item *item)
+{
+	unsigned int i;
+
+	item->core = xzalloc(sizeof(*item->core) * item->nr_threads);
+	if (!item->core)
+		return -1;
+
+	for (i = 0; i < item->nr_threads; i++) {
+		if (item->threads[i].real == item->pid.real) {
+			item->core[i] = core_entry_alloc(1, 1);
+			item->this_core = item->core[i];
+		} else
+			item->core[i] = core_entry_alloc(1, 0);
+
+		if (!item->core[i])
+			goto err;
+	}
+
+	return 0;
+err:
+	pstree_free_cores(item);
+	return -1;
+}
+
+void pstree_free_cores(struct pstree_item *item)
+{
+	unsigned int i;
+
+	if (item->core) {
+		for (i = 1; i < item->nr_threads; i++)
+			core_entry_free(item->core[i]);
+		xfree(item->core);
+		item->core = NULL;
+	}
+}
+
 void free_pstree(struct pstree_item *root_item)
 {
 	struct pstree_item *item = root_item, *parent;
@@ -28,6 +107,7 @@ void free_pstree(struct pstree_item *root_item)
 
 		parent = item->parent;
 		list_del(&item->sibling);
+		pstree_free_cores(item);
 		xfree(item->threads);
 		xfree(item);
 		item = parent;
-- 
1.8.2



More information about the CRIU mailing list