[CRIU] [PATCH] add join-ns opt to criu restore

Dengguangxing dengguangxing at huawei.com
Mon Mar 14 23:08:51 PDT 2016


join-ns will restore process with specified existing namespace.
This opt can be used in this fomat:
	--join-ns NS:PID, for example net:12345.

pid namespaces is not supported yet. As fork() is needed to make
new pid-namespace take effect. That makes it hard for criu to track the
child-process through pid because another child process has been
created after fork().

Signed-off-by: Deng Guangxing <dengguangxing at huawei.com>
---
 criu/cr-restore.c         |  5 +++
 criu/crtools.c            | 44 ++++++++++++++++++++++++-
 criu/include/cr_options.h |  1 +
 criu/include/namespaces.h | 10 ++++++
 criu/namespaces.c         | 82 ++++++++++++++++++++++++++++++++++++++++-------
 5 files changed, 129 insertions(+), 13 deletions(-)

diff --git a/criu/cr-restore.c b/criu/cr-restore.c
index 30ddff9..e3f0add 100644
--- a/criu/cr-restore.c
+++ b/criu/cr-restore.c
@@ -1566,6 +1566,11 @@ static int restore_task_with_children(void *_arg)

 	/* Restore root task */
 	if (current->parent == NULL) {
+		if (join_namespaces()) {
+			pr_perror("Join namespaces failed");
+			goto err;
+		}
+
 		if (restore_finish_stage(CR_STATE_RESTORE_NS) < 0)
 			goto err;

diff --git a/criu/crtools.c b/criu/crtools.c
index d6e8672..87d9ec4 100644
--- a/criu/crtools.c
+++ b/criu/crtools.c
@@ -36,6 +36,7 @@
 #include "cr-service.h"
 #include "plugin.h"
 #include "mount.h"
+#include "namespaces.h"
 #include "cgroup.h"
 #include "cpu.h"
 #include "action-scripts.h"
@@ -58,6 +59,7 @@ void init_opts(void)
 	INIT_LIST_HEAD(&opts.veth_pairs);
 	INIT_LIST_HEAD(&opts.scripts);
 	INIT_LIST_HEAD(&opts.ext_mounts);
+	INIT_LIST_HEAD(&opts.join_ns);
 	INIT_LIST_HEAD(&opts.inherit_fds);
 	INIT_LIST_HEAD(&opts.external);
 	INIT_LIST_HEAD(&opts.new_cgroup_roots);
@@ -99,6 +101,39 @@ bad_ns:
 	return -1;
 }

+static int parse_join_ns(const char *ptr)
+{
+	char *aux;
+	pid_t pid;
+
+	aux = strchr(ptr, ':');
+	if (aux == NULL)
+		return -1;
+	*aux = '\0';
+
+	if (!strcmp(ptr, "pid")) {
+		pr_perror("pid namespace not supported in join-ns\n");
+		return -1;
+	} else if (strcmp(ptr, "net") &&
+		strcmp(ptr, "uts") &&
+		strcmp(ptr, "ipc") &&
+		strcmp(ptr, "user") &&
+		strcmp(ptr, "mnt")) {
+		pr_perror("Illegal namespace %s in join-ns\n", ptr);
+		return -1;
+	}
+
+	pid = atoi(aux+1);
+	if (pid <= 0) {
+		pr_perror("Invalid pid %s in join-ns\n", aux+1);
+		return -1;
+	}
+	if (join_ns_add(ptr, pid))
+		return -1;
+
+	return 0;
+}
+
 static int parse_cpu_cap(struct cr_options *opts, const char *optarg)
 {
 	bool inverse = false;
@@ -218,7 +253,7 @@ int main(int argc, char *argv[], char *envp[])
 	int log_level = LOG_UNSET;
 	char *imgs_dir = ".";
 	char *work_dir = NULL;
-	static const char short_opts[] = "dSsRf:F:t:p:hcD:o:n:v::x::Vr:jlW:L:M:";
+	static const char short_opts[] = "dSsRf:F:t:p:hcD:o:n:v::x::Vr:jJ:lW:L:M:";
 	static struct option long_opts[] = {
 		{ "tree",			required_argument,	0, 't'	},
 		{ "pid",			required_argument,	0, 'p'	},
@@ -234,6 +269,7 @@ int main(int argc, char *argv[], char *envp[])
 		{ "work-dir",			required_argument,	0, 'W'	},
 		{ "log-file",			required_argument,	0, 'o'	},
 		{ "namespaces",			required_argument,	0, 'n'	},
+		{ "join-ns",			required_argument,	0, 'J'	},
 		{ "root",			required_argument,	0, 'r'	},
 		{ USK_EXT_PARAM,		optional_argument,	0, 'x'	},
 		{ "help",			no_argument,		0, 'h'	},
@@ -366,6 +402,10 @@ int main(int argc, char *argv[], char *envp[])
 			if (parse_ns_string(optarg))
 				goto bad_arg;
 			break;
+		case 'J':
+			if (parse_join_ns(optarg))
+				goto bad_arg;
+			break;
 		case 'v':
 			if (log_level == LOG_UNSET)
 				log_level = 0;
@@ -810,6 +850,8 @@ usage:
 "  --empty-ns {net}\n"
 "			Create a namespace, but don't restore its properies.\n"
 "			An user will retore them from action scripts.\n"
+"  -J|--join-ns NS:PID\n"
+"			Join exist namespace and restore process in it.\n"
 "\n"
 "* Logging:\n"
 "  -o|--log-file FILE    log file name\n"
diff --git a/criu/include/cr_options.h b/criu/include/cr_options.h
index a6f0b3e..cf3cb0e 100644
--- a/criu/include/cr_options.h
+++ b/criu/include/cr_options.h
@@ -82,6 +82,7 @@ struct cr_options {
 	struct list_head	ext_mounts;
 	struct list_head	inherit_fds;
 	struct list_head	external;
+	struct list_head	join_ns;
 	char			*libdir;
 	bool			use_page_server;
 	unsigned short		port;
diff --git a/criu/include/namespaces.h b/criu/include/namespaces.h
index 303c9e6..a7a8863 100644
--- a/criu/include/namespaces.h
+++ b/criu/include/namespaces.h
@@ -3,6 +3,7 @@

 #include "compiler.h"
 #include "files.h"
+#include "list.h"

 /* including syscall-types.h gives another weird error; do we really need to
  * define this twice? */
@@ -19,6 +20,13 @@ struct ns_desc {
 	size_t		len;
 };

+struct join_ns {
+	struct list_head 	list;
+	pid_t 			pid;
+	struct ns_desc		nd;
+
+};
+
 enum ns_type {
 	NS_UNKNOWN = 0,
 	NS_CRIU,
@@ -100,6 +108,8 @@ extern gid_t userns_gid(gid_t gid);

 extern int dump_user_ns(pid_t pid, int ns_id);
 extern void free_userns_maps(void);
+extern int join_ns_add(const char *type, pid_t pid);
+extern int join_namespaces();

 typedef int (*uns_call_t)(void *arg, int fd, pid_t pid);
 /*
diff --git a/criu/namespaces.c b/criu/namespaces.c
index d7f8a9f..b3b829e 100644
--- a/criu/namespaces.c
+++ b/criu/namespaces.c
@@ -10,7 +10,9 @@
 #include <signal.h>
 #include <sched.h>
 #include <sys/capability.h>
+#include <sys/stat.h>

+#include "cr_options.h"
 #include "util.h"
 #include "imgset.h"
 #include "uts_ns.h"
@@ -35,6 +37,37 @@ static struct ns_desc *ns_desc_array[] = {
 	&cgroup_ns_desc,
 };

+int join_ns_add(const char *type, pid_t pid) {
+	struct join_ns *jn;
+
+	jn = xmalloc(sizeof(*jn));
+	if (!jn) {
+		return -1;
+	}
+
+	jn->pid = pid;
+	if (!strcmp(type, "net")) {
+			jn->nd = net_ns_desc;
+	} else if (!strcmp(type, "uts")) {
+			jn->nd = uts_ns_desc;
+	} else if (!strcmp(type, "ipc")) {
+			jn->nd = ipc_ns_desc;
+	} else if (!strcmp(type, "pid")) {
+			jn->nd = pid_ns_desc;
+	} else if (!strcmp(type, "user")) {
+			jn->nd = user_ns_desc;
+	} else if (!strcmp(type, "mnt")) {
+			jn->nd = mnt_ns_desc;
+	} else {
+			pr_perror("invalid namespace type %s\n", type);
+			return -1;
+	}
+
+	list_add_tail(&jn->list, &opts.join_ns);
+	pr_info("Added %s:%d join namespace\n", type, pid);
+	return 0;
+}
+
 static unsigned int parse_ns_link(char *link, size_t len, struct ns_desc *d)
 {
 	unsigned long kid = 0;
@@ -73,28 +106,41 @@ bool check_ns_proc(struct fd_link *link)
 int switch_ns(int pid, struct ns_desc *nd, int *rst)
 {
 	char buf[32];
-	int nsfd;
+	int nsfd, self_fd;
 	int ret = -1;
+	struct stat st, self_st;

 	nsfd = open_proc(pid, "ns/%s", nd->str);
 	if (nsfd < 0) {
-		pr_perror("Can't open ipcns file");
+		pr_perror("Can't open ns file");
+		goto err_ns;
+	}
+	if (fstat(nsfd, &st) == -1) {
+		pr_perror("Can't get ns file stat");
 		goto err_ns;
 	}

+	snprintf(buf, sizeof(buf), "/proc/self/ns/%s", nd->str);
+	self_fd = open(buf, O_RDONLY);
+	if (self_fd < 0) {
+		pr_perror("Can't open ns file");
+		goto err_rst;
+	}
+	if (fstat(self_fd, &self_st) == -1) {
+		pr_perror("Can't get ns file stat");
+		goto err_ns;
+	}
 	if (rst) {
-		snprintf(buf, sizeof(buf), "/proc/self/ns/%s", nd->str);
-		*rst = open(buf, O_RDONLY);
-		if (*rst < 0) {
-			pr_perror("Can't open ns file");
-			goto err_rst;
-		}
+		*rst = self_fd;
 	}

-	ret = setns(nsfd, nd->cflag);
-	if (ret < 0) {
-		pr_perror("Can't setns %d/%s", pid, nd->str);
-		goto err_set;
+	//re-set the same user-ns would fail, check it here
+	if (st.st_ino != self_st.st_ino) {
+		ret = setns(nsfd, nd->cflag);
+		if (ret < 0) {
+			pr_perror("Can't setns %d/%s", pid, nd->str);
+			goto err_set;
+		}
 	}

 	close(nsfd);
@@ -1371,6 +1417,18 @@ static int prepare_userns_creds()
 	return 0;
 }

+int join_namespaces()
+{
+	struct join_ns *jn;
+
+	list_for_each_entry(jn, &opts.join_ns, list)
+		if (switch_ns(jn->pid, &jn->nd, NULL)) {
+			return -1;
+		}
+
+	return 0;
+}
+
 int prepare_namespace(struct pstree_item *item, unsigned long clone_flags)
 {
 	pid_t pid = item->pid.virt;
-- 
2.5.0



More information about the CRIU mailing list