diff options
author | Al Viro <viro@zeniv.linux.org.uk> | 2011-02-21 23:38:09 -0500 |
---|---|---|
committer | Al Viro <viro@zeniv.linux.org.uk> | 2011-03-14 09:15:24 -0400 |
commit | ee0827cd6b42b0385dc1a116cd853ac1b739f711 (patch) | |
tree | 2b96985f7c87c4333d740d991fbdcb3f49a1a67e /fs/namei.c | |
parent | 52094c8a0610cf57920ad4c6c57470ae2ccbbd25 (diff) |
sanitize path_walk() mess
New helper: path_lookupat(). Basically, what do_path_lookup() boils to
modulo -ECHILD/-ESTALE handler. path_walk* family is gone; vfs_path_lookup()
is using link_path_walk() directly, do_path_lookup() and do_filp_open()
are using path_lookupat().
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
Diffstat (limited to 'fs/namei.c')
-rw-r--r-- | fs/namei.c | 148 |
1 files changed, 56 insertions, 92 deletions
diff --git a/fs/namei.c b/fs/namei.c index 8c704465f6ce..f5de5bb1a61f 100644 --- a/fs/namei.c +++ b/fs/namei.c | |||
@@ -1520,59 +1520,6 @@ return_err: | |||
1520 | return err; | 1520 | return err; |
1521 | } | 1521 | } |
1522 | 1522 | ||
1523 | static inline int path_walk_rcu(const char *name, struct nameidata *nd) | ||
1524 | { | ||
1525 | current->total_link_count = 0; | ||
1526 | |||
1527 | return link_path_walk(name, nd); | ||
1528 | } | ||
1529 | |||
1530 | static inline int path_walk_simple(const char *name, struct nameidata *nd) | ||
1531 | { | ||
1532 | current->total_link_count = 0; | ||
1533 | |||
1534 | return link_path_walk(name, nd); | ||
1535 | } | ||
1536 | |||
1537 | static int path_walk(const char *name, struct nameidata *nd) | ||
1538 | { | ||
1539 | struct path save = nd->path; | ||
1540 | int result; | ||
1541 | |||
1542 | current->total_link_count = 0; | ||
1543 | |||
1544 | /* make sure the stuff we saved doesn't go away */ | ||
1545 | path_get(&save); | ||
1546 | |||
1547 | result = link_path_walk(name, nd); | ||
1548 | if (result == -ESTALE) { | ||
1549 | /* nd->path had been dropped */ | ||
1550 | current->total_link_count = 0; | ||
1551 | nd->path = save; | ||
1552 | nd->inode = save.dentry->d_inode; | ||
1553 | path_get(&nd->path); | ||
1554 | nd->flags |= LOOKUP_REVAL; | ||
1555 | result = link_path_walk(name, nd); | ||
1556 | } | ||
1557 | |||
1558 | path_put(&save); | ||
1559 | |||
1560 | return result; | ||
1561 | } | ||
1562 | |||
1563 | static void path_finish_rcu(struct nameidata *nd) | ||
1564 | { | ||
1565 | if (nd->flags & LOOKUP_RCU) { | ||
1566 | /* RCU dangling. Cancel it. */ | ||
1567 | nd->flags &= ~LOOKUP_RCU; | ||
1568 | nd->root.mnt = NULL; | ||
1569 | rcu_read_unlock(); | ||
1570 | br_read_unlock(vfsmount_lock); | ||
1571 | } | ||
1572 | if (nd->file) | ||
1573 | fput(nd->file); | ||
1574 | } | ||
1575 | |||
1576 | static int path_init_rcu(int dfd, const char *name, unsigned int flags, struct nameidata *nd) | 1523 | static int path_init_rcu(int dfd, const char *name, unsigned int flags, struct nameidata *nd) |
1577 | { | 1524 | { |
1578 | int retval = 0; | 1525 | int retval = 0; |
@@ -1697,7 +1644,7 @@ out_fail: | |||
1697 | } | 1644 | } |
1698 | 1645 | ||
1699 | /* Returns 0 and nd will be valid on success; Retuns error, otherwise. */ | 1646 | /* Returns 0 and nd will be valid on success; Retuns error, otherwise. */ |
1700 | static int do_path_lookup(int dfd, const char *name, | 1647 | static int path_lookupat(int dfd, const char *name, |
1701 | unsigned int flags, struct nameidata *nd) | 1648 | unsigned int flags, struct nameidata *nd) |
1702 | { | 1649 | { |
1703 | int retval; | 1650 | int retval; |
@@ -1716,29 +1663,45 @@ static int do_path_lookup(int dfd, const char *name, | |||
1716 | * be handled by restarting a traditional ref-walk (which will always | 1663 | * be handled by restarting a traditional ref-walk (which will always |
1717 | * be able to complete). | 1664 | * be able to complete). |
1718 | */ | 1665 | */ |
1719 | retval = path_init_rcu(dfd, name, flags, nd); | 1666 | if (flags & LOOKUP_RCU) |
1667 | retval = path_init_rcu(dfd, name, flags, nd); | ||
1668 | else | ||
1669 | retval = path_init(dfd, name, flags, nd); | ||
1670 | |||
1720 | if (unlikely(retval)) | 1671 | if (unlikely(retval)) |
1721 | return retval; | 1672 | return retval; |
1722 | retval = path_walk_rcu(name, nd); | 1673 | |
1723 | path_finish_rcu(nd); | 1674 | current->total_link_count = 0; |
1675 | retval = link_path_walk(name, nd); | ||
1676 | |||
1677 | if (nd->flags & LOOKUP_RCU) { | ||
1678 | /* RCU dangling. Cancel it. */ | ||
1679 | nd->flags &= ~LOOKUP_RCU; | ||
1680 | nd->root.mnt = NULL; | ||
1681 | rcu_read_unlock(); | ||
1682 | br_read_unlock(vfsmount_lock); | ||
1683 | } | ||
1684 | |||
1685 | if (nd->file) { | ||
1686 | fput(nd->file); | ||
1687 | nd->file = NULL; | ||
1688 | } | ||
1689 | |||
1724 | if (nd->root.mnt) { | 1690 | if (nd->root.mnt) { |
1725 | path_put(&nd->root); | 1691 | path_put(&nd->root); |
1726 | nd->root.mnt = NULL; | 1692 | nd->root.mnt = NULL; |
1727 | } | 1693 | } |
1694 | return retval; | ||
1695 | } | ||
1728 | 1696 | ||
1729 | if (unlikely(retval == -ECHILD || retval == -ESTALE)) { | 1697 | static int do_path_lookup(int dfd, const char *name, |
1730 | /* slower, locked walk */ | 1698 | unsigned int flags, struct nameidata *nd) |
1731 | if (retval == -ESTALE) | 1699 | { |
1732 | flags |= LOOKUP_REVAL; | 1700 | int retval = path_lookupat(dfd, name, flags | LOOKUP_RCU, nd); |
1733 | retval = path_init(dfd, name, flags, nd); | 1701 | if (unlikely(retval == -ECHILD)) |
1734 | if (unlikely(retval)) | 1702 | retval = path_lookupat(dfd, name, flags, nd); |
1735 | return retval; | 1703 | if (unlikely(retval == -ESTALE)) |
1736 | retval = path_walk(name, nd); | 1704 | retval = path_lookupat(dfd, name, flags | LOOKUP_REVAL, nd); |
1737 | if (nd->root.mnt) { | ||
1738 | path_put(&nd->root); | ||
1739 | nd->root.mnt = NULL; | ||
1740 | } | ||
1741 | } | ||
1742 | 1705 | ||
1743 | if (likely(!retval)) { | 1706 | if (likely(!retval)) { |
1744 | if (unlikely(!audit_dummy_context())) { | 1707 | if (unlikely(!audit_dummy_context())) { |
@@ -1746,7 +1709,6 @@ static int do_path_lookup(int dfd, const char *name, | |||
1746 | audit_inode(name, nd->path.dentry); | 1709 | audit_inode(name, nd->path.dentry); |
1747 | } | 1710 | } |
1748 | } | 1711 | } |
1749 | |||
1750 | return retval; | 1712 | return retval; |
1751 | } | 1713 | } |
1752 | 1714 | ||
@@ -1776,7 +1738,7 @@ int vfs_path_lookup(struct dentry *dentry, struct vfsmount *mnt, | |||
1776 | const char *name, unsigned int flags, | 1738 | const char *name, unsigned int flags, |
1777 | struct nameidata *nd) | 1739 | struct nameidata *nd) |
1778 | { | 1740 | { |
1779 | int retval; | 1741 | int result; |
1780 | 1742 | ||
1781 | /* same as do_path_lookup */ | 1743 | /* same as do_path_lookup */ |
1782 | nd->last_type = LAST_ROOT; | 1744 | nd->last_type = LAST_ROOT; |
@@ -1790,15 +1752,27 @@ int vfs_path_lookup(struct dentry *dentry, struct vfsmount *mnt, | |||
1790 | path_get(&nd->root); | 1752 | path_get(&nd->root); |
1791 | nd->inode = nd->path.dentry->d_inode; | 1753 | nd->inode = nd->path.dentry->d_inode; |
1792 | 1754 | ||
1793 | retval = path_walk(name, nd); | 1755 | current->total_link_count = 0; |
1794 | if (unlikely(!retval && !audit_dummy_context() && nd->path.dentry && | 1756 | |
1757 | result = link_path_walk(name, nd); | ||
1758 | if (result == -ESTALE) { | ||
1759 | /* nd->path had been dropped */ | ||
1760 | current->total_link_count = 0; | ||
1761 | nd->path.dentry = dentry; | ||
1762 | nd->path.mnt = mnt; | ||
1763 | nd->inode = dentry->d_inode; | ||
1764 | path_get(&nd->path); | ||
1765 | nd->flags |= LOOKUP_REVAL; | ||
1766 | result = link_path_walk(name, nd); | ||
1767 | } | ||
1768 | if (unlikely(!result && !audit_dummy_context() && nd->path.dentry && | ||
1795 | nd->inode)) | 1769 | nd->inode)) |
1796 | audit_inode(name, nd->path.dentry); | 1770 | audit_inode(name, nd->path.dentry); |
1797 | 1771 | ||
1798 | path_put(&nd->root); | 1772 | path_put(&nd->root); |
1799 | nd->root.mnt = NULL; | 1773 | nd->root.mnt = NULL; |
1800 | 1774 | ||
1801 | return retval; | 1775 | return result; |
1802 | } | 1776 | } |
1803 | 1777 | ||
1804 | static struct dentry *__lookup_hash(struct qstr *name, | 1778 | static struct dentry *__lookup_hash(struct qstr *name, |
@@ -2483,24 +2457,14 @@ out_filp2: | |||
2483 | 2457 | ||
2484 | creat: | 2458 | creat: |
2485 | /* OK, have to create the file. Find the parent. */ | 2459 | /* OK, have to create the file. Find the parent. */ |
2486 | error = path_init_rcu(dfd, pathname, | 2460 | error = path_lookupat(dfd, pathname, LOOKUP_PARENT | LOOKUP_RCU, &nd); |
2487 | LOOKUP_PARENT | (flags & LOOKUP_REVAL), &nd); | 2461 | if (unlikely(error == -ECHILD)) |
2488 | if (error) | 2462 | error = path_lookupat(dfd, pathname, LOOKUP_PARENT, &nd); |
2489 | goto out_filp; | 2463 | if (unlikely(error == -ESTALE)) { |
2490 | error = path_walk_rcu(pathname, &nd); | ||
2491 | path_finish_rcu(&nd); | ||
2492 | if (unlikely(error == -ECHILD || error == -ESTALE)) { | ||
2493 | /* slower, locked walk */ | ||
2494 | if (error == -ESTALE) { | ||
2495 | reval: | 2464 | reval: |
2496 | flags |= LOOKUP_REVAL; | 2465 | flags |= LOOKUP_REVAL; |
2497 | } | 2466 | error = path_lookupat(dfd, pathname, |
2498 | error = path_init(dfd, pathname, | 2467 | LOOKUP_PARENT | LOOKUP_REVAL, &nd); |
2499 | LOOKUP_PARENT | (flags & LOOKUP_REVAL), &nd); | ||
2500 | if (error) | ||
2501 | goto out_filp; | ||
2502 | |||
2503 | error = path_walk_simple(pathname, &nd); | ||
2504 | } | 2468 | } |
2505 | if (unlikely(error)) | 2469 | if (unlikely(error)) |
2506 | goto out_filp; | 2470 | goto out_filp; |