aboutsummaryrefslogtreecommitdiffstats
path: root/fs/namei.c
diff options
context:
space:
mode:
authorNeilBrown <neilb@suse.de>2014-08-04 03:06:29 -0400
committerAl Viro <viro@zeniv.linux.org.uk>2014-08-07 14:40:10 -0400
commitb8faf035ea9d0011b04856a8198e2e212d93346a (patch)
treefe06d46ee4a2d659f05740e331a8c823d62d5e3a /fs/namei.c
parent7c33d5972ce382bcc506d16235f1e9b7d22cbef8 (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.c27
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}
1092EXPORT_SYMBOL(follow_down_one); 1092EXPORT_SYMBOL(follow_down_one);
1093 1093
1094static inline bool managed_dentry_might_block(struct dentry *dentry) 1094static 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
1136static int follow_dotdot_rcu(struct nameidata *nd) 1144static 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;
1410unlazy: 1415unlazy:
1411 if (unlazy_walk(nd, dentry)) 1416 if (unlazy_walk(nd, dentry))
1412 return -ECHILD; 1417 return -ECHILD;