[v2,15/57] pid: Alloc threads dynamically

Submitted by Kirill Tkhai on March 28, 2017, 3:36 p.m.

Details

Message ID 149071538504.12770.528553800196729224.stgit@localhost.localdomain
State New
Series "Nested pid namespaces support"
Headers show

Commit Message

Kirill Tkhai March 28, 2017, 3:36 p.m.
Threads pid values also may be multi-level, so allocate
them dynamically.

Signed-off-by: Kirill Tkhai <ktkhai@virtuozzo.com>
---
 criu/cr-dump.c            |   10 +++++-----
 criu/cr-restore.c         |   14 +++++++-------
 criu/files-reg.c          |    4 ++--
 criu/include/proc_parse.h |    2 +-
 criu/include/pstree.h     |    2 +-
 criu/parasite-syscall.c   |    2 +-
 criu/proc_parse.c         |   23 ++++++++++++++++-------
 criu/pstree.c             |   23 +++++++++++++----------
 criu/seize.c              |   32 ++++++++++++++++++++++----------
 9 files changed, 68 insertions(+), 44 deletions(-)

Patch hide | download patch | download mbox

diff --git a/criu/cr-dump.c b/criu/cr-dump.c
index c61bb263..018c61d1 100644
--- a/criu/cr-dump.c
+++ b/criu/cr-dump.c
@@ -821,7 +821,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 pid *tid = &item->threads[id];
+	struct pid *tid = item->threads[id];
 	CoreEntry *core = item->core[id];
 	pid_t pid = tid->real;
 	int ret = -1;
@@ -963,9 +963,9 @@  static int dump_task_signals(pid_t pid, struct pstree_item *item)
 
 	/* Dump private signals for each thread */
 	for (i = 0; i < item->nr_threads; i++) {
-		ret = dump_signal_queue(item->threads[i].real, &item->core[i]->thread_core->signals_p, false);
+		ret = dump_signal_queue(item->threads[i]->real, &item->core[i]->thread_core->signals_p, false);
 		if (ret) {
-			pr_err("Can't dump private signals for thread %d\n", item->threads[i].real);
+			pr_err("Can't dump private signals for thread %d\n", item->threads[i]->real);
 			return -1;
 		}
 	}
@@ -989,8 +989,8 @@  static int dump_task_threads(struct parasite_ctl *parasite_ctl,
 
 	for (i = 0; i < item->nr_threads; i++) {
 		/* Leader is already dumped */
-		if (item->pid->real == item->threads[i].real) {
-			item->threads[i].ns[0].virt = vpid(item);
+		if (item->pid->real == item->threads[i]->real) {
+			item->threads[i]->ns[0].virt = vpid(item);
 			continue;
 		}
 		if (dump_task_thread(parasite_ctl, item, i))
diff --git a/criu/cr-restore.c b/criu/cr-restore.c
index 5795f645..1434971a 100644
--- a/criu/cr-restore.c
+++ b/criu/cr-restore.c
@@ -578,7 +578,7 @@  static int open_cores(int pid, CoreEntry *leader_core)
 		goto err;
 
 	for (i = 0; i < current->nr_threads; i++) {
-		tpid = current->threads[i].ns[0].virt;
+		tpid = current->threads[i]->ns[0].virt;
 
 		if (tpid == pid)
 			cores[i] = leader_core;
@@ -1571,7 +1571,7 @@  static int attach_to_tasks(bool root_seized)
 			return -1;
 
 		for (i = 0; i < item->nr_threads; i++) {
-			pid_t pid = item->threads[i].real;
+			pid_t pid = item->threads[i]->real;
 
 			if (item != root_item || !root_seized || i != 0) {
 				if (ptrace(PTRACE_SEIZE, pid, 0, 0)) {
@@ -1624,7 +1624,7 @@  static int catch_tasks(bool root_seized, enum trace_flags *flag)
 			return -1;
 
 		for (i = 0; i < item->nr_threads; i++) {
-			pid_t pid = item->threads[i].real;
+			pid_t pid = item->threads[i]->real;
 
 			if (ptrace(PTRACE_INTERRUPT, pid, 0, 0)) {
 				pr_perror("Can't interrupt the %d task", pid);
@@ -1658,7 +1658,7 @@  static int clear_breakpoints()
 		if (!task_alive(item))
 			continue;
 		for (i = 0; i < item->nr_threads; i++)
-			ret |= ptrace_flush_breakpoints(item->threads[i].real);
+			ret |= ptrace_flush_breakpoints(item->threads[i]->real);
 	}
 
 	return ret;
@@ -1702,7 +1702,7 @@  static void finalize_restore_detach(int status)
 			continue;
 
 		for (i = 0; i < item->nr_threads; i++) {
-			pid = item->threads[i].real;
+			pid = item->threads[i]->real;
 			if (pid < 0) {
 				BUG_ON(status >= 0);
 				break;
@@ -2727,7 +2727,7 @@  static int prepare_signals(int pid, struct task_restore_args *ta, CoreEntry *lea
 	for (i = 0; i < current->nr_threads; i++) {
 		if (!current->core[i]->thread_core->signals_p)/*backward compatibility*/
 			ret = open_signal_image(CR_FD_PSIGNAL,
-					current->threads[i].ns[0].virt, &siginfo_priv_nr[i]);
+					current->threads[i]->ns[0].virt, &siginfo_priv_nr[i]);
 		else
 			ret = prepare_one_signal_queue(current->core[i]->thread_core->signals_p,
 										&siginfo_priv_nr[i]);
@@ -3186,7 +3186,7 @@  static int sigreturn_restore(pid_t pid, struct task_restore_args *task_args, uns
 		struct rt_sigframe *sigframe;
 		k_rtsigset_t *blkset = NULL;
 
-		thread_args[i].pid = current->threads[i].ns[0].virt;
+		thread_args[i].pid = current->threads[i]->ns[0].virt;
 		thread_args[i].siginfo_n = siginfo_priv_nr[i];
 		thread_args[i].siginfo = task_args->siginfo;
 		thread_args[i].siginfo += siginfo_n;
diff --git a/criu/files-reg.c b/criu/files-reg.c
index ede2744e..48f068d2 100644
--- a/criu/files-reg.c
+++ b/criu/files-reg.c
@@ -824,8 +824,8 @@  int dead_pid_conflict(void)
 			 * process, this is handled during restore.
 			 */
 			item = node->item;
-			if (item->pid->real == item->threads[i].real ||
-			    item->threads[i].ns[0].virt != pid)
+			if (item->pid->real == item->threads[i]->real ||
+			    item->threads[i]->ns[0].virt != pid)
 				continue;
 		}
 
diff --git a/criu/include/proc_parse.h b/criu/include/proc_parse.h
index d67ac5e5..13b71092 100644
--- a/criu/include/proc_parse.h
+++ b/criu/include/proc_parse.h
@@ -101,7 +101,7 @@  extern int parse_file_locks(void);
 extern int get_fd_mntid(int fd, int *mnt_id);
 
 struct pid;
-extern int parse_threads(int pid, struct pid **_t, int *_n);
+extern int parse_threads(int pid, struct pid ***_t, int *_n);
 
 int parse_children(pid_t pid, pid_t **_c, int *_n);
 
diff --git a/criu/include/pstree.h b/criu/include/pstree.h
index 6edd04d7..0a62bfde 100644
--- a/criu/include/pstree.h
+++ b/criu/include/pstree.h
@@ -22,7 +22,7 @@  struct pstree_item {
 	pid_t			born_sid;
 
 	int			nr_threads;	/* number of threads */
-	struct pid		*threads;	/* array of threads */
+	struct pid		**threads;	/* array of threads */
 	CoreEntry		**core;
 	TaskKobjIdsEntry	*ids;
 	union {
diff --git a/criu/parasite-syscall.c b/criu/parasite-syscall.c
index 30b0a5ed..8ec3b727 100644
--- a/criu/parasite-syscall.c
+++ b/criu/parasite-syscall.c
@@ -481,7 +481,7 @@  struct parasite_ctl *parasite_infect_seized(pid_t pid, struct pstree_item *item,
 	struct infect_ctx *ictx;
 	unsigned long p;
 
-	BUG_ON(item->threads[0].real != pid);
+	BUG_ON(item->threads[0]->real != pid);
 
 	p = get_exec_start(vma_area_list);
 	if (!p) {
diff --git a/criu/proc_parse.c b/criu/proc_parse.c
index 5e9780a4..84a8f9ea 100644
--- a/criu/proc_parse.c
+++ b/criu/proc_parse.c
@@ -2196,11 +2196,11 @@  int parse_posix_timers(pid_t pid, struct proc_posix_timers_stat *args)
 	goto out;
 }
 
-int parse_threads(int pid, struct pid **_t, int *_n)
+int parse_threads(int pid, struct pid ***_t, int *_n)
 {
 	struct dirent *de;
 	DIR *dir;
-	struct pid *t = NULL;
+	struct pid **t = NULL;
 	int nr = 1;
 
 	if (*_t)
@@ -2211,23 +2211,32 @@  int parse_threads(int pid, struct pid **_t, int *_n)
 		return -1;
 
 	while ((de = readdir(dir))) {
-		struct pid *tmp;
+		struct pid **tmp;
 
 		/* We expect numbers only here */
 		if (de->d_name[0] == '.')
 			continue;
 
 		if (*_t == NULL) {
-			tmp = xrealloc(t, nr * sizeof(struct pid));
+			tmp = xrealloc(t, nr * sizeof(struct pid *));
 			if (!tmp) {
+				while (--nr > 0)
+					xfree(t[nr-1]);
 				xfree(t);
 				return -1;
 			}
 			t = tmp;
-			t[nr - 1].ns[0].virt = -1;
+			t[nr - 1] = xmalloc(sizeof(struct pid));
+			if (!t[nr - 1]) {
+				while (--nr > 0)
+					xfree(t[nr-1]);
+				xfree(t);
+			}
+			t[nr - 1]->ns[0].virt = -1;
 		}
-		t[nr - 1].real = atoi(de->d_name);
-		t[nr - 1].state = TASK_THREAD;
+		t[nr - 1]->real = atoi(de->d_name);
+		t[nr - 1]->state = TASK_THREAD;
+		t[nr - 1]->level = 1;
 		nr++;
 	}
 
diff --git a/criu/pstree.c b/criu/pstree.c
index 0dffabcf..46c2096b 100644
--- a/criu/pstree.c
+++ b/criu/pstree.c
@@ -149,7 +149,7 @@  int pstree_alloc_cores(struct pstree_item *item)
 		return -1;
 
 	for (i = 0; i < item->nr_threads; i++) {
-		if (item->threads[i].real == item->pid->real)
+		if (item->threads[i]->real == item->pid->real)
 			item->core[i] = core_entry_alloc(1, 1);
 		else
 			item->core[i] = core_entry_alloc(1, 0);
@@ -336,7 +336,7 @@  int dump_pstree(struct pstree_item *root_item)
 			goto err;
 
 		for (i = 0; i < item->nr_threads; i++)
-			e.threads[i] = item->threads[i].ns[0].virt;
+			e.threads[i] = item->threads[i]->ns[0].virt;
 
 		ret = pb_write_one(img, &e, PB_PSTREE);
 		xfree(e.threads);
@@ -602,23 +602,26 @@  static int read_pstree_image(pid_t *pid_max)
 		}
 
 		pi->nr_threads = e->n_threads;
-		pi->threads = xmalloc(e->n_threads * sizeof(struct pid));
+		pi->threads = xzalloc(e->n_threads * sizeof(struct pid *));
 		if (!pi->threads)
 			break;
 
 		for (i = 0; i < e->n_threads; i++) {
 			struct pid *node;
-			pi->threads[i].real = -1;
-			pi->threads[i].level = pi->pid->level;
-			pi->threads[i].ns[0].virt = e->threads[i];
-			pi->threads[i].state = TASK_THREAD;
-			pi->threads[i].item = NULL;
+			pi->threads[i] = xmalloc(sizeof(struct pid) + (pi->pid->level-1) * sizeof(node->ns[0]));
+			if (!pi->threads)
+				goto err;
+			pi->threads[i]->real = -1;
+			pi->threads[i]->level = pi->pid->level;
+			pi->threads[i]->ns[0].virt = e->threads[i];
+			pi->threads[i]->state = TASK_THREAD;
+			pi->threads[i]->item = NULL;
 			if (i == 0)
 				continue; /* A thread leader is in a tree already */
-			node = lookup_create_pid(pi->threads[i].ns[0].virt, &pi->threads[i]);
+			node = lookup_create_pid(pi->threads[i]->ns[0].virt, pi->threads[i]);
 
 			BUG_ON(node == NULL);
-			if (node != &pi->threads[i]) {
+			if (node != pi->threads[i]) {
 				pr_err("Unexpected task %d in a tree %d\n", e->threads[i], i);
 				return -1;
 			}
diff --git a/criu/seize.c b/criu/seize.c
index d5079ca6..7e44d136 100644
--- a/criu/seize.c
+++ b/criu/seize.c
@@ -544,8 +544,8 @@  static void unseize_task_and_threads(const struct pstree_item *item, int st)
 		return;
 
 	for (i = 1; i < item->nr_threads; i++)
-		if (ptrace(PTRACE_DETACH, item->threads[i].real, NULL, NULL))
-			pr_perror("Unable to detach from %d", item->threads[i].real);
+		if (ptrace(PTRACE_DETACH, item->threads[i]->real, NULL, NULL))
+			pr_perror("Unable to detach from %d", item->threads[i]->real);
 }
 
 static void pstree_wait(struct pstree_item *root_item)
@@ -620,7 +620,7 @@  static inline bool thread_collected(struct pstree_item *i, pid_t tid)
 		return true;
 
 	for (t = 0; t < i->nr_threads; t++)
-		if (tid == i->threads[t].real)
+		if (tid == i->threads[t]->real)
 			return true;
 
 	return false;
@@ -677,7 +677,7 @@  static bool creds_dumpable(struct proc_status_creds *parent,
 
 static int collect_threads(struct pstree_item *item)
 {
-	struct pid *threads = NULL;
+	struct pid **threads = NULL;
 	int nr_threads = 0, i = 0, ret, nr_inprogress, nr_stopped = 0;
 
 	ret = parse_threads(item->pid->real, &threads, &nr_threads);
@@ -690,19 +690,23 @@  static int collect_threads(struct pstree_item *item)
 	}
 
 	/* The number of threads can't be less than already frozen */
-	item->threads = xrealloc(item->threads, nr_threads * sizeof(struct pid));
+	item->threads = xrealloc(item->threads, nr_threads * sizeof(struct pid *));
 	if (item->threads == NULL)
 		return -1;
 
 	if (item->nr_threads == 0) {
-		item->threads[0].real = item->pid->real;
+		item->threads[0] = xmalloc(sizeof(struct pid));
+		if (!item->threads[0])
+			return -1;
+		item->threads[0]->real = item->pid->real;
 		item->nr_threads = 1;
-		item->threads[0].item = NULL;
+		item->threads[0]->item = NULL;
+		item->threads[0]->level = 1;
 	}
 
 	nr_inprogress = 0;
 	for (i = 0; i < nr_threads; i++) {
-		pid_t pid = threads[i].real;
+		pid_t pid = threads[i]->real;
 		struct proc_status_creds t_creds = {};
 
 		if (thread_collected(item, pid))
@@ -734,8 +738,12 @@  static int collect_threads(struct pstree_item *item)
 			processes_to_wait--;
 
 		BUG_ON(item->nr_threads + 1 > nr_threads);
-		item->threads[item->nr_threads].real = pid;
-		item->threads[item->nr_threads].item = NULL;
+		item->threads[item->nr_threads] = xmalloc(sizeof(struct pid));
+		if (!item->threads[item->nr_threads])
+			goto err;
+		item->threads[item->nr_threads]->real = pid;
+		item->threads[item->nr_threads]->item = NULL;
+		item->threads[item->nr_threads]->level = 1;
 		item->nr_threads++;
 
 		if (ret == TASK_DEAD) {
@@ -756,10 +764,14 @@  static int collect_threads(struct pstree_item *item)
 		goto err;
 	}
 
+	while (nr_threads-- > 0)
+		xfree(threads[nr_threads]);
 	xfree(threads);
 	return nr_inprogress;
 
 err:
+	while (nr_threads-- > 0)
+		xfree(threads[nr_threads]);
 	xfree(threads);
 	return -1;
 }

Comments

Andrey Vagin April 7, 2017, 12:42 a.m.
On Tue, Mar 28, 2017 at 06:36:25PM +0300, Kirill Tkhai wrote:
> Threads pid values also may be multi-level, so allocate
> them dynamically.

Can a thread leave in another pid namespace? Maybe it is enough to know
pid in the a process pidns?

> 
> Signed-off-by: Kirill Tkhai <ktkhai@virtuozzo.com>
> ---
>  criu/cr-dump.c            |   10 +++++-----
>  criu/cr-restore.c         |   14 +++++++-------
>  criu/files-reg.c          |    4 ++--
>  criu/include/proc_parse.h |    2 +-
>  criu/include/pstree.h     |    2 +-
>  criu/parasite-syscall.c   |    2 +-
>  criu/proc_parse.c         |   23 ++++++++++++++++-------
>  criu/pstree.c             |   23 +++++++++++++----------
>  criu/seize.c              |   32 ++++++++++++++++++++++----------
>  9 files changed, 68 insertions(+), 44 deletions(-)
> 
> diff --git a/criu/cr-dump.c b/criu/cr-dump.c
> index c61bb263..018c61d1 100644
> --- a/criu/cr-dump.c
> +++ b/criu/cr-dump.c
> @@ -821,7 +821,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 pid *tid = &item->threads[id];
> +	struct pid *tid = item->threads[id];
>  	CoreEntry *core = item->core[id];
>  	pid_t pid = tid->real;
>  	int ret = -1;
> @@ -963,9 +963,9 @@ static int dump_task_signals(pid_t pid, struct pstree_item *item)
>  
>  	/* Dump private signals for each thread */
>  	for (i = 0; i < item->nr_threads; i++) {
> -		ret = dump_signal_queue(item->threads[i].real, &item->core[i]->thread_core->signals_p, false);
> +		ret = dump_signal_queue(item->threads[i]->real, &item->core[i]->thread_core->signals_p, false);
>  		if (ret) {
> -			pr_err("Can't dump private signals for thread %d\n", item->threads[i].real);
> +			pr_err("Can't dump private signals for thread %d\n", item->threads[i]->real);
>  			return -1;
>  		}
>  	}
> @@ -989,8 +989,8 @@ static int dump_task_threads(struct parasite_ctl *parasite_ctl,
>  
>  	for (i = 0; i < item->nr_threads; i++) {
>  		/* Leader is already dumped */
> -		if (item->pid->real == item->threads[i].real) {
> -			item->threads[i].ns[0].virt = vpid(item);
> +		if (item->pid->real == item->threads[i]->real) {
> +			item->threads[i]->ns[0].virt = vpid(item);
>  			continue;
>  		}
>  		if (dump_task_thread(parasite_ctl, item, i))
> diff --git a/criu/cr-restore.c b/criu/cr-restore.c
> index 5795f645..1434971a 100644
> --- a/criu/cr-restore.c
> +++ b/criu/cr-restore.c
> @@ -578,7 +578,7 @@ static int open_cores(int pid, CoreEntry *leader_core)
>  		goto err;
>  
>  	for (i = 0; i < current->nr_threads; i++) {
> -		tpid = current->threads[i].ns[0].virt;
> +		tpid = current->threads[i]->ns[0].virt;
>  
>  		if (tpid == pid)
>  			cores[i] = leader_core;
> @@ -1571,7 +1571,7 @@ static int attach_to_tasks(bool root_seized)
>  			return -1;
>  
>  		for (i = 0; i < item->nr_threads; i++) {
> -			pid_t pid = item->threads[i].real;
> +			pid_t pid = item->threads[i]->real;
>  
>  			if (item != root_item || !root_seized || i != 0) {
>  				if (ptrace(PTRACE_SEIZE, pid, 0, 0)) {
> @@ -1624,7 +1624,7 @@ static int catch_tasks(bool root_seized, enum trace_flags *flag)
>  			return -1;
>  
>  		for (i = 0; i < item->nr_threads; i++) {
> -			pid_t pid = item->threads[i].real;
> +			pid_t pid = item->threads[i]->real;
>  
>  			if (ptrace(PTRACE_INTERRUPT, pid, 0, 0)) {
>  				pr_perror("Can't interrupt the %d task", pid);
> @@ -1658,7 +1658,7 @@ static int clear_breakpoints()
>  		if (!task_alive(item))
>  			continue;
>  		for (i = 0; i < item->nr_threads; i++)
> -			ret |= ptrace_flush_breakpoints(item->threads[i].real);
> +			ret |= ptrace_flush_breakpoints(item->threads[i]->real);
>  	}
>  
>  	return ret;
> @@ -1702,7 +1702,7 @@ static void finalize_restore_detach(int status)
>  			continue;
>  
>  		for (i = 0; i < item->nr_threads; i++) {
> -			pid = item->threads[i].real;
> +			pid = item->threads[i]->real;
>  			if (pid < 0) {
>  				BUG_ON(status >= 0);
>  				break;
> @@ -2727,7 +2727,7 @@ static int prepare_signals(int pid, struct task_restore_args *ta, CoreEntry *lea
>  	for (i = 0; i < current->nr_threads; i++) {
>  		if (!current->core[i]->thread_core->signals_p)/*backward compatibility*/
>  			ret = open_signal_image(CR_FD_PSIGNAL,
> -					current->threads[i].ns[0].virt, &siginfo_priv_nr[i]);
> +					current->threads[i]->ns[0].virt, &siginfo_priv_nr[i]);
>  		else
>  			ret = prepare_one_signal_queue(current->core[i]->thread_core->signals_p,
>  										&siginfo_priv_nr[i]);
> @@ -3186,7 +3186,7 @@ static int sigreturn_restore(pid_t pid, struct task_restore_args *task_args, uns
>  		struct rt_sigframe *sigframe;
>  		k_rtsigset_t *blkset = NULL;
>  
> -		thread_args[i].pid = current->threads[i].ns[0].virt;
> +		thread_args[i].pid = current->threads[i]->ns[0].virt;
>  		thread_args[i].siginfo_n = siginfo_priv_nr[i];
>  		thread_args[i].siginfo = task_args->siginfo;
>  		thread_args[i].siginfo += siginfo_n;
> diff --git a/criu/files-reg.c b/criu/files-reg.c
> index ede2744e..48f068d2 100644
> --- a/criu/files-reg.c
> +++ b/criu/files-reg.c
> @@ -824,8 +824,8 @@ int dead_pid_conflict(void)
>  			 * process, this is handled during restore.
>  			 */
>  			item = node->item;
> -			if (item->pid->real == item->threads[i].real ||
> -			    item->threads[i].ns[0].virt != pid)
> +			if (item->pid->real == item->threads[i]->real ||
> +			    item->threads[i]->ns[0].virt != pid)
>  				continue;
>  		}
>  
> diff --git a/criu/include/proc_parse.h b/criu/include/proc_parse.h
> index d67ac5e5..13b71092 100644
> --- a/criu/include/proc_parse.h
> +++ b/criu/include/proc_parse.h
> @@ -101,7 +101,7 @@ extern int parse_file_locks(void);
>  extern int get_fd_mntid(int fd, int *mnt_id);
>  
>  struct pid;
> -extern int parse_threads(int pid, struct pid **_t, int *_n);
> +extern int parse_threads(int pid, struct pid ***_t, int *_n);
>  
>  int parse_children(pid_t pid, pid_t **_c, int *_n);
>  
> diff --git a/criu/include/pstree.h b/criu/include/pstree.h
> index 6edd04d7..0a62bfde 100644
> --- a/criu/include/pstree.h
> +++ b/criu/include/pstree.h
> @@ -22,7 +22,7 @@ struct pstree_item {
>  	pid_t			born_sid;
>  
>  	int			nr_threads;	/* number of threads */
> -	struct pid		*threads;	/* array of threads */
> +	struct pid		**threads;	/* array of threads */
>  	CoreEntry		**core;
>  	TaskKobjIdsEntry	*ids;
>  	union {
> diff --git a/criu/parasite-syscall.c b/criu/parasite-syscall.c
> index 30b0a5ed..8ec3b727 100644
> --- a/criu/parasite-syscall.c
> +++ b/criu/parasite-syscall.c
> @@ -481,7 +481,7 @@ struct parasite_ctl *parasite_infect_seized(pid_t pid, struct pstree_item *item,
>  	struct infect_ctx *ictx;
>  	unsigned long p;
>  
> -	BUG_ON(item->threads[0].real != pid);
> +	BUG_ON(item->threads[0]->real != pid);
>  
>  	p = get_exec_start(vma_area_list);
>  	if (!p) {
> diff --git a/criu/proc_parse.c b/criu/proc_parse.c
> index 5e9780a4..84a8f9ea 100644
> --- a/criu/proc_parse.c
> +++ b/criu/proc_parse.c
> @@ -2196,11 +2196,11 @@ int parse_posix_timers(pid_t pid, struct proc_posix_timers_stat *args)
>  	goto out;
>  }
>  
> -int parse_threads(int pid, struct pid **_t, int *_n)
> +int parse_threads(int pid, struct pid ***_t, int *_n)
>  {
>  	struct dirent *de;
>  	DIR *dir;
> -	struct pid *t = NULL;
> +	struct pid **t = NULL;
>  	int nr = 1;
>  
>  	if (*_t)
> @@ -2211,23 +2211,32 @@ int parse_threads(int pid, struct pid **_t, int *_n)
>  		return -1;
>  
>  	while ((de = readdir(dir))) {
> -		struct pid *tmp;
> +		struct pid **tmp;
>  
>  		/* We expect numbers only here */
>  		if (de->d_name[0] == '.')
>  			continue;
>  
>  		if (*_t == NULL) {
> -			tmp = xrealloc(t, nr * sizeof(struct pid));
> +			tmp = xrealloc(t, nr * sizeof(struct pid *));
>  			if (!tmp) {
> +				while (--nr > 0)
> +					xfree(t[nr-1]);
>  				xfree(t);
>  				return -1;
>  			}
>  			t = tmp;
> -			t[nr - 1].ns[0].virt = -1;
> +			t[nr - 1] = xmalloc(sizeof(struct pid));
> +			if (!t[nr - 1]) {
> +				while (--nr > 0)
> +					xfree(t[nr-1]);
> +				xfree(t);
> +			}
> +			t[nr - 1]->ns[0].virt = -1;
>  		}
> -		t[nr - 1].real = atoi(de->d_name);
> -		t[nr - 1].state = TASK_THREAD;
> +		t[nr - 1]->real = atoi(de->d_name);
> +		t[nr - 1]->state = TASK_THREAD;
> +		t[nr - 1]->level = 1;
>  		nr++;
>  	}
>  
> diff --git a/criu/pstree.c b/criu/pstree.c
> index 0dffabcf..46c2096b 100644
> --- a/criu/pstree.c
> +++ b/criu/pstree.c
> @@ -149,7 +149,7 @@ int pstree_alloc_cores(struct pstree_item *item)
>  		return -1;
>  
>  	for (i = 0; i < item->nr_threads; i++) {
> -		if (item->threads[i].real == item->pid->real)
> +		if (item->threads[i]->real == item->pid->real)
>  			item->core[i] = core_entry_alloc(1, 1);
>  		else
>  			item->core[i] = core_entry_alloc(1, 0);
> @@ -336,7 +336,7 @@ int dump_pstree(struct pstree_item *root_item)
>  			goto err;
>  
>  		for (i = 0; i < item->nr_threads; i++)
> -			e.threads[i] = item->threads[i].ns[0].virt;
> +			e.threads[i] = item->threads[i]->ns[0].virt;
>  
>  		ret = pb_write_one(img, &e, PB_PSTREE);
>  		xfree(e.threads);
> @@ -602,23 +602,26 @@ static int read_pstree_image(pid_t *pid_max)
>  		}
>  
>  		pi->nr_threads = e->n_threads;
> -		pi->threads = xmalloc(e->n_threads * sizeof(struct pid));
> +		pi->threads = xzalloc(e->n_threads * sizeof(struct pid *));
>  		if (!pi->threads)
>  			break;
>  
>  		for (i = 0; i < e->n_threads; i++) {
>  			struct pid *node;
> -			pi->threads[i].real = -1;
> -			pi->threads[i].level = pi->pid->level;
> -			pi->threads[i].ns[0].virt = e->threads[i];
> -			pi->threads[i].state = TASK_THREAD;
> -			pi->threads[i].item = NULL;
> +			pi->threads[i] = xmalloc(sizeof(struct pid) + (pi->pid->level-1) * sizeof(node->ns[0]));
> +			if (!pi->threads)
> +				goto err;
> +			pi->threads[i]->real = -1;
> +			pi->threads[i]->level = pi->pid->level;
> +			pi->threads[i]->ns[0].virt = e->threads[i];
> +			pi->threads[i]->state = TASK_THREAD;
> +			pi->threads[i]->item = NULL;
>  			if (i == 0)
>  				continue; /* A thread leader is in a tree already */
> -			node = lookup_create_pid(pi->threads[i].ns[0].virt, &pi->threads[i]);
> +			node = lookup_create_pid(pi->threads[i]->ns[0].virt, pi->threads[i]);
>  
>  			BUG_ON(node == NULL);
> -			if (node != &pi->threads[i]) {
> +			if (node != pi->threads[i]) {
>  				pr_err("Unexpected task %d in a tree %d\n", e->threads[i], i);
>  				return -1;
>  			}
> diff --git a/criu/seize.c b/criu/seize.c
> index d5079ca6..7e44d136 100644
> --- a/criu/seize.c
> +++ b/criu/seize.c
> @@ -544,8 +544,8 @@ static void unseize_task_and_threads(const struct pstree_item *item, int st)
>  		return;
>  
>  	for (i = 1; i < item->nr_threads; i++)
> -		if (ptrace(PTRACE_DETACH, item->threads[i].real, NULL, NULL))
> -			pr_perror("Unable to detach from %d", item->threads[i].real);
> +		if (ptrace(PTRACE_DETACH, item->threads[i]->real, NULL, NULL))
> +			pr_perror("Unable to detach from %d", item->threads[i]->real);
>  }
>  
>  static void pstree_wait(struct pstree_item *root_item)
> @@ -620,7 +620,7 @@ static inline bool thread_collected(struct pstree_item *i, pid_t tid)
>  		return true;
>  
>  	for (t = 0; t < i->nr_threads; t++)
> -		if (tid == i->threads[t].real)
> +		if (tid == i->threads[t]->real)
>  			return true;
>  
>  	return false;
> @@ -677,7 +677,7 @@ static bool creds_dumpable(struct proc_status_creds *parent,
>  
>  static int collect_threads(struct pstree_item *item)
>  {
> -	struct pid *threads = NULL;
> +	struct pid **threads = NULL;
>  	int nr_threads = 0, i = 0, ret, nr_inprogress, nr_stopped = 0;
>  
>  	ret = parse_threads(item->pid->real, &threads, &nr_threads);
> @@ -690,19 +690,23 @@ static int collect_threads(struct pstree_item *item)
>  	}
>  
>  	/* The number of threads can't be less than already frozen */
> -	item->threads = xrealloc(item->threads, nr_threads * sizeof(struct pid));
> +	item->threads = xrealloc(item->threads, nr_threads * sizeof(struct pid *));
>  	if (item->threads == NULL)
>  		return -1;
>  
>  	if (item->nr_threads == 0) {
> -		item->threads[0].real = item->pid->real;
> +		item->threads[0] = xmalloc(sizeof(struct pid));
> +		if (!item->threads[0])
> +			return -1;
> +		item->threads[0]->real = item->pid->real;
>  		item->nr_threads = 1;
> -		item->threads[0].item = NULL;
> +		item->threads[0]->item = NULL;
> +		item->threads[0]->level = 1;
>  	}
>  
>  	nr_inprogress = 0;
>  	for (i = 0; i < nr_threads; i++) {
> -		pid_t pid = threads[i].real;
> +		pid_t pid = threads[i]->real;
>  		struct proc_status_creds t_creds = {};
>  
>  		if (thread_collected(item, pid))
> @@ -734,8 +738,12 @@ static int collect_threads(struct pstree_item *item)
>  			processes_to_wait--;
>  
>  		BUG_ON(item->nr_threads + 1 > nr_threads);
> -		item->threads[item->nr_threads].real = pid;
> -		item->threads[item->nr_threads].item = NULL;
> +		item->threads[item->nr_threads] = xmalloc(sizeof(struct pid));
> +		if (!item->threads[item->nr_threads])
> +			goto err;
> +		item->threads[item->nr_threads]->real = pid;
> +		item->threads[item->nr_threads]->item = NULL;
> +		item->threads[item->nr_threads]->level = 1;
>  		item->nr_threads++;
>  
>  		if (ret == TASK_DEAD) {
> @@ -756,10 +764,14 @@ static int collect_threads(struct pstree_item *item)
>  		goto err;
>  	}
>  
> +	while (nr_threads-- > 0)
> +		xfree(threads[nr_threads]);
>  	xfree(threads);
>  	return nr_inprogress;
>  
>  err:
> +	while (nr_threads-- > 0)
> +		xfree(threads[nr_threads]);
>  	xfree(threads);
>  	return -1;
>  }
>
Kirill Tkhai April 7, 2017, 9:34 a.m.
On 07.04.2017 03:42, Andrei Vagin wrote:
> On Tue, Mar 28, 2017 at 06:36:25PM +0300, Kirill Tkhai wrote:
>> Threads pid values also may be multi-level, so allocate
>> them dynamically.
> 
> Can a thread leave in another pid namespace? Maybe it is enough to know
> pid in the a process pidns?

No, they don't leave in another pid_ns, but they have mappings in the whole
ns hierarhy.

kirill:~$ cat /proc/28851/task/28851/status | grep NS
NStgid:	28851	20
NSpid:	28851	20
NSpgid:	28851	20
NSsid:	28851	20
kirill:~$ cat /proc/28851/task/28852/status | grep NS
NStgid:	28851	20
NSpid:	28852	21
NSpgid:	28851	20
NSsid:	28851	20
 
>>
>> Signed-off-by: Kirill Tkhai <ktkhai@virtuozzo.com>
>> ---
>>  criu/cr-dump.c            |   10 +++++-----
>>  criu/cr-restore.c         |   14 +++++++-------
>>  criu/files-reg.c          |    4 ++--
>>  criu/include/proc_parse.h |    2 +-
>>  criu/include/pstree.h     |    2 +-
>>  criu/parasite-syscall.c   |    2 +-
>>  criu/proc_parse.c         |   23 ++++++++++++++++-------
>>  criu/pstree.c             |   23 +++++++++++++----------
>>  criu/seize.c              |   32 ++++++++++++++++++++++----------
>>  9 files changed, 68 insertions(+), 44 deletions(-)
>>
>> diff --git a/criu/cr-dump.c b/criu/cr-dump.c
>> index c61bb263..018c61d1 100644
>> --- a/criu/cr-dump.c
>> +++ b/criu/cr-dump.c
>> @@ -821,7 +821,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 pid *tid = &item->threads[id];
>> +	struct pid *tid = item->threads[id];
>>  	CoreEntry *core = item->core[id];
>>  	pid_t pid = tid->real;
>>  	int ret = -1;
>> @@ -963,9 +963,9 @@ static int dump_task_signals(pid_t pid, struct pstree_item *item)
>>  
>>  	/* Dump private signals for each thread */
>>  	for (i = 0; i < item->nr_threads; i++) {
>> -		ret = dump_signal_queue(item->threads[i].real, &item->core[i]->thread_core->signals_p, false);
>> +		ret = dump_signal_queue(item->threads[i]->real, &item->core[i]->thread_core->signals_p, false);
>>  		if (ret) {
>> -			pr_err("Can't dump private signals for thread %d\n", item->threads[i].real);
>> +			pr_err("Can't dump private signals for thread %d\n", item->threads[i]->real);
>>  			return -1;
>>  		}
>>  	}
>> @@ -989,8 +989,8 @@ static int dump_task_threads(struct parasite_ctl *parasite_ctl,
>>  
>>  	for (i = 0; i < item->nr_threads; i++) {
>>  		/* Leader is already dumped */
>> -		if (item->pid->real == item->threads[i].real) {
>> -			item->threads[i].ns[0].virt = vpid(item);
>> +		if (item->pid->real == item->threads[i]->real) {
>> +			item->threads[i]->ns[0].virt = vpid(item);
>>  			continue;
>>  		}
>>  		if (dump_task_thread(parasite_ctl, item, i))
>> diff --git a/criu/cr-restore.c b/criu/cr-restore.c
>> index 5795f645..1434971a 100644
>> --- a/criu/cr-restore.c
>> +++ b/criu/cr-restore.c
>> @@ -578,7 +578,7 @@ static int open_cores(int pid, CoreEntry *leader_core)
>>  		goto err;
>>  
>>  	for (i = 0; i < current->nr_threads; i++) {
>> -		tpid = current->threads[i].ns[0].virt;
>> +		tpid = current->threads[i]->ns[0].virt;
>>  
>>  		if (tpid == pid)
>>  			cores[i] = leader_core;
>> @@ -1571,7 +1571,7 @@ static int attach_to_tasks(bool root_seized)
>>  			return -1;
>>  
>>  		for (i = 0; i < item->nr_threads; i++) {
>> -			pid_t pid = item->threads[i].real;
>> +			pid_t pid = item->threads[i]->real;
>>  
>>  			if (item != root_item || !root_seized || i != 0) {
>>  				if (ptrace(PTRACE_SEIZE, pid, 0, 0)) {
>> @@ -1624,7 +1624,7 @@ static int catch_tasks(bool root_seized, enum trace_flags *flag)
>>  			return -1;
>>  
>>  		for (i = 0; i < item->nr_threads; i++) {
>> -			pid_t pid = item->threads[i].real;
>> +			pid_t pid = item->threads[i]->real;
>>  
>>  			if (ptrace(PTRACE_INTERRUPT, pid, 0, 0)) {
>>  				pr_perror("Can't interrupt the %d task", pid);
>> @@ -1658,7 +1658,7 @@ static int clear_breakpoints()
>>  		if (!task_alive(item))
>>  			continue;
>>  		for (i = 0; i < item->nr_threads; i++)
>> -			ret |= ptrace_flush_breakpoints(item->threads[i].real);
>> +			ret |= ptrace_flush_breakpoints(item->threads[i]->real);
>>  	}
>>  
>>  	return ret;
>> @@ -1702,7 +1702,7 @@ static void finalize_restore_detach(int status)
>>  			continue;
>>  
>>  		for (i = 0; i < item->nr_threads; i++) {
>> -			pid = item->threads[i].real;
>> +			pid = item->threads[i]->real;
>>  			if (pid < 0) {
>>  				BUG_ON(status >= 0);
>>  				break;
>> @@ -2727,7 +2727,7 @@ static int prepare_signals(int pid, struct task_restore_args *ta, CoreEntry *lea
>>  	for (i = 0; i < current->nr_threads; i++) {
>>  		if (!current->core[i]->thread_core->signals_p)/*backward compatibility*/
>>  			ret = open_signal_image(CR_FD_PSIGNAL,
>> -					current->threads[i].ns[0].virt, &siginfo_priv_nr[i]);
>> +					current->threads[i]->ns[0].virt, &siginfo_priv_nr[i]);
>>  		else
>>  			ret = prepare_one_signal_queue(current->core[i]->thread_core->signals_p,
>>  										&siginfo_priv_nr[i]);
>> @@ -3186,7 +3186,7 @@ static int sigreturn_restore(pid_t pid, struct task_restore_args *task_args, uns
>>  		struct rt_sigframe *sigframe;
>>  		k_rtsigset_t *blkset = NULL;
>>  
>> -		thread_args[i].pid = current->threads[i].ns[0].virt;
>> +		thread_args[i].pid = current->threads[i]->ns[0].virt;
>>  		thread_args[i].siginfo_n = siginfo_priv_nr[i];
>>  		thread_args[i].siginfo = task_args->siginfo;
>>  		thread_args[i].siginfo += siginfo_n;
>> diff --git a/criu/files-reg.c b/criu/files-reg.c
>> index ede2744e..48f068d2 100644
>> --- a/criu/files-reg.c
>> +++ b/criu/files-reg.c
>> @@ -824,8 +824,8 @@ int dead_pid_conflict(void)
>>  			 * process, this is handled during restore.
>>  			 */
>>  			item = node->item;
>> -			if (item->pid->real == item->threads[i].real ||
>> -			    item->threads[i].ns[0].virt != pid)
>> +			if (item->pid->real == item->threads[i]->real ||
>> +			    item->threads[i]->ns[0].virt != pid)
>>  				continue;
>>  		}
>>  
>> diff --git a/criu/include/proc_parse.h b/criu/include/proc_parse.h
>> index d67ac5e5..13b71092 100644
>> --- a/criu/include/proc_parse.h
>> +++ b/criu/include/proc_parse.h
>> @@ -101,7 +101,7 @@ extern int parse_file_locks(void);
>>  extern int get_fd_mntid(int fd, int *mnt_id);
>>  
>>  struct pid;
>> -extern int parse_threads(int pid, struct pid **_t, int *_n);
>> +extern int parse_threads(int pid, struct pid ***_t, int *_n);
>>  
>>  int parse_children(pid_t pid, pid_t **_c, int *_n);
>>  
>> diff --git a/criu/include/pstree.h b/criu/include/pstree.h
>> index 6edd04d7..0a62bfde 100644
>> --- a/criu/include/pstree.h
>> +++ b/criu/include/pstree.h
>> @@ -22,7 +22,7 @@ struct pstree_item {
>>  	pid_t			born_sid;
>>  
>>  	int			nr_threads;	/* number of threads */
>> -	struct pid		*threads;	/* array of threads */
>> +	struct pid		**threads;	/* array of threads */
>>  	CoreEntry		**core;
>>  	TaskKobjIdsEntry	*ids;
>>  	union {
>> diff --git a/criu/parasite-syscall.c b/criu/parasite-syscall.c
>> index 30b0a5ed..8ec3b727 100644
>> --- a/criu/parasite-syscall.c
>> +++ b/criu/parasite-syscall.c
>> @@ -481,7 +481,7 @@ struct parasite_ctl *parasite_infect_seized(pid_t pid, struct pstree_item *item,
>>  	struct infect_ctx *ictx;
>>  	unsigned long p;
>>  
>> -	BUG_ON(item->threads[0].real != pid);
>> +	BUG_ON(item->threads[0]->real != pid);
>>  
>>  	p = get_exec_start(vma_area_list);
>>  	if (!p) {
>> diff --git a/criu/proc_parse.c b/criu/proc_parse.c
>> index 5e9780a4..84a8f9ea 100644
>> --- a/criu/proc_parse.c
>> +++ b/criu/proc_parse.c
>> @@ -2196,11 +2196,11 @@ int parse_posix_timers(pid_t pid, struct proc_posix_timers_stat *args)
>>  	goto out;
>>  }
>>  
>> -int parse_threads(int pid, struct pid **_t, int *_n)
>> +int parse_threads(int pid, struct pid ***_t, int *_n)
>>  {
>>  	struct dirent *de;
>>  	DIR *dir;
>> -	struct pid *t = NULL;
>> +	struct pid **t = NULL;
>>  	int nr = 1;
>>  
>>  	if (*_t)
>> @@ -2211,23 +2211,32 @@ int parse_threads(int pid, struct pid **_t, int *_n)
>>  		return -1;
>>  
>>  	while ((de = readdir(dir))) {
>> -		struct pid *tmp;
>> +		struct pid **tmp;
>>  
>>  		/* We expect numbers only here */
>>  		if (de->d_name[0] == '.')
>>  			continue;
>>  
>>  		if (*_t == NULL) {
>> -			tmp = xrealloc(t, nr * sizeof(struct pid));
>> +			tmp = xrealloc(t, nr * sizeof(struct pid *));
>>  			if (!tmp) {
>> +				while (--nr > 0)
>> +					xfree(t[nr-1]);
>>  				xfree(t);
>>  				return -1;
>>  			}
>>  			t = tmp;
>> -			t[nr - 1].ns[0].virt = -1;
>> +			t[nr - 1] = xmalloc(sizeof(struct pid));
>> +			if (!t[nr - 1]) {
>> +				while (--nr > 0)
>> +					xfree(t[nr-1]);
>> +				xfree(t);
>> +			}
>> +			t[nr - 1]->ns[0].virt = -1;
>>  		}
>> -		t[nr - 1].real = atoi(de->d_name);
>> -		t[nr - 1].state = TASK_THREAD;
>> +		t[nr - 1]->real = atoi(de->d_name);
>> +		t[nr - 1]->state = TASK_THREAD;
>> +		t[nr - 1]->level = 1;
>>  		nr++;
>>  	}
>>  
>> diff --git a/criu/pstree.c b/criu/pstree.c
>> index 0dffabcf..46c2096b 100644
>> --- a/criu/pstree.c
>> +++ b/criu/pstree.c
>> @@ -149,7 +149,7 @@ int pstree_alloc_cores(struct pstree_item *item)
>>  		return -1;
>>  
>>  	for (i = 0; i < item->nr_threads; i++) {
>> -		if (item->threads[i].real == item->pid->real)
>> +		if (item->threads[i]->real == item->pid->real)
>>  			item->core[i] = core_entry_alloc(1, 1);
>>  		else
>>  			item->core[i] = core_entry_alloc(1, 0);
>> @@ -336,7 +336,7 @@ int dump_pstree(struct pstree_item *root_item)
>>  			goto err;
>>  
>>  		for (i = 0; i < item->nr_threads; i++)
>> -			e.threads[i] = item->threads[i].ns[0].virt;
>> +			e.threads[i] = item->threads[i]->ns[0].virt;
>>  
>>  		ret = pb_write_one(img, &e, PB_PSTREE);
>>  		xfree(e.threads);
>> @@ -602,23 +602,26 @@ static int read_pstree_image(pid_t *pid_max)
>>  		}
>>  
>>  		pi->nr_threads = e->n_threads;
>> -		pi->threads = xmalloc(e->n_threads * sizeof(struct pid));
>> +		pi->threads = xzalloc(e->n_threads * sizeof(struct pid *));
>>  		if (!pi->threads)
>>  			break;
>>  
>>  		for (i = 0; i < e->n_threads; i++) {
>>  			struct pid *node;
>> -			pi->threads[i].real = -1;
>> -			pi->threads[i].level = pi->pid->level;
>> -			pi->threads[i].ns[0].virt = e->threads[i];
>> -			pi->threads[i].state = TASK_THREAD;
>> -			pi->threads[i].item = NULL;
>> +			pi->threads[i] = xmalloc(sizeof(struct pid) + (pi->pid->level-1) * sizeof(node->ns[0]));
>> +			if (!pi->threads)
>> +				goto err;
>> +			pi->threads[i]->real = -1;
>> +			pi->threads[i]->level = pi->pid->level;
>> +			pi->threads[i]->ns[0].virt = e->threads[i];
>> +			pi->threads[i]->state = TASK_THREAD;
>> +			pi->threads[i]->item = NULL;
>>  			if (i == 0)
>>  				continue; /* A thread leader is in a tree already */
>> -			node = lookup_create_pid(pi->threads[i].ns[0].virt, &pi->threads[i]);
>> +			node = lookup_create_pid(pi->threads[i]->ns[0].virt, pi->threads[i]);
>>  
>>  			BUG_ON(node == NULL);
>> -			if (node != &pi->threads[i]) {
>> +			if (node != pi->threads[i]) {
>>  				pr_err("Unexpected task %d in a tree %d\n", e->threads[i], i);
>>  				return -1;
>>  			}
>> diff --git a/criu/seize.c b/criu/seize.c
>> index d5079ca6..7e44d136 100644
>> --- a/criu/seize.c
>> +++ b/criu/seize.c
>> @@ -544,8 +544,8 @@ static void unseize_task_and_threads(const struct pstree_item *item, int st)
>>  		return;
>>  
>>  	for (i = 1; i < item->nr_threads; i++)
>> -		if (ptrace(PTRACE_DETACH, item->threads[i].real, NULL, NULL))
>> -			pr_perror("Unable to detach from %d", item->threads[i].real);
>> +		if (ptrace(PTRACE_DETACH, item->threads[i]->real, NULL, NULL))
>> +			pr_perror("Unable to detach from %d", item->threads[i]->real);
>>  }
>>  
>>  static void pstree_wait(struct pstree_item *root_item)
>> @@ -620,7 +620,7 @@ static inline bool thread_collected(struct pstree_item *i, pid_t tid)
>>  		return true;
>>  
>>  	for (t = 0; t < i->nr_threads; t++)
>> -		if (tid == i->threads[t].real)
>> +		if (tid == i->threads[t]->real)
>>  			return true;
>>  
>>  	return false;
>> @@ -677,7 +677,7 @@ static bool creds_dumpable(struct proc_status_creds *parent,
>>  
>>  static int collect_threads(struct pstree_item *item)
>>  {
>> -	struct pid *threads = NULL;
>> +	struct pid **threads = NULL;
>>  	int nr_threads = 0, i = 0, ret, nr_inprogress, nr_stopped = 0;
>>  
>>  	ret = parse_threads(item->pid->real, &threads, &nr_threads);
>> @@ -690,19 +690,23 @@ static int collect_threads(struct pstree_item *item)
>>  	}
>>  
>>  	/* The number of threads can't be less than already frozen */
>> -	item->threads = xrealloc(item->threads, nr_threads * sizeof(struct pid));
>> +	item->threads = xrealloc(item->threads, nr_threads * sizeof(struct pid *));
>>  	if (item->threads == NULL)
>>  		return -1;
>>  
>>  	if (item->nr_threads == 0) {
>> -		item->threads[0].real = item->pid->real;
>> +		item->threads[0] = xmalloc(sizeof(struct pid));
>> +		if (!item->threads[0])
>> +			return -1;
>> +		item->threads[0]->real = item->pid->real;
>>  		item->nr_threads = 1;
>> -		item->threads[0].item = NULL;
>> +		item->threads[0]->item = NULL;
>> +		item->threads[0]->level = 1;
>>  	}
>>  
>>  	nr_inprogress = 0;
>>  	for (i = 0; i < nr_threads; i++) {
>> -		pid_t pid = threads[i].real;
>> +		pid_t pid = threads[i]->real;
>>  		struct proc_status_creds t_creds = {};
>>  
>>  		if (thread_collected(item, pid))
>> @@ -734,8 +738,12 @@ static int collect_threads(struct pstree_item *item)
>>  			processes_to_wait--;
>>  
>>  		BUG_ON(item->nr_threads + 1 > nr_threads);
>> -		item->threads[item->nr_threads].real = pid;
>> -		item->threads[item->nr_threads].item = NULL;
>> +		item->threads[item->nr_threads] = xmalloc(sizeof(struct pid));
>> +		if (!item->threads[item->nr_threads])
>> +			goto err;
>> +		item->threads[item->nr_threads]->real = pid;
>> +		item->threads[item->nr_threads]->item = NULL;
>> +		item->threads[item->nr_threads]->level = 1;
>>  		item->nr_threads++;
>>  
>>  		if (ret == TASK_DEAD) {
>> @@ -756,10 +764,14 @@ static int collect_threads(struct pstree_item *item)
>>  		goto err;
>>  	}
>>  
>> +	while (nr_threads-- > 0)
>> +		xfree(threads[nr_threads]);
>>  	xfree(threads);
>>  	return nr_inprogress;
>>  
>>  err:
>> +	while (nr_threads-- > 0)
>> +		xfree(threads[nr_threads]);
>>  	xfree(threads);
>>  	return -1;
>>  }
>>