[PATCH 8/9] ns: Add c/r for /proc/$pid/ns/$ids references

Cyrill Gorcunov gorcunov at openvz.org
Mon May 20 04:59:45 EDT 2013


In this commit we implement c/r for files which have opened
/proc/$pid/ns/$ids entries.

The idea is rather simple one

Checkpoint
==========

- Check if the file name is the one of known to be ns ref
- If match then write protobuf entry

Restore
=======

- Read all ns entries from the image
- When criu tries to open one we lookup over process
  tree to figure out which PID should be used in path
  and then just open it

Signed-off-by: Cyrill Gorcunov <gorcunov at openvz.org>
---
 cr-restore.c         |   3 ++
 files.c              |  12 ++---
 include/files.h      |   2 +
 include/namespaces.h |   4 ++
 namespaces.c         | 131 +++++++++++++++++++++++++++++++++++++++++++++++++++
 5 files changed, 145 insertions(+), 7 deletions(-)

diff --git a/cr-restore.c b/cr-restore.c
index c76eed8..08dc970 100644
--- a/cr-restore.c
+++ b/cr-restore.c
@@ -124,6 +124,9 @@ static int root_prepare_shared(void)
 	if (collect_reg_files())
 		return -1;
 
+	if (collect_ns_files())
+		return -1;
+
 	if (collect_pipes())
 		return -1;
 
diff --git a/files.c b/files.c
index 2c40c5f..af1bffc 100644
--- a/files.c
+++ b/files.c
@@ -263,20 +263,18 @@ static int dump_one_file(struct parasite_ctl *ctl, int fd, int lfd, struct fd_op
 	}
 
 	if (S_ISREG(p.stat.st_mode) || S_ISDIR(p.stat.st_mode)) {
-		struct ns_proc_entry found;
+		struct ns_proc_entry found = { };
 		struct fd_link link;
 
 		if (fill_fdlink(lfd, &p, &link))
 			return -1;
 		p.link = &link;
+		p.arg = &found;
 
-		if (link.name[1] == '/') {
+		if (link.name[1] == '/')
 			return dump_reg_file(&p, lfd, fdinfo);
-		} else if (check_ns_proc(&link.name[1], link.len - 1, &found) == 0) {
-			pr_err("Found ns link %s:%li, not yet supported\n",
-				found.d->str, found.i_ino);
-			return -1;
-		}
+		else if (check_ns_proc(&link.name[1], link.len - 1, &found) == 0)
+			return dump_ns_file(&p, lfd, fdinfo);
 	}
 
 	if (S_ISFIFO(p.stat.st_mode)) {
diff --git a/include/files.h b/include/files.h
index 9e49d1f..c923a6b 100644
--- a/include/files.h
+++ b/include/files.h
@@ -31,6 +31,7 @@ struct fd_parms {
 	pid_t		pid;
 	FownEntry	fown;
 	struct fd_link	*link;
+	void		*arg;
 
 	struct parasite_ctl *ctl;
 };
@@ -40,6 +41,7 @@ struct fd_parms {
 	.fd	= FD_DESC_INVALID,	\
 	.fown	= FOWN_ENTRY__INIT,	\
 	.link	= NULL,			\
+	.arg	= NULL,			\
 }
 
 extern int fill_fdlink(int lfd, struct fd_parms *p, struct fd_link *link);
diff --git a/include/namespaces.h b/include/namespaces.h
index a646ea7..59914d6 100644
--- a/include/namespaces.h
+++ b/include/namespaces.h
@@ -3,6 +3,7 @@
 
 #include "crtools.h"
 #include "pstree.h"
+#include "files.h"
 
 struct cr_options;
 
@@ -30,6 +31,9 @@ extern struct ns_desc pid_ns_desc;
 extern struct ns_desc user_ns_desc;
 extern unsigned long current_ns_mask;
 
+extern int dump_ns_file(struct fd_parms *p, int lfd, const int fdinfo);
+extern int collect_ns_files(void);
+
 int dump_namespaces(struct pid *pid, unsigned int ns_flags);
 int prepare_namespace(int pid, unsigned long clone_flags);
 int try_show_namespaces(int pid, struct cr_options *o);
diff --git a/namespaces.c b/namespaces.c
index 7ba1309..b45a19a 100644
--- a/namespaces.c
+++ b/namespaces.c
@@ -10,6 +10,9 @@
 #include "namespaces.h"
 #include "net.h"
 
+#include "protobuf.h"
+#include "protobuf/ns.pb-c.h"
+
 struct ns_desc *ns_desc_array[] = {
 	&net_ns_desc,
 	&uts_ns_desc,
@@ -175,6 +178,134 @@ static unsigned int get_ns_id(int pid, struct ns_desc *nd)
 	return generate_ns_id(pid, kid, nd);
 }
 
+int dump_one_ns_file(int lfd, u32 id, const struct fd_parms *p)
+{
+	int fd = fdset_fd(glob_fdset, CR_FD_NS_FILES);
+	NsFileEntry nfe = NS_FILE_ENTRY__INIT;
+	struct ns_proc_entry *entry = p->arg;
+	unsigned int ns_id;
+
+	ns_id = generate_ns_id(p->pid, entry->i_ino, entry->d);
+	if (!ns_id) {
+		pr_err("Can't generate NS ID with kid %li\n", entry->i_ino);
+		return -1;
+	}
+
+	nfe.id		= id;
+	nfe.ns_id	= ns_id;
+	nfe.cflag	= entry->d->cflag;
+	nfe.flags	= p->flags;
+
+	return pb_write_one(fd, &nfe, PB_NS_FILES);
+}
+
+static const struct fdtype_ops nsfile_ops = {
+	.type		= FD_TYPES__NS,
+	.dump		= dump_one_ns_file,
+};
+
+int dump_ns_file(struct fd_parms *p, int lfd, const int fdinfo)
+{
+	return do_dump_gen_file(p, lfd, &nsfile_ops, fdinfo);
+}
+
+struct ns_file_info {
+	struct file_desc	d;
+	NsFileEntry		*nfe;
+};
+
+static int open_ns_fd(struct file_desc *d)
+{
+	struct ns_file_info *nfi = container_of(d, struct ns_file_info, d);
+	struct pstree_item *item, *t;
+	struct ns_desc *nd = NULL;
+	char path[64];
+	int fd;
+
+	/*
+	 * Find out who can open us.
+	 *
+	 * FIXME I need a hash or RBtree here.
+	 */
+	for_each_pstree_item(t) {
+		TaskKobjIdsEntry *ids = t->ids;
+
+		if (ids->pid_ns_id == nfi->nfe->ns_id) {
+			item = t;
+			nd = &pid_ns_desc;
+			break;
+		} else if (ids->net_ns_id == nfi->nfe->ns_id) {
+			item = t;
+			nd = &net_ns_desc;
+			break;
+		} else if (ids->ipc_ns_id == nfi->nfe->ns_id) {
+			item = t;
+			nd = &ipc_ns_desc;
+			break;
+		} else if (ids->uts_ns_id == nfi->nfe->ns_id) {
+			item = t;
+			nd = &uts_ns_desc;
+			break;
+		} else if (ids->mnt_ns_id == nfi->nfe->ns_id) {
+			item = t;
+			nd = &mnt_ns_desc;
+			break;
+		}
+	}
+
+	if (!nd || !item) {
+		pr_err("Can't find suitable NS ID for %#x\n",
+		       nfi->nfe->ns_id);
+		return -1;
+	} else if (nd->cflag != nfi->nfe->cflag) {
+		pr_err("Clone flag mismatch for %#x\n",
+		       nfi->nfe->ns_id);
+		return -1;
+	}
+
+	snprintf(path, sizeof(path) - 1, "/proc/%d/ns/%s",
+		 item->pid.virt, nd->str);
+	path[sizeof(path) - 1] = '\0';
+
+	fd = open(path, nfi->nfe->flags);
+	if (fd < 0) {
+		pr_perror("Can't open file %s on restore", path);
+		return fd;
+	}
+
+	return fd;
+}
+
+static struct file_desc_ops ns_desc_ops = {
+	.type = FD_TYPES__NS,
+	.open = open_ns_fd,
+};
+
+static int collect_one_nsfile(void *o, ProtobufCMessage *base)
+{
+	struct ns_file_info *nfi = o;
+
+	nfi->nfe = pb_msg(base, NsFileEntry);
+
+	pr_info("Collected ns file ID %#x NS-ID %#x\n",
+		nfi->nfe->id, nfi->nfe->ns_id);
+	file_desc_add(&nfi->d, nfi->nfe->id, &ns_desc_ops);
+
+	return 0;
+}
+
+int collect_ns_files(void)
+{
+	int ret;
+
+	ret = collect_image(CR_FD_NS_FILES, PB_NS_FILES,
+			    sizeof(struct ns_file_info),
+			    collect_one_nsfile);
+	if (ret < 0 && errno == ENOENT)
+		ret = 0;
+	return ret;
+}
+
 int dump_task_ns_ids(struct pstree_item *item)
 {
 	int pid = item->pid.real;
-- 
1.8.1.4


--Nq2Wo0NMKNjxTN9z--


More information about the CRIU mailing list