[CRIU] [PATCH v3 26/55] pstree: Make lookup_create_pid() able to create tasks with pid->level > 1
Kirill Tkhai
ktkhai at virtuozzo.com
Mon Apr 10 01:19:19 PDT 2017
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 at virtuozzo.com>
---
criu/files-reg.c | 2 +
criu/include/pstree.h | 2 +
criu/pstree.c | 80 +++++++++++++++++++++++++++++++++++++------------
3 files changed, 63 insertions(+), 21 deletions(-)
diff --git a/criu/files-reg.c b/criu/files-reg.c
index d59c825ef..7c81d182a 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 9978b8a77..438ef939a 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 766726318..f4984ec40 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(¤t_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(¤t_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;
More information about the CRIU
mailing list