diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2011-03-09 13:55:51 -0800 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2011-03-09 13:55:51 -0800 |
commit | 78833dd70602be6b71ef34225f708b1e500947dc (patch) | |
tree | 807050f760ccc7305b194d7568ebf98737076a40 /fs | |
parent | a5abba989deceb731047425812d268daf7536575 (diff) | |
parent | b306419ae08d9def53f2142a37cc0a58622307a8 (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.c | 14 | ||||
-rw-r--r-- | fs/proc/inode.c | 8 | ||||
-rw-r--r-- | fs/proc/proc_sysctl.c | 7 |
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) /* nd->path had been dropped */ current->total_link_count = 0; nd->path = save; + nd->inode = save.dentry->d_inode; path_get(&nd->path); nd->flags |= LOOKUP_REVAL; result = link_path_walk(name, nd); @@ -2455,22 +2456,29 @@ struct file *do_filp_open(int dfd, const char *pathname, /* !O_CREAT, simple open */ error = do_path_lookup(dfd, pathname, flags, &nd); if (unlikely(error)) - goto out_filp; + goto out_filp2; error = -ELOOP; if (!(nd.flags & LOOKUP_FOLLOW)) { if (nd.inode->i_op->follow_link) - goto out_path; + goto out_path2; } error = -ENOTDIR; if (nd.flags & LOOKUP_DIRECTORY) { if (!nd.inode->i_op->lookup) - goto out_path; + goto out_path2; } audit_inode(pathname, nd.path.dentry); filp = finish_open(&nd, open_flag, acc_mode); +out2: release_open_intent(&nd); return filp; +out_path2: + path_put(&nd.path); +out_filp2: + filp = ERR_PTR(error); + goto out2; + creat: /* OK, have to create the file. Find the parent. */ 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 @@ static void proc_evict_inode(struct inode *inode) { struct proc_dir_entry *de; + struct ctl_table_header *head; truncate_inode_pages(&inode->i_data, 0); end_writeback(inode); @@ -38,8 +39,11 @@ static void proc_evict_inode(struct inode *inode) de = PROC_I(inode)->pde; if (de) pde_put(de); - if (PROC_I(inode)->sysctl) - sysctl_head_put(PROC_I(inode)->sysctl); + head = PROC_I(inode)->sysctl; + if (head) { + rcu_assign_pointer(PROC_I(inode)->sysctl, NULL); + sysctl_head_put(head); + } } struct 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, const struct dentry *dentry, const struct inode *inode, unsigned int len, const char *str, const struct qstr *name) { + struct ctl_table_header *head; /* Although proc doesn't have negative dentries, rcu-walk means * that inode here can be NULL */ + /* AV: can it, indeed? */ if (!inode) - return 0; + return 1; if (name->len != len) return 1; if (memcmp(name->name, str, len)) return 1; - return !sysctl_is_seen(PROC_I(inode)->sysctl); + head = rcu_dereference(PROC_I(inode)->sysctl); + return !head || !sysctl_is_seen(head); } static const struct dentry_operations proc_sys_dentry_operations = { |