All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH] netns: add /proc/*/net/id symlink
@ 2011-05-21  9:39 Alexey Dobriyan
  2011-05-21 15:39 ` Eric W. Biederman
  0 siblings, 1 reply; 15+ messages in thread
From: Alexey Dobriyan @ 2011-05-21  9:39 UTC (permalink / raw)
  To: davem; +Cc: netdev, ebiederm, equinox

David Lamparter pointed some real scenarios where knowing
if two processes live in same netns is important,
like "how do I kill _all_ processes in netns to shutdown it".

Currently only kernel knows if two netns are the same.
Userspace maybe can look at different proc files to find a match
indirectly sysconf-style but result will be ugly no matter what.

Add /proc/*/net/id symlink which "points" to an integer.

	$ readlink /proc/net/id
	0

	$ readlink /proc/2941/net/id
	1

"id" is not a file because 1 syscall is faster than 3 syscalls.

The only rules and expectations for userspace are:
[as if they will comply, ha-ha]

* init_net always has id 0
* two netns do not have same id
* id is unsigned integer

Kernel code continues to use net_eq(), there is no need
to compare net->id inside kernel, because it is slower than net_eq().

Signed-off-by: Alexey Dobriyan <adobriyan@gmail.com>
---

 fs/proc/generic.c           |   16 +++++++++++++
 fs/proc/proc_net.c          |   31 ++++++++++++++++++++++++-
 include/linux/proc_fs.h     |    7 +++++
 include/net/net_namespace.h |   10 ++++++++
 net/core/net_namespace.c    |   54 ++++++++++++++++++++++++++++++++++++++++++++
 5 files changed, 117 insertions(+), 1 deletion(-)

--- a/fs/proc/generic.c
+++ b/fs/proc/generic.c
@@ -660,6 +660,22 @@ struct proc_dir_entry *proc_symlink(const char *name,
 }
 EXPORT_SYMBOL(proc_symlink);
 
+struct proc_dir_entry *_proc_symlink(const char *name, struct proc_dir_entry *parent, const struct inode_operations *proc_iops)
+{
+	struct proc_dir_entry *pde;
+
+	pde = __proc_create(&parent, name, S_IFLNK | S_IRUGO|S_IWUGO|S_IXUGO, 1);
+	if (!pde)
+		return NULL;
+	pde->proc_iops = proc_iops;
+	pde->data = NULL;
+	if (proc_register(parent, pde) < 0) {
+		kfree(pde);
+		return NULL;
+	}
+	return pde;
+}
+
 struct proc_dir_entry *proc_mkdir_mode(const char *name, mode_t mode,
 		struct proc_dir_entry *parent)
 {
--- a/fs/proc/proc_net.c
+++ b/fs/proc/proc_net.c
@@ -191,9 +191,30 @@ void proc_net_remove(struct net *net, const char *name)
 }
 EXPORT_SYMBOL_GPL(proc_net_remove);
 
+static int net_id_readlink(struct dentry *dentry, char __user *buf, int buflen)
+{
+	struct net *net;
+	char kbuf[42];
+	int len;
+
+	net = get_proc_net(dentry->d_inode);
+	if (!net)
+		return -ENXIO;
+	len = snprintf(kbuf, sizeof(kbuf), "%u", net->id);
+	put_net(net);
+	len = min(len, buflen);
+	if (copy_to_user(buf, kbuf, len))
+		return -EFAULT;
+	return len;
+}
+
+static const struct inode_operations net_id_proc_iops = {
+	.readlink	= net_id_readlink,
+};
+
 static __net_init int proc_net_ns_init(struct net *net)
 {
-	struct proc_dir_entry *netd, *net_statd;
+	struct proc_dir_entry *netd, *net_statd, *pde;
 	int err;
 
 	err = -ENOMEM;
@@ -214,8 +235,15 @@ static __net_init int proc_net_ns_init(struct net *net)
 
 	net->proc_net = netd;
 	net->proc_net_stat = net_statd;
+
+	pde = _proc_symlink("id", net->proc_net, &net_id_proc_iops);
+	if (!pde)
+		goto free_net_stat;
+
 	return 0;
 
+free_net_stat:
+	kfree(net_statd);
 free_net:
 	kfree(netd);
 out:
@@ -224,6 +252,7 @@ out:
 
 static __net_exit void proc_net_ns_exit(struct net *net)
 {
+	remove_proc_entry("id", net->proc_net);
 	remove_proc_entry("stat", net->proc_net);
 	kfree(net->proc_net);
 }
--- a/include/linux/proc_fs.h
+++ b/include/linux/proc_fs.h
@@ -143,6 +143,7 @@ extern void proc_device_tree_update_prop(struct proc_dir_entry *pde,
 					 struct property *oldprop);
 #endif /* CONFIG_PROC_DEVICETREE */
 
+struct proc_dir_entry *_proc_symlink(const char *name, struct proc_dir_entry *parent, const struct inode_operations *proc_iops);
 extern struct proc_dir_entry *proc_symlink(const char *,
 		struct proc_dir_entry *, const char *);
 extern struct proc_dir_entry *proc_mkdir(const char *,struct proc_dir_entry *);
@@ -204,8 +205,14 @@ static inline struct proc_dir_entry *proc_create_data(const char *name,
 }
 #define remove_proc_entry(name, parent) do {} while (0)
 
+static inline struct proc_dir_entry *_proc_symlink(const char *name, struct proc_dir_entry *parent, const struct inode_operations *proc_iops)
+{
+	return NULL;
+}
+
 static inline struct proc_dir_entry *proc_symlink(const char *name,
 		struct proc_dir_entry *parent,const char *dest) {return NULL;}
+
 static inline struct proc_dir_entry *proc_mkdir(const char *name,
 	struct proc_dir_entry *parent) {return NULL;}
 static inline struct proc_dir_entry *proc_mkdir_mode(const char *name,
--- a/include/net/net_namespace.h
+++ b/include/net/net_namespace.h
@@ -96,6 +96,16 @@ struct net {
 	struct netns_xfrm	xfrm;
 #endif
 	struct netns_ipvs	*ipvs;
+
+	/*
+	 * netns unique id solely for userspace consumption,
+	 * see /proc/net/id symlink.
+	 *
+	 * init_net has id 0.
+	 *
+	 * Write-once field.
+	 */
+	unsigned int		id;
 };
 
 
--- a/net/core/net_namespace.c
+++ b/net/core/net_namespace.c
@@ -115,6 +115,52 @@ static void ops_free_list(const struct pernet_operations *ops,
 	}
 }
 
+#ifdef CONFIG_NET_NS
+static DEFINE_IDA(net_id_ida);
+static DEFINE_SPINLOCK(net_id_ida_lock);
+
+static int __net_init set_net_id(struct net *net)
+{
+	int id;
+
+	if (net_eq(net, &init_net)) {
+		id = 0;
+	} else {
+		int rv;
+
+		do {
+			if (ida_pre_get(&net_id_ida, GFP_KERNEL) == 0)
+				return -ENOMEM;
+			spin_lock(&net_id_ida_lock);
+			/* init_net has id 0 */
+			rv = ida_get_new_above(&net_id_ida, 1, &id);
+			spin_unlock(&net_id_ida_lock);
+		} while (rv == -EAGAIN);
+		if (rv < 0)
+			return rv;
+	}
+	net->id = id;
+	return 0;
+}
+
+static void free_net_id(struct net *net)
+{
+	spin_lock(&net_id_ida_lock);
+	ida_remove(&net_id_ida, net->id);
+	spin_unlock(&net_id_ida_lock);
+}
+#else
+static inline int set_net_id(struct net *net)
+{
+	net->id = 0;
+	return 0;
+}
+
+static inline void free_net_id(struct net *net)
+{
+}
+#endif
+
 /*
  * setup_net runs the initializers for the network namespace object.
  */
@@ -131,6 +177,10 @@ static __net_init int setup_net(struct net *net)
 	atomic_set(&net->use_count, 0);
 #endif
 
+	error = set_net_id(net);
+	if (error < 0)
+		goto out;
+
 	list_for_each_entry(ops, &pernet_list, list) {
 		error = ops_init(ops, net);
 		if (error < 0)
@@ -140,6 +190,8 @@ out:
 	return error;
 
 out_undo:
+	free_net_id(net);
+
 	/* Walk through the list backwards calling the exit functions
 	 * for the pernet modules whose init functions did not fail.
 	 */
@@ -204,6 +256,8 @@ static void net_free(struct net *net)
 		return;
 	}
 #endif
+
+	free_net_id(net);
 	kfree(net->gen);
 	kmem_cache_free(net_cachep, net);
 }

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [PATCH] netns: add /proc/*/net/id symlink
  2011-05-21  9:39 [PATCH] netns: add /proc/*/net/id symlink Alexey Dobriyan
@ 2011-05-21 15:39 ` Eric W. Biederman
  2011-05-21 22:30   ` Alexey Dobriyan
  0 siblings, 1 reply; 15+ messages in thread
From: Eric W. Biederman @ 2011-05-21 15:39 UTC (permalink / raw)
  To: Alexey Dobriyan; +Cc: davem, netdev, equinox

Alexey Dobriyan <adobriyan@gmail.com> writes:

> David Lamparter pointed some real scenarios where knowing
> if two processes live in same netns is important,
> like "how do I kill _all_ processes in netns to shutdown it".

Currently today the way I do this is md5sum /proc/<pid>/mounts.

That works because it is usually necessary to have a separate mount
namespace with a separate set of mounts to accommodate sysfs.

> Currently only kernel knows if two netns are the same.
> Userspace maybe can look at different proc files to find a match
> indirectly sysconf-style but result will be ugly no matter what.

Somewhat. 

Right now today without patches if we limit ourselves to the network
namespace there is a pretty valid way to do this.

stat /proc/<pid>/net/dev and compare the inode numbers.

Or any other file in /proc/*/net/.  The inode numbers are the
same if you are in the same network namespace.

> Add /proc/*/net/id symlink which "points" to an integer.
>
> 	$ readlink /proc/net/id
> 	0
>
> 	$ readlink /proc/2941/net/id
> 	1
>
> "id" is not a file because 1 syscall is faster than 3 syscalls.
>
> The only rules and expectations for userspace are:
> [as if they will comply, ha-ha]
>
> * init_net always has id 0
> * two netns do not have same id
> * id is unsigned integer

I don't like this patch because we already have a proc interface
that already solves this in production kernels today.

- stat is a single syscall
- two netns do not have the same id
- id is an ino_t.

Now it probably needs to be better documented that /proc/*/net/*
have the same inode number if the network namespace is the
same, as everyone including myself overlooked this very handy
existing property.




Writing this it occurs to me there is a misfeature in my pending
namespace file descriptor code.  Right now /proc/<pid>/ns/net
has a floating inode number and it would be good if I could make
that a inode number be the same for every file that refers to
the same network namespace. Ugh.

Eric


^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [PATCH] netns: add /proc/*/net/id symlink
  2011-05-21 15:39 ` Eric W. Biederman
@ 2011-05-21 22:30   ` Alexey Dobriyan
  2011-05-22  0:15     ` Eric W. Biederman
  0 siblings, 1 reply; 15+ messages in thread
From: Alexey Dobriyan @ 2011-05-21 22:30 UTC (permalink / raw)
  To: Eric W. Biederman; +Cc: davem, netdev, equinox

On Sat, May 21, 2011 at 08:39:37AM -0700, Eric W. Biederman wrote:
> Alexey Dobriyan <adobriyan@gmail.com> writes:
> > * init_net always has id 0
> > * two netns do not have same id
> > * id is unsigned integer
> 
> I don't like this patch because we already have a proc interface
> that already solves this in production kernels today.
> 
> - stat is a single syscall
> - two netns do not have the same id
> - id is an ino_t.

Yeah, stat /proc/*/net/dev works.
If you document this, it means we can't change the way ->low_ino is set.
And we can't do other things inside irregular part of procfs.

But can we add clean interface once in a while.

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [PATCH] netns: add /proc/*/net/id symlink
  2011-05-21 22:30   ` Alexey Dobriyan
@ 2011-05-22  0:15     ` Eric W. Biederman
  2011-05-23  1:43       ` David Lamparter
  0 siblings, 1 reply; 15+ messages in thread
From: Eric W. Biederman @ 2011-05-22  0:15 UTC (permalink / raw)
  To: Alexey Dobriyan; +Cc: davem, netdev, equinox, Linux Containers


Adding the containers list.

Alexey Dobriyan <adobriyan@gmail.com> writes:

> On Sat, May 21, 2011 at 08:39:37AM -0700, Eric W. Biederman wrote:
>> Alexey Dobriyan <adobriyan@gmail.com> writes:
>> > * init_net always has id 0
>> > * two netns do not have same id
>> > * id is unsigned integer
>> 
>> I don't like this patch because we already have a proc interface
>> that already solves this in production kernels today.
>> 
>> - stat is a single syscall
>> - two netns do not have the same id
>> - id is an ino_t.
>
> Yeah, stat /proc/*/net/dev works.
> If you document this, it means we can't change the way ->low_ino is set.
> And we can't do other things inside irregular part of procfs.

Maybe.  Certainly there are things that would suggest we need some
fixes to this part of procfs.

> But can we add clean interface once in a while.

I am all for making a clean solution.  I don't see a proc file
in in /proc/net that provides a small integer as particularly clean.

It has the classic problem of what namespace are namespaces named in.
It only solves the problem for the network namespace.

So on that level I really like the idea of inode numbers in proc
being the place where we have a name.  People generally don't get
confused about inode numbers understanding they are an implementation
detail but they do understand that inode numbers plus filesystem
information can be used to compare files for identity.

So let's skip the fact that /proc/*/net/dev happens to work for a
moment.

For clean interfaces I am in the process of adding /proc/<pid>/ns/net,
/proc/<pid>/ns/ipc, and /proc/<pid>/ns/uts.

If we can make those files inode number be the same if the namespace is
the same like /proc/<pid>/net/dev is today.  I think we will have a
clean solution.

Additionally that solution will work for comparing network namespaces
that don't happen to have any processes in them at the moment.  Because
fstat works on file descriptors.

With the /proc/<pid>/ns/net file and bind mounts I have solved the
deeper problem of how do we get userspace policy into the naming of
namespaces.  With those files and the setns system call I have solved
the other problem of what is a good way to refer to namespaces without
assuming a global name.  So once those changes are merged I expect there
to be much less pressure to misuse any kind of identifier we can have.

And if we only make the guarantee about inode consistency for the
/proc/<pid>/ns/FILE files I don't expect it will make maintenance
of procfs any harder than it already is.

Eric


^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [PATCH] netns: add /proc/*/net/id symlink
  2011-05-22  0:15     ` Eric W. Biederman
@ 2011-05-23  1:43       ` David Lamparter
  2011-05-23  1:47         ` David Lamparter
  2011-05-23  2:02         ` [PATCH] netns: add /proc/*/net/id symlink Eric W. Biederman
  0 siblings, 2 replies; 15+ messages in thread
From: David Lamparter @ 2011-05-23  1:43 UTC (permalink / raw)
  To: Eric W. Biederman
  Cc: Alexey Dobriyan, davem, netdev, equinox, Linux Containers

> ... Eric W. Biederman wrote:
> Now it probably needs to be better documented that /proc/*/net/*
> have the same inode number if the network namespace is the
> same, as everyone including myself overlooked this very handy
> existing property.

Eh, so did I. But, yes, very nice.

On Sat, May 21, 2011 at 05:15:38PM -0700, Eric W. Biederman wrote:
> Additionally that solution will work for comparing network namespaces
> that don't happen to have any processes in them at the moment.  Because
> fstat works on file descriptors.

Hm. I have a peeve here. Assume I am a... rogue admin, whatever. I have
root on a router. I create a new network namespace, put a macvlan of
eth0 in it and a macvlan of eth1. I enable ip_forward.

Then I make a mount namespace, bind-mount the net namespace, bind mount
the mount namespace and terminate all processes that reference it (yes
this does work, i just checked [!]).

Now I can use it to bypass all firewall rules, IDS, whatever.

How is any normal admin, monitoring script or whatever else able to
detect this?

> With the /proc/<pid>/ns/net file and bind mounts I have solved the
> deeper problem of how do we get userspace policy into the naming of
> namespaces.  With those files and the setns system call I have solved
> the other problem of what is a good way to refer to namespaces without
> assuming a global name.  So once those changes are merged I expect there
> to be much less pressure to misuse any kind of identifier we can have.
> 
> And if we only make the guarantee about inode consistency for the
> /proc/<pid>/ns/FILE files I don't expect it will make maintenance
> of procfs any harder than it already is.


-David


^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [PATCH] netns: add /proc/*/net/id symlink
  2011-05-23  1:43       ` David Lamparter
@ 2011-05-23  1:47         ` David Lamparter
  2011-06-17 23:31             ` Eric W. Biederman
  2011-05-23  2:02         ` [PATCH] netns: add /proc/*/net/id symlink Eric W. Biederman
  1 sibling, 1 reply; 15+ messages in thread
From: David Lamparter @ 2011-05-23  1:47 UTC (permalink / raw)
  To: David Lamparter
  Cc: Eric W. Biederman, Alexey Dobriyan, davem, netdev, Linux Containers

On Mon, May 23, 2011 at 03:43:03AM +0200, David Lamparter wrote:
> Then I make a mount namespace, bind-mount the net namespace, bind mount
> the mount namespace and terminate all processes that reference it (yes
> this does work, i just checked [!]).

Actually, Eric, bind-mounting a mount namespace inside itself should
probably be forbidden? No idea if you changed that (running a year-old
version of your patches here). Not only can you lose network namespaces
inside those self-referential mount namespaces but also references to
block devices, unix socket connections, etc. pp.


-David


^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [PATCH] netns: add /proc/*/net/id symlink
  2011-05-23  1:43       ` David Lamparter
  2011-05-23  1:47         ` David Lamparter
@ 2011-05-23  2:02         ` Eric W. Biederman
  1 sibling, 0 replies; 15+ messages in thread
From: Eric W. Biederman @ 2011-05-23  2:02 UTC (permalink / raw)
  To: David Lamparter; +Cc: Alexey Dobriyan, davem, netdev, Linux Containers

David Lamparter <equinox@diac24.net> writes:

>> ... Eric W. Biederman wrote:
>> Now it probably needs to be better documented that /proc/*/net/*
>> have the same inode number if the network namespace is the
>> same, as everyone including myself overlooked this very handy
>> existing property.
>
> Eh, so did I. But, yes, very nice.
>
> On Sat, May 21, 2011 at 05:15:38PM -0700, Eric W. Biederman wrote:
>> Additionally that solution will work for comparing network namespaces
>> that don't happen to have any processes in them at the moment.  Because
>> fstat works on file descriptors.
>
> Hm. I have a peeve here. Assume I am a... rogue admin, whatever. I have
> root on a router. I create a new network namespace, put a macvlan of
> eth0 in it and a macvlan of eth1. I enable ip_forward.
>
> Then I make a mount namespace, bind-mount the net namespace, bind mount
> the mount namespace and terminate all processes that reference it (yes
> this does work, i just checked [!]).

You must be using an older version of my patchset than what I have
queued for Linus.  Bind mounting the mount namepsace and creating
reference counting loops is a weird and ugly case.  So for the moment I
am not supporting the mount namespace, until I can think through
the consequences.

> Now I can use it to bypass all firewall rules, IDS, whatever.
>
> How is any normal admin, monitoring script or whatever else able to
> detect this?

Which is why we I proceed slowly and cautiously with adding new kernel
interfaces.  It is hard to think of everything until you can actually
put it into use, and play with it.

Other than not allowing bind mounting the mount namespace I don't
have any all encompassing really good answers at the moment.

I do have a few small answers.  For network namespaces you can look in
/proc/slabinfo and see how many you have, unless slub is lying to you.
On the switch your server is connected to you can look at the mac table
and see which mac addresses are currently in use, and notice if there
are unaccounted for mac addresses.

Eric

^ permalink raw reply	[flat|nested] 15+ messages in thread

* [PATCH 1/2] proc: Generalize proc inode allocation
  2011-05-23  1:47         ` David Lamparter
@ 2011-06-17 23:31             ` Eric W. Biederman
  0 siblings, 0 replies; 15+ messages in thread
From: Eric W. Biederman @ 2011-06-17 23:31 UTC (permalink / raw)
  To: Linux Containers
  Cc: Alexey Dobriyan, netdev, David Lamparter, linux-kernel, Serge E. Hallyn


Generalize the proc inode allocation so that it can be
used without having to having to create a proc_dir_entry.

This will allow namespace file descriptors to remain light
weight entitities but still have the same inode number
when the backing namespace is the same.

Signed-off-by: Eric W. Biederman <ebiederm@xmission.com>
---

Baring problems in review I plan to merge these patches
via my linux-2.6-nsfd tree.

 fs/proc/generic.c       |   26 +++++++++++++-------------
 include/linux/proc_fs.h |   10 ++++++++++
 2 files changed, 23 insertions(+), 13 deletions(-)

diff --git a/fs/proc/generic.c b/fs/proc/generic.c
index f1637f1..65416a1 100644
--- a/fs/proc/generic.c
+++ b/fs/proc/generic.c
@@ -350,14 +350,14 @@ static DEFINE_SPINLOCK(proc_inum_lock); /* protects the above */
  * Return an inode number between PROC_DYNAMIC_FIRST and
  * 0xffffffff, or zero on failure.
  */
-static unsigned int get_inode_number(void)
+int proc_alloc_inum(unsigned int *inum)
 {
 	unsigned int i;
 	int error;
 
 retry:
-	if (ida_pre_get(&proc_inum_ida, GFP_KERNEL) == 0)
-		return 0;
+	if (!ida_pre_get(&proc_inum_ida, GFP_KERNEL))
+		return -ENOMEM;
 
 	spin_lock(&proc_inum_lock);
 	error = ida_get_new(&proc_inum_ida, &i);
@@ -365,18 +365,19 @@ retry:
 	if (error == -EAGAIN)
 		goto retry;
 	else if (error)
-		return 0;
+		return error;
 
 	if (i > UINT_MAX - PROC_DYNAMIC_FIRST) {
 		spin_lock(&proc_inum_lock);
 		ida_remove(&proc_inum_ida, i);
 		spin_unlock(&proc_inum_lock);
-		return 0;
+		return -ENOSPC;
 	}
-	return PROC_DYNAMIC_FIRST + i;
+	*inum = PROC_DYNAMIC_FIRST + i;
+	return 0;
 }
 
-static void release_inode_number(unsigned int inum)
+void proc_free_inum(unsigned int inum)
 {
 	spin_lock(&proc_inum_lock);
 	ida_remove(&proc_inum_ida, inum - PROC_DYNAMIC_FIRST);
@@ -554,13 +555,12 @@ static const struct inode_operations proc_dir_inode_operations = {
 
 static int proc_register(struct proc_dir_entry * dir, struct proc_dir_entry * dp)
 {
-	unsigned int i;
 	struct proc_dir_entry *tmp;
+	int ret;
 	
-	i = get_inode_number();
-	if (i == 0)
-		return -EAGAIN;
-	dp->low_ino = i;
+	ret = proc_alloc_inum(&dp->low_ino);
+	if (ret)
+		return ret;
 
 	if (S_ISDIR(dp->mode)) {
 		if (dp->proc_iops == NULL) {
@@ -766,7 +766,7 @@ EXPORT_SYMBOL(proc_create_data);
 
 static void free_proc_entry(struct proc_dir_entry *de)
 {
-	release_inode_number(de->low_ino);
+	proc_free_inum(de->low_ino);
 
 	if (S_ISLNK(de->mode))
 		kfree(de->data);
diff --git a/include/linux/proc_fs.h b/include/linux/proc_fs.h
index e7576cf..3067b44 100644
--- a/include/linux/proc_fs.h
+++ b/include/linux/proc_fs.h
@@ -175,6 +175,8 @@ extern struct proc_dir_entry *proc_net_mkdir(struct net *net, const char *name,
 
 extern struct file *proc_ns_fget(int fd);
 
+extern int proc_alloc_inum(unsigned int *pino);
+extern void proc_free_inum(unsigned int inum);
 #else
 
 #define proc_net_fops_create(net, name, mode, fops)  ({ (void)(mode), NULL; })
@@ -229,6 +231,14 @@ static inline struct file *proc_ns_fget(int fd)
 	return ERR_PTR(-EINVAL);
 }
 
+static inline int proc_alloc_inum(unsigned int *inum)
+{
+	*inum = 1;
+	return 0;
+}
+static inline void proc_free_inum(unsigned int inum)
+{
+}
 #endif /* CONFIG_PROC_FS */
 
 #if !defined(CONFIG_PROC_KCORE)
-- 
1.7.5.1.217.g4e3aa


^ permalink raw reply related	[flat|nested] 15+ messages in thread

* [PATCH 1/2] proc: Generalize proc inode allocation
@ 2011-06-17 23:31             ` Eric W. Biederman
  0 siblings, 0 replies; 15+ messages in thread
From: Eric W. Biederman @ 2011-06-17 23:31 UTC (permalink / raw)
  To: Linux Containers
  Cc: Alexey Dobriyan, netdev, David Lamparter, linux-kernel, Serge E. Hallyn


Generalize the proc inode allocation so that it can be
used without having to having to create a proc_dir_entry.

This will allow namespace file descriptors to remain light
weight entitities but still have the same inode number
when the backing namespace is the same.

Signed-off-by: Eric W. Biederman <ebiederm@xmission.com>
---

Baring problems in review I plan to merge these patches
via my linux-2.6-nsfd tree.

 fs/proc/generic.c       |   26 +++++++++++++-------------
 include/linux/proc_fs.h |   10 ++++++++++
 2 files changed, 23 insertions(+), 13 deletions(-)

diff --git a/fs/proc/generic.c b/fs/proc/generic.c
index f1637f1..65416a1 100644
--- a/fs/proc/generic.c
+++ b/fs/proc/generic.c
@@ -350,14 +350,14 @@ static DEFINE_SPINLOCK(proc_inum_lock); /* protects the above */
  * Return an inode number between PROC_DYNAMIC_FIRST and
  * 0xffffffff, or zero on failure.
  */
-static unsigned int get_inode_number(void)
+int proc_alloc_inum(unsigned int *inum)
 {
 	unsigned int i;
 	int error;
 
 retry:
-	if (ida_pre_get(&proc_inum_ida, GFP_KERNEL) == 0)
-		return 0;
+	if (!ida_pre_get(&proc_inum_ida, GFP_KERNEL))
+		return -ENOMEM;
 
 	spin_lock(&proc_inum_lock);
 	error = ida_get_new(&proc_inum_ida, &i);
@@ -365,18 +365,19 @@ retry:
 	if (error == -EAGAIN)
 		goto retry;
 	else if (error)
-		return 0;
+		return error;
 
 	if (i > UINT_MAX - PROC_DYNAMIC_FIRST) {
 		spin_lock(&proc_inum_lock);
 		ida_remove(&proc_inum_ida, i);
 		spin_unlock(&proc_inum_lock);
-		return 0;
+		return -ENOSPC;
 	}
-	return PROC_DYNAMIC_FIRST + i;
+	*inum = PROC_DYNAMIC_FIRST + i;
+	return 0;
 }
 
-static void release_inode_number(unsigned int inum)
+void proc_free_inum(unsigned int inum)
 {
 	spin_lock(&proc_inum_lock);
 	ida_remove(&proc_inum_ida, inum - PROC_DYNAMIC_FIRST);
@@ -554,13 +555,12 @@ static const struct inode_operations proc_dir_inode_operations = {
 
 static int proc_register(struct proc_dir_entry * dir, struct proc_dir_entry * dp)
 {
-	unsigned int i;
 	struct proc_dir_entry *tmp;
+	int ret;
 	
-	i = get_inode_number();
-	if (i == 0)
-		return -EAGAIN;
-	dp->low_ino = i;
+	ret = proc_alloc_inum(&dp->low_ino);
+	if (ret)
+		return ret;
 
 	if (S_ISDIR(dp->mode)) {
 		if (dp->proc_iops == NULL) {
@@ -766,7 +766,7 @@ EXPORT_SYMBOL(proc_create_data);
 
 static void free_proc_entry(struct proc_dir_entry *de)
 {
-	release_inode_number(de->low_ino);
+	proc_free_inum(de->low_ino);
 
 	if (S_ISLNK(de->mode))
 		kfree(de->data);
diff --git a/include/linux/proc_fs.h b/include/linux/proc_fs.h
index e7576cf..3067b44 100644
--- a/include/linux/proc_fs.h
+++ b/include/linux/proc_fs.h
@@ -175,6 +175,8 @@ extern struct proc_dir_entry *proc_net_mkdir(struct net *net, const char *name,
 
 extern struct file *proc_ns_fget(int fd);
 
+extern int proc_alloc_inum(unsigned int *pino);
+extern void proc_free_inum(unsigned int inum);
 #else
 
 #define proc_net_fops_create(net, name, mode, fops)  ({ (void)(mode), NULL; })
@@ -229,6 +231,14 @@ static inline struct file *proc_ns_fget(int fd)
 	return ERR_PTR(-EINVAL);
 }
 
+static inline int proc_alloc_inum(unsigned int *inum)
+{
+	*inum = 1;
+	return 0;
+}
+static inline void proc_free_inum(unsigned int inum)
+{
+}
 #endif /* CONFIG_PROC_FS */
 
 #if !defined(CONFIG_PROC_KCORE)
-- 
1.7.5.1.217.g4e3aa


^ permalink raw reply related	[flat|nested] 15+ messages in thread

* [PATCH 2/2] proc: Usable inode numbers for the namespace file descriptors.
  2011-06-17 23:31             ` Eric W. Biederman
@ 2011-06-17 23:33               ` Eric W. Biederman
  -1 siblings, 0 replies; 15+ messages in thread
From: Eric W. Biederman @ 2011-06-17 23:33 UTC (permalink / raw)
  To: Linux Containers
  Cc: Alexey Dobriyan, netdev, David Lamparter, linux-kernel, Serge E. Hallyn


Assign a unique proc inode to each namespace, yielding an
identifier that userspace can use for identifying a namespace.

This has been a long requested feature and only blocked because
a naive implementation would put the id in a global space and
would ultimately require having a namespace for the names of
namespaces, making migration and certain virtualization tricks
impossible.

We still don't have per superblock inode numbers for proc, which
appears necessary for application unaware checkpoint/restart and
migrations (if the application is using namespace filedescriptors)
but that is now allowd by the design if it becomes important.

I have preallocated the ipc and uts initial proc inode numbers so
their structures can be statically initialized.

Signed-off-by: Eric W. Biederman <ebiederm@xmission.com>
---
 fs/proc/namespaces.c          |    1 +
 include/linux/ipc_namespace.h |    2 ++
 include/linux/proc_fs.h       |    4 ++++
 include/linux/utsname.h       |    1 +
 include/net/net_namespace.h   |    2 ++
 init/version.c                |    2 ++
 ipc/msgutil.c                 |    2 ++
 ipc/namespace.c               |   16 ++++++++++++++++
 kernel/utsname.c              |   17 ++++++++++++++++-
 net/core/net_namespace.c      |   24 ++++++++++++++++++++++++
 10 files changed, 70 insertions(+), 1 deletions(-)

diff --git a/fs/proc/namespaces.c b/fs/proc/namespaces.c
index be177f7..ddc2bb4 100644
--- a/fs/proc/namespaces.c
+++ b/fs/proc/namespaces.c
@@ -54,6 +54,7 @@ static struct dentry *proc_ns_instantiate(struct inode *dir,
 	ei->ns_ops    = ns_ops;
 	ei->ns	      = ns;
 
+	inode->i_ino = ns_ops->inum(ei->ns);
 	dentry->d_op = &pid_dentry_operations;
 	d_add(dentry, inode);
 	/* Close the race of the process dying before we return the dentry */
diff --git a/include/linux/ipc_namespace.h b/include/linux/ipc_namespace.h
index a6d1655..22a4dc4 100644
--- a/include/linux/ipc_namespace.h
+++ b/include/linux/ipc_namespace.h
@@ -60,6 +60,8 @@ struct ipc_namespace {
 
 	/* user_ns which owns the ipc ns */
 	struct user_namespace *user_ns;
+
+	unsigned int	proc_inum;
 };
 
 extern struct ipc_namespace init_ipc_ns;
diff --git a/include/linux/proc_fs.h b/include/linux/proc_fs.h
index 3067b44..1aee7f0 100644
--- a/include/linux/proc_fs.h
+++ b/include/linux/proc_fs.h
@@ -29,8 +29,11 @@ struct mm_struct;
 
 enum {
 	PROC_ROOT_INO = 1,
+	PROC_IPC_INIT_INO = 2,
+	PROC_UTS_INIT_INO = 3,
 };
 
+
 /*
  * This is not completely implemented yet. The idea is to
  * create an in-memory tree (like the actual /proc filesystem
@@ -257,6 +260,7 @@ struct proc_ns_operations {
 	void *(*get)(struct task_struct *task);
 	void (*put)(void *ns);
 	int (*install)(struct nsproxy *nsproxy, void *ns);
+	unsigned int (*inum)(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 4e5b021..03db764 100644
--- a/include/linux/utsname.h
+++ b/include/linux/utsname.h
@@ -44,6 +44,7 @@ struct uts_namespace {
 	struct kref kref;
 	struct new_utsname name;
 	struct user_namespace *user_ns;
+	unsigned int proc_inum;
 };
 extern struct uts_namespace init_uts_ns;
 
diff --git a/include/net/net_namespace.h b/include/net/net_namespace.h
index 2bf9ed9..4b85be2 100644
--- a/include/net/net_namespace.h
+++ b/include/net/net_namespace.h
@@ -49,6 +49,8 @@ struct net {
 	struct list_head	cleanup_list;	/* namespaces on death row */
 	struct list_head	exit_list;	/* Use only net_mutex */
 
+	unsigned int		proc_inum;
+
 	struct proc_dir_entry 	*proc_net;
 	struct proc_dir_entry 	*proc_net_stat;
 
diff --git a/init/version.c b/init/version.c
index 86fe0cc..58170f1 100644
--- a/init/version.c
+++ b/init/version.c
@@ -12,6 +12,7 @@
 #include <linux/utsname.h>
 #include <generated/utsrelease.h>
 #include <linux/version.h>
+#include <linux/proc_fs.h>
 
 #ifndef CONFIG_KALLSYMS
 #define version(a) Version_ ## a
@@ -34,6 +35,7 @@ struct uts_namespace init_uts_ns = {
 		.domainname	= UTS_DOMAINNAME,
 	},
 	.user_ns = &init_user_ns,
+	.proc_inum = PROC_UTS_INIT_INO,
 };
 EXPORT_SYMBOL_GPL(init_uts_ns);
 
diff --git a/ipc/msgutil.c b/ipc/msgutil.c
index 8b5ce5d..f7da485 100644
--- a/ipc/msgutil.c
+++ b/ipc/msgutil.c
@@ -14,6 +14,7 @@
 #include <linux/slab.h>
 #include <linux/ipc.h>
 #include <linux/ipc_namespace.h>
+#include <linux/proc_fs.h>
 #include <asm/uaccess.h>
 
 #include "util.h"
@@ -33,6 +34,7 @@ struct ipc_namespace init_ipc_ns = {
 	.mq_msgsize_max  = DFLT_MSGSIZEMAX,
 #endif
 	.user_ns = &init_user_ns,
+	.proc_inum = PROC_IPC_INIT_INO,
 };
 
 atomic_t nr_ipc_ns = ATOMIC_INIT(1);
diff --git a/ipc/namespace.c b/ipc/namespace.c
index ce0a647..cd7f733 100644
--- a/ipc/namespace.c
+++ b/ipc/namespace.c
@@ -26,9 +26,16 @@ static struct ipc_namespace *create_ipc_ns(struct task_struct *tsk,
 	if (ns == NULL)
 		return ERR_PTR(-ENOMEM);
 
+	err = proc_alloc_inum(&ns->proc_inum);
+	if (err) {
+		kfree(ns);
+		return ERR_PTR(err);
+	}
+
 	atomic_set(&ns->count, 1);
 	err = mq_init_ns(ns);
 	if (err) {
+		proc_free_inum(ns->proc_inum);
 		kfree(ns);
 		return ERR_PTR(err);
 	}
@@ -113,6 +120,7 @@ static void free_ipc_ns(struct ipc_namespace *ns)
 	 */
 	ipcns_notify(IPCNS_REMOVED);
 	put_user_ns(ns->user_ns);
+	proc_free_inum(ns->proc_inum);
 	kfree(ns);
 }
 
@@ -170,10 +178,18 @@ static int ipcns_install(struct nsproxy *nsproxy, void *ns)
 	return 0;
 }
 
+static unsigned int ipcns_inum(void *vp)
+{
+	struct ipc_namespace *ns = vp;
+
+	return ns->proc_inum;
+}
+
 const struct proc_ns_operations ipcns_operations = {
 	.name		= "ipc",
 	.type		= CLONE_NEWIPC,
 	.get		= ipcns_get,
 	.put		= ipcns_put,
 	.install	= ipcns_install,
+	.inum		= ipcns_inum,
 };
diff --git a/kernel/utsname.c b/kernel/utsname.c
index bff131b..3ab6a08 100644
--- a/kernel/utsname.c
+++ b/kernel/utsname.c
@@ -36,11 +36,18 @@ static struct uts_namespace *clone_uts_ns(struct task_struct *tsk,
 					  struct uts_namespace *old_ns)
 {
 	struct uts_namespace *ns;
+	int err;
 
 	ns = create_uts_ns();
 	if (!ns)
 		return ERR_PTR(-ENOMEM);
 
+	err = proc_alloc_inum(&ns->proc_inum);
+	if (err) {
+		kfree(ns);
+		return ERR_PTR(err);
+	}
+
 	down_read(&uts_sem);
 	memcpy(&ns->name, &old_ns->name, sizeof(ns->name));
 	ns->user_ns = get_user_ns(task_cred_xxx(tsk, user)->user_ns);
@@ -78,6 +85,7 @@ void free_uts_ns(struct kref *kref)
 
 	ns = container_of(kref, struct uts_namespace, kref);
 	put_user_ns(ns->user_ns);
+	proc_free_inum(ns->proc_inum);
 	kfree(ns);
 }
 
@@ -110,11 +118,18 @@ static int utsns_install(struct nsproxy *nsproxy, void *ns)
 	return 0;
 }
 
+static unsigned int utsns_inum(void *vp)
+{
+	struct uts_namespace *ns = vp;
+
+	return ns->proc_inum;
+}
+
 const struct proc_ns_operations utsns_operations = {
 	.name		= "uts",
 	.type		= CLONE_NEWUTS,
 	.get		= utsns_get,
 	.put		= utsns_put,
 	.install	= utsns_install,
+	.inum		= utsns_inum,
 };
-
diff --git a/net/core/net_namespace.c b/net/core/net_namespace.c
index e41e511..6199ec2 100644
--- a/net/core/net_namespace.c
+++ b/net/core/net_namespace.c
@@ -358,6 +358,21 @@ struct net *get_net_ns_by_pid(pid_t pid)
 }
 EXPORT_SYMBOL_GPL(get_net_ns_by_pid);
 
+static __net_init int net_ns_net_init(struct net *net)
+{
+	return proc_alloc_inum(&net->proc_inum);
+}
+
+static __net_exit void net_ns_net_exit(struct net *net)
+{
+	proc_free_inum(net->proc_inum);
+}
+
+static struct pernet_operations __net_initdata net_ns_ops = {
+	.init = net_ns_net_init,
+	.exit = net_ns_net_exit,		
+};
+
 static int __init net_ns_init(void)
 {
 	struct net_generic *ng;
@@ -389,6 +404,8 @@ static int __init net_ns_init(void)
 
 	mutex_unlock(&net_mutex);
 
+	register_pernet_subsys(&net_ns_ops);
+
 	return 0;
 }
 
@@ -616,11 +633,18 @@ static int netns_install(struct nsproxy *nsproxy, void *ns)
 	return 0;
 }
 
+static unsigned int netns_inum(void *ns)
+{
+	struct net *net = ns;
+	return net->proc_inum;
+}
+
 const struct proc_ns_operations netns_operations = {
 	.name		= "net",
 	.type		= CLONE_NEWNET,
 	.get		= netns_get,
 	.put		= netns_put,
 	.install	= netns_install,
+	.inum		= netns_inum,
 };
 #endif
-- 
1.7.5.1.217.g4e3aa

^ permalink raw reply related	[flat|nested] 15+ messages in thread

* [PATCH 2/2] proc: Usable inode numbers for the namespace file descriptors.
@ 2011-06-17 23:33               ` Eric W. Biederman
  0 siblings, 0 replies; 15+ messages in thread
From: Eric W. Biederman @ 2011-06-17 23:33 UTC (permalink / raw)
  To: Linux Containers
  Cc: Alexey Dobriyan, netdev, David Lamparter, linux-kernel, Serge E. Hallyn


Assign a unique proc inode to each namespace, yielding an
identifier that userspace can use for identifying a namespace.

This has been a long requested feature and only blocked because
a naive implementation would put the id in a global space and
would ultimately require having a namespace for the names of
namespaces, making migration and certain virtualization tricks
impossible.

We still don't have per superblock inode numbers for proc, which
appears necessary for application unaware checkpoint/restart and
migrations (if the application is using namespace filedescriptors)
but that is now allowd by the design if it becomes important.

I have preallocated the ipc and uts initial proc inode numbers so
their structures can be statically initialized.

Signed-off-by: Eric W. Biederman <ebiederm@xmission.com>
---
 fs/proc/namespaces.c          |    1 +
 include/linux/ipc_namespace.h |    2 ++
 include/linux/proc_fs.h       |    4 ++++
 include/linux/utsname.h       |    1 +
 include/net/net_namespace.h   |    2 ++
 init/version.c                |    2 ++
 ipc/msgutil.c                 |    2 ++
 ipc/namespace.c               |   16 ++++++++++++++++
 kernel/utsname.c              |   17 ++++++++++++++++-
 net/core/net_namespace.c      |   24 ++++++++++++++++++++++++
 10 files changed, 70 insertions(+), 1 deletions(-)

diff --git a/fs/proc/namespaces.c b/fs/proc/namespaces.c
index be177f7..ddc2bb4 100644
--- a/fs/proc/namespaces.c
+++ b/fs/proc/namespaces.c
@@ -54,6 +54,7 @@ static struct dentry *proc_ns_instantiate(struct inode *dir,
 	ei->ns_ops    = ns_ops;
 	ei->ns	      = ns;
 
+	inode->i_ino = ns_ops->inum(ei->ns);
 	dentry->d_op = &pid_dentry_operations;
 	d_add(dentry, inode);
 	/* Close the race of the process dying before we return the dentry */
diff --git a/include/linux/ipc_namespace.h b/include/linux/ipc_namespace.h
index a6d1655..22a4dc4 100644
--- a/include/linux/ipc_namespace.h
+++ b/include/linux/ipc_namespace.h
@@ -60,6 +60,8 @@ struct ipc_namespace {
 
 	/* user_ns which owns the ipc ns */
 	struct user_namespace *user_ns;
+
+	unsigned int	proc_inum;
 };
 
 extern struct ipc_namespace init_ipc_ns;
diff --git a/include/linux/proc_fs.h b/include/linux/proc_fs.h
index 3067b44..1aee7f0 100644
--- a/include/linux/proc_fs.h
+++ b/include/linux/proc_fs.h
@@ -29,8 +29,11 @@ struct mm_struct;
 
 enum {
 	PROC_ROOT_INO = 1,
+	PROC_IPC_INIT_INO = 2,
+	PROC_UTS_INIT_INO = 3,
 };
 
+
 /*
  * This is not completely implemented yet. The idea is to
  * create an in-memory tree (like the actual /proc filesystem
@@ -257,6 +260,7 @@ struct proc_ns_operations {
 	void *(*get)(struct task_struct *task);
 	void (*put)(void *ns);
 	int (*install)(struct nsproxy *nsproxy, void *ns);
+	unsigned int (*inum)(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 4e5b021..03db764 100644
--- a/include/linux/utsname.h
+++ b/include/linux/utsname.h
@@ -44,6 +44,7 @@ struct uts_namespace {
 	struct kref kref;
 	struct new_utsname name;
 	struct user_namespace *user_ns;
+	unsigned int proc_inum;
 };
 extern struct uts_namespace init_uts_ns;
 
diff --git a/include/net/net_namespace.h b/include/net/net_namespace.h
index 2bf9ed9..4b85be2 100644
--- a/include/net/net_namespace.h
+++ b/include/net/net_namespace.h
@@ -49,6 +49,8 @@ struct net {
 	struct list_head	cleanup_list;	/* namespaces on death row */
 	struct list_head	exit_list;	/* Use only net_mutex */
 
+	unsigned int		proc_inum;
+
 	struct proc_dir_entry 	*proc_net;
 	struct proc_dir_entry 	*proc_net_stat;
 
diff --git a/init/version.c b/init/version.c
index 86fe0cc..58170f1 100644
--- a/init/version.c
+++ b/init/version.c
@@ -12,6 +12,7 @@
 #include <linux/utsname.h>
 #include <generated/utsrelease.h>
 #include <linux/version.h>
+#include <linux/proc_fs.h>
 
 #ifndef CONFIG_KALLSYMS
 #define version(a) Version_ ## a
@@ -34,6 +35,7 @@ struct uts_namespace init_uts_ns = {
 		.domainname	= UTS_DOMAINNAME,
 	},
 	.user_ns = &init_user_ns,
+	.proc_inum = PROC_UTS_INIT_INO,
 };
 EXPORT_SYMBOL_GPL(init_uts_ns);
 
diff --git a/ipc/msgutil.c b/ipc/msgutil.c
index 8b5ce5d..f7da485 100644
--- a/ipc/msgutil.c
+++ b/ipc/msgutil.c
@@ -14,6 +14,7 @@
 #include <linux/slab.h>
 #include <linux/ipc.h>
 #include <linux/ipc_namespace.h>
+#include <linux/proc_fs.h>
 #include <asm/uaccess.h>
 
 #include "util.h"
@@ -33,6 +34,7 @@ struct ipc_namespace init_ipc_ns = {
 	.mq_msgsize_max  = DFLT_MSGSIZEMAX,
 #endif
 	.user_ns = &init_user_ns,
+	.proc_inum = PROC_IPC_INIT_INO,
 };
 
 atomic_t nr_ipc_ns = ATOMIC_INIT(1);
diff --git a/ipc/namespace.c b/ipc/namespace.c
index ce0a647..cd7f733 100644
--- a/ipc/namespace.c
+++ b/ipc/namespace.c
@@ -26,9 +26,16 @@ static struct ipc_namespace *create_ipc_ns(struct task_struct *tsk,
 	if (ns == NULL)
 		return ERR_PTR(-ENOMEM);
 
+	err = proc_alloc_inum(&ns->proc_inum);
+	if (err) {
+		kfree(ns);
+		return ERR_PTR(err);
+	}
+
 	atomic_set(&ns->count, 1);
 	err = mq_init_ns(ns);
 	if (err) {
+		proc_free_inum(ns->proc_inum);
 		kfree(ns);
 		return ERR_PTR(err);
 	}
@@ -113,6 +120,7 @@ static void free_ipc_ns(struct ipc_namespace *ns)
 	 */
 	ipcns_notify(IPCNS_REMOVED);
 	put_user_ns(ns->user_ns);
+	proc_free_inum(ns->proc_inum);
 	kfree(ns);
 }
 
@@ -170,10 +178,18 @@ static int ipcns_install(struct nsproxy *nsproxy, void *ns)
 	return 0;
 }
 
+static unsigned int ipcns_inum(void *vp)
+{
+	struct ipc_namespace *ns = vp;
+
+	return ns->proc_inum;
+}
+
 const struct proc_ns_operations ipcns_operations = {
 	.name		= "ipc",
 	.type		= CLONE_NEWIPC,
 	.get		= ipcns_get,
 	.put		= ipcns_put,
 	.install	= ipcns_install,
+	.inum		= ipcns_inum,
 };
diff --git a/kernel/utsname.c b/kernel/utsname.c
index bff131b..3ab6a08 100644
--- a/kernel/utsname.c
+++ b/kernel/utsname.c
@@ -36,11 +36,18 @@ static struct uts_namespace *clone_uts_ns(struct task_struct *tsk,
 					  struct uts_namespace *old_ns)
 {
 	struct uts_namespace *ns;
+	int err;
 
 	ns = create_uts_ns();
 	if (!ns)
 		return ERR_PTR(-ENOMEM);
 
+	err = proc_alloc_inum(&ns->proc_inum);
+	if (err) {
+		kfree(ns);
+		return ERR_PTR(err);
+	}
+
 	down_read(&uts_sem);
 	memcpy(&ns->name, &old_ns->name, sizeof(ns->name));
 	ns->user_ns = get_user_ns(task_cred_xxx(tsk, user)->user_ns);
@@ -78,6 +85,7 @@ void free_uts_ns(struct kref *kref)
 
 	ns = container_of(kref, struct uts_namespace, kref);
 	put_user_ns(ns->user_ns);
+	proc_free_inum(ns->proc_inum);
 	kfree(ns);
 }
 
@@ -110,11 +118,18 @@ static int utsns_install(struct nsproxy *nsproxy, void *ns)
 	return 0;
 }
 
+static unsigned int utsns_inum(void *vp)
+{
+	struct uts_namespace *ns = vp;
+
+	return ns->proc_inum;
+}
+
 const struct proc_ns_operations utsns_operations = {
 	.name		= "uts",
 	.type		= CLONE_NEWUTS,
 	.get		= utsns_get,
 	.put		= utsns_put,
 	.install	= utsns_install,
+	.inum		= utsns_inum,
 };
-
diff --git a/net/core/net_namespace.c b/net/core/net_namespace.c
index e41e511..6199ec2 100644
--- a/net/core/net_namespace.c
+++ b/net/core/net_namespace.c
@@ -358,6 +358,21 @@ struct net *get_net_ns_by_pid(pid_t pid)
 }
 EXPORT_SYMBOL_GPL(get_net_ns_by_pid);
 
+static __net_init int net_ns_net_init(struct net *net)
+{
+	return proc_alloc_inum(&net->proc_inum);
+}
+
+static __net_exit void net_ns_net_exit(struct net *net)
+{
+	proc_free_inum(net->proc_inum);
+}
+
+static struct pernet_operations __net_initdata net_ns_ops = {
+	.init = net_ns_net_init,
+	.exit = net_ns_net_exit,		
+};
+
 static int __init net_ns_init(void)
 {
 	struct net_generic *ng;
@@ -389,6 +404,8 @@ static int __init net_ns_init(void)
 
 	mutex_unlock(&net_mutex);
 
+	register_pernet_subsys(&net_ns_ops);
+
 	return 0;
 }
 
@@ -616,11 +633,18 @@ static int netns_install(struct nsproxy *nsproxy, void *ns)
 	return 0;
 }
 
+static unsigned int netns_inum(void *ns)
+{
+	struct net *net = ns;
+	return net->proc_inum;
+}
+
 const struct proc_ns_operations netns_operations = {
 	.name		= "net",
 	.type		= CLONE_NEWNET,
 	.get		= netns_get,
 	.put		= netns_put,
 	.install	= netns_install,
+	.inum		= netns_inum,
 };
 #endif
-- 
1.7.5.1.217.g4e3aa


^ permalink raw reply related	[flat|nested] 15+ messages in thread

* Re: [PATCH 1/2] proc: Generalize proc inode allocation
  2011-06-17 23:31             ` Eric W. Biederman
  (?)
  (?)
@ 2011-06-19 14:20             ` Serge E. Hallyn
  -1 siblings, 0 replies; 15+ messages in thread
From: Serge E. Hallyn @ 2011-06-19 14:20 UTC (permalink / raw)
  To: Eric W. Biederman
  Cc: Linux Containers, Alexey Dobriyan, netdev, David Lamparter,
	linux-kernel, Serge E. Hallyn

Quoting Eric W. Biederman (ebiederm@xmission.com):
> 
> Generalize the proc inode allocation so that it can be
> used without having to having to create a proc_dir_entry.
> 
> This will allow namespace file descriptors to remain light
> weight entitities but still have the same inode number
> when the backing namespace is the same.
> 
> Signed-off-by: Eric W. Biederman <ebiederm@xmission.com>

Acked-by: Serge Hallyn <serge@hallyn.com>

> ---
> 
> Baring problems in review I plan to merge these patches
> via my linux-2.6-nsfd tree.
> 
>  fs/proc/generic.c       |   26 +++++++++++++-------------
>  include/linux/proc_fs.h |   10 ++++++++++
>  2 files changed, 23 insertions(+), 13 deletions(-)
> 
> diff --git a/fs/proc/generic.c b/fs/proc/generic.c
> index f1637f1..65416a1 100644
> --- a/fs/proc/generic.c
> +++ b/fs/proc/generic.c
> @@ -350,14 +350,14 @@ static DEFINE_SPINLOCK(proc_inum_lock); /* protects the above */
>   * Return an inode number between PROC_DYNAMIC_FIRST and
>   * 0xffffffff, or zero on failure.
>   */
> -static unsigned int get_inode_number(void)
> +int proc_alloc_inum(unsigned int *inum)
>  {
>  	unsigned int i;
>  	int error;
>  
>  retry:
> -	if (ida_pre_get(&proc_inum_ida, GFP_KERNEL) == 0)
> -		return 0;
> +	if (!ida_pre_get(&proc_inum_ida, GFP_KERNEL))
> +		return -ENOMEM;
>  
>  	spin_lock(&proc_inum_lock);
>  	error = ida_get_new(&proc_inum_ida, &i);
> @@ -365,18 +365,19 @@ retry:
>  	if (error == -EAGAIN)
>  		goto retry;
>  	else if (error)
> -		return 0;
> +		return error;
>  
>  	if (i > UINT_MAX - PROC_DYNAMIC_FIRST) {
>  		spin_lock(&proc_inum_lock);
>  		ida_remove(&proc_inum_ida, i);
>  		spin_unlock(&proc_inum_lock);
> -		return 0;
> +		return -ENOSPC;
>  	}
> -	return PROC_DYNAMIC_FIRST + i;
> +	*inum = PROC_DYNAMIC_FIRST + i;
> +	return 0;
>  }
>  
> -static void release_inode_number(unsigned int inum)
> +void proc_free_inum(unsigned int inum)
>  {
>  	spin_lock(&proc_inum_lock);
>  	ida_remove(&proc_inum_ida, inum - PROC_DYNAMIC_FIRST);
> @@ -554,13 +555,12 @@ static const struct inode_operations proc_dir_inode_operations = {
>  
>  static int proc_register(struct proc_dir_entry * dir, struct proc_dir_entry * dp)
>  {
> -	unsigned int i;
>  	struct proc_dir_entry *tmp;
> +	int ret;
>  	
> -	i = get_inode_number();
> -	if (i == 0)
> -		return -EAGAIN;
> -	dp->low_ino = i;
> +	ret = proc_alloc_inum(&dp->low_ino);
> +	if (ret)
> +		return ret;
>  
>  	if (S_ISDIR(dp->mode)) {
>  		if (dp->proc_iops == NULL) {
> @@ -766,7 +766,7 @@ EXPORT_SYMBOL(proc_create_data);
>  
>  static void free_proc_entry(struct proc_dir_entry *de)
>  {
> -	release_inode_number(de->low_ino);
> +	proc_free_inum(de->low_ino);
>  
>  	if (S_ISLNK(de->mode))
>  		kfree(de->data);
> diff --git a/include/linux/proc_fs.h b/include/linux/proc_fs.h
> index e7576cf..3067b44 100644
> --- a/include/linux/proc_fs.h
> +++ b/include/linux/proc_fs.h
> @@ -175,6 +175,8 @@ extern struct proc_dir_entry *proc_net_mkdir(struct net *net, const char *name,
>  
>  extern struct file *proc_ns_fget(int fd);
>  
> +extern int proc_alloc_inum(unsigned int *pino);
> +extern void proc_free_inum(unsigned int inum);
>  #else
>  
>  #define proc_net_fops_create(net, name, mode, fops)  ({ (void)(mode), NULL; })
> @@ -229,6 +231,14 @@ static inline struct file *proc_ns_fget(int fd)
>  	return ERR_PTR(-EINVAL);
>  }
>  
> +static inline int proc_alloc_inum(unsigned int *inum)
> +{
> +	*inum = 1;
> +	return 0;
> +}
> +static inline void proc_free_inum(unsigned int inum)
> +{
> +}
>  #endif /* CONFIG_PROC_FS */
>  
>  #if !defined(CONFIG_PROC_KCORE)
> -- 
> 1.7.5.1.217.g4e3aa
> 

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [PATCH 2/2] proc: Usable inode numbers for the namespace file descriptors.
  2011-06-17 23:33               ` Eric W. Biederman
  (?)
@ 2011-06-19 23:22               ` David Miller
  -1 siblings, 0 replies; 15+ messages in thread
From: David Miller @ 2011-06-19 23:22 UTC (permalink / raw)
  To: ebiederm; +Cc: containers, adobriyan, netdev, equinox, linux-kernel, serge

From: ebiederm@xmission.com (Eric W. Biederman)
Date: Fri, 17 Jun 2011 16:33:19 -0700

> 
> Assign a unique proc inode to each namespace, yielding an
> identifier that userspace can use for identifying a namespace.
> 
> This has been a long requested feature and only blocked because
> a naive implementation would put the id in a global space and
> would ultimately require having a namespace for the names of
> namespaces, making migration and certain virtualization tricks
> impossible.
> 
> We still don't have per superblock inode numbers for proc, which
> appears necessary for application unaware checkpoint/restart and
> migrations (if the application is using namespace filedescriptors)
> but that is now allowd by the design if it becomes important.
> 
> I have preallocated the ipc and uts initial proc inode numbers so
> their structures can be statically initialized.
> 
> Signed-off-by: Eric W. Biederman <ebiederm@xmission.com>

For networking bits:

Acked-by: David S. Miller <davem@davemloft.net>

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [PATCH 2/2] proc: Usable inode numbers for the namespace file descriptors.
  2011-06-17 23:33               ` Eric W. Biederman
  (?)
  (?)
@ 2011-06-20 16:06               ` Serge E. Hallyn
  2011-06-20 19:50                 ` Eric W. Biederman
  -1 siblings, 1 reply; 15+ messages in thread
From: Serge E. Hallyn @ 2011-06-20 16:06 UTC (permalink / raw)
  To: Eric W. Biederman
  Cc: Linux Containers, Alexey Dobriyan, netdev, David Lamparter,
	linux-kernel, Serge E. Hallyn

Quoting Eric W. Biederman (ebiederm@xmission.com):
> 
> Assign a unique proc inode to each namespace, yielding an
> identifier that userspace can use for identifying a namespace.
> 
> This has been a long requested feature and only blocked because
> a naive implementation would put the id in a global space and
> would ultimately require having a namespace for the names of
> namespaces, making migration and certain virtualization tricks
> impossible.
> 
> We still don't have per superblock inode numbers for proc, which
> appears necessary for application unaware checkpoint/restart and
> migrations (if the application is using namespace filedescriptors)
> but that is now allowd by the design if it becomes important.
> 
> I have preallocated the ipc and uts initial proc inode numbers so
> their structures can be statically initialized.
> 
> Signed-off-by: Eric W. Biederman <ebiederm@xmission.com>

I've not looked at the setns patches enough, but from what I can see
here it looks good.

Acked-by: Serge Hallyn <serge@hallyn.com>

thanks,
-serge

> ---
>  fs/proc/namespaces.c          |    1 +
>  include/linux/ipc_namespace.h |    2 ++
>  include/linux/proc_fs.h       |    4 ++++
>  include/linux/utsname.h       |    1 +
>  include/net/net_namespace.h   |    2 ++
>  init/version.c                |    2 ++
>  ipc/msgutil.c                 |    2 ++
>  ipc/namespace.c               |   16 ++++++++++++++++
>  kernel/utsname.c              |   17 ++++++++++++++++-
>  net/core/net_namespace.c      |   24 ++++++++++++++++++++++++
>  10 files changed, 70 insertions(+), 1 deletions(-)
> 
> diff --git a/fs/proc/namespaces.c b/fs/proc/namespaces.c
> index be177f7..ddc2bb4 100644
> --- a/fs/proc/namespaces.c
> +++ b/fs/proc/namespaces.c
> @@ -54,6 +54,7 @@ static struct dentry *proc_ns_instantiate(struct inode *dir,
>  	ei->ns_ops    = ns_ops;
>  	ei->ns	      = ns;
>  
> +	inode->i_ino = ns_ops->inum(ei->ns);
>  	dentry->d_op = &pid_dentry_operations;
>  	d_add(dentry, inode);
>  	/* Close the race of the process dying before we return the dentry */
> diff --git a/include/linux/ipc_namespace.h b/include/linux/ipc_namespace.h
> index a6d1655..22a4dc4 100644
> --- a/include/linux/ipc_namespace.h
> +++ b/include/linux/ipc_namespace.h
> @@ -60,6 +60,8 @@ struct ipc_namespace {
>  
>  	/* user_ns which owns the ipc ns */
>  	struct user_namespace *user_ns;
> +
> +	unsigned int	proc_inum;
>  };
>  
>  extern struct ipc_namespace init_ipc_ns;
> diff --git a/include/linux/proc_fs.h b/include/linux/proc_fs.h
> index 3067b44..1aee7f0 100644
> --- a/include/linux/proc_fs.h
> +++ b/include/linux/proc_fs.h
> @@ -29,8 +29,11 @@ struct mm_struct;
>  
>  enum {
>  	PROC_ROOT_INO = 1,
> +	PROC_IPC_INIT_INO = 2,
> +	PROC_UTS_INIT_INO = 3,
>  };
>  
> +
>  /*
>   * This is not completely implemented yet. The idea is to
>   * create an in-memory tree (like the actual /proc filesystem
> @@ -257,6 +260,7 @@ struct proc_ns_operations {
>  	void *(*get)(struct task_struct *task);
>  	void (*put)(void *ns);
>  	int (*install)(struct nsproxy *nsproxy, void *ns);
> +	unsigned int (*inum)(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 4e5b021..03db764 100644
> --- a/include/linux/utsname.h
> +++ b/include/linux/utsname.h
> @@ -44,6 +44,7 @@ struct uts_namespace {
>  	struct kref kref;
>  	struct new_utsname name;
>  	struct user_namespace *user_ns;
> +	unsigned int proc_inum;
>  };
>  extern struct uts_namespace init_uts_ns;
>  
> diff --git a/include/net/net_namespace.h b/include/net/net_namespace.h
> index 2bf9ed9..4b85be2 100644
> --- a/include/net/net_namespace.h
> +++ b/include/net/net_namespace.h
> @@ -49,6 +49,8 @@ struct net {
>  	struct list_head	cleanup_list;	/* namespaces on death row */
>  	struct list_head	exit_list;	/* Use only net_mutex */
>  
> +	unsigned int		proc_inum;
> +
>  	struct proc_dir_entry 	*proc_net;
>  	struct proc_dir_entry 	*proc_net_stat;
>  
> diff --git a/init/version.c b/init/version.c
> index 86fe0cc..58170f1 100644
> --- a/init/version.c
> +++ b/init/version.c
> @@ -12,6 +12,7 @@
>  #include <linux/utsname.h>
>  #include <generated/utsrelease.h>
>  #include <linux/version.h>
> +#include <linux/proc_fs.h>
>  
>  #ifndef CONFIG_KALLSYMS
>  #define version(a) Version_ ## a
> @@ -34,6 +35,7 @@ struct uts_namespace init_uts_ns = {
>  		.domainname	= UTS_DOMAINNAME,
>  	},
>  	.user_ns = &init_user_ns,
> +	.proc_inum = PROC_UTS_INIT_INO,
>  };
>  EXPORT_SYMBOL_GPL(init_uts_ns);
>  
> diff --git a/ipc/msgutil.c b/ipc/msgutil.c
> index 8b5ce5d..f7da485 100644
> --- a/ipc/msgutil.c
> +++ b/ipc/msgutil.c
> @@ -14,6 +14,7 @@
>  #include <linux/slab.h>
>  #include <linux/ipc.h>
>  #include <linux/ipc_namespace.h>
> +#include <linux/proc_fs.h>
>  #include <asm/uaccess.h>
>  
>  #include "util.h"
> @@ -33,6 +34,7 @@ struct ipc_namespace init_ipc_ns = {
>  	.mq_msgsize_max  = DFLT_MSGSIZEMAX,
>  #endif
>  	.user_ns = &init_user_ns,
> +	.proc_inum = PROC_IPC_INIT_INO,
>  };
>  
>  atomic_t nr_ipc_ns = ATOMIC_INIT(1);
> diff --git a/ipc/namespace.c b/ipc/namespace.c
> index ce0a647..cd7f733 100644
> --- a/ipc/namespace.c
> +++ b/ipc/namespace.c
> @@ -26,9 +26,16 @@ static struct ipc_namespace *create_ipc_ns(struct task_struct *tsk,
>  	if (ns == NULL)
>  		return ERR_PTR(-ENOMEM);
>  
> +	err = proc_alloc_inum(&ns->proc_inum);
> +	if (err) {
> +		kfree(ns);
> +		return ERR_PTR(err);
> +	}
> +
>  	atomic_set(&ns->count, 1);
>  	err = mq_init_ns(ns);
>  	if (err) {
> +		proc_free_inum(ns->proc_inum);
>  		kfree(ns);
>  		return ERR_PTR(err);
>  	}
> @@ -113,6 +120,7 @@ static void free_ipc_ns(struct ipc_namespace *ns)
>  	 */
>  	ipcns_notify(IPCNS_REMOVED);
>  	put_user_ns(ns->user_ns);
> +	proc_free_inum(ns->proc_inum);
>  	kfree(ns);
>  }
>  
> @@ -170,10 +178,18 @@ static int ipcns_install(struct nsproxy *nsproxy, void *ns)
>  	return 0;
>  }
>  
> +static unsigned int ipcns_inum(void *vp)
> +{
> +	struct ipc_namespace *ns = vp;
> +
> +	return ns->proc_inum;
> +}
> +
>  const struct proc_ns_operations ipcns_operations = {
>  	.name		= "ipc",
>  	.type		= CLONE_NEWIPC,
>  	.get		= ipcns_get,
>  	.put		= ipcns_put,
>  	.install	= ipcns_install,
> +	.inum		= ipcns_inum,
>  };
> diff --git a/kernel/utsname.c b/kernel/utsname.c
> index bff131b..3ab6a08 100644
> --- a/kernel/utsname.c
> +++ b/kernel/utsname.c
> @@ -36,11 +36,18 @@ static struct uts_namespace *clone_uts_ns(struct task_struct *tsk,
>  					  struct uts_namespace *old_ns)
>  {
>  	struct uts_namespace *ns;
> +	int err;
>  
>  	ns = create_uts_ns();
>  	if (!ns)
>  		return ERR_PTR(-ENOMEM);
>  
> +	err = proc_alloc_inum(&ns->proc_inum);
> +	if (err) {
> +		kfree(ns);
> +		return ERR_PTR(err);
> +	}
> +
>  	down_read(&uts_sem);
>  	memcpy(&ns->name, &old_ns->name, sizeof(ns->name));
>  	ns->user_ns = get_user_ns(task_cred_xxx(tsk, user)->user_ns);
> @@ -78,6 +85,7 @@ void free_uts_ns(struct kref *kref)
>  
>  	ns = container_of(kref, struct uts_namespace, kref);
>  	put_user_ns(ns->user_ns);
> +	proc_free_inum(ns->proc_inum);
>  	kfree(ns);
>  }
>  
> @@ -110,11 +118,18 @@ static int utsns_install(struct nsproxy *nsproxy, void *ns)
>  	return 0;
>  }
>  
> +static unsigned int utsns_inum(void *vp)
> +{
> +	struct uts_namespace *ns = vp;
> +
> +	return ns->proc_inum;
> +}
> +
>  const struct proc_ns_operations utsns_operations = {
>  	.name		= "uts",
>  	.type		= CLONE_NEWUTS,
>  	.get		= utsns_get,
>  	.put		= utsns_put,
>  	.install	= utsns_install,
> +	.inum		= utsns_inum,
>  };
> -
> diff --git a/net/core/net_namespace.c b/net/core/net_namespace.c
> index e41e511..6199ec2 100644
> --- a/net/core/net_namespace.c
> +++ b/net/core/net_namespace.c
> @@ -358,6 +358,21 @@ struct net *get_net_ns_by_pid(pid_t pid)
>  }
>  EXPORT_SYMBOL_GPL(get_net_ns_by_pid);
>  
> +static __net_init int net_ns_net_init(struct net *net)
> +{
> +	return proc_alloc_inum(&net->proc_inum);
> +}
> +
> +static __net_exit void net_ns_net_exit(struct net *net)
> +{
> +	proc_free_inum(net->proc_inum);
> +}
> +
> +static struct pernet_operations __net_initdata net_ns_ops = {
> +	.init = net_ns_net_init,
> +	.exit = net_ns_net_exit,		
> +};
> +
>  static int __init net_ns_init(void)
>  {
>  	struct net_generic *ng;
> @@ -389,6 +404,8 @@ static int __init net_ns_init(void)
>  
>  	mutex_unlock(&net_mutex);
>  
> +	register_pernet_subsys(&net_ns_ops);
> +
>  	return 0;
>  }
>  
> @@ -616,11 +633,18 @@ static int netns_install(struct nsproxy *nsproxy, void *ns)
>  	return 0;
>  }
>  
> +static unsigned int netns_inum(void *ns)
> +{
> +	struct net *net = ns;
> +	return net->proc_inum;
> +}
> +
>  const struct proc_ns_operations netns_operations = {
>  	.name		= "net",
>  	.type		= CLONE_NEWNET,
>  	.get		= netns_get,
>  	.put		= netns_put,
>  	.install	= netns_install,
> +	.inum		= netns_inum,
>  };
>  #endif
> -- 
> 1.7.5.1.217.g4e3aa
> 

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [PATCH 2/2] proc: Usable inode numbers for the namespace file descriptors.
  2011-06-20 16:06               ` Serge E. Hallyn
@ 2011-06-20 19:50                 ` Eric W. Biederman
  0 siblings, 0 replies; 15+ messages in thread
From: Eric W. Biederman @ 2011-06-20 19:50 UTC (permalink / raw)
  To: Serge E. Hallyn
  Cc: Linux Containers, Alexey Dobriyan, netdev, David Lamparter, linux-kernel

"Serge E. Hallyn" <serge@hallyn.com> writes:

> Quoting Eric W. Biederman (ebiederm@xmission.com):
>> 
>> Assign a unique proc inode to each namespace, yielding an
>> identifier that userspace can use for identifying a namespace.
>> 
>> This has been a long requested feature and only blocked because
>> a naive implementation would put the id in a global space and
>> would ultimately require having a namespace for the names of
>> namespaces, making migration and certain virtualization tricks
>> impossible.
>> 
>> We still don't have per superblock inode numbers for proc, which
>> appears necessary for application unaware checkpoint/restart and
>> migrations (if the application is using namespace filedescriptors)
>> but that is now allowd by the design if it becomes important.
>> 
>> I have preallocated the ipc and uts initial proc inode numbers so
>> their structures can be statically initialized.
>> 
>> Signed-off-by: Eric W. Biederman <ebiederm@xmission.com>
>
> I've not looked at the setns patches enough, but from what I can see
> here it looks good.
>
> Acked-by: Serge Hallyn <serge@hallyn.com>

Thanks.

There are bugs in my existing proc bits that I am working on fixing so
this second patch will have a small update, before it gets merged.

But posting the patches I was looking for a little review and I was
announcing I had solved the technical problem of how we talk about
namespaces, without needing to introduce another namespace for
namespaces.

Eric

^ permalink raw reply	[flat|nested] 15+ messages in thread

end of thread, other threads:[~2011-06-20 19:50 UTC | newest]

Thread overview: 15+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2011-05-21  9:39 [PATCH] netns: add /proc/*/net/id symlink Alexey Dobriyan
2011-05-21 15:39 ` Eric W. Biederman
2011-05-21 22:30   ` Alexey Dobriyan
2011-05-22  0:15     ` Eric W. Biederman
2011-05-23  1:43       ` David Lamparter
2011-05-23  1:47         ` David Lamparter
2011-06-17 23:31           ` [PATCH 1/2] proc: Generalize proc inode allocation Eric W. Biederman
2011-06-17 23:31             ` Eric W. Biederman
2011-06-17 23:33             ` [PATCH 2/2] proc: Usable inode numbers for the namespace file descriptors Eric W. Biederman
2011-06-17 23:33               ` Eric W. Biederman
2011-06-19 23:22               ` David Miller
2011-06-20 16:06               ` Serge E. Hallyn
2011-06-20 19:50                 ` Eric W. Biederman
2011-06-19 14:20             ` [PATCH 1/2] proc: Generalize proc inode allocation Serge E. Hallyn
2011-05-23  2:02         ` [PATCH] netns: add /proc/*/net/id symlink Eric W. Biederman

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.