[CRIU] [PATCH] predump: Collect mnt and net namespaces properly

Pavel Emelyanov xemul at parallels.com
Wed Oct 1 05:15:52 PDT 2014


On pre-dump we collect only two namespaces -- the mnt one
for criu and mnt one again for root task.

This is not correct. We need all mount namespaces to make
the irmap generation work properly and we need all net
namespaces to have parasite sockets created.

Signed-off-by: Pavel Emelyanov <xemul at parallels.com>

---

diff --git a/cr-dump.c b/cr-dump.c
index 562edbd..df4bd73 100644
--- a/cr-dump.c
+++ b/cr-dump.c
@@ -1036,6 +1036,36 @@ err_close:
 	return -1;
 }
 
+static int collect_pstree_ids_predump(void)
+{
+	struct pstree_item *item;
+	struct {
+		struct pstree_item i;
+		struct dmp_info d;
+	} crt = { };
+
+	/*
+	 * This thing is normally done inside
+	 * write_img_inventory().
+	 */
+
+	crt.i.state = TASK_ALIVE;
+	crt.i.pid.real = getpid();
+
+	if (predump_task_ns_ids(&crt.i))
+		return -1;
+
+	for_each_pstree_item(item) {
+		if (item->state == TASK_DEAD)
+			continue;
+
+		if (predump_task_ns_ids(item))
+			return -1;
+	}
+
+	return 0;
+}
+
 int collect_pstree_ids(void)
 {
 	struct pstree_item *item;
@@ -1682,10 +1712,10 @@ int cr_pre_dump_tasks(pid_t pid)
 	if (collect_pstree(pid))
 		goto err;
 
-	if (gen_predump_ns_mask())
+	if (collect_pstree_ids_predump())
 		goto err;
 
-	if (collect_mnt_namespaces() < 0)
+	if (collect_namespaces(false) < 0)
 		goto err;
 
 	for_each_pstree_item(item)
@@ -1798,7 +1828,7 @@ int cr_dump_tasks(pid_t pid)
 	if (collect_file_locks())
 		goto err;
 
-	if (collect_namespaces() < 0)
+	if (collect_namespaces(true) < 0)
 		goto err;
 
 	glob_imgset = cr_glob_imgset_open(O_DUMP);
diff --git a/include/namespaces.h b/include/namespaces.h
index 09d631c..7edc37c 100644
--- a/include/namespaces.h
+++ b/include/namespaces.h
@@ -46,7 +46,7 @@ extern unsigned long root_ns_mask;
 extern const struct fdtype_ops nsfile_dump_ops;
 extern struct collect_image_info nsfile_cinfo;
 
-extern int collect_namespaces(void);
+extern int collect_namespaces(bool for_dump);
 extern int collect_mnt_namespaces(void);
 extern int dump_mnt_namespaces(void);
 extern int dump_namespaces(struct pstree_item *item, unsigned int ns_flags);
@@ -57,10 +57,9 @@ extern int switch_ns(int pid, struct ns_desc *nd, int *rst);
 extern int restore_ns(int rst, struct ns_desc *nd);
 
 extern int dump_task_ns_ids(struct pstree_item *);
+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);
 extern int rst_add_ns_id(unsigned int id, pid_t pid, struct ns_desc *nd);
 extern struct ns_id *lookup_ns_by_id(unsigned int id, struct ns_desc *nd);
 
-extern int gen_predump_ns_mask(void);
-
 #endif /* __CR_NS_H__ */
diff --git a/include/net.h b/include/net.h
index ac07c6b..df9e67d 100644
--- a/include/net.h
+++ b/include/net.h
@@ -14,7 +14,7 @@ struct veth_pair {
 	char *outside;
 };
 
-extern int collect_net_namespaces(void);
+extern int collect_net_namespaces(bool for_dump);
 
 extern int network_lock(void);
 extern void network_unlock(void);
diff --git a/namespaces.c b/namespaces.c
index 3453ef7..1feb165 100644
--- a/namespaces.c
+++ b/namespaces.c
@@ -359,6 +359,28 @@ struct collect_image_info nsfile_cinfo = {
 	.flags = COLLECT_OPTIONAL,
 };
 
+/*
+ * Same as dump_task_ns_ids(), but
+ * a) doesn't keep IDs (don't need them)
+ * b) generates them for mount and netns only
+ *    mnt ones are needed for open_mount() in
+ *    inotify pred-dump
+ *    net ones are needed for parasite socket
+ */
+
+int predump_task_ns_ids(struct pstree_item *item)
+{
+	int pid = item->pid.real;
+
+	if (!__get_ns_id(pid, &net_ns_desc, &dmpi(item)->netns))
+		return -1;
+
+	if (!get_ns_id(pid, &mnt_ns_desc))
+		return -1;
+
+	return 0;
+}
+
 int dump_task_ns_ids(struct pstree_item *item)
 {
 	int pid = item->pid.real;
@@ -402,34 +424,6 @@ int dump_task_ns_ids(struct pstree_item *item)
 	return 0;
 }
 
-static int gen_ns_ids(int pid)
-{
-	/* needed for mntns_get_root_fd */
-	if (!get_ns_id(pid, &mnt_ns_desc))
-		return -1;
-	return 0;
-}
-
-/*
- * We use ns_mask in various places to check whether
- * the tasks we dump live in namespaces or not. The
- * mask generation is tied with dumping inventory and
- * tasks' images, which is not needed for pre-dump.
- * This routine generates a mask for pre-dump.
- */
-int gen_predump_ns_mask(void)
-{
-	BUG_ON(root_ns_mask);
-
-	if (gen_ns_ids(getpid()))
-		return -1;
-	if (gen_ns_ids(root_item->pid.real))
-		return -1;
-
-	pr_info("NS mask generated: %lx\n", root_ns_mask);
-	return 0;
-}
-
 static int do_dump_namespaces(struct ns_id *ns)
 {
 	int ret;
@@ -536,7 +530,7 @@ int dump_namespaces(struct pstree_item *item, unsigned int ns_flags)
 	return 0;
 }
 
-int collect_namespaces(void)
+int collect_namespaces(bool for_dump)
 {
 	int ret;
 
@@ -544,7 +538,7 @@ int collect_namespaces(void)
 	if (ret < 0)
 		return ret;
 
-	ret = collect_net_namespaces();
+	ret = collect_net_namespaces(for_dump);
 	if (ret < 0)
 		return ret;
 
diff --git a/net.c b/net.c
index 7338d1c..e02a4fa 100644
--- a/net.c
+++ b/net.c
@@ -636,7 +636,7 @@ int veth_pair_add(char *in, char *out)
  * needed other-ns sockets in advance.
  */
 
-static int prep_ns_sockets(struct ns_id *ns)
+static int prep_ns_sockets(struct ns_id *ns, bool for_dump)
 {
 	int nsret = -1, ret;
 
@@ -646,11 +646,14 @@ static int prep_ns_sockets(struct ns_id *ns)
 			return -1;
 	}
 
-	ret = ns->net.nlsk = socket(PF_NETLINK, SOCK_RAW, NETLINK_SOCK_DIAG);
-	if (ret < 0) {
-		pr_perror("Can't create sock diag socket");
-		goto err_nl;
-	}
+	if (for_dump) {
+		ret = ns->net.nlsk = socket(PF_NETLINK, SOCK_RAW, NETLINK_SOCK_DIAG);
+		if (ret < 0) {
+			pr_perror("Can't create sock diag socket");
+			goto err_nl;
+		}
+	} else
+		ns->net.nlsk = -1;
 
 	ret = ns->net.seqsk = socket(PF_UNIX, SOCK_SEQPACKET, 0);
 	if (ret < 0) {
@@ -671,24 +674,28 @@ out:
 err_ret:
 	close(ns->net.seqsk);
 err_sq:
-	close(ns->net.nlsk);
+	if (ns->net.nlsk >= 0)
+		close(ns->net.nlsk);
 err_nl:
 	goto out;
 }
 
-static int collect_net_ns(struct ns_id *ns)
+static int collect_net_ns(struct ns_id *ns, bool for_dump)
 {
 	int ret;
 
 	pr_info("Collecting netns %d/%d\n", ns->id, ns->pid);
-	ret = prep_ns_sockets(ns);
+	ret = prep_ns_sockets(ns, for_dump);
 	if (ret)
 		return ret;
 
+	if (!for_dump)
+		return 0;
+
 	return collect_sockets(ns);
 }
 
-int collect_net_namespaces(void)
+int collect_net_namespaces(bool for_dump)
 {
 	int ret = 0;
 	struct ns_id *ns;
@@ -701,11 +708,11 @@ int collect_net_namespaces(void)
 			if ((root_ns_mask & CLONE_NEWNET))
 				continue;
 
-			ret = collect_net_ns(ns);
+			ret = collect_net_ns(ns, for_dump);
 			break;
 		}
 
-		ret = collect_net_ns(ns);
+		ret = collect_net_ns(ns, for_dump);
 		if (ret)
 			break;
 	}



More information about the CRIU mailing list