[CRIU] [PATCH 6/7] files: Add c/r for /proc/$pid/ns/$ids references

Cyrill Gorcunov gorcunov at openvz.org
Wed May 8 09:00:40 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 use generate_ns_id helper to generate namespace
  ids (note if the ids came from nested namespace we issue error
  out because it's not yet supported by criu)
- 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              |   5 +-
 include/files.h      |   2 +
 include/namespaces.h |   5 ++
 namespaces.c         | 153 +++++++++++++++++++++++++++++++++++++++++++++++++++
 5 files changed, 165 insertions(+), 3 deletions(-)

diff --git a/cr-restore.c b/cr-restore.c
index b8a936b..691725e 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 5d3f089..eac425d 100644
--- a/files.c
+++ b/files.c
@@ -280,9 +280,8 @@ static int dump_one_file(struct parasite_ctl *ctl, int fd, int lfd, struct fd_op
 		 * entry thus choose which strategy to dump it with.
 		 */
 		if (parse_ns_proc(&p.nmlink[1], p.nmsize - 1, &found) == 0) {
-			pr_err("Dumping procfs namespace reference "
-			       "is not yet implemented\n");
-			return -1;
+			p.arg = &found;
+			return dump_ns_file(&p, lfd, fdinfo);
 		}
 
 		return dump_reg_file(&p, lfd, fdinfo);
diff --git a/include/files.h b/include/files.h
index 3927580..06f9f10 100644
--- a/include/files.h
+++ b/include/files.h
@@ -33,6 +33,7 @@ struct fd_parms {
 	char		*nmlink;
 	size_t		nmsize;
 	size_t		nmlen;
+	void		*arg;
 
 	struct parasite_ctl *ctl;
 };
@@ -44,6 +45,7 @@ struct fd_parms {
 	.nmlink	= NULL,			\
 	.nmsize	= 0,			\
 	.nmlen	= 0,			\
+	.arg	= NULL,			\
 }
 
 struct file_desc;
diff --git a/include/namespaces.h b/include/namespaces.h
index bfe875c..1384135 100644
--- a/include/namespaces.h
+++ b/include/namespaces.h
@@ -3,6 +3,7 @@
 
 #include "crtools.h"
 #include "pstree.h"
+#include "files.h"
 
 enum {
 	PROC_NS_NET,
@@ -16,6 +17,7 @@ enum {
 };
 
 struct ns_proc_entry {
+	int		type;
 	char		*name;
 	size_t		name_len;
 	unsigned long	i_ino;
@@ -23,11 +25,14 @@ struct ns_proc_entry {
 
 #define NS_PROC_ENTRY(_index, _name)			\
 	[_index] = {					\
+		.type		= _index,		\
 		.name		= _name,		\
 		.name_len	= sizeof(_name) - 1,	\
 	}
 
 extern int parse_ns_proc(char *link, size_t len, struct ns_proc_entry *found);
+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);
diff --git a/namespaces.c b/namespaces.c
index f95928c..81c6ca8 100644
--- a/namespaces.c
+++ b/namespaces.c
@@ -10,6 +10,9 @@
 #include "namespaces.h"
 #include "net.h"
 
+#include "protobuf.h"
+#include "protobuf/nsfile.pb-c.h"
+
 static struct ns_proc_entry ns_proc_entries[PROC_NS_MAX] = {
 	NS_PROC_ENTRY(PROC_NS_NET,	"net"),
 	NS_PROC_ENTRY(PROC_NS_UTS,	"uts"),
@@ -33,6 +36,7 @@ int parse_ns_proc(char *link, size_t len, struct ns_proc_entry *found)
 		if (link[sz] == ':' && !memcmp(link, ns_proc_entries[i].name, sz)) {
 			found->i_ino	= strtoul(&link[sz + 2], &end, 10);
 			found->name	= ns_proc_entries[i].name;
+			found->type	= ns_proc_entries[i].type;
 			found->name_len	= sz;
 
 			if (end && *end == ']')
@@ -166,6 +170,155 @@ 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;
+	struct ns_desc *nd;
+
+	switch (entry->type) {
+	case PROC_NS_NET:
+		nd = &net_ns_desc;
+		break;
+	case PROC_NS_UTS:
+		nd = &uts_ns_desc;
+		break;
+	case PROC_NS_IPC:
+		nd = &ipc_ns_desc;
+		break;
+	case PROC_NS_PID:
+		nd = &pid_ns_desc;
+		break;
+	case PROC_NS_MNT:
+		nd = &mnt_ns_desc;
+		break;
+	default:
+		pr_err("Namespace `%s' referred by fd %d "
+		       "(pid %d) is unsupported\n",
+		       entry->name, p->fd, p->pid);
+		return -1;
+	}
+
+	BUG_ON(entry->i_ino > UINT_MAX);
+
+	nfe.id		= id;
+	nfe.flags	= p->flags;
+	nfe.ns_id	= generate_ns_id(p->pid, (unsigned int)entry->i_ino, nd);
+
+	if (!nfe.ns_id) {
+		pr_err("Can't generate id for ns `%s' referred by fd %d (pid %d)\n",
+		       entry->name, p->fd, p->pid);
+		return -1;
+	}
+
+	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 ns_proc_entry *ns_proc_entry = NULL;
+	struct pstree_item *item, *t;
+	char path[64];
+	int fd;
+
+#define __ns_match(_name)		\
+	ids->has_##_name &&		\
+	ids->_name == nfi->nfe->ns_id
+
+	/*
+	 * Find out who can open us.
+	 *
+	 * FIXME I need a hash or RBtree here.
+	 */
+	for_each_pstree_item(t) {
+		TaskKobjIdsEntry *ids = t->ids;
+
+		if (__ns_match(pid_ns_id)) {
+			item = t;
+			ns_proc_entry = &ns_proc_entries[PROC_NS_PID];
+			break;
+		} else if (__ns_match(net_ns_id)) {
+			item = t;
+			ns_proc_entry = &ns_proc_entries[PROC_NS_NET];
+			break;
+		} else if (__ns_match(ipc_ns_id)) {
+			item = t;
+			ns_proc_entry = &ns_proc_entries[PROC_NS_IPC];
+			break;
+		} else if (__ns_match(uts_ns_id)) {
+			item = t;
+			ns_proc_entry = &ns_proc_entries[PROC_NS_UTS];
+			break;
+		} else if (__ns_match(mnt_ns_id)) {
+			item = t;
+			ns_proc_entry = &ns_proc_entries[PROC_NS_MNT];
+			break;
+		}
+	}
+
+#undef __ns_match
+
+	if (!ns_proc_entry || !item) {
+		pr_err("Can't find suitable NS ID for %#x\n",
+		       nfi->nfe->ns_id);
+		return -1;
+	}
+
+	snprintf(path, sizeof(path) - 1, "/proc/%d/ns/%s",
+		 item->pid.virt, ns_proc_entry->name);
+	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)
+{
+	return collect_image(CR_FD_NS_FILES, PB_NS_FILES,
+			     sizeof(struct ns_file_info),
+			     collect_one_nsfile);
+}
+
 int dump_task_ns_ids(struct pstree_item *item)
 {
 	int pid = item->pid.real;
-- 
1.8.1.4



More information about the CRIU mailing list