diff options
author | Al Viro <viro@zeniv.linux.org.uk> | 2012-06-10 04:15:17 -0400 |
---|---|---|
committer | Al Viro <viro@zeniv.linux.org.uk> | 2012-07-14 08:32:56 -0400 |
commit | 6d7b5aaed7d887b34f29f900244cdbd17a86637c (patch) | |
tree | e94341bc903a57e1c92c03c4953ae041b87f9807 /fs/namei.c | |
parent | 1d674107ea4b68669e012e654d64369b7f2bb250 (diff) |
namei.c: let follow_link() do put_link() on failure
no need for kludgy "set cookie to ERR_PTR(...) because we failed
before we did actual ->follow_link() and want to suppress put_link()",
no pointless check in put_link() itself.
Callers checked if follow_link() has failed anyway; might as well
break out of their loops if that happened, without bothering
to call put_link() first.
[AV: folded fixes from hch]
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
Diffstat (limited to 'fs/namei.c')
-rw-r--r-- | fs/namei.c | 74 |
1 files changed, 41 insertions, 33 deletions
diff --git a/fs/namei.c b/fs/namei.c index 7d694194024a..6135a14d5a84 100644 --- a/fs/namei.c +++ b/fs/namei.c | |||
@@ -605,7 +605,7 @@ static inline void path_to_nameidata(const struct path *path, | |||
605 | static inline void put_link(struct nameidata *nd, struct path *link, void *cookie) | 605 | static inline void put_link(struct nameidata *nd, struct path *link, void *cookie) |
606 | { | 606 | { |
607 | struct inode *inode = link->dentry->d_inode; | 607 | struct inode *inode = link->dentry->d_inode; |
608 | if (!IS_ERR(cookie) && inode->i_op->put_link) | 608 | if (inode->i_op->put_link) |
609 | inode->i_op->put_link(link->dentry, nd, cookie); | 609 | inode->i_op->put_link(link->dentry, nd, cookie); |
610 | path_put(link); | 610 | path_put(link); |
611 | } | 611 | } |
@@ -613,19 +613,19 @@ static inline void put_link(struct nameidata *nd, struct path *link, void *cooki | |||
613 | static __always_inline int | 613 | static __always_inline int |
614 | follow_link(struct path *link, struct nameidata *nd, void **p) | 614 | follow_link(struct path *link, struct nameidata *nd, void **p) |
615 | { | 615 | { |
616 | int error; | ||
617 | struct dentry *dentry = link->dentry; | 616 | struct dentry *dentry = link->dentry; |
617 | int error; | ||
618 | char *s; | ||
618 | 619 | ||
619 | BUG_ON(nd->flags & LOOKUP_RCU); | 620 | BUG_ON(nd->flags & LOOKUP_RCU); |
620 | 621 | ||
621 | if (link->mnt == nd->path.mnt) | 622 | if (link->mnt == nd->path.mnt) |
622 | mntget(link->mnt); | 623 | mntget(link->mnt); |
623 | 624 | ||
624 | if (unlikely(current->total_link_count >= 40)) { | 625 | error = -ELOOP; |
625 | *p = ERR_PTR(-ELOOP); /* no ->put_link(), please */ | 626 | if (unlikely(current->total_link_count >= 40)) |
626 | path_put(&nd->path); | 627 | goto out_put_nd_path; |
627 | return -ELOOP; | 628 | |
628 | } | ||
629 | cond_resched(); | 629 | cond_resched(); |
630 | current->total_link_count++; | 630 | current->total_link_count++; |
631 | 631 | ||
@@ -633,30 +633,37 @@ follow_link(struct path *link, struct nameidata *nd, void **p) | |||
633 | nd_set_link(nd, NULL); | 633 | nd_set_link(nd, NULL); |
634 | 634 | ||
635 | error = security_inode_follow_link(link->dentry, nd); | 635 | error = security_inode_follow_link(link->dentry, nd); |
636 | if (error) { | 636 | if (error) |
637 | *p = ERR_PTR(error); /* no ->put_link(), please */ | 637 | goto out_put_nd_path; |
638 | path_put(&nd->path); | ||
639 | return error; | ||
640 | } | ||
641 | 638 | ||
642 | nd->last_type = LAST_BIND; | 639 | nd->last_type = LAST_BIND; |
643 | *p = dentry->d_inode->i_op->follow_link(dentry, nd); | 640 | *p = dentry->d_inode->i_op->follow_link(dentry, nd); |
644 | error = PTR_ERR(*p); | 641 | error = PTR_ERR(*p); |
645 | if (!IS_ERR(*p)) { | 642 | if (IS_ERR(*p)) |
646 | char *s = nd_get_link(nd); | 643 | goto out_put_link; |
647 | error = 0; | 644 | |
648 | if (s) | 645 | error = 0; |
649 | error = __vfs_follow_link(nd, s); | 646 | s = nd_get_link(nd); |
650 | else if (nd->last_type == LAST_BIND) { | 647 | if (s) { |
651 | nd->flags |= LOOKUP_JUMPED; | 648 | error = __vfs_follow_link(nd, s); |
652 | nd->inode = nd->path.dentry->d_inode; | 649 | } else if (nd->last_type == LAST_BIND) { |
653 | if (nd->inode->i_op->follow_link) { | 650 | nd->flags |= LOOKUP_JUMPED; |
654 | /* stepped on a _really_ weird one */ | 651 | nd->inode = nd->path.dentry->d_inode; |
655 | path_put(&nd->path); | 652 | if (nd->inode->i_op->follow_link) { |
656 | error = -ELOOP; | 653 | /* stepped on a _really_ weird one */ |
657 | } | 654 | path_put(&nd->path); |
655 | error = -ELOOP; | ||
658 | } | 656 | } |
659 | } | 657 | } |
658 | if (unlikely(error)) | ||
659 | put_link(nd, link, *p); | ||
660 | |||
661 | return error; | ||
662 | |||
663 | out_put_nd_path: | ||
664 | path_put(&nd->path); | ||
665 | out_put_link: | ||
666 | path_put(link); | ||
660 | return error; | 667 | return error; |
661 | } | 668 | } |
662 | 669 | ||
@@ -1383,9 +1390,10 @@ static inline int nested_symlink(struct path *path, struct nameidata *nd) | |||
1383 | void *cookie; | 1390 | void *cookie; |
1384 | 1391 | ||
1385 | res = follow_link(&link, nd, &cookie); | 1392 | res = follow_link(&link, nd, &cookie); |
1386 | if (!res) | 1393 | if (res) |
1387 | res = walk_component(nd, path, &nd->last, | 1394 | break; |
1388 | nd->last_type, LOOKUP_FOLLOW); | 1395 | res = walk_component(nd, path, &nd->last, |
1396 | nd->last_type, LOOKUP_FOLLOW); | ||
1389 | put_link(nd, &link, cookie); | 1397 | put_link(nd, &link, cookie); |
1390 | } while (res > 0); | 1398 | } while (res > 0); |
1391 | 1399 | ||
@@ -1777,8 +1785,9 @@ static int path_lookupat(int dfd, const char *name, | |||
1777 | struct path link = path; | 1785 | struct path link = path; |
1778 | nd->flags |= LOOKUP_PARENT; | 1786 | nd->flags |= LOOKUP_PARENT; |
1779 | err = follow_link(&link, nd, &cookie); | 1787 | err = follow_link(&link, nd, &cookie); |
1780 | if (!err) | 1788 | if (err) |
1781 | err = lookup_last(nd, &path); | 1789 | break; |
1790 | err = lookup_last(nd, &path); | ||
1782 | put_link(nd, &link, cookie); | 1791 | put_link(nd, &link, cookie); |
1783 | } | 1792 | } |
1784 | } | 1793 | } |
@@ -2475,9 +2484,8 @@ static struct file *path_openat(int dfd, const char *pathname, | |||
2475 | nd->flags &= ~(LOOKUP_OPEN|LOOKUP_CREATE|LOOKUP_EXCL); | 2484 | nd->flags &= ~(LOOKUP_OPEN|LOOKUP_CREATE|LOOKUP_EXCL); |
2476 | error = follow_link(&link, nd, &cookie); | 2485 | error = follow_link(&link, nd, &cookie); |
2477 | if (unlikely(error)) | 2486 | if (unlikely(error)) |
2478 | filp = ERR_PTR(error); | 2487 | goto out_filp; |
2479 | else | 2488 | filp = do_last(nd, &path, op, pathname); |
2480 | filp = do_last(nd, &path, op, pathname); | ||
2481 | put_link(nd, &link, cookie); | 2489 | put_link(nd, &link, cookie); |
2482 | } | 2490 | } |
2483 | out: | 2491 | out: |