[CRIU] [PATCH v2 07/36] ns: Set nested namespaces hookups
Kirill Tkhai
ktkhai at virtuozzo.com
Tue Feb 7 00:22:17 PST 2017
On 07.02.2017 04:45, Andrei Vagin wrote:
> On Fri, Feb 03, 2017 at 07:12:40PM +0300, Kirill Tkhai wrote:
>> Introduce ns_id::parent and assign a pointer to parent
>> for every ns except NS_CRIU and NS_ROOT.
>> Also populate user_ns for pid_ns.
>>
>> Signed-off-by: Kirill Tkhai <ktkhai at virtuozzo.com>
>> ---
>> criu/include/namespaces.h | 12 +++++++
>> criu/namespaces.c | 81 +++++++++++++++++++++++++++++++++++++++++++++
>> 2 files changed, 93 insertions(+)
>>
>> diff --git a/criu/include/namespaces.h b/criu/include/namespaces.h
>> index c9f3e8a74..e1f0fa79f 100644
>> --- a/criu/include/namespaces.h
>> +++ b/criu/include/namespaces.h
>> @@ -1,6 +1,8 @@
>> #ifndef __CR_NS_H__
>> #define __CR_NS_H__
>>
>> +#include <sys/ioctl.h>
>> +
>> #include "common/compiler.h"
>> #include "files.h"
>> #include "common/list.h"
>> @@ -39,6 +41,12 @@
>> #define CLONE_SUBNS (CLONE_NEWNS)
>> #define EXTRA_SIZE 20
>>
>> +#ifndef NSIO
>> +#define NSIO 0xb7
>> +#define NS_GET_USERNS _IO(NSIO, 0x1)
>> +#define NS_GET_PARENT _IO(NSIO, 0x2)
>> +#endif
>> +
>> struct ns_desc {
>> unsigned int cflag;
>> char *str;
>> @@ -75,6 +83,10 @@ struct ns_id {
>> unsigned int id;
>> pid_t ns_pid;
>> struct ns_desc *nd;
>> + struct ns_id *parent;
>> + struct list_head children;
>> + struct list_head siblings;
>> + struct ns_id *user_ns;
>> struct ns_id *next;
>> enum ns_type type;
>>
>> diff --git a/criu/namespaces.c b/criu/namespaces.c
>> index f655c164e..12a5408e2 100644
>> --- a/criu/namespaces.c
>> +++ b/criu/namespaces.c
>> @@ -13,6 +13,7 @@
>> #include <sys/stat.h>
>> #include <limits.h>
>> #include <errno.h>
>> +#include <sys/ioctl.h>
>>
>> #include "page.h"
>> #include "rst-malloc.h"
>> @@ -302,6 +303,8 @@ struct ns_id *rst_new_ns_id(unsigned int id, pid_t pid,
>> nsid->type = type;
>> nsid_add(nsid, nd, id, pid);
>> nsid->ns_populated = false;
>> + INIT_LIST_HEAD(&nsid->children);
>> + INIT_LIST_HEAD(&nsid->siblings);
>> }
>>
>> return nsid;
>> @@ -421,6 +424,8 @@ static unsigned int generate_ns_id(int pid, unsigned int kid, struct ns_desc *nd
>> nsid->type = type;
>> nsid->kid = kid;
>> nsid->ns_populated = true;
>> + INIT_LIST_HEAD(&nsid->children);
>> + INIT_LIST_HEAD(&nsid->siblings);
>> nsid_add(nsid, nd, ns_next_id++, pid);
>>
>> found:
>> @@ -661,6 +666,82 @@ int dump_task_ns_ids(struct pstree_item *item)
>> return 0;
>> }
>>
>> +static int set_ns_opt(int ns_fd, unsigned ioc, struct ns_id **ns, struct ns_desc *nd)
>> +{
>> + int opt_fd, ret = -1;
>> + struct stat st;
>> +
>> + opt_fd = ioctl(ns_fd, ioc);
>> + if (opt_fd < 0) {
>> + pr_info("Can't do ns ioctl %x\n", ioc);
>> + return -errno;
>> + }
>> + if (fstat(opt_fd, &st) < 0) {
>> + pr_perror("Unable to stat on ns fd");
>> + ret = -errno;
>> + goto out;
>> + }
>> + *ns = lookup_ns_by_kid(st.st_ino, nd);
>> + if (!*ns) {
>> + pr_err("Namespaces hierarhies with holes are not supported\n");
>> + ret = -EINVAL;
>> + goto out;
>> + }
>> + ret = 0;
>> +out:
>> + close(opt_fd);
>> + return ret;
>> +}
>> +
>> +static int set_ns_hookups(struct ns_id *ns)
>> +{
>> + struct ns_desc *nd = ns->nd;
>> + struct ns_id *u_ns;
>> + int fd, ret = -1;
>> +
>> + if (ns->type == NS_CRIU)
>> + return 0;
>> +
>> + fd = open_proc(ns->ns_pid, "ns/%s", nd->str);
>> + if (fd < 0) {
>> + pr_perror("Can't open %s, pid %d", nd->str, ns->ns_pid);
>> + return -1;
>> + }
>> +
>> + if (ns->type != NS_ROOT && (nd == &user_ns_desc || nd == &pid_ns_desc)) {
>> + if (set_ns_opt(fd, NS_GET_PARENT, &ns->parent, nd) < 0)
>> + goto out;
>> + list_add(&ns->siblings, &ns->parent->children);
>> + }
>> +
>> + if (nd != &user_ns_desc) {
>> + ret = set_ns_opt(fd, NS_GET_USERNS, &ns->user_ns, &user_ns_desc);
>
> I think we should not dump more than one userns, if NS_GET_USERNS isn't
> supported by this kernel.
Yeah, exactly yesterday worked about that :)
commit 1db8cb2cfc3184f3a22830cdfe85f6efa749300c
Author: Kirill Tkhai <ktkhai at virtuozzo.com>
Date: Mon Feb 6 13:33:16 2017 +0300
ns: Set nested namespaces hookups
Introduce ns_id::parent and assign a pointer to parent
for every ns except NS_CRIU and NS_ROOT.
Also populate user_ns for pid_ns.
Signed-off-by: Kirill Tkhai <ktkhai at virtuozzo.com>
diff --git a/criu/include/namespaces.h b/criu/include/namespaces.h
index c9f3e8a74..e1f0fa79f 100644
--- a/criu/include/namespaces.h
+++ b/criu/include/namespaces.h
@@ -1,6 +1,8 @@
#ifndef __CR_NS_H__
#define __CR_NS_H__
+#include <sys/ioctl.h>
+
#include "common/compiler.h"
#include "files.h"
#include "common/list.h"
@@ -39,6 +41,12 @@
#define CLONE_SUBNS (CLONE_NEWNS)
#define EXTRA_SIZE 20
+#ifndef NSIO
+#define NSIO 0xb7
+#define NS_GET_USERNS _IO(NSIO, 0x1)
+#define NS_GET_PARENT _IO(NSIO, 0x2)
+#endif
+
struct ns_desc {
unsigned int cflag;
char *str;
@@ -75,6 +83,10 @@ struct ns_id {
unsigned int id;
pid_t ns_pid;
struct ns_desc *nd;
+ struct ns_id *parent;
+ struct list_head children;
+ struct list_head siblings;
+ struct ns_id *user_ns;
struct ns_id *next;
enum ns_type type;
diff --git a/criu/namespaces.c b/criu/namespaces.c
index b1cca989f..7e9917c74 100644
--- a/criu/namespaces.c
+++ b/criu/namespaces.c
@@ -13,6 +13,7 @@
#include <sys/stat.h>
#include <limits.h>
#include <errno.h>
+#include <sys/ioctl.h>
#include "page.h"
#include "rst-malloc.h"
@@ -302,6 +303,8 @@ struct ns_id *rst_new_ns_id(unsigned int id, pid_t pid,
nsid->type = type;
nsid_add(nsid, nd, id, pid);
nsid->ns_populated = false;
+ INIT_LIST_HEAD(&nsid->children);
+ INIT_LIST_HEAD(&nsid->siblings);
}
return nsid;
@@ -421,6 +424,8 @@ static unsigned int generate_ns_id(int pid, unsigned int kid, struct ns_desc *nd
nsid->type = type;
nsid->kid = kid;
nsid->ns_populated = true;
+ INIT_LIST_HEAD(&nsid->children);
+ INIT_LIST_HEAD(&nsid->siblings);
nsid_add(nsid, nd, ns_next_id++, pid);
found:
@@ -661,6 +666,83 @@ int dump_task_ns_ids(struct pstree_item *item)
return 0;
}
+static int set_ns_opt(int ns_fd, unsigned ioc, struct ns_id **ns, struct ns_desc *nd)
+{
+ int opt_fd, ret = -1;
+ struct stat st;
+
+ opt_fd = ioctl(ns_fd, ioc);
+ if (opt_fd < 0) {
+ pr_info("Can't do ns ioctl %x\n", ioc);
+ return -errno;
+ }
+ if (fstat(opt_fd, &st) < 0) {
+ pr_perror("Unable to stat on ns fd");
+ ret = -errno;
+ goto out;
+ }
+ *ns = lookup_ns_by_kid(st.st_ino, nd);
+ if (!*ns) {
+ pr_err("Namespaces hierarhies with holes are not supported\n");
+ ret = -EINVAL;
+ goto out;
+ }
+ ret = 0;
+out:
+ close(opt_fd);
+ return ret;
+}
+
+static int set_ns_hookups(struct ns_id *ns)
+{
+ struct ns_desc *nd = ns->nd;
+ struct ns_id *u_ns;
+ int fd, ret = -1;
+
+ fd = open_proc(ns->ns_pid, "ns/%s", nd->str);
+ if (fd < 0) {
+ pr_perror("Can't open %s, pid %d", nd->str, ns->ns_pid);
+ return -1;
+ }
+
+ if (ns->type != NS_ROOT && (nd == &pid_ns_desc || nd == &user_ns_desc)) {
+ if (set_ns_opt(fd, NS_GET_PARENT, &ns->parent, nd) < 0)
+ goto out;
+ if (ns->parent && ns->parent->type == NS_CRIU) {
+ pr_err("Wrong determined NS_ROOT, or root_item has NS_OTHER user_ns\n");
+ goto out;
+ }
+ list_add(&ns->siblings, &ns->parent->children);
+ }
+
+ if (nd != &user_ns_desc) {
+ ret = set_ns_opt(fd, NS_GET_USERNS, &ns->user_ns, &user_ns_desc);
+ if (ret == -ENOTTY) {
+ pr_info("Can't get user_ns of %s %u, assuming NS_ROOT\n",
+ nd->str, ns->id);
+ for (u_ns = ns_ids; u_ns; u_ns = u_ns->next) {
+ /*
+ * Find any user_ns. If there is a NS_OTHER one,
+ * we'll fail when we search its parent.
+ */
+ if (u_ns->nd == &user_ns_desc &&
+ (!(root_ns_mask & CLONE_NEWUSER) || u_ns->type == NS_ROOT))
+ break;
+ }
+ if (!u_ns) {
+ pr_err("Can't find root user_ns\n");
+ goto out;
+ }
+ ns->user_ns = u_ns;
+ } else if (ret < 0)
+ goto out;
+ }
+ ret = 0;
+out:
+ close(fd);
+ return ret;
+}
+
static UsernsEntry userns_entry = USERNS_ENTRY__INIT;
#define INVALID_ID (~0U)
More information about the CRIU
mailing list