Commit b8faf035 authored by NeilBrown's avatar NeilBrown Committed by Al Viro

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: default avatarDan Carpenter <dan.carpenter@oracle.com>
Cc: Ian Kent <raven@themaw.net>
Signed-off-by: default avatarNeilBrown <neilb@suse.de>
Signed-off-by: default avatarAl Viro <viro@zeniv.linux.org.uk>
parent 7c33d597
...@@ -1053,7 +1053,8 @@ struct dentry_operations { ...@@ -1053,7 +1053,8 @@ struct dentry_operations {
If the 'rcu_walk' parameter is true, then the caller is doing a If the 'rcu_walk' parameter is true, then the caller is doing a
pathwalk in RCU-walk mode. Sleeping is not permitted in this mode, pathwalk in RCU-walk mode. Sleeping is not permitted in this mode,
and the caller can be asked to leave it and call again by returning and the caller can be asked to leave it and call again by returning
-ECHILD. -ECHILD. -EISDIR may also be returned to tell pathwalk to
ignore d_automount or any mounts.
This function is only used if DCACHE_MANAGE_TRANSIT is set on the This function is only used if DCACHE_MANAGE_TRANSIT is set on the
dentry being transited from. dentry being transited from.
......
...@@ -1091,10 +1091,10 @@ int follow_down_one(struct path *path) ...@@ -1091,10 +1091,10 @@ int follow_down_one(struct path *path)
} }
EXPORT_SYMBOL(follow_down_one); EXPORT_SYMBOL(follow_down_one);
static inline bool managed_dentry_might_block(struct dentry *dentry) static inline int managed_dentry_rcu(struct dentry *dentry)
{ {
return (dentry->d_flags & DCACHE_MANAGE_TRANSIT && return (dentry->d_flags & DCACHE_MANAGE_TRANSIT) ?
dentry->d_op->d_manage(dentry, true) < 0); dentry->d_op->d_manage(dentry, true) : 0;
} }
/* /*
...@@ -1110,11 +1110,18 @@ static bool __follow_mount_rcu(struct nameidata *nd, struct path *path, ...@@ -1110,11 +1110,18 @@ static bool __follow_mount_rcu(struct nameidata *nd, struct path *path,
* Don't forget we might have a non-mountpoint managed dentry * Don't forget we might have a non-mountpoint managed dentry
* that wants to block transit. * that wants to block transit.
*/ */
if (unlikely(managed_dentry_might_block(path->dentry))) switch (managed_dentry_rcu(path->dentry)) {
case -ECHILD:
default:
return false; return false;
case -EISDIR:
return true;
case 0:
break;
}
if (!d_mountpoint(path->dentry)) if (!d_mountpoint(path->dentry))
return true; return !(path->dentry->d_flags & DCACHE_NEED_AUTOMOUNT);
mounted = __lookup_mnt(path->mnt, path->dentry); mounted = __lookup_mnt(path->mnt, path->dentry);
if (!mounted) if (!mounted)
...@@ -1130,7 +1137,8 @@ static bool __follow_mount_rcu(struct nameidata *nd, struct path *path, ...@@ -1130,7 +1137,8 @@ static bool __follow_mount_rcu(struct nameidata *nd, struct path *path,
*/ */
*inode = path->dentry->d_inode; *inode = path->dentry->d_inode;
} }
return read_seqretry(&mount_lock, nd->m_seq); return read_seqretry(&mount_lock, nd->m_seq) &&
!(path->dentry->d_flags & DCACHE_NEED_AUTOMOUNT);
} }
static int follow_dotdot_rcu(struct nameidata *nd) static int follow_dotdot_rcu(struct nameidata *nd)
...@@ -1402,11 +1410,8 @@ static int lookup_fast(struct nameidata *nd, ...@@ -1402,11 +1410,8 @@ static int lookup_fast(struct nameidata *nd,
} }
path->mnt = mnt; path->mnt = mnt;
path->dentry = dentry; path->dentry = dentry;
if (unlikely(!__follow_mount_rcu(nd, path, inode))) if (likely(__follow_mount_rcu(nd, path, inode)))
goto unlazy; return 0;
if (unlikely(path->dentry->d_flags & DCACHE_NEED_AUTOMOUNT))
goto unlazy;
return 0;
unlazy: unlazy:
if (unlazy_walk(nd, dentry)) if (unlazy_walk(nd, dentry))
return -ECHILD; return -ECHILD;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment