| @@ -669,23 +669,25 @@ static bool legitimize_root(struct nameidata *nd) · 668 unmodified lines |
| 669 | 669 | */ |
| 670 | 670 | |
| 671 | 671 | /** |
| 672 | | − * unlazy_walk - try to switch to ref-walk mode. |
| 672 | + * try_to_unlazy - try to switch to ref-walk mode. |
| 673 | 673 | * @nd: nameidata pathwalk data |
| 674 | | − * Returns: 0 on success, -ECHILD on failure |
| 674 | + * Returns: true on success, false on failure |
| 675 | 675 | * |
| 676 | | − * unlazy_walk attempts to legitimize the current nd->path and nd->root |
| 676 | + * try_to_unlazy attempts to legitimize the current nd->path and nd->root |
| 677 | 677 | * for ref-walk mode. |
| 678 | 678 | * Must be called from rcu-walk context. |
| 679 | | − * Nothing should touch nameidata between unlazy_walk() failure and |
| 679 | + * Nothing should touch nameidata between try_to_unlazy() failure and |
| 680 | 680 | * terminate_walk(). |
| 681 | 681 | */ |
| 682 | | −static int unlazy_walk(struct nameidata *nd) |
| 682 | +static bool try_to_unlazy(struct nameidata *nd) |
| 683 | 683 | { |
| 684 | 684 | struct dentry *parent = nd->path.dentry; |
| 685 | 685 | |
| 686 | 686 | BUG_ON(!(nd->flags & LOOKUP_RCU)); |
| 687 | 687 | |
| 688 | 688 | nd->flags &= ~LOOKUP_RCU; |
| 689 | + if (nd->flags & LOOKUP_CACHED) |
| 690 | + goto out1; |
| 689 | 691 | if (unlikely(!legitimize_links(nd))) |
| 690 | 692 | goto out1; |
| 691 | 693 | if (unlikely(!legitimize_path(nd, &nd->path, nd->seq))) |
| @@ -694,34 +696,36 @@ static int unlazy_walk(struct nameidata *nd) · 2 unmodified lines |
| 694 | 696 | goto out; |
| 695 | 697 | rcu_read_unlock(); |
| 696 | 698 | BUG_ON(nd->inode != parent->d_inode); |
| 697 | | − return 0; |
| 699 | + return true; |
| 698 | 700 | |
| 699 | 701 | out1: |
| 700 | 702 | nd->path.mnt = NULL; |
| 701 | 703 | nd->path.dentry = NULL; |
| 702 | 704 | out: |
| 703 | 705 | rcu_read_unlock(); |
| 704 | | − return -ECHILD; |
| 706 | + return false; |
| 705 | 707 | } |
| 706 | 708 | |
| 707 | 709 | /** |
| 708 | | − * unlazy_child - try to switch to ref-walk mode. |
| 710 | + * try_to_unlazy_next - try to switch to ref-walk mode. |
| 709 | 711 | * @nd: nameidata pathwalk data |
| 710 | | − * @dentry: child of nd->path.dentry |
| 711 | | − * @seq: seq number to check dentry against |
| 712 | | − * Returns: 0 on success, -ECHILD on failure |
| 712 | + * @dentry: next dentry to step into |
| 713 | + * @seq: seq number to check @dentry against |
| 714 | + * Returns: true on success, false on failure |
| 713 | 715 | * |
| 714 | | − * unlazy_child attempts to legitimize the current nd->path, nd->root and dentry |
| 715 | | − * for ref-walk mode. @dentry must be a path found by a do_lookup call on |
| 716 | | − * @nd. Must be called from rcu-walk context. |
| 717 | | − * Nothing should touch nameidata between unlazy_child() failure and |
| 716 | + * Similar to to try_to_unlazy(), but here we have the next dentry already |
| 717 | + * picked by rcu-walk and want to legitimize that in addition to the current |
| 718 | + * nd->path and nd->root for ref-walk mode. Must be called from rcu-walk context. |
| 719 | + * Nothing should touch nameidata between try_to_unlazy_next() failure and |
| 718 | 720 | * terminate_walk(). |
| 719 | 721 | */ |
| 720 | | −static int unlazy_child(struct nameidata *nd, struct dentry *dentry, unsigned seq) |
| 722 | +static bool try_to_unlazy_next(struct nameidata *nd, struct dentry *dentry, unsigned seq) |
| 721 | 723 | { |
| 722 | 724 | BUG_ON(!(nd->flags & LOOKUP_RCU)); |
| 723 | 725 | |
| 724 | 726 | nd->flags &= ~LOOKUP_RCU; |
| 727 | + if (nd->flags & LOOKUP_CACHED) |
| 728 | + goto out2; |
| 725 | 729 | if (unlikely(!legitimize_links(nd))) |
| 726 | 730 | goto out2; |
| 727 | 731 | if (unlikely(!legitimize_mnt(nd->path.mnt, nd->m_seq))) |
| @@ -747,7 +751,7 @@ static int unlazy_child(struct nameidata *nd, struct dentry *dentry, unsigned se · 19 unmodified lines |
| 747 | 751 | if (unlikely(!legitimize_root(nd))) |
| 748 | 752 | goto out_dput; |
| 749 | 753 | rcu_read_unlock(); |
| 750 | | − return 0; |
| 754 | + return true; |
| 751 | 755 | |
| 752 | 756 | out2: |
| 753 | 757 | nd->path.mnt = NULL; |
| @@ -755,11 +759,11 @@ out1: · 1 unmodified line |
| 755 | 759 | nd->path.dentry = NULL; |
| 756 | 760 | out: |
| 757 | 761 | rcu_read_unlock(); |
| 758 | | − return -ECHILD; |
| 762 | + return false; |
| 759 | 763 | out_dput: |
| 760 | 764 | rcu_read_unlock(); |
| 761 | 765 | dput(dentry); |
| 762 | | − return -ECHILD; |
| 766 | + return false; |
| 763 | 767 | } |
| 764 | 768 | |
| 765 | 769 | static inline int d_revalidate(struct dentry *dentry, unsigned int flags) |
| @@ -792,7 +796,8 @@ static int complete_walk(struct nameidata *nd) · 26 unmodified lines |
| 792 | 796 | */ |
| 793 | 797 | if (!(nd->flags & (LOOKUP_ROOT | LOOKUP_IS_SCOPED))) |
| 794 | 798 | nd->root.mnt = NULL; |
| 795 | | − if (unlikely(unlazy_walk(nd))) |
| 799 | + nd->flags &= ~LOOKUP_CACHED; |
| 800 | + if (!try_to_unlazy(nd)) |
| 796 | 801 | return -ECHILD; |
| 797 | 802 | } |
| 798 | 803 | |
| @@ -1372,7 +1377,7 @@ static inline int handle_mounts(struct nameidata *nd, struct dentry *dentry, · 573 unmodified lines |
| 1372 | 1377 | return -ENOENT; |
| 1373 | 1378 | if (likely(__follow_mount_rcu(nd, path, inode, seqp))) |
| 1374 | 1379 | return 0; |
| 1375 | | − if (unlazy_child(nd, dentry, seq)) |
| 1380 | + if (!try_to_unlazy_next(nd, dentry, seq)) |
| 1376 | 1381 | return -ECHILD; |
| 1377 | 1382 | // *path might've been clobbered by __follow_mount_rcu() |
| 1378 | 1383 | path->mnt = nd->path.mnt; |
| @@ -1466,7 +1471,7 @@ static struct dentry *lookup_fast(struct nameidata *nd, · 87 unmodified lines |
| 1466 | 1471 | unsigned seq; |
| 1467 | 1472 | dentry = __d_lookup_rcu(parent, &nd->last, &seq); |
| 1468 | 1473 | if (unlikely(!dentry)) { |
| 1469 | | − if (unlazy_walk(nd)) |
| 1474 | + if (!try_to_unlazy(nd)) |
| 1470 | 1475 | return ERR_PTR(-ECHILD); |
| 1471 | 1476 | return NULL; |
| 1472 | 1477 | } |
| @@ -1493,9 +1498,9 @@ static struct dentry *lookup_fast(struct nameidata *nd, · 20 unmodified lines |
| 1493 | 1498 | status = d_revalidate(dentry, nd->flags); |
| 1494 | 1499 | if (likely(status > 0)) |
| 1495 | 1500 | return dentry; |
| 1496 | | − if (unlazy_child(nd, dentry, seq)) |
| 1501 | + if (!try_to_unlazy_next(nd, dentry, seq)) |
| 1497 | 1502 | return ERR_PTR(-ECHILD); |
| 1498 | | − if (unlikely(status == -ECHILD)) |
| 1503 | + if (status == -ECHILD) |
| 1499 | 1504 | /* we'd been told to redo it in non-rcu mode */ |
| 1500 | 1505 | status = d_revalidate(dentry, nd->flags); |
| 1501 | 1506 | } else { |
| @@ -1567,10 +1572,8 @@ static inline int may_lookup(struct nameidata *nd) · 65 unmodified lines |
| 1567 | 1572 | { |
| 1568 | 1573 | if (nd->flags & LOOKUP_RCU) { |
| 1569 | 1574 | int err = inode_permission(nd->inode, MAY_EXEC|MAY_NOT_BLOCK); |
| 1570 | | − if (err != -ECHILD) |
| 1575 | + if (err != -ECHILD || !try_to_unlazy(nd)) |
| 1571 | 1576 | return err; |
| 1572 | | − if (unlazy_walk(nd)) |
| 1573 | | − return -ECHILD; |
| 1574 | 1577 | } |
| 1575 | 1578 | return inode_permission(nd->inode, MAY_EXEC); |
| 1576 | 1579 | } |
| @@ -1592,7 +1595,7 @@ static int reserve_stack(struct nameidata *nd, struct path *link, unsigned seq) · 15 unmodified lines |
| 1592 | 1595 | // unlazy even if we fail to grab the link - cleanup needs it |
| 1593 | 1596 | bool grabbed_link = legitimize_path(nd, link, seq); |
| 1594 | 1597 | |
| 1595 | | − if (unlazy_walk(nd) != 0 || !grabbed_link) |
| 1598 | + if (!try_to_unlazy(nd) != 0 || !grabbed_link) |
| 1596 | 1599 | return -ECHILD; |
| 1597 | 1600 | |
| 1598 | 1601 | if (nd_alloc_stack(nd)) |
| @@ -1634,7 +1637,7 @@ static const char *pick_link(struct nameidata *nd, struct path *link, · 35 unmodified lines |
| 1634 | 1637 | touch_atime(&last->link); |
| 1635 | 1638 | cond_resched(); |
| 1636 | 1639 | } else if (atime_needs_update(&last->link, inode)) { |
| 1637 | | − if (unlikely(unlazy_walk(nd))) |
| 1640 | + if (!try_to_unlazy(nd)) |
| 1638 | 1641 | return ERR_PTR(-ECHILD); |
| 1639 | 1642 | touch_atime(&last->link); |
| 1640 | 1643 | } |
| @@ -1651,11 +1654,8 @@ static const char *pick_link(struct nameidata *nd, struct path *link, · 10 unmodified lines |
| 1651 | 1654 | get = inode->i_op->get_link; |
| 1652 | 1655 | if (nd->flags & LOOKUP_RCU) { |
| 1653 | 1656 | res = get(NULL, inode, &last->done); |
| 1654 | | − if (res == ERR_PTR(-ECHILD)) { |
| 1655 | | − if (unlikely(unlazy_walk(nd))) |
| 1656 | | − return ERR_PTR(-ECHILD); |
| 1657 | + if (res == ERR_PTR(-ECHILD) && try_to_unlazy(nd)) |
| 1657 | 1658 | res = get(link->dentry, inode, &last->done); |
| 1658 | | − } |
| 1659 | 1659 | } else { |
| 1660 | 1660 | res = get(link->dentry, inode, &last->done); |
| 1661 | 1661 | } |
| @@ -2195,7 +2195,7 @@ OK: · 533 unmodified lines |
| 2195 | 2195 | } |
| 2196 | 2196 | if (unlikely(!d_can_lookup(nd->path.dentry))) { |
| 2197 | 2197 | if (nd->flags & LOOKUP_RCU) { |
| 2198 | | − if (unlazy_walk(nd)) |
| 2198 | + if (!try_to_unlazy(nd)) |
| 2199 | 2199 | return -ECHILD; |
| 2200 | 2200 | } |
| 2201 | 2201 | return -ENOTDIR; |
| @@ -2209,6 +2209,10 @@ static const char *path_init(struct nameidata *nd, unsigned flags) · 7 unmodified lines |
| 2209 | 2209 | int error; |
| 2210 | 2210 | const char *s = nd->name->name; |
| 2211 | 2211 | |
| 2212 | + /* LOOKUP_CACHED requires RCU, ask caller to retry */ |
| 2213 | + if ((flags & (LOOKUP_RCU | LOOKUP_CACHED)) == LOOKUP_CACHED) |
| 2214 | + return ERR_PTR(-EAGAIN); |
| 2215 | + |
| 2212 | 2216 | if (!*s) |
| 2213 | 2217 | flags &= ~LOOKUP_RCU; |
| 2214 | 2218 | if (flags & LOOKUP_RCU) |
| @@ -3129,7 +3133,6 @@ static const char *open_last_lookups(struct nameidata *nd, · 914 unmodified lines |
| 3129 | 3133 | struct inode *inode; |
| 3130 | 3134 | struct dentry *dentry; |
| 3131 | 3135 | const char *res; |
| 3132 | | − int error; |
| 3133 | 3136 | |
| 3134 | 3137 | nd->flags |= op->intent; |
| 3135 | 3138 | |
| @@ -3153,9 +3156,8 @@ static const char *open_last_lookups(struct nameidata *nd, · 17 unmodified lines |
| 3153 | 3156 | } else { |
| 3154 | 3157 | /* create side of things */ |
| 3155 | 3158 | if (nd->flags & LOOKUP_RCU) { |
| 3156 | | − error = unlazy_walk(nd); |
| 3157 | | − if (unlikely(error)) |
| 3158 | | − return ERR_PTR(error); |
| 3159 | + if (!try_to_unlazy(nd)) |
| 3160 | + return ERR_PTR(-ECHILD); |
| 3159 | 3161 | } |
| 3160 | 3162 | audit_inode(nd->name, dir, AUDIT_INODE_PARENT); |
| 3161 | 3163 | /* trailing slashes? */ |
| @@ -3164,9 +3166,7 @@ static const char *open_last_lookups(struct nameidata *nd, · 2 unmodified lines |
| 3164 | 3166 | } |
| 3165 | 3167 | |
| 3166 | 3168 | if (open_flag & (O_CREAT | O_TRUNC | O_WRONLY | O_RDWR)) { |
| 3167 | | − error = mnt_want_write(nd->path.mnt); |
| 3168 | | − if (!error) |
| 3169 | | − got_write = true; |
| 3169 | + got_write = !mnt_want_write(nd->path.mnt); |
| 3170 | 3170 | /* |
| 3171 | 3171 | * do _not_ fail yet - we might not need that or fail with |
| 3172 | 3172 | * a different error; let lookup_open() decide; we'll be |
| @@ -3325,10 +3325,8 @@ static int do_tmpfile(struct nameidata *nd, unsigned flags, · 152 unmodified lines |
| 3325 | 3325 | audit_inode(nd->name, child, 0); |
| 3326 | 3326 | /* Don't check for other permissions, the inode was just created */ |
| 3327 | 3327 | error = may_open(&path, 0, op->open_flag); |
| 3328 | | − if (error) |
| 3329 | | − goto out2; |
| 3330 | | − file->f_path.mnt = path.mnt; |
| 3331 | | − error = finish_open(file, child, NULL); |
| 3328 | + if (!error) |
| 3329 | + error = vfs_open(&path, file); |
| 3332 | 3330 | out2: |
| 3333 | 3331 | mnt_drop_write(path.mnt); |
| 3334 | 3332 | out: |