aboutsummaryrefslogtreecommitdiffstats
path: root/fs/namei.c
diff options
context:
space:
mode:
authorAl Viro <viro@zeniv.linux.org.uk>2011-03-14 19:54:59 -0400
committerAl Viro <viro@zeniv.linux.org.uk>2011-03-15 17:16:25 -0400
commitbd92d7fed877ed1e6997e4f3f13dbcd872947653 (patch)
tree184223c18695fd1b543850dc186e89faf71bb461 /fs/namei.c
parentb21041d0f72899ed815bd2cbf7275339c74737b6 (diff)
Make trailing symlink resolution in path_lookupat() iterative
Now the only caller of link_path_walk() that does *not* pass LOOKUP_PARENT is do_follow_link() Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
Diffstat (limited to 'fs/namei.c')
-rw-r--r--fs/namei.c63
1 files changed, 53 insertions, 10 deletions
diff --git a/fs/namei.c b/fs/namei.c
index 9e7b18a8be66..a3431639e166 100644
--- a/fs/namei.c
+++ b/fs/namei.c
@@ -1588,12 +1588,23 @@ out_fail:
1588 return retval; 1588 return retval;
1589} 1589}
1590 1590
1591static inline int lookup_last(struct nameidata *nd, struct path *path)
1592{
1593 if (nd->last_type == LAST_NORM && nd->last.name[nd->last.len])
1594 nd->flags |= LOOKUP_FOLLOW | LOOKUP_DIRECTORY;
1595
1596 nd->flags &= ~LOOKUP_PARENT;
1597 return walk_component(nd, path, &nd->last, nd->last_type,
1598 nd->flags & LOOKUP_FOLLOW);
1599}
1600
1591/* Returns 0 and nd will be valid on success; Retuns error, otherwise. */ 1601/* Returns 0 and nd will be valid on success; Retuns error, otherwise. */
1592static int path_lookupat(int dfd, const char *name, 1602static int path_lookupat(int dfd, const char *name,
1593 unsigned int flags, struct nameidata *nd) 1603 unsigned int flags, struct nameidata *nd)
1594{ 1604{
1595 struct file *base = NULL; 1605 struct file *base = NULL;
1596 int retval; 1606 struct path path;
1607 int err;
1597 1608
1598 /* 1609 /*
1599 * Path walking is largely split up into 2 different synchronisation 1610 * Path walking is largely split up into 2 different synchronisation
@@ -1609,23 +1620,55 @@ static int path_lookupat(int dfd, const char *name,
1609 * be handled by restarting a traditional ref-walk (which will always 1620 * be handled by restarting a traditional ref-walk (which will always
1610 * be able to complete). 1621 * be able to complete).
1611 */ 1622 */
1612 retval = path_init(dfd, name, flags, nd, &base); 1623 err = path_init(dfd, name, flags | LOOKUP_PARENT, nd, &base);
1613 1624
1614 if (unlikely(retval)) 1625 if (unlikely(err))
1615 return retval; 1626 return err;
1616 1627
1617 current->total_link_count = 0; 1628 current->total_link_count = 0;
1618 retval = link_path_walk(name, nd); 1629 err = link_path_walk(name, nd);
1630
1631 if (!err && !(flags & LOOKUP_PARENT)) {
1632 int count = 0;
1633 err = lookup_last(nd, &path);
1634 while (err > 0) {
1635 void *cookie;
1636 struct path link = path;
1637 struct inode *inode = link.dentry->d_inode;
1638
1639 if (count++ > 32) {
1640 path_put_conditional(&path, nd);
1641 path_put(&nd->path);
1642 err = -ELOOP;
1643 break;
1644 }
1645 cond_resched();
1646 nd->flags |= LOOKUP_PARENT;
1647 err = __do_follow_link(&link, nd, &cookie);
1648 if (!err)
1649 err = lookup_last(nd, &path);
1650 if (!IS_ERR(cookie) && inode->i_op->put_link)
1651 inode->i_op->put_link(link.dentry, nd, cookie);
1652 path_put(&link);
1653 }
1654 }
1619 1655
1620 if (nd->flags & LOOKUP_RCU) { 1656 if (nd->flags & LOOKUP_RCU) {
1621 /* went all way through without dropping RCU */ 1657 /* went all way through without dropping RCU */
1622 BUG_ON(retval); 1658 BUG_ON(err);
1623 if (nameidata_drop_rcu_last(nd)) 1659 if (nameidata_drop_rcu_last(nd))
1624 retval = -ECHILD; 1660 err = -ECHILD;
1625 } 1661 }
1626 1662
1627 if (!retval) 1663 if (!err)
1628 retval = handle_reval_path(nd); 1664 err = handle_reval_path(nd);
1665
1666 if (!err && nd->flags & LOOKUP_DIRECTORY) {
1667 if (!nd->inode->i_op->lookup) {
1668 path_put(&nd->path);
1669 return -ENOTDIR;
1670 }
1671 }
1629 1672
1630 if (base) 1673 if (base)
1631 fput(base); 1674 fput(base);
@@ -1634,7 +1677,7 @@ static int path_lookupat(int dfd, const char *name,
1634 path_put(&nd->root); 1677 path_put(&nd->root);
1635 nd->root.mnt = NULL; 1678 nd->root.mnt = NULL;
1636 } 1679 }
1637 return retval; 1680 return err;
1638} 1681}
1639 1682
1640static int do_path_lookup(int dfd, const char *name, 1683static int do_path_lookup(int dfd, const char *name,