diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2012-12-01 16:29:55 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2012-12-01 16:29:55 -0500 |
commit | 331fee3cd31c3ec3641062ca01a71b79dbf58b40 (patch) | |
tree | 90fa1a59b0256c82f95853f60b5e551431a1eb43 | |
parent | b3c3a9cf2a28ee4a8d0b62e2e58c61e9ca9bb47b (diff) | |
parent | a77cfcb429ed98845a4e4df72473b8f37acd890b (diff) |
Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs
Pull vfs fixes from Al Viro:
"A bunch of fixes; the last one is this cycle regression, the rest are
-stable fodder."
* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs:
fix off-by-one in argument passed by iterate_fd() to callbacks
lookup_one_len: don't accept . and ..
cifs: get rid of blind d_drop() in readdir
nfs_lookup_revalidate(): fix a leak
don't do blind d_drop() in nfs_prime_dcache()
-rw-r--r-- | fs/cifs/readdir.c | 5 | ||||
-rw-r--r-- | fs/file.c | 14 | ||||
-rw-r--r-- | fs/namei.c | 5 | ||||
-rw-r--r-- | fs/nfs/dir.c | 7 |
4 files changed, 21 insertions, 10 deletions
diff --git a/fs/cifs/readdir.c b/fs/cifs/readdir.c index f9b5d3d6cf33..1c576e871366 100644 --- a/fs/cifs/readdir.c +++ b/fs/cifs/readdir.c | |||
@@ -86,14 +86,17 @@ cifs_readdir_lookup(struct dentry *parent, struct qstr *name, | |||
86 | 86 | ||
87 | dentry = d_lookup(parent, name); | 87 | dentry = d_lookup(parent, name); |
88 | if (dentry) { | 88 | if (dentry) { |
89 | int err; | ||
89 | inode = dentry->d_inode; | 90 | inode = dentry->d_inode; |
90 | /* update inode in place if i_ino didn't change */ | 91 | /* update inode in place if i_ino didn't change */ |
91 | if (inode && CIFS_I(inode)->uniqueid == fattr->cf_uniqueid) { | 92 | if (inode && CIFS_I(inode)->uniqueid == fattr->cf_uniqueid) { |
92 | cifs_fattr_to_inode(inode, fattr); | 93 | cifs_fattr_to_inode(inode, fattr); |
93 | return dentry; | 94 | return dentry; |
94 | } | 95 | } |
95 | d_drop(dentry); | 96 | err = d_invalidate(dentry); |
96 | dput(dentry); | 97 | dput(dentry); |
98 | if (err) | ||
99 | return NULL; | ||
97 | } | 100 | } |
98 | 101 | ||
99 | dentry = d_alloc(parent, name); | 102 | dentry = d_alloc(parent, name); |
@@ -994,16 +994,18 @@ int iterate_fd(struct files_struct *files, unsigned n, | |||
994 | const void *p) | 994 | const void *p) |
995 | { | 995 | { |
996 | struct fdtable *fdt; | 996 | struct fdtable *fdt; |
997 | struct file *file; | ||
998 | int res = 0; | 997 | int res = 0; |
999 | if (!files) | 998 | if (!files) |
1000 | return 0; | 999 | return 0; |
1001 | spin_lock(&files->file_lock); | 1000 | spin_lock(&files->file_lock); |
1002 | fdt = files_fdtable(files); | 1001 | for (fdt = files_fdtable(files); n < fdt->max_fds; n++) { |
1003 | while (!res && n < fdt->max_fds) { | 1002 | struct file *file; |
1004 | file = rcu_dereference_check_fdtable(files, fdt->fd[n++]); | 1003 | file = rcu_dereference_check_fdtable(files, fdt->fd[n]); |
1005 | if (file) | 1004 | if (!file) |
1006 | res = f(p, file, n); | 1005 | continue; |
1006 | res = f(p, file, n); | ||
1007 | if (res) | ||
1008 | break; | ||
1007 | } | 1009 | } |
1008 | spin_unlock(&files->file_lock); | 1010 | spin_unlock(&files->file_lock); |
1009 | return res; | 1011 | return res; |
diff --git a/fs/namei.c b/fs/namei.c index 937f9d50c84b..5f4cdf3ad913 100644 --- a/fs/namei.c +++ b/fs/namei.c | |||
@@ -2131,6 +2131,11 @@ struct dentry *lookup_one_len(const char *name, struct dentry *base, int len) | |||
2131 | if (!len) | 2131 | if (!len) |
2132 | return ERR_PTR(-EACCES); | 2132 | return ERR_PTR(-EACCES); |
2133 | 2133 | ||
2134 | if (unlikely(name[0] == '.')) { | ||
2135 | if (len < 2 || (len == 2 && name[1] == '.')) | ||
2136 | return ERR_PTR(-EACCES); | ||
2137 | } | ||
2138 | |||
2134 | while (len--) { | 2139 | while (len--) { |
2135 | c = *(const unsigned char *)name++; | 2140 | c = *(const unsigned char *)name++; |
2136 | if (c == '/' || c == '\0') | 2141 | if (c == '/' || c == '\0') |
diff --git a/fs/nfs/dir.c b/fs/nfs/dir.c index ce8cb926526b..b9e66b7e0c14 100644 --- a/fs/nfs/dir.c +++ b/fs/nfs/dir.c | |||
@@ -450,7 +450,8 @@ void nfs_prime_dcache(struct dentry *parent, struct nfs_entry *entry) | |||
450 | nfs_refresh_inode(dentry->d_inode, entry->fattr); | 450 | nfs_refresh_inode(dentry->d_inode, entry->fattr); |
451 | goto out; | 451 | goto out; |
452 | } else { | 452 | } else { |
453 | d_drop(dentry); | 453 | if (d_invalidate(dentry) != 0) |
454 | goto out; | ||
454 | dput(dentry); | 455 | dput(dentry); |
455 | } | 456 | } |
456 | } | 457 | } |
@@ -1100,6 +1101,8 @@ out_set_verifier: | |||
1100 | out_zap_parent: | 1101 | out_zap_parent: |
1101 | nfs_zap_caches(dir); | 1102 | nfs_zap_caches(dir); |
1102 | out_bad: | 1103 | out_bad: |
1104 | nfs_free_fattr(fattr); | ||
1105 | nfs_free_fhandle(fhandle); | ||
1103 | nfs_mark_for_revalidate(dir); | 1106 | nfs_mark_for_revalidate(dir); |
1104 | if (inode && S_ISDIR(inode->i_mode)) { | 1107 | if (inode && S_ISDIR(inode->i_mode)) { |
1105 | /* Purge readdir caches. */ | 1108 | /* Purge readdir caches. */ |
@@ -1112,8 +1115,6 @@ out_zap_parent: | |||
1112 | shrink_dcache_parent(dentry); | 1115 | shrink_dcache_parent(dentry); |
1113 | } | 1116 | } |
1114 | d_drop(dentry); | 1117 | d_drop(dentry); |
1115 | nfs_free_fattr(fattr); | ||
1116 | nfs_free_fhandle(fhandle); | ||
1117 | dput(parent); | 1118 | dput(parent); |
1118 | dfprintk(LOOKUPCACHE, "NFS: %s(%s/%s) is invalid\n", | 1119 | dfprintk(LOOKUPCACHE, "NFS: %s(%s/%s) is invalid\n", |
1119 | __func__, dentry->d_parent->d_name.name, | 1120 | __func__, dentry->d_parent->d_name.name, |