[v2,29/57] pstree: Make lookup_create_pid() able to create tasks with pid->level > 1

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

Details

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

Commit Message

Kirill Tkhai March 28, 2017, 3:38 p.m.
Pid may contain more then one level, so this patch teaches the function
to work with such pids. The signify difference after this patch is that
we link a new item in several rb_root in every ns.

Signed-off-by: Kirill Tkhai <ktkhai@virtuozzo.com>
---
 criu/files-reg.c      |    2 +
 criu/include/pstree.h |    2 +
 criu/pstree.c         |   80 +++++++++++++++++++++++++++++++++++++------------
 3 files changed, 63 insertions(+), 21 deletions(-)

Patch hide | download patch | download mbox

diff --git a/criu/files-reg.c b/criu/files-reg.c
index d59c825e..7c81d182 100644
--- a/criu/files-reg.c
+++ b/criu/files-reg.c
@@ -379,7 +379,7 @@  static int open_remap_dead_process(struct reg_file_info *rfi,
 {
 	struct pstree_item *helper;
 
-	helper = lookup_create_item(rfe->remap_id, root_item->ids->pid_ns_id);
+	helper = lookup_create_item((pid_t *)&rfe->remap_id, 1, root_item->ids->pid_ns_id);
 	if (!helper)
 		return -1;
 
diff --git a/criu/include/pstree.h b/criu/include/pstree.h
index 9978b8a7..438ef939 100644
--- a/criu/include/pstree.h
+++ b/criu/include/pstree.h
@@ -90,7 +90,7 @@  extern struct pstree_item *__alloc_pstree_item(bool rst, int level);
 #define alloc_pstree_item() __alloc_pstree_item(false, 1)
 extern void init_pstree_helper(struct pstree_item *ret);
 
-extern struct pstree_item *lookup_create_item(pid_t pid, uint32_t ns_id);
+extern struct pstree_item *lookup_create_item(pid_t *pid, int level, uint32_t ns_id);
 extern void pstree_insert_pid(struct pid *pid_node, uint32_t ns_id);
 extern struct pid *pstree_pid_by_virt(pid_t pid);
 
diff --git a/criu/pstree.c b/criu/pstree.c
index 76672631..f4984ec4 100644
--- a/criu/pstree.c
+++ b/criu/pstree.c
@@ -24,7 +24,6 @@ 
 #include "crtools.h"
 
 struct pstree_item *root_item;
-static struct rb_root pid_root_rb;
 
 void core_entry_free(CoreEntry *core)
 {
@@ -398,9 +397,9 @@  static int prepare_pstree_for_shell_job(void)
 			pi->sid->ns[0].virt = current_sid;
 	}
 
-	if (lookup_create_item(current_sid, root_item->ids->pid_ns_id) == NULL)
+	if (lookup_create_item(&current_sid, 1, root_item->ids->pid_ns_id) == NULL)
 		return -1;
-	if (lookup_create_item(current_gid, root_item->ids->pid_ns_id) == NULL)
+	if (lookup_create_item(&current_gid, 1, root_item->ids->pid_ns_id) == NULL)
 		return -1;
 
 	return 0;
@@ -434,43 +433,86 @@  static struct pid *find_pid_or_place_in_hier(struct rb_node **root, pid_t pid, i
  * it is not there yet. If pid_node isn't set, pstree_item
  * is inserted.
  */
-static struct pid *lookup_create_pid(pid_t pid, struct pid *pid_node, int ns_id)
+static struct pid *lookup_create_pid(pid_t *pid, int level, struct pid *pid_node, int ns_id)
 {
 	struct rb_node **new = NULL, *parent = NULL;
+	int i, orig_level = level;
 	struct pid *found;
+	struct ns_id *ns;
 
-	found = find_pid_or_place_in_hier(&pid_root_rb.rb_node, pid, 0, &parent, &new);
-	if (found)
+	ns = lookup_ns_by_id(ns_id, &pid_ns_desc);
+
+	while (level > 0 && ns && !pid[level-1]) {
+		level--;
+		ns = ns->parent;
+	}
+	if (!level || !ns) {
+		pr_err("Can't skip zero pids levels (%d) or find {parent,} ns (%d)\n", level, ns_id);
+		return NULL;
+	}
+
+	found = find_pid_or_place_in_hier(&ns->pid.rb_root.rb_node, pid[level-1], level-1, &parent, &new);
+	if (found) {
+		for (i = level - 2; i >= 0; i--)
+			if (pid[i] != found->ns[i].virt || !rb_parent(&found->ns[i].node)) {
+				pr_err("Wrong pid\n");
+				return NULL;
+			}
 		return found;
+	}
 
 	if (!pid_node) {
 		struct pstree_item *item;
 
-		item = __alloc_pstree_item(true, 1);
+		item = __alloc_pstree_item(true, orig_level);
 		if (item == NULL)
 			return NULL;
 
-		item->pid->ns[0].virt = pid;
+		for (i = 0; i < orig_level; i++)
+			item->pid->ns[i].virt = pid[i];
 		pid_node = item->pid;
 	}
-	rb_link_and_balance(&pid_root_rb, &pid_node->ns[0].node, parent, new);
+
+	for (i = level-1; i >= 0; i--) {
+		found = find_pid_or_place_in_hier(&ns->pid.rb_root.rb_node, pid[i], i, &parent, &new);
+		if (found) {
+			pr_err("pid is already linked\n");
+			return NULL;
+		}
+		if (!pid[i]) {
+			pr_err("Zero pid level\n");
+			return NULL;
+		}
+		rb_link_and_balance(&ns->pid.rb_root, &pid_node->ns[i].node, parent, new);
+		ns = ns->parent;
+		if (!ns && i) {
+			pr_err("ns has no parent\n");
+			return NULL;
+		}
+	}
 	return pid_node;
 }
 
 void pstree_insert_pid(struct pid *pid_node, uint32_t ns_id)
 {
 	struct pid* n;
+	pid_t pid[MAX_NS_NESTING];
+	int i;
+
+	BUG_ON(pid_node->level > MAX_NS_NESTING);
+	for (i = 0; i < pid_node->level; i++)
+		pid[i] = pid_node->ns[i].virt;
 
-	n = lookup_create_pid(pid_node->ns[0].virt, pid_node, ns_id);
+	n = lookup_create_pid(pid, pid_node->level, pid_node, ns_id);
 
 	BUG_ON(n != pid_node);
 }
 
-struct pstree_item *lookup_create_item(pid_t pid, uint32_t ns_id)
+struct pstree_item *lookup_create_item(pid_t *pid, int level, uint32_t ns_id)
 {
 	struct pid *node;;
 
-	node = lookup_create_pid(pid, NULL, ns_id);
+	node = lookup_create_pid(pid, level, NULL, ns_id);
 	if (!node)
 		return NULL;
 	BUG_ON(node->state == TASK_THREAD);
@@ -480,7 +522,7 @@  struct pstree_item *lookup_create_item(pid_t pid, uint32_t ns_id)
 
 struct pid *pstree_pid_by_virt(pid_t pid)
 {
-	struct rb_node *node = pid_root_rb.rb_node;
+	struct rb_node *node = top_pid_ns->pid.rb_root.rb_node;
 
 	while (node) {
 		struct pid *this = rb_entry(node, struct pid, ns[0].node);
@@ -597,7 +639,7 @@  static int read_pstree_image(pid_t *pid_max)
 			break;
 		}
 
-		pi = lookup_create_item(e->pid, ids->pid_ns_id);
+		pi = lookup_create_item((pid_t *)&e->pid, 1, ids->pid_ns_id);
 		if (pi == NULL)
 			break;
 		BUG_ON(pi->pid->state != TASK_UNDEF);
@@ -610,9 +652,9 @@  static int read_pstree_image(pid_t *pid_max)
 		 * be initialized when we meet PstreeEntry with this pid or
 		 * we will create helpers for them.
 		 */
-		if (lookup_create_item(e->pgid, ids->pid_ns_id) == NULL)
+		if (lookup_create_item((pid_t *)&e->pgid, 1, ids->pid_ns_id) == NULL)
 			break;
-		if (lookup_create_item(e->sid, ids->pid_ns_id) == NULL)
+		if (lookup_create_item((pid_t *)&e->sid, 1, ids->pid_ns_id) == NULL)
 			break;
 
 		pi->pid->ns[0].virt = e->pid;
@@ -656,7 +698,7 @@  static int read_pstree_image(pid_t *pid_max)
 			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], ids->pid_ns_id);
+			node = lookup_create_pid((pid_t *)&pi->threads[i]->ns[0].virt, 1, pi->threads[i], ids->pid_ns_id);
 
 			BUG_ON(node == NULL);
 			if (node != pi->threads[i]) {
@@ -684,7 +726,7 @@  static int get_free_pid()
 	static struct pid *prev, *next;
 
 	if (prev == NULL)
-		prev = rb_entry(rb_first(&pid_root_rb), struct pid, ns[0].node);
+		prev = rb_entry(rb_first(&top_pid_ns->pid.rb_root), struct pid, ns[0].node);
 
 	while (1) {
 		struct rb_node *node;
@@ -737,7 +779,7 @@  static int prepare_pstree_ids(void)
 			pid = get_free_pid();
 			if (pid < 0)
 				break;
-			helper = lookup_create_item(pid, item->ids->pid_ns_id);
+			helper = lookup_create_item(&pid, 1, item->ids->pid_ns_id);
 			if (helper == NULL)
 				return -1;