step_into(): move fetching ->d_inode past handle_mounts()
... and lose messing with it in __follow_mount_rcu() Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
This commit is contained in:
parent
4cb6402480
commit
3bd8bc8971
31
fs/namei.c
31
fs/namei.c
@ -1474,8 +1474,7 @@ EXPORT_SYMBOL(follow_down);
|
||||
* Try to skip to top of mountpoint pile in rcuwalk mode. Fail if
|
||||
* we meet a managed dentry that would need blocking.
|
||||
*/
|
||||
static bool __follow_mount_rcu(struct nameidata *nd, struct path *path,
|
||||
struct inode **inode)
|
||||
static bool __follow_mount_rcu(struct nameidata *nd, struct path *path)
|
||||
{
|
||||
struct dentry *dentry = path->dentry;
|
||||
unsigned int flags = dentry->d_flags;
|
||||
@ -1505,13 +1504,6 @@ static bool __follow_mount_rcu(struct nameidata *nd, struct path *path,
|
||||
dentry = path->dentry = mounted->mnt.mnt_root;
|
||||
nd->state |= ND_JUMPED;
|
||||
nd->next_seq = read_seqcount_begin(&dentry->d_seq);
|
||||
*inode = dentry->d_inode;
|
||||
/*
|
||||
* We don't need to re-check ->d_seq after this
|
||||
* ->d_inode read - there will be an RCU delay
|
||||
* between mount hash removal and ->mnt_root
|
||||
* becoming unpinned.
|
||||
*/
|
||||
flags = dentry->d_flags;
|
||||
// makes sure that non-RCU pathwalk could reach
|
||||
// this state.
|
||||
@ -1527,7 +1519,7 @@ static bool __follow_mount_rcu(struct nameidata *nd, struct path *path,
|
||||
}
|
||||
|
||||
static inline int handle_mounts(struct nameidata *nd, struct dentry *dentry,
|
||||
struct path *path, struct inode **inode)
|
||||
struct path *path)
|
||||
{
|
||||
bool jumped;
|
||||
int ret;
|
||||
@ -1536,12 +1528,7 @@ static inline int handle_mounts(struct nameidata *nd, struct dentry *dentry,
|
||||
path->dentry = dentry;
|
||||
if (nd->flags & LOOKUP_RCU) {
|
||||
unsigned int seq = nd->next_seq;
|
||||
*inode = dentry->d_inode;
|
||||
if (read_seqcount_retry(&dentry->d_seq, seq))
|
||||
return -ECHILD;
|
||||
if (unlikely(!*inode))
|
||||
return -ENOENT;
|
||||
if (likely(__follow_mount_rcu(nd, path, inode)))
|
||||
if (likely(__follow_mount_rcu(nd, path)))
|
||||
return 0;
|
||||
// *path and nd->next_seq might've been clobbered
|
||||
path->mnt = nd->path.mnt;
|
||||
@ -1561,8 +1548,6 @@ static inline int handle_mounts(struct nameidata *nd, struct dentry *dentry,
|
||||
dput(path->dentry);
|
||||
if (path->mnt != nd->path.mnt)
|
||||
mntput(path->mnt);
|
||||
} else {
|
||||
*inode = d_backing_inode(path->dentry);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
@ -1843,15 +1828,21 @@ static const char *step_into(struct nameidata *nd, int flags,
|
||||
{
|
||||
struct path path;
|
||||
struct inode *inode;
|
||||
int err = handle_mounts(nd, dentry, &path, &inode);
|
||||
int err = handle_mounts(nd, dentry, &path);
|
||||
|
||||
if (err < 0)
|
||||
return ERR_PTR(err);
|
||||
inode = path.dentry->d_inode;
|
||||
if (likely(!d_is_symlink(path.dentry)) ||
|
||||
((flags & WALK_TRAILING) && !(nd->flags & LOOKUP_FOLLOW)) ||
|
||||
(flags & WALK_NOFOLLOW)) {
|
||||
/* not a symlink or should not follow */
|
||||
if (!(nd->flags & LOOKUP_RCU)) {
|
||||
if (nd->flags & LOOKUP_RCU) {
|
||||
if (read_seqcount_retry(&path.dentry->d_seq, nd->next_seq))
|
||||
return ERR_PTR(-ECHILD);
|
||||
if (unlikely(!inode))
|
||||
return ERR_PTR(-ENOENT);
|
||||
} else {
|
||||
dput(nd->path.dentry);
|
||||
if (nd->path.mnt != path.mnt)
|
||||
mntput(nd->path.mnt);
|
||||
|
Loading…
Reference in New Issue
Block a user