Skip to content

Commit

Permalink
namespaces: generalize restoring of nested-ns
Browse files Browse the repository at this point in the history
Take code that creates ns, holds it with fd in root task, restores it
afterwards by ns_id from nested net namespaces restore.

The same code will be used in IPC, UTS namespaces for restore,
so generalize it.

Cc: Andrei Vagin <avagin@virtuozzo.com>
Signed-off-by: Dmitry Safonov <dsafonov@virtuozzo.com>
  • Loading branch information
0x7f454c46 committed Feb 3, 2017
1 parent 31878a3 commit 1d88b49
Show file tree
Hide file tree
Showing 5 changed files with 136 additions and 114 deletions.
6 changes: 3 additions & 3 deletions criu/cr-restore.c
Expand Up @@ -717,7 +717,7 @@ static int restore_one_alive_task(int pid, CoreEntry *core)
* Sockets have to be restored in their network namespaces,
* so a task namespace has to be restored after sockets.
*/
if (restore_task_net_ns(current))
if (restore_task_ns(current))
return -1;

if (setup_uffd(pid, ta))
Expand Down Expand Up @@ -1436,7 +1436,7 @@ static int restore_task_with_children(void *_arg)
if (mount_proc())
goto err;

if (prepare_namespace(current, ca->clone_flags))
if (prepare_namespaces(current, ca->clone_flags))
goto err;

if (root_prepare_shared())
Expand Down Expand Up @@ -2967,7 +2967,7 @@ static int sigreturn_restore(pid_t pid, struct task_restore_args *task_args, uns
if (current->parent == NULL) {
/* Wait when all tasks restored all files */
restore_wait_other_tasks();
fini_net_namespaces();
fini_namespaces_fd();
}

/*
Expand Down
4 changes: 3 additions & 1 deletion criu/include/namespaces.h
Expand Up @@ -128,7 +128,9 @@ extern int collect_mnt_namespaces(bool for_dump);
extern int dump_mnt_namespaces(void);
extern int dump_namespaces(struct pstree_item *item, unsigned int ns_flags);
extern int prepare_namespace_before_tasks(void);
extern int prepare_namespace(struct pstree_item *item, unsigned long clone_flags);
extern int prepare_namespaces(struct pstree_item *item, unsigned long clone_flags);
extern void fini_namespaces_fd(void);
extern int restore_task_ns(struct pstree_item *current);

extern int switch_ns(int pid, struct ns_desc *nd, int *rst);
extern int switch_ns_by_fd(int nsfd, struct ns_desc *nd, int *rst);
Expand Down
6 changes: 1 addition & 5 deletions criu/include/net.h
Expand Up @@ -12,13 +12,9 @@

struct cr_imgset;
extern int dump_net_ns(int ns_id);
extern int prepare_net_namespaces(void);
extern void fini_net_namespaces(void);
extern int prepare_net_ns(int ns_id);
extern int netns_keep_nsfd(void);

struct pstree_item;
extern int restore_task_net_ns(struct pstree_item *current);

struct veth_pair {
struct list_head node;
char *inside;
Expand Down
130 changes: 128 additions & 2 deletions criu/namespaces.c
Expand Up @@ -1643,7 +1643,133 @@ int join_namespaces(void)
return ret;
}

int prepare_namespace(struct pstree_item *item, unsigned long clone_flags)
/*
* Namespaces, holded by opened fd in criu root task and
* restored by setns-ing into them.
*/
#define CLONE_FD_NS (CLONE_NEWNET)

static int do_restore_task_ns(unsigned int id, struct ns_desc *desc)
{
struct ns_id *nsid;
int fd;

nsid = lookup_ns_by_id(id, desc);
if (nsid == NULL) {
pr_err("Can't find %s namespace %d\n", desc->str, id);
return -1;
}

BUG_ON(nsid->type == NS_CRIU);

fd = open_proc(root_item->pid->ns[0].virt, "fd/%d", nsid->ns_fd);
if (fd < 0)
return -1;

if (setns(fd, desc->cflag)) {
pr_perror("Can't restore %s namespace", desc->str);
close(fd);
return -1;
}
close(fd);

return 0;
}

int restore_task_ns(struct pstree_item *current)
{
if (!current->ids)
return 0;

if (current->ids->has_net_ns_id && (root_ns_mask & CLONE_NEWNET)) {
if (do_restore_task_ns(current->ids->net_ns_id, &net_ns_desc))
return -1;
}

return 0;
}

void fini_namespaces_fd(void)
{
struct ns_id *nsid;

if (!(root_ns_mask & CLONE_FD_NS))
return;

for_each_ns(nsid) {
if (nsid->nd != &net_ns_desc)
continue;
close_safe(&nsid->ns_fd);
}
}

static int add_ns_fd(struct ns_id *nsid, struct rst_info *rst)
{
int fd, tfd;

/* Pin one with a file descriptor */
fd = open_proc(PROC_SELF, "ns/%s", nsid->nd->str);
if (fd < 0)
return -1;

tfd = reopen_as_unused_fd(fd, rst);
if (tfd < 0) {
close(fd);
return -1;
}
nsid->ns_fd = tfd;

return 0;
}

static int create_one_namespace(struct ns_id *nsid)
{
unsigned int ns_cflag = nsid->nd->cflag;

if (!(ns_cflag & CLONE_FD_NS))
return 0;

if (!(root_ns_mask & ns_cflag))
return 0;

if (unshare(ns_cflag)) {
pr_perror("Unable to create a new %s namespace", nsid->nd->str);
return -1;
}

switch (ns_cflag) {
case CLONE_NEWNET:
if (prepare_net_ns(nsid->id))
return -1;
break;
default:
BUG();
}

if (add_ns_fd(nsid, rsti(root_item)))
return -1;

return 0;
}

static int create_namespaces(void)
{
struct ns_id *nsid;
int ret;

if (!(root_ns_mask & CLONE_FD_NS))
return 0;

for_each_ns(nsid) {
ret = create_one_namespace(nsid);
if (ret)
return ret;
}

return 0;
}

int prepare_namespaces(struct pstree_item *item, unsigned long clone_flags)
{
pid_t pid = item->pid->ns[0].virt;
int id;
Expand All @@ -1667,7 +1793,7 @@ int prepare_namespace(struct pstree_item *item, unsigned long clone_flags)
if ((clone_flags & CLONE_NEWIPC) && prepare_ipc_ns(id))
return -1;

if (prepare_net_namespaces())
if (create_namespaces())
return -1;

/*
Expand Down
104 changes: 1 addition & 103 deletions criu/net.c
Expand Up @@ -1670,7 +1670,7 @@ int dump_net_ns(int ns_id)
return ret;
}

static int prepare_net_ns(int nsid)
int prepare_net_ns(int nsid)
{
int ret = 0;
NetnsEntry *netns = NULL;
Expand Down Expand Up @@ -1702,108 +1702,6 @@ static int prepare_net_ns(int nsid)
return ret;
}

static int open_net_ns(struct ns_id *nsid, struct rst_info *rst)
{
int fd, tfd;

/* Pin one with a file descriptor */
fd = open_proc(PROC_SELF, "ns/net");
if (fd < 0)
return -1;
tfd = reopen_as_unused_fd(fd, rst);
if (tfd < 0) {
close(fd);
return -1;
}
nsid->ns_fd = tfd;

return 0;
}

int prepare_net_namespaces()
{
struct ns_id *nsid;

if (!(root_ns_mask & CLONE_NEWNET))
return 0;

for_each_ns(nsid) {
if (nsid->nd != &net_ns_desc)
continue;

if (unshare(CLONE_NEWNET)) {
pr_perror("Unable to create a new netns");
goto err;
}

if (prepare_net_ns(nsid->id))
goto err;

if (open_net_ns(nsid, rsti(root_item)))
goto err;
}

return 0;
err:
return -1;
}

void fini_net_namespaces()
{
struct ns_id *nsid;

if (!(root_ns_mask & CLONE_NEWNET))
return;

for_each_ns(nsid) {
if (nsid->nd != &net_ns_desc)
continue;
close_safe(&nsid->ns_fd);
}
}

static int do_restore_task_net_ns(struct ns_id *nsid, struct pstree_item *current)
{
int fd;

if (!(root_ns_mask & CLONE_NEWNET))
return 0;

fd = open_proc(root_item->pid->ns[0].virt, "fd/%d", nsid->ns_fd);
if (fd < 0)
return -1;

if (setns(fd, CLONE_NEWNET)) {
pr_perror("Can't restore netns");
close(fd);
return -1;
}
close(fd);

return 0;
}

int restore_task_net_ns(struct pstree_item *current)
{
if (current->ids && current->ids->has_net_ns_id) {
unsigned int id = current->ids->net_ns_id;
struct ns_id *nsid;

nsid = lookup_ns_by_id(id, &net_ns_desc);
if (nsid == NULL) {
pr_err("Can't find mount namespace %d\n", id);
return -1;
}

BUG_ON(nsid->type == NS_CRIU);

if (do_restore_task_net_ns(nsid, current))
return -1;
}

return 0;
}

int netns_keep_nsfd(void)
{
int ns_fd, ret;
Expand Down

0 comments on commit 1d88b49

Please sign in to comment.