aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAl Viro <viro@zeniv.linux.org.uk>2016-03-06 14:20:52 -0500
committerAl Viro <viro@zeniv.linux.org.uk>2016-03-14 00:15:46 -0400
commit949a852e46dda07caaa0ff02e181f55d24e3ebf8 (patch)
tree7f2d5177638fb4fd6257a2e2571a3c556de08ce9
parente3c13928086f1ed3620329b9fff678df2294d327 (diff)
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>
-rw-r--r--fs/namei.c58
-rw-r--r--include/linux/namei.h1
2 files changed, 36 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,
1605{ 1605{
1606 struct dentry *dentry; 1606 struct dentry *dentry;
1607 inode_lock(dir->d_inode); 1607 inode_lock(dir->d_inode);
1608 dentry = __lookup_hash(name, dir, flags); 1608 dentry = d_lookup(dir, name);
1609 if (unlikely(dentry)) {
1610 if ((dentry->d_flags & DCACHE_OP_REVALIDATE) &&
1611 !(flags & LOOKUP_NO_REVAL)) {
1612 int error = d_revalidate(dentry, flags);
1613 if (unlikely(error <= 0)) {
1614 if (!error)
1615 d_invalidate(dentry);
1616 dput(dentry);
1617 dentry = ERR_PTR(error);
1618 }
1619 }
1620 if (dentry) {
1621 inode_unlock(dir->d_inode);
1622 return dentry;
1623 }
1624 }
1625 dentry = d_alloc(dir, name);
1626 if (unlikely(!dentry)) {
1627 inode_unlock(dir->d_inode);
1628 return ERR_PTR(-ENOMEM);
1629 }
1630 dentry = lookup_real(dir->d_inode, dentry, flags);
1609 inode_unlock(dir->d_inode); 1631 inode_unlock(dir->d_inode);
1610 return dentry; 1632 return dentry;
1611} 1633}
@@ -2425,31 +2447,21 @@ mountpoint_last(struct nameidata *nd, struct path *path)
2425 if (error) 2447 if (error)
2426 return error; 2448 return error;
2427 dentry = dget(nd->path.dentry); 2449 dentry = dget(nd->path.dentry);
2428 goto done; 2450 } else {
2429 } 2451 dentry = d_lookup(dir, &nd->last);
2430
2431 inode_lock(dir->d_inode);
2432 dentry = d_lookup(dir, &nd->last);
2433 if (!dentry) {
2434 /*
2435 * No cached dentry. Mounted dentries are pinned in the cache,
2436 * so that means that this dentry is probably a symlink or the
2437 * path doesn't actually point to a mounted dentry.
2438 */
2439 dentry = d_alloc(dir, &nd->last);
2440 if (!dentry) { 2452 if (!dentry) {
2441 inode_unlock(dir->d_inode); 2453 /*
2442 return -ENOMEM; 2454 * No cached dentry. Mounted dentries are pinned in the
2443 } 2455 * cache, so that means that this dentry is probably
2444 dentry = lookup_real(dir->d_inode, dentry, nd->flags); 2456 * a symlink or the path doesn't actually point
2445 if (IS_ERR(dentry)) { 2457 * to a mounted dentry.
2446 inode_unlock(dir->d_inode); 2458 */
2447 return PTR_ERR(dentry); 2459 dentry = lookup_slow(&nd->last, dir,
2460 nd->flags | LOOKUP_NO_REVAL);
2461 if (IS_ERR(dentry))
2462 return PTR_ERR(dentry);
2448 } 2463 }
2449 } 2464 }
2450 inode_unlock(dir->d_inode);
2451
2452done:
2453 if (d_is_negative(dentry)) { 2465 if (d_is_negative(dentry)) {
2454 dput(dentry); 2466 dput(dentry);
2455 return -ENOENT; 2467 return -ENOENT;
diff --git a/include/linux/namei.h b/include/linux/namei.h
index d0f25d81b46a..77d01700daf7 100644
--- a/include/linux/namei.h
+++ b/include/linux/namei.h
@@ -31,6 +31,7 @@ enum {LAST_NORM, LAST_ROOT, LAST_DOT, LAST_DOTDOT, LAST_BIND};
31#define LOOKUP_PARENT 0x0010 31#define LOOKUP_PARENT 0x0010
32#define LOOKUP_REVAL 0x0020 32#define LOOKUP_REVAL 0x0020
33#define LOOKUP_RCU 0x0040 33#define LOOKUP_RCU 0x0040
34#define LOOKUP_NO_REVAL 0x0080
34 35
35/* 36/*
36 * Intent data 37 * Intent data