History

take the targets of /proc/*/ns/* symlinks to separate fs

New pseudo-filesystem: nsfs. Targets of /proc/*/ns/* live there now. It's not mountable (not even registered, so it's not in /proc/filesystems, etc.). Files on it *are* bindable - we explicitly permit that in do_loopback(). This stuff lives in fs/nsfs.c now; proc_ns_fget() moved there as well. get_proc_ns() is a macro now (it's simply returning ->i_private; would have been an inline, if not for header ordering headache). proc_ns_inode() is an ex-parrot. The interface used in procfs is ns_get_path(path, task, ops) and ns_get_name(buf, size, task, ops). Dentries and inodes are never hashed; a non-counting reference to dentry is stashed in ns_common (removed by ->d_prune()) and reused by ns_get_path() if present. See ns_get_path()/ns_prune_dentry/nsfs_evict() for details of that mechanism. As the result, proc_ns_follow_link() has stopped poking in nd->path.mnt; it does nd_jump_link() on a consistent <vfsmount,dentry> pair it gets from ns_get_path().

Al Viro committed 12 years ago

Commit e149ed21 parent f77c80110 files · +208 −161Browse files

Unified · Split

10 files
  1. fs/Makefile +1 −1
  2. fs/internal.h +5 −0
  3. fs/namespace.c +6 −3
  4. fs/nsfs.c +161 −0
  5. fs/proc/inode.c +0 −5
  6. fs/proc/namespaces.c +13 −139
  7. include/linux/ns_common.h +1 −0
  8. include/linux/proc_ns.h +18 −13
  9. include/uapi/linux/magic.h +1 −0
  10. init/main.c +2 −0
fs/Makefile+1−1
@@ -11,7 +11,7 @@ obj-y := open.o read_write.o file_table.o super.o \ · 10 unmodified lines
1111 attr.o bad_inode.o file.o filesystems.o namespace.o \
1212 seq_file.o xattr.o libfs.o fs-writeback.o \
1313 pnode.o splice.o sync.o utimes.o \
14− stack.o fs_struct.o statfs.o fs_pin.o
14+ stack.o fs_struct.o statfs.o fs_pin.o nsfs.o
1515
1616 ifeq ($(CONFIG_BLOCK),y)
1717 obj-y += buffer.o block_dev.o direct-io.o mpage.o
fs/internal.h+5−0
@@ -147,3 +147,8 @@ extern const struct file_operations pipefifo_fops; · 146 unmodified lines
147147 */
148148 extern void sb_pin_kill(struct super_block *sb);
149149 extern void mnt_pin_kill(struct mount *m);
150+
151+/*
152+ * fs/nsfs.c
153+ */
154+extern struct dentry_operations ns_dentry_operations;
fs/namespace.c+6−3
@@ -1569,8 +1569,8 @@ SYSCALL_DEFINE1(oldumount, char __user *, name) · 1568 unmodified lines
15691569 static bool is_mnt_ns_file(struct dentry *dentry)
15701570 {
15711571 /* Is this a proxy for a mount namespace? */
1572− struct inode *inode = dentry->d_inode;
1573− return proc_ns_inode(inode) && dentry->d_fsdata == &mntns_operations;
1572+ return dentry->d_op == &ns_dentry_operations &&
1573+ dentry->d_fsdata == &mntns_operations;
15741574 }
15751575
15761576 struct mnt_namespace *to_mnt_ns(struct ns_common *ns)
@@ -2016,7 +2016,10 @@ static int do_loopback(struct path *path, const char *old_name, · 439 unmodified lines
20162016 if (IS_MNT_UNBINDABLE(old))
20172017 goto out2;
20182018
2019− if (!check_mnt(parent) || !check_mnt(old))
2019+ if (!check_mnt(parent))
2020+ goto out2;
2021+
2022+ if (!check_mnt(old) && old_path.dentry->d_op != &ns_dentry_operations)
20202023 goto out2;
20212024
20222025 if (!recurse && has_locked_children(old, old_path.dentry))
fs/nsfs.c+161−0
@@ -0,0 +1,161 @@
1+#include <linux/mount.h>
2+#include <linux/file.h>
3+#include <linux/fs.h>
4+#include <linux/proc_ns.h>
5+#include <linux/magic.h>
6+#include <linux/ktime.h>
7+
8+static struct vfsmount *nsfs_mnt;
9+
10+static const struct file_operations ns_file_operations = {
11+ .llseek = no_llseek,
12+};
13+
14+static char *ns_dname(struct dentry *dentry, char *buffer, int buflen)
15+{
16+ struct inode *inode = dentry->d_inode;
17+ const struct proc_ns_operations *ns_ops = dentry->d_fsdata;
18+
19+ return dynamic_dname(dentry, buffer, buflen, "%s:[%lu]",
20+ ns_ops->name, inode->i_ino);
21+}
22+
23+static void ns_prune_dentry(struct dentry *dentry)
24+{
25+ struct inode *inode = dentry->d_inode;
26+ if (inode) {
27+ struct ns_common *ns = inode->i_private;
28+ atomic_long_set(&ns->stashed, 0);
29+ }
30+}
31+
32+const struct dentry_operations ns_dentry_operations =
33+{
34+ .d_prune = ns_prune_dentry,
35+ .d_delete = always_delete_dentry,
36+ .d_dname = ns_dname,
37+};
38+
39+static void nsfs_evict(struct inode *inode)
40+{
41+ struct ns_common *ns = inode->i_private;
42+ clear_inode(inode);
43+ ns->ops->put(ns);
44+}
45+
46+void *ns_get_path(struct path *path, struct task_struct *task,
47+ const struct proc_ns_operations *ns_ops)
48+{
49+ struct vfsmount *mnt = mntget(nsfs_mnt);
50+ struct qstr qname = { .name = "", };
51+ struct dentry *dentry;
52+ struct inode *inode;
53+ struct ns_common *ns;
54+ unsigned long d;
55+
56+again:
57+ ns = ns_ops->get(task);
58+ if (!ns) {
59+ mntput(mnt);
60+ return ERR_PTR(-ENOENT);
61+ }
62+ rcu_read_lock();
63+ d = atomic_long_read(&ns->stashed);
64+ if (!d)
65+ goto slow;
66+ dentry = (struct dentry *)d;
67+ if (!lockref_get_not_dead(&dentry->d_lockref))
68+ goto slow;
69+ rcu_read_unlock();
70+ ns_ops->put(ns);
71+got_it:
72+ path->mnt = mnt;
73+ path->dentry = dentry;
74+ return NULL;
75+slow:
76+ rcu_read_unlock();
77+ inode = new_inode_pseudo(mnt->mnt_sb);
78+ if (!inode) {
79+ ns_ops->put(ns);
80+ mntput(mnt);
81+ return ERR_PTR(-ENOMEM);
82+ }
83+ inode->i_ino = ns->inum;
84+ inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME;
85+ inode->i_flags |= S_IMMUTABLE;
86+ inode->i_mode = S_IFREG | S_IRUGO;
87+ inode->i_fop = &ns_file_operations;
88+ inode->i_private = ns;
89+
90+ dentry = d_alloc_pseudo(mnt->mnt_sb, &qname);
91+ if (!dentry) {
92+ iput(inode);
93+ mntput(mnt);
94+ return ERR_PTR(-ENOMEM);
95+ }
96+ d_instantiate(dentry, inode);
97+ dentry->d_fsdata = (void *)ns_ops;
98+ d = atomic_long_cmpxchg(&ns->stashed, 0, (unsigned long)dentry);
99+ if (d) {
100+ d_delete(dentry); /* make sure ->d_prune() does nothing */
101+ dput(dentry);
102+ cpu_relax();
103+ goto again;
104+ }
105+ goto got_it;
106+}
107+
108+int ns_get_name(char *buf, size_t size, struct task_struct *task,
109+ const struct proc_ns_operations *ns_ops)
110+{
111+ struct ns_common *ns;
112+ int res = -ENOENT;
113+ ns = ns_ops->get(task);
114+ if (ns) {
115+ res = snprintf(buf, size, "%s:[%u]", ns_ops->name, ns->inum);
116+ ns_ops->put(ns);
117+ }
118+ return res;
119+}
120+
121+struct file *proc_ns_fget(int fd)
122+{
123+ struct file *file;
124+
125+ file = fget(fd);
126+ if (!file)
127+ return ERR_PTR(-EBADF);
128+
129+ if (file->f_op != &ns_file_operations)
130+ goto out_invalid;
131+
132+ return file;
133+
134+out_invalid:
135+ fput(file);
136+ return ERR_PTR(-EINVAL);
137+}
138+
139+static const struct super_operations nsfs_ops = {
140+ .statfs = simple_statfs,
141+ .evict_inode = nsfs_evict,
142+};
143+static struct dentry *nsfs_mount(struct file_system_type *fs_type,
144+ int flags, const char *dev_name, void *data)
145+{
146+ return mount_pseudo(fs_type, "nsfs:", &nsfs_ops,
147+ &ns_dentry_operations, NSFS_MAGIC);
148+}
149+static struct file_system_type nsfs = {
150+ .name = "nsfs",
151+ .mount = nsfs_mount,
152+ .kill_sb = kill_anon_super,
153+};
154+
155+void __init nsfs_init(void)
156+{
157+ nsfs_mnt = kern_mount(&nsfs);
158+ if (IS_ERR(nsfs_mnt))
159+ panic("can't set nsfs up\n");
160+ nsfs_mnt->mnt_sb->s_flags &= ~MS_NOUSER;
161+}
fs/proc/inode.c+0−5
@@ -32,7 +32,6 @@ static void proc_evict_inode(struct inode *inode) · 31 unmodified lines
3232 {
3333 struct proc_dir_entry *de;
3434 struct ctl_table_header *head;
35− struct ns_common *ns;
3635
3736 truncate_inode_pages_final(&inode->i_data);
3837 clear_inode(inode);
@@ -49,10 +48,6 @@ static void proc_evict_inode(struct inode *inode) · 10 unmodified lines
4948 RCU_INIT_POINTER(PROC_I(inode)->sysctl, NULL);
5049 sysctl_head_put(head);
5150 }
52− /* Release any associated namespace */
53− ns = PROC_I(inode)->ns.ns;
54− if (ns && ns->ops)
55− ns->ops->put(ns);
5651 }
5752
5853 static struct kmem_cache * proc_inode_cachep;
fs/proc/namespaces.c+13−139
@@ -1,10 +1,6 @@
11 #include <linux/proc_fs.h>
22 #include <linux/nsproxy.h>
3−#include <linux/sched.h>
43 #include <linux/ptrace.h>
5−#include <linux/fs_struct.h>
6−#include <linux/mount.h>
7−#include <linux/path.h>
84 #include <linux/namei.h>
95 #include <linux/file.h>
106 #include <linux/utsname.h>
@@ -34,139 +30,45 @@ static const struct proc_ns_operations *ns_entries[] = { · 23 unmodified lines
3430 &mntns_operations,
3531 };
3632
37−static const struct file_operations ns_file_operations = {
38− .llseek = no_llseek,
39−};
40−
41−static const struct inode_operations ns_inode_operations = {
42− .setattr = proc_setattr,
43−};
44−
45−static char *ns_dname(struct dentry *dentry, char *buffer, int buflen)
46−{
47− struct inode *inode = dentry->d_inode;
48− const struct proc_ns_operations *ns_ops = dentry->d_fsdata;
49−
50− return dynamic_dname(dentry, buffer, buflen, "%s:[%lu]",
51− ns_ops->name, inode->i_ino);
52−}
53−
54−const struct dentry_operations ns_dentry_operations =
55−{
56− .d_delete = always_delete_dentry,
57− .d_dname = ns_dname,
58−};
59−
60−static struct dentry *proc_ns_get_dentry(struct super_block *sb,
61− struct task_struct *task, const struct proc_ns_operations *ns_ops)
62−{
63− struct dentry *dentry, *result;
64− struct inode *inode;
65− struct proc_inode *ei;
66− struct qstr qname = { .name = "", };
67− struct ns_common *ns;
68−
69− ns = ns_ops->get(task);
70− if (!ns)
71− return ERR_PTR(-ENOENT);
72−
73− dentry = d_alloc_pseudo(sb, &qname);
74− if (!dentry) {
75− ns_ops->put(ns);
76− return ERR_PTR(-ENOMEM);
77− }
78− dentry->d_fsdata = (void *)ns_ops;
79−
80− inode = iget_locked(sb, ns->inum);
81− if (!inode) {
82− dput(dentry);
83− ns_ops->put(ns);
84− return ERR_PTR(-ENOMEM);
85− }
86−
87− ei = PROC_I(inode);
88− if (inode->i_state & I_NEW) {
89− inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME;
90− inode->i_op = &ns_inode_operations;
91− inode->i_mode = S_IFREG | S_IRUGO;
92− inode->i_fop = &ns_file_operations;
93− ei->ns.ns_ops = ns_ops;
94− ei->ns.ns = ns;
95− unlock_new_inode(inode);
96− } else {
97− ns_ops->put(ns);
98− }
99−
100− d_set_d_op(dentry, &ns_dentry_operations);
101− result = d_instantiate_unique(dentry, inode);
102− if (result) {
103− dput(dentry);
104− dentry = result;
105− }
106−
107− return dentry;
108−}
109−
11033 static void *proc_ns_follow_link(struct dentry *dentry, struct nameidata *nd)
11134 {
11235 struct inode *inode = dentry->d_inode;
113− struct super_block *sb = inode->i_sb;
114− struct proc_inode *ei = PROC_I(inode);
36+ const struct proc_ns_operations *ns_ops = PROC_I(inode)->ns.ns_ops;
11537 struct task_struct *task;
11638 struct path ns_path;
11739 void *error = ERR_PTR(-EACCES);
11840
11941 task = get_proc_task(inode);
12042 if (!task)
121− goto out;
43+ return error;
12244
123− if (!ptrace_may_access(task, PTRACE_MODE_READ))
124− goto out_put_task;
125−
126− ns_path.dentry = proc_ns_get_dentry(sb, task, ei->ns.ns_ops);
127− if (IS_ERR(ns_path.dentry)) {
128− error = ERR_CAST(ns_path.dentry);
129− goto out_put_task;
45+ if (ptrace_may_access(task, PTRACE_MODE_READ)) {
46+ error = ns_get_path(&ns_path, task, ns_ops);
47+ if (!error)
48+ nd_jump_link(nd, &ns_path);
13049 }
131−
132− ns_path.mnt = mntget(nd->path.mnt);
133− nd_jump_link(nd, &ns_path);
134− error = NULL;
135−
136−out_put_task:
13750 put_task_struct(task);
138−out:
13951 return error;
14052 }
14153
14254 static int proc_ns_readlink(struct dentry *dentry, char __user *buffer, int buflen)
14355 {
14456 struct inode *inode = dentry->d_inode;
145− struct proc_inode *ei = PROC_I(inode);
146− const struct proc_ns_operations *ns_ops = ei->ns.ns_ops;
57+ const struct proc_ns_operations *ns_ops = PROC_I(inode)->ns.ns_ops;
14758 struct task_struct *task;
148− struct ns_common *ns;
14959 char name[50];
15060 int res = -EACCES;
15161
15262 task = get_proc_task(inode);
15363 if (!task)
154− goto out;
155−
156− if (!ptrace_may_access(task, PTRACE_MODE_READ))
157− goto out_put_task;
64+ return res;
15865
159− res = -ENOENT;
160− ns = ns_ops->get(task);
161− if (!ns)
162− goto out_put_task;
163−
164− snprintf(name, sizeof(name), "%s:[%u]", ns_ops->name, ns->inum);
165− res = readlink_copy(buffer, buflen, name);
166− ns_ops->put(ns);
167−out_put_task:
66+ if (ptrace_may_access(task, PTRACE_MODE_READ)) {
67+ res = ns_get_name(name, sizeof(name), task, ns_ops);
68+ if (res >= 0)
69+ res = readlink_copy(buffer, buflen, name);
70+ }
16871 put_task_struct(task);
169−out:
17072 return res;
17173 }
17274
@@ -268,31 +170,3 @@ const struct inode_operations proc_ns_dir_inode_operations = { · 95 unmodified lines
268170 .getattr = pid_getattr,
269171 .setattr = proc_setattr,
270172 };
271−
272−struct file *proc_ns_fget(int fd)
273−{
274− struct file *file;
275−
276− file = fget(fd);
277− if (!file)
278− return ERR_PTR(-EBADF);
279−
280− if (file->f_op != &ns_file_operations)
281− goto out_invalid;
282−
283− return file;
284−
285−out_invalid:
286− fput(file);
287− return ERR_PTR(-EINVAL);
288−}
289−
290−struct ns_common *get_proc_ns(struct inode *inode)
291−{
292− return PROC_I(inode)->ns.ns;
293−}
294−
295−bool proc_ns_inode(struct inode *inode)
296−{
297− return inode->i_fop == &ns_file_operations;
298−}
include/linux/ns_common.h+1−0
@@ -4,6 +4,7 @@ · 3 unmodified lines
44 struct proc_ns_operations;
55
66 struct ns_common {
7+ atomic_long_t stashed;
78 const struct proc_ns_operations *ops;
89 unsigned int inum;
910 };
include/linux/proc_ns.h+18−13
@@ -4,9 +4,11 @@ · 3 unmodified lines
44 #ifndef _LINUX_PROC_NS_H
55 #define _LINUX_PROC_NS_H
66
7+#include <linux/ns_common.h>
8+
79 struct pid_namespace;
810 struct nsproxy;
9−struct ns_common;
11+struct path;
1012
1113 struct proc_ns_operations {
1214 const char *name;
@@ -38,35 +40,38 @@ enum { · 25 unmodified lines
3840
3941 extern int pid_ns_prepare_proc(struct pid_namespace *ns);
4042 extern void pid_ns_release_proc(struct pid_namespace *ns);
41−extern struct file *proc_ns_fget(int fd);
42−extern struct ns_common *get_proc_ns(struct inode *);
4343 extern int proc_alloc_inum(unsigned int *pino);
4444 extern void proc_free_inum(unsigned int inum);
45−extern bool proc_ns_inode(struct inode *inode);
4645
4746 #else /* CONFIG_PROC_FS */
4847
4948 static inline int pid_ns_prepare_proc(struct pid_namespace *ns) { return 0; }
5049 static inline void pid_ns_release_proc(struct pid_namespace *ns) {}
5150
52−static inline struct file *proc_ns_fget(int fd)
53−{
54− return ERR_PTR(-EINVAL);
55−}
56−
57−static inline struct ns_common *get_proc_ns(struct inode *inode) { return NULL; }
58−
5951 static inline int proc_alloc_inum(unsigned int *inum)
6052 {
6153 *inum = 1;
6254 return 0;
6355 }
6456 static inline void proc_free_inum(unsigned int inum) {}
65−static inline bool proc_ns_inode(struct inode *inode) { return false; }
6657
6758 #endif /* CONFIG_PROC_FS */
6859
69−#define ns_alloc_inum(ns) proc_alloc_inum(&(ns)->inum)
60+static inline int ns_alloc_inum(struct ns_common *ns)
61+{
62+ atomic_long_set(&ns->stashed, 0);
63+ return proc_alloc_inum(&ns->inum);
64+}
65+
7066 #define ns_free_inum(ns) proc_free_inum((ns)->inum)
7167
68+extern struct file *proc_ns_fget(int fd);
69+#define get_proc_ns(inode) ((struct ns_common *)(inode)->i_private)
70+extern void *ns_get_path(struct path *path, struct task_struct *task,
71+ const struct proc_ns_operations *ns_ops);
72+
73+extern int ns_get_name(char *buf, size_t size, struct task_struct *task,
74+ const struct proc_ns_operations *ns_ops);
75+extern void nsfs_init(void);
76+
7277 #endif /* _LINUX_PROC_NS_H */
include/uapi/linux/magic.h+1−0
@@ -72,5 +72,6 @@ · 71 unmodified lines
7272 #define MTD_INODE_FS_MAGIC 0x11307854
7373 #define ANON_INODE_FS_MAGIC 0x09041934
7474 #define BTRFS_TEST_MAGIC 0x73727279
75+#define NSFS_MAGIC 0x6e736673
7576
7677 #endif /* __LINUX_MAGIC_H__ */
init/main.c+2−0
@@ -78,6 +78,7 @@ · 77 unmodified lines
7878 #include <linux/context_tracking.h>
7979 #include <linux/random.h>
8080 #include <linux/list.h>
81+#include <linux/proc_ns.h>
8182
8283 #include <asm/io.h>
8384 #include <asm/bugs.h>
@@ -660,6 +661,7 @@ asmlinkage __visible void __init start_kernel(void) · 576 unmodified lines
660661 /* rootfs populating might need page-writeback */
661662 page_writeback_init();
662663 proc_root_init();
664+ nsfs_init();
663665 cgroup_init();
664666 cpuset_init();
665667 taskstats_init_early();