Commit 6d7b5aaed7d887b34f29f900244cdbd17a86637c
1 parent
1d674107ea
Exists in
master
and in
20 other branches
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>
Showing 1 changed file with 41 additions and 33 deletions Side-by-side Diff
fs/namei.c
... | ... | @@ -605,7 +605,7 @@ |
605 | 605 | static inline void put_link(struct nameidata *nd, struct path *link, void *cookie) |
606 | 606 | { |
607 | 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 | 609 | inode->i_op->put_link(link->dentry, nd, cookie); |
610 | 610 | path_put(link); |
611 | 611 | } |
612 | 612 | |
613 | 613 | |
... | ... | @@ -613,19 +613,19 @@ |
613 | 613 | static __always_inline int |
614 | 614 | follow_link(struct path *link, struct nameidata *nd, void **p) |
615 | 615 | { |
616 | - int error; | |
617 | 616 | struct dentry *dentry = link->dentry; |
617 | + int error; | |
618 | + char *s; | |
618 | 619 | |
619 | 620 | BUG_ON(nd->flags & LOOKUP_RCU); |
620 | 621 | |
621 | 622 | if (link->mnt == nd->path.mnt) |
622 | 623 | mntget(link->mnt); |
623 | 624 | |
624 | - if (unlikely(current->total_link_count >= 40)) { | |
625 | - *p = ERR_PTR(-ELOOP); /* no ->put_link(), please */ | |
626 | - path_put(&nd->path); | |
627 | - return -ELOOP; | |
628 | - } | |
625 | + error = -ELOOP; | |
626 | + if (unlikely(current->total_link_count >= 40)) | |
627 | + goto out_put_nd_path; | |
628 | + | |
629 | 629 | cond_resched(); |
630 | 630 | current->total_link_count++; |
631 | 631 | |
632 | 632 | |
633 | 633 | |
634 | 634 | |
... | ... | @@ -633,31 +633,38 @@ |
633 | 633 | nd_set_link(nd, NULL); |
634 | 634 | |
635 | 635 | error = security_inode_follow_link(link->dentry, nd); |
636 | - if (error) { | |
637 | - *p = ERR_PTR(error); /* no ->put_link(), please */ | |
638 | - path_put(&nd->path); | |
639 | - return error; | |
640 | - } | |
636 | + if (error) | |
637 | + goto out_put_nd_path; | |
641 | 638 | |
642 | 639 | nd->last_type = LAST_BIND; |
643 | 640 | *p = dentry->d_inode->i_op->follow_link(dentry, nd); |
644 | 641 | error = PTR_ERR(*p); |
645 | - if (!IS_ERR(*p)) { | |
646 | - char *s = nd_get_link(nd); | |
647 | - error = 0; | |
648 | - if (s) | |
649 | - error = __vfs_follow_link(nd, s); | |
650 | - else if (nd->last_type == LAST_BIND) { | |
651 | - nd->flags |= LOOKUP_JUMPED; | |
652 | - nd->inode = nd->path.dentry->d_inode; | |
653 | - if (nd->inode->i_op->follow_link) { | |
654 | - /* stepped on a _really_ weird one */ | |
655 | - path_put(&nd->path); | |
656 | - error = -ELOOP; | |
657 | - } | |
642 | + if (IS_ERR(*p)) | |
643 | + goto out_put_link; | |
644 | + | |
645 | + error = 0; | |
646 | + s = nd_get_link(nd); | |
647 | + if (s) { | |
648 | + error = __vfs_follow_link(nd, s); | |
649 | + } else if (nd->last_type == LAST_BIND) { | |
650 | + nd->flags |= LOOKUP_JUMPED; | |
651 | + nd->inode = nd->path.dentry->d_inode; | |
652 | + if (nd->inode->i_op->follow_link) { | |
653 | + /* stepped on a _really_ weird one */ | |
654 | + path_put(&nd->path); | |
655 | + error = -ELOOP; | |
658 | 656 | } |
659 | 657 | } |
658 | + if (unlikely(error)) | |
659 | + put_link(nd, link, *p); | |
660 | + | |
660 | 661 | return error; |
662 | + | |
663 | +out_put_nd_path: | |
664 | + path_put(&nd->path); | |
665 | +out_put_link: | |
666 | + path_put(link); | |
667 | + return error; | |
661 | 668 | } |
662 | 669 | |
663 | 670 | static int follow_up_rcu(struct path *path) |
... | ... | @@ -1383,9 +1390,10 @@ |
1383 | 1390 | void *cookie; |
1384 | 1391 | |
1385 | 1392 | res = follow_link(&link, nd, &cookie); |
1386 | - if (!res) | |
1387 | - res = walk_component(nd, path, &nd->last, | |
1388 | - nd->last_type, LOOKUP_FOLLOW); | |
1393 | + if (res) | |
1394 | + break; | |
1395 | + res = walk_component(nd, path, &nd->last, | |
1396 | + nd->last_type, LOOKUP_FOLLOW); | |
1389 | 1397 | put_link(nd, &link, cookie); |
1390 | 1398 | } while (res > 0); |
1391 | 1399 | |
... | ... | @@ -1777,8 +1785,9 @@ |
1777 | 1785 | struct path link = path; |
1778 | 1786 | nd->flags |= LOOKUP_PARENT; |
1779 | 1787 | err = follow_link(&link, nd, &cookie); |
1780 | - if (!err) | |
1781 | - err = lookup_last(nd, &path); | |
1788 | + if (err) | |
1789 | + break; | |
1790 | + err = lookup_last(nd, &path); | |
1782 | 1791 | put_link(nd, &link, cookie); |
1783 | 1792 | } |
1784 | 1793 | } |
... | ... | @@ -2475,9 +2484,8 @@ |
2475 | 2484 | nd->flags &= ~(LOOKUP_OPEN|LOOKUP_CREATE|LOOKUP_EXCL); |
2476 | 2485 | error = follow_link(&link, nd, &cookie); |
2477 | 2486 | if (unlikely(error)) |
2478 | - filp = ERR_PTR(error); | |
2479 | - else | |
2480 | - filp = do_last(nd, &path, op, pathname); | |
2487 | + goto out_filp; | |
2488 | + filp = do_last(nd, &path, op, pathname); | |
2481 | 2489 | put_link(nd, &link, cookie); |
2482 | 2490 | } |
2483 | 2491 | out: |