[PATCH 22/32] vfs: Provide an fspick() system call [ver #8]

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



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);
	write(fd, "o intr");
	write(fd, "o noac");
	write(fd, "x reconfigure");

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@xxxxxxxxxx>
---

 arch/x86/entry/syscalls/syscall_32.tbl |    1 
 arch/x86/entry/syscalls/syscall_64.tbl |    1 
 fs/fsopen.c                            |   94 +++++++++++++++++++++++++-------
 include/linux/syscalls.h               |    1 
 include/uapi/linux/fs.h                |    5 ++
 kernel/sys_ni.c                        |    1 
 6 files changed, 83 insertions(+), 20 deletions(-)

diff --git a/arch/x86/entry/syscalls/syscall_32.tbl b/arch/x86/entry/syscalls/syscall_32.tbl
index bdcb0c4a0491..b7e2adda092c 100644
--- a/arch/x86/entry/syscalls/syscall_32.tbl
+++ b/arch/x86/entry/syscalls/syscall_32.tbl
@@ -399,3 +399,4 @@
 385	i386	io_pgetevents		sys_io_pgetevents		__ia32_compat_sys_io_pgetevents
 386	i386	fsopen			sys_fsopen			__ia32_sys_fsopen
 387	i386	fsmount			sys_fsmount			__ia32_sys_fsmount
+388	i386	fspick			sys_fspick			__ia32_sys_fspick
diff --git a/arch/x86/entry/syscalls/syscall_64.tbl b/arch/x86/entry/syscalls/syscall_64.tbl
index 7d932d3897fa..fd322986974b 100644
--- a/arch/x86/entry/syscalls/syscall_64.tbl
+++ b/arch/x86/entry/syscalls/syscall_64.tbl
@@ -344,6 +344,7 @@
 333	common	io_pgetevents		__x64_sys_io_pgetevents
 334	common	fsopen			__x64_sys_fsopen
 335	common	fsmount			__x64_sys_fsmount
+336	common	fspick			__x64_sys_fspick
 
 #
 # x32-specific system call numbers start at 512 to avoid cache impact
diff --git a/fs/fsopen.c b/fs/fsopen.c
index 26565ddd7c9e..d69155b9303e 100644
--- a/fs/fsopen.c
+++ b/fs/fsopen.c
@@ -17,6 +17,7 @@
 #include <linux/magic.h>
 #include <linux/syscalls.h>
 #include <linux/security.h>
+#include <linux/namei.h>
 #include "mount.h"
 
 static struct vfsmount *fscontext_fs_mnt __read_mostly;
@@ -286,6 +287,36 @@ static int __init init_fscontext_fs(void)
 
 fs_initcall(init_fscontext_fs);
 
+/*
+ * Attach a filesystem context to a file and an fd.
+ */
+static int fsopen_create_fd(struct fs_context *fc, bool cloexec)
+{
+	struct file *file;
+	int ret;
+
+	file = create_fscontext_file(fc);
+	if (IS_ERR(file)) {
+		ret = PTR_ERR(file);
+		goto err_fc;
+	}
+
+	ret = get_unused_fd_flags(cloexec);
+	if (ret < 0)
+		goto err_file;
+
+	fd_install(ret, file);
+	return ret;
+
+err_fc:
+	put_fs_context(fc);
+	goto err;
+err_file:
+	fput(file);
+err:
+	return ret;
+}
+
 /*
  * Open a filesystem by name so that it can be configured for mounting.
  *
@@ -298,9 +329,7 @@ SYSCALL_DEFINE5(fsopen, const char __user *, _fs_name, unsigned int, flags,
 {
 	struct file_system_type *fs_type;
 	struct fs_context *fc;
-	struct file *file;
 	const char *fs_name;
-	int fd, ret;
 
 	if (!ns_capable(current->nsproxy->mnt_ns->user_ns, CAP_SYS_ADMIN))
 		return -EPERM;
@@ -324,29 +353,54 @@ SYSCALL_DEFINE5(fsopen, const char __user *, _fs_name, unsigned int, flags,
 
 	fc->phase = FS_CONTEXT_CREATE_PARAMS;
 
-	ret = -EOPNOTSUPP;
-	if (!fc->ops)
-		goto err_fc;
+	return fsopen_create_fd(fc, flags & FSOPEN_CLOEXEC);
+}
 
-	file = create_fscontext_file(fc);
-	if (IS_ERR(file)) {
-		ret = PTR_ERR(file);
-		goto err_fc;
-	}
+/*
+ * Pick a superblock into a context for reconfiguration.
+ */
+SYSCALL_DEFINE3(fspick, int, dfd, const char *, path, unsigned int, flags)
+{
+	struct fs_context *fc;
+	struct path target;
+	unsigned int lookup_flags;
+	int ret;
+
+	if ((flags & ~(FSPICK_CLOEXEC |
+		       FSPICK_SYMLINK_NOFOLLOW |
+		       FSPICK_NO_AUTOMOUNT |
+		       FSPICK_EMPTY_PATH)) != 0)
+		return -EINVAL;
 
-	ret = get_unused_fd_flags(flags & O_CLOEXEC);
+	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_file;
+		goto err;
+
+	ret = -EOPNOTSUPP;
+	if (!target.dentry->d_sb->s_op->reconfigure)
+		goto err;
+
+	fc = vfs_new_fs_context(target.dentry->d_sb->s_type, target.dentry,
+				0, FS_CONTEXT_FOR_RECONFIGURE);
+	if (IS_ERR(fc)) {
+		ret = PTR_ERR(fc);
+		goto err_path;
+	}
 
-	fd = ret;
-	fd_install(fd, file);
-	return fd;
+	fc->phase = FS_CONTEXT_RECONF_PARAMS;
 
-err_file:
-	fput(file);
-	return ret;
+	path_put(&target);
+	return fsopen_create_fd(fc, flags & FSPICK_CLOEXEC);
 
-err_fc:
-	put_fs_context(fc);
+err_path:
+	path_put(&target);
+err:
 	return ret;
 }
diff --git a/include/linux/syscalls.h b/include/linux/syscalls.h
index 178370cad1dd..5130fd687a85 100644
--- a/include/linux/syscalls.h
+++ b/include/linux/syscalls.h
@@ -900,6 +900,7 @@ asmlinkage long sys_fsopen(const char *fs_name, unsigned int flags,
 			   void *reserved3, void *reserved4, void *reserved5);
 asmlinkage long sys_fsmount(int fsfd, int dfd, const char *path, unsigned int at_flags,
 			    unsigned int flags);
+asmlinkage long sys_fspick(int dfd, const char *path, unsigned int at_flags);
 
 
 /*
diff --git a/include/uapi/linux/fs.h b/include/uapi/linux/fs.h
index edb1983a9990..f3875a84349d 100644
--- a/include/uapi/linux/fs.h
+++ b/include/uapi/linux/fs.h
@@ -345,4 +345,9 @@ typedef int __bitwise __kernel_rwf_t;
 
 #define FSMOUNT_CLOEXEC		0x00000001
 
+#define FSPICK_CLOEXEC		0x00000001
+#define FSPICK_SYMLINK_NOFOLLOW	0x00000002
+#define FSPICK_NO_AUTOMOUNT	0x00000004
+#define FSPICK_EMPTY_PATH	0x00000008
+
 #endif /* _UAPI_LINUX_FS_H */
diff --git a/kernel/sys_ni.c b/kernel/sys_ni.c
index 632a937ca09c..152fdc95d426 100644
--- a/kernel/sys_ni.c
+++ b/kernel/sys_ni.c
@@ -436,3 +436,4 @@ COND_SYSCALL(setuid16);
 /* fd-based mount */
 COND_SYSCALL(sys_fsopen);
 COND_SYSCALL(sys_fsmount);
+COND_SYSCALL(sys_fspick);




[Index of Archives]     [Linux Ext4 Filesystem]     [Union Filesystem]     [Filesystem Testing]     [Ceph Users]     [Ecryptfs]     [AutoFS]     [Kernel Newbies]     [Share Photos]     [Security]     [Netfilter]     [Bugtraq]     [Yosemite News]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux Cachefs]     [Reiser Filesystem]     [Linux RAID]     [Samba]     [Device Mapper]     [CEPH Development]

  Powered by Linux