[v4,14/41] pstree: Collect NSpid, NSsid and NStgid when possible

Submitted by Kirill Tkhai on May 4, 2017, 4:07 p.m.

Details

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

Commit Message

Kirill Tkhai May 4, 2017, 4:07 p.m.
v4: New

Signed-off-by: Kirill Tkhai <ktkhai@virtuozzo.com>
---
 criu/cr-dump.c    |   28 ++++++++++++++++---
 criu/proc_parse.c |   78 +++++++++++++++++++++++++++++++++++++++++++++++++++--
 2 files changed, 99 insertions(+), 7 deletions(-)

Patch hide | download patch | download mbox

diff --git a/criu/cr-dump.c b/criu/cr-dump.c
index 08976a941..83c4907c5 100644
--- a/criu/cr-dump.c
+++ b/criu/cr-dump.c
@@ -844,7 +844,16 @@  static int dump_task_thread(struct parasite_ctl *parasite_ctl,
 		pr_err("Can't dump thread for pid %d\n", pid);
 		goto err;
 	}
-	tid->ns[0].virt = parasite_tid;
+
+	if (tid->ns[0].virt == -1)
+		tid->ns[0].virt = parasite_tid;
+	else {
+		/* It was collected in parse_pid_status() */
+		if (last_level_pid(tid) != parasite_tid) {
+			pr_err("Parasite and /proc/[pid]/status gave different tids\n");
+			goto err;
+		}
+	}
 
 	pstree_insert_pid(tid, item->ids->pid_ns_id);
 
@@ -1314,9 +1323,20 @@  static int dump_one_task(struct pstree_item *item)
 		goto err_cure_imgset;
 	}
 
-	vpid(item) = misc.pid;
-	vsid(item) = misc.sid;
-	vpgid(item) = misc.pgid;
+	if (vpid(item) == -1) {
+		vpid(item) = misc.pid;
+		vsid(item) = misc.sid;
+		vpgid(item) = misc.pgid;
+	} else {
+		/* They were collected in parse_pid_status() */
+		if (last_level_pid(item->pid) != misc.pid ||
+		    last_level_pid(item->sid) != misc.sid ||
+		    last_level_pid(item->pgid) != misc.pgid) {
+			pr_err("Parasite and /proc/[pid]/status gave different pids\n");
+			goto err;
+		}
+	}
+
 	pstree_insert_pid(item->pid, item->ids->pid_ns_id);
 
 	pr_info("sid=%d pgid=%d pid=%d\n", vsid(item), vpgid(item), vpid(item));
diff --git a/criu/proc_parse.c b/criu/proc_parse.c
index d4f123904..072f65543 100644
--- a/criu/proc_parse.c
+++ b/criu/proc_parse.c
@@ -993,6 +993,44 @@  static int cap_parse(char *str, unsigned int *res)
 	return 0;
 }
 
+static int get_ns_pid(char *str, struct pid **pid_ptr)
+{
+	pid_t pid[MAX_NS_NESTING];
+	int level, size, skip;
+	pid_t val;
+
+	skip = pid_ns_root_off();
+
+	level = 0;
+	while (sscanf(str, "%d%n", &val, &size) == 1) {
+		if (level == MAX_NS_NESTING) {
+			pr_err("Too nested hierarchy\n");
+			return -1;
+		}
+		str += size;
+		if (skip > 0) {
+			skip--;
+			continue;
+		}
+		pid[level++] = val;
+	}
+
+	if (level == 0) {
+		pr_err("Line can't be collected\n");
+		return -1;
+	}
+
+	(*pid_ptr) = xrealloc(*pid_ptr, PID_SIZE(level));
+	if (!*pid_ptr)
+		return -1;
+
+	(*pid_ptr)->level = level;
+	while (level-- > 0)
+		(*pid_ptr)->ns[level].virt = pid[level];
+
+	return 0;
+}
+
 int parse_pid_status(pid_t pid, struct seize_task_status *ss,
 		     struct pstree_item *item, struct pid **thread)
 {
@@ -1002,6 +1040,7 @@  int parse_pid_status(pid_t pid, struct seize_task_status *ss,
 	int ret = -1;
 	char *str;
 	bool parsed_seccomp = false;
+	int expected_done;
 
 	f.fd = open_proc(pid, "status");
 	if (f.fd < 0)
@@ -1013,7 +1052,7 @@  int parse_pid_status(pid_t pid, struct seize_task_status *ss,
 	if (bfdopenr(&f))
 		return -1;
 
-	while (done < 12) {
+	while (done < 14) {
 		str = breadline(&f);
 		if (str == NULL)
 			break;
@@ -1113,10 +1152,43 @@  int parse_pid_status(pid_t pid, struct seize_task_status *ss,
 			done++;
 			continue;
 		}
+		if (!strncmp(str, "NSpid:", 6)) {
+			if (get_ns_pid(str + 6, thread ? : &item->pid) < 0) {
+				pr_err("Can't get NSpid\n");
+				goto err_parse;
+			}
+			done++;
+			continue;
+		}
+		if (!strncmp(str, "NSpgid:", 7) && !thread) {
+			if (get_ns_pid(str + 7, &item->pgid) < 0) {
+				pr_err("Can't get NSpgid\n");
+				goto err_parse;
+			}
+			done++;
+			continue;
+		}
+		if (!strncmp(str, "NSsid:", 6) && !thread) {
+			if (get_ns_pid(str + 6, &item->sid) < 0) {
+				pr_err("Can't get NSsid\n");
+				goto err_parse;
+			}
+			done++;
+			continue;
+		}
+	}
+
+	if (!thread && (item->pid->level != item->sid->level ||
+			item->pid->level != item->pgid->level)) {
+		pr_err("Level mismatch\n");
+		goto err_parse;
 	}
 
-	/* seccomp is optional */
-	if (done >= 11 || (done == 10 && !parsed_seccomp))
+	/* seccomp and nspids are optional */
+	expected_done = (parsed_seccomp ? 11 : 10);
+	if (kdat.has_nspid)
+		expected_done += (thread ? 1 : 3);
+	if (done == expected_done)
 		ret = 0;
 
 err_parse: