diff options
author | David Howells <dhowells@redhat.com> | 2011-01-14 13:46:51 -0500 |
---|---|---|
committer | Al Viro <viro@zeniv.linux.org.uk> | 2011-01-15 20:07:47 -0500 |
commit | ab90911ff90cdab59b31c045c3f0ae480d14f29d (patch) | |
tree | 683450a66eb9dc6bf053e38d63f4740bb53a7b6e /fs/namei.c | |
parent | 87556ef19926e97464e0163a7840140527ae6615 (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.c | 15 |
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) | |||
1048 | static bool __follow_mount_rcu(struct nameidata *nd, struct path *path, | 1049 | static 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 | } |