vfs: syscall: Add fspick() to select a superblock for reconfiguration
authorDavid Howells <dhowells@redhat.com>
Thu, 1 Nov 2018 23:36:23 +0000 (23:36 +0000)
committerAl Viro <viro@zeniv.linux.org.uk>
Wed, 20 Mar 2019 22:49:06 +0000 (18:49 -0400)
Provide an fspick() system call that can be used to pick an existing
mountpoint into an fs_context which can thereafter be used to reconfigure a
superblock (equivalent of the superblock side of -o remount).

This looks like:

int fd = fspick(AT_FDCWD, "/mnt",
FSPICK_CLOEXEC | FSPICK_NO_AUTOMOUNT);
fsconfig(fd, FSCONFIG_SET_FLAG, "intr", NULL, 0);
fsconfig(fd, FSCONFIG_SET_FLAG, "noac", NULL, 0);
fsconfig(fd, FSCONFIG_CMD_RECONFIGURE, NULL, NULL, 0);

At the point of fspick being called, the file descriptor referring to the
filesystem context is in exactly the same state as the one that was created
by fsopen() after fsmount() has been successfully called.

Signed-off-by: David Howells <dhowells@redhat.com>
cc: linux-api@vger.kernel.org
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
arch/x86/entry/syscalls/syscall_32.tbl
arch/x86/entry/syscalls/syscall_64.tbl
fs/fsopen.c
include/linux/syscalls.h
include/uapi/linux/mount.h

index 5b5c9189c507dd4382bff257fb3587ce18e4e7f6..4cd5f982b1e5d6127175564e0f0f79903605d06f 100644 (file)
 389    i386    fsopen                  sys_fsopen                      __ia32_sys_fsopen
 390    i386    fsconfig                sys_fsconfig                    __ia32_sys_fsconfig
 391    i386    fsmount                 sys_fsmount                     __ia32_sys_fsmount
-# don't use number 392, add new calls at the end
+392    i386    fspick                  sys_fspick                      __ia32_sys_fspick
 393    i386    semget                  sys_semget                      __ia32_sys_semget
 394    i386    semctl                  sys_semctl                      __ia32_compat_sys_semctl
 395    i386    shmget                  sys_shmget                      __ia32_sys_shmget
index 984ad594bb2bb7fd0fad5931eb0d383861a0e374..64ca0d06259a7635ebc8ae1fa5e3a6b1447b3cd3 100644 (file)
 337    common  fsopen                  __x64_sys_fsopen
 338    common  fsconfig                __x64_sys_fsconfig
 339    common  fsmount                 __x64_sys_fsmount
+340    common  fspick                  __x64_sys_fspick
 # don't use numbers 387 through 423, add new calls after the last
 # 'common' entry
 424    common  pidfd_send_signal       __x64_sys_pidfd_send_signal
index 65cc2f68f994d7665abb12a88b33df7c4c3375d0..3bb9c0c8cbcc2f6d8ede5ccad01ca1bb903ad418 100644 (file)
@@ -156,6 +156,63 @@ err_fc:
        return ret;
 }
 
+/*
+ * Pick a superblock into a context for reconfiguration.
+ */
+SYSCALL_DEFINE3(fspick, int, dfd, const char __user *, path, unsigned int, flags)
+{
+       struct fs_context *fc;
+       struct path target;
+       unsigned int lookup_flags;
+       int ret;
+
+       if (!ns_capable(current->nsproxy->mnt_ns->user_ns, CAP_SYS_ADMIN))
+               return -EPERM;
+
+       if ((flags & ~(FSPICK_CLOEXEC |
+                      FSPICK_SYMLINK_NOFOLLOW |
+                      FSPICK_NO_AUTOMOUNT |
+                      FSPICK_EMPTY_PATH)) != 0)
+               return -EINVAL;
+
+       lookup_flags = LOOKUP_FOLLOW | LOOKUP_AUTOMOUNT;
+       if (flags & FSPICK_SYMLINK_NOFOLLOW)
+               lookup_flags &= ~LOOKUP_FOLLOW;
+       if (flags & FSPICK_NO_AUTOMOUNT)
+               lookup_flags &= ~LOOKUP_AUTOMOUNT;
+       if (flags & FSPICK_EMPTY_PATH)
+               lookup_flags |= LOOKUP_EMPTY;
+       ret = user_path_at(dfd, path, lookup_flags, &target);
+       if (ret < 0)
+               goto err;
+
+       ret = -EINVAL;
+       if (target.mnt->mnt_root != target.dentry)
+               goto err_path;
+
+       fc = fs_context_for_reconfigure(target.dentry, 0, 0);
+       if (IS_ERR(fc)) {
+               ret = PTR_ERR(fc);
+               goto err_path;
+       }
+
+       fc->phase = FS_CONTEXT_RECONF_PARAMS;
+
+       ret = fscontext_alloc_log(fc);
+       if (ret < 0)
+               goto err_fc;
+
+       path_put(&target);
+       return fscontext_create_fd(fc, flags & FSPICK_CLOEXEC ? O_CLOEXEC : 0);
+
+err_fc:
+       put_fs_context(fc);
+err_path:
+       path_put(&target);
+err:
+       return ret;
+}
+
 /*
  * Check the state and apply the configuration.  Note that this function is
  * allowed to 'steal' the value by setting param->xxx to NULL before returning.
index 0e697f595278948d39fd3f0ebac27b3ea3cd7934..e2870fe1be5b7f7b4d0fd8fbd258c0fc5bc3b1a5 100644 (file)
@@ -993,6 +993,7 @@ asmlinkage long sys_fsopen(const char __user *fs_name, unsigned int flags);
 asmlinkage long sys_fsconfig(int fs_fd, unsigned int cmd, const char __user *key,
                             const void __user *value, int aux);
 asmlinkage long sys_fsmount(int fs_fd, unsigned int flags, unsigned int ms_flags);
+asmlinkage long sys_fspick(int dfd, const char __user *path, unsigned int flags);
 asmlinkage long sys_pidfd_send_signal(int pidfd, int sig,
                                       siginfo_t __user *info,
                                       unsigned int flags);
index 3888d3b91dc5035f86f3575e7760f387db1aa299..96a0240f23fed37be9430b72d2f2d9ffd6d42237 100644 (file)
  */
 #define FSOPEN_CLOEXEC         0x00000001
 
+/*
+ * fspick() flags.
+ */
+#define FSPICK_CLOEXEC         0x00000001
+#define FSPICK_SYMLINK_NOFOLLOW        0x00000002
+#define FSPICK_NO_AUTOMOUNT    0x00000004
+#define FSPICK_EMPTY_PATH      0x00000008
+
 /*
  * The type of fsconfig() call made.
  */