aboutsummaryrefslogtreecommitdiffstats
path: root/fs/namei.c
diff options
context:
space:
mode:
authorAl Viro <viro@zeniv.linux.org.uk>2011-02-21 23:38:09 -0500
committerAl Viro <viro@zeniv.linux.org.uk>2011-03-14 09:15:24 -0400
commitee0827cd6b42b0385dc1a116cd853ac1b739f711 (patch)
tree2b96985f7c87c4333d740d991fbdcb3f49a1a67e /fs/namei.c
parent52094c8a0610cf57920ad4c6c57470ae2ccbbd25 (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.c148
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
1523static 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
1530static 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
1537static 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
1563static 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
1576static int path_init_rcu(int dfd, const char *name, unsigned int flags, struct nameidata *nd) 1523static 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. */
1700static int do_path_lookup(int dfd, const char *name, 1647static 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)) { 1697static 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
1804static struct dentry *__lookup_hash(struct qstr *name, 1778static struct dentry *__lookup_hash(struct qstr *name,
@@ -2483,24 +2457,14 @@ out_filp2:
2483 2457
2484creat: 2458creat:
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) {
2495reval: 2464reval:
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;