Commit 16c2cd7179881d5dd87779512ca5a0d657c64f62

Authored by Al Viro
1 parent fe479a580d

untangle the "need_reval_dot" mess

instead of ad-hackery around need_reval_dot(), do the following:
set a flag (LOOKUP_JUMPED) in the beginning of path, on absolute
symlink traversal, on ".." and on procfs-style symlinks.  Clear on
normal components, leave unchanged on ".".  Non-nested callers of
link_path_walk() call handle_reval_path(), which checks that flag
is set and that fs does want the final revalidate thing, then does
->d_revalidate().  In link_path_walk() all the return_reval stuff
is gone.

Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>

Showing 2 changed files with 46 additions and 63 deletions Side-by-side Diff

... ... @@ -613,19 +613,8 @@
613 613 return dentry;
614 614 }
615 615  
616   -static inline int need_reval_dot(struct dentry *dentry)
617   -{
618   - if (likely(!(dentry->d_flags & DCACHE_OP_REVALIDATE)))
619   - return 0;
620   -
621   - if (likely(!(dentry->d_sb->s_type->fs_flags & FS_REVAL_DOT)))
622   - return 0;
623   -
624   - return 1;
625   -}
626   -
627 616 /*
628   - * force_reval_path - force revalidation of a dentry
  617 + * handle_reval_path - force revalidation of a dentry
629 618 *
630 619 * In some situations the path walking code will trust dentries without
631 620 * revalidating them. This causes problems for filesystems that depend on
632 621  
633 622  
634 623  
635 624  
636 625  
637 626  
... ... @@ -639,27 +628,28 @@
639 628 * invalidate the dentry. It's up to the caller to handle putting references
640 629 * to the path if necessary.
641 630 */
642   -static int
643   -force_reval_path(struct path *path, struct nameidata *nd)
  631 +static inline int handle_reval_path(struct nameidata *nd)
644 632 {
  633 + struct dentry *dentry = nd->path.dentry;
645 634 int status;
646   - struct dentry *dentry = path->dentry;
647 635  
648   - /*
649   - * only check on filesystems where it's possible for the dentry to
650   - * become stale.
651   - */
652   - if (!need_reval_dot(dentry))
  636 + if (likely(!(nd->flags & LOOKUP_JUMPED)))
653 637 return 0;
654 638  
  639 + if (likely(!(dentry->d_flags & DCACHE_OP_REVALIDATE)))
  640 + return 0;
  641 +
  642 + if (likely(!(dentry->d_sb->s_type->fs_flags & FS_REVAL_DOT)))
  643 + return 0;
  644 +
  645 + /* Note: we do not d_invalidate() */
655 646 status = d_revalidate(dentry, nd);
656 647 if (status > 0)
657 648 return 0;
658 649  
659   - if (!status) {
660   - d_invalidate(dentry);
  650 + if (!status)
661 651 status = -ESTALE;
662   - }
  652 +
663 653 return status;
664 654 }
665 655  
... ... @@ -728,6 +718,7 @@
728 718 path_put(&nd->path);
729 719 nd->path = nd->root;
730 720 path_get(&nd->root);
  721 + nd->flags |= LOOKUP_JUMPED;
731 722 }
732 723 nd->inode = nd->path.dentry->d_inode;
733 724  
... ... @@ -779,11 +770,8 @@
779 770 error = 0;
780 771 if (s)
781 772 error = __vfs_follow_link(nd, s);
782   - else if (nd->last_type == LAST_BIND) {
783   - error = force_reval_path(&nd->path, nd);
784   - if (error)
785   - path_put(&nd->path);
786   - }
  773 + else if (nd->last_type == LAST_BIND)
  774 + nd->flags |= LOOKUP_JUMPED;
787 775 }
788 776 return error;
789 777 }
... ... @@ -1351,7 +1339,7 @@
1351 1339 while (*name=='/')
1352 1340 name++;
1353 1341 if (!*name)
1354   - goto return_reval;
  1342 + goto return_base;
1355 1343  
1356 1344 if (nd->depth)
1357 1345 lookup_flags = LOOKUP_FOLLOW | (nd->flags & LOOKUP_CONTINUE);
1358 1346  
1359 1347  
... ... @@ -1385,12 +1373,16 @@
1385 1373 type = LAST_NORM;
1386 1374 if (this.name[0] == '.') switch (this.len) {
1387 1375 case 2:
1388   - if (this.name[1] == '.')
  1376 + if (this.name[1] == '.') {
1389 1377 type = LAST_DOTDOT;
  1378 + nd->flags |= LOOKUP_JUMPED;
  1379 + }
1390 1380 break;
1391 1381 case 1:
1392 1382 type = LAST_DOT;
1393 1383 }
  1384 + if (likely(type == LAST_NORM))
  1385 + nd->flags &= ~LOOKUP_JUMPED;
1394 1386  
1395 1387 /* remove trailing slashes? */
1396 1388 if (!c)
... ... @@ -1456,7 +1448,7 @@
1456 1448 } else
1457 1449 follow_dotdot(nd);
1458 1450 }
1459   - goto return_reval;
  1451 + goto return_base;
1460 1452 }
1461 1453 err = do_lookup(nd, &this, &next, &inode);
1462 1454 if (err)
... ... @@ -1483,24 +1475,6 @@
1483 1475 lookup_parent:
1484 1476 nd->last = this;
1485 1477 nd->last_type = type;
1486   - if (type == LAST_NORM)
1487   - goto return_base;
1488   -return_reval:
1489   - /*
1490   - * We bypassed the ordinary revalidation routines.
1491   - * We may need to check the cached dentry for staleness.
1492   - */
1493   - if (need_reval_dot(nd->path.dentry)) {
1494   - if (nameidata_drop_rcu_last_maybe(nd))
1495   - return -ECHILD;
1496   - /* Note: we do not d_invalidate() */
1497   - err = d_revalidate(nd->path.dentry, nd);
1498   - if (!err)
1499   - err = -ESTALE;
1500   - if (err < 0)
1501   - break;
1502   - return 0;
1503   - }
1504 1478 return_base:
1505 1479 if (nameidata_drop_rcu_last_maybe(nd))
1506 1480 return -ECHILD;
... ... @@ -1523,7 +1497,7 @@
1523 1497 struct file *file;
1524 1498  
1525 1499 nd->last_type = LAST_ROOT; /* if there are only slashes... */
1526   - nd->flags = flags;
  1500 + nd->flags = flags | LOOKUP_JUMPED;
1527 1501 nd->depth = 0;
1528 1502 nd->root.mnt = NULL;
1529 1503 nd->file = NULL;
... ... @@ -1630,6 +1604,9 @@
1630 1604 br_read_unlock(vfsmount_lock);
1631 1605 }
1632 1606  
  1607 + if (!retval)
  1608 + retval = handle_reval_path(nd);
  1609 +
1633 1610 if (nd->file) {
1634 1611 fput(nd->file);
1635 1612 nd->file = NULL;
... ... @@ -1690,7 +1667,7 @@
1690 1667  
1691 1668 /* same as do_path_lookup */
1692 1669 nd->last_type = LAST_ROOT;
1693   - nd->flags = flags;
  1670 + nd->flags = flags | LOOKUP_JUMPED;
1694 1671 nd->depth = 0;
1695 1672  
1696 1673 nd->path.dentry = dentry;
... ... @@ -1703,6 +1680,8 @@
1703 1680 current->total_link_count = 0;
1704 1681  
1705 1682 result = link_path_walk(name, nd);
  1683 + if (!result)
  1684 + result = handle_reval_path(nd);
1706 1685 if (result == -ESTALE) {
1707 1686 /* nd->path had been dropped */
1708 1687 current->total_link_count = 0;
1709 1688  
... ... @@ -1710,8 +1689,11 @@
1710 1689 nd->path.mnt = mnt;
1711 1690 nd->inode = dentry->d_inode;
1712 1691 path_get(&nd->path);
1713   - nd->flags |= LOOKUP_REVAL;
  1692 + nd->flags = flags | LOOKUP_JUMPED | LOOKUP_REVAL;
  1693 +
1714 1694 result = link_path_walk(name, nd);
  1695 + if (!result)
  1696 + result = handle_reval_path(nd);
1715 1697 }
1716 1698 if (unlikely(!result && !audit_dummy_context() && nd->path.dentry &&
1717 1699 nd->inode))
1718 1700  
1719 1701  
1720 1702  
1721 1703  
... ... @@ -2198,30 +2180,29 @@
2198 2180 {
2199 2181 struct dentry *dir = nd->path.dentry;
2200 2182 struct file *filp;
2201   - int error = -EISDIR;
  2183 + int error;
2202 2184  
2203 2185 switch (nd->last_type) {
2204 2186 case LAST_DOTDOT:
2205 2187 follow_dotdot(nd);
2206 2188 dir = nd->path.dentry;
2207 2189 case LAST_DOT:
2208   - if (need_reval_dot(dir)) {
2209   - int status = d_revalidate(nd->path.dentry, nd);
2210   - if (!status)
2211   - status = -ESTALE;
2212   - if (status < 0) {
2213   - error = status;
2214   - goto exit;
2215   - }
2216   - }
2217 2190 /* fallthrough */
2218 2191 case LAST_ROOT:
  2192 + error = handle_reval_path(nd);
  2193 + if (error)
  2194 + goto exit;
  2195 + error = -EISDIR;
2219 2196 goto exit;
2220 2197 case LAST_BIND:
  2198 + error = handle_reval_path(nd);
  2199 + if (error)
  2200 + goto exit;
2221 2201 audit_inode(pathname, dir);
2222 2202 goto ok;
2223 2203 }
2224 2204  
  2205 + error = -EISDIR;
2225 2206 /* trailing slashes? */
2226 2207 if (nd->last.name[nd->last.len])
2227 2208 goto exit;
... ... @@ -2422,7 +2403,7 @@
2422 2403 /*
2423 2404 * We have the parent and last component.
2424 2405 */
2425   - nd.flags = flags;
  2406 + nd.flags = (nd.flags & ~LOOKUP_PARENT) | flags;
2426 2407 filp = do_last(&nd, &path, open_flag, acc_mode, mode, pathname);
2427 2408 while (unlikely(!filp)) { /* trailing symlink */
2428 2409 struct path link = path;
include/linux/namei.h
... ... @@ -63,6 +63,8 @@
63 63 #define LOOKUP_EXCL 0x0400
64 64 #define LOOKUP_RENAME_TARGET 0x0800
65 65  
  66 +#define LOOKUP_JUMPED 0x1000
  67 +
66 68 extern int user_path_at(int, const char __user *, unsigned, struct path *);
67 69  
68 70 #define user_path(name, path) user_path_at(AT_FDCWD, name, LOOKUP_FOLLOW, path)