aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Documentation/filesystems/porting8
-rw-r--r--Documentation/filesystems/vfs.txt4
-rw-r--r--fs/namei.c28
-rw-r--r--fs/nfs/dir.c6
-rw-r--r--include/linux/list_bl.h5
-rw-r--r--include/linux/rculist_bl.h3
6 files changed, 40 insertions, 14 deletions
diff --git a/Documentation/filesystems/porting b/Documentation/filesystems/porting
index 266d2059b9b8..dfbcd1b00b0a 100644
--- a/Documentation/filesystems/porting
+++ b/Documentation/filesystems/porting
@@ -365,8 +365,8 @@ must be done in the RCU callback.
365[recommended] 365[recommended]
366 vfs now tries to do path walking in "rcu-walk mode", which avoids 366 vfs now tries to do path walking in "rcu-walk mode", which avoids
367atomic operations and scalability hazards on dentries and inodes (see 367atomic operations and scalability hazards on dentries and inodes (see
368Documentation/filesystems/path-walk.txt). d_hash and d_compare changes (above) 368Documentation/filesystems/path-lookup.txt). d_hash and d_compare changes
369are examples of the changes required to support this. For more complex 369(above) are 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 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 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 372the benefits of rcu-walk mode. We will begin to add filesystem callbacks that
@@ -383,8 +383,8 @@ Documentation/filesystems/vfs.txt for more details.
383 383
384 permission and check_acl are inode permission checks that are called 384 permission and check_acl are inode permission checks that are called
385on many or all directory inodes on the way down a path walk (to check for 385on many or all directory inodes on the way down a path walk (to check for
386exec permission). These must now be rcu-walk aware (flags & IPERM_RCU). See 386exec permission). These must now be rcu-walk aware (flags & IPERM_FLAG_RCU).
387Documentation/filesystems/vfs.txt for more details. 387See Documentation/filesystems/vfs.txt for more details.
388 388
389-- 389--
390[mandatory] 390[mandatory]
diff --git a/Documentation/filesystems/vfs.txt b/Documentation/filesystems/vfs.txt
index fbb324e2bd43..cae6d27c9f5b 100644
--- a/Documentation/filesystems/vfs.txt
+++ b/Documentation/filesystems/vfs.txt
@@ -415,8 +415,8 @@ otherwise noted.
415 permission: called by the VFS to check for access rights on a POSIX-like 415 permission: called by the VFS to check for access rights on a POSIX-like
416 filesystem. 416 filesystem.
417 417
418 May be called in rcu-walk mode (flags & IPERM_RCU). If in rcu-walk 418 May be called in rcu-walk mode (flags & IPERM_FLAG_RCU). If in rcu-walk
419 mode, the filesystem must check the permission without blocking or 419 mode, the filesystem must check the permission without blocking or
420 storing to the inode. 420 storing to the inode.
421 421
422 If a situation is encountered that rcu-walk cannot handle, return 422 If a situation is encountered that rcu-walk cannot handle, return
diff --git a/fs/namei.c b/fs/namei.c
index 0b14f6910fc6..86643302079e 100644
--- a/fs/namei.c
+++ b/fs/namei.c
@@ -479,6 +479,14 @@ static int nameidata_dentry_drop_rcu(struct nameidata *nd, struct dentry *dentry
479 struct fs_struct *fs = current->fs; 479 struct fs_struct *fs = current->fs;
480 struct dentry *parent = nd->path.dentry; 480 struct dentry *parent = nd->path.dentry;
481 481
482 /*
483 * It can be possible to revalidate the dentry that we started
484 * the path walk with. force_reval_path may also revalidate the
485 * dentry already committed to the nameidata.
486 */
487 if (unlikely(parent == dentry))
488 return nameidata_drop_rcu(nd);
489
482 BUG_ON(!(nd->flags & LOOKUP_RCU)); 490 BUG_ON(!(nd->flags & LOOKUP_RCU));
483 if (nd->root.mnt) { 491 if (nd->root.mnt) {
484 spin_lock(&fs->lock); 492 spin_lock(&fs->lock);
@@ -583,6 +591,13 @@ void release_open_intent(struct nameidata *nd)
583 fput(nd->intent.open.file); 591 fput(nd->intent.open.file);
584} 592}
585 593
594/*
595 * Call d_revalidate and handle filesystems that request rcu-walk
596 * to be dropped. This may be called and return in rcu-walk mode,
597 * regardless of success or error. If -ECHILD is returned, the caller
598 * must return -ECHILD back up the path walk stack so path walk may
599 * be restarted in ref-walk mode.
600 */
586static int d_revalidate(struct dentry *dentry, struct nameidata *nd) 601static int d_revalidate(struct dentry *dentry, struct nameidata *nd)
587{ 602{
588 int status; 603 int status;
@@ -673,6 +688,9 @@ force_reval_path(struct path *path, struct nameidata *nd)
673 return 0; 688 return 0;
674 689
675 if (!status) { 690 if (!status) {
691 /* Don't d_invalidate in rcu-walk mode */
692 if (nameidata_drop_rcu(nd))
693 return -ECHILD;
676 d_invalidate(dentry); 694 d_invalidate(dentry);
677 status = -ESTALE; 695 status = -ESTALE;
678 } 696 }
@@ -2105,11 +2123,13 @@ static struct file *do_last(struct nameidata *nd, struct path *path,
2105 dir = nd->path.dentry; 2123 dir = nd->path.dentry;
2106 case LAST_DOT: 2124 case LAST_DOT:
2107 if (need_reval_dot(dir)) { 2125 if (need_reval_dot(dir)) {
2108 error = d_revalidate(nd->path.dentry, nd); 2126 int status = d_revalidate(nd->path.dentry, nd);
2109 if (!error) 2127 if (!status)
2110 error = -ESTALE; 2128 status = -ESTALE;
2111 if (error < 0) 2129 if (status < 0) {
2130 error = status;
2112 goto exit; 2131 goto exit;
2132 }
2113 } 2133 }
2114 /* fallthrough */ 2134 /* fallthrough */
2115 case LAST_ROOT: 2135 case LAST_ROOT:
diff --git a/fs/nfs/dir.c b/fs/nfs/dir.c
index 64ee240f3c80..df8c03a02161 100644
--- a/fs/nfs/dir.c
+++ b/fs/nfs/dir.c
@@ -1406,11 +1406,15 @@ no_open:
1406static int nfs_open_revalidate(struct dentry *dentry, struct nameidata *nd) 1406static int nfs_open_revalidate(struct dentry *dentry, struct nameidata *nd)
1407{ 1407{
1408 struct dentry *parent = NULL; 1408 struct dentry *parent = NULL;
1409 struct inode *inode = dentry->d_inode; 1409 struct inode *inode;
1410 struct inode *dir; 1410 struct inode *dir;
1411 struct nfs_open_context *ctx; 1411 struct nfs_open_context *ctx;
1412 int openflags, ret = 0; 1412 int openflags, ret = 0;
1413 1413
1414 if (nd->flags & LOOKUP_RCU)
1415 return -ECHILD;
1416
1417 inode = dentry->d_inode;
1414 if (!is_atomic_open(nd) || d_mountpoint(dentry)) 1418 if (!is_atomic_open(nd) || d_mountpoint(dentry))
1415 goto no_open; 1419 goto no_open;
1416 1420
diff --git a/include/linux/list_bl.h b/include/linux/list_bl.h
index 9ee97e7f2be4..b2adbb4b2f73 100644
--- a/include/linux/list_bl.h
+++ b/include/linux/list_bl.h
@@ -16,7 +16,7 @@
16 * some fast and compact auxiliary data. 16 * some fast and compact auxiliary data.
17 */ 17 */
18 18
19#if defined(CONFIG_SMP) || defined(CONFIG_DEBUG_SPINLOCK) 19#if defined(CONFIG_SMP)
20#define LIST_BL_LOCKMASK 1UL 20#define LIST_BL_LOCKMASK 1UL
21#else 21#else
22#define LIST_BL_LOCKMASK 0UL 22#define LIST_BL_LOCKMASK 0UL
@@ -62,7 +62,8 @@ static inline void hlist_bl_set_first(struct hlist_bl_head *h,
62 struct hlist_bl_node *n) 62 struct hlist_bl_node *n)
63{ 63{
64 LIST_BL_BUG_ON((unsigned long)n & LIST_BL_LOCKMASK); 64 LIST_BL_BUG_ON((unsigned long)n & LIST_BL_LOCKMASK);
65 LIST_BL_BUG_ON(!((unsigned long)h->first & LIST_BL_LOCKMASK)); 65 LIST_BL_BUG_ON(((unsigned long)h->first & LIST_BL_LOCKMASK) !=
66 LIST_BL_LOCKMASK);
66 h->first = (struct hlist_bl_node *)((unsigned long)n | LIST_BL_LOCKMASK); 67 h->first = (struct hlist_bl_node *)((unsigned long)n | LIST_BL_LOCKMASK);
67} 68}
68 69
diff --git a/include/linux/rculist_bl.h b/include/linux/rculist_bl.h
index b872b493724d..cf1244fbf3b6 100644
--- a/include/linux/rculist_bl.h
+++ b/include/linux/rculist_bl.h
@@ -11,7 +11,8 @@ static inline void hlist_bl_set_first_rcu(struct hlist_bl_head *h,
11 struct hlist_bl_node *n) 11 struct hlist_bl_node *n)
12{ 12{
13 LIST_BL_BUG_ON((unsigned long)n & LIST_BL_LOCKMASK); 13 LIST_BL_BUG_ON((unsigned long)n & LIST_BL_LOCKMASK);
14 LIST_BL_BUG_ON(!((unsigned long)h->first & LIST_BL_LOCKMASK)); 14 LIST_BL_BUG_ON(((unsigned long)h->first & LIST_BL_LOCKMASK) !=
15 LIST_BL_LOCKMASK);
15 rcu_assign_pointer(h->first, 16 rcu_assign_pointer(h->first,
16 (struct hlist_bl_node *)((unsigned long)n | LIST_BL_LOCKMASK)); 17 (struct hlist_bl_node *)((unsigned long)n | LIST_BL_LOCKMASK));
17} 18}