namei: teach lookup_slow() to skip revalidate
... and make mountpoint_last() use it. That makes all candidates for lookup with parent locked shared go through lookup_slow(). Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
This commit is contained in:
parent
e3c1392808
commit
949a852e46
58
fs/namei.c
58
fs/namei.c
|
@ -1605,7 +1605,29 @@ static struct dentry *lookup_slow(const struct qstr *name,
|
|||
{
|
||||
struct dentry *dentry;
|
||||
inode_lock(dir->d_inode);
|
||||
dentry = __lookup_hash(name, dir, flags);
|
||||
dentry = d_lookup(dir, name);
|
||||
if (unlikely(dentry)) {
|
||||
if ((dentry->d_flags & DCACHE_OP_REVALIDATE) &&
|
||||
!(flags & LOOKUP_NO_REVAL)) {
|
||||
int error = d_revalidate(dentry, flags);
|
||||
if (unlikely(error <= 0)) {
|
||||
if (!error)
|
||||
d_invalidate(dentry);
|
||||
dput(dentry);
|
||||
dentry = ERR_PTR(error);
|
||||
}
|
||||
}
|
||||
if (dentry) {
|
||||
inode_unlock(dir->d_inode);
|
||||
return dentry;
|
||||
}
|
||||
}
|
||||
dentry = d_alloc(dir, name);
|
||||
if (unlikely(!dentry)) {
|
||||
inode_unlock(dir->d_inode);
|
||||
return ERR_PTR(-ENOMEM);
|
||||
}
|
||||
dentry = lookup_real(dir->d_inode, dentry, flags);
|
||||
inode_unlock(dir->d_inode);
|
||||
return dentry;
|
||||
}
|
||||
|
@ -2425,31 +2447,21 @@ mountpoint_last(struct nameidata *nd, struct path *path)
|
|||
if (error)
|
||||
return error;
|
||||
dentry = dget(nd->path.dentry);
|
||||
goto done;
|
||||
}
|
||||
|
||||
inode_lock(dir->d_inode);
|
||||
dentry = d_lookup(dir, &nd->last);
|
||||
if (!dentry) {
|
||||
/*
|
||||
* No cached dentry. Mounted dentries are pinned in the cache,
|
||||
* so that means that this dentry is probably a symlink or the
|
||||
* path doesn't actually point to a mounted dentry.
|
||||
*/
|
||||
dentry = d_alloc(dir, &nd->last);
|
||||
} else {
|
||||
dentry = d_lookup(dir, &nd->last);
|
||||
if (!dentry) {
|
||||
inode_unlock(dir->d_inode);
|
||||
return -ENOMEM;
|
||||
}
|
||||
dentry = lookup_real(dir->d_inode, dentry, nd->flags);
|
||||
if (IS_ERR(dentry)) {
|
||||
inode_unlock(dir->d_inode);
|
||||
return PTR_ERR(dentry);
|
||||
/*
|
||||
* No cached dentry. Mounted dentries are pinned in the
|
||||
* cache, so that means that this dentry is probably
|
||||
* a symlink or the path doesn't actually point
|
||||
* to a mounted dentry.
|
||||
*/
|
||||
dentry = lookup_slow(&nd->last, dir,
|
||||
nd->flags | LOOKUP_NO_REVAL);
|
||||
if (IS_ERR(dentry))
|
||||
return PTR_ERR(dentry);
|
||||
}
|
||||
}
|
||||
inode_unlock(dir->d_inode);
|
||||
|
||||
done:
|
||||
if (d_is_negative(dentry)) {
|
||||
dput(dentry);
|
||||
return -ENOENT;
|
||||
|
|
|
@ -31,6 +31,7 @@ enum {LAST_NORM, LAST_ROOT, LAST_DOT, LAST_DOTDOT, LAST_BIND};
|
|||
#define LOOKUP_PARENT 0x0010
|
||||
#define LOOKUP_REVAL 0x0020
|
||||
#define LOOKUP_RCU 0x0040
|
||||
#define LOOKUP_NO_REVAL 0x0080
|
||||
|
||||
/*
|
||||
* Intent data
|
||||
|
|
Loading…
Reference in New Issue