[CRIU] [PATCH v1 03/17] user_ns: Set nested namespaces hierarhy

Kirill Tkhai ktkhai at virtuozzo.com
Thu Jan 12 09:52:29 PST 2017


Introduce ns_id::parent and assign a pointer to parent
for every ns except NS_CRIU.

Signed-off-by: Kirill Tkhai <ktkhai at virtuozzo.com>
---
 criu/cr-dump.c            |    3 ++
 criu/include/namespaces.h |   12 ++++++++
 criu/namespaces.c         |   65 +++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 80 insertions(+)

diff --git a/criu/cr-dump.c b/criu/cr-dump.c
index b6a9c9b63..18ff6d6d1 100644
--- a/criu/cr-dump.c
+++ b/criu/cr-dump.c
@@ -1755,6 +1755,9 @@ int cr_dump_tasks(pid_t pid)
 	if (collect_file_locks())
 		goto err;
 
+	if (populate_ns_hierarhy() < 0)
+		goto err;
+
 	if (collect_namespaces(true) < 0)
 		goto err;
 
diff --git a/criu/include/namespaces.h b/criu/include/namespaces.h
index c9f3e8a74..558050783 100644
--- a/criu/include/namespaces.h
+++ b/criu/include/namespaces.h
@@ -1,6 +1,8 @@
 #ifndef __CR_NS_H__
 #define __CR_NS_H__
 
+#include <sys/ioctl.h>
+
 #include "common/compiler.h"
 #include "files.h"
 #include "common/list.h"
@@ -39,6 +41,12 @@
 #define CLONE_SUBNS	(CLONE_NEWNS)
 #define EXTRA_SIZE	20
 
+#ifndef NSIO
+#define NSIO    0xb7
+#define NS_GET_USERNS   _IO(NSIO, 0x1)
+#define NS_GET_PARENT   _IO(NSIO, 0x2)
+#endif
+
 struct ns_desc {
 	unsigned int	cflag;
 	char		*str;
@@ -75,6 +83,9 @@ struct ns_id {
 	unsigned int id;
 	pid_t ns_pid;
 	struct ns_desc *nd;
+	struct ns_id *parent;
+	struct list_head parent_head;
+	struct list_head child_node;
 	struct ns_id *next;
 	enum ns_type type;
 
@@ -135,6 +146,7 @@ extern int predump_task_ns_ids(struct pstree_item *);
 extern struct ns_id *rst_new_ns_id(unsigned int id, pid_t pid, struct ns_desc *nd, enum ns_type t);
 extern int rst_add_ns_id(unsigned int id, struct pstree_item *, struct ns_desc *nd);
 extern struct ns_id *lookup_ns_by_id(unsigned int id, struct ns_desc *nd);
+extern int populate_ns_hierarhy(void);
 
 extern int collect_user_namespaces(bool for_dump);
 extern int prepare_userns(struct pstree_item *item);
diff --git a/criu/namespaces.c b/criu/namespaces.c
index b954f9796..148b54a00 100644
--- a/criu/namespaces.c
+++ b/criu/namespaces.c
@@ -13,6 +13,7 @@
 #include <sys/stat.h>
 #include <limits.h>
 #include <errno.h>
+#include <sys/ioctl.h>
 
 #include "page.h"
 #include "rst-malloc.h"
@@ -421,6 +422,8 @@ static unsigned int generate_ns_id(int pid, unsigned int kid, struct ns_desc *nd
 	nsid->type = type;
 	nsid->kid = kid;
 	nsid->ns_populated = true;
+	INIT_LIST_HEAD(&nsid->parent_head);
+	INIT_LIST_HEAD(&nsid->child_node);
 	nsid_add(nsid, nd, ns_next_id++, pid);
 
 found:
@@ -661,6 +664,68 @@ int dump_task_ns_ids(struct pstree_item *item)
 	return 0;
 }
 
+static int set_parent_ns(struct ns_id *ns, void *oarg)
+{
+	int proc_dir, ns_fd, p_ns_fd, ret = -1;
+	struct ns_id *p_ns;
+	char ns_path[10];
+	struct stat st;
+
+	if (ns->type == NS_CRIU || ns->type == NS_ROOT)
+		return 0;
+
+	proc_dir = open_pid_proc(ns->ns_pid);
+	if (proc_dir < 0)
+		return -1;
+
+	sprintf(ns_path, "ns/%s", ns->nd->str);
+
+	ns_fd = openat(proc_dir, ns_path, O_RDONLY);
+	if (ns_fd < 0) {
+		pr_perror("Can't open %s, pid %d", ns_path, ns->ns_pid);
+		return -1;
+	}
+
+	p_ns_fd = ioctl(ns_fd, NS_GET_PARENT);
+	if (p_ns_fd < 0) {
+		pr_perror("Can't get parent of ns user:[%u], err=%d.\n"
+			  "Check, that you kernel has NS_GET_PARENT support.\n",
+			   ns->kid, p_ns_fd);
+		goto close_ns_fd;
+	}
+
+	if (fstat(p_ns_fd, &st) < 0) {
+		pr_perror("Unable to stat parent %s ns of pid %d", ns->nd->str, ns->ns_pid);
+	} else {
+		p_ns = lookup_ns_by_kid(st.st_ino, ns->nd);
+		if (!p_ns) {
+			pr_err("User namespaces hierarhies with holes are not supported\n");
+			goto close_p_ns_fd;
+		}
+		ns->parent = p_ns;
+		list_add(&ns->child_node, &p_ns->parent_head);
+		pr_debug("%s ns: %u(%d)<<%u(%d)\n", ns->nd->str, ns->kid,
+					ns->type, p_ns->kid, p_ns->type);
+		ret = 0;
+	}
+
+close_p_ns_fd:
+	close(p_ns_fd);
+close_ns_fd:
+	close(ns_fd);
+
+	return ret;
+}
+
+int populate_ns_hierarhy(void)
+{
+	if (!(root_ns_mask & CLONE_NEWUSER))
+		return 0;
+
+	/* Currently only user_ns needs the hierarhy populated */
+	return walk_namespaces(&user_ns_desc, set_parent_ns, NULL);
+}
+
 static UsernsEntry userns_entry = USERNS_ENTRY__INIT;
 #define INVALID_ID (~0U)
 



More information about the CRIU mailing list