[CRIU] [PATCH 6/6] unshare: Support pidns
Pavel Emelyanov
xemul at parallels.com
Wed Dec 9 04:02:46 PST 2015
This one is tricky. When restoring into new pidns we have to provide
some init for it, and root task cannot be such, as it already has non
1 pid.
So for pidns unshare insert a fake entry as root with pid 1 and teach
it to be pseudo-init, i.e. just pick up all died tasks.
Signed-off-by: Pavel Emelyanov <xemul at parallels.com>
---
cr-restore.c | 7 ++++++-
crtools.c | 2 +-
include/rst_info.h | 5 ++++-
pstree.c | 57 +++++++++++++++++++++++++++++++++++++++++++++++++++++-
4 files changed, 67 insertions(+), 4 deletions(-)
diff --git a/cr-restore.c b/cr-restore.c
index 74f4b90..deabc5d 100644
--- a/cr-restore.c
+++ b/cr-restore.c
@@ -1017,6 +1017,8 @@ static int restore_one_task(int pid, CoreEntry *core)
ret = restore_one_zombie(core);
else if (current->state == TASK_HELPER) {
restore_finish_stage(CR_STATE_RESTORE);
+ if (rsti(current)->helper_cb)
+ rsti(current)->helper_cb();
ret = 0;
} else {
pr_err("Unknown state in code %d\n", (int)core->tc->task_state);
@@ -1121,7 +1123,10 @@ static inline int fork_with_pid(struct pstree_item *item)
* Helper entry will not get moved around and thus
* will live in the parent's cgset.
*/
- rsti(item)->cg_set = rsti(item->parent)->cg_set;
+ if (item->parent)
+ rsti(item)->cg_set = rsti(item->parent)->cg_set;
+ else
+ rsti(item)->cg_set = root_cg_set;
ca.core = NULL;
}
diff --git a/crtools.c b/crtools.c
index 24b4a3f..c82648f 100644
--- a/crtools.c
+++ b/crtools.c
@@ -130,7 +130,7 @@ static int parse_unshare_arg(char *opt)
}
/* Only pid, mnt and user for now */
- if (opts.unshare_flags & ~(CLONE_NEWNS | 0x1)) {
+ if (opts.unshare_flags & ~(CLONE_NEWNS | CLONE_NEWPID | 0x1)) {
pr_err("Unsharing this namespace(s) is not supported yet\n");
return -1;
}
diff --git a/include/rst_info.h b/include/rst_info.h
index b72e5d0..b6d378e 100644
--- a/include/rst_info.h
+++ b/include/rst_info.h
@@ -65,7 +65,10 @@ struct rst_info {
*/
bool has_seccomp;
- void *breakpoint;
+ union {
+ void *breakpoint;
+ void (*helper_cb)(void);
+ };
};
#endif /* __CR_RST_INFO_H__ */
diff --git a/pstree.c b/pstree.c
index ba547c1..bb30817 100644
--- a/pstree.c
+++ b/pstree.c
@@ -1,6 +1,7 @@
#include <sys/mman.h>
#include <unistd.h>
#include <stdlib.h>
+#include <sys/wait.h>
#include "cr_options.h"
#include "pstree.h"
@@ -11,6 +12,8 @@
#include "tty.h"
#include "mount.h"
#include "asm/dump.h"
+#include "setproctitle.h"
+#include "files.h"
#include "protobuf.h"
#include "protobuf/pstree.pb-c.h"
@@ -741,9 +744,61 @@ set_mask:
return 0;
}
+static void do_fake_init(void)
+{
+ close_old_fds();
+ close_image_dir();
+ close_proc();
+ close_service_fd(CR_PROC_FD_OFF);
+ close_service_fd(ROOT_FD_OFF);
+ close_service_fd(USERNSD_SK);
+ log_fini();
+
+ setproctitle("criu-init");
+
+ while (wait(NULL) >= 0)
+ ;
+ exit(0);
+}
+
static int prepare_pstree_for_unshare(void)
{
- {
+ /*
+ * Unsharing in anything but pid namespace just puts the
+ * root task into the requesting set. If pidns is the aim,
+ * then check for the root task to already live in it,
+ * otherwise -- insert fake init entry into the tree.
+ */
+
+ if ((opts.unshare_flags & CLONE_NEWPID) &&
+ !(rsti(root_item)->clone_flags & CLONE_NEWPID)) {
+ struct pstree_item *fake_root;
+
+ fake_root = alloc_pstree_item_with_rst();
+
+ fake_root->state = TASK_HELPER;
+ fake_root->pid.virt = INIT_PID;
+ fake_root->pgid = INIT_PID;
+ fake_root->sid = INIT_PID;
+ fake_root->nr_threads = 1;
+ fake_root->threads = xmalloc(sizeof(struct pid));
+ if (!fake_root->threads)
+ return -1;
+
+ fake_root->threads->real = -1;
+ fake_root->threads->virt = INIT_PID;
+ fake_root->ids = root_ids;
+ rsti(fake_root)->clone_flags = opts.unshare_flags | rsti(root_item)->clone_flags;
+
+ rsti(fake_root)->helper_cb = do_fake_init;
+
+ list_add_tail(&root_item->sibling, &fake_root->children);
+ root_item->parent = fake_root;
+ rsti(root_item)->clone_flags = 0;
+
+ task_entries->nr_helpers++;
+ root_item = fake_root;
+ } else {
unsigned long aux;
/*
--
1.9.3
More information about the CRIU
mailing list