[3/6] criu: dump: prepare parasite control for threads at infect time

Submitted by Mike Rapoport on Aug. 13, 2018, 1:29 p.m.

Details

Message ID 1534166953-15041-4-git-send-email-rppt@linux.vnet.ibm.com
State Accepted
Series "lazy-pages: always use pre-copy for stack"
Headers show

Commit Message

Mike Rapoport Aug. 13, 2018, 1:29 p.m.
Currently parasite_thread_ctl for non-leader threads is initialized after we
stop the compel daemon. Moving this initialization earlier will allow us to
make stack pointers of all threads available during memory dump.

Signed-off-by: Mike Rapoport <rppt@linux.vnet.ibm.com>
---
 criu/cr-dump.c                  |  3 ++-
 criu/include/parasite-syscall.h |  6 ++++--
 criu/include/pstree.h           |  1 +
 criu/parasite-syscall.c         | 40 +++++++++++++++++++++++++++++++++-------
 4 files changed, 40 insertions(+), 10 deletions(-)

Patch hide | download patch | download mbox

diff --git a/criu/cr-dump.c b/criu/cr-dump.c
index 6596793..ec5e1e4 100644
--- a/criu/cr-dump.c
+++ b/criu/cr-dump.c
@@ -842,6 +842,7 @@  static int collect_file_locks(void)
 static int dump_task_thread(struct parasite_ctl *parasite_ctl,
 				const struct pstree_item *item, int id)
 {
+	struct parasite_thread_ctl *tctl = dmpi(item)->thread_ctls[id];
 	struct pid *tid = &item->threads[id];
 	CoreEntry *core = item->core[id];
 	pid_t pid = tid->real;
@@ -852,7 +853,7 @@  static int dump_task_thread(struct parasite_ctl *parasite_ctl,
 	pr_info("Dumping core for thread (pid: %d)\n", pid);
 	pr_info("----------------------------------------\n");
 
-	ret = parasite_dump_thread_seized(parasite_ctl, id, tid, core);
+	ret = parasite_dump_thread_seized(tctl, parasite_ctl, id, tid, core);
 	if (ret) {
 		pr_err("Can't dump thread for pid %d\n", pid);
 		goto err;
diff --git a/criu/include/parasite-syscall.h b/criu/include/parasite-syscall.h
index 0e9d340..c86a724 100644
--- a/criu/include/parasite-syscall.h
+++ b/criu/include/parasite-syscall.h
@@ -21,6 +21,7 @@  struct parasite_dump_cgroup_args;
 struct rt_sigframe;
 
 struct parasite_ctl;
+struct parasite_thread_ctl;
 
 extern int parasite_dump_sigacts_seized(struct parasite_ctl *ctl, struct pstree_item *);
 extern int parasite_dump_itimers_seized(struct parasite_ctl *ctl, struct pstree_item *);
@@ -32,8 +33,9 @@  extern int parasite_dump_posix_timers_seized(struct proc_posix_timers_stat *proc
 extern int parasite_dump_misc_seized(struct parasite_ctl *ctl, struct parasite_dump_misc *misc);
 extern int parasite_dump_creds(struct parasite_ctl *ctl, struct _CredsEntry *ce);
 extern int parasite_dump_thread_leader_seized(struct parasite_ctl *ctl, int pid, struct _CoreEntry *core);
-extern int parasite_dump_thread_seized(struct parasite_ctl *ctl, int id,
-					struct pid *tid, struct _CoreEntry *core);
+extern int parasite_dump_thread_seized(struct parasite_thread_ctl *tctl,
+				       struct parasite_ctl *ctl, int id,
+				       struct pid *tid, struct _CoreEntry *core);
 extern int dump_thread_core(int pid, CoreEntry *core,
 					const struct parasite_dump_thread *dt);
 
diff --git a/criu/include/pstree.h b/criu/include/pstree.h
index 508d6df..4913aae 100644
--- a/criu/include/pstree.h
+++ b/criu/include/pstree.h
@@ -56,6 +56,7 @@  struct dmp_info {
 	struct ns_id *netns;
 	struct page_pipe *mem_pp;
 	struct parasite_ctl *parasite_ctl;
+	struct parasite_thread_ctl **thread_ctls;
 };
 
 static inline struct dmp_info *dmpi(const struct pstree_item *i)
diff --git a/criu/parasite-syscall.c b/criu/parasite-syscall.c
index 267d3fa..366c6c9 100644
--- a/criu/parasite-syscall.c
+++ b/criu/parasite-syscall.c
@@ -162,7 +162,8 @@  int parasite_dump_thread_leader_seized(struct parasite_ctl *ctl, int pid, CoreEn
 	return dump_thread_core(pid, core, args);
 }
 
-int parasite_dump_thread_seized(struct parasite_ctl *ctl, int id,
+int parasite_dump_thread_seized(struct parasite_thread_ctl *tctl,
+				struct parasite_ctl *ctl, int id,
 				struct pid *tid, CoreEntry *core)
 {
 	struct parasite_dump_thread *args;
@@ -171,7 +172,6 @@  int parasite_dump_thread_seized(struct parasite_ctl *ctl, int id,
 	CredsEntry *creds = tc->creds;
 	struct parasite_dump_creds *pc;
 	int ret;
-	struct parasite_thread_ctl *tctl;
 
 	BUG_ON(id == 0); /* Leader is dumped in dump_task_core_all */
 
@@ -180,10 +180,6 @@  int parasite_dump_thread_seized(struct parasite_ctl *ctl, int id,
 	pc = args->creds;
 	pc->cap_last_cap = kdat.last_cap;
 
-	tctl = compel_prepare_thread(ctl, pid);
-	if (!tctl)
-		return -1;
-
 	tc->has_blk_sigset = true;
 	memcpy(&tc->blk_sigset, compel_thread_sigmask(tctl), sizeof(k_rtsigset_t));
 	ret = compel_get_thread_regs(tctl, save_task_regs, core);
@@ -468,12 +464,39 @@  static int make_sigframe(void *arg, struct rt_sigframe *sf, struct rt_sigframe *
 	return construct_sigframe(sf, rtsf, bs, (CoreEntry *)arg);
 }
 
+static int parasite_prepare_threads(struct parasite_ctl *ctl,
+				    struct pstree_item *item)
+{
+	struct parasite_thread_ctl **thread_ctls;
+	int i;
+
+	thread_ctls = xzalloc(sizeof(*thread_ctls) * item->nr_threads);
+	if (!thread_ctls)
+		return -1;
+
+	for (i = 0; i < item->nr_threads; i++) {
+		struct pid *tid = &item->threads[i];
+
+		if (item->pid->real == tid->real)
+			continue;
+
+		thread_ctls[i] = compel_prepare_thread(ctl, tid->real);
+		if (!thread_ctls[i])
+			return -1;
+	}
+
+	dmpi(item)->thread_ctls = thread_ctls;
+
+	return 0;
+}
+
 struct parasite_ctl *parasite_infect_seized(pid_t pid, struct pstree_item *item,
 		struct vm_area_list *vma_area_list)
 {
 	struct parasite_ctl *ctl;
 	struct infect_ctx *ictx;
 	unsigned long p;
+	int ret;
 
 	BUG_ON(item->threads[0].real != pid);
 
@@ -487,6 +510,10 @@  struct parasite_ctl *parasite_infect_seized(pid_t pid, struct pstree_item *item,
 	if (!ctl)
 		return NULL;
 
+	ret = parasite_prepare_threads(ctl, item);
+	if (ret)
+		return NULL;
+
 	ictx = compel_infect_ctx(ctl);
 
 	ictx->open_proc = do_open_proc;
@@ -532,4 +559,3 @@  struct parasite_ctl *parasite_infect_seized(pid_t pid, struct pstree_item *item,
 
 	return ctl;
 }
-

Comments

Laurent Dufour Aug. 16, 2018, 4:08 p.m.
On 13/08/2018 15:29, Mike Rapoport wrote:
> Currently parasite_thread_ctl for non-leader threads is initialized after we
> stop the compel daemon. Moving this initialization earlier will allow us to
> make stack pointers of all threads available during memory dump.

I've to admit that I'm no more accurate on that part, so my question could make
no sense: What would happen if a thread dies while dumping the memory, which is
quite a long operation ?

Cheers,
Laurent.


> Signed-off-by: Mike Rapoport <rppt@linux.vnet.ibm.com>
> ---
>  criu/cr-dump.c                  |  3 ++-
>  criu/include/parasite-syscall.h |  6 ++++--
>  criu/include/pstree.h           |  1 +
>  criu/parasite-syscall.c         | 40 +++++++++++++++++++++++++++++++++-------
>  4 files changed, 40 insertions(+), 10 deletions(-)
> 
> diff --git a/criu/cr-dump.c b/criu/cr-dump.c
> index 6596793..ec5e1e4 100644
> --- a/criu/cr-dump.c
> +++ b/criu/cr-dump.c
> @@ -842,6 +842,7 @@ static int collect_file_locks(void)
>  static int dump_task_thread(struct parasite_ctl *parasite_ctl,
>  				const struct pstree_item *item, int id)
>  {
> +	struct parasite_thread_ctl *tctl = dmpi(item)->thread_ctls[id];
>  	struct pid *tid = &item->threads[id];
>  	CoreEntry *core = item->core[id];
>  	pid_t pid = tid->real;
> @@ -852,7 +853,7 @@ static int dump_task_thread(struct parasite_ctl *parasite_ctl,
>  	pr_info("Dumping core for thread (pid: %d)\n", pid);
>  	pr_info("----------------------------------------\n");
> 
> -	ret = parasite_dump_thread_seized(parasite_ctl, id, tid, core);
> +	ret = parasite_dump_thread_seized(tctl, parasite_ctl, id, tid, core);
>  	if (ret) {
>  		pr_err("Can't dump thread for pid %d\n", pid);
>  		goto err;
> diff --git a/criu/include/parasite-syscall.h b/criu/include/parasite-syscall.h
> index 0e9d340..c86a724 100644
> --- a/criu/include/parasite-syscall.h
> +++ b/criu/include/parasite-syscall.h
> @@ -21,6 +21,7 @@ struct parasite_dump_cgroup_args;
>  struct rt_sigframe;
> 
>  struct parasite_ctl;
> +struct parasite_thread_ctl;
> 
>  extern int parasite_dump_sigacts_seized(struct parasite_ctl *ctl, struct pstree_item *);
>  extern int parasite_dump_itimers_seized(struct parasite_ctl *ctl, struct pstree_item *);
> @@ -32,8 +33,9 @@ extern int parasite_dump_posix_timers_seized(struct proc_posix_timers_stat *proc
>  extern int parasite_dump_misc_seized(struct parasite_ctl *ctl, struct parasite_dump_misc *misc);
>  extern int parasite_dump_creds(struct parasite_ctl *ctl, struct _CredsEntry *ce);
>  extern int parasite_dump_thread_leader_seized(struct parasite_ctl *ctl, int pid, struct _CoreEntry *core);
> -extern int parasite_dump_thread_seized(struct parasite_ctl *ctl, int id,
> -					struct pid *tid, struct _CoreEntry *core);
> +extern int parasite_dump_thread_seized(struct parasite_thread_ctl *tctl,
> +				       struct parasite_ctl *ctl, int id,
> +				       struct pid *tid, struct _CoreEntry *core);
>  extern int dump_thread_core(int pid, CoreEntry *core,
>  					const struct parasite_dump_thread *dt);
> 
> diff --git a/criu/include/pstree.h b/criu/include/pstree.h
> index 508d6df..4913aae 100644
> --- a/criu/include/pstree.h
> +++ b/criu/include/pstree.h
> @@ -56,6 +56,7 @@ struct dmp_info {
>  	struct ns_id *netns;
>  	struct page_pipe *mem_pp;
>  	struct parasite_ctl *parasite_ctl;
> +	struct parasite_thread_ctl **thread_ctls;
>  };
> 
>  static inline struct dmp_info *dmpi(const struct pstree_item *i)
> diff --git a/criu/parasite-syscall.c b/criu/parasite-syscall.c
> index 267d3fa..366c6c9 100644
> --- a/criu/parasite-syscall.c
> +++ b/criu/parasite-syscall.c
> @@ -162,7 +162,8 @@ int parasite_dump_thread_leader_seized(struct parasite_ctl *ctl, int pid, CoreEn
>  	return dump_thread_core(pid, core, args);
>  }
> 
> -int parasite_dump_thread_seized(struct parasite_ctl *ctl, int id,
> +int parasite_dump_thread_seized(struct parasite_thread_ctl *tctl,
> +				struct parasite_ctl *ctl, int id,
>  				struct pid *tid, CoreEntry *core)
>  {
>  	struct parasite_dump_thread *args;
> @@ -171,7 +172,6 @@ int parasite_dump_thread_seized(struct parasite_ctl *ctl, int id,
>  	CredsEntry *creds = tc->creds;
>  	struct parasite_dump_creds *pc;
>  	int ret;
> -	struct parasite_thread_ctl *tctl;
> 
>  	BUG_ON(id == 0); /* Leader is dumped in dump_task_core_all */
> 
> @@ -180,10 +180,6 @@ int parasite_dump_thread_seized(struct parasite_ctl *ctl, int id,
>  	pc = args->creds;
>  	pc->cap_last_cap = kdat.last_cap;
> 
> -	tctl = compel_prepare_thread(ctl, pid);
> -	if (!tctl)
> -		return -1;
> -
>  	tc->has_blk_sigset = true;
>  	memcpy(&tc->blk_sigset, compel_thread_sigmask(tctl), sizeof(k_rtsigset_t));
>  	ret = compel_get_thread_regs(tctl, save_task_regs, core);
> @@ -468,12 +464,39 @@ static int make_sigframe(void *arg, struct rt_sigframe *sf, struct rt_sigframe *
>  	return construct_sigframe(sf, rtsf, bs, (CoreEntry *)arg);
>  }
> 
> +static int parasite_prepare_threads(struct parasite_ctl *ctl,
> +				    struct pstree_item *item)
> +{
> +	struct parasite_thread_ctl **thread_ctls;
> +	int i;
> +
> +	thread_ctls = xzalloc(sizeof(*thread_ctls) * item->nr_threads);
> +	if (!thread_ctls)
> +		return -1;
> +
> +	for (i = 0; i < item->nr_threads; i++) {
> +		struct pid *tid = &item->threads[i];
> +
> +		if (item->pid->real == tid->real)
> +			continue;
> +
> +		thread_ctls[i] = compel_prepare_thread(ctl, tid->real);
> +		if (!thread_ctls[i])
> +			return -1;
> +	}
> +
> +	dmpi(item)->thread_ctls = thread_ctls;
> +
> +	return 0;
> +}
> +
>  struct parasite_ctl *parasite_infect_seized(pid_t pid, struct pstree_item *item,
>  		struct vm_area_list *vma_area_list)
>  {
>  	struct parasite_ctl *ctl;
>  	struct infect_ctx *ictx;
>  	unsigned long p;
> +	int ret;
> 
>  	BUG_ON(item->threads[0].real != pid);
> 
> @@ -487,6 +510,10 @@ struct parasite_ctl *parasite_infect_seized(pid_t pid, struct pstree_item *item,
>  	if (!ctl)
>  		return NULL;
> 
> +	ret = parasite_prepare_threads(ctl, item);
> +	if (ret)
> +		return NULL;
> +
>  	ictx = compel_infect_ctx(ctl);
> 
>  	ictx->open_proc = do_open_proc;
> @@ -532,4 +559,3 @@ struct parasite_ctl *parasite_infect_seized(pid_t pid, struct pstree_item *item,
> 
>  	return ctl;
>  }
> -
>
Mike Rapoport Aug. 16, 2018, 4:30 p.m.
On Thu, Aug 16, 2018 at 06:08:56PM +0200, Laurent Dufour wrote:
> On 13/08/2018 15:29, Mike Rapoport wrote:
> > Currently parasite_thread_ctl for non-leader threads is initialized after we
> > stop the compel daemon. Moving this initialization earlier will allow us to
> > make stack pointers of all threads available during memory dump.
> 
> I've to admit that I'm no more accurate on that part, so my question could make
> no sense: What would happen if a thread dies while dumping the memory, which is
> quite a long operation ?

By the time memory dump happens all the threads are anyway stopped.
Currently we just collect thread data late in the process, but threads are
nor running.
 
> Cheers,
> Laurent.
> 
> 
> > Signed-off-by: Mike Rapoport <rppt@linux.vnet.ibm.com>
> > ---
> >  criu/cr-dump.c                  |  3 ++-
> >  criu/include/parasite-syscall.h |  6 ++++--
> >  criu/include/pstree.h           |  1 +
> >  criu/parasite-syscall.c         | 40 +++++++++++++++++++++++++++++++++-------
> >  4 files changed, 40 insertions(+), 10 deletions(-)
> > 
> > diff --git a/criu/cr-dump.c b/criu/cr-dump.c
> > index 6596793..ec5e1e4 100644
> > --- a/criu/cr-dump.c
> > +++ b/criu/cr-dump.c
> > @@ -842,6 +842,7 @@ static int collect_file_locks(void)
> >  static int dump_task_thread(struct parasite_ctl *parasite_ctl,
> >  				const struct pstree_item *item, int id)
> >  {
> > +	struct parasite_thread_ctl *tctl = dmpi(item)->thread_ctls[id];
> >  	struct pid *tid = &item->threads[id];
> >  	CoreEntry *core = item->core[id];
> >  	pid_t pid = tid->real;
> > @@ -852,7 +853,7 @@ static int dump_task_thread(struct parasite_ctl *parasite_ctl,
> >  	pr_info("Dumping core for thread (pid: %d)\n", pid);
> >  	pr_info("----------------------------------------\n");
> > 
> > -	ret = parasite_dump_thread_seized(parasite_ctl, id, tid, core);
> > +	ret = parasite_dump_thread_seized(tctl, parasite_ctl, id, tid, core);
> >  	if (ret) {
> >  		pr_err("Can't dump thread for pid %d\n", pid);
> >  		goto err;
> > diff --git a/criu/include/parasite-syscall.h b/criu/include/parasite-syscall.h
> > index 0e9d340..c86a724 100644
> > --- a/criu/include/parasite-syscall.h
> > +++ b/criu/include/parasite-syscall.h
> > @@ -21,6 +21,7 @@ struct parasite_dump_cgroup_args;
> >  struct rt_sigframe;
> > 
> >  struct parasite_ctl;
> > +struct parasite_thread_ctl;
> > 
> >  extern int parasite_dump_sigacts_seized(struct parasite_ctl *ctl, struct pstree_item *);
> >  extern int parasite_dump_itimers_seized(struct parasite_ctl *ctl, struct pstree_item *);
> > @@ -32,8 +33,9 @@ extern int parasite_dump_posix_timers_seized(struct proc_posix_timers_stat *proc
> >  extern int parasite_dump_misc_seized(struct parasite_ctl *ctl, struct parasite_dump_misc *misc);
> >  extern int parasite_dump_creds(struct parasite_ctl *ctl, struct _CredsEntry *ce);
> >  extern int parasite_dump_thread_leader_seized(struct parasite_ctl *ctl, int pid, struct _CoreEntry *core);
> > -extern int parasite_dump_thread_seized(struct parasite_ctl *ctl, int id,
> > -					struct pid *tid, struct _CoreEntry *core);
> > +extern int parasite_dump_thread_seized(struct parasite_thread_ctl *tctl,
> > +				       struct parasite_ctl *ctl, int id,
> > +				       struct pid *tid, struct _CoreEntry *core);
> >  extern int dump_thread_core(int pid, CoreEntry *core,
> >  					const struct parasite_dump_thread *dt);
> > 
> > diff --git a/criu/include/pstree.h b/criu/include/pstree.h
> > index 508d6df..4913aae 100644
> > --- a/criu/include/pstree.h
> > +++ b/criu/include/pstree.h
> > @@ -56,6 +56,7 @@ struct dmp_info {
> >  	struct ns_id *netns;
> >  	struct page_pipe *mem_pp;
> >  	struct parasite_ctl *parasite_ctl;
> > +	struct parasite_thread_ctl **thread_ctls;
> >  };
> > 
> >  static inline struct dmp_info *dmpi(const struct pstree_item *i)
> > diff --git a/criu/parasite-syscall.c b/criu/parasite-syscall.c
> > index 267d3fa..366c6c9 100644
> > --- a/criu/parasite-syscall.c
> > +++ b/criu/parasite-syscall.c
> > @@ -162,7 +162,8 @@ int parasite_dump_thread_leader_seized(struct parasite_ctl *ctl, int pid, CoreEn
> >  	return dump_thread_core(pid, core, args);
> >  }
> > 
> > -int parasite_dump_thread_seized(struct parasite_ctl *ctl, int id,
> > +int parasite_dump_thread_seized(struct parasite_thread_ctl *tctl,
> > +				struct parasite_ctl *ctl, int id,
> >  				struct pid *tid, CoreEntry *core)
> >  {
> >  	struct parasite_dump_thread *args;
> > @@ -171,7 +172,6 @@ int parasite_dump_thread_seized(struct parasite_ctl *ctl, int id,
> >  	CredsEntry *creds = tc->creds;
> >  	struct parasite_dump_creds *pc;
> >  	int ret;
> > -	struct parasite_thread_ctl *tctl;
> > 
> >  	BUG_ON(id == 0); /* Leader is dumped in dump_task_core_all */
> > 
> > @@ -180,10 +180,6 @@ int parasite_dump_thread_seized(struct parasite_ctl *ctl, int id,
> >  	pc = args->creds;
> >  	pc->cap_last_cap = kdat.last_cap;
> > 
> > -	tctl = compel_prepare_thread(ctl, pid);
> > -	if (!tctl)
> > -		return -1;
> > -
> >  	tc->has_blk_sigset = true;
> >  	memcpy(&tc->blk_sigset, compel_thread_sigmask(tctl), sizeof(k_rtsigset_t));
> >  	ret = compel_get_thread_regs(tctl, save_task_regs, core);
> > @@ -468,12 +464,39 @@ static int make_sigframe(void *arg, struct rt_sigframe *sf, struct rt_sigframe *
> >  	return construct_sigframe(sf, rtsf, bs, (CoreEntry *)arg);
> >  }
> > 
> > +static int parasite_prepare_threads(struct parasite_ctl *ctl,
> > +				    struct pstree_item *item)
> > +{
> > +	struct parasite_thread_ctl **thread_ctls;
> > +	int i;
> > +
> > +	thread_ctls = xzalloc(sizeof(*thread_ctls) * item->nr_threads);
> > +	if (!thread_ctls)
> > +		return -1;
> > +
> > +	for (i = 0; i < item->nr_threads; i++) {
> > +		struct pid *tid = &item->threads[i];
> > +
> > +		if (item->pid->real == tid->real)
> > +			continue;
> > +
> > +		thread_ctls[i] = compel_prepare_thread(ctl, tid->real);
> > +		if (!thread_ctls[i])
> > +			return -1;
> > +	}
> > +
> > +	dmpi(item)->thread_ctls = thread_ctls;
> > +
> > +	return 0;
> > +}
> > +
> >  struct parasite_ctl *parasite_infect_seized(pid_t pid, struct pstree_item *item,
> >  		struct vm_area_list *vma_area_list)
> >  {
> >  	struct parasite_ctl *ctl;
> >  	struct infect_ctx *ictx;
> >  	unsigned long p;
> > +	int ret;
> > 
> >  	BUG_ON(item->threads[0].real != pid);
> > 
> > @@ -487,6 +510,10 @@ struct parasite_ctl *parasite_infect_seized(pid_t pid, struct pstree_item *item,
> >  	if (!ctl)
> >  		return NULL;
> > 
> > +	ret = parasite_prepare_threads(ctl, item);
> > +	if (ret)
> > +		return NULL;
> > +
> >  	ictx = compel_infect_ctx(ctl);
> > 
> >  	ictx->open_proc = do_open_proc;
> > @@ -532,4 +559,3 @@ struct parasite_ctl *parasite_infect_seized(pid_t pid, struct pstree_item *item,
> > 
> >  	return ctl;
> >  }
> > -
> >