aboutsummaryrefslogtreecommitdiffstats
path: root/fs/namei.c
diff options
context:
space:
mode:
authorDavid Howells <dhowells@redhat.com>2011-01-14 13:46:51 -0500
committerAl Viro <viro@zeniv.linux.org.uk>2011-01-15 20:07:47 -0500
commitab90911ff90cdab59b31c045c3f0ae480d14f29d (patch)
tree683450a66eb9dc6bf053e38d63f4740bb53a7b6e /fs/namei.c
parent87556ef19926e97464e0163a7840140527ae6615 (diff)
Allow d_manage() to be used in RCU-walk mode
Allow d_manage() to be called from pathwalk when it is in RCU-walk mode as well as when it is in Ref-walk mode. This permits __follow_mount_rcu() to call d_manage() directly. d_manage() needs a parameter to indicate that it is in RCU-walk mode as it isn't allowed to sleep if in that mode (but should return -ECHILD instead). autofs4_d_manage() can then be set to retain RCU-walk mode if the daemon accesses it and otherwise request dropping back to ref-walk mode. Signed-off-by: David Howells <dhowells@redhat.com> Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
Diffstat (limited to 'fs/namei.c')
-rw-r--r--fs/namei.c15
1 files changed, 8 insertions, 7 deletions
diff --git a/fs/namei.c b/fs/namei.c
index 373852012713..5c89695ae1e4 100644
--- a/fs/namei.c
+++ b/fs/namei.c
@@ -987,7 +987,8 @@ static int follow_managed(struct path *path, unsigned flags)
987 if (managed & DCACHE_MANAGE_TRANSIT) { 987 if (managed & DCACHE_MANAGE_TRANSIT) {
988 BUG_ON(!path->dentry->d_op); 988 BUG_ON(!path->dentry->d_op);
989 BUG_ON(!path->dentry->d_op->d_manage); 989 BUG_ON(!path->dentry->d_op->d_manage);
990 ret = path->dentry->d_op->d_manage(path->dentry, false); 990 ret = path->dentry->d_op->d_manage(path->dentry,
991 false, false);
991 if (ret < 0) 992 if (ret < 0)
992 return ret == -EISDIR ? 0 : ret; 993 return ret == -EISDIR ? 0 : ret;
993 } 994 }
@@ -1048,13 +1049,12 @@ int follow_down_one(struct path *path)
1048static bool __follow_mount_rcu(struct nameidata *nd, struct path *path, 1049static bool __follow_mount_rcu(struct nameidata *nd, struct path *path,
1049 struct inode **inode, bool reverse_transit) 1050 struct inode **inode, bool reverse_transit)
1050{ 1051{
1051 unsigned abort_mask =
1052 reverse_transit ? 0 : DCACHE_MANAGE_TRANSIT;
1053
1054 while (d_mountpoint(path->dentry)) { 1052 while (d_mountpoint(path->dentry)) {
1055 struct vfsmount *mounted; 1053 struct vfsmount *mounted;
1056 if (path->dentry->d_flags & abort_mask) 1054 if (unlikely(path->dentry->d_flags & DCACHE_MANAGE_TRANSIT) &&
1057 return true; 1055 !reverse_transit &&
1056 path->dentry->d_op->d_manage(path->dentry, false, true) < 0)
1057 return false;
1058 mounted = __lookup_mnt(path->mnt, path->dentry, 1); 1058 mounted = __lookup_mnt(path->mnt, path->dentry, 1);
1059 if (!mounted) 1059 if (!mounted)
1060 break; 1060 break;
@@ -1132,7 +1132,8 @@ int follow_down(struct path *path, bool mounting_here)
1132 if (managed & DCACHE_MANAGE_TRANSIT) { 1132 if (managed & DCACHE_MANAGE_TRANSIT) {
1133 BUG_ON(!path->dentry->d_op); 1133 BUG_ON(!path->dentry->d_op);
1134 BUG_ON(!path->dentry->d_op->d_manage); 1134 BUG_ON(!path->dentry->d_op->d_manage);
1135 ret = path->dentry->d_op->d_manage(path->dentry, mounting_here); 1135 ret = path->dentry->d_op->d_manage(
1136 path->dentry, mounting_here, false);
1136 if (ret < 0) 1137 if (ret < 0)
1137 return ret == -EISDIR ? 0 : ret; 1138 return ret == -EISDIR ? 0 : ret;
1138 } 1139 }