aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorNick Piggin <npiggin@kernel.dk>2011-01-07 01:49:57 -0500
committerNick Piggin <npiggin@kernel.dk>2011-01-07 01:50:29 -0500
commit34286d6662308d82aed891852d04c7c3a2649b16 (patch)
treec4b7311404d302e7cb94df7a4690298e1059910a
parent44a7d7a878c9cbb74f236ea755b25b6b2e26a9a9 (diff)
fs: rcu-walk aware d_revalidate method
Require filesystems be aware of .d_revalidate being called in rcu-walk mode (nd->flags & LOOKUP_RCU). For now do a simple push down, returning -ECHILD from all implementations. Signed-off-by: Nick Piggin <npiggin@kernel.dk>
-rw-r--r--Documentation/filesystems/Locking18
-rw-r--r--Documentation/filesystems/path-lookup.txt5
-rw-r--r--Documentation/filesystems/porting20
-rw-r--r--Documentation/filesystems/vfs.txt9
-rw-r--r--drivers/staging/autofs/root.c5
-rw-r--r--drivers/staging/smbfs/dir.c16
-rw-r--r--fs/afs/dir.c4
-rw-r--r--fs/autofs4/root.c13
-rw-r--r--fs/ceph/dir.c7
-rw-r--r--fs/cifs/dir.c3
-rw-r--r--fs/coda/dir.c7
-rw-r--r--fs/ecryptfs/dentry.c9
-rw-r--r--fs/fat/namei_vfat.c6
-rw-r--r--fs/fuse/dir.c6
-rw-r--r--fs/gfs2/dentry.c17
-rw-r--r--fs/hfs/sysdep.c7
-rw-r--r--fs/jfs/namei.c2
-rw-r--r--fs/namei.c54
-rw-r--r--fs/ncpfs/dir.c4
-rw-r--r--fs/ncpfs/inode.c1
-rw-r--r--fs/nfs/dir.c8
-rw-r--r--fs/ocfs2/dcache.c10
-rw-r--r--fs/proc/base.c33
-rw-r--r--fs/proc/proc_sysctl.c3
-rw-r--r--fs/reiserfs/xattr.c2
-rw-r--r--fs/sysfs/dir.c6
-rw-r--r--include/linux/dcache.h1
27 files changed, 215 insertions, 61 deletions
diff --git a/Documentation/filesystems/Locking b/Documentation/filesystems/Locking
index bdad6414dfa0..e90ffe61eb65 100644
--- a/Documentation/filesystems/Locking
+++ b/Documentation/filesystems/Locking
@@ -9,7 +9,7 @@ be able to use diff(1).
9 9
10--------------------------- dentry_operations -------------------------- 10--------------------------- dentry_operations --------------------------
11prototypes: 11prototypes:
12 int (*d_revalidate)(struct dentry *, int); 12 int (*d_revalidate)(struct dentry *, struct nameidata *);
13 int (*d_hash)(const struct dentry *, const struct inode *, 13 int (*d_hash)(const struct dentry *, const struct inode *,
14 struct qstr *); 14 struct qstr *);
15 int (*d_compare)(const struct dentry *, const struct inode *, 15 int (*d_compare)(const struct dentry *, const struct inode *,
@@ -21,14 +21,14 @@ prototypes:
21 char *(*d_dname)((struct dentry *dentry, char *buffer, int buflen); 21 char *(*d_dname)((struct dentry *dentry, char *buffer, int buflen);
22 22
23locking rules: 23locking rules:
24 rename_lock ->d_lock may block 24 rename_lock ->d_lock may block rcu-walk
25d_revalidate: no no yes 25d_revalidate: no no yes (ref-walk) maybe
26d_hash no no no 26d_hash no no no maybe
27d_compare: yes no no 27d_compare: yes no no maybe
28d_delete: no yes no 28d_delete: no yes no no
29d_release: no no yes 29d_release: no no yes no
30d_iput: no no yes 30d_iput: no no yes no
31d_dname: no no no 31d_dname: no no no no
32 32
33--------------------------- inode_operations --------------------------- 33--------------------------- inode_operations ---------------------------
34prototypes: 34prototypes:
diff --git a/Documentation/filesystems/path-lookup.txt b/Documentation/filesystems/path-lookup.txt
index 09b2878724a1..8789d1810bed 100644
--- a/Documentation/filesystems/path-lookup.txt
+++ b/Documentation/filesystems/path-lookup.txt
@@ -317,11 +317,10 @@ The detailed design for rcu-walk is like this:
317The cases where rcu-walk cannot continue are: 317The cases where rcu-walk cannot continue are:
318* NULL dentry (ie. any uncached path element) 318* NULL dentry (ie. any uncached path element)
319* parent with d_inode->i_op->permission or ACLs 319* parent with d_inode->i_op->permission or ACLs
320* dentries with d_revalidate
321* Following links 320* Following links
322 321
323In future patches, permission checks and d_revalidate become rcu-walk aware. It 322In future patches, permission checks become rcu-walk aware. It may be possible
324may be possible eventually to make following links rcu-walk aware. 323eventually to make following links rcu-walk aware.
325 324
326Uncached path elements will always require dropping to ref-walk mode, at the 325Uncached path elements will always require dropping to ref-walk mode, at the
327very least because i_mutex needs to be grabbed, and objects allocated. 326very least because i_mutex needs to be grabbed, and objects allocated.
diff --git a/Documentation/filesystems/porting b/Documentation/filesystems/porting
index ccf0ce7866b9..cd9756a2709d 100644
--- a/Documentation/filesystems/porting
+++ b/Documentation/filesystems/porting
@@ -360,3 +360,23 @@ i_dentry to be reinitialized before it is freed, so an:
360 INIT_LIST_HEAD(&inode->i_dentry); 360 INIT_LIST_HEAD(&inode->i_dentry);
361 361
362must be done in the RCU callback. 362must be done in the RCU callback.
363
364--
365[recommended]
366 vfs now tries to do path walking in "rcu-walk mode", which avoids
367atomic operations and scalability hazards on dentries and inodes (see
368Documentation/filesystems/path-walk.txt). d_hash and d_compare changes (above)
369are examples of the changes required to support this. For more complex
370filesystem callbacks, the vfs drops out of rcu-walk mode before the fs call, so
371no changes are required to the filesystem. However, this is costly and loses
372the benefits of rcu-walk mode. We will begin to add filesystem callbacks that
373are rcu-walk aware, shown below. Filesystems should take advantage of this
374where possible.
375
376--
377[mandatory]
378 d_revalidate is a callback that is made on every path element (if
379the filesystem provides it), which requires dropping out of rcu-walk mode. This
380may now be called in rcu-walk mode (nd->flags & LOOKUP_RCU). -ECHILD should be
381returned if the filesystem cannot handle rcu-walk. See
382Documentation/filesystems/vfs.txt for more details.
diff --git a/Documentation/filesystems/vfs.txt b/Documentation/filesystems/vfs.txt
index 69b10ff5ec81..c936b4912383 100644
--- a/Documentation/filesystems/vfs.txt
+++ b/Documentation/filesystems/vfs.txt
@@ -863,6 +863,15 @@ struct dentry_operations {
863 dcache. Most filesystems leave this as NULL, because all their 863 dcache. Most filesystems leave this as NULL, because all their
864 dentries in the dcache are valid 864 dentries in the dcache are valid
865 865
866 d_revalidate may be called in rcu-walk mode (nd->flags & LOOKUP_RCU).
867 If in rcu-walk mode, the filesystem must revalidate the dentry without
868 blocking or storing to the dentry, d_parent and d_inode should not be
869 used without care (because they can go NULL), instead nd->inode should
870 be used.
871
872 If a situation is encountered that rcu-walk cannot handle, return
873 -ECHILD and it will be called again in ref-walk mode.
874
866 d_hash: called when the VFS adds a dentry to the hash table. The first 875 d_hash: called when the VFS adds a dentry to the hash table. The first
867 dentry passed to d_hash is the parent directory that the name is 876 dentry passed to d_hash is the parent directory that the name is
868 to be hashed into. The inode is the dentry's inode. 877 to be hashed into. The inode is the dentry's inode.
diff --git a/drivers/staging/autofs/root.c b/drivers/staging/autofs/root.c
index b09adb57971f..bf0e9755da67 100644
--- a/drivers/staging/autofs/root.c
+++ b/drivers/staging/autofs/root.c
@@ -154,13 +154,16 @@ static int try_to_fill_dentry(struct dentry *dentry, struct super_block *sb, str
154 * yet completely filled in, and revalidate has to delay such 154 * yet completely filled in, and revalidate has to delay such
155 * lookups.. 155 * lookups..
156 */ 156 */
157static int autofs_revalidate(struct dentry * dentry, struct nameidata *nd) 157static int autofs_revalidate(struct dentry *dentry, struct nameidata *nd)
158{ 158{
159 struct inode * dir; 159 struct inode * dir;
160 struct autofs_sb_info *sbi; 160 struct autofs_sb_info *sbi;
161 struct autofs_dir_ent *ent; 161 struct autofs_dir_ent *ent;
162 int res; 162 int res;
163 163
164 if (nd->flags & LOOKUP_RCU)
165 return -ECHILD;
166
164 lock_kernel(); 167 lock_kernel();
165 dir = dentry->d_parent->d_inode; 168 dir = dentry->d_parent->d_inode;
166 sbi = autofs_sbi(dir->i_sb); 169 sbi = autofs_sbi(dir->i_sb);
diff --git a/drivers/staging/smbfs/dir.c b/drivers/staging/smbfs/dir.c
index 78f09412740c..dd612f50749f 100644
--- a/drivers/staging/smbfs/dir.c
+++ b/drivers/staging/smbfs/dir.c
@@ -14,6 +14,7 @@
14#include <linux/ctype.h> 14#include <linux/ctype.h>
15#include <linux/net.h> 15#include <linux/net.h>
16#include <linux/sched.h> 16#include <linux/sched.h>
17#include <linux/namei.h>
17 18
18#include "smb_fs.h" 19#include "smb_fs.h"
19#include "smb_mount.h" 20#include "smb_mount.h"
@@ -301,13 +302,20 @@ static const struct dentry_operations smbfs_dentry_operations_case =
301 * This is the callback when the dcache has a lookup hit. 302 * This is the callback when the dcache has a lookup hit.
302 */ 303 */
303static int 304static int
304smb_lookup_validate(struct dentry * dentry, struct nameidata *nd) 305smb_lookup_validate(struct dentry *dentry, struct nameidata *nd)
305{ 306{
306 struct smb_sb_info *server = server_from_dentry(dentry); 307 struct smb_sb_info *server;
307 struct inode * inode = dentry->d_inode; 308 struct inode *inode;
308 unsigned long age = jiffies - dentry->d_time; 309 unsigned long age;
309 int valid; 310 int valid;
310 311
312 if (nd->flags & LOOKUP_RCU)
313 return -ECHILD;
314
315 server = server_from_dentry(dentry);
316 inode = dentry->d_inode;
317 age = jiffies - dentry->d_time;
318
311 /* 319 /*
312 * The default validation is based on dentry age: 320 * The default validation is based on dentry age:
313 * we believe in dentries for a few seconds. (But each 321 * we believe in dentries for a few seconds. (But each
diff --git a/fs/afs/dir.c b/fs/afs/dir.c
index b8bb7e7148d0..34a3263d60a4 100644
--- a/fs/afs/dir.c
+++ b/fs/afs/dir.c
@@ -13,6 +13,7 @@
13#include <linux/module.h> 13#include <linux/module.h>
14#include <linux/init.h> 14#include <linux/init.h>
15#include <linux/fs.h> 15#include <linux/fs.h>
16#include <linux/namei.h>
16#include <linux/pagemap.h> 17#include <linux/pagemap.h>
17#include <linux/ctype.h> 18#include <linux/ctype.h>
18#include <linux/sched.h> 19#include <linux/sched.h>
@@ -607,6 +608,9 @@ static int afs_d_revalidate(struct dentry *dentry, struct nameidata *nd)
607 void *dir_version; 608 void *dir_version;
608 int ret; 609 int ret;
609 610
611 if (nd->flags & LOOKUP_RCU)
612 return -ECHILD;
613
610 vnode = AFS_FS_I(dentry->d_inode); 614 vnode = AFS_FS_I(dentry->d_inode);
611 615
612 if (dentry->d_inode) 616 if (dentry->d_inode)
diff --git a/fs/autofs4/root.c b/fs/autofs4/root.c
index bfe3f2eb684d..651e4ef563b1 100644
--- a/fs/autofs4/root.c
+++ b/fs/autofs4/root.c
@@ -315,12 +315,19 @@ out_error:
315 */ 315 */
316static int autofs4_revalidate(struct dentry *dentry, struct nameidata *nd) 316static int autofs4_revalidate(struct dentry *dentry, struct nameidata *nd)
317{ 317{
318 struct inode *dir = dentry->d_parent->d_inode; 318 struct inode *dir;
319 struct autofs_sb_info *sbi = autofs4_sbi(dir->i_sb); 319 struct autofs_sb_info *sbi;
320 int oz_mode = autofs4_oz_mode(sbi); 320 int oz_mode;
321 int flags = nd ? nd->flags : 0; 321 int flags = nd ? nd->flags : 0;
322 int status = 1; 322 int status = 1;
323 323
324 if (flags & LOOKUP_RCU)
325 return -ECHILD;
326
327 dir = dentry->d_parent->d_inode;
328 sbi = autofs4_sbi(dir->i_sb);
329 oz_mode = autofs4_oz_mode(sbi);
330
324 /* Pending dentry */ 331 /* Pending dentry */
325 spin_lock(&sbi->fs_lock); 332 spin_lock(&sbi->fs_lock);
326 if (autofs4_ispending(dentry)) { 333 if (autofs4_ispending(dentry)) {
diff --git a/fs/ceph/dir.c b/fs/ceph/dir.c
index cc01cf826769..fa7ca04ee816 100644
--- a/fs/ceph/dir.c
+++ b/fs/ceph/dir.c
@@ -990,7 +990,12 @@ static int dir_lease_is_valid(struct inode *dir, struct dentry *dentry)
990 */ 990 */
991static int ceph_d_revalidate(struct dentry *dentry, struct nameidata *nd) 991static int ceph_d_revalidate(struct dentry *dentry, struct nameidata *nd)
992{ 992{
993 struct inode *dir = dentry->d_parent->d_inode; 993 struct inode *dir;
994
995 if (nd->flags & LOOKUP_RCU)
996 return -ECHILD;
997
998 dir = dentry->d_parent->d_inode;
994 999
995 dout("d_revalidate %p '%.*s' inode %p offset %lld\n", dentry, 1000 dout("d_revalidate %p '%.*s' inode %p offset %lld\n", dentry,
996 dentry->d_name.len, dentry->d_name.name, dentry->d_inode, 1001 dentry->d_name.len, dentry->d_name.name, dentry->d_inode,
diff --git a/fs/cifs/dir.c b/fs/cifs/dir.c
index e3b10ca6d453..db2a58c00f7b 100644
--- a/fs/cifs/dir.c
+++ b/fs/cifs/dir.c
@@ -656,6 +656,9 @@ lookup_out:
656static int 656static int
657cifs_d_revalidate(struct dentry *direntry, struct nameidata *nd) 657cifs_d_revalidate(struct dentry *direntry, struct nameidata *nd)
658{ 658{
659 if (nd->flags & LOOKUP_RCU)
660 return -ECHILD;
661
659 if (direntry->d_inode) { 662 if (direntry->d_inode) {
660 if (cifs_revalidate_dentry(direntry)) 663 if (cifs_revalidate_dentry(direntry))
661 return 0; 664 return 0;
diff --git a/fs/coda/dir.c b/fs/coda/dir.c
index aa40c811f8d2..619a8303766e 100644
--- a/fs/coda/dir.c
+++ b/fs/coda/dir.c
@@ -18,6 +18,7 @@
18#include <linux/errno.h> 18#include <linux/errno.h>
19#include <linux/string.h> 19#include <linux/string.h>
20#include <linux/spinlock.h> 20#include <linux/spinlock.h>
21#include <linux/namei.h>
21 22
22#include <asm/uaccess.h> 23#include <asm/uaccess.h>
23 24
@@ -541,9 +542,13 @@ out:
541/* called when a cache lookup succeeds */ 542/* called when a cache lookup succeeds */
542static int coda_dentry_revalidate(struct dentry *de, struct nameidata *nd) 543static int coda_dentry_revalidate(struct dentry *de, struct nameidata *nd)
543{ 544{
544 struct inode *inode = de->d_inode; 545 struct inode *inode;
545 struct coda_inode_info *cii; 546 struct coda_inode_info *cii;
546 547
548 if (nd->flags & LOOKUP_RCU)
549 return -ECHILD;
550
551 inode = de->d_inode;
547 if (!inode || coda_isroot(inode)) 552 if (!inode || coda_isroot(inode))
548 goto out; 553 goto out;
549 if (is_bad_inode(inode)) 554 if (is_bad_inode(inode))
diff --git a/fs/ecryptfs/dentry.c b/fs/ecryptfs/dentry.c
index 906e803f7f79..6fc4f319b550 100644
--- a/fs/ecryptfs/dentry.c
+++ b/fs/ecryptfs/dentry.c
@@ -44,12 +44,17 @@
44 */ 44 */
45static int ecryptfs_d_revalidate(struct dentry *dentry, struct nameidata *nd) 45static int ecryptfs_d_revalidate(struct dentry *dentry, struct nameidata *nd)
46{ 46{
47 struct dentry *lower_dentry = ecryptfs_dentry_to_lower(dentry); 47 struct dentry *lower_dentry;
48 struct vfsmount *lower_mnt = ecryptfs_dentry_to_lower_mnt(dentry); 48 struct vfsmount *lower_mnt;
49 struct dentry *dentry_save; 49 struct dentry *dentry_save;
50 struct vfsmount *vfsmount_save; 50 struct vfsmount *vfsmount_save;
51 int rc = 1; 51 int rc = 1;
52 52
53 if (nd->flags & LOOKUP_RCU)
54 return -ECHILD;
55
56 lower_dentry = ecryptfs_dentry_to_lower(dentry);
57 lower_mnt = ecryptfs_dentry_to_lower_mnt(dentry);
53 if (!lower_dentry->d_op || !lower_dentry->d_op->d_revalidate) 58 if (!lower_dentry->d_op || !lower_dentry->d_op->d_revalidate)
54 goto out; 59 goto out;
55 dentry_save = nd->path.dentry; 60 dentry_save = nd->path.dentry;
diff --git a/fs/fat/namei_vfat.c b/fs/fat/namei_vfat.c
index 3be5ed7d859f..e3ffc5e12332 100644
--- a/fs/fat/namei_vfat.c
+++ b/fs/fat/namei_vfat.c
@@ -43,6 +43,9 @@ static int vfat_revalidate_shortname(struct dentry *dentry)
43 43
44static int vfat_revalidate(struct dentry *dentry, struct nameidata *nd) 44static int vfat_revalidate(struct dentry *dentry, struct nameidata *nd)
45{ 45{
46 if (nd->flags & LOOKUP_RCU)
47 return -ECHILD;
48
46 /* This is not negative dentry. Always valid. */ 49 /* This is not negative dentry. Always valid. */
47 if (dentry->d_inode) 50 if (dentry->d_inode)
48 return 1; 51 return 1;
@@ -51,6 +54,9 @@ static int vfat_revalidate(struct dentry *dentry, struct nameidata *nd)
51 54
52static int vfat_revalidate_ci(struct dentry *dentry, struct nameidata *nd) 55static int vfat_revalidate_ci(struct dentry *dentry, struct nameidata *nd)
53{ 56{
57 if (nd->flags & LOOKUP_RCU)
58 return -ECHILD;
59
54 /* 60 /*
55 * This is not negative dentry. Always valid. 61 * This is not negative dentry. Always valid.
56 * 62 *
diff --git a/fs/fuse/dir.c b/fs/fuse/dir.c
index c9a8a426a395..07f4b5e675fc 100644
--- a/fs/fuse/dir.c
+++ b/fs/fuse/dir.c
@@ -156,8 +156,12 @@ u64 fuse_get_attr_version(struct fuse_conn *fc)
156 */ 156 */
157static int fuse_dentry_revalidate(struct dentry *entry, struct nameidata *nd) 157static int fuse_dentry_revalidate(struct dentry *entry, struct nameidata *nd)
158{ 158{
159 struct inode *inode = entry->d_inode; 159 struct inode *inode;
160
161 if (nd->flags & LOOKUP_RCU)
162 return -ECHILD;
160 163
164 inode = entry->d_inode;
161 if (inode && is_bad_inode(inode)) 165 if (inode && is_bad_inode(inode))
162 return 0; 166 return 0;
163 else if (fuse_dentry_time(entry) < get_jiffies_64()) { 167 else if (fuse_dentry_time(entry) < get_jiffies_64()) {
diff --git a/fs/gfs2/dentry.c b/fs/gfs2/dentry.c
index 50497f65763b..4a456338b873 100644
--- a/fs/gfs2/dentry.c
+++ b/fs/gfs2/dentry.c
@@ -11,6 +11,7 @@
11#include <linux/completion.h> 11#include <linux/completion.h>
12#include <linux/buffer_head.h> 12#include <linux/buffer_head.h>
13#include <linux/gfs2_ondisk.h> 13#include <linux/gfs2_ondisk.h>
14#include <linux/namei.h>
14#include <linux/crc32.h> 15#include <linux/crc32.h>
15 16
16#include "gfs2.h" 17#include "gfs2.h"
@@ -34,15 +35,23 @@
34 35
35static int gfs2_drevalidate(struct dentry *dentry, struct nameidata *nd) 36static int gfs2_drevalidate(struct dentry *dentry, struct nameidata *nd)
36{ 37{
37 struct dentry *parent = dget_parent(dentry); 38 struct dentry *parent;
38 struct gfs2_sbd *sdp = GFS2_SB(parent->d_inode); 39 struct gfs2_sbd *sdp;
39 struct gfs2_inode *dip = GFS2_I(parent->d_inode); 40 struct gfs2_inode *dip;
40 struct inode *inode = dentry->d_inode; 41 struct inode *inode;
41 struct gfs2_holder d_gh; 42 struct gfs2_holder d_gh;
42 struct gfs2_inode *ip = NULL; 43 struct gfs2_inode *ip = NULL;
43 int error; 44 int error;
44 int had_lock = 0; 45 int had_lock = 0;
45 46
47 if (nd->flags & LOOKUP_RCU)
48 return -ECHILD;
49
50 parent = dget_parent(dentry);
51 sdp = GFS2_SB(parent->d_inode);
52 dip = GFS2_I(parent->d_inode);
53 inode = dentry->d_inode;
54
46 if (inode) { 55 if (inode) {
47 if (is_bad_inode(inode)) 56 if (is_bad_inode(inode))
48 goto invalid; 57 goto invalid;
diff --git a/fs/hfs/sysdep.c b/fs/hfs/sysdep.c
index 7478f5c219aa..19cf291eb91f 100644
--- a/fs/hfs/sysdep.c
+++ b/fs/hfs/sysdep.c
@@ -8,15 +8,20 @@
8 * This file contains the code to do various system dependent things. 8 * This file contains the code to do various system dependent things.
9 */ 9 */
10 10
11#include <linux/namei.h>
11#include "hfs_fs.h" 12#include "hfs_fs.h"
12 13
13/* dentry case-handling: just lowercase everything */ 14/* dentry case-handling: just lowercase everything */
14 15
15static int hfs_revalidate_dentry(struct dentry *dentry, struct nameidata *nd) 16static int hfs_revalidate_dentry(struct dentry *dentry, struct nameidata *nd)
16{ 17{
17 struct inode *inode = dentry->d_inode; 18 struct inode *inode;
18 int diff; 19 int diff;
19 20
21 if (nd->flags & LOOKUP_RCU)
22 return -ECHILD;
23
24 inode = dentry->d_inode;
20 if(!inode) 25 if(!inode)
21 return 1; 26 return 1;
22 27
diff --git a/fs/jfs/namei.c b/fs/jfs/namei.c
index a151cbdec626..4414e3a42264 100644
--- a/fs/jfs/namei.c
+++ b/fs/jfs/namei.c
@@ -1608,6 +1608,8 @@ out:
1608 1608
1609static int jfs_ci_revalidate(struct dentry *dentry, struct nameidata *nd) 1609static int jfs_ci_revalidate(struct dentry *dentry, struct nameidata *nd)
1610{ 1610{
1611 if (nd->flags & LOOKUP_RCU)
1612 return -ECHILD;
1611 /* 1613 /*
1612 * This is not negative dentry. Always valid. 1614 * This is not negative dentry. Always valid.
1613 * 1615 *
diff --git a/fs/namei.c b/fs/namei.c
index 90bd2873e117..6e275363e89d 100644
--- a/fs/namei.c
+++ b/fs/namei.c
@@ -563,10 +563,26 @@ void release_open_intent(struct nameidata *nd)
563 fput(nd->intent.open.file); 563 fput(nd->intent.open.file);
564} 564}
565 565
566static int d_revalidate(struct dentry *dentry, struct nameidata *nd)
567{
568 int status;
569
570 status = dentry->d_op->d_revalidate(dentry, nd);
571 if (status == -ECHILD) {
572 if (nameidata_dentry_drop_rcu(nd, dentry))
573 return status;
574 status = dentry->d_op->d_revalidate(dentry, nd);
575 }
576
577 return status;
578}
579
566static inline struct dentry * 580static inline struct dentry *
567do_revalidate(struct dentry *dentry, struct nameidata *nd) 581do_revalidate(struct dentry *dentry, struct nameidata *nd)
568{ 582{
569 int status = dentry->d_op->d_revalidate(dentry, nd); 583 int status;
584
585 status = d_revalidate(dentry, nd);
570 if (unlikely(status <= 0)) { 586 if (unlikely(status <= 0)) {
571 /* 587 /*
572 * The dentry failed validation. 588 * The dentry failed validation.
@@ -574,14 +590,20 @@ do_revalidate(struct dentry *dentry, struct nameidata *nd)
574 * the dentry otherwise d_revalidate is asking us 590 * the dentry otherwise d_revalidate is asking us
575 * to return a fail status. 591 * to return a fail status.
576 */ 592 */
577 if (!status) { 593 if (status < 0) {
594 /* If we're in rcu-walk, we don't have a ref */
595 if (!(nd->flags & LOOKUP_RCU))
596 dput(dentry);
597 dentry = ERR_PTR(status);
598
599 } else {
600 /* Don't d_invalidate in rcu-walk mode */
601 if (nameidata_dentry_drop_rcu_maybe(nd, dentry))
602 return ERR_PTR(-ECHILD);
578 if (!d_invalidate(dentry)) { 603 if (!d_invalidate(dentry)) {
579 dput(dentry); 604 dput(dentry);
580 dentry = NULL; 605 dentry = NULL;
581 } 606 }
582 } else {
583 dput(dentry);
584 dentry = ERR_PTR(status);
585 } 607 }
586 } 608 }
587 return dentry; 609 return dentry;
@@ -626,7 +648,7 @@ force_reval_path(struct path *path, struct nameidata *nd)
626 if (!need_reval_dot(dentry)) 648 if (!need_reval_dot(dentry))
627 return 0; 649 return 0;
628 650
629 status = dentry->d_op->d_revalidate(dentry, nd); 651 status = d_revalidate(dentry, nd);
630 if (status > 0) 652 if (status > 0)
631 return 0; 653 return 0;
632 654
@@ -1039,12 +1061,8 @@ static int do_lookup(struct nameidata *nd, struct qstr *name,
1039 return -ECHILD; 1061 return -ECHILD;
1040 1062
1041 nd->seq = seq; 1063 nd->seq = seq;
1042 if (dentry->d_flags & DCACHE_OP_REVALIDATE) { 1064 if (dentry->d_flags & DCACHE_OP_REVALIDATE)
1043 /* We commonly drop rcu-walk here */
1044 if (nameidata_dentry_drop_rcu(nd, dentry))
1045 return -ECHILD;
1046 goto need_revalidate; 1065 goto need_revalidate;
1047 }
1048 path->mnt = mnt; 1066 path->mnt = mnt;
1049 path->dentry = dentry; 1067 path->dentry = dentry;
1050 __follow_mount_rcu(nd, path, inode); 1068 __follow_mount_rcu(nd, path, inode);
@@ -1292,12 +1310,11 @@ return_reval:
1292 * We may need to check the cached dentry for staleness. 1310 * We may need to check the cached dentry for staleness.
1293 */ 1311 */
1294 if (need_reval_dot(nd->path.dentry)) { 1312 if (need_reval_dot(nd->path.dentry)) {
1295 if (nameidata_drop_rcu_maybe(nd))
1296 return -ECHILD;
1297 err = -ESTALE;
1298 /* Note: we do not d_invalidate() */ 1313 /* Note: we do not d_invalidate() */
1299 if (!nd->path.dentry->d_op->d_revalidate( 1314 err = d_revalidate(nd->path.dentry, nd);
1300 nd->path.dentry, nd)) 1315 if (!err)
1316 err = -ESTALE;
1317 if (err < 0)
1301 break; 1318 break;
1302 } 1319 }
1303return_base: 1320return_base:
@@ -2080,10 +2097,11 @@ static struct file *do_last(struct nameidata *nd, struct path *path,
2080 dir = nd->path.dentry; 2097 dir = nd->path.dentry;
2081 case LAST_DOT: 2098 case LAST_DOT:
2082 if (need_reval_dot(dir)) { 2099 if (need_reval_dot(dir)) {
2083 if (!dir->d_op->d_revalidate(dir, nd)) { 2100 error = d_revalidate(nd->path.dentry, nd);
2101 if (!error)
2084 error = -ESTALE; 2102 error = -ESTALE;
2103 if (error < 0)
2085 goto exit; 2104 goto exit;
2086 }
2087 } 2105 }
2088 /* fallthrough */ 2106 /* fallthrough */
2089 case LAST_ROOT: 2107 case LAST_ROOT:
diff --git a/fs/ncpfs/dir.c b/fs/ncpfs/dir.c
index 4b9cbb28d7fa..28f136d4aaec 100644
--- a/fs/ncpfs/dir.c
+++ b/fs/ncpfs/dir.c
@@ -17,6 +17,7 @@
17#include <linux/kernel.h> 17#include <linux/kernel.h>
18#include <linux/vmalloc.h> 18#include <linux/vmalloc.h>
19#include <linux/mm.h> 19#include <linux/mm.h>
20#include <linux/namei.h>
20#include <asm/uaccess.h> 21#include <asm/uaccess.h>
21#include <asm/byteorder.h> 22#include <asm/byteorder.h>
22 23
@@ -308,6 +309,9 @@ ncp_lookup_validate(struct dentry *dentry, struct nameidata *nd)
308 int res, val = 0, len; 309 int res, val = 0, len;
309 __u8 __name[NCP_MAXPATHLEN + 1]; 310 __u8 __name[NCP_MAXPATHLEN + 1];
310 311
312 if (nd->flags & LOOKUP_RCU)
313 return -ECHILD;
314
311 parent = dget_parent(dentry); 315 parent = dget_parent(dentry);
312 dir = parent->d_inode; 316 dir = parent->d_inode;
313 317
diff --git a/fs/ncpfs/inode.c b/fs/ncpfs/inode.c
index 0c75a5f3cafd..9531c052d7a4 100644
--- a/fs/ncpfs/inode.c
+++ b/fs/ncpfs/inode.c
@@ -29,6 +29,7 @@
29#include <linux/vfs.h> 29#include <linux/vfs.h>
30#include <linux/mount.h> 30#include <linux/mount.h>
31#include <linux/seq_file.h> 31#include <linux/seq_file.h>
32#include <linux/namei.h>
32 33
33#include <linux/ncp_fs.h> 34#include <linux/ncp_fs.h>
34 35
diff --git a/fs/nfs/dir.c b/fs/nfs/dir.c
index 37e0a8bb077e..58beace14b19 100644
--- a/fs/nfs/dir.c
+++ b/fs/nfs/dir.c
@@ -938,7 +938,8 @@ static int nfs_check_verifier(struct inode *dir, struct dentry *dentry)
938 * component of the path. 938 * component of the path.
939 * We check for this using LOOKUP_CONTINUE and LOOKUP_PARENT. 939 * We check for this using LOOKUP_CONTINUE and LOOKUP_PARENT.
940 */ 940 */
941static inline unsigned int nfs_lookup_check_intent(struct nameidata *nd, unsigned int mask) 941static inline unsigned int nfs_lookup_check_intent(struct nameidata *nd,
942 unsigned int mask)
942{ 943{
943 if (nd->flags & (LOOKUP_CONTINUE|LOOKUP_PARENT)) 944 if (nd->flags & (LOOKUP_CONTINUE|LOOKUP_PARENT))
944 return 0; 945 return 0;
@@ -1018,7 +1019,7 @@ int nfs_neg_need_reval(struct inode *dir, struct dentry *dentry,
1018 * If the parent directory is seen to have changed, we throw out the 1019 * If the parent directory is seen to have changed, we throw out the
1019 * cached dentry and do a new lookup. 1020 * cached dentry and do a new lookup.
1020 */ 1021 */
1021static int nfs_lookup_revalidate(struct dentry * dentry, struct nameidata *nd) 1022static int nfs_lookup_revalidate(struct dentry *dentry, struct nameidata *nd)
1022{ 1023{
1023 struct inode *dir; 1024 struct inode *dir;
1024 struct inode *inode; 1025 struct inode *inode;
@@ -1027,6 +1028,9 @@ static int nfs_lookup_revalidate(struct dentry * dentry, struct nameidata *nd)
1027 struct nfs_fattr *fattr = NULL; 1028 struct nfs_fattr *fattr = NULL;
1028 int error; 1029 int error;
1029 1030
1031 if (nd->flags & LOOKUP_RCU)
1032 return -ECHILD;
1033
1030 parent = dget_parent(dentry); 1034 parent = dget_parent(dentry);
1031 dir = parent->d_inode; 1035 dir = parent->d_inode;
1032 nfs_inc_stats(dir, NFSIOS_DENTRYREVALIDATE); 1036 nfs_inc_stats(dir, NFSIOS_DENTRYREVALIDATE);
diff --git a/fs/ocfs2/dcache.c b/fs/ocfs2/dcache.c
index 4d54c60ceee4..0310b16a7238 100644
--- a/fs/ocfs2/dcache.c
+++ b/fs/ocfs2/dcache.c
@@ -52,9 +52,15 @@ void ocfs2_dentry_attach_gen(struct dentry *dentry)
52static int ocfs2_dentry_revalidate(struct dentry *dentry, 52static int ocfs2_dentry_revalidate(struct dentry *dentry,
53 struct nameidata *nd) 53 struct nameidata *nd)
54{ 54{
55 struct inode *inode = dentry->d_inode; 55 struct inode *inode;
56 int ret = 0; /* if all else fails, just return false */ 56 int ret = 0; /* if all else fails, just return false */
57 struct ocfs2_super *osb = OCFS2_SB(dentry->d_sb); 57 struct ocfs2_super *osb;
58
59 if (nd->flags & LOOKUP_RCU)
60 return -ECHILD;
61
62 inode = dentry->d_inode;
63 osb = OCFS2_SB(dentry->d_sb);
58 64
59 mlog_entry("(0x%p, '%.*s')\n", dentry, 65 mlog_entry("(0x%p, '%.*s')\n", dentry,
60 dentry->d_name.len, dentry->d_name.name); 66 dentry->d_name.len, dentry->d_name.name);
diff --git a/fs/proc/base.c b/fs/proc/base.c
index 85f0a80912aa..dc5b2fcadc3b 100644
--- a/fs/proc/base.c
+++ b/fs/proc/base.c
@@ -1719,10 +1719,16 @@ static int pid_getattr(struct vfsmount *mnt, struct dentry *dentry, struct kstat
1719 */ 1719 */
1720static int pid_revalidate(struct dentry *dentry, struct nameidata *nd) 1720static int pid_revalidate(struct dentry *dentry, struct nameidata *nd)
1721{ 1721{
1722 struct inode *inode = dentry->d_inode; 1722 struct inode *inode;
1723 struct task_struct *task = get_proc_task(inode); 1723 struct task_struct *task;
1724 const struct cred *cred; 1724 const struct cred *cred;
1725 1725
1726 if (nd && nd->flags & LOOKUP_RCU)
1727 return -ECHILD;
1728
1729 inode = dentry->d_inode;
1730 task = get_proc_task(inode);
1731
1726 if (task) { 1732 if (task) {
1727 if ((inode->i_mode == (S_IFDIR|S_IRUGO|S_IXUGO)) || 1733 if ((inode->i_mode == (S_IFDIR|S_IRUGO|S_IXUGO)) ||
1728 task_dumpable(task)) { 1734 task_dumpable(task)) {
@@ -1888,12 +1894,19 @@ static int proc_fd_link(struct inode *inode, struct path *path)
1888 1894
1889static int tid_fd_revalidate(struct dentry *dentry, struct nameidata *nd) 1895static int tid_fd_revalidate(struct dentry *dentry, struct nameidata *nd)
1890{ 1896{
1891 struct inode *inode = dentry->d_inode; 1897 struct inode *inode;
1892 struct task_struct *task = get_proc_task(inode); 1898 struct task_struct *task;
1893 int fd = proc_fd(inode); 1899 int fd;
1894 struct files_struct *files; 1900 struct files_struct *files;
1895 const struct cred *cred; 1901 const struct cred *cred;
1896 1902
1903 if (nd && nd->flags & LOOKUP_RCU)
1904 return -ECHILD;
1905
1906 inode = dentry->d_inode;
1907 task = get_proc_task(inode);
1908 fd = proc_fd(inode);
1909
1897 if (task) { 1910 if (task) {
1898 files = get_files_struct(task); 1911 files = get_files_struct(task);
1899 if (files) { 1912 if (files) {
@@ -2563,8 +2576,14 @@ static const struct pid_entry proc_base_stuff[] = {
2563 */ 2576 */
2564static int proc_base_revalidate(struct dentry *dentry, struct nameidata *nd) 2577static int proc_base_revalidate(struct dentry *dentry, struct nameidata *nd)
2565{ 2578{
2566 struct inode *inode = dentry->d_inode; 2579 struct inode *inode;
2567 struct task_struct *task = get_proc_task(inode); 2580 struct task_struct *task;
2581
2582 if (nd->flags & LOOKUP_RCU)
2583 return -ECHILD;
2584
2585 inode = dentry->d_inode;
2586 task = get_proc_task(inode);
2568 if (task) { 2587 if (task) {
2569 put_task_struct(task); 2588 put_task_struct(task);
2570 return 1; 2589 return 1;
diff --git a/fs/proc/proc_sysctl.c b/fs/proc/proc_sysctl.c
index 35efd85a4d32..c9097f43b425 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
10static const struct dentry_operations proc_sys_dentry_operations; 11static const struct dentry_operations proc_sys_dentry_operations;
@@ -389,6 +390,8 @@ static const struct inode_operations proc_sys_dir_operations = {
389 390
390static int proc_sys_revalidate(struct dentry *dentry, struct nameidata *nd) 391static int proc_sys_revalidate(struct dentry *dentry, struct nameidata *nd)
391{ 392{
393 if (nd->flags & LOOKUP_RCU)
394 return -ECHILD;
392 return !PROC_I(dentry->d_inode)->sysctl->unregistering; 395 return !PROC_I(dentry->d_inode)->sysctl->unregistering;
393} 396}
394 397
diff --git a/fs/reiserfs/xattr.c b/fs/reiserfs/xattr.c
index e0f0d7ea10a1..9ea22a56cdf1 100644
--- a/fs/reiserfs/xattr.c
+++ b/fs/reiserfs/xattr.c
@@ -972,6 +972,8 @@ int reiserfs_permission(struct inode *inode, int mask)
972 972
973static int xattr_hide_revalidate(struct dentry *dentry, struct nameidata *nd) 973static int xattr_hide_revalidate(struct dentry *dentry, struct nameidata *nd)
974{ 974{
975 if (nd->flags & LOOKUP_RCU)
976 return -ECHILD;
975 return -EPERM; 977 return -EPERM;
976} 978}
977 979
diff --git a/fs/sysfs/dir.c b/fs/sysfs/dir.c
index 3e076caa8daf..ea9120a830d8 100644
--- a/fs/sysfs/dir.c
+++ b/fs/sysfs/dir.c
@@ -239,9 +239,13 @@ static int sysfs_dentry_delete(const struct dentry *dentry)
239 239
240static int sysfs_dentry_revalidate(struct dentry *dentry, struct nameidata *nd) 240static int sysfs_dentry_revalidate(struct dentry *dentry, struct nameidata *nd)
241{ 241{
242 struct sysfs_dirent *sd = dentry->d_fsdata; 242 struct sysfs_dirent *sd;
243 int is_dir; 243 int is_dir;
244 244
245 if (nd->flags & LOOKUP_RCU)
246 return -ECHILD;
247
248 sd = dentry->d_fsdata;
245 mutex_lock(&sysfs_mutex); 249 mutex_lock(&sysfs_mutex);
246 250
247 /* The sysfs dirent has been deleted */ 251 /* The sysfs dirent has been deleted */
diff --git a/include/linux/dcache.h b/include/linux/dcache.h
index b1aeda077258..8b2064d02928 100644
--- a/include/linux/dcache.h
+++ b/include/linux/dcache.h
@@ -190,7 +190,6 @@ struct dentry_operations {
190#define DCACHE_OP_REVALIDATE 0x4000 190#define DCACHE_OP_REVALIDATE 0x4000
191#define DCACHE_OP_DELETE 0x8000 191#define DCACHE_OP_DELETE 0x8000
192 192
193
194extern spinlock_t dcache_inode_lock; 193extern spinlock_t dcache_inode_lock;
195extern seqlock_t rename_lock; 194extern seqlock_t rename_lock;
196 195