diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2011-01-07 11:56:33 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2011-01-07 11:56:33 -0500 |
commit | b4a45f5fe8078bfc10837dbd5b98735058bc4698 (patch) | |
tree | df6f13a27610a3ec7eb4a661448cd779a8f84c79 /fs/proc | |
parent | 01539ba2a706ab7d35fc0667dff919ade7f87d63 (diff) | |
parent | b3e19d924b6eaf2ca7d22cba99a517c5171007b6 (diff) |
Merge branch 'vfs-scale-working' of git://git.kernel.org/pub/scm/linux/kernel/git/npiggin/linux-npiggin
* 'vfs-scale-working' of git://git.kernel.org/pub/scm/linux/kernel/git/npiggin/linux-npiggin: (57 commits)
fs: scale mntget/mntput
fs: rename vfsmount counter helpers
fs: implement faster dentry memcmp
fs: prefetch inode data in dcache lookup
fs: improve scalability of pseudo filesystems
fs: dcache per-inode inode alias locking
fs: dcache per-bucket dcache hash locking
bit_spinlock: add required includes
kernel: add bl_list
xfs: provide simple rcu-walk ACL implementation
btrfs: provide simple rcu-walk ACL implementation
ext2,3,4: provide simple rcu-walk ACL implementation
fs: provide simple rcu-walk generic_check_acl implementation
fs: provide rcu-walk aware permission i_ops
fs: rcu-walk aware d_revalidate method
fs: cache optimise dentry and inode for rcu-walk
fs: dcache reduce branches in lookup path
fs: dcache remove d_mounted
fs: fs_struct use seqlock
fs: rcu-walk for path lookup
...
Diffstat (limited to 'fs/proc')
-rw-r--r-- | fs/proc/base.c | 53 | ||||
-rw-r--r-- | fs/proc/generic.c | 4 | ||||
-rw-r--r-- | fs/proc/inode.c | 9 | ||||
-rw-r--r-- | fs/proc/proc_sysctl.c | 31 |
4 files changed, 68 insertions, 29 deletions
diff --git a/fs/proc/base.c b/fs/proc/base.c index 08cba2c3b612..b20962c71a52 100644 --- a/fs/proc/base.c +++ b/fs/proc/base.c | |||
@@ -1795,10 +1795,16 @@ static int pid_getattr(struct vfsmount *mnt, struct dentry *dentry, struct kstat | |||
1795 | */ | 1795 | */ |
1796 | static int pid_revalidate(struct dentry *dentry, struct nameidata *nd) | 1796 | static int pid_revalidate(struct dentry *dentry, struct nameidata *nd) |
1797 | { | 1797 | { |
1798 | struct inode *inode = dentry->d_inode; | 1798 | struct inode *inode; |
1799 | struct task_struct *task = get_proc_task(inode); | 1799 | struct task_struct *task; |
1800 | const struct cred *cred; | 1800 | const struct cred *cred; |
1801 | 1801 | ||
1802 | if (nd && nd->flags & LOOKUP_RCU) | ||
1803 | return -ECHILD; | ||
1804 | |||
1805 | inode = dentry->d_inode; | ||
1806 | task = get_proc_task(inode); | ||
1807 | |||
1802 | if (task) { | 1808 | if (task) { |
1803 | if ((inode->i_mode == (S_IFDIR|S_IRUGO|S_IXUGO)) || | 1809 | if ((inode->i_mode == (S_IFDIR|S_IRUGO|S_IXUGO)) || |
1804 | task_dumpable(task)) { | 1810 | task_dumpable(task)) { |
@@ -1820,7 +1826,7 @@ static int pid_revalidate(struct dentry *dentry, struct nameidata *nd) | |||
1820 | return 0; | 1826 | return 0; |
1821 | } | 1827 | } |
1822 | 1828 | ||
1823 | static int pid_delete_dentry(struct dentry * dentry) | 1829 | static int pid_delete_dentry(const struct dentry * dentry) |
1824 | { | 1830 | { |
1825 | /* Is the task we represent dead? | 1831 | /* Is the task we represent dead? |
1826 | * If so, then don't put the dentry on the lru list, | 1832 | * If so, then don't put the dentry on the lru list, |
@@ -1964,12 +1970,19 @@ static int proc_fd_link(struct inode *inode, struct path *path) | |||
1964 | 1970 | ||
1965 | static int tid_fd_revalidate(struct dentry *dentry, struct nameidata *nd) | 1971 | static int tid_fd_revalidate(struct dentry *dentry, struct nameidata *nd) |
1966 | { | 1972 | { |
1967 | struct inode *inode = dentry->d_inode; | 1973 | struct inode *inode; |
1968 | struct task_struct *task = get_proc_task(inode); | 1974 | struct task_struct *task; |
1969 | int fd = proc_fd(inode); | 1975 | int fd; |
1970 | struct files_struct *files; | 1976 | struct files_struct *files; |
1971 | const struct cred *cred; | 1977 | const struct cred *cred; |
1972 | 1978 | ||
1979 | if (nd && nd->flags & LOOKUP_RCU) | ||
1980 | return -ECHILD; | ||
1981 | |||
1982 | inode = dentry->d_inode; | ||
1983 | task = get_proc_task(inode); | ||
1984 | fd = proc_fd(inode); | ||
1985 | |||
1973 | if (task) { | 1986 | if (task) { |
1974 | files = get_files_struct(task); | 1987 | files = get_files_struct(task); |
1975 | if (files) { | 1988 | if (files) { |
@@ -2045,7 +2058,7 @@ static struct dentry *proc_fd_instantiate(struct inode *dir, | |||
2045 | inode->i_op = &proc_pid_link_inode_operations; | 2058 | inode->i_op = &proc_pid_link_inode_operations; |
2046 | inode->i_size = 64; | 2059 | inode->i_size = 64; |
2047 | ei->op.proc_get_link = proc_fd_link; | 2060 | ei->op.proc_get_link = proc_fd_link; |
2048 | dentry->d_op = &tid_fd_dentry_operations; | 2061 | d_set_d_op(dentry, &tid_fd_dentry_operations); |
2049 | d_add(dentry, inode); | 2062 | d_add(dentry, inode); |
2050 | /* Close the race of the process dying before we return the dentry */ | 2063 | /* Close the race of the process dying before we return the dentry */ |
2051 | if (tid_fd_revalidate(dentry, NULL)) | 2064 | if (tid_fd_revalidate(dentry, NULL)) |
@@ -2177,11 +2190,13 @@ static const struct file_operations proc_fd_operations = { | |||
2177 | * /proc/pid/fd needs a special permission handler so that a process can still | 2190 | * /proc/pid/fd needs a special permission handler so that a process can still |
2178 | * access /proc/self/fd after it has executed a setuid(). | 2191 | * access /proc/self/fd after it has executed a setuid(). |
2179 | */ | 2192 | */ |
2180 | static int proc_fd_permission(struct inode *inode, int mask) | 2193 | static int proc_fd_permission(struct inode *inode, int mask, unsigned int flags) |
2181 | { | 2194 | { |
2182 | int rv; | 2195 | int rv; |
2183 | 2196 | ||
2184 | rv = generic_permission(inode, mask, NULL); | 2197 | if (flags & IPERM_FLAG_RCU) |
2198 | return -ECHILD; | ||
2199 | rv = generic_permission(inode, mask, flags, NULL); | ||
2185 | if (rv == 0) | 2200 | if (rv == 0) |
2186 | return 0; | 2201 | return 0; |
2187 | if (task_pid(current) == proc_pid(inode)) | 2202 | if (task_pid(current) == proc_pid(inode)) |
@@ -2213,7 +2228,7 @@ static struct dentry *proc_fdinfo_instantiate(struct inode *dir, | |||
2213 | ei->fd = fd; | 2228 | ei->fd = fd; |
2214 | inode->i_mode = S_IFREG | S_IRUSR; | 2229 | inode->i_mode = S_IFREG | S_IRUSR; |
2215 | inode->i_fop = &proc_fdinfo_file_operations; | 2230 | inode->i_fop = &proc_fdinfo_file_operations; |
2216 | dentry->d_op = &tid_fd_dentry_operations; | 2231 | d_set_d_op(dentry, &tid_fd_dentry_operations); |
2217 | d_add(dentry, inode); | 2232 | d_add(dentry, inode); |
2218 | /* Close the race of the process dying before we return the dentry */ | 2233 | /* Close the race of the process dying before we return the dentry */ |
2219 | if (tid_fd_revalidate(dentry, NULL)) | 2234 | if (tid_fd_revalidate(dentry, NULL)) |
@@ -2272,7 +2287,7 @@ static struct dentry *proc_pident_instantiate(struct inode *dir, | |||
2272 | if (p->fop) | 2287 | if (p->fop) |
2273 | inode->i_fop = p->fop; | 2288 | inode->i_fop = p->fop; |
2274 | ei->op = p->op; | 2289 | ei->op = p->op; |
2275 | dentry->d_op = &pid_dentry_operations; | 2290 | d_set_d_op(dentry, &pid_dentry_operations); |
2276 | d_add(dentry, inode); | 2291 | d_add(dentry, inode); |
2277 | /* Close the race of the process dying before we return the dentry */ | 2292 | /* Close the race of the process dying before we return the dentry */ |
2278 | if (pid_revalidate(dentry, NULL)) | 2293 | if (pid_revalidate(dentry, NULL)) |
@@ -2639,8 +2654,14 @@ static const struct pid_entry proc_base_stuff[] = { | |||
2639 | */ | 2654 | */ |
2640 | static int proc_base_revalidate(struct dentry *dentry, struct nameidata *nd) | 2655 | static int proc_base_revalidate(struct dentry *dentry, struct nameidata *nd) |
2641 | { | 2656 | { |
2642 | struct inode *inode = dentry->d_inode; | 2657 | struct inode *inode; |
2643 | struct task_struct *task = get_proc_task(inode); | 2658 | struct task_struct *task; |
2659 | |||
2660 | if (nd->flags & LOOKUP_RCU) | ||
2661 | return -ECHILD; | ||
2662 | |||
2663 | inode = dentry->d_inode; | ||
2664 | task = get_proc_task(inode); | ||
2644 | if (task) { | 2665 | if (task) { |
2645 | put_task_struct(task); | 2666 | put_task_struct(task); |
2646 | return 1; | 2667 | return 1; |
@@ -2691,7 +2712,7 @@ static struct dentry *proc_base_instantiate(struct inode *dir, | |||
2691 | if (p->fop) | 2712 | if (p->fop) |
2692 | inode->i_fop = p->fop; | 2713 | inode->i_fop = p->fop; |
2693 | ei->op = p->op; | 2714 | ei->op = p->op; |
2694 | dentry->d_op = &proc_base_dentry_operations; | 2715 | d_set_d_op(dentry, &proc_base_dentry_operations); |
2695 | d_add(dentry, inode); | 2716 | d_add(dentry, inode); |
2696 | error = NULL; | 2717 | error = NULL; |
2697 | out: | 2718 | out: |
@@ -3005,7 +3026,7 @@ static struct dentry *proc_pid_instantiate(struct inode *dir, | |||
3005 | inode->i_nlink = 2 + pid_entry_count_dirs(tgid_base_stuff, | 3026 | inode->i_nlink = 2 + pid_entry_count_dirs(tgid_base_stuff, |
3006 | ARRAY_SIZE(tgid_base_stuff)); | 3027 | ARRAY_SIZE(tgid_base_stuff)); |
3007 | 3028 | ||
3008 | dentry->d_op = &pid_dentry_operations; | 3029 | d_set_d_op(dentry, &pid_dentry_operations); |
3009 | 3030 | ||
3010 | d_add(dentry, inode); | 3031 | d_add(dentry, inode); |
3011 | /* Close the race of the process dying before we return the dentry */ | 3032 | /* Close the race of the process dying before we return the dentry */ |
@@ -3248,7 +3269,7 @@ static struct dentry *proc_task_instantiate(struct inode *dir, | |||
3248 | inode->i_nlink = 2 + pid_entry_count_dirs(tid_base_stuff, | 3269 | inode->i_nlink = 2 + pid_entry_count_dirs(tid_base_stuff, |
3249 | ARRAY_SIZE(tid_base_stuff)); | 3270 | ARRAY_SIZE(tid_base_stuff)); |
3250 | 3271 | ||
3251 | dentry->d_op = &pid_dentry_operations; | 3272 | d_set_d_op(dentry, &pid_dentry_operations); |
3252 | 3273 | ||
3253 | d_add(dentry, inode); | 3274 | d_add(dentry, inode); |
3254 | /* Close the race of the process dying before we return the dentry */ | 3275 | /* Close the race of the process dying before we return the dentry */ |
diff --git a/fs/proc/generic.c b/fs/proc/generic.c index dd29f0337661..f766be29d2c7 100644 --- a/fs/proc/generic.c +++ b/fs/proc/generic.c | |||
@@ -400,7 +400,7 @@ static const struct inode_operations proc_link_inode_operations = { | |||
400 | * smarter: we could keep a "volatile" flag in the | 400 | * smarter: we could keep a "volatile" flag in the |
401 | * inode to indicate which ones to keep. | 401 | * inode to indicate which ones to keep. |
402 | */ | 402 | */ |
403 | static int proc_delete_dentry(struct dentry * dentry) | 403 | static int proc_delete_dentry(const struct dentry * dentry) |
404 | { | 404 | { |
405 | return 1; | 405 | return 1; |
406 | } | 406 | } |
@@ -439,7 +439,7 @@ struct dentry *proc_lookup_de(struct proc_dir_entry *de, struct inode *dir, | |||
439 | out_unlock: | 439 | out_unlock: |
440 | 440 | ||
441 | if (inode) { | 441 | if (inode) { |
442 | dentry->d_op = &proc_dentry_operations; | 442 | d_set_d_op(dentry, &proc_dentry_operations); |
443 | d_add(dentry, inode); | 443 | d_add(dentry, inode); |
444 | return NULL; | 444 | return NULL; |
445 | } | 445 | } |
diff --git a/fs/proc/inode.c b/fs/proc/inode.c index 3ddb6068177c..6bcb926b101b 100644 --- a/fs/proc/inode.c +++ b/fs/proc/inode.c | |||
@@ -65,11 +65,18 @@ static struct inode *proc_alloc_inode(struct super_block *sb) | |||
65 | return inode; | 65 | return inode; |
66 | } | 66 | } |
67 | 67 | ||
68 | static void proc_destroy_inode(struct inode *inode) | 68 | static void proc_i_callback(struct rcu_head *head) |
69 | { | 69 | { |
70 | struct inode *inode = container_of(head, struct inode, i_rcu); | ||
71 | INIT_LIST_HEAD(&inode->i_dentry); | ||
70 | kmem_cache_free(proc_inode_cachep, PROC_I(inode)); | 72 | kmem_cache_free(proc_inode_cachep, PROC_I(inode)); |
71 | } | 73 | } |
72 | 74 | ||
75 | static void proc_destroy_inode(struct inode *inode) | ||
76 | { | ||
77 | call_rcu(&inode->i_rcu, proc_i_callback); | ||
78 | } | ||
79 | |||
73 | static void init_once(void *foo) | 80 | static void init_once(void *foo) |
74 | { | 81 | { |
75 | struct proc_inode *ei = (struct proc_inode *) foo; | 82 | struct proc_inode *ei = (struct proc_inode *) foo; |
diff --git a/fs/proc/proc_sysctl.c b/fs/proc/proc_sysctl.c index b652cb00906b..09a1f92a34ef 100644 --- a/fs/proc/proc_sysctl.c +++ b/fs/proc/proc_sysctl.c | |||
@@ -5,6 +5,7 @@ | |||
5 | #include <linux/sysctl.h> | 5 | #include <linux/sysctl.h> |
6 | #include <linux/proc_fs.h> | 6 | #include <linux/proc_fs.h> |
7 | #include <linux/security.h> | 7 | #include <linux/security.h> |
8 | #include <linux/namei.h> | ||
8 | #include "internal.h" | 9 | #include "internal.h" |
9 | 10 | ||
10 | static const struct dentry_operations proc_sys_dentry_operations; | 11 | static const struct dentry_operations proc_sys_dentry_operations; |
@@ -120,7 +121,7 @@ static struct dentry *proc_sys_lookup(struct inode *dir, struct dentry *dentry, | |||
120 | goto out; | 121 | goto out; |
121 | 122 | ||
122 | err = NULL; | 123 | err = NULL; |
123 | dentry->d_op = &proc_sys_dentry_operations; | 124 | d_set_d_op(dentry, &proc_sys_dentry_operations); |
124 | d_add(dentry, inode); | 125 | d_add(dentry, inode); |
125 | 126 | ||
126 | out: | 127 | out: |
@@ -201,7 +202,7 @@ static int proc_sys_fill_cache(struct file *filp, void *dirent, | |||
201 | dput(child); | 202 | dput(child); |
202 | return -ENOMEM; | 203 | return -ENOMEM; |
203 | } else { | 204 | } else { |
204 | child->d_op = &proc_sys_dentry_operations; | 205 | d_set_d_op(child, &proc_sys_dentry_operations); |
205 | d_add(child, inode); | 206 | d_add(child, inode); |
206 | } | 207 | } |
207 | } else { | 208 | } else { |
@@ -294,7 +295,7 @@ out: | |||
294 | return ret; | 295 | return ret; |
295 | } | 296 | } |
296 | 297 | ||
297 | static int proc_sys_permission(struct inode *inode, int mask) | 298 | static int proc_sys_permission(struct inode *inode, int mask,unsigned int flags) |
298 | { | 299 | { |
299 | /* | 300 | /* |
300 | * sysctl entries that are not writeable, | 301 | * sysctl entries that are not writeable, |
@@ -304,6 +305,9 @@ static int proc_sys_permission(struct inode *inode, int mask) | |||
304 | struct ctl_table *table; | 305 | struct ctl_table *table; |
305 | int error; | 306 | int error; |
306 | 307 | ||
308 | if (flags & IPERM_FLAG_RCU) | ||
309 | return -ECHILD; | ||
310 | |||
307 | /* Executable files are not allowed under /proc/sys/ */ | 311 | /* Executable files are not allowed under /proc/sys/ */ |
308 | if ((mask & MAY_EXEC) && S_ISREG(inode->i_mode)) | 312 | if ((mask & MAY_EXEC) && S_ISREG(inode->i_mode)) |
309 | return -EACCES; | 313 | return -EACCES; |
@@ -389,23 +393,30 @@ static const struct inode_operations proc_sys_dir_operations = { | |||
389 | 393 | ||
390 | static int proc_sys_revalidate(struct dentry *dentry, struct nameidata *nd) | 394 | static int proc_sys_revalidate(struct dentry *dentry, struct nameidata *nd) |
391 | { | 395 | { |
396 | if (nd->flags & LOOKUP_RCU) | ||
397 | return -ECHILD; | ||
392 | return !PROC_I(dentry->d_inode)->sysctl->unregistering; | 398 | return !PROC_I(dentry->d_inode)->sysctl->unregistering; |
393 | } | 399 | } |
394 | 400 | ||
395 | static int proc_sys_delete(struct dentry *dentry) | 401 | static int proc_sys_delete(const struct dentry *dentry) |
396 | { | 402 | { |
397 | return !!PROC_I(dentry->d_inode)->sysctl->unregistering; | 403 | return !!PROC_I(dentry->d_inode)->sysctl->unregistering; |
398 | } | 404 | } |
399 | 405 | ||
400 | static int proc_sys_compare(struct dentry *dir, struct qstr *qstr, | 406 | static int proc_sys_compare(const struct dentry *parent, |
401 | struct qstr *name) | 407 | const struct inode *pinode, |
408 | const struct dentry *dentry, const struct inode *inode, | ||
409 | unsigned int len, const char *str, const struct qstr *name) | ||
402 | { | 410 | { |
403 | struct dentry *dentry = container_of(qstr, struct dentry, d_name); | 411 | /* Although proc doesn't have negative dentries, rcu-walk means |
404 | if (qstr->len != name->len) | 412 | * that inode here can be NULL */ |
413 | if (!inode) | ||
414 | return 0; | ||
415 | if (name->len != len) | ||
405 | return 1; | 416 | return 1; |
406 | if (memcmp(qstr->name, name->name, name->len)) | 417 | if (memcmp(name->name, str, len)) |
407 | return 1; | 418 | return 1; |
408 | return !sysctl_is_seen(PROC_I(dentry->d_inode)->sysctl); | 419 | return !sysctl_is_seen(PROC_I(inode)->sysctl); |
409 | } | 420 | } |
410 | 421 | ||
411 | static const struct dentry_operations proc_sys_dentry_operations = { | 422 | static const struct dentry_operations proc_sys_dentry_operations = { |