]> git.proxmox.com Git - mirror_ubuntu-jammy-kernel.git/commitdiff
Merge branch 'work.namei' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs
authorLinus Torvalds <torvalds@linux-foundation.org>
Sat, 3 Jul 2021 18:41:14 +0000 (11:41 -0700)
committerLinus Torvalds <torvalds@linux-foundation.org>
Sat, 3 Jul 2021 18:41:14 +0000 (11:41 -0700)
Pull vfs name lookup updates from Al Viro:
 "Small namei.c patch series, mostly to simplify the rules for nameidata
  state. It's actually from the previous cycle - but I didn't post it
  for review in time...

  Changes visible outside of fs/namei.c: file_open_root() calling
  conventions change, some freed bits in LOOKUP_... space"

* 'work.namei' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs:
  namei: make sure nd->depth is always valid
  teach set_nameidata() to handle setting the root as well
  take LOOKUP_{ROOT,ROOT_GRABBED,JUMPED} out of LOOKUP_... space
  switch file_open_root() to struct path

14 files changed:
Documentation/filesystems/path-lookup.rst
Documentation/filesystems/porting.rst
arch/um/drivers/mconsole_kern.c
fs/coredump.c
fs/fhandle.c
fs/internal.h
fs/kernel_read_file.c
fs/namei.c
fs/nfs/nfstrace.h
fs/open.c
fs/proc/proc_sysctl.c
include/linux/fs.h
include/linux/namei.h
kernel/usermode_driver.c

index a6fa7619b69ec1971d1ef4709017bceae5cb7ff3..2b2df6aa54324bfe82ae14eb20444f249f36b3ec 100644 (file)
@@ -1297,18 +1297,18 @@ to lookup: RCU-walk, REF-walk, and REF-walk with forced revalidation.
 yet.  This is primarily used to tell the audit subsystem the full
 context of a particular access being audited.
 
-``LOOKUP_ROOT`` indicates that the ``root`` field in the ``nameidata`` was
+``ND_ROOT_PRESET`` indicates that the ``root`` field in the ``nameidata`` was
 provided by the caller, so it shouldn't be released when it is no
 longer needed.
 
-``LOOKUP_JUMPED`` means that the current dentry was chosen not because
+``ND_JUMPED`` means that the current dentry was chosen not because
 it had the right name but for some other reason.  This happens when
 following "``..``", following a symlink to ``/``, crossing a mount point
 or accessing a "``/proc/$PID/fd/$FD``" symlink (also known as a "magic
 link"). In this case the filesystem has not been asked to revalidate the
 name (with ``d_revalidate()``).  In such cases the inode may still need
 to be revalidated, so ``d_op->d_weak_revalidate()`` is called if
-``LOOKUP_JUMPED`` is set when the look completes - which may be at the
+``ND_JUMPED`` is set when the look completes - which may be at the
 final component or, when creating, unlinking, or renaming, at the penultimate component.
 
 Resolution-restriction flags
index 43b492d08dec3ce95308a72ad6b4f3eb858f092d..bf19fd6b86e71ad7c7fc3d36dcd42588b0d8d2ae 100644 (file)
@@ -899,3 +899,12 @@ iov_iter_copy_from_user_atomic() is gone; use copy_page_from_iter_atomic().
 The difference is copy_page_from_iter_atomic() advances the iterator and
 you don't need iov_iter_advance() after it.  However, if you decide to use
 only a part of obtained data, you should do iov_iter_revert().
+
+---
+
+**mandatory**
+
+Calling conventions for file_open_root() changed; now it takes struct path *
+instead of passing mount and dentry separately.  For callers that used to
+pass <mnt, mnt->mnt_root> pair (i.e. the root of given mount), a new helper
+is provided - file_open_root_mnt().  In-tree users adjusted.
index 328b16f99b30389b4a91e679a4285180308909b7..6ead1e24045765bb77826662eb278eb29d48fc96 100644 (file)
@@ -141,7 +141,7 @@ void mconsole_proc(struct mc_request *req)
                mconsole_reply(req, "Proc not available", 1, 0);
                goto out;
        }
-       file = file_open_root(mnt->mnt_root, mnt, ptr, O_RDONLY, 0);
+       file = file_open_root_mnt(mnt, ptr, O_RDONLY, 0);
        if (IS_ERR(file)) {
                mconsole_reply(req, "Failed to open file", 1, 0);
                printk(KERN_ERR "open /proc/%s: %ld\n", ptr, PTR_ERR(file));
index c3d8fc14b993047bfb9a628e893537eb926e0e85..07afb5ddb1c4e747f39b3f92a15e23d951f2fa17 100644 (file)
@@ -755,8 +755,8 @@ void do_coredump(const kernel_siginfo_t *siginfo)
                        task_lock(&init_task);
                        get_fs_root(init_task.fs, &root);
                        task_unlock(&init_task);
-                       cprm.file = file_open_root(root.dentry, root.mnt,
-                               cn.corename, open_flags, 0600);
+                       cprm.file = file_open_root(&root, cn.corename,
+                                                  open_flags, 0600);
                        path_put(&root);
                } else {
                        cprm.file = filp_open(cn.corename, open_flags, 0600);
index ec6feeccc276152010e0e421cd48cf679067f6ea..6630c69c23a2a357fe21947a207afaaac77072bf 100644 (file)
@@ -229,7 +229,7 @@ static long do_handle_open(int mountdirfd, struct file_handle __user *ufh,
                path_put(&path);
                return fd;
        }
-       file = file_open_root(path.dentry, path.mnt, "", open_flag, 0);
+       file = file_open_root(&path, "", open_flag, 0);
        if (IS_ERR(file)) {
                put_unused_fd(fd);
                retval =  PTR_ERR(file);
index 6aeae7ef33803daa83572198d0f4d2de022a6477..3ce8edbaa3ca2f55973e46966ae1017f3e4a0d2a 100644 (file)
@@ -129,7 +129,7 @@ struct open_flags {
 };
 extern struct file *do_filp_open(int dfd, struct filename *pathname,
                const struct open_flags *op);
-extern struct file *do_file_open_root(struct dentry *, struct vfsmount *,
+extern struct file *do_file_open_root(const struct path *,
                const char *, const struct open_flags *);
 extern struct open_how build_open_how(int flags, umode_t mode);
 extern int build_open_flags(const struct open_how *how, struct open_flags *op);
index 90d255fbdd9b34d366bd6b6fe64f6c760595ea8f..87aac4c72c37da2f82cad443279d66f0b5a2cf8c 100644 (file)
@@ -160,7 +160,7 @@ int kernel_read_file_from_path_initns(const char *path, loff_t offset,
        get_fs_root(init_task.fs, &root);
        task_unlock(&init_task);
 
-       file = file_open_root(root.dentry, root.mnt, path, O_RDONLY, 0);
+       file = file_open_root(&root, path, O_RDONLY, 0);
        path_put(&root);
        if (IS_ERR(file))
                return PTR_ERR(file);
index 79b0ff9b151e22b16b28016fbc5fcd14726386c2..bf6d8a738c599e62bf6de18b59c27cf2bd19725f 100644 (file)
@@ -554,7 +554,7 @@ struct nameidata {
        struct qstr     last;
        struct path     root;
        struct inode    *inode; /* path.dentry.d_inode */
-       unsigned int    flags;
+       unsigned int    flags, state;
        unsigned        seq, m_seq, r_seq;
        int             last_type;
        unsigned        depth;
@@ -573,10 +573,15 @@ struct nameidata {
        umode_t         dir_mode;
 } __randomize_layout;
 
-static void set_nameidata(struct nameidata *p, int dfd, struct filename *name)
+#define ND_ROOT_PRESET 1
+#define ND_ROOT_GRABBED 2
+#define ND_JUMPED 4
+
+static void __set_nameidata(struct nameidata *p, int dfd, struct filename *name)
 {
        struct nameidata *old = current->nameidata;
        p->stack = p->internal;
+       p->depth = 0;
        p->dfd = dfd;
        p->name = name;
        p->path.mnt = NULL;
@@ -586,6 +591,17 @@ static void set_nameidata(struct nameidata *p, int dfd, struct filename *name)
        current->nameidata = p;
 }
 
+static inline void set_nameidata(struct nameidata *p, int dfd, struct filename *name,
+                         const struct path *root)
+{
+       __set_nameidata(p, dfd, name);
+       p->state = 0;
+       if (unlikely(root)) {
+               p->state = ND_ROOT_PRESET;
+               p->root = *root;
+       }
+}
+
 static void restore_nameidata(void)
 {
        struct nameidata *now = current->nameidata, *old = now->saved;
@@ -645,9 +661,9 @@ static void terminate_walk(struct nameidata *nd)
                path_put(&nd->path);
                for (i = 0; i < nd->depth; i++)
                        path_put(&nd->stack[i].link);
-               if (nd->flags & LOOKUP_ROOT_GRABBED) {
+               if (nd->state & ND_ROOT_GRABBED) {
                        path_put(&nd->root);
-                       nd->flags &= ~LOOKUP_ROOT_GRABBED;
+                       nd->state &= ~ND_ROOT_GRABBED;
                }
        } else {
                nd->flags &= ~LOOKUP_RCU;
@@ -710,9 +726,9 @@ static bool legitimize_root(struct nameidata *nd)
        if (!nd->root.mnt && (nd->flags & LOOKUP_IS_SCOPED))
                return false;
        /* Nothing to do if nd->root is zero or is managed by the VFS user. */
-       if (!nd->root.mnt || (nd->flags & LOOKUP_ROOT))
+       if (!nd->root.mnt || (nd->state & ND_ROOT_PRESET))
                return true;
-       nd->flags |= LOOKUP_ROOT_GRABBED;
+       nd->state |= ND_ROOT_GRABBED;
        return legitimize_path(nd, &nd->root, nd->root_seq);
 }
 
@@ -849,8 +865,9 @@ static int complete_walk(struct nameidata *nd)
                 * We don't want to zero nd->root for scoped-lookups or
                 * externally-managed nd->root.
                 */
-               if (!(nd->flags & (LOOKUP_ROOT | LOOKUP_IS_SCOPED)))
-                       nd->root.mnt = NULL;
+               if (!(nd->state & ND_ROOT_PRESET))
+                       if (!(nd->flags & LOOKUP_IS_SCOPED))
+                               nd->root.mnt = NULL;
                nd->flags &= ~LOOKUP_CACHED;
                if (!try_to_unlazy(nd))
                        return -ECHILD;
@@ -877,7 +894,7 @@ static int complete_walk(struct nameidata *nd)
                        return -EXDEV;
        }
 
-       if (likely(!(nd->flags & LOOKUP_JUMPED)))
+       if (likely(!(nd->state & ND_JUMPED)))
                return 0;
 
        if (likely(!(dentry->d_flags & DCACHE_OP_WEAK_REVALIDATE)))
@@ -915,7 +932,7 @@ static int set_root(struct nameidata *nd)
                } while (read_seqcount_retry(&fs->seq, seq));
        } else {
                get_fs_root(fs, &nd->root);
-               nd->flags |= LOOKUP_ROOT_GRABBED;
+               nd->state |= ND_ROOT_GRABBED;
        }
        return 0;
 }
@@ -948,7 +965,7 @@ static int nd_jump_root(struct nameidata *nd)
                path_get(&nd->path);
                nd->inode = nd->path.dentry->d_inode;
        }
-       nd->flags |= LOOKUP_JUMPED;
+       nd->state |= ND_JUMPED;
        return 0;
 }
 
@@ -976,7 +993,7 @@ int nd_jump_link(struct path *path)
        path_put(&nd->path);
        nd->path = *path;
        nd->inode = nd->path.dentry->d_inode;
-       nd->flags |= LOOKUP_JUMPED;
+       nd->state |= ND_JUMPED;
        return 0;
 
 err:
@@ -1423,7 +1440,7 @@ static bool __follow_mount_rcu(struct nameidata *nd, struct path *path,
                        if (mounted) {
                                path->mnt = &mounted->mnt;
                                dentry = path->dentry = mounted->mnt.mnt_root;
-                               nd->flags |= LOOKUP_JUMPED;
+                               nd->state |= ND_JUMPED;
                                *seqp = read_seqcount_begin(&dentry->d_seq);
                                *inode = dentry->d_inode;
                                /*
@@ -1468,7 +1485,7 @@ static inline int handle_mounts(struct nameidata *nd, struct dentry *dentry,
                if (unlikely(nd->flags & LOOKUP_NO_XDEV))
                        ret = -EXDEV;
                else
-                       nd->flags |= LOOKUP_JUMPED;
+                       nd->state |= ND_JUMPED;
        }
        if (unlikely(ret)) {
                dput(path->dentry);
@@ -2219,7 +2236,7 @@ static int link_path_walk(const char *name, struct nameidata *nd)
                        case 2:
                                if (name[1] == '.') {
                                        type = LAST_DOTDOT;
-                                       nd->flags |= LOOKUP_JUMPED;
+                                       nd->state |= ND_JUMPED;
                                }
                                break;
                        case 1:
@@ -2227,7 +2244,7 @@ static int link_path_walk(const char *name, struct nameidata *nd)
                }
                if (likely(type == LAST_NORM)) {
                        struct dentry *parent = nd->path.dentry;
-                       nd->flags &= ~LOOKUP_JUMPED;
+                       nd->state &= ~ND_JUMPED;
                        if (unlikely(parent->d_flags & DCACHE_OP_HASH)) {
                                struct qstr this = { { .hash_len = hash_len }, .name = name };
                                err = parent->d_op->d_hash(parent, &this);
@@ -2301,14 +2318,14 @@ static const char *path_init(struct nameidata *nd, unsigned flags)
        if (flags & LOOKUP_RCU)
                rcu_read_lock();
 
-       nd->flags = flags | LOOKUP_JUMPED;
-       nd->depth = 0;
+       nd->flags = flags;
+       nd->state |= ND_JUMPED;
 
        nd->m_seq = __read_seqcount_begin(&mount_lock.seqcount);
        nd->r_seq = __read_seqcount_begin(&rename_lock.seqcount);
        smp_rmb();
 
-       if (flags & LOOKUP_ROOT) {
+       if (nd->state & ND_ROOT_PRESET) {
                struct dentry *root = nd->root.dentry;
                struct inode *inode = root->d_inode;
                if (*s && unlikely(!d_can_lookup(root)))
@@ -2383,7 +2400,7 @@ static const char *path_init(struct nameidata *nd, unsigned flags)
                        nd->root_seq = nd->seq;
                } else {
                        path_get(&nd->root);
-                       nd->flags |= LOOKUP_ROOT_GRABBED;
+                       nd->state |= ND_ROOT_GRABBED;
                }
        }
        return s;
@@ -2422,7 +2439,7 @@ static int path_lookupat(struct nameidata *nd, unsigned flags, struct path *path
                ;
        if (!err && unlikely(nd->flags & LOOKUP_MOUNTPOINT)) {
                err = handle_lookup_down(nd);
-               nd->flags &= ~LOOKUP_JUMPED; // no d_weak_revalidate(), please...
+               nd->state &= ~ND_JUMPED; // no d_weak_revalidate(), please...
        }
        if (!err)
                err = complete_walk(nd);
@@ -2446,11 +2463,7 @@ int filename_lookup(int dfd, struct filename *name, unsigned flags,
        struct nameidata nd;
        if (IS_ERR(name))
                return PTR_ERR(name);
-       if (unlikely(root)) {
-               nd.root = *root;
-               flags |= LOOKUP_ROOT;
-       }
-       set_nameidata(&nd, dfd, name);
+       set_nameidata(&nd, dfd, name, root);
        retval = path_lookupat(&nd, flags | LOOKUP_RCU, path);
        if (unlikely(retval == -ECHILD))
                retval = path_lookupat(&nd, flags, path);
@@ -2491,7 +2504,7 @@ static struct filename *filename_parentat(int dfd, struct filename *name,
 
        if (IS_ERR(name))
                return name;
-       set_nameidata(&nd, dfd, name);
+       set_nameidata(&nd, dfd, name, NULL);
        retval = path_parentat(&nd, flags | LOOKUP_RCU, parent);
        if (unlikely(retval == -ECHILD))
                retval = path_parentat(&nd, flags, parent);
@@ -3517,7 +3530,7 @@ struct file *do_filp_open(int dfd, struct filename *pathname,
        int flags = op->lookup_flags;
        struct file *filp;
 
-       set_nameidata(&nd, dfd, pathname);
+       set_nameidata(&nd, dfd, pathname, NULL);
        filp = path_openat(&nd, op, flags | LOOKUP_RCU);
        if (unlikely(filp == ERR_PTR(-ECHILD)))
                filp = path_openat(&nd, op, flags);
@@ -3527,25 +3540,22 @@ struct file *do_filp_open(int dfd, struct filename *pathname,
        return filp;
 }
 
-struct file *do_file_open_root(struct dentry *dentry, struct vfsmount *mnt,
+struct file *do_file_open_root(const struct path *root,
                const char *name, const struct open_flags *op)
 {
        struct nameidata nd;
        struct file *file;
        struct filename *filename;
-       int flags = op->lookup_flags | LOOKUP_ROOT;
-
-       nd.root.mnt = mnt;
-       nd.root.dentry = dentry;
+       int flags = op->lookup_flags;
 
-       if (d_is_symlink(dentry) && op->intent & LOOKUP_OPEN)
+       if (d_is_symlink(root->dentry) && op->intent & LOOKUP_OPEN)
                return ERR_PTR(-ELOOP);
 
        filename = getname_kernel(name);
        if (IS_ERR(filename))
                return ERR_CAST(filename);
 
-       set_nameidata(&nd, -1, filename);
+       set_nameidata(&nd, -1, filename, root);
        file = path_openat(&nd, op, flags | LOOKUP_RCU);
        if (unlikely(file == ERR_PTR(-ECHILD)))
                file = path_openat(&nd, op, flags);
index 73080526f5f35900deda6076fa82aef9b8e73815..8a224871be74c6587a4a6c44d70b7c42305529be 100644 (file)
@@ -280,8 +280,6 @@ TRACE_DEFINE_ENUM(LOOKUP_OPEN);
 TRACE_DEFINE_ENUM(LOOKUP_CREATE);
 TRACE_DEFINE_ENUM(LOOKUP_EXCL);
 TRACE_DEFINE_ENUM(LOOKUP_RENAME_TARGET);
-TRACE_DEFINE_ENUM(LOOKUP_JUMPED);
-TRACE_DEFINE_ENUM(LOOKUP_ROOT);
 TRACE_DEFINE_ENUM(LOOKUP_EMPTY);
 TRACE_DEFINE_ENUM(LOOKUP_DOWN);
 
@@ -297,8 +295,6 @@ TRACE_DEFINE_ENUM(LOOKUP_DOWN);
                        { LOOKUP_CREATE, "CREATE" }, \
                        { LOOKUP_EXCL, "EXCL" }, \
                        { LOOKUP_RENAME_TARGET, "RENAME_TARGET" }, \
-                       { LOOKUP_JUMPED, "JUMPED" }, \
-                       { LOOKUP_ROOT, "ROOT" }, \
                        { LOOKUP_EMPTY, "EMPTY" }, \
                        { LOOKUP_DOWN, "DOWN" })
 
index 1a325b3194dfebd48075c956579e839f03302ce9..94bef26ff1b616a23544da9e0d9232ef97aca034 100644 (file)
--- a/fs/open.c
+++ b/fs/open.c
@@ -1173,7 +1173,7 @@ struct file *filp_open(const char *filename, int flags, umode_t mode)
 }
 EXPORT_SYMBOL(filp_open);
 
-struct file *file_open_root(struct dentry *dentry, struct vfsmount *mnt,
+struct file *file_open_root(const struct path *root,
                            const char *filename, int flags, umode_t mode)
 {
        struct open_flags op;
@@ -1181,7 +1181,7 @@ struct file *file_open_root(struct dentry *dentry, struct vfsmount *mnt,
        int err = build_open_flags(&how, &op);
        if (err)
                return ERR_PTR(err);
-       return do_file_open_root(dentry, mnt, filename, &op);
+       return do_file_open_root(root, filename, &op);
 }
 EXPORT_SYMBOL(file_open_root);
 
index dea0f5ee540cce0ba9d30ca67572c057d99a31ce..5d66faecd4ef06b8225a22e1abad55b3cf2ee3e1 100644 (file)
@@ -1807,7 +1807,7 @@ static int process_sysctl_arg(char *param, char *val,
                panic("%s: Failed to allocate path for %s\n", __func__, param);
        strreplace(path, '.', '/');
 
-       file = file_open_root((*proc_mnt)->mnt_root, *proc_mnt, path, O_WRONLY, 0);
+       file = file_open_root_mnt(*proc_mnt, path, O_WRONLY, 0);
        if (IS_ERR(file)) {
                err = PTR_ERR(file);
                if (err == -ENOENT)
index 02bf57e6f6e2be8cd7e1438f5a6b8a45528e4819..bb40ac8608a7b13f240f7baf70e82e08dc853fe3 100644 (file)
@@ -2768,8 +2768,14 @@ extern long do_sys_open(int dfd, const char __user *filename, int flags,
                        umode_t mode);
 extern struct file *file_open_name(struct filename *, int, umode_t);
 extern struct file *filp_open(const char *, int, umode_t);
-extern struct file *file_open_root(struct dentry *, struct vfsmount *,
+extern struct file *file_open_root(const struct path *,
                                   const char *, int, umode_t);
+static inline struct file *file_open_root_mnt(struct vfsmount *mnt,
+                                  const char *name, int flags, umode_t mode)
+{
+       return file_open_root(&(struct path){.mnt = mnt, .dentry = mnt->mnt_root},
+                             name, flags, mode);
+}
 extern struct file * dentry_open(const struct path *, int, const struct cred *);
 extern struct file * open_with_fake_path(const struct path *, int,
                                         struct inode*, const struct cred *);
index b9605b2b46e7141f4a6366e787f70b7c19839909..be9a2b349ca7e80e003f4ce86bd2512a928f1494 100644 (file)
@@ -36,9 +36,6 @@ enum {LAST_NORM, LAST_ROOT, LAST_DOT, LAST_DOTDOT};
 
 /* internal use only */
 #define LOOKUP_PARENT          0x0010
-#define LOOKUP_JUMPED          0x1000
-#define LOOKUP_ROOT            0x2000
-#define LOOKUP_ROOT_GRABBED    0x0008
 
 /* Scoping flags for lookup. */
 #define LOOKUP_NO_SYMLINKS     0x010000 /* No symlink crossing. */
index bb7bb3b478abfa5c6dbb81466125858db1f90d5b..9dae1f6487136a3b9132c6f18c5c2aba2a028fc4 100644 (file)
@@ -26,7 +26,7 @@ static struct vfsmount *blob_to_mnt(const void *data, size_t len, const char *na
        if (IS_ERR(mnt))
                return mnt;
 
-       file = file_open_root(mnt->mnt_root, mnt, name, O_CREAT | O_WRONLY, 0700);
+       file = file_open_root_mnt(mnt, name, O_CREAT | O_WRONLY, 0700);
        if (IS_ERR(file)) {
                mntput(mnt);
                return ERR_CAST(file);