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
669669 */
670670
671671 /**
672− * unlazy_walk - try to switch to ref-walk mode.
672+ * try_to_unlazy - try to switch to ref-walk mode.
673673 * @nd: nameidata pathwalk data
674− * Returns: 0 on success, -ECHILD on failure
674+ * Returns: true on success, false on failure
675675 *
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
677677 * for ref-walk mode.
678678 * 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
680680 * terminate_walk().
681681 */
682−static int unlazy_walk(struct nameidata *nd)
682+static bool try_to_unlazy(struct nameidata *nd)
683683 {
684684 struct dentry *parent = nd->path.dentry;
685685
686686 BUG_ON(!(nd->flags & LOOKUP_RCU));
687687
688688 nd->flags &= ~LOOKUP_RCU;
689+ if (nd->flags & LOOKUP_CACHED)
690+ goto out1;
689691 if (unlikely(!legitimize_links(nd)))
690692 goto out1;
691693 if (unlikely(!legitimize_path(nd, &nd->path, nd->seq)))
@@ -694,34 +696,36 @@ static int unlazy_walk(struct nameidata *nd) · 2 unmodified lines
694696 goto out;
695697 rcu_read_unlock();
696698 BUG_ON(nd->inode != parent->d_inode);
697− return 0;
699+ return true;
698700
699701 out1:
700702 nd->path.mnt = NULL;
701703 nd->path.dentry = NULL;
702704 out:
703705 rcu_read_unlock();
704− return -ECHILD;
706+ return false;
705707 }
706708
707709 /**
708− * unlazy_child - try to switch to ref-walk mode.
710+ * try_to_unlazy_next - try to switch to ref-walk mode.
709711 * @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
713715 *
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
718720 * terminate_walk().
719721 */
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)
721723 {
722724 BUG_ON(!(nd->flags & LOOKUP_RCU));
723725
724726 nd->flags &= ~LOOKUP_RCU;
727+ if (nd->flags & LOOKUP_CACHED)
728+ goto out2;
725729 if (unlikely(!legitimize_links(nd)))
726730 goto out2;
727731 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
747751 if (unlikely(!legitimize_root(nd)))
748752 goto out_dput;
749753 rcu_read_unlock();
750− return 0;
754+ return true;
751755
752756 out2:
753757 nd->path.mnt = NULL;
@@ -755,11 +759,11 @@ out1: · 1 unmodified line
755759 nd->path.dentry = NULL;
756760 out:
757761 rcu_read_unlock();
758− return -ECHILD;
762+ return false;
759763 out_dput:
760764 rcu_read_unlock();
761765 dput(dentry);
762− return -ECHILD;
766+ return false;
763767 }
764768
765769 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
792796 */
793797 if (!(nd->flags & (LOOKUP_ROOT | LOOKUP_IS_SCOPED)))
794798 nd->root.mnt = NULL;
795− if (unlikely(unlazy_walk(nd)))
799+ nd->flags &= ~LOOKUP_CACHED;
800+ if (!try_to_unlazy(nd))
796801 return -ECHILD;
797802 }
798803
@@ -1372,7 +1377,7 @@ static inline int handle_mounts(struct nameidata *nd, struct dentry *dentry, · 573 unmodified lines
13721377 return -ENOENT;
13731378 if (likely(__follow_mount_rcu(nd, path, inode, seqp)))
13741379 return 0;
1375− if (unlazy_child(nd, dentry, seq))
1380+ if (!try_to_unlazy_next(nd, dentry, seq))
13761381 return -ECHILD;
13771382 // *path might've been clobbered by __follow_mount_rcu()
13781383 path->mnt = nd->path.mnt;
@@ -1466,7 +1471,7 @@ static struct dentry *lookup_fast(struct nameidata *nd, · 87 unmodified lines
14661471 unsigned seq;
14671472 dentry = __d_lookup_rcu(parent, &nd->last, &seq);
14681473 if (unlikely(!dentry)) {
1469− if (unlazy_walk(nd))
1474+ if (!try_to_unlazy(nd))
14701475 return ERR_PTR(-ECHILD);
14711476 return NULL;
14721477 }
@@ -1493,9 +1498,9 @@ static struct dentry *lookup_fast(struct nameidata *nd, · 20 unmodified lines
14931498 status = d_revalidate(dentry, nd->flags);
14941499 if (likely(status > 0))
14951500 return dentry;
1496− if (unlazy_child(nd, dentry, seq))
1501+ if (!try_to_unlazy_next(nd, dentry, seq))
14971502 return ERR_PTR(-ECHILD);
1498− if (unlikely(status == -ECHILD))
1503+ if (status == -ECHILD)
14991504 /* we'd been told to redo it in non-rcu mode */
15001505 status = d_revalidate(dentry, nd->flags);
15011506 } else {
@@ -1567,10 +1572,8 @@ static inline int may_lookup(struct nameidata *nd) · 65 unmodified lines
15671572 {
15681573 if (nd->flags & LOOKUP_RCU) {
15691574 int err = inode_permission(nd->inode, MAY_EXEC|MAY_NOT_BLOCK);
1570− if (err != -ECHILD)
1575+ if (err != -ECHILD || !try_to_unlazy(nd))
15711576 return err;
1572− if (unlazy_walk(nd))
1573− return -ECHILD;
15741577 }
15751578 return inode_permission(nd->inode, MAY_EXEC);
15761579 }
@@ -1592,7 +1595,7 @@ static int reserve_stack(struct nameidata *nd, struct path *link, unsigned seq) · 15 unmodified lines
15921595 // unlazy even if we fail to grab the link - cleanup needs it
15931596 bool grabbed_link = legitimize_path(nd, link, seq);
15941597
1595− if (unlazy_walk(nd) != 0 || !grabbed_link)
1598+ if (!try_to_unlazy(nd) != 0 || !grabbed_link)
15961599 return -ECHILD;
15971600
15981601 if (nd_alloc_stack(nd))
@@ -1634,7 +1637,7 @@ static const char *pick_link(struct nameidata *nd, struct path *link, · 35 unmodified lines
16341637 touch_atime(&last->link);
16351638 cond_resched();
16361639 } else if (atime_needs_update(&last->link, inode)) {
1637− if (unlikely(unlazy_walk(nd)))
1640+ if (!try_to_unlazy(nd))
16381641 return ERR_PTR(-ECHILD);
16391642 touch_atime(&last->link);
16401643 }
@@ -1651,11 +1654,8 @@ static const char *pick_link(struct nameidata *nd, struct path *link, · 10 unmodified lines
16511654 get = inode->i_op->get_link;
16521655 if (nd->flags & LOOKUP_RCU) {
16531656 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))
16571658 res = get(link->dentry, inode, &last->done);
1658− }
16591659 } else {
16601660 res = get(link->dentry, inode, &last->done);
16611661 }
@@ -2195,7 +2195,7 @@ OK: · 533 unmodified lines
21952195 }
21962196 if (unlikely(!d_can_lookup(nd->path.dentry))) {
21972197 if (nd->flags & LOOKUP_RCU) {
2198− if (unlazy_walk(nd))
2198+ if (!try_to_unlazy(nd))
21992199 return -ECHILD;
22002200 }
22012201 return -ENOTDIR;
@@ -2209,6 +2209,10 @@ static const char *path_init(struct nameidata *nd, unsigned flags) · 7 unmodified lines
22092209 int error;
22102210 const char *s = nd->name->name;
22112211
2212+ /* LOOKUP_CACHED requires RCU, ask caller to retry */
2213+ if ((flags & (LOOKUP_RCU | LOOKUP_CACHED)) == LOOKUP_CACHED)
2214+ return ERR_PTR(-EAGAIN);
2215+
22122216 if (!*s)
22132217 flags &= ~LOOKUP_RCU;
22142218 if (flags & LOOKUP_RCU)
@@ -3129,7 +3133,6 @@ static const char *open_last_lookups(struct nameidata *nd, · 914 unmodified lines
31293133 struct inode *inode;
31303134 struct dentry *dentry;
31313135 const char *res;
3132− int error;
31333136
31343137 nd->flags |= op->intent;
31353138
@@ -3153,9 +3156,8 @@ static const char *open_last_lookups(struct nameidata *nd, · 17 unmodified lines
31533156 } else {
31543157 /* create side of things */
31553158 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);
31593161 }
31603162 audit_inode(nd->name, dir, AUDIT_INODE_PARENT);
31613163 /* trailing slashes? */
@@ -3164,9 +3166,7 @@ static const char *open_last_lookups(struct nameidata *nd, · 2 unmodified lines
31643166 }
31653167
31663168 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);
31703170 /*
31713171 * do _not_ fail yet - we might not need that or fail with
31723172 * 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
33253325 audit_inode(nd->name, child, 0);
33263326 /* Don't check for other permissions, the inode was just created */
33273327 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);
33323330 out2:
33333331 mnt_drop_write(path.mnt);
33343332 out:
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
10911091 lookup_flags |= LOOKUP_BENEATH;
10921092 if (how->resolve & RESOLVE_IN_ROOT)
10931093 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+ }
10941100
10951101 op->lookup_flags = lookup_flags;
10961102 return 0;
include/linux/fcntl.h+1−1
@@ -19,7 +19,7 @@ · 18 unmodified lines
1919 /* List of all valid flags for the how->resolve argument: */
2020 #define VALID_RESOLVE_FLAGS \
2121 (RESOLVE_NO_XDEV | RESOLVE_NO_MAGICLINKS | RESOLVE_NO_SYMLINKS | \
22− RESOLVE_BENEATH | RESOLVE_IN_ROOT)
22+ RESOLVE_BENEATH | RESOLVE_IN_ROOT | RESOLVE_CACHED)
2323
2424 /* List of all open_how "versions". */
2525 #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
4646 #define LOOKUP_NO_XDEV 0x040000 /* No mountpoint crossing. */
4747 #define LOOKUP_BENEATH 0x080000 /* No escaping from starting point. */
4848 #define LOOKUP_IN_ROOT 0x100000 /* Treat dirfd as fs root. */
49+#define LOOKUP_CACHED 0x200000 /* Only do cached lookup */
4950 /* LOOKUP_* flags which do scope-related checks based on the dirfd. */
5051 #define LOOKUP_IS_SCOPED (LOOKUP_BENEATH | LOOKUP_IN_ROOT)
5152
include/uapi/linux/openat2.h+4−0
@@ -35,5 +35,9 @@ struct open_how { · 34 unmodified lines
3535 #define RESOLVE_IN_ROOT 0x10 /* Make all jumps to "/" and ".."
3636 be scoped inside the dirfd
3737 (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. */
3842
3943 #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