linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
From: Pavel Emelyanov <xemul@parallels.com>
To: "Eric W. Biederman" <ebiederm@xmission.com>,
	Daniel Lezcano <dlezcano@fr.ibm.com>,
	Linux Kernel Mailing List <linux-kernel@vger.kernel.org>,
	"Serge E. Hallyn" <serge@hallyn.com>
Cc: Andrew Morton <akpm@linux-foundation.org>
Subject: [PATCH 1/2] proc: Show ns-based inode numbers for /proc/pid/ns/* files
Date: Fri, 11 May 2012 16:25:08 +0400	[thread overview]
Message-ID: <4FAD0524.3000307@parallels.com> (raw)

Some time ago we tried to expose kernel object IDs to the user space to
let it possible to detect shared mm, fs, etc. The namespaces' IDs were
included in this set and Eric proposed, that we'd better expose the ID
in the stat's st_ino field.

That's an implementation of this proposal. The proc_ns_operations is
equipped with the get_ns_id() callback, which should return some unique
ID of a namespace provided. This value is then mixed with the namespace's
type number to make the IDs truly unique.

For IPC and UTS namespaces these IDs are generated with sequentially
incremented 64-bit atomic number. For net namespace the ID is the ifindex
of the namespace's loopback device.

Signed-off-by: Pavel Emelyanov <xemul@parallels.com>
---
 fs/proc/namespaces.c          |   49 +++++++++++++++++++++++++++++++++++++++++
 include/linux/ipc_namespace.h |    1 +
 include/linux/proc_fs.h       |    1 +
 include/linux/utsname.h       |    1 +
 ipc/namespace.c               |   10 ++++++++
 kernel/utsname.c              |   11 +++++++++
 net/core/net_namespace.c      |    7 ++++++
 7 files changed, 80 insertions(+), 0 deletions(-)

diff --git a/fs/proc/namespaces.c b/fs/proc/namespaces.c
index 0d9e23a..b6c7560 100644
--- a/fs/proc/namespaces.c
+++ b/fs/proc/namespaces.c
@@ -30,6 +30,54 @@ static const struct file_operations ns_file_operations = {
 	.llseek		= no_llseek,
 };
 
+/*
+ * Namespaces IDs are generated by sequential increment of a
+ * static variable. Then the type value is mixed with it to make
+ * them unique. Thus, this salt value should never be overwritten
+ * by the ID. The 60 bits for constantly incrementing ID will
+ * overflow in 4k years, so it's big enough.
+ */
+
+#define NS_ID_SHIFT	(4)
+#define NS_BIT_MIN	(16)	/* to fit CLONE_NEWNS */
+
+static inline u64 ns_id_gen(u64 id, unsigned type)
+{
+	type = fls(type) - NS_BIT_MIN;
+	BUG_ON(type == 0 || (type >= (1 << NS_ID_SHIFT)));
+	return (id << NS_ID_SHIFT) | type;
+}
+
+static int proc_ns_getattr(struct vfsmount *mnt, struct dentry *dentry,
+		struct kstat *stat)
+{
+	int ret;
+
+	ret = pid_getattr(mnt, dentry, stat);
+	if (!ret) {
+		u64 ns_id = 0;
+		struct proc_inode *ei;
+		const struct proc_ns_operations *ops;
+
+		ei = PROC_I(dentry->d_inode);
+		ops = ei->ns_ops;
+		if (!ops || !ops->get_id)
+			printk("No OPS/ID for %p, %x, %s\n", ops, ops ? ops->type : -1,
+					dentry->d_name.name);
+		else {
+			ns_id = ops->get_id(ei->ns);
+			stat->ino = ns_id_gen(ns_id, ops->type);
+		}
+	}
+
+	return ret;
+}
+
+static const struct inode_operations ns_inode_operations = {
+	.getattr	= proc_ns_getattr,
+	.setattr	= proc_setattr,
+};
+
 static struct dentry *proc_ns_instantiate(struct inode *dir,
 	struct dentry *dentry, struct task_struct *task, const void *ptr)
 {
@@ -49,6 +97,7 @@ static struct dentry *proc_ns_instantiate(struct inode *dir,
 
 	ei = PROC_I(inode);
 	inode->i_mode = S_IFREG|S_IRUSR;
+	inode->i_op = &ns_inode_operations;
 	inode->i_fop  = &ns_file_operations;
 	ei->ns_ops    = ns_ops;
 	ei->ns	      = ns;
diff --git a/include/linux/ipc_namespace.h b/include/linux/ipc_namespace.h
index 8a297a5..e8c2dab 100644
--- a/include/linux/ipc_namespace.h
+++ b/include/linux/ipc_namespace.h
@@ -65,6 +65,7 @@ struct ipc_namespace {
 
 	/* user_ns which owns the ipc ns */
 	struct user_namespace *user_ns;
+	u64		id;
 };
 
 extern struct ipc_namespace init_ipc_ns;
diff --git a/include/linux/proc_fs.h b/include/linux/proc_fs.h
index 85c5073..e5ee83a 100644
--- a/include/linux/proc_fs.h
+++ b/include/linux/proc_fs.h
@@ -247,6 +247,7 @@ struct proc_ns_operations {
 	void *(*get)(struct task_struct *task);
 	void (*put)(void *ns);
 	int (*install)(struct nsproxy *nsproxy, void *ns);
+	u64 (*get_id)(void *ns);
 };
 extern const struct proc_ns_operations netns_operations;
 extern const struct proc_ns_operations utsns_operations;
diff --git a/include/linux/utsname.h b/include/linux/utsname.h
index c714ed7..5f7cdbb 100644
--- a/include/linux/utsname.h
+++ b/include/linux/utsname.h
@@ -52,6 +52,7 @@ struct uts_namespace {
 	struct kref kref;
 	struct new_utsname name;
 	struct user_namespace *user_ns;
+	u64 id;
 };
 extern struct uts_namespace init_uts_ns;
 
diff --git a/ipc/namespace.c b/ipc/namespace.c
index ce0a647..e837bd0 100644
--- a/ipc/namespace.c
+++ b/ipc/namespace.c
@@ -16,6 +16,8 @@
 
 #include "util.h"
 
+static atomic_long_t ipcns_id = ATOMIC_LONG_INIT(0);
+
 static struct ipc_namespace *create_ipc_ns(struct task_struct *tsk,
 					   struct ipc_namespace *old_ns)
 {
@@ -47,6 +49,7 @@ static struct ipc_namespace *create_ipc_ns(struct task_struct *tsk,
 	register_ipcns_notifier(ns);
 
 	ns->user_ns = get_user_ns(task_cred_xxx(tsk, user)->user_ns);
+	ns->id = atomic_long_inc_return(&ipcns_id);
 
 	return ns;
 }
@@ -170,10 +173,17 @@ static int ipcns_install(struct nsproxy *nsproxy, void *ns)
 	return 0;
 }
 
+static u64 ipcns_get_id(void *_ns)
+{
+	struct ipc_namespace *ns = _ns;
+	return ns->id;
+}
+
 const struct proc_ns_operations ipcns_operations = {
 	.name		= "ipc",
 	.type		= CLONE_NEWIPC,
 	.get		= ipcns_get,
 	.put		= ipcns_put,
 	.install	= ipcns_install,
+	.get_id		= ipcns_get_id,
 };
diff --git a/kernel/utsname.c b/kernel/utsname.c
index 405caf9..cba6ad3 100644
--- a/kernel/utsname.c
+++ b/kernel/utsname.c
@@ -17,6 +17,8 @@
 #include <linux/user_namespace.h>
 #include <linux/proc_fs.h>
 
+static atomic_long_t utsns_id = ATOMIC_LONG_INIT(0);
+
 static struct uts_namespace *create_uts_ns(void)
 {
 	struct uts_namespace *uts_ns;
@@ -45,6 +47,8 @@ static struct uts_namespace *clone_uts_ns(struct task_struct *tsk,
 	memcpy(&ns->name, &old_ns->name, sizeof(ns->name));
 	ns->user_ns = get_user_ns(task_cred_xxx(tsk, user)->user_ns);
 	up_read(&uts_sem);
+	ns->id = atomic_long_inc_return(&utsns_id);
+
 	return ns;
 }
 
@@ -110,11 +114,18 @@ static int utsns_install(struct nsproxy *nsproxy, void *ns)
 	return 0;
 }
 
+static u64 utsns_get_id(void *_ns)
+{
+	struct uts_namespace *ns = _ns;
+	return ns->id;
+}
+
 const struct proc_ns_operations utsns_operations = {
 	.name		= "uts",
 	.type		= CLONE_NEWUTS,
 	.get		= utsns_get,
 	.put		= utsns_put,
 	.install	= utsns_install,
+	.get_id		= utsns_get_id,
 };
 
diff --git a/net/core/net_namespace.c b/net/core/net_namespace.c
index 0e950fd..6611433 100644
--- a/net/core/net_namespace.c
+++ b/net/core/net_namespace.c
@@ -627,11 +627,18 @@ static int netns_install(struct nsproxy *nsproxy, void *ns)
 	return 0;
 }
 
+static u64 netns_get_id(void *_ns)
+{
+	struct net *ns = _ns;
+	return ns->loopback_dev->ifindex;
+}
+
 const struct proc_ns_operations netns_operations = {
 	.name		= "net",
 	.type		= CLONE_NEWNET,
 	.get		= netns_get,
 	.put		= netns_put,
 	.install	= netns_install,
+	.get_id		= netns_get_id,
 };
 #endif
-- 
1.7.6.5

             reply	other threads:[~2012-05-11 12:25 UTC|newest]

Thread overview: 10+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2012-05-11 12:25 Pavel Emelyanov [this message]
2012-05-11 12:25 ` [PATCH 2/2] ns: Add proc_ns_operations for mount namespaces Pavel Emelyanov
2012-05-11 17:05   ` Eric W. Biederman
2012-05-12 11:42     ` Pavel Emelyanov
     [not found]   ` <87mx5e5tho.fsf_-_@xmission.com>
2012-05-12 11:41     ` [PATCH] vfs: Add setns support for the mount namespace Pavel Emelyanov
2012-05-18 19:44       ` Serge E. Hallyn
2012-05-18 22:47         ` Eric W. Biederman
2012-05-11 17:07 ` [PATCH 1/2] proc: Show ns-based inode numbers for /proc/pid/ns/* files Eric W. Biederman
2012-05-12 11:40   ` Pavel Emelyanov
2012-05-26 15:14     ` Eric W. Biederman

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=4FAD0524.3000307@parallels.com \
    --to=xemul@parallels.com \
    --cc=akpm@linux-foundation.org \
    --cc=dlezcano@fr.ibm.com \
    --cc=ebiederm@xmission.com \
    --cc=linux-kernel@vger.kernel.org \
    --cc=serge@hallyn.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).