diff options
author | Al Viro <viro@zeniv.linux.org.uk> | 2016-03-06 22:20:52 +0300 |
---|---|---|
committer | Al Viro <viro@zeniv.linux.org.uk> | 2016-03-14 07:15:46 +0300 |
commit | 949a852e46dda07caaa0ff02e181f55d24e3ebf8 (patch) | |
tree | 7f2d5177638fb4fd6257a2e2571a3c556de08ce9 /fs/namei.c | |
parent | e3c13928086f1ed3620329b9fff678df2294d327 (diff) | |
download | linux-949a852e46dda07caaa0ff02e181f55d24e3ebf8.tar.xz |
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>
Diffstat (limited to 'fs/namei.c')
-rw-r--r-- | fs/namei.c | 58 |
1 files changed, 35 insertions, 23 deletions
diff --git a/fs/namei.c b/fs/namei.c index cb70a817d439..dbb8ec1a2006 100644 --- a/fs/namei.c +++ b/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; |