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