diff options
author | Al Viro <viro@zeniv.linux.org.uk> | 2011-02-22 15:50:10 -0500 |
---|---|---|
committer | Al Viro <viro@zeniv.linux.org.uk> | 2011-03-14 09:15:24 -0400 |
commit | 16c2cd7179881d5dd87779512ca5a0d657c64f62 (patch) | |
tree | 822d14ecf505cb3f53e2afe3e1e7867bb32ca346 /fs/namei.c | |
parent | fe479a580dc9c737c4eb49ff7fdb31d41d2c7003 (diff) |
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>
Diffstat (limited to 'fs/namei.c')
-rw-r--r-- | fs/namei.c | 107 |
1 files changed, 44 insertions, 63 deletions
diff --git a/fs/namei.c b/fs/namei.c index 4521b5ff7c93..450b686e9682 100644 --- a/fs/namei.c +++ b/fs/namei.c | |||
@@ -613,19 +613,8 @@ do_revalidate_rcu(struct dentry *dentry, struct nameidata *nd) | |||
613 | return dentry; | 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 | * In some situations the path walking code will trust dentries without | 619 | * In some situations the path walking code will trust dentries without |
631 | * revalidating them. This causes problems for filesystems that depend on | 620 | * revalidating them. This causes problems for filesystems that depend on |
@@ -639,27 +628,28 @@ static inline int need_reval_dot(struct dentry *dentry) | |||
639 | * invalidate the dentry. It's up to the caller to handle putting references | 628 | * invalidate the dentry. It's up to the caller to handle putting references |
640 | * to the path if necessary. | 629 | * to the path if necessary. |
641 | */ | 630 | */ |
642 | static int | 631 | static inline int handle_reval_path(struct nameidata *nd) |
643 | force_reval_path(struct path *path, struct nameidata *nd) | ||
644 | { | 632 | { |
633 | struct dentry *dentry = nd->path.dentry; | ||
645 | int status; | 634 | int status; |
646 | struct dentry *dentry = path->dentry; | ||
647 | 635 | ||
648 | /* | 636 | if (likely(!(nd->flags & LOOKUP_JUMPED))) |
649 | * only check on filesystems where it's possible for the dentry to | 637 | return 0; |
650 | * become stale. | 638 | |
651 | */ | 639 | if (likely(!(dentry->d_flags & DCACHE_OP_REVALIDATE))) |
652 | if (!need_reval_dot(dentry)) | ||
653 | return 0; | 640 | return 0; |
654 | 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 | status = d_revalidate(dentry, nd); | 646 | status = d_revalidate(dentry, nd); |
656 | if (status > 0) | 647 | if (status > 0) |
657 | return 0; | 648 | return 0; |
658 | 649 | ||
659 | if (!status) { | 650 | if (!status) |
660 | d_invalidate(dentry); | ||
661 | status = -ESTALE; | 651 | status = -ESTALE; |
662 | } | 652 | |
663 | return status; | 653 | return status; |
664 | } | 654 | } |
665 | 655 | ||
@@ -728,6 +718,7 @@ static __always_inline int __vfs_follow_link(struct nameidata *nd, const char *l | |||
728 | path_put(&nd->path); | 718 | path_put(&nd->path); |
729 | nd->path = nd->root; | 719 | nd->path = nd->root; |
730 | path_get(&nd->root); | 720 | path_get(&nd->root); |
721 | nd->flags |= LOOKUP_JUMPED; | ||
731 | } | 722 | } |
732 | nd->inode = nd->path.dentry->d_inode; | 723 | nd->inode = nd->path.dentry->d_inode; |
733 | 724 | ||
@@ -779,11 +770,8 @@ __do_follow_link(const struct path *link, struct nameidata *nd, void **p) | |||
779 | error = 0; | 770 | error = 0; |
780 | if (s) | 771 | if (s) |
781 | error = __vfs_follow_link(nd, s); | 772 | error = __vfs_follow_link(nd, s); |
782 | else if (nd->last_type == LAST_BIND) { | 773 | else if (nd->last_type == LAST_BIND) |
783 | error = force_reval_path(&nd->path, nd); | 774 | nd->flags |= LOOKUP_JUMPED; |
784 | if (error) | ||
785 | path_put(&nd->path); | ||
786 | } | ||
787 | } | 775 | } |
788 | return error; | 776 | return error; |
789 | } | 777 | } |
@@ -1351,7 +1339,7 @@ static int link_path_walk(const char *name, struct nameidata *nd) | |||
1351 | while (*name=='/') | 1339 | while (*name=='/') |
1352 | name++; | 1340 | name++; |
1353 | if (!*name) | 1341 | if (!*name) |
1354 | goto return_reval; | 1342 | goto return_base; |
1355 | 1343 | ||
1356 | if (nd->depth) | 1344 | if (nd->depth) |
1357 | lookup_flags = LOOKUP_FOLLOW | (nd->flags & LOOKUP_CONTINUE); | 1345 | lookup_flags = LOOKUP_FOLLOW | (nd->flags & LOOKUP_CONTINUE); |
@@ -1385,12 +1373,16 @@ static int link_path_walk(const char *name, struct nameidata *nd) | |||
1385 | type = LAST_NORM; | 1373 | type = LAST_NORM; |
1386 | if (this.name[0] == '.') switch (this.len) { | 1374 | if (this.name[0] == '.') switch (this.len) { |
1387 | case 2: | 1375 | case 2: |
1388 | if (this.name[1] == '.') | 1376 | if (this.name[1] == '.') { |
1389 | type = LAST_DOTDOT; | 1377 | type = LAST_DOTDOT; |
1378 | nd->flags |= LOOKUP_JUMPED; | ||
1379 | } | ||
1390 | break; | 1380 | break; |
1391 | case 1: | 1381 | case 1: |
1392 | type = LAST_DOT; | 1382 | type = LAST_DOT; |
1393 | } | 1383 | } |
1384 | if (likely(type == LAST_NORM)) | ||
1385 | nd->flags &= ~LOOKUP_JUMPED; | ||
1394 | 1386 | ||
1395 | /* remove trailing slashes? */ | 1387 | /* remove trailing slashes? */ |
1396 | if (!c) | 1388 | if (!c) |
@@ -1456,7 +1448,7 @@ last_component: | |||
1456 | } else | 1448 | } else |
1457 | follow_dotdot(nd); | 1449 | follow_dotdot(nd); |
1458 | } | 1450 | } |
1459 | goto return_reval; | 1451 | goto return_base; |
1460 | } | 1452 | } |
1461 | err = do_lookup(nd, &this, &next, &inode); | 1453 | err = do_lookup(nd, &this, &next, &inode); |
1462 | if (err) | 1454 | if (err) |
@@ -1483,24 +1475,6 @@ last_component: | |||
1483 | lookup_parent: | 1475 | lookup_parent: |
1484 | nd->last = this; | 1476 | nd->last = this; |
1485 | nd->last_type = type; | 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 | return_base: | 1478 | return_base: |
1505 | if (nameidata_drop_rcu_last_maybe(nd)) | 1479 | if (nameidata_drop_rcu_last_maybe(nd)) |
1506 | return -ECHILD; | 1480 | return -ECHILD; |
@@ -1523,7 +1497,7 @@ static int path_init(int dfd, const char *name, unsigned int flags, struct namei | |||
1523 | struct file *file; | 1497 | struct file *file; |
1524 | 1498 | ||
1525 | nd->last_type = LAST_ROOT; /* if there are only slashes... */ | 1499 | nd->last_type = LAST_ROOT; /* if there are only slashes... */ |
1526 | nd->flags = flags; | 1500 | nd->flags = flags | LOOKUP_JUMPED; |
1527 | nd->depth = 0; | 1501 | nd->depth = 0; |
1528 | nd->root.mnt = NULL; | 1502 | nd->root.mnt = NULL; |
1529 | nd->file = NULL; | 1503 | nd->file = NULL; |
@@ -1630,6 +1604,9 @@ static int path_lookupat(int dfd, const char *name, | |||
1630 | br_read_unlock(vfsmount_lock); | 1604 | br_read_unlock(vfsmount_lock); |
1631 | } | 1605 | } |
1632 | 1606 | ||
1607 | if (!retval) | ||
1608 | retval = handle_reval_path(nd); | ||
1609 | |||
1633 | if (nd->file) { | 1610 | if (nd->file) { |
1634 | fput(nd->file); | 1611 | fput(nd->file); |
1635 | nd->file = NULL; | 1612 | nd->file = NULL; |
@@ -1690,7 +1667,7 @@ int vfs_path_lookup(struct dentry *dentry, struct vfsmount *mnt, | |||
1690 | 1667 | ||
1691 | /* same as do_path_lookup */ | 1668 | /* same as do_path_lookup */ |
1692 | nd->last_type = LAST_ROOT; | 1669 | nd->last_type = LAST_ROOT; |
1693 | nd->flags = flags; | 1670 | nd->flags = flags | LOOKUP_JUMPED; |
1694 | nd->depth = 0; | 1671 | nd->depth = 0; |
1695 | 1672 | ||
1696 | nd->path.dentry = dentry; | 1673 | nd->path.dentry = dentry; |
@@ -1703,6 +1680,8 @@ int vfs_path_lookup(struct dentry *dentry, struct vfsmount *mnt, | |||
1703 | current->total_link_count = 0; | 1680 | current->total_link_count = 0; |
1704 | 1681 | ||
1705 | result = link_path_walk(name, nd); | 1682 | result = link_path_walk(name, nd); |
1683 | if (!result) | ||
1684 | result = handle_reval_path(nd); | ||
1706 | if (result == -ESTALE) { | 1685 | if (result == -ESTALE) { |
1707 | /* nd->path had been dropped */ | 1686 | /* nd->path had been dropped */ |
1708 | current->total_link_count = 0; | 1687 | current->total_link_count = 0; |
@@ -1710,8 +1689,11 @@ int vfs_path_lookup(struct dentry *dentry, struct vfsmount *mnt, | |||
1710 | nd->path.mnt = mnt; | 1689 | nd->path.mnt = mnt; |
1711 | nd->inode = dentry->d_inode; | 1690 | nd->inode = dentry->d_inode; |
1712 | path_get(&nd->path); | 1691 | path_get(&nd->path); |
1713 | nd->flags |= LOOKUP_REVAL; | 1692 | nd->flags = flags | LOOKUP_JUMPED | LOOKUP_REVAL; |
1693 | |||
1714 | result = link_path_walk(name, nd); | 1694 | result = link_path_walk(name, nd); |
1695 | if (!result) | ||
1696 | result = handle_reval_path(nd); | ||
1715 | } | 1697 | } |
1716 | if (unlikely(!result && !audit_dummy_context() && nd->path.dentry && | 1698 | if (unlikely(!result && !audit_dummy_context() && nd->path.dentry && |
1717 | nd->inode)) | 1699 | nd->inode)) |
@@ -2198,30 +2180,29 @@ static struct file *do_last(struct nameidata *nd, struct path *path, | |||
2198 | { | 2180 | { |
2199 | struct dentry *dir = nd->path.dentry; | 2181 | struct dentry *dir = nd->path.dentry; |
2200 | struct file *filp; | 2182 | struct file *filp; |
2201 | int error = -EISDIR; | 2183 | int error; |
2202 | 2184 | ||
2203 | switch (nd->last_type) { | 2185 | switch (nd->last_type) { |
2204 | case LAST_DOTDOT: | 2186 | case LAST_DOTDOT: |
2205 | follow_dotdot(nd); | 2187 | follow_dotdot(nd); |
2206 | dir = nd->path.dentry; | 2188 | dir = nd->path.dentry; |
2207 | case LAST_DOT: | 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 | /* fallthrough */ | 2190 | /* fallthrough */ |
2218 | case LAST_ROOT: | 2191 | case LAST_ROOT: |
2192 | error = handle_reval_path(nd); | ||
2193 | if (error) | ||
2194 | goto exit; | ||
2195 | error = -EISDIR; | ||
2219 | goto exit; | 2196 | goto exit; |
2220 | case LAST_BIND: | 2197 | case LAST_BIND: |
2198 | error = handle_reval_path(nd); | ||
2199 | if (error) | ||
2200 | goto exit; | ||
2221 | audit_inode(pathname, dir); | 2201 | audit_inode(pathname, dir); |
2222 | goto ok; | 2202 | goto ok; |
2223 | } | 2203 | } |
2224 | 2204 | ||
2205 | error = -EISDIR; | ||
2225 | /* trailing slashes? */ | 2206 | /* trailing slashes? */ |
2226 | if (nd->last.name[nd->last.len]) | 2207 | if (nd->last.name[nd->last.len]) |
2227 | goto exit; | 2208 | goto exit; |
@@ -2422,7 +2403,7 @@ reval: | |||
2422 | /* | 2403 | /* |
2423 | * We have the parent and last component. | 2404 | * We have the parent and last component. |
2424 | */ | 2405 | */ |
2425 | nd.flags = flags; | 2406 | nd.flags = (nd.flags & ~LOOKUP_PARENT) | flags; |
2426 | filp = do_last(&nd, &path, open_flag, acc_mode, mode, pathname); | 2407 | filp = do_last(&nd, &path, open_flag, acc_mode, mode, pathname); |
2427 | while (unlikely(!filp)) { /* trailing symlink */ | 2408 | while (unlikely(!filp)) { /* trailing symlink */ |
2428 | struct path link = path; | 2409 | struct path link = path; |