aboutsummaryrefslogtreecommitdiffstats
path: root/fs
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2011-03-09 16:55:51 -0500
committerLinus Torvalds <torvalds@linux-foundation.org>2011-03-09 16:55:51 -0500
commit78833dd70602be6b71ef34225f708b1e500947dc (patch)
tree807050f760ccc7305b194d7568ebf98737076a40 /fs
parenta5abba989deceb731047425812d268daf7536575 (diff)
parentb306419ae08d9def53f2142a37cc0a58622307a8 (diff)
Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs-2.6
* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs-2.6: nd->inode is not set on the second attempt in path_walk() unfuck proc_sysctl ->d_compare() minimal fix for do_filp_open() race
Diffstat (limited to 'fs')
-rw-r--r--fs/namei.c14
-rw-r--r--fs/proc/inode.c8
-rw-r--r--fs/proc/proc_sysctl.c7
3 files changed, 22 insertions, 7 deletions
diff --git a/fs/namei.c b/fs/namei.c
index 0087cf9c2c6b..a4689eb2df28 100644
--- a/fs/namei.c
+++ b/fs/namei.c
@@ -1546,6 +1546,7 @@ static int path_walk(const char *name, struct nameidata *nd)
1546 /* nd->path had been dropped */ 1546 /* nd->path had been dropped */
1547 current->total_link_count = 0; 1547 current->total_link_count = 0;
1548 nd->path = save; 1548 nd->path = save;
1549 nd->inode = save.dentry->d_inode;
1549 path_get(&nd->path); 1550 path_get(&nd->path);
1550 nd->flags |= LOOKUP_REVAL; 1551 nd->flags |= LOOKUP_REVAL;
1551 result = link_path_walk(name, nd); 1552 result = link_path_walk(name, nd);
@@ -2455,22 +2456,29 @@ struct file *do_filp_open(int dfd, const char *pathname,
2455 /* !O_CREAT, simple open */ 2456 /* !O_CREAT, simple open */
2456 error = do_path_lookup(dfd, pathname, flags, &nd); 2457 error = do_path_lookup(dfd, pathname, flags, &nd);
2457 if (unlikely(error)) 2458 if (unlikely(error))
2458 goto out_filp; 2459 goto out_filp2;
2459 error = -ELOOP; 2460 error = -ELOOP;
2460 if (!(nd.flags & LOOKUP_FOLLOW)) { 2461 if (!(nd.flags & LOOKUP_FOLLOW)) {
2461 if (nd.inode->i_op->follow_link) 2462 if (nd.inode->i_op->follow_link)
2462 goto out_path; 2463 goto out_path2;
2463 } 2464 }
2464 error = -ENOTDIR; 2465 error = -ENOTDIR;
2465 if (nd.flags & LOOKUP_DIRECTORY) { 2466 if (nd.flags & LOOKUP_DIRECTORY) {
2466 if (!nd.inode->i_op->lookup) 2467 if (!nd.inode->i_op->lookup)
2467 goto out_path; 2468 goto out_path2;
2468 } 2469 }
2469 audit_inode(pathname, nd.path.dentry); 2470 audit_inode(pathname, nd.path.dentry);
2470 filp = finish_open(&nd, open_flag, acc_mode); 2471 filp = finish_open(&nd, open_flag, acc_mode);
2472out2:
2471 release_open_intent(&nd); 2473 release_open_intent(&nd);
2472 return filp; 2474 return filp;
2473 2475
2476out_path2:
2477 path_put(&nd.path);
2478out_filp2:
2479 filp = ERR_PTR(error);
2480 goto out2;
2481
2474creat: 2482creat:
2475 /* OK, have to create the file. Find the parent. */ 2483 /* OK, have to create the file. Find the parent. */
2476 error = path_init_rcu(dfd, pathname, 2484 error = path_init_rcu(dfd, pathname,
diff --git a/fs/proc/inode.c b/fs/proc/inode.c
index 176ce4cda68a..d6a7ca1fdac5 100644
--- a/fs/proc/inode.c
+++ b/fs/proc/inode.c
@@ -27,6 +27,7 @@
27static void proc_evict_inode(struct inode *inode) 27static void proc_evict_inode(struct inode *inode)
28{ 28{
29 struct proc_dir_entry *de; 29 struct proc_dir_entry *de;
30 struct ctl_table_header *head;
30 31
31 truncate_inode_pages(&inode->i_data, 0); 32 truncate_inode_pages(&inode->i_data, 0);
32 end_writeback(inode); 33 end_writeback(inode);
@@ -38,8 +39,11 @@ static void proc_evict_inode(struct inode *inode)
38 de = PROC_I(inode)->pde; 39 de = PROC_I(inode)->pde;
39 if (de) 40 if (de)
40 pde_put(de); 41 pde_put(de);
41 if (PROC_I(inode)->sysctl) 42 head = PROC_I(inode)->sysctl;
42 sysctl_head_put(PROC_I(inode)->sysctl); 43 if (head) {
44 rcu_assign_pointer(PROC_I(inode)->sysctl, NULL);
45 sysctl_head_put(head);
46 }
43} 47}
44 48
45struct vfsmount *proc_mnt; 49struct vfsmount *proc_mnt;
diff --git a/fs/proc/proc_sysctl.c b/fs/proc/proc_sysctl.c
index 09a1f92a34ef..8eb2522111c5 100644
--- a/fs/proc/proc_sysctl.c
+++ b/fs/proc/proc_sysctl.c
@@ -408,15 +408,18 @@ static int proc_sys_compare(const struct dentry *parent,
408 const struct dentry *dentry, const struct inode *inode, 408 const struct dentry *dentry, const struct inode *inode,
409 unsigned int len, const char *str, const struct qstr *name) 409 unsigned int len, const char *str, const struct qstr *name)
410{ 410{
411 struct ctl_table_header *head;
411 /* Although proc doesn't have negative dentries, rcu-walk means 412 /* Although proc doesn't have negative dentries, rcu-walk means
412 * that inode here can be NULL */ 413 * that inode here can be NULL */
414 /* AV: can it, indeed? */
413 if (!inode) 415 if (!inode)
414 return 0; 416 return 1;
415 if (name->len != len) 417 if (name->len != len)
416 return 1; 418 return 1;
417 if (memcmp(name->name, str, len)) 419 if (memcmp(name->name, str, len))
418 return 1; 420 return 1;
419 return !sysctl_is_seen(PROC_I(inode)->sysctl); 421 head = rcu_dereference(PROC_I(inode)->sysctl);
422 return !head || !sysctl_is_seen(head);
420} 423}
421 424
422static const struct dentry_operations proc_sys_dentry_operations = { 425static const struct dentry_operations proc_sys_dentry_operations = {