diff options
author | NeilBrown <neilb@suse.de> | 2014-08-04 03:06:29 -0400 |
---|---|---|
committer | Al Viro <viro@zeniv.linux.org.uk> | 2014-08-07 14:40:10 -0400 |
commit | b8faf035ea9d0011b04856a8198e2e212d93346a (patch) | |
tree | fe06d46ee4a2d659f05740e331a8c823d62d5e3a /fs/namei.c | |
parent | 7c33d5972ce382bcc506d16235f1e9b7d22cbef8 (diff) |
VFS: allow ->d_manage() to declare -EISDIR in rcu_walk mode.
In REF-walk mode, ->d_manage can return -EISDIR to indicate
that the dentry is not really a mount trap (or even a mount point)
and that any mounts or any DCACHE_NEED_AUTOMOUNT flag should be
ignored.
RCU-walk mode doesn't currently support this, so if there is a dentry
with DCACHE_NEED_AUTOMOUNT set but which shouldn't be a mount-trap,
lookup_fast() will always drop in REF-walk mode.
With this patch, an -EISDIR from ->d_manage will always cause mounts
and automounts to be ignored, both in REF-walk and RCU-walk.
Bug-fixed-by: Dan Carpenter <dan.carpenter@oracle.com>
Cc: Ian Kent <raven@themaw.net>
Signed-off-by: NeilBrown <neilb@suse.de>
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
Diffstat (limited to 'fs/namei.c')
-rw-r--r-- | fs/namei.c | 27 |
1 files changed, 16 insertions, 11 deletions
diff --git a/fs/namei.c b/fs/namei.c index 0ff23cecb1bb..8a217c48f6db 100644 --- a/fs/namei.c +++ b/fs/namei.c | |||
@@ -1091,10 +1091,10 @@ int follow_down_one(struct path *path) | |||
1091 | } | 1091 | } |
1092 | EXPORT_SYMBOL(follow_down_one); | 1092 | EXPORT_SYMBOL(follow_down_one); |
1093 | 1093 | ||
1094 | static inline bool managed_dentry_might_block(struct dentry *dentry) | 1094 | static inline int managed_dentry_rcu(struct dentry *dentry) |
1095 | { | 1095 | { |
1096 | return (dentry->d_flags & DCACHE_MANAGE_TRANSIT && | 1096 | return (dentry->d_flags & DCACHE_MANAGE_TRANSIT) ? |
1097 | dentry->d_op->d_manage(dentry, true) < 0); | 1097 | dentry->d_op->d_manage(dentry, true) : 0; |
1098 | } | 1098 | } |
1099 | 1099 | ||
1100 | /* | 1100 | /* |
@@ -1110,11 +1110,18 @@ static bool __follow_mount_rcu(struct nameidata *nd, struct path *path, | |||
1110 | * Don't forget we might have a non-mountpoint managed dentry | 1110 | * Don't forget we might have a non-mountpoint managed dentry |
1111 | * that wants to block transit. | 1111 | * that wants to block transit. |
1112 | */ | 1112 | */ |
1113 | if (unlikely(managed_dentry_might_block(path->dentry))) | 1113 | switch (managed_dentry_rcu(path->dentry)) { |
1114 | case -ECHILD: | ||
1115 | default: | ||
1114 | return false; | 1116 | return false; |
1117 | case -EISDIR: | ||
1118 | return true; | ||
1119 | case 0: | ||
1120 | break; | ||
1121 | } | ||
1115 | 1122 | ||
1116 | if (!d_mountpoint(path->dentry)) | 1123 | if (!d_mountpoint(path->dentry)) |
1117 | return true; | 1124 | return !(path->dentry->d_flags & DCACHE_NEED_AUTOMOUNT); |
1118 | 1125 | ||
1119 | mounted = __lookup_mnt(path->mnt, path->dentry); | 1126 | mounted = __lookup_mnt(path->mnt, path->dentry); |
1120 | if (!mounted) | 1127 | if (!mounted) |
@@ -1130,7 +1137,8 @@ static bool __follow_mount_rcu(struct nameidata *nd, struct path *path, | |||
1130 | */ | 1137 | */ |
1131 | *inode = path->dentry->d_inode; | 1138 | *inode = path->dentry->d_inode; |
1132 | } | 1139 | } |
1133 | return read_seqretry(&mount_lock, nd->m_seq); | 1140 | return read_seqretry(&mount_lock, nd->m_seq) && |
1141 | !(path->dentry->d_flags & DCACHE_NEED_AUTOMOUNT); | ||
1134 | } | 1142 | } |
1135 | 1143 | ||
1136 | static int follow_dotdot_rcu(struct nameidata *nd) | 1144 | static int follow_dotdot_rcu(struct nameidata *nd) |
@@ -1402,11 +1410,8 @@ static int lookup_fast(struct nameidata *nd, | |||
1402 | } | 1410 | } |
1403 | path->mnt = mnt; | 1411 | path->mnt = mnt; |
1404 | path->dentry = dentry; | 1412 | path->dentry = dentry; |
1405 | if (unlikely(!__follow_mount_rcu(nd, path, inode))) | 1413 | if (likely(__follow_mount_rcu(nd, path, inode))) |
1406 | goto unlazy; | 1414 | return 0; |
1407 | if (unlikely(path->dentry->d_flags & DCACHE_NEED_AUTOMOUNT)) | ||
1408 | goto unlazy; | ||
1409 | return 0; | ||
1410 | unlazy: | 1415 | unlazy: |
1411 | if (unlazy_walk(nd, dentry)) | 1416 | if (unlazy_walk(nd, dentry)) |
1412 | return -ECHILD; | 1417 | return -ECHILD; |