[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