History

Merge branch 'work.namei' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs into for-5.12/io_uring

Merge RESOLVE_CACHED bits from Al, as the io_uring changes will build on top of that. * 'work.namei' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs: fs: expose LOOKUP_CACHED through openat2() RESOLVE_CACHED fs: add support for LOOKUP_CACHED saner calling conventions for unlazy_child() fs: make unlazy_walk() error handling consistent fs/namei.c: Remove unlikely of status being -ECHILD in lookup_fast() do_tmpfile(): don't mess with finish_open()

Jens Axboe committed 5 years ago

Commit b2d86c72 parents 1048ba8 99668f65 files · +55 −46Browse files

Unified · Split

5 files
  1. fs/namei.c +43 −45
  2. fs/open.c +6 −0
  3. include/linux/fcntl.h +1 −1
  4. include/linux/namei.h +1 −0
  5. include/uapi/linux/openat2.h +4 −0
fs/namei.c+43−45
@@ -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 data673 * @nd: nameidata pathwalk data
674 * Returns: 0 on success, -ECHILD on failure674 * Returns: true on success, false on failure
675 *675 *
676 * unlazy_walk attempts to legitimize the current nd->path and nd->root676 * 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 and679 * Nothing should touch nameidata between try_to_unlazy() failure and
680 * terminate_walk().680 * terminate_walk().
681 */681 */
682static int unlazy_walk(struct nameidata *nd)682static 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
699out1:701out1:
700 nd->path.mnt = NULL;702 nd->path.mnt = NULL;
701 nd->path.dentry = NULL;703 nd->path.dentry = NULL;
702out:704out:
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 data711 * @nd: nameidata pathwalk data
710 * @dentry: child of nd->path.dentry712 * @dentry: next dentry to step into
711 * @seq: seq number to check dentry against713 * @seq: seq number to check @dentry against
712 * Returns: 0 on success, -ECHILD on failure714 * Returns: true on success, false on failure
713 *715 *
714 * unlazy_child attempts to legitimize the current nd->path, nd->root and dentry716 * 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 on717 * 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 and719 * Nothing should touch nameidata between try_to_unlazy_next() failure and
718 * terminate_walk().720 * terminate_walk().
719 */721 */
720static int unlazy_child(struct nameidata *nd, struct dentry *dentry, unsigned seq)722static 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
752out2:756out2:
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;
756out:760out:
757 rcu_read_unlock();761 rcu_read_unlock();
758 return -ECHILD;762 return false;
759out_dput:763out_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
765static inline int d_revalidate(struct dentry *dentry, unsigned int flags)769static 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 it1595 // 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 with3171 * do _not_ fail yet - we might not need that or fail with
3172 * a different error; let lookup_open() decide; we'll be3172 * 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);
3332out2:3330out2:
3333 mnt_drop_write(path.mnt);3331 mnt_drop_write(path.mnt);
3334out:3332out:
fs/open.c+6−0
@@ -1091,6 +1091,12 @@ inline int build_open_flags(const struct open_how *how, struct open_flags *op) · 1090 unmodified lines
1091 lookup_flags |= LOOKUP_BENEATH;1091 lookup_flags |= LOOKUP_BENEATH;
1092 if (how->resolve & RESOLVE_IN_ROOT)1092 if (how->resolve & RESOLVE_IN_ROOT)
1093 lookup_flags |= LOOKUP_IN_ROOT;1093 lookup_flags |= LOOKUP_IN_ROOT;
1094 if (how->resolve & RESOLVE_CACHED) {
1095 /* Don't bother even trying for create/truncate/tmpfile open */
1096 if (flags & (O_TRUNC | O_CREAT | O_TMPFILE))
1097 return -EAGAIN;
1098 lookup_flags |= LOOKUP_CACHED;
1099 }
1094 1100
1095 op->lookup_flags = lookup_flags;1101 op->lookup_flags = lookup_flags;
1096 return 0;1102 return 0;
include/linux/fcntl.h+1−1
@@ -19,7 +19,7 @@ · 18 unmodified lines
19/* List of all valid flags for the how->resolve argument: */19/* List of all valid flags for the how->resolve argument: */
20#define VALID_RESOLVE_FLAGS \20#define VALID_RESOLVE_FLAGS \
21 (RESOLVE_NO_XDEV | RESOLVE_NO_MAGICLINKS | RESOLVE_NO_SYMLINKS | \21 (RESOLVE_NO_XDEV | RESOLVE_NO_MAGICLINKS | RESOLVE_NO_SYMLINKS | \
22 RESOLVE_BENEATH | RESOLVE_IN_ROOT)22 RESOLVE_BENEATH | RESOLVE_IN_ROOT | RESOLVE_CACHED)
23 23
24/* List of all open_how "versions". */24/* List of all open_how "versions". */
25#define OPEN_HOW_SIZE_VER0 24 /* sizeof first published struct */25#define OPEN_HOW_SIZE_VER0 24 /* sizeof first published struct */
include/linux/namei.h+1−0
@@ -46,6 +46,7 @@ enum {LAST_NORM, LAST_ROOT, LAST_DOT, LAST_DOTDOT}; · 45 unmodified lines
46#define LOOKUP_NO_XDEV 0x040000 /* No mountpoint crossing. */46#define LOOKUP_NO_XDEV 0x040000 /* No mountpoint crossing. */
47#define LOOKUP_BENEATH 0x080000 /* No escaping from starting point. */47#define LOOKUP_BENEATH 0x080000 /* No escaping from starting point. */
48#define LOOKUP_IN_ROOT 0x100000 /* Treat dirfd as fs root. */48#define LOOKUP_IN_ROOT 0x100000 /* Treat dirfd as fs root. */
49#define LOOKUP_CACHED 0x200000 /* Only do cached lookup */
49/* LOOKUP_* flags which do scope-related checks based on the dirfd. */50/* LOOKUP_* flags which do scope-related checks based on the dirfd. */
50#define LOOKUP_IS_SCOPED (LOOKUP_BENEATH | LOOKUP_IN_ROOT)51#define LOOKUP_IS_SCOPED (LOOKUP_BENEATH | LOOKUP_IN_ROOT)
51 52
include/uapi/linux/openat2.h+4−0
@@ -35,5 +35,9 @@ struct open_how { · 34 unmodified lines
35#define RESOLVE_IN_ROOT 0x10 /* Make all jumps to "/" and ".."35#define RESOLVE_IN_ROOT 0x10 /* Make all jumps to "/" and ".."
36 be scoped inside the dirfd36 be scoped inside the dirfd
37 (similar to chroot(2)). */37 (similar to chroot(2)). */
38#define RESOLVE_CACHED 0x20 /* Only complete if resolution can be
39 completed through cached lookup. May
40 return -EAGAIN if that's not
41 possible. */
38 42
39#endif /* _UAPI_LINUX_OPENAT2_H */43#endif /* _UAPI_LINUX_OPENAT2_H */

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t