diff options
Diffstat (limited to 'fs')
-rw-r--r-- | fs/autofs4/root.c | 8 | ||||
-rw-r--r-- | fs/namei.c | 15 |
2 files changed, 14 insertions, 9 deletions
diff --git a/fs/autofs4/root.c b/fs/autofs4/root.c index 9194e274f849..dbd95512808c 100644 --- a/fs/autofs4/root.c +++ b/fs/autofs4/root.c | |||
@@ -36,7 +36,7 @@ static long autofs4_root_compat_ioctl(struct file *,unsigned int,unsigned long); | |||
36 | static int autofs4_dir_open(struct inode *inode, struct file *file); | 36 | static int autofs4_dir_open(struct inode *inode, struct file *file); |
37 | static struct dentry *autofs4_lookup(struct inode *,struct dentry *, struct nameidata *); | 37 | static struct dentry *autofs4_lookup(struct inode *,struct dentry *, struct nameidata *); |
38 | static struct vfsmount *autofs4_d_automount(struct path *); | 38 | static struct vfsmount *autofs4_d_automount(struct path *); |
39 | static int autofs4_d_manage(struct dentry *, bool); | 39 | static int autofs4_d_manage(struct dentry *, bool, bool); |
40 | 40 | ||
41 | const struct file_operations autofs4_root_operations = { | 41 | const struct file_operations autofs4_root_operations = { |
42 | .open = dcache_dir_open, | 42 | .open = dcache_dir_open, |
@@ -450,7 +450,7 @@ done: | |||
450 | return NULL; | 450 | return NULL; |
451 | } | 451 | } |
452 | 452 | ||
453 | int autofs4_d_manage(struct dentry *dentry, bool mounting_here) | 453 | int autofs4_d_manage(struct dentry *dentry, bool mounting_here, bool rcu_walk) |
454 | { | 454 | { |
455 | struct autofs_sb_info *sbi = autofs4_sbi(dentry->d_sb); | 455 | struct autofs_sb_info *sbi = autofs4_sbi(dentry->d_sb); |
456 | 456 | ||
@@ -464,6 +464,10 @@ int autofs4_d_manage(struct dentry *dentry, bool mounting_here) | |||
464 | return 0; | 464 | return 0; |
465 | } | 465 | } |
466 | 466 | ||
467 | /* We need to sleep, so we need pathwalk to be in ref-mode */ | ||
468 | if (rcu_walk) | ||
469 | return -ECHILD; | ||
470 | |||
467 | /* Wait for pending expires */ | 471 | /* Wait for pending expires */ |
468 | do_expire_wait(dentry); | 472 | do_expire_wait(dentry); |
469 | 473 | ||
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 | } |