[CRIU] [PATCH] add join-ns opt to criu restore
Dengguangxing
dengguangxing at huawei.com
Mon Mar 14 23:08:51 PDT 2016
join-ns will restore process with specified existing namespace.
This opt can be used in this fomat:
--join-ns NS:PID, for example net:12345.
pid namespaces is not supported yet. As fork() is needed to make
new pid-namespace take effect. That makes it hard for criu to track the
child-process through pid because another child process has been
created after fork().
Signed-off-by: Deng Guangxing <dengguangxing at huawei.com>
---
criu/cr-restore.c | 5 +++
criu/crtools.c | 44 ++++++++++++++++++++++++-
criu/include/cr_options.h | 1 +
criu/include/namespaces.h | 10 ++++++
criu/namespaces.c | 82 ++++++++++++++++++++++++++++++++++++++++-------
5 files changed, 129 insertions(+), 13 deletions(-)
diff --git a/criu/cr-restore.c b/criu/cr-restore.c
index 30ddff9..e3f0add 100644
--- a/criu/cr-restore.c
+++ b/criu/cr-restore.c
@@ -1566,6 +1566,11 @@ static int restore_task_with_children(void *_arg)
/* Restore root task */
if (current->parent == NULL) {
+ if (join_namespaces()) {
+ pr_perror("Join namespaces failed");
+ goto err;
+ }
+
if (restore_finish_stage(CR_STATE_RESTORE_NS) < 0)
goto err;
diff --git a/criu/crtools.c b/criu/crtools.c
index d6e8672..87d9ec4 100644
--- a/criu/crtools.c
+++ b/criu/crtools.c
@@ -36,6 +36,7 @@
#include "cr-service.h"
#include "plugin.h"
#include "mount.h"
+#include "namespaces.h"
#include "cgroup.h"
#include "cpu.h"
#include "action-scripts.h"
@@ -58,6 +59,7 @@ void init_opts(void)
INIT_LIST_HEAD(&opts.veth_pairs);
INIT_LIST_HEAD(&opts.scripts);
INIT_LIST_HEAD(&opts.ext_mounts);
+ INIT_LIST_HEAD(&opts.join_ns);
INIT_LIST_HEAD(&opts.inherit_fds);
INIT_LIST_HEAD(&opts.external);
INIT_LIST_HEAD(&opts.new_cgroup_roots);
@@ -99,6 +101,39 @@ bad_ns:
return -1;
}
+static int parse_join_ns(const char *ptr)
+{
+ char *aux;
+ pid_t pid;
+
+ aux = strchr(ptr, ':');
+ if (aux == NULL)
+ return -1;
+ *aux = '\0';
+
+ if (!strcmp(ptr, "pid")) {
+ pr_perror("pid namespace not supported in join-ns\n");
+ return -1;
+ } else if (strcmp(ptr, "net") &&
+ strcmp(ptr, "uts") &&
+ strcmp(ptr, "ipc") &&
+ strcmp(ptr, "user") &&
+ strcmp(ptr, "mnt")) {
+ pr_perror("Illegal namespace %s in join-ns\n", ptr);
+ return -1;
+ }
+
+ pid = atoi(aux+1);
+ if (pid <= 0) {
+ pr_perror("Invalid pid %s in join-ns\n", aux+1);
+ return -1;
+ }
+ if (join_ns_add(ptr, pid))
+ return -1;
+
+ return 0;
+}
+
static int parse_cpu_cap(struct cr_options *opts, const char *optarg)
{
bool inverse = false;
@@ -218,7 +253,7 @@ int main(int argc, char *argv[], char *envp[])
int log_level = LOG_UNSET;
char *imgs_dir = ".";
char *work_dir = NULL;
- static const char short_opts[] = "dSsRf:F:t:p:hcD:o:n:v::x::Vr:jlW:L:M:";
+ static const char short_opts[] = "dSsRf:F:t:p:hcD:o:n:v::x::Vr:jJ:lW:L:M:";
static struct option long_opts[] = {
{ "tree", required_argument, 0, 't' },
{ "pid", required_argument, 0, 'p' },
@@ -234,6 +269,7 @@ int main(int argc, char *argv[], char *envp[])
{ "work-dir", required_argument, 0, 'W' },
{ "log-file", required_argument, 0, 'o' },
{ "namespaces", required_argument, 0, 'n' },
+ { "join-ns", required_argument, 0, 'J' },
{ "root", required_argument, 0, 'r' },
{ USK_EXT_PARAM, optional_argument, 0, 'x' },
{ "help", no_argument, 0, 'h' },
@@ -366,6 +402,10 @@ int main(int argc, char *argv[], char *envp[])
if (parse_ns_string(optarg))
goto bad_arg;
break;
+ case 'J':
+ if (parse_join_ns(optarg))
+ goto bad_arg;
+ break;
case 'v':
if (log_level == LOG_UNSET)
log_level = 0;
@@ -810,6 +850,8 @@ usage:
" --empty-ns {net}\n"
" Create a namespace, but don't restore its properies.\n"
" An user will retore them from action scripts.\n"
+" -J|--join-ns NS:PID\n"
+" Join exist namespace and restore process in it.\n"
"\n"
"* Logging:\n"
" -o|--log-file FILE log file name\n"
diff --git a/criu/include/cr_options.h b/criu/include/cr_options.h
index a6f0b3e..cf3cb0e 100644
--- a/criu/include/cr_options.h
+++ b/criu/include/cr_options.h
@@ -82,6 +82,7 @@ struct cr_options {
struct list_head ext_mounts;
struct list_head inherit_fds;
struct list_head external;
+ struct list_head join_ns;
char *libdir;
bool use_page_server;
unsigned short port;
diff --git a/criu/include/namespaces.h b/criu/include/namespaces.h
index 303c9e6..a7a8863 100644
--- a/criu/include/namespaces.h
+++ b/criu/include/namespaces.h
@@ -3,6 +3,7 @@
#include "compiler.h"
#include "files.h"
+#include "list.h"
/* including syscall-types.h gives another weird error; do we really need to
* define this twice? */
@@ -19,6 +20,13 @@ struct ns_desc {
size_t len;
};
+struct join_ns {
+ struct list_head list;
+ pid_t pid;
+ struct ns_desc nd;
+
+};
+
enum ns_type {
NS_UNKNOWN = 0,
NS_CRIU,
@@ -100,6 +108,8 @@ extern gid_t userns_gid(gid_t gid);
extern int dump_user_ns(pid_t pid, int ns_id);
extern void free_userns_maps(void);
+extern int join_ns_add(const char *type, pid_t pid);
+extern int join_namespaces();
typedef int (*uns_call_t)(void *arg, int fd, pid_t pid);
/*
diff --git a/criu/namespaces.c b/criu/namespaces.c
index d7f8a9f..b3b829e 100644
--- a/criu/namespaces.c
+++ b/criu/namespaces.c
@@ -10,7 +10,9 @@
#include <signal.h>
#include <sched.h>
#include <sys/capability.h>
+#include <sys/stat.h>
+#include "cr_options.h"
#include "util.h"
#include "imgset.h"
#include "uts_ns.h"
@@ -35,6 +37,37 @@ static struct ns_desc *ns_desc_array[] = {
&cgroup_ns_desc,
};
+int join_ns_add(const char *type, pid_t pid) {
+ struct join_ns *jn;
+
+ jn = xmalloc(sizeof(*jn));
+ if (!jn) {
+ return -1;
+ }
+
+ jn->pid = pid;
+ if (!strcmp(type, "net")) {
+ jn->nd = net_ns_desc;
+ } else if (!strcmp(type, "uts")) {
+ jn->nd = uts_ns_desc;
+ } else if (!strcmp(type, "ipc")) {
+ jn->nd = ipc_ns_desc;
+ } else if (!strcmp(type, "pid")) {
+ jn->nd = pid_ns_desc;
+ } else if (!strcmp(type, "user")) {
+ jn->nd = user_ns_desc;
+ } else if (!strcmp(type, "mnt")) {
+ jn->nd = mnt_ns_desc;
+ } else {
+ pr_perror("invalid namespace type %s\n", type);
+ return -1;
+ }
+
+ list_add_tail(&jn->list, &opts.join_ns);
+ pr_info("Added %s:%d join namespace\n", type, pid);
+ return 0;
+}
+
static unsigned int parse_ns_link(char *link, size_t len, struct ns_desc *d)
{
unsigned long kid = 0;
@@ -73,28 +106,41 @@ bool check_ns_proc(struct fd_link *link)
int switch_ns(int pid, struct ns_desc *nd, int *rst)
{
char buf[32];
- int nsfd;
+ int nsfd, self_fd;
int ret = -1;
+ struct stat st, self_st;
nsfd = open_proc(pid, "ns/%s", nd->str);
if (nsfd < 0) {
- pr_perror("Can't open ipcns file");
+ pr_perror("Can't open ns file");
+ goto err_ns;
+ }
+ if (fstat(nsfd, &st) == -1) {
+ pr_perror("Can't get ns file stat");
goto err_ns;
}
+ snprintf(buf, sizeof(buf), "/proc/self/ns/%s", nd->str);
+ self_fd = open(buf, O_RDONLY);
+ if (self_fd < 0) {
+ pr_perror("Can't open ns file");
+ goto err_rst;
+ }
+ if (fstat(self_fd, &self_st) == -1) {
+ pr_perror("Can't get ns file stat");
+ goto err_ns;
+ }
if (rst) {
- snprintf(buf, sizeof(buf), "/proc/self/ns/%s", nd->str);
- *rst = open(buf, O_RDONLY);
- if (*rst < 0) {
- pr_perror("Can't open ns file");
- goto err_rst;
- }
+ *rst = self_fd;
}
- ret = setns(nsfd, nd->cflag);
- if (ret < 0) {
- pr_perror("Can't setns %d/%s", pid, nd->str);
- goto err_set;
+ //re-set the same user-ns would fail, check it here
+ if (st.st_ino != self_st.st_ino) {
+ ret = setns(nsfd, nd->cflag);
+ if (ret < 0) {
+ pr_perror("Can't setns %d/%s", pid, nd->str);
+ goto err_set;
+ }
}
close(nsfd);
@@ -1371,6 +1417,18 @@ static int prepare_userns_creds()
return 0;
}
+int join_namespaces()
+{
+ struct join_ns *jn;
+
+ list_for_each_entry(jn, &opts.join_ns, list)
+ if (switch_ns(jn->pid, &jn->nd, NULL)) {
+ return -1;
+ }
+
+ return 0;
+}
+
int prepare_namespace(struct pstree_item *item, unsigned long clone_flags)
{
pid_t pid = item->pid.virt;
--
2.5.0
More information about the CRIU
mailing list