diff options
author | Eric W. Biederman <ebiederm@xmission.com> | 2011-06-15 13:21:48 -0400 |
---|---|---|
committer | Eric W. Biederman <ebiederm@xmission.com> | 2012-11-20 07:19:49 -0500 |
commit | 98f842e675f96ffac96e6c50315790912b2812be (patch) | |
tree | ed4dee9a6e54e3443e9f3f1614c8a2fcf9b31e0a /fs/proc/namespaces.c | |
parent | bf056bfa80596a5d14b26b17276a56a0dcb080e5 (diff) |
proc: Usable inode numbers for the namespace file descriptors.
Assign a unique proc inode to each namespace, and use that
inode number to ensure we only allocate at most one proc
inode for every namespace in proc.
A single proc inode per namespace allows userspace to test
to see if two processes are in the same 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 file descriptors)
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>
Diffstat (limited to 'fs/proc/namespaces.c')
-rw-r--r-- | fs/proc/namespaces.c | 24 |
1 files changed, 14 insertions, 10 deletions
diff --git a/fs/proc/namespaces.c b/fs/proc/namespaces.c index 7a6d8d69cdb8..b7a47196c8c3 100644 --- a/fs/proc/namespaces.c +++ b/fs/proc/namespaces.c | |||
@@ -82,7 +82,7 @@ static struct dentry *proc_ns_get_dentry(struct super_block *sb, | |||
82 | return ERR_PTR(-ENOMEM); | 82 | return ERR_PTR(-ENOMEM); |
83 | } | 83 | } |
84 | 84 | ||
85 | inode = new_inode(sb); | 85 | inode = iget_locked(sb, ns_ops->inum(ns)); |
86 | if (!inode) { | 86 | if (!inode) { |
87 | dput(dentry); | 87 | dput(dentry); |
88 | ns_ops->put(ns); | 88 | ns_ops->put(ns); |
@@ -90,13 +90,17 @@ static struct dentry *proc_ns_get_dentry(struct super_block *sb, | |||
90 | } | 90 | } |
91 | 91 | ||
92 | ei = PROC_I(inode); | 92 | ei = PROC_I(inode); |
93 | inode->i_ino = get_next_ino(); | 93 | if (inode->i_state & I_NEW) { |
94 | inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME; | 94 | inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME; |
95 | inode->i_op = &ns_inode_operations; | 95 | inode->i_op = &ns_inode_operations; |
96 | inode->i_mode = S_IFREG | S_IRUGO; | 96 | inode->i_mode = S_IFREG | S_IRUGO; |
97 | inode->i_fop = &ns_file_operations; | 97 | inode->i_fop = &ns_file_operations; |
98 | ei->ns_ops = ns_ops; | 98 | ei->ns_ops = ns_ops; |
99 | ei->ns = ns; | 99 | ei->ns = ns; |
100 | unlock_new_inode(inode); | ||
101 | } else { | ||
102 | ns_ops->put(ns); | ||
103 | } | ||
100 | 104 | ||
101 | d_set_d_op(dentry, &ns_dentry_operations); | 105 | d_set_d_op(dentry, &ns_dentry_operations); |
102 | result = d_instantiate_unique(dentry, inode); | 106 | result = d_instantiate_unique(dentry, inode); |
@@ -162,12 +166,12 @@ static int proc_ns_readlink(struct dentry *dentry, char __user *buffer, int bufl | |||
162 | if (!ns) | 166 | if (!ns) |
163 | goto out_put_task; | 167 | goto out_put_task; |
164 | 168 | ||
165 | snprintf(name, sizeof(name), "%s", ns_ops->name); | 169 | snprintf(name, sizeof(name), "%s:[%u]", ns_ops->name, ns_ops->inum(ns)); |
166 | len = strlen(name); | 170 | len = strlen(name); |
167 | 171 | ||
168 | if (len > buflen) | 172 | if (len > buflen) |
169 | len = buflen; | 173 | len = buflen; |
170 | if (copy_to_user(buffer, ns_ops->name, len)) | 174 | if (copy_to_user(buffer, name, len)) |
171 | len = -EFAULT; | 175 | len = -EFAULT; |
172 | 176 | ||
173 | ns_ops->put(ns); | 177 | ns_ops->put(ns); |