VFS: Introduce filesystem context [ver #8]
Subsystems (100)
David Howells
maintainercover VFS: Introduce filesystem context [ver #8]
Hi Al,
Can you take a look at this please, in particular the last 6 patches?
Here are a set of patches to create a filesystem context prior to setting up a new mount, populating it with the parsed options/binary data, creating the superblock and then effecting the mount. This is also used for remount since much of the parsing stuff is common in many filesystems.
This allows namespaces and other information to be conveyed through the mount procedure.
This also allows Miklós Szeredi's idea of doing:
fd = fsopen("nfs");
write(fd, "option=val", ...);
mfd = fsmount(fd, MS_NODEV);
move_mount(mfd, "", AT_FDCWD, "/mnt", MOVE_MOUNT_F_EMPTY_PATH);that he presented at LSF-2017 to be implemented (see the relevant patches in the series).
I didn't use netlink as that would make the core kernel depend on CONFIG_NET and CONFIG_NETLINK and would introduce network namespacing issues.
I've implemented filesystem context handling for procfs, nfs, mqueue, cpuset, kernfs, sysfs, cgroup and afs filesystems.
Unconverted filesystems are handled by the legacy filesystem wrapper.
This post is mostly about the internal filesystem context and the special kernel interface filesystems. I've included the fsopen() and fsmount() syscall implementations for reference, but I expect these to undergo some reconsideration during LSF. The last five patches relate to the AFS conversion and are included as an example.
Significant changes:
ver #8:
(*) Changed the way fsmount() mounts into the namespace according to some
of Al's ideas.
(*) Put better typing on the fd cookie obtained from __fdget() & co..
(*) Stored the fd cookie in struct nameidata rather than the dfd number.
(*) Changed sys_fsmount() to return an O_PATH-style fd rather than
actually mounting into the mount namespace.
(*) Separated internal FMODE_* handling from O_* handling to free up
certain O_* flag numbers.
(*) Added two new open flags (O_CLONE_MOUNT and O_NON_RECURSIVE) for use
with open(O_PATH) to copy a mount or mount-subtree to an O_PATH fd.
(*) Added a new syscall, sys_move_mount(), to move a mount from an
dfd+path source to a dfd+path destination.
(*) Added a file->f_mode flag (FMODE_NEED_UNMOUNT) that indicates that the
vfsmount attached to file->f_path needs 'unmounting' if set.
(*) Made sys_move_mount() clear FMODE_NEED_UNMOUNT if successful.
[!] This doesn't work quite right.
(*) Added a new syscall, fsinfo(), to query information about a
filesystem. The idea being that this will, in future, work with the fd from fsopen() too and permit querying of the parameters and metadata before fsmount() is called.
ver #7:
(*) Undo an incorrect MS_* -> SB_* conversion.
(*) Pass the mount data buffer size to all the mount-related functions that
take the data pointer. This fixes a problem where someone (say SELinux) tries to copy the mount data, assuming it to be a page in size, and overruns the buffer - thereby incurring an oops by hitting a guard page.
(*) Made the AFS filesystem use them as an example. This is a much easier to
deal with than with NFS or Ext4 as there are very few mount options.
ver #6:
(*) Dropped the supplementary error string facility for the moment.
(*) Dropped the NFS patches for the moment.
(*) Dropped the reserved file descriptor argument from fsopen() and
replaced it with three reserved pointers that must be NULL.
ver #5:
(*) Renamed sb_config -> fs_context and adjusted variable names.
(*) Differentiated the flags in sb->s_flags (now named SB_*) from those
passed to mount(2) (named MS_*).
(*) Renamed __vfs_new_fs_context() to vfs_new_fs_context() and made the
caller always provide a struct file_system_type pointer and the parameters required.
(*) Got rid of vfs_submount_fc() in favour of passing
FS_CONTEXT_FOR_SUBMOUNT to vfs_new_fs_context(). The purpose is now used more.
(*) Call ->validate() on the remount path.
(*) Got rid of the inode locking in sys_fsmount().
(*) Call security_sb_mountpoint() in the mount(2) path.
ver #4:
(*) Split the sb_config patch up somewhat.
(*) Made the supplementary error string facility something attached to the
task_struct rather than the sb_config so that error messages can be obtained from NFS doing a mount-root-and-pathwalk inside the nfs_get_tree() operation.
Further, made this managed and read by prctl rather than through the mount fd so that it's more generally available.
ver #3:
(*) Rebased on 4.12-rc1.
(*) Split the NFS patch up somewhat.
ver #2:
(*) Removed the ->fill_super() from sb_config_operations and passed it in
directly to functions that want to call it. NFS now calls nfs_fill_super() directly rather than jumping through a pointer to it since there's only the one option at the moment.
(*) Removed ->mnt_ns and ->sb from sb_config and moved ->pid_ns into
proc_sb_config.
(*) Renamed create_super -> get_tree.
(*) Renamed struct mount_context to struct sb_config and amended various
variable names.
(*) sys_fsmount() acquired AT_* flags and MS_* flags (for MNT_* flags)
arguments.
ver #1:
(*) Split the sb_config stuff out into its own header.
(*) Support non-context aware filesystems through a special set of
sb_config operations.
(*) Stored the created superblock and root dentry into the sb_config after
creation rather than directly into a vfsmount. This allows some arguments to be removed to various NFS functions.
(*) Added an explicit superblock-creation step. This allows a created
superblock to then be mounted multiple times.
(*) Added a flag to say that the sb_config is degraded and cannot have
another go at having a superblock creation whilst getting rid of the one that says it's already mounted.
Possible further developments:
(*) Implement sb reconfiguration (for now it returns ENOANO).
(*) Implement mount context support in more filesystems, ext4 being next
on my list.
(*) Move the walk-from-root stuff that nfs has to generic code so that you
can do something akin to:
mount /dev/sda1:/foo/bar /mnt
See nfs_follow_remote_path() and mount_subtree(). This is slightly tricky in NFS as we have to prevent referral loops.
(*) Work out how to get at the error message incurred by submounts
encountered during nfs_follow_remote_path().
Should the error message be moved to task_struct and made more general, perhaps retrieved with a prctl() function?
(*) Clean up/consolidate the security functions. Possibly add a
validation hook to be called at the same time as the mount context validate op.
The patches can be found here also:
http://git.kernel.org/cgit/linux/kernel/git/dhowells/linux-fs.git/log/?h=mount-context
David
---
David Howells (32):
VFS: Suppress MS_* flag defs within the kernel unless explicitly enabled
vfs: Provide documentation for new mount API
VFS: Introduce the basic header for the new mount API's filesystem context
VFS: Add LSM hooks for the new mount API
selinux: Implement the new mount API LSM hooks
smack: Implement filesystem context security hooks
apparmor: Implement security hooks for the new mount API
tomoyo: Implement security hooks for the new mount API
VFS: Require specification of size of mount data for internal mounts
VFS: Implement a filesystem superblock creation/configuration context
VFS: Remove unused code after filesystem context changes
procfs: Move proc_fill_super() to fs/proc/root.c
proc: Add fs_context support to procfs
ipc: Convert mqueue fs to fs_context
cpuset: Use fs_context
kernfs, sysfs, cgroup, intel_rdt: Support fs_context
hugetlbfs: Convert to fs_context
VFS: Remove kern_mount_data()
VFS: Implement fsopen() to prepare for a mount
vfs: Make close() unmount the attached mount if so flagged
VFS: Implement fsmount() to effect a pre-configured mount
vfs: Provide an fspick() system call
VFS: Implement logging through fs_context
vfs: Add some logging to the core users of the fs_context log
afs: Add fs_context support
afs: Use fs_context to pass parameters over automount
vfs: Use a 'struct fd_cookie *' type for light fd handling
vfs: Store the fd_cookie in nameidata, not the dfd int
vfs: Don't mix FMODE_* flags with O_* flags
vfs: Allow cloning of a mount tree with open(O_PATH|O_CLONE_MOUNT) [RFC] fs: Add a move_mount() system call
[RFC] fsinfo: Add a system call to allow querying of filesystem information
Documentation/filesystems/mounting.txt | 458 +++++++++++++ arch/arc/kernel/setup.c | 1 arch/arm/kernel/atags_parse.c | 1 arch/ia64/kernel/perfmon.c | 3 arch/powerpc/platforms/cell/spufs/inode.c | 6 arch/s390/hypfs/inode.c | 7 arch/sh/kernel/setup.c | 1 arch/sparc/kernel/setup_32.c | 1 arch/sparc/kernel/setup_64.c | 1 arch/x86/entry/syscalls/syscall_32.tbl | 5 arch/x86/entry/syscalls/syscall_64.tbl | 5 arch/x86/kernel/cpu/intel_rdt_rdtgroup.c | 129 ++-- arch/x86/kernel/setup.c | 1 drivers/base/devtmpfs.c | 7 drivers/dax/super.c | 2 drivers/dma-buf/dma-buf.c | 2 drivers/dma-buf/sync_file.c | 2 drivers/gpu/drm/drm_drv.c | 3 drivers/gpu/drm/drm_syncobj.c | 2 drivers/gpu/drm/i915/i915_gemfs.c | 2 drivers/infiniband/hw/qib/qib_fs.c | 7 drivers/misc/ibmasm/ibmasmfs.c | 11 drivers/mtd/mtdsuper.c | 26 - drivers/oprofile/oprofilefs.c | 8 .../staging/lustre/lustre/llite/llite_internal.h | 2 drivers/staging/lustre/lustre/llite/llite_lib.c | 3 drivers/staging/lustre/lustre/mdc/mdc_lib.c | 2 drivers/staging/lustre/lustre/mdc/mdc_locks.c | 2 drivers/staging/lustre/lustre/obdclass/obd_mount.c | 7 drivers/staging/ncpfs/inode.c | 10 drivers/tty/pty.c | 4 drivers/usb/gadget/function/f_fs.c | 7 drivers/usb/gadget/legacy/inode.c | 7 drivers/virtio/virtio_balloon.c | 2 drivers/xen/xenfs/super.c | 7 fs/9p/vfs_super.c | 2 fs/Makefile | 3 fs/adfs/super.c | 9 fs/affs/super.c | 13 fs/afs/internal.h | 9 fs/afs/mntpt.c | 147 ++-- fs/afs/super.c | 423 ++++++------ fs/afs/volume.c | 4 fs/aio.c | 3 fs/anon_inodes.c | 23 - fs/autofs4/autofs_i.h | 2 fs/autofs4/dev-ioctl.c | 2 fs/autofs4/init.c | 4 fs/autofs4/inode.c | 3 fs/befs/linuxvfs.c | 11 fs/bfs/inode.c | 8 fs/binfmt_misc.c | 7 fs/block_dev.c | 2 fs/btrfs/super.c | 30 + fs/btrfs/tests/btrfs-tests.c | 2 fs/cachefiles/rdwr.c | 2 fs/ceph/super.c | 3 fs/cifs/cifs_dfs_ref.c | 3 fs/cifs/cifsfs.c | 5 fs/coda/inode.c | 11 fs/configfs/mount.c | 7 fs/cramfs/inode.c | 17 fs/debugfs/inode.c | 14 fs/devpts/inode.c | 10 fs/ecryptfs/main.c | 2 fs/efivarfs/super.c | 9 fs/efs/super.c | 14 fs/eventfd.c | 2 fs/eventpoll.c | 2 fs/exec.c | 6 fs/exofs/super.c | 7 fs/exportfs/expfs.c | 2 fs/ext2/super.c | 14 fs/ext4/super.c | 16 fs/f2fs/super.c | 13 fs/fat/inode.c | 3 fs/fat/namei_msdos.c | 8 fs/fat/namei_vfat.c | 8 fs/fcntl.c | 6 fs/file.c | 20 - fs/file_table.c | 4 fs/freevxfs/vxfs_super.c | 12 fs/fs_context.c | 689 ++++++++++++++++++++ fs/fsopen.c | 477 ++++++++++++++ fs/fuse/control.c | 9 fs/fuse/inode.c | 16 fs/gfs2/ops_fstype.c | 6 fs/gfs2/super.c | 4 fs/hfs/super.c | 12 fs/hfsplus/super.c | 12 fs/hostfs/hostfs_kern.c | 7 fs/hpfs/super.c | 11 fs/hugetlbfs/inode.c | 337 ++++++---- fs/internal.h | 10 fs/isofs/inode.c | 11 fs/jffs2/super.c | 10 fs/jfs/super.c | 11 fs/kernfs/mount.c | 88 +-- fs/libfs.c | 17 fs/minix/inode.c | 14 fs/namei.c | 105 ++- fs/namespace.c | 650 +++++++++++++++---- fs/nfs/dir.c | 15 fs/nfs/internal.h | 4 fs/nfs/namespace.c | 3 fs/nfs/nfs4namespace.c | 3 fs/nfs/nfs4proc.c | 9 fs/nfs/nfs4super.c | 27 - fs/nfs/super.c | 22 - fs/nfsd/nfsctl.c | 8 fs/nilfs2/super.c | 10 fs/notify/fanotify/fanotify_user.c | 10 fs/notify/inotify/inotify_user.c | 2 fs/nsfs.c | 5 fs/ntfs/super.c | 13 fs/ocfs2/dlmfs/dlmfs.c | 5 fs/ocfs2/super.c | 14 fs/omfs/inode.c | 9 fs/open.c | 31 + fs/openpromfs/inode.c | 11 fs/orangefs/orangefs-kernel.h | 2 fs/orangefs/super.c | 5 fs/overlayfs/super.c | 11 fs/pipe.c | 3 fs/pnode.c | 1 fs/proc/inode.c | 50 - fs/proc/internal.h | 6 fs/proc/root.c | 212 +++++- fs/pstore/inode.c | 10 fs/qnx4/inode.c | 14 fs/qnx6/inode.c | 14 fs/ramfs/inode.c | 6 fs/reiserfs/super.c | 14 fs/romfs/super.c | 13 fs/signalfd.c | 3 fs/squashfs/super.c | 12 fs/statfs.c | 431 +++++++++++++ fs/super.c | 402 +++++++++--- fs/sysfs/mount.c | 64 +- fs/sysv/inode.c | 3 fs/sysv/super.c | 16 fs/timerfd.c | 2 fs/tracefs/inode.c | 10 fs/ubifs/super.c | 5 fs/udf/super.c | 16 fs/ufs/super.c | 11 fs/xfs/xfs_ioctl.c | 2 fs/xfs/xfs_super.c | 10 include/linux/anon_inodes.h | 6 include/linux/cgroup.h | 3 include/linux/debugfs.h | 8 include/linux/fcntl.h | 3 include/linux/file.h | 31 + include/linux/fs.h | 73 +- include/linux/fs_context.h | 178 +++++ include/linux/fsinfo.h | 25 + include/linux/fsnotify.h | 8 include/linux/kernfs.h | 36 + include/linux/lsm_hooks.h | 89 ++- include/linux/mount.h | 8 include/linux/mtd/super.h | 4 include/linux/nfs_fs.h | 3 include/linux/ramfs.h | 4 include/linux/security.h | 74 ++ include/linux/shmem_fs.h | 3 include/linux/syscalls.h | 11 include/uapi/asm-generic/fcntl.h | 9 include/uapi/linux/fs.h | 68 -- include/uapi/linux/fsinfo.h | 231 +++++++ include/uapi/linux/magic.h | 1 include/uapi/linux/mount.h | 69 ++ init/do_mounts.c | 5 init/do_mounts_initrd.c | 1 ipc/mqueue.c | 126 +++- kernel/bpf/inode.c | 7 kernel/bpf/syscall.c | 6 kernel/cgroup/cgroup-internal.h | 42 + kernel/cgroup/cgroup-v1.c | 296 ++++----- kernel/cgroup/cgroup.c | 224 ++++--- kernel/cgroup/cpuset.c | 65 ++ kernel/events/core.c | 2 kernel/sys_ni.c | 6 kernel/trace/trace.c | 7 mm/shmem.c | 10 mm/zsmalloc.c | 3 net/socket.c | 3 net/sunrpc/rpc_pipe.c | 7 net/unix/af_unix.c | 2 samples/statx/Makefile | 5 samples/statx/test-fsinfo.c | 179 +++++ security/apparmor/apparmorfs.c | 8 security/apparmor/file.c | 2 security/apparmor/include/mount.h | 11 security/apparmor/lsm.c | 84 ++ security/apparmor/mount.c | 47 + security/inode.c | 7 security/keys/big_key.c | 2 security/security.c | 70 ++ security/selinux/hooks.c | 294 ++++++++- security/selinux/selinuxfs.c | 8 security/smack/smack_lsm.c | 344 +++++++++- security/smack/smackfs.c | 9 security/tomoyo/common.h | 3 security/tomoyo/mount.c | 46 + security/tomoyo/tomoyo.c | 19 + 205 files changed, 6775 insertions(+), 1836 deletions(-) create mode 100644 Documentation/filesystems/mounting.txt create mode 100644 fs/fs_context.c create mode 100644 fs/fsopen.c create mode 100644 include/linux/fs_context.h create mode 100644 include/linux/fsinfo.h create mode 100644 include/uapi/linux/fsinfo.h create mode 100644 include/uapi/linux/mount.h create mode 100644 samples/statx/test-fsinfo.c
David Howells
maintainerPATCH 1/32 VFS: Suppress MS_* flag defs within the kernel unless explicitly enabled [ver #8]
Only the mount namespace code that implements mount(2) should be using the MS_* flags. Suppress them inside the kernel unless uapi/linux/mount.h is included.
---
arch/arc/kernel/setup.c | 1 + arch/arm/kernel/atags_parse.c | 1 + arch/sh/kernel/setup.c | 1 + arch/sparc/kernel/setup_32.c | 1 + arch/sparc/kernel/setup_64.c | 1 + arch/x86/kernel/setup.c | 1 + drivers/base/devtmpfs.c | 1 + fs/f2fs/super.c | 2 + fs/namespace.c | 1 + fs/pnode.c | 1 + fs/super.c | 1 + include/uapi/linux/fs.h | 56 ++++------------------------------------ include/uapi/linux/mount.h | 58 +++++++++++++++++++++++++++++++++++++++++ init/do_mounts.c | 1 + init/do_mounts_initrd.c | 1 + security/apparmor/lsm.c | 1 + security/apparmor/mount.c | 1 + security/selinux/hooks.c | 1 + security/tomoyo/mount.c | 1 + 19 files changed, 80 insertions(+), 52 deletions(-) create mode 100644 include/uapi/linux/mount.h
arch/arc/kernel/setup.c +1 -0
@@ -19,6 +19,7 @@#include <linux/of_fdt.h> #include <linux/of.h> #include <linux/cache.h> +#include <uapi/linux/mount.h> #include <asm/sections.h> #include <asm/arcregs.h> #include <asm/tlb.h>
arch/arm/kernel/atags_parse.c +1 -0
@@ -24,6 +24,7 @@#include <linux/root_dev.h> #include <linux/screen_info.h> #include <linux/memblock.h> +#include <uapi/linux/mount.h> #include <asm/setup.h> #include <asm/system_info.h>
arch/sh/kernel/setup.c +1 -0
@@ -32,6 +32,7 @@#include <linux/of.h> #include <linux/of_fdt.h> #include <linux/uaccess.h> +#include <uapi/linux/mount.h> #include <asm/io.h> #include <asm/page.h> #include <asm/elf.h>
arch/sparc/kernel/setup_32.c +1 -0
@@ -34,6 +34,7 @@#include <linux/kdebug.h> #include <linux/export.h> #include <linux/start_kernel.h> +#include <uapi/linux/mount.h> #include <asm/io.h> #include <asm/processor.h>
arch/sparc/kernel/setup_64.c +1 -0
@@ -33,6 +33,7 @@#include <linux/module.h> #include <linux/start_kernel.h> #include <linux/bootmem.h> +#include <uapi/linux/mount.h> #include <asm/io.h> #include <asm/processor.h>
arch/x86/kernel/setup.c +1 -0
@@ -51,6 +51,7 @@#include <linux/kvm_para.h> #include <linux/dma-contiguous.h> #include <xen/xen.h> +#include <uapi/linux/mount.h> #include <linux/errno.h> #include <linux/kernel.h>
drivers/base/devtmpfs.c +1 -0
@@ -25,6 +25,7 @@#include <linux/sched.h> #include <linux/slab.h> #include <linux/kthread.h> +#include <uapi/linux/mount.h> #include "base.h" static struct task_struct *thread;
fs/f2fs/super.c +1 -1
@@ -1450,7 +1450,7 @@ static int f2fs_remount(struct super_block *sb, int *flags, char *data) err =dquot_suspend (sb,-1 );if (err <0 ) goto restore_opts; - }else if (f2fs_readonly (sb) && !(*flags &MS_RDONLY )) { + }else if (f2fs_readonly (sb) && !(*flags &SB_RDONLY )) {/* dquot_resume needs RW */ sb->s_flags &= ~SB_RDONLY ;if (sb_any_quota_suspended (sb)) {
fs/namespace.c +1 -0
@@ -26,6 +26,7 @@#include <linux/bootmem.h> #include <linux/task_work.h> #include <linux/sched/task.h> +#include <uapi/linux/mount.h> #include "pnode.h" #include "internal.h"
fs/pnode.c +1 -0
@@ -10,6 +10,7 @@#include <linux/mount.h> #include <linux/fs.h> #include <linux/nsproxy.h> +#include <uapi/linux/mount.h> #include "internal.h" #include "pnode.h"
fs/super.c +1 -0
@@ -35,6 +35,7 @@#include <linux/fsnotify.h> #include <linux/lockdep.h> #include <linux/user_namespace.h> +#include <uapi/linux/mount.h> #include "internal.h" static int thaw_super_locked (struct super_block *sb);
include/uapi/linux/fs.h +5 -51
68 lines not on this page · raw message
include/uapi/linux/mount.h new file +58 -0
58 lines not on this page · raw message
init/do_mounts.c +1 -0
@@ -32,6 +32,7 @@#include <linux/nfs_fs.h> #include <linux/nfs_fs_sb.h> #include <linux/nfs_mount.h> +#include <uapi/linux/mount.h> #include "do_mounts.h"
init/do_mounts_initrd.c +1 -0
@@ -18,6 +18,7 @@#include <linux/sched.h> #include <linux/freezer.h> #include <linux/kmod.h> +#include <uapi/linux/mount.h> #include "do_mounts.h"
security/apparmor/lsm.c +1 -0
@@ -24,6 +24,7 @@#include <linux/audit.h> #include <linux/user_namespace.h> #include <net/sock.h> +#include <uapi/linux/mount.h> #include "include/apparmor.h" #include "include/apparmorfs.h"
security/apparmor/mount.c +1 -0
@@ -15,6 +15,7 @@#include <linux/fs.h> #include <linux/mount.h> #include <linux/namei.h> +#include <uapi/linux/mount.h> #include "include/apparmor.h" #include "include/audit.h"
security/selinux/hooks.c +1 -0
@@ -88,6 +88,7 @@#include <linux/msg.h> #include <linux/shm.h> #include <linux/bpf.h> +#include <uapi/linux/mount.h> #include "avc.h" #include "objsec.h"
security/tomoyo/mount.c +1 -0
@@ -6,6 +6,7 @@*/ #include <linux/slab.h> +#include <uapi/linux/mount.h> #include "common.h" /* String table for special mount operations. */
David Howells
maintainerPATCH 2/32 vfs: Provide documentation for new mount API [ver #8]
In reply to David HowellsProvide documentation for the new mount API.
---
Documentation/filesystems/mounting.txt | 458 ++++++++++++++++++++++++++++++++ 1 file changed, 458 insertions(+) create mode 100644 Documentation/filesystems/mounting.txt
Documentation/filesystems/mounting.txt new file +458 -0
@@ -0,0 +1,458 @@ + =================== + FILESYSTEM MOUNTING + =================== + +CONTENTS + + (1) Overview. + + (2) The filesystem context. + + (3) The filesystem context operations. + + (4) Filesystem context security. + + (5) VFS filesystem context operations. + + +======== +OVERVIEW +======== + +The creation of new mounts is now to be done in a multistep process: + + (1) Create a filesystem context. + + (2) Parse the options and attach them to the context. Options may be passed + individually from userspace. + + (3) Validate and pre-process the context. + + (4) Get or create a superblock and mountable root. + + (5) Perform the mount. + + (6) Return an error message attached to the context. + + (7) Destroy the context. + +To support this, the file_system_type struct gains two new fields: + + unsigned short fs_context_size; + +which indicates the total amount of space that should be allocated for context +data (see the Filesystem Context section), and: + + int (*init_fs_context)(struct fs_context *fc, struct super_block *src_sb); + +which is invoked to set up the filesystem-specific parts of a filesystem +context, including the additional space. The src_sb parameter is used to +convey the superblock from which the filesystem may draw extra information +(such as namespaces) for submount (FS_CONTEXT_FOR_SUBMOUNT) or reconfiguration +(FS_CONTEXT_FOR_RECONFIGURE) purposes - otherwise it will be NULL. + +Note that security initialisation is done *after* the filesystem is called so +that the namespaces may be adjusted first. + +And the super_operations struct gains one field: + + int (*reconfigure) (struct super_block *, struct fs_context *); + +This shadows the ->reconfigure() operation and takes a prepared filesystem +context instead of the mount flags and data page. It may modify the sb_flags +in the context for the caller to pick up. + +[NOTE] reconfigure is intended as a replacement for remount_fs. + + +====================== +THE FILESYSTEM CONTEXT +====================== + +The creation and reconfiguration of a superblock is governed by a filesystem +context. This is represented by the fs_context structure: + + struct fs_context { + const struct fs_context_operations *ops; + struct file_system_type *fs; + struct dentry *root; + struct user_namespace *user_ns; + struct net *net_ns; + const struct cred *cred; + char *source; + char *subtype; + void *security; + void *s_fs_info; + unsigned int sb_flags; + bool sloppy; + bool silent; + bool degraded; + bool drop_sb; + enum fs_context_purpose purpose : 8; + }; + +When the VFS creates this, it allocates ->fs_context_size bytes (as specified +by the file_system_type object) to hold both the fs_context struct and any +extra data required by the filesystem. The fs_context struct is placed at the +beginning of this space. Any extra space beyond that is for use by the +filesystem. The filesystem should wrap the struct in one of its own, e.g.: + + struct nfs_fs_context { + struct fs_context fc; + ... + }; + +placing the fs_context struct first. container_of() can then be used. The +file_system_type would be initialised thus: + + struct file_system_type nfs = { + ... + .fs_context_size = sizeof(struct nfs_fs_context), + .init_fs_context = nfs_init_fs_context, + ... + }; + +The fs_context fields are as follows: + + (*) const struct fs_context_operations *ops + + These are operations that can be done on a filesystem context (see + below). This must be set by the ->init_fs_context() file_system_type + operation. + + (*) struct file_system_type *fs + + A pointer to the file_system_type of the filesystem that is being + constructed or reconfigured. This retains a reference on the type owner. + + (*) struct dentry *root + + A pointer to the root of the mountable tree (and indirectly, the + superblock thereof). This is filled in by the ->get_tree() op. + + (*) struct user_namespace *user_ns + (*) struct net *net_ns + + There are a subset of the namespaces in use by the invoking process. They + retain references on each namespace. The subscribed namespaces may be + replaced by the filesystem to reflect other sources, such as the parent + mount superblock on an automount. + + (*) struct cred *cred + + The mounter's credentials. This retains a reference on the credentials. + + (*) char *source + + This specifies the source. It may be a block device (e.g. /dev/sda1) or + something more exotic, such as the "host:/path" that NFS desires. + + (*) char *subtype + + This is a string to be added to the type displayed in /proc/mounts to + qualify it (used by FUSE). This is available for the filesystem to set if + desired. + + (*) void *security + + A place for the LSMs to hang their security data for the superblock. The + relevant security operations are described below. + + (*) void *s_fs_info + + The proposed s_fs_info for a new superblock, set in the superblock by + sget_fc(). This can be used to distinguish superblocks. + + (*) unsigned int sb_flags + + This holds the SB_* flags to be set in super_block::s_flags. + + (*) bool sloppy + (*) bool silent + + These are set if the sloppy or silent mount options are given. + + [NOTE] sloppy is probably unnecessary when userspace passes over one + option at a time since the error can just be ignored if userspace deems it + to be unimportant. + + [NOTE] silent is probably redundant with sb_flags & SB_SILENT. + + (*) bool degraded + + This is set if any preallocated resources in the context have been used + up, thereby rendering it unreusable for the ->get_tree() op. + + (*) bool drop_sb + + This is set if a superblock reference needs to be deactivated when the + context is put. + + (*) enum fs_context_purpose + + This indicates the purpose for which the context is intended. The + available values are: + + FS_CONTEXT_FOR_USER_MOUNT, -- New superblock for user-specified mount + FS_CONTEXT_FOR_KERNEL_MOUNT, -- New superblock for kernel-internal mount + FS_CONTEXT_FOR_SUBMOUNT -- New automatic submount of extant mount + FS_CONTEXT_FOR_RECONFIGURE -- Change an existing mount + +The mount context is created by calling vfs_new_fs_context(), vfs_sb_reconfig() +or vfs_dup_fs_context() and is destroyed with put_fs_context(). Note that the +structure is not refcounted. + +VFS, security and filesystem mount options are set individually with +vfs_parse_mount_option(). Options provided by the old mount(2) system call as +a page of data can be parsed with generic_parse_monolithic(). + +When mounting, the filesystem is allowed to take data from any of the pointers +and attach it to the superblock (or whatever), provided it clears the pointer +in the mount context. + +The filesystem is also allowed to allocate resources and pin them with the +mount context. For instance, NFS might pin the appropriate protocol version +module. + + +================================= +THE FILESYSTEM CONTEXT OPERATIONS +================================= + +The filesystem context points to a table of operations: + + struct fs_context_operations { + void (*free)(struct fs_context *fc); + int (*dup)(struct fs_context *fc, struct fs_context *src_fc); + int (*parse_source)(struct fs_context *fc, char *source); + int (*parse_option)(struct fs_context *fc, char *opt, size_t len); + int (*parse_monolithic)(struct fs_context *fc, void *data); + int (*validate)(struct fs_context *fc); + int (*get_tree)(struct fs_context *fc); + }; + +These operations are invoked by the various stages of the mount procedure to +manage the filesystem context. They are as follows: + + (*) void (*free)(struct fs_context *fc); + + Called to clean up the filesystem-specific part of the filesystem context + when the context is destroyed. It should be aware that parts of the + context may have been removed and NULL'd out by ->get_tree(). + + (*) int (*dup)(struct fs_context *fc, struct fs_context *src_fc); + + Called when a filesystem context has been duplicated to get any refs or + copy any non-referenced resources held in the filesystem-specific part of + the filesystem context. An error may be returned to indicate failure to + do this. + + [!] Note that even if this fails, put_fs_context() will be called + immediately thereafter, so ->dup() *must* make the + filesystem-specific part safe for ->free(). + + (*) int (*parse_source)(struct fs_context *fc, char *p); + + Called when a source or device is specified for a filesystem context. + This may be called multiple times if the filesystem supports it. If + successful, 0 should be returned or a negative error code otherwise. + + (*) int (*parse_option)(struct fs_context *fc, char *p); + + Called when an option is to be added to the filesystem context. p points + to the option string, likely in "key[=val]" format. VFS-specific options + will have been weeded out and fc->sb_flags updated in the context. + Security options will also have been weeded out and fc->security updated. + + If successful, 0 should be returned or a negative error code otherwise. + + (*) int (*parse_monolithic)(struct fs_context *fc, void *data); + + Called when the mount(2) system call is invoked to pass the entire data + page in one go. If this is expected to be just a list of "key[=val]" + items separated by commas, then this may be set to NULL. + + The return value is as for ->parse_option(). + + If the filesystem (e.g. NFS) needs to examine the data first and then + finds it's the standard key-val list then it may pass it off to + generic_parse_monolithic(). + + (*) int (*validate)(struct fs_context *fc); + + Called when all the options have been applied and the mount is about to + take place. It is should check for inconsistencies from mount options and + it is also allowed to do preliminary resource acquisition. For instance, + the core NFS module could load the NFS protocol module here. + + Note that if fc->purpose == FS_CONTEXT_FOR_RECONFIGURE, some of the + options necessary for a new mount may not be set. + + The return value is as for ->parse_option(). + + (*) int (*get_tree)(struct fs_context *fc); + + Called to get or create the mountable root and superblock, using the + information stored in the filesystem context (reconfiguration goes via a + different vector). It may detach any resources it desires from the + filesystem context and transfer them to the superblock it creates. + + On success it should set fc->root to the mountable root and return 0. In + the case of an error, it should return a negative error code. + + +=========================== +FILESYSTEM CONTEXT SECURITY +=========================== + +The filesystem context contains a security pointer that the LSMs can use for +building up a security context for the superblock to be mounted. There are a +number of operations used by the new mount code for this purpose: + + (*) int security_fs_context_alloc(struct fs_context *fc, + struct super_block *src_sb); + + Called to initialise fc->security (which is preset to NULL) and allocate + any resources needed. It should return 0 on success or a negative error + code on failure. + + src_sb will be non-NULL if the context is being created for superblock + reconfiguration (FS_CONTEXT_FOR_RECONFIGURE) in which case it indicates + the superblock to be reconfigured. It will also be non-NULL in the case + of a submount (FS_CONTEXT_FOR_SUBMOUNT) in which case it indicates the + parent superblock. + + (*) int security_fs_context_dup(struct fs_context *fc, + struct fs_context *src_fc); + + Called to initialise fc->security (which is preset to NULL) and allocate + any resources needed. The original filesystem context is pointed to by + src_fc and may be used for reference. It should return 0 on success or a + negative error code on failure. + + (*) void security_fs_context_free(struct fs_context *fc); + + Called to clean up anything attached to fc->security. Note that the + contents may have been transferred to a superblock and the pointer cleared + during get_tree. + + (*) int security_fs_context_parse_source(struct fs_context *fc, char *src); + + Called for each source (there may be more than one if the filesystem + supports it). The arguments are as for the ->parse_source() method. It + should return 0 on success or a negative error code on failure. + + (*) int security_fs_context_parse_option(struct fs_context *fc, char *opt); + + Called for each mount option. The arguments are as for the + ->parse_option() method. It should return 0 to indicate that the option + should be passed on to the filesystem, 1 to indicate that the option + should be discarded or an error to indicate that the option should be + rejected. + + The buffer pointed to by opt may be modified. + + (*) int security_fs_context_validate(struct fs_context *fc); + + Called after all the options have been parsed to validate the collection + as a whole and to do any necessary allocation so that + security_sb_get_tree() is less likely to fail. It should return 0 or a + negative error code. + + (*) int security_sb_get_tree(struct fs_context *fc); + + Called during the mount procedure to verify that the specified superblock + is allowed to be mounted and to transfer the security data there. It + should return 0 or a negative error code. + + (*) int security_sb_mountpoint(struct fs_context *fc, struct path *mountpoint); + + Called during the mount procedure to verify that the root dentry attached + to the context is permitted to be attached to the specified mountpoint. + It should return 0 on success or a negative error code on failure. + + +================================= +VFS FILESYSTEM CONTEXT OPERATIONS +================================= + +There are four operations for creating a filesystem context and +one for destroying a context: + + (*) struct fs_context *vfs_new_fs_context(struct file_system_type *fs_type, + struct super_block *src_sb, + unsigned int sb_flags); + + Create a filesystem context for a given filesystem type. This allocates + the filesystem context, sets the flags, initialises the security and calls + fs_type->init_fs_context() to initialise the filesystem context. + + src_sb can be NULL or it may indicate a superblock that is going to be + reconfigured (FS_CONTEXT_FOR_RECONFIGURE) or a superblock that is the + parent of a submount (FS_CONTEXT_FOR_SUBMOUNT). This superblock is + provided as a source of namespace information. + + (*) struct fs_context *vfs_sb_reconfigure(struct vfsmount *mnt, + unsigned int sb_flags); + + Create a filesystem context from the same filesystem as an extant mount + and initialise the mount parameters from the superblock underlying that + mount. This is for use by superblock parameter reconfiguration. + + (*) struct fs_context *vfs_dup_fs_context(struct fs_context *src_fc); + + Duplicate a filesystem context, copying any options noted and duplicating + or additionally referencing any resources held therein. This is available + for use where a filesystem has to get a mount within a mount, such as NFS4 + does by internally mounting the root of the target server and then doing a + private pathwalk to the target directory. + + (*) void put_fs_context(struct fs_context *fc); + + Destroy a filesystem context, releasing any resources it holds. This + calls the ->free() operation. This is intended to be called by anyone who + created a filesystem context. + + [!] filesystem contexts are not refcounted, so this causes unconditional + destruction. + +In all the above operations, apart from the put op, the return is a mount +context pointer or a negative error code. + +For the remaining operations, if an error occurs, a negative error code will be +returned. + + (*) int vfs_get_tree(struct fs_context *fc); + + Get or create the mountable root and superblock, using the parameters in + the filesystem context to select/configure the superblock. This invokes + the ->validate() op and then the ->get_tree() op. + + [NOTE] ->validate() could perhaps be rolled into ->get_tree() and + ->reconfigure(). + + (*) struct vfsmount *vfs_create_mount(struct fs_context *fc); + + Create a mount given the parameters in the specified filesystem context. + Note that this does not attach the mount to anything. + + (*) int vfs_set_fs_source(struct fs_context *fc, char *source); + + Supply one or more source names or device names for the mount. This may + cause the filesystem to access the source. Multiple sources may be + specified if the filesystem supports it. + + (*) int vfs_parse_fs_option(struct fs_context *fc, char *data); + + Supply a single mount option to the filesystem context. The mount option + should likely be in a "key[=val]" string form. The option is first + checked to see if it corresponds to a standard mount flag (in which case + it is used to set an SB_xxx flag and consumed) or a security option (in + which case the LSM consumes it) before it is passed on to the filesystem. + + (*) int generic_parse_monolithic(struct fs_context *fc, void *data); + + Parse a sys_mount() data page, assuming the form to be a text list + consisting of key[=val] options separated by commas. Each item in the + list is passed to vfs_mount_option(). This is the default when the + ->parse_monolithic() operation is NULL.
David Howells
maintainerPATCH 3/32 VFS: Introduce the basic header for the new mount API's filesystem context [ver #8]
In reply to David HowellsIntroduce a filesystem context concept to be used during superblock creation for mount and superblock reconfiguration for remount. This is allocated at the beginning of the mount procedure and into it is placed:
(1) Filesystem type.
(2) Namespaces.
(3) Source/Device names (there may be multiple).
(4) Superblock flags (SB_*).
(5) Security details.
(6) Filesystem-specific data, as set by the mount options.
---
include/linux/fs_context.h | 75 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 75 insertions(+) create mode 100644 include/linux/fs_context.h
include/linux/fs_context.h new file +75 -0
@@ -0,0 +1,75 @@ +/* Filesystem superblock creation and reconfiguration context. +* +* Copyright (C) 2018 Red Hat, Inc. All Rights Reserved. +* Written by David Howells ([email protected]) +* +* This program is free software; you can redistribute it and/or +* modify it under the terms of the GNU General Public Licence +* as published by the Free Software Foundation; either version +* 2 of the Licence, or (at your option) any later version. +*/ + +#ifndef _LINUX_FS_CONTEXT_H +#define _LINUX_FS_CONTEXT_H + +#include <linux/kernel.h> +#include <linux/errno.h> + +struct cred ; +struct dentry ; +struct file_operations ; +struct file_system_type ; +struct mnt_namespace ; +struct net ; +struct pid_namespace ; +struct super_block ; +struct user_namespace ; +struct vfsmount ; + +enum fs_context_purpose { +FS_CONTEXT_FOR_USER_MOUNT ,/* New superblock for user-specified mount */ +FS_CONTEXT_FOR_KERNEL_MOUNT ,/* New superblock for kernel-internal mount */ +FS_CONTEXT_FOR_SUBMOUNT ,/* New superblock for automatic submount */ +FS_CONTEXT_FOR_RECONFIGURE ,/* Superblock reconfiguration (remount) */ +}; + +/* +* Filesystem context for holding the parameters used in the creation or +* reconfiguration of a superblock. +* +* Superblock creation fills in ->root whereas reconfiguration begins with this +* already set. +* +* See Documentation/filesystems/mounting.txt +*/ +struct fs_context { +const struct fs_context_operations *ops; +struct file_system_type *fs_type; +void *fs_private;/* The filesystem's context */ +struct dentry *root;/* The root and superblock */ +struct user_namespace *user_ns;/* The user namespace for this mount */ +struct net *net_ns;/* The network namespace for this mount */ +const struct cred *cred;/* The mounter's credentials */ +char *source;/* The source name (eg. dev path) */ +char *subtype;/* The subtype to set on the superblock */ +void *security;/* The LSM context */ +void *s_fs_info;/* Proposed s_fs_info */ +unsigned int sb_flags;/* Proposed superblock flags (SB_*) */ +bool sloppy:1 ;/* T if unrecognised options are okay */ +bool silent:1 ;/* T if "o silent" specified */ +bool drop_sb:1 ;/* T if need to drop an SB reference */ +bool source_is_dev:1 ;/* T if source is local device/file */ +enum fs_context_purpose purpose :8 ; +}; + +struct fs_context_operations { +void (*free)(struct fs_context *fc); +int (*dup)(struct fs_context *fc,struct fs_context *src_fc); +int (*parse_source)(struct fs_context *fc,char *source); +int (*parse_option)(struct fs_context *fc,char *opt,size_t len); +int (*parse_monolithic)(struct fs_context *fc,void *data); +int (*validate)(struct fs_context *fc); +int (*get_tree)(struct fs_context *fc); +}; + +#endif /* _LINUX_FS_CONTEXT_H */
Al Viro
maintainerRe: [PATCH 03/32] VFS: Introduce the basic header for the new mount API's filesystem context [ver #8]
include/linux/fs_context.h line 60
Quoted 1 line · David Howells
include/linux/fs_context.h new file +1
-0+ bool drop_sb:1; /* T if need to drop an SB reference */
IMO that should be simply fc->root != NULL - if you keep a dentry, you'd better make sure that its superblock has an active reference, so deactivate_super() is needed anyway.
Al Viro
maintainerRe: [PATCH 03/32] VFS: Introduce the basic header for the new mount API's filesystem context [ver #8]
In reply to David Howellsinclude/linux/fs_context.h line 48
Quoted 1 line · David Howells
include/linux/fs_context.h new file +1
-0+void *fs_private;/* The filesystem's context */
...
include/linux/fs_context.h line 56
Quoted 1 line
include/linux/fs_context.h new file +1
-0+void *s_fs_info;/* Proposed s_fs_info */
While we are at it, do we really need both in generic interface?
David Howells
maintainerPATCH 4/32 VFS: Add LSM hooks for the new mount API [ver #8]
In reply to David HowellsAdd LSM hooks for use by the new mount API and filesystem context code. This includes:
(1) Hooks to handle allocation, duplication and freeing of the security record attached to a filesystem context.
(2) A hook to snoop source specifications. There may be multiple of these if the filesystem supports it. They will to be local files/devices if fs_context::source_is_dev is true and will be something else, possibly remote server specifications, if false.
(3) A hook to snoop superblock configuration options in key[=val] form. If the LSM decides it wants to handle it, it can suppress the option being passed to the filesystem. Note that 'val' may include commas and binary data with the fsopen patch.
(4) A hook to perform validation and allocation after the configuration has been done but before the superblock is allocated and set up.
(5) A hook to transfer the security from the context to a newly created superblock.
(6) A hook to rule on whether a path point can be used as a mountpoint.
These are intended to replace:
security_sb_copy_data
security_sb_kern_mount
security_sb_mount
security_sb_set_mnt_opts
security_sb_clone_mnt_opts
security_sb_parse_opts_str
---
include/linux/lsm_hooks.h | 71 +++++++++++++++++++++++++++++++++++++++++++++ include/linux/security.h | 49 +++++++++++++++++++++++++++++++ security/security.c | 46 +++++++++++++++++++++++++++++ 3 files changed, 166 insertions(+)
include/linux/lsm_hooks.h +71 -0
@@ -76,6 +76,57 @@* changes on the process such as clearing out non-inheritable signal * state. This is called immediately after commit_creds(). * +* Security hooks for mount using fs_context. +* [See also Documentation/filesystems/mounting.txt] +* +* @fs_context_alloc: +* Allocate and attach a security structure to sc->security. This pointer +* is initialised to NULL by the caller. +* @fc indicates the new filesystem context. +* @reference indicates the source dentry of a submount or start of reconfig. +* @fs_context_dup: +* Allocate and attach a security structure to sc->security. This pointer +* is initialised to NULL by the caller. +* @fc indicates the new filesystem context. +* @src_fc indicates the original filesystem context. +* @fs_context_free: +* Clean up a filesystem context. +* @fc indicates the filesystem context. +* @fs_context_parse_source: +* Check a source for the superblock (multiple sources may be provided). +* The LSM may reject it with an error; otherwise it should return 0. +* @fc indicates the filesystem context. +* @src indicates the source name. It is NUL-terminated, +* @fc->source_is_dev is true if the source should be a local file or dev. +* @fs_context_parse_option: +* Userspace provided an option to configure a superblock. The LSM may +* reject it with an error and may use it for itself, in which case it +* should return 1; otherwise it should return 0 to pass it on to the +* filesystem. +* @fc indicates the filesystem context. +* @opt indicates the option in "key[=val]" form. It is NUL-terminated, +* but val may be binary data. +* @len indicates the size of the option. +* @fs_context_validate: +* Validate the filesystem context preparatory to applying it. This is +* done after all the options have been parsed. +* @fc indicates the filesystem context. +* @sb_get_tree: +* Assign the security to a newly created superblock. +* @fc indicates the filesystem context. +* @fc->root indicates the root that will be mounted. +* @fc->root->d_sb points to the superblock. +* @sb_reconfigure: +* Apply reconfiguration to the security on a superblock. +* @fc indicates the filesystem context. +* @fc->root indicates a dentry in the mount. +* @fc->root->d_sb points to the superblock. +* @sb_mountpoint: +* Equivalent of sb_mount, but with an fs_context. +* @fc indicates the filesystem context. +* @mountpoint indicates the path on which the mount will take place. +* @mnt_flags indicates the MNT_* flags specified. +* * Security hooks for filesystem operations. * * @sb_alloc_security:
@@ -1450,6 +1501,17 @@ union security_list_options {void (*bprm_committing_creds)(struct linux_binprm *bprm);void (*bprm_committed_creds)(struct linux_binprm *bprm); +int (*fs_context_alloc)(struct fs_context *fc,struct dentry *reference); +int (*fs_context_dup)(struct fs_context *fc,struct fs_context *src_sc); +void (*fs_context_free)(struct fs_context *fc); +int (*fs_context_parse_source)(struct fs_context *fc,char *src); +int (*fs_context_parse_option)(struct fs_context *fc,char *opt,size_t len); +int (*fs_context_validate)(struct fs_context *fc); +int (*sb_get_tree)(struct fs_context *fc); +void (*sb_reconfigure)(struct fs_context *fc); +int (*sb_mountpoint)(struct fs_context *fc,struct path *mountpoint, +unsigned int mnt_flags); +int (*sb_alloc_security)(struct super_block *sb);void (*sb_free_security)(struct super_block *sb);int (*sb_copy_data)(char *orig,char *copy);
@@ -1787,6 +1849,15 @@ struct security_hook_heads {struct hlist_head bprm_check_security;struct hlist_head bprm_committing_creds;struct hlist_head bprm_committed_creds; +struct hlist_head fs_context_alloc; +struct hlist_head fs_context_dup; +struct hlist_head fs_context_free; +struct hlist_head fs_context_parse_source; +struct hlist_head fs_context_parse_option; +struct hlist_head fs_context_validate; +struct hlist_head sb_get_tree; +struct hlist_head sb_reconfigure; +struct hlist_head sb_mountpoint;struct hlist_head sb_alloc_security;struct hlist_head sb_free_security;struct hlist_head sb_copy_data;
include/linux/security.h +49 -0
67 lines not on this page · raw message
security/security.c +46 -0
52 lines not on this page · raw message
David Howells
maintainerPATCH 5/32 selinux: Implement the new mount API LSM hooks [ver #8]
In reply to David HowellsImplement the new mount API LSM hooks for SELinux. At some point the old hooks will need to be removed.
Question: Should the ->fs_context_parse_source() hook be implemented to check the labels on any source devices specified?
---
security/selinux/hooks.c | 262 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 262 insertions(+)
security/selinux/hooks.c +262 -0
@@ -48,6 +48,7 @@#include <linux/fdtable.h> #include <linux/namei.h> #include <linux/mount.h> +#include <linux/fs_context.h> #include <linux/netfilter_ipv4.h> #include <linux/netfilter_ipv6.h> #include <linux/tty.h>
@@ -2971,6 +2972,259 @@ static int selinux_umount(struct vfsmount *mnt, int flags) FILESYSTEM__UNMOUNT, NULL); } +/* fsopen mount context operations */ + +static int selinux_fs_context_alloc (struct fs_context *fc, +struct dentry *reference) +{ +struct security_mnt_opts *opts; + + opts =kzalloc (sizeof (*opts),GFP_KERNEL ); +if (!opts) +return -ENOMEM ; + + fc->security = opts; +return 0 ; +} + +static int selinux_fs_context_dup (struct fs_context *fc, +struct fs_context *src_fc) +{ +const struct security_mnt_opts *src = src_fc->security; +struct security_mnt_opts *opts; +int i, n; + + opts =kzalloc (sizeof (*opts),GFP_KERNEL ); +if (!opts) +return -ENOMEM ; + fc->security = opts; + +if (!src || !src->num_mnt_opts) +return 0 ; + n = opts->num_mnt_opts = src->num_mnt_opts; + +if (src->mnt_opts) { + opts->mnt_opts =kcalloc (n,sizeof (char *),GFP_KERNEL ); +if (!opts->mnt_opts) +return -ENOMEM ; + +for (i =0 ; i < n; i++) { +if (src->mnt_opts[i]) { + opts->mnt_opts[i] =kstrdup (src->mnt_opts[i], +GFP_KERNEL ); +if (!opts->mnt_opts[i]) +return -ENOMEM ; + } + } + } + +if (src->mnt_opts_flags) { + opts->mnt_opts_flags =kmemdup (src->mnt_opts_flags, + n *sizeof (int ),GFP_KERNEL ); +if (!opts->mnt_opts_flags) +return -ENOMEM ; + } + +return 0 ; +} + +static void selinux_fs_context_free (struct fs_context *fc) +{ +struct security_mnt_opts *opts = fc->security; + +security_free_mnt_opts (opts); + fc->security =NULL ; +} + +static int selinux_fs_context_parse_option (struct fs_context *fc,char *opt,size_t len) +{ +struct security_mnt_opts *opts = fc->security; +substring_t args[MAX_OPT_ARGS ]; +unsigned int have; +char *c, **oo; +int token, ctx, i, *of; + + token =match_token (opt, tokens, args); +if (token == Opt_error) +return 0 ;/* Doesn't belong to us. */ + + have =0 ; +for (i =0 ; i < opts->num_mnt_opts; i++) + have |=1 << opts->mnt_opts_flags[i]; +if (have & (1 << token)) +return -EINVAL ; + +switch (token) { +case Opt_context: +if (have & (1 << Opt_defcontext)) + goto incompatible; + ctx =CONTEXT_MNT ; + goto copy_context_string; + +case Opt_fscontext: + ctx =FSCONTEXT_MNT ; + goto copy_context_string; + +case Opt_rootcontext: + ctx =ROOTCONTEXT_MNT ; + goto copy_context_string; + +case Opt_defcontext: +if (have & (1 << Opt_context)) + goto incompatible; + ctx =DEFCONTEXT_MNT ; + goto copy_context_string; + +case Opt_labelsupport: +return 1 ; + +default : +return -EINVAL ; + } + +copy_context_string: +if (opts->num_mnt_opts >3 ) +return -EINVAL ; + + of =krealloc (opts->mnt_opts_flags, + (opts->num_mnt_opts +1 ) *sizeof (int ),GFP_KERNEL ); +if (!of) +return -ENOMEM ; + of[opts->num_mnt_opts] =0 ; + opts->mnt_opts_flags = of; + + oo =krealloc (opts->mnt_opts, + (opts->num_mnt_opts +1 ) *sizeof (char *),GFP_KERNEL ); +if (!oo) +return -ENOMEM ; + oo[opts->num_mnt_opts] =NULL ; + opts->mnt_opts = oo; + + c =match_strdup (&args[0 ]); +if (!c) +return -ENOMEM ; + opts->mnt_opts[opts->num_mnt_opts] = c; + opts->mnt_opts_flags[opts->num_mnt_opts] = ctx; + opts->num_mnt_opts++; +return 1 ; + +incompatible: +return -EINVAL ; +} + +/* +* Validate the security parameters supplied for a reconfiguration/remount +* event. +*/ +static int selinux_validate_for_sb_reconfigure (struct fs_context *fc) +{ +struct super_block *sb = fc->root->d_sb; +struct superblock_security_struct *sbsec = sb->s_security; +struct security_mnt_opts *opts = fc->security; +int rc, i, *flags; +char **mount_options; + +if (!(sbsec->flags &SE_SBINITIALIZED )) +return 0 ; + + mount_options = opts->mnt_opts; + flags = opts->mnt_opts_flags; + +for (i =0 ; i < opts->num_mnt_opts; i++) { +u32 sid; + +if (flags[i] ==SBLABEL_MNT ) +continue ; + + rc =security_context_str_to_sid (&selinux_state, mount_options[i], + &sid,GFP_KERNEL ); +if (rc) { +pr_warn ("SELinux: security_context_str_to_sid" +"(%s) failed for (dev %s, type %s) errno=%d\n" , + mount_options[i], sb->s_id, sb->s_type->name, rc); + goto inval; + } + +switch (flags[i]) { +case FSCONTEXT_MNT : +if (bad_option (sbsec,FSCONTEXT_MNT , sbsec->sid, sid)) + goto bad_option; +break ; +case CONTEXT_MNT : +if (bad_option (sbsec,CONTEXT_MNT , sbsec->mntpoint_sid, sid)) + goto bad_option; +break ; +case ROOTCONTEXT_MNT : { +struct inode_security_struct *root_isec; + root_isec =backing_inode_security (sb->s_root); + +if (bad_option (sbsec,ROOTCONTEXT_MNT , root_isec->sid, sid)) + goto bad_option; +break ; + } +case DEFCONTEXT_MNT : +if (bad_option (sbsec,DEFCONTEXT_MNT , sbsec->def_sid, sid)) + goto bad_option; +break ; +default : + goto inval; + } + } + + rc =0 ; +out: +return rc; + +bad_option: +pr_warn ("SELinux: unable to change security options " +"during remount (dev %s, type=%s)\n" , + sb->s_id, sb->s_type->name); +inval: + rc = -EINVAL ; + goto out; +} + +/* +* Validate the security context assembled from the option data supplied to +* mount. +*/ +static int selinux_fs_context_validate (struct fs_context *fc) +{ +if (fc->purpose ==FS_CONTEXT_FOR_RECONFIGURE ) +return selinux_validate_for_sb_reconfigure (fc); +return 0 ; +} + +/* +* Set the security context on a superblock. +*/ +static int selinux_sb_get_tree (struct fs_context *fc) +{ +const struct cred *cred =current_cred (); +struct common_audit_data ad; +int rc; + + rc =selinux_set_mnt_opts (fc->root->d_sb, fc->security,0 ,NULL ); +if (rc) +return rc; + +/* Allow all mounts performed by the kernel */ +if (fc->purpose ==FS_CONTEXT_FOR_KERNEL_MOUNT ) +return 0 ; + + ad.type =LSM_AUDIT_DATA_DENTRY ; + ad.u.dentry = fc->root; +return superblock_has_perm (cred, fc->root->d_sb,FILESYSTEM__MOUNT , &ad); +} + +static int selinux_sb_mountpoint (struct fs_context *fc,struct path *mountpoint, +unsigned int mnt_flags) +{ +const struct cred *cred =current_cred (); + +return path_has_perm (cred, mountpoint,FILE__MOUNTON ); +} +/* inode security operations */ static int selinux_inode_alloc_security (struct inode *inode)
@@ -6882,6 +7136,14 @@ static struct security_hook_list selinux_hooks[] __lsm_ro_after_init = {LSM_HOOK_INIT (bprm_committing_creds, selinux_bprm_committing_creds),LSM_HOOK_INIT (bprm_committed_creds, selinux_bprm_committed_creds), +LSM_HOOK_INIT (fs_context_alloc, selinux_fs_context_alloc), +LSM_HOOK_INIT (fs_context_dup, selinux_fs_context_dup), +LSM_HOOK_INIT (fs_context_free, selinux_fs_context_free), +LSM_HOOK_INIT (fs_context_parse_option, selinux_fs_context_parse_option), +LSM_HOOK_INIT (fs_context_validate, selinux_fs_context_validate), +LSM_HOOK_INIT (sb_get_tree, selinux_sb_get_tree), +LSM_HOOK_INIT (sb_mountpoint, selinux_sb_mountpoint), +LSM_HOOK_INIT (sb_alloc_security, selinux_sb_alloc_security),LSM_HOOK_INIT (sb_free_security, selinux_sb_free_security), LSM_HOOK_INIT(sb_copy_data, selinux_sb_copy_data),
David Howells
maintainerPATCH 6/32 smack: Implement filesystem context security hooks [ver #8]
In reply to David HowellsImplement filesystem context security hooks for the smack LSM.
Question: Should the ->fs_context_parse_source() hook be implemented to check the labels on any source devices specified?
---
security/smack/smack_lsm.c | 309 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 309 insertions(+)
security/smack/smack_lsm.c +309 -0
@@ -42,6 +42,7 @@#include <linux/shm.h> #include <linux/binfmts.h> #include <linux/parser.h> +#include <linux/fs_context.h> #include "smack.h" #define TRANS_TRUE "TRUE"
@@ -521,6 +522,307 @@ static int smack_syslog(int typefrom_file)return rc; } +/* +* Mount context operations +*/ + +struct smack_fs_context { +union { +struct { +char *fsdefault; +char *fsfloor; +char *fshat; +char *fsroot; +char *fstransmute; + }; +char *ptrs[5 ]; + + }; +struct superblock_smack *sbsp; +struct inode_smack *isp; +bool transmute; +}; + +/** +* smack_fs_context_free - Free the security data from a filesystem context +* @fc: The filesystem context to be cleaned up. +*/ +static void smack_fs_context_free (struct fs_context *fc) +{ +struct smack_fs_context *ctx = fc->security; +int i; + +if (ctx) { +for (i =0 ; i <ARRAY_SIZE (ctx->ptrs); i++) +kfree (ctx->ptrs[i]); +kfree (ctx->isp); +kfree (ctx->sbsp); +kfree (ctx); + fc->security =NULL ; + } +} + +/** +* smack_fs_context_alloc - Allocate security data for a filesystem context +* @fc: The filesystem context. +* @reference: Reference dentry (automount/reconfigure) or NULL +* +* Returns 0 on success or -ENOMEM on error. +*/ +static int smack_fs_context_alloc (struct fs_context *fc, +struct dentry *reference) +{ +struct smack_fs_context *ctx; +struct superblock_smack *sbsp; +struct inode_smack *isp; +struct smack_known *skp; + + ctx =kzalloc (sizeof (struct smack_fs_context ),GFP_KERNEL ); +if (!ctx) + goto nomem; + fc->security = ctx; + + sbsp =kzalloc (sizeof (struct superblock_smack ),GFP_KERNEL ); +if (!sbsp) + goto nomem_free; + ctx->sbsp = sbsp; + + isp =new_inode_smack (NULL ); +if (!isp) + goto nomem_free; + ctx->isp = isp; + +if (reference) { +if (reference->d_sb->s_security) +memcpy (sbsp, reference->d_sb->s_security,sizeof (*sbsp)); + }else if (!smack_privileged (CAP_MAC_ADMIN )) { +/* Unprivileged mounts get root and default from the caller. */ + skp =smk_of_current (); + sbsp->smk_root = skp; + sbsp->smk_default = skp; + }else { + sbsp->smk_root = &smack_known_floor; + sbsp->smk_default = &smack_known_floor; + sbsp->smk_floor = &smack_known_floor; + sbsp->smk_hat = &smack_known_hat; +/* SMK_SB_INITIALIZED will be zero from kzalloc. */ + } + +return 0 ; + +nomem_free: +smack_fs_context_free (fc); +nomem: +return -ENOMEM ; +} + +/** +* smack_fs_context_dup - Duplicate the security data on fs_context duplication +* @fc: The new filesystem context. +* @src_fc: The source filesystem context being duplicated. +* +* Returns 0 on success or -ENOMEM on error. +*/ +static int smack_fs_context_dup (struct fs_context *fc, +struct fs_context *src_fc) +{ +struct smack_fs_context *dst, *src = src_fc->security; +int i; + + dst =kzalloc (sizeof (struct smack_fs_context ),GFP_KERNEL ); +if (!dst) + goto nomem; + fc->security = dst; + + dst->sbsp =kmemdup (src->sbsp,sizeof (struct superblock_smack ), +GFP_KERNEL ); +if (!dst->sbsp) + goto nomem_free; + +for (i =0 ; i <ARRAY_SIZE (dst->ptrs); i++) { +if (src->ptrs[i]) { + dst->ptrs[i] =kstrdup (src->ptrs[i],GFP_KERNEL ); +if (!dst->ptrs[i]) + goto nomem_free; + } + } + +return 0 ; + +nomem_free: +smack_fs_context_free (fc); +nomem: +return -ENOMEM ; +} + +/** +* smack_fs_context_parse_option - Parse a single mount option +* @fc: The new filesystem context being constructed. +* @opt: The option text buffer. +* @len: The length of the text. +* +* Returns 0 on success or -ENOMEM on error. +*/ +static int smack_fs_context_parse_option (struct fs_context *fc,char *p,size_t len) +{ +struct smack_fs_context *ctx = fc->security; +substring_t args[MAX_OPT_ARGS ]; +int rc = -ENOMEM ; +int token; + +/* Unprivileged mounts don't get to specify Smack values. */ +if (!smack_privileged (CAP_MAC_ADMIN )) +return -EPERM ; + + token =match_token (p, smk_mount_tokens, args); +switch (token) { +case Opt_fsdefault: +if (ctx->fsdefault) + goto error_dup; + ctx->fsdefault =match_strdup (&args[0 ]); +if (!ctx->fsdefault) + goto error; +break ; +case Opt_fsfloor: +if (ctx->fsfloor) + goto error_dup; + ctx->fsfloor =match_strdup (&args[0 ]); +if (!ctx->fsfloor) + goto error; +break ; +case Opt_fshat: +if (ctx->fshat) + goto error_dup; + ctx->fshat =match_strdup (&args[0 ]); +if (!ctx->fshat) + goto error; +break ; +case Opt_fsroot: +if (ctx->fsroot) + goto error_dup; + ctx->fsroot =match_strdup (&args[0 ]); +if (!ctx->fsroot) + goto error; +break ; +case Opt_fstransmute: +if (ctx->fstransmute) + goto error_dup; + ctx->fstransmute =match_strdup (&args[0 ]); +if (!ctx->fstransmute) + goto error; +break ; +default : +pr_warn ("Smack: unknown mount option\n" ); + goto error_inval; + } + +return 0 ; + +error_dup: +pr_warn ("Smack: duplicate mount option\n" ); +error_inval: + rc = -EINVAL ; +error: +return rc; +} + +/** +* smack_fs_context_validate - Validate the filesystem context security data +* @fc: The filesystem context. +* +* Returns 0 on success or -ENOMEM on error. +*/ +static int smack_fs_context_validate (struct fs_context *fc) +{ +struct smack_fs_context *ctx = fc->security; +struct superblock_smack *sbsp = ctx->sbsp; +struct inode_smack *isp = ctx->isp; +struct smack_known *skp; + +if (ctx->fsdefault) { + skp =smk_import_entry (ctx->fsdefault,0 ); +if (IS_ERR (skp)) +return PTR_ERR (skp); + sbsp->smk_default = skp; + } + +if (ctx->fsfloor) { + skp =smk_import_entry (ctx->fsfloor,0 ); +if (IS_ERR (skp)) +return PTR_ERR (skp); + sbsp->smk_floor = skp; + } + +if (ctx->fshat) { + skp =smk_import_entry (ctx->fshat,0 ); +if (IS_ERR (skp)) +return PTR_ERR (skp); + sbsp->smk_hat = skp; + } + +if (ctx->fsroot || ctx->fstransmute) { + skp =smk_import_entry (ctx->fstransmute ?: ctx->fsroot,0 ); +if (IS_ERR (skp)) +return PTR_ERR (skp); + sbsp->smk_root = skp; + ctx->transmute = !!ctx->fstransmute; + } + + isp->smk_inode = sbsp->smk_root; +return 0 ; +} + +/** +* smack_sb_get_tree - Assign the context to a newly created superblock +* @fc: The new filesystem context. +* +* Returns 0 on success or -ENOMEM on error. +*/ +static int smack_sb_get_tree (struct fs_context *fc) +{ +struct smack_fs_context *ctx = fc->security; +struct superblock_smack *sbsp = ctx->sbsp; +struct dentry *root = fc->root; +struct inode *inode =d_backing_inode (root); +struct super_block *sb = root->d_sb; +struct inode_smack *isp; +bool transmute = ctx->transmute; + +if (sb->s_security) +return 0 ; + +if (!smack_privileged (CAP_MAC_ADMIN )) { +/* +* For a handful of fs types with no user-controlled +* backing store it's okay to trust security labels +* in the filesystem. The rest are untrusted. +*/ +if (fc->user_ns != &init_user_ns && + sb->s_magic !=SYSFS_MAGIC && sb->s_magic !=TMPFS_MAGIC && + sb->s_magic !=RAMFS_MAGIC ) { + transmute = true; + sbsp->smk_flags |=SMK_SB_UNTRUSTED ; + } + } + + sbsp->smk_flags |=SMK_SB_INITIALIZED ; + sb->s_security = sbsp; + ctx->sbsp =NULL ; + +/* Initialize the root inode. */ + isp = inode->i_security; +if (isp ==NULL ) { + isp = ctx->isp; + ctx->isp =NULL ; + inode->i_security = isp; + }else + isp->smk_inode = sbsp->smk_root; + +if (transmute) + isp->smk_flags |=SMK_INODE_TRANSMUTE ; + +return 0 ; +}/* * Superblock Hooks.
@@ -4628,6 +4930,13 @@ static struct security_hook_list smack_hooks[] __lsm_ro_after_init = {LSM_HOOK_INIT (ptrace_traceme, smack_ptrace_traceme),LSM_HOOK_INIT (syslog, smack_syslog), +LSM_HOOK_INIT (fs_context_alloc, smack_fs_context_alloc), +LSM_HOOK_INIT (fs_context_dup, smack_fs_context_dup), +LSM_HOOK_INIT (fs_context_free, smack_fs_context_free), +LSM_HOOK_INIT (fs_context_parse_option, smack_fs_context_parse_option), +LSM_HOOK_INIT (fs_context_validate, smack_fs_context_validate), +LSM_HOOK_INIT (sb_get_tree, smack_sb_get_tree), +LSM_HOOK_INIT (sb_alloc_security, smack_sb_alloc_security),LSM_HOOK_INIT (sb_free_security, smack_sb_free_security), LSM_HOOK_INIT(sb_copy_data, smack_sb_copy_data),
David Howells
maintainerPATCH 7/32 apparmor: Implement security hooks for the new mount API [ver #8]
In reply to David HowellsImplement hooks to check the creation of new mountpoints for AppArmor.
Unfortunately, the DFA evaluation puts the option data in last, after the details of the mountpoint, so we have to cache the mount options in the fs_context using those hooks till we get to the new mountpoint hook.
---
security/apparmor/include/mount.h | 11 +++++ security/apparmor/lsm.c | 80 +++++++++++++++++++++++++++++++++++++ security/apparmor/mount.c | 46 +++++++++++++++++++++ 3 files changed, 135 insertions(+), 2 deletions(-)
security/apparmor/include/mount.h +10 -1
@@ -16,6 +16,7 @@#include <linux/fs.h> #include <linux/path.h> +#include <linux/fs_context.h> #include "domain.h" #include "policy.h"
@@ -27,7 +28,13 @@#define AA_AUDIT_DATA 0x40#define AA_MNT_CONT_MATCH 0x40 -#define AA_MS_IGNORE_MASK (MS_KERNMOUNT | MS_NOSEC | MS_ACTIVE | MS_BORN) +#define AA_SB_IGNORE_MASK (SB_KERNMOUNT | SB_NOSEC | SB_ACTIVE | SB_BORN) + +struct apparmor_fs_context { +struct fs_context fc; +char *saved_options; +size_t saved_size; +};int aa_remount (struct aa_label *label,const struct path *path,unsigned long flags,void *data);
@@ -45,6 +52,8 @@ int aa_move_mount(struct aa_label *label, const struct path *path,int aa_new_mount (struct aa_label *label,const char *dev_name,const struct path *path,const char *type,unsigned long flags,void *data); +int aa_new_mount_fc (struct aa_label *label,struct fs_context *fc, +const struct path *mountpoint);int aa_umount (struct aa_label *label,struct vfsmount *mnt,int flags);
security/apparmor/lsm.c +79 -1
98 lines not on this page · raw message
security/apparmor/mount.c +46 -0
52 lines not on this page · raw message
David Howells
maintainerPATCH 8/32 tomoyo: Implement security hooks for the new mount API [ver #8]
In reply to David HowellsImplement the security hook to check the creation of a new mountpoint for Tomoyo.
As far as I can tell, Tomoyo doesn't make use of the mount data or parse any mount options, so I haven't implemented any of the fs_context hooks for it.
---
security/tomoyo/common.h | 3 +++ security/tomoyo/mount.c | 45 +++++++++++++++++++++++++++++++++++++++++++++ security/tomoyo/tomoyo.c | 15 +++++++++++++++ 3 files changed, 63 insertions(+)
security/tomoyo/common.h +3 -0
@@ -971,6 +971,9 @@ int tomoyo_init_request_info(struct tomoyo_request_info *r, const u8 index);int tomoyo_mkdev_perm (const u8 operation,const struct path *path,const unsigned int mode,unsigned int dev); +int tomoyo_mount_permission_fc (struct fs_context *fc, +const struct path *mountpoint, +unsigned int mnt_flags);int tomoyo_mount_permission (const char *dev_name,const struct path *path,const char *type,unsigned long flags,void *data_page);
security/tomoyo/mount.c +45 -0
54 lines not on this page · raw message
security/tomoyo/tomoyo.c +15 -0
@@ -391,6 +391,20 @@ static int tomoyo_path_chroot(const struct path *path)return tomoyo_path_perm (TOMOYO_TYPE_CHROOT , path,NULL ); } +/** +* tomoyo_sb_mount - Target for security_sb_mountpoint(). +* @fc: Context describing the object to be mounted. +* @mountpoint: The target object to mount on. +* @mnt_flags: Mountpoint specific options (as MNT_* flags). +* +* Returns 0 on success, negative value otherwise. +*/ +static int tomoyo_sb_mountpoint (struct fs_context *fc,struct path *mountpoint, +unsigned int mnt_flags) +{ +return tomoyo_mount_permission_fc (fc, mountpoint, mnt_flags); +} +/** * tomoyo_sb_mount - Target for security_sb_mount(). *
@@ -519,6 +533,7 @@ static struct security_hook_list tomoyo_hooks[] __lsm_ro_after_init = {LSM_HOOK_INIT (path_chmod, tomoyo_path_chmod),LSM_HOOK_INIT (path_chown, tomoyo_path_chown),LSM_HOOK_INIT (path_chroot, tomoyo_path_chroot), +LSM_HOOK_INIT (sb_mountpoint, tomoyo_sb_mountpoint),LSM_HOOK_INIT (sb_mount, tomoyo_sb_mount),LSM_HOOK_INIT (sb_umount, tomoyo_sb_umount), LSM_HOOK_INIT(sb_pivotroot, tomoyo_sb_pivotroot),
David Howells
maintainerPATCH 9/32 VFS: Require specification of size of mount data for internal mounts [ver #8]
In reply to David HowellsRequire specification of the size of the mount data passed to the VFS mounting functions by internal mounts. The problem is that the legacy handling for the upcoming mount-context patches has to copy an entire page as that's how big the buffer is defined as being, but some of the internal calls pass in a short bit of stack space, with the result that the stack guard page may get hit.
---
arch/ia64/kernel/perfmon.c | 3 + arch/powerpc/platforms/cell/spufs/inode.c | 6 +-- arch/s390/hypfs/inode.c | 7 ++- arch/x86/kernel/cpu/intel_rdt_rdtgroup.c | 2 - drivers/base/devtmpfs.c | 6 +-- drivers/dax/super.c | 2 - drivers/gpu/drm/drm_drv.c | 3 + drivers/gpu/drm/i915/i915_gemfs.c | 2 - drivers/infiniband/hw/qib/qib_fs.c | 7 ++- drivers/misc/ibmasm/ibmasmfs.c | 11 +++-- drivers/mtd/mtdsuper.c | 26 +++++++----- drivers/oprofile/oprofilefs.c | 8 ++-- .../staging/lustre/lustre/llite/llite_internal.h | 2 - drivers/staging/lustre/lustre/llite/llite_lib.c | 3 + drivers/staging/lustre/lustre/obdclass/obd_mount.c | 7 ++- drivers/staging/ncpfs/inode.c | 10 +++-- drivers/usb/gadget/function/f_fs.c | 7 ++- drivers/usb/gadget/legacy/inode.c | 7 ++- drivers/virtio/virtio_balloon.c | 2 - drivers/xen/xenfs/super.c | 7 ++- fs/9p/vfs_super.c | 2 - fs/adfs/super.c | 9 ++-- fs/affs/super.c | 13 ++++-- fs/afs/mntpt.c | 3 + fs/afs/super.c | 6 ++- fs/aio.c | 3 + fs/anon_inodes.c | 3 + fs/autofs4/autofs_i.h | 2 - fs/autofs4/init.c | 4 +- fs/autofs4/inode.c | 3 + fs/befs/linuxvfs.c | 11 +++-- fs/bfs/inode.c | 8 ++-- fs/binfmt_misc.c | 7 ++- fs/block_dev.c | 2 - fs/btrfs/super.c | 30 ++++++++------ fs/btrfs/tests/btrfs-tests.c | 2 - fs/ceph/super.c | 3 + fs/cifs/cifs_dfs_ref.c | 3 + fs/cifs/cifsfs.c | 5 +- fs/coda/inode.c | 11 +++-- fs/configfs/mount.c | 7 ++- fs/cramfs/inode.c | 17 +++++--- fs/debugfs/inode.c | 14 ++++-- fs/devpts/inode.c | 10 +++-- fs/ecryptfs/main.c | 2 - fs/efivarfs/super.c | 9 +++- fs/efs/super.c | 14 ++++-- fs/exofs/super.c | 7 ++- fs/ext2/super.c | 14 ++++-- fs/ext4/super.c | 16 +++++-- fs/f2fs/super.c | 11 +++-- fs/fat/inode.c | 3 + fs/fat/namei_msdos.c | 8 ++-- fs/fat/namei_vfat.c | 8 ++-- fs/freevxfs/vxfs_super.c | 12 ++++- fs/fuse/control.c | 9 +++- fs/fuse/inode.c | 16 +++++-- fs/gfs2/ops_fstype.c | 6 ++- fs/gfs2/super.c | 4 +- fs/hfs/super.c | 12 ++++- fs/hfsplus/super.c | 12 ++++- fs/hostfs/hostfs_kern.c | 7 ++- fs/hpfs/super.c | 11 +++-- fs/hugetlbfs/inode.c | 13 ++++-- fs/internal.h | 4 +- fs/isofs/inode.c | 11 +++-- fs/jffs2/super.c | 10 +++-- fs/jfs/super.c | 11 +++-- fs/kernfs/mount.c | 3 + fs/libfs.c | 2 - fs/minix/inode.c | 14 ++++-- fs/namespace.c | 38 ++++++++++------- fs/nfs/internal.h | 4 +- fs/nfs/namespace.c | 3 + fs/nfs/nfs4namespace.c | 3 + fs/nfs/nfs4super.c | 27 +++++++----- fs/nfs/super.c | 22 +++++----- fs/nfsd/nfsctl.c | 8 ++-- fs/nilfs2/super.c | 10 +++-- fs/nsfs.c | 3 + fs/ntfs/super.c | 13 ++++-- fs/ocfs2/dlmfs/dlmfs.c | 5 +- fs/ocfs2/super.c | 14 ++++-- fs/omfs/inode.c | 9 +++- fs/openpromfs/inode.c | 11 +++-- fs/orangefs/orangefs-kernel.h | 2 - fs/orangefs/super.c | 5 +- fs/overlayfs/super.c | 11 +++-- fs/pipe.c | 3 + fs/proc/inode.c | 3 + fs/proc/internal.h | 4 +- fs/proc/root.c | 11 +++-- fs/pstore/inode.c | 10 +++-- fs/qnx4/inode.c | 14 ++++-- fs/qnx6/inode.c | 14 ++++-- fs/ramfs/inode.c | 6 +-- fs/reiserfs/super.c | 14 ++++-- fs/romfs/super.c | 13 ++++-- fs/squashfs/super.c | 12 ++++- fs/super.c | 44 +++++++++++--------- fs/sysfs/mount.c | 2 - fs/sysv/inode.c | 3 + fs/sysv/super.c | 16 +++++-- fs/tracefs/inode.c | 10 +++-- fs/ubifs/super.c | 5 +- fs/udf/super.c | 16 +++++-- fs/ufs/super.c | 11 +++-- fs/xfs/xfs_super.c | 10 +++-- include/linux/debugfs.h | 8 ++-- include/linux/fs.h | 29 +++++++------ include/linux/lsm_hooks.h | 13 ++++-- include/linux/mount.h | 5 +- include/linux/mtd/super.h | 4 +- include/linux/ramfs.h | 4 +- include/linux/security.h | 17 ++++---- include/linux/shmem_fs.h | 3 + init/do_mounts.c | 4 +- ipc/mqueue.c | 9 ++-- kernel/bpf/inode.c | 7 ++- kernel/cgroup/cgroup.c | 2 - kernel/cgroup/cpuset.c | 7 ++- kernel/trace/trace.c | 7 ++- mm/shmem.c | 10 +++-- mm/zsmalloc.c | 3 + net/socket.c | 3 + net/sunrpc/rpc_pipe.c | 7 ++- security/apparmor/apparmorfs.c | 8 ++-- security/apparmor/lsm.c | 3 + security/inode.c | 7 ++- security/security.c | 18 +++++--- security/selinux/hooks.c | 11 +++-- security/selinux/selinuxfs.c | 8 ++-- security/smack/smack_lsm.c | 6 ++- security/smack/smackfs.c | 9 +++- security/tomoyo/tomoyo.c | 4 +- 135 files changed, 710 insertions(+), 470 deletions(-)
arch/ia64/kernel/perfmon.c +2 -1
@@ -611,7 +611,8 @@ pfm_unprotect_ctx_ctxsw(pfm_context_t *x, unsigned long f)static const struct dentry_operations pfmfs_dentry_operations;static struct dentry * -pfmfs_mount (struct file_system_type *fs_type,int flags,const char *dev_name,void *data) +pfmfs_mount (struct file_system_type *fs_type,int flags,const char *dev_name, +void *data,size_t data_size) {return mount_pseudo (fs_type,"pfm:" ,NULL , &pfmfs_dentry_operations,PFMFS_MAGIC );
arch/powerpc/platforms/cell/spufs/inode.c +3 -3
@@ -734,7 +734,7 @@ spufs_create_root(struct super_block *sb, void *data) }static int -spufs_fill_super (struct super_block *sb,void *data,int silent) +spufs_fill_super (struct super_block *sb,void *data,size_t data_size,int silent) {struct spufs_sb_info *info;static const struct super_operations s_ops = {
@@ -761,9 +761,9 @@ spufs_fill_super(struct super_block *sb, void *data, int silent)static struct dentry *spufs_mount (struct file_system_type *fstype,int flags, -const char *name,void *data) +const char *name,void *data,size_t data_size) { -return mount_single (fstype, flags, data, spufs_fill_super); +return mount_single (fstype, flags, data, data_size, spufs_fill_super); }static struct file_system_type spufs_type = {
arch/s390/hypfs/inode.c +4 -3
@@ -266,7 +266,8 @@ static int hypfs_show_options(struct seq_file *s, struct dentry *root)return 0 ; } -static int hypfs_fill_super (struct super_block *sb,void *data,int silent) +static int hypfs_fill_super (struct super_block *sb, +void *data,size_t data_size,int silent) {struct inode *root_inode;struct dentry *root_dentry;
@@ -309,9 +310,9 @@ static int hypfs_fill_super(struct super_block *sb, void *data, int silent) }static struct dentry *hypfs_mount (struct file_system_type *fst,int flags, -const char *devname,void *data) +const char *devname,void *data,size_t data_size) { -return mount_single (fst, flags, data, hypfs_fill_super); +return mount_single (fst, flags, data, data_size, hypfs_fill_super); }static void hypfs_kill_super (struct super_block *sb)
arch/x86/kernel/cpu/intel_rdt_rdtgroup.c +1 -1
@@ -1207,7 +1207,7 @@ static int mkdir_mondata_all(struct kernfs_node *parent_kn,static struct dentry *rdt_mount (struct file_system_type *fs_type,int flags,const char *unused_dev_name, -void *data) +void *data,size_t data_size) {struct rdt_domain *dom;struct rdt_resource *r;
drivers/base/devtmpfs.c +3 -3
@@ -57,12 +57,12 @@ static int __init mount_param(char *str)__setup ("devtmpfs.mount=" , mount_param);static struct dentry *dev_mount (struct file_system_type *fs_type,int flags, -const char *dev_name,void *data) +const char *dev_name,void *data,size_t data_size) {#ifdef CONFIG_TMPFS -return mount_single (fs_type, flags, data, shmem_fill_super); +return mount_single (fs_type, flags, data, data_size, shmem_fill_super);#else -return mount_single (fs_type, flags, data, ramfs_fill_super); +return mount_single (fs_type, flags, data, data_size, ramfs_fill_super);#endif }
drivers/dax/super.c +1 -1
@@ -396,7 +396,7 @@ static const struct super_operations dax_sops = { };static struct dentry *dax_mount (struct file_system_type *fs_type, -int flags,const char *dev_name,void *data) +int flags,const char *dev_name,void *data,size_t data_size) {return mount_pseudo (fs_type,"dax:" , &dax_sops,NULL ,DAXFS_MAGIC ); }
drivers/gpu/drm/drm_drv.c +2 -1
@@ -375,7 +375,8 @@ static const struct super_operations drm_fs_sops = { };static struct dentry *drm_fs_mount (struct file_system_type *fs_type,int flags, -const char *dev_name,void *data) +const char *dev_name, +void *data,size_t data_size) { return mount_pseudo(fs_type, "drm:",
drivers/gpu/drm/i915/i915_gemfs.c +1 -1
@@ -57,7 +57,7 @@ int i915_gemfs_init(struct drm_i915_private *i915)int flags =0 ;int err; - err = sb->s_op->remount_fs (sb, &flags, options); + err = sb->s_op->remount_fs (sb, &flags, options,sizeof (options));if (err) {kern_unmount (gemfs);return err;
drivers/infiniband/hw/qib/qib_fs.c +4 -3
@@ -506,7 +506,8 @@ static int remove_device_files(struct super_block *sb,* after device init. The direct add_cntr_files() call handles adding * them from the init code, when the fs is already mounted. */ -static int qibfs_fill_super (struct super_block *sb,void *data,int silent) +static int qibfs_fill_super (struct super_block *sb, +void *data,size_t data_size,int silent) {struct qib_devdata *dd, *tmp;unsigned long flags;
@@ -541,11 +542,11 @@ static int qibfs_fill_super(struct super_block *sb, void *data, int silent) }static struct dentry *qibfs_mount (struct file_system_type *fs_type,int flags, -const char *dev_name,void *data) +const char *dev_name,void *data,size_t data_size) {struct dentry *ret; - ret =mount_single (fs_type, flags, data, qibfs_fill_super); + ret =mount_single (fs_type, flags, data, data_size, qibfs_fill_super);if (!IS_ERR (ret)) qib_super = ret->d_sb;return ret;
drivers/misc/ibmasm/ibmasmfs.c +7 -4
@@ -88,13 +88,15 @@ static LIST_HEAD(service_processors);static struct inode *ibmasmfs_make_inode (struct super_block *sb,int mode);static void ibmasmfs_create_files (struct super_block *sb); -static int ibmasmfs_fill_super (struct super_block *sb,void *data,int silent); +static int ibmasmfs_fill_super (struct super_block *sb,void *data,size_t data_size, +int silent);static struct dentry *ibmasmfs_mount (struct file_system_type *fst, -int flags,const char *name,void *data) +int flags,const char *name, +void *data,size_t data_size) { -return mount_single (fst, flags, data, ibmasmfs_fill_super); +return mount_single (fst, flags, data, data_size, ibmasmfs_fill_super); }static const struct super_operations ibmasmfs_s_ops = {
@@ -112,7 +114,8 @@ static struct file_system_type ibmasmfs_type = { };MODULE_ALIAS_FS ("ibmasmfs" ); -static int ibmasmfs_fill_super (struct super_block *sb,void *data,int silent) +static int ibmasmfs_fill_super (struct super_block *sb, +void *data,size_t data_size,int silent) {struct inode *root;
drivers/mtd/mtdsuper.c +15 -11
@@ -61,9 +61,9 @@ static int get_sb_mtd_set(struct super_block *sb, void *_mtd)* get a superblock on an MTD-backed filesystem */ static struct dentry *mount_mtd_aux (struct file_system_type *fs_type,int flags, -const char *dev_name,void *data, +const char *dev_name,void *data,size_t data_size,struct mtd_info *mtd, -int (*fill_super)(struct super_block *,void *,int )) +int (*fill_super)(struct super_block *,void *,size_t ,int )) {struct super_block *sb;int ret;
@@ -79,7 +79,7 @@ static struct dentry *mount_mtd_aux(struct file_system_type *fs_type, int flags,pr_debug ("MTDSB: New superblock for device %d (\"%s\")\n" , mtd->index, mtd->name); - ret =fill_super (sb, data, flags &SB_SILENT ?1 :0 ); + ret =fill_super (sb, data, data_size, flags &SB_SILENT ?1 :0 );if (ret <0 ) {deactivate_locked_super (sb);return ERR_PTR (ret);
@@ -105,8 +105,10 @@ static struct dentry *mount_mtd_aux(struct file_system_type *fs_type, int flags,* get a superblock on an MTD-backed filesystem by MTD device number */ static struct dentry *mount_mtd_nr (struct file_system_type *fs_type,int flags, -const char *dev_name,void *data,int mtdnr, -int (*fill_super)(struct super_block *,void *,int )) +const char *dev_name, +void *data,size_t data_size,int mtdnr, +int (*fill_super)(struct super_block *,void *, +size_t ,int )) {struct mtd_info *mtd;
@@ -116,15 +118,16 @@ static struct dentry *mount_mtd_nr(struct file_system_type *fs_type, int flags,return ERR_CAST (mtd); } -return mount_mtd_aux (fs_type, flags, dev_name, data, mtd, fill_super); +return mount_mtd_aux (fs_type, flags, dev_name, data, data_size, mtd, + fill_super); }/* * set up an MTD-based superblock */ struct dentry *mount_mtd (struct file_system_type *fs_type,int flags, -const char *dev_name,void *data, -int (*fill_super)(struct super_block *,void *,int )) +const char *dev_name,void *data,size_t data_size, +int (*fill_super)(struct super_block *,void *,size_t ,int )) {#ifdef CONFIG_BLOCK struct block_device *bdev;
@@ -153,7 +156,7 @@ struct dentry *mount_mtd(struct file_system_type *fs_type, int flags,if (!IS_ERR (mtd))return mount_mtd_aux ( fs_type, flags, - dev_name, data, mtd, + dev_name, data, data_size, mtd, fill_super); printk(KERN_NOTICE "MTD:"
@@ -170,7 +173,7 @@ struct dentry *mount_mtd(struct file_system_type *fs_type, int flags,pr_debug ("MTDSB: mtd%%d, mtdnr %d\n" , mtdnr);return mount_mtd_nr (fs_type, flags, - dev_name, data, + dev_name, data, data_size, mtdnr, fill_super); } }
@@ -197,7 +200,8 @@ struct dentry *mount_mtd(struct file_system_type *fs_type, int flags,if (major !=MTD_BLOCK_MAJOR ) goto not_an_MTD_device; -return mount_mtd_nr (fs_type, flags, dev_name, data, mtdnr, fill_super); +return mount_mtd_nr (fs_type, flags, dev_name, data, data_size, mtdnr, + fill_super); not_an_MTD_device:#endif /* CONFIG_BLOCK */
drivers/oprofile/oprofilefs.c +5 -3
@@ -238,7 +238,8 @@ struct dentry *oprofilefs_mkdir(struct dentry *parent, char const *name) } -static int oprofilefs_fill_super (struct super_block *sb,void *data,int silent) +static int oprofilefs_fill_super (struct super_block *sb, +void *data,size_t data_size,int silent) {struct inode *root_inode;
@@ -265,9 +266,10 @@ static int oprofilefs_fill_super(struct super_block *sb, void *data, int silent)static struct dentry *oprofilefs_mount (struct file_system_type *fs_type, -int flags,const char *dev_name,void *data) +int flags,const char *dev_name,void *data,size_t data_size) { -return mount_single (fs_type, flags, data, oprofilefs_fill_super); +return mount_single (fs_type, flags, data, data_size, + oprofilefs_fill_super); }
drivers/staging/lustre/lustre/llite/llite_internal.h +1 -1
@@ -810,7 +810,7 @@ int ll_iocontrol(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg);int ll_flush_ctx (struct inode *inode);void ll_umount_begin (struct super_block *sb); -int ll_remount_fs (struct super_block *sb,int *flags,char *data); +int ll_remount_fs (struct super_block *sb,int *flags,char *data,size_t data_size);int ll_show_options (struct seq_file *seq,struct dentry *dentry);void ll_dirty_page_discard_warn (struct page *page,int ioret); int ll_prep_inode(struct inode **inode, struct ptlrpc_request *req,
drivers/staging/lustre/lustre/llite/llite_lib.c +2 -1
@@ -2039,7 +2039,8 @@ void ll_umount_begin(struct super_block *sb)schedule (); } -int ll_remount_fs (struct super_block *sb,int *flags,char *data) +int ll_remount_fs (struct super_block *sb,int *flags, +char *data,size_t data_size) {struct ll_sb_info *sbi =ll_s2sbi (sb);char *profilenm =get_profile_name (sb);
drivers/staging/lustre/lustre/obdclass/obd_mount.c +4 -3
@@ -1112,7 +1112,8 @@ static int lmd_parse(char *options, struct lustre_mount_data *lmd)* and this is where we start setting things up. * @param data Mount options (e.g. -o flock,abort_recov) */ -static int lustre_fill_super (struct super_block *sb,void *lmd2_data,int silent) +static int lustre_fill_super (struct super_block *sb, +void *lmd2_data,size_t data_size,int silent) {struct lustre_mount_data *lmd;struct lustre_sb_info *lsi;
@@ -1207,9 +1208,9 @@ EXPORT_SYMBOL(lustre_register_super_ops);/***************** FS registration ******************/ static struct dentry *lustre_mount (struct file_system_type *fs_type,int flags, -const char *devname,void *data) +const char *devname,void *data,size_t data_size) { -return mount_nodev (fs_type, flags, data, lustre_fill_super); +return mount_nodev (fs_type, flags, data, data_size, lustre_fill_super); }static void lustre_kill_super (struct super_block *sb)
drivers/staging/ncpfs/inode.c +6 -4
@@ -101,7 +101,8 @@ static void destroy_inodecache(void)kmem_cache_destroy (ncp_inode_cachep); } -static int ncp_remount (struct super_block *sb,int *flags,char * data) +static int ncp_remount (struct super_block *sb,int *flags, +char *data,size_t data_size) {sync_filesystem (sb); *flags |=SB_NODIRATIME ;
@@ -466,7 +467,8 @@ static int ncp_parse_options(struct ncp_mount_data_kernel *data, char *options)return ret; } -static int ncp_fill_super (struct super_block *sb,void *raw_data,int silent) +static int ncp_fill_super (struct super_block *sb, +void *raw_data,size_t data_size,int silent) {struct ncp_mount_data_kernel data;struct ncp_server *server;
@@ -1023,9 +1025,9 @@ int ncp_notify_change(struct dentry *dentry, struct iattr *attr) }static struct dentry *ncp_mount (struct file_system_type *fs_type, -int flags,const char *dev_name,void *data) +int flags,const char *dev_name,void *data,size_t data_size) { -return mount_nodev (fs_type, flags, data, ncp_fill_super); +return mount_nodev (fs_type, flags, data, data_size, ncp_fill_super); }static struct file_system_type ncp_fs_type = {
drivers/usb/gadget/function/f_fs.c +4 -3
@@ -1355,7 +1355,8 @@ struct ffs_sb_fill_data {struct ffs_data *ffs_data; }; -static int ffs_sb_fill (struct super_block *sb,void *_data,int silent) +static int ffs_sb_fill (struct super_block *sb,void *_data,size_t data_size, +int silent) {struct ffs_sb_fill_data *data = _data;struct inode *inode;
@@ -1483,7 +1484,7 @@ static int ffs_fs_parse_opts(struct ffs_sb_fill_data *data, char *opts)static struct dentry *ffs_fs_mount (struct file_system_type *t,int flags, -const char *dev_name,void *opts) +const char *dev_name,void *opts,size_t data_size) {struct ffs_sb_fill_data data = { .perms = {
@@ -1525,7 +1526,7 @@ ffs_fs_mount(struct file_system_type *t, int flags, ffs->private_data = ffs_dev; data.ffs_data = ffs; - rv =mount_nodev (t, flags, &data, ffs_sb_fill); + rv =mount_nodev (t, flags, &data,sizeof (data), ffs_sb_fill);if (IS_ERR (rv) && data.ffs_data) {ffs_release_dev (data.ffs_data);ffs_data_put (data.ffs_data);
drivers/usb/gadget/legacy/inode.c +4 -3
@@ -1990,7 +1990,8 @@ static const struct super_operations gadget_fs_operations = { };static int -gadgetfs_fill_super (struct super_block *sb,void *opts,int silent) +gadgetfs_fill_super (struct super_block *sb,void *opts,size_t data_size, +int silent) {struct inode *inode;struct dev_data *dev;
@@ -2046,9 +2047,9 @@ gadgetfs_fill_super (struct super_block *sb, void *opts, int silent)/* "mount -t gadgetfs path /dev/gadget" ends up here */ static struct dentry *gadgetfs_mount (struct file_system_type *t,int flags, -const char *path,void *opts) +const char *path,void *opts,size_t data_size) { -return mount_single (t, flags, opts, gadgetfs_fill_super); +return mount_single (t, flags, opts, data_size, gadgetfs_fill_super); } static void
drivers/virtio/virtio_balloon.c +1 -1
@@ -526,7 +526,7 @@ static int virtballoon_migratepage(struct balloon_dev_info *vb_dev_info, }static struct dentry *balloon_mount (struct file_system_type *fs_type, -int flags,const char *dev_name,void *data) +int flags,const char *dev_name,void *data,size_t data_size) {static const struct dentry_operations ops = { .d_dname = simple_dname,
drivers/xen/xenfs/super.c +4 -3
@@ -42,7 +42,8 @@ static const struct file_operations capabilities_file_ops = { .llseek = default_llseek, }; -static int xenfs_fill_super (struct super_block *sb,void *data,int silent) +static int xenfs_fill_super (struct super_block *sb, +void *data,size_t data_size,int silent) {static const struct tree_descr xenfs_files[] = { [2 ] = {"xenbus" , &xen_xenbus_fops,S_IRUSR |S_IWUSR },
@@ -69,9 +70,9 @@ static int xenfs_fill_super(struct super_block *sb, void *data, int silent)static struct dentry *xenfs_mount (struct file_system_type *fs_type,int flags,const char *dev_name, -void *data) +void *data,size_t data_size) { -return mount_single (fs_type, flags, data, xenfs_fill_super); +return mount_single (fs_type, flags, data, data_size, xenfs_fill_super); }static struct file_system_type xenfs_type = {
fs/9p/vfs_super.c +1 -1
@@ -116,7 +116,7 @@ v9fs_fill_super(struct super_block *sb, struct v9fs_session_info *v9ses,*/ static struct dentry *v9fs_mount (struct file_system_type *fs_type,int flags, -const char *dev_name,void *data) +const char *dev_name,void *data,size_t data_size) {struct super_block *sb =NULL ;struct inode *inode =NULL ;
fs/adfs/super.c +5 -4
@@ -210,7 +210,7 @@ static int parse_options(struct super_block *sb, char *options)return 0 ; } -static int adfs_remount (struct super_block *sb,int *flags,char *data) +static int adfs_remount (struct super_block *sb,int *flags,char *data,size_t data_size) {sync_filesystem (sb); *flags |=SB_NODIRATIME ;
@@ -362,7 +362,8 @@ static inline unsigned long adfs_discsize(struct adfs_discrecord *dr, int block_return discsize; } -static int adfs_fill_super (struct super_block *sb,void *data,int silent) +static int adfs_fill_super (struct super_block *sb,void *data,size_t data_size, +int silent) {struct adfs_discrecord *dr;struct buffer_head *bh;
@@ -522,9 +523,9 @@ static int adfs_fill_super(struct super_block *sb, void *data, int silent) }static struct dentry *adfs_mount (struct file_system_type *fs_type, -int flags,const char *dev_name,void *data) +int flags,const char *dev_name,void *data,size_t data_size) { -return mount_bdev (fs_type, flags, dev_name, data, adfs_fill_super); +return mount_bdev (fs_type, flags, dev_name, data, data_size, adfs_fill_super); }static struct file_system_type adfs_fs_type = {
fs/affs/super.c +8 -5
@@ -26,7 +26,8 @@static int affs_statfs (struct dentry *dentry,struct kstatfs *buf);static int affs_show_options (struct seq_file *m,struct dentry *root); -static int affs_remount (struct super_block *sb,int *flags,char *data); +static int affs_remount (struct super_block *sb,int *flags, +char *data,size_t data_size);static void affs_commit_super (struct super_block *sb,int wait)
@@ -334,7 +335,8 @@ static int affs_show_options(struct seq_file *m, struct dentry *root)* hopefully have the guts to do so. Until then: sorry for the mess. */ -static int affs_fill_super (struct super_block *sb,void *data,int silent) +static int affs_fill_super (struct super_block *sb,void *data,size_t data_size, +int silent) {struct affs_sb_info *sbi;struct buffer_head *root_bh =NULL ;
@@ -549,7 +551,7 @@ static int affs_fill_super(struct super_block *sb, void *data, int silent) }static int -affs_remount (struct super_block *sb,int *flags,char *data) +affs_remount (struct super_block *sb,int *flags,char *data,size_t data_size) {struct affs_sb_info *sbi =AFFS_SB (sb);int blocksize;
@@ -632,9 +634,10 @@ affs_statfs(struct dentry *dentry, struct kstatfs *buf) }static struct dentry *affs_mount (struct file_system_type *fs_type, -int flags,const char *dev_name,void *data) +int flags,const char *dev_name,void *data,size_t data_size) { -return mount_bdev (fs_type, flags, dev_name, data, affs_fill_super); +return mount_bdev (fs_type, flags, dev_name, data, data_size, + affs_fill_super); }static void affs_kill_sb (struct super_block *sb)
fs/afs/mntpt.c +2 -1
@@ -152,7 +152,8 @@ static struct vfsmount *afs_mntpt_do_automount(struct dentry *mntpt)/* try and do the mount */ _debug ("--- attempting mount %s -o %s ---" , devname, options); - mnt =vfs_submount (mntpt, &afs_fs_type, devname, options); + mnt =vfs_submount (mntpt, &afs_fs_type, devname, + options,strlen (options) +1 );_debug ("--- mount result %p ---" , mnt);free_page ((unsigned long ) devname);
fs/afs/super.c +4 -2
@@ -31,7 +31,8 @@static void afs_i_init_once (void *foo);static struct dentry *afs_mount (struct file_system_type *fs_type, -int flags,const char *dev_name,void *data); +int flags,const char *dev_name, +void *data,size_t data_size);static void afs_kill_super (struct super_block *sb);static struct inode *afs_alloc_inode (struct super_block *sb);static void afs_destroy_inode (struct inode *inode);
@@ -462,7 +463,8 @@ static void afs_destroy_sbi(struct afs_super_info *as)* get an AFS superblock */ static struct dentry *afs_mount (struct file_system_type *fs_type, -int flags,const char *dev_name,void *options) +int flags,const char *dev_name, +void *options,size_t data_size) {struct afs_mount_params params;struct super_block *sb;
fs/aio.c +2 -1
@@ -243,7 +243,8 @@ static struct file *aio_private_file(struct kioctx *ctx, loff_t nr_pages) }static struct dentry *aio_mount (struct file_system_type *fs_type, -int flags,const char *dev_name,void *data) +int flags,const char *dev_name, +void *data,size_t data_size) {static const struct dentry_operations ops = { .d_dname = simple_dname,
fs/anon_inodes.c +2 -1
@@ -39,7 +39,8 @@ static const struct dentry_operations anon_inodefs_dentry_operations = { };static struct dentry *anon_inodefs_mount (struct file_system_type *fs_type, -int flags,const char *dev_name,void *data) +int flags,const char *dev_name, +void *data,size_t data_size) {return mount_pseudo (fs_type,"anon_inode:" ,NULL , &anon_inodefs_dentry_operations,ANON_INODE_FS_MAGIC );
fs/autofs4/autofs_i.h +1 -1
@@ -201,7 +201,7 @@ static inline void managed_dentry_clear_managed(struct dentry *dentry)/* Initializing function */ -int autofs4_fill_super (struct super_block *,void *,int ); +int autofs4_fill_super (struct super_block *,void *,size_t ,int );struct autofs_info *autofs4_new_ino (struct autofs_sb_info *);void autofs4_clean_ino (struct autofs_info *);
fs/autofs4/init.c +2 -2
@@ -11,9 +11,9 @@#include "autofs_i.h" static struct dentry *autofs_mount (struct file_system_type *fs_type, -int flags,const char *dev_name,void *data) +int flags,const char *dev_name,void *data,size_t data_size) { -return mount_nodev (fs_type, flags, data, autofs4_fill_super); +return mount_nodev (fs_type, flags, data, data_size, autofs4_fill_super); }static struct file_system_type autofs_fs_type = {
fs/autofs4/inode.c +2 -1
@@ -206,7 +206,8 @@ static int parse_options(char *options, int *pipefd, kuid_t *uid, kgid_t *gid,return (*pipefd <0 ); } -int autofs4_fill_super (struct super_block *s,void *data,int silent) +int autofs4_fill_super (struct super_block *s,void *data,size_t data_size, +int silent) {struct inode *root_inode;struct dentry *root;
fs/befs/linuxvfs.c +6 -5
@@ -52,7 +52,7 @@ static int befs_utf2nls(struct super_block *sb, const char *in, int in_len,static int befs_nls2utf (struct super_block *sb,const char *in,int in_len,char **out,int *out_len);static void befs_put_super (struct super_block *); -static int befs_remount (struct super_block *,int *,char *); +static int befs_remount (struct super_block *,int *,char *,size_t );static int befs_statfs (struct dentry *,struct kstatfs *);static int befs_show_options (struct seq_file *,struct dentry *);static int parse_options (char *,struct befs_mount_options *);
@@ -810,7 +810,7 @@ befs_put_super(struct super_block *sb)* Load a set of NLS translations if needed. */ static int -befs_fill_super (struct super_block *sb,void *data,int silent) +befs_fill_super (struct super_block *sb,void *data,size_t data_size,int silent) {struct buffer_head *bh;struct befs_sb_info *befs_sb;
@@ -942,7 +942,7 @@ befs_fill_super(struct super_block *sb, void *data, int silent) }static int -befs_remount (struct super_block *sb,int *flags,char *data) +befs_remount (struct super_block *sb,int *flags,char *data,size_t data_size) {sync_filesystem (sb);if (!(*flags &SB_RDONLY ))
@@ -976,9 +976,10 @@ befs_statfs(struct dentry *dentry, struct kstatfs *buf)static struct dentry *befs_mount (struct file_system_type *fs_type,int flags,const char *dev_name, -void *data) +void *data,size_t data_size) { -return mount_bdev (fs_type, flags, dev_name, data, befs_fill_super); +return mount_bdev (fs_type, flags, dev_name, data, data_size, + befs_fill_super); }static struct file_system_type befs_fs_type = {
fs/bfs/inode.c +5 -3
@@ -317,7 +317,8 @@ void bfs_dump_imap(const char *prefix, struct super_block *s)#endif } -static int bfs_fill_super (struct super_block *s,void *data,int silent) +static int bfs_fill_super (struct super_block *s,void *data,size_t data_size, +int silent) {struct buffer_head *bh, *sbh;struct bfs_super_block *bfs_sb;
@@ -460,9 +461,10 @@ static int bfs_fill_super(struct super_block *s, void *data, int silent) }static struct dentry *bfs_mount (struct file_system_type *fs_type, -int flags,const char *dev_name,void *data) +int flags,const char *dev_name,void *data,size_t data_size) { -return mount_bdev (fs_type, flags, dev_name, data, bfs_fill_super); +return mount_bdev (fs_type, flags, dev_name, data, data_size, + bfs_fill_super); }static struct file_system_type bfs_fs_type = {
fs/binfmt_misc.c +4 -3
@@ -814,7 +814,8 @@ static const struct super_operations s_ops = { .evict_inode = bm_evict_inode, }; -static int bm_fill_super (struct super_block *sb,void *data,int silent) +static int bm_fill_super (struct super_block *sb,void *data,size_t data_size, +int silent) {int err;static const struct tree_descr bm_files[] = {
@@ -830,9 +831,9 @@ static int bm_fill_super(struct super_block *sb, void *data, int silent) }static struct dentry *bm_mount (struct file_system_type *fs_type, -int flags,const char *dev_name,void *data) +int flags,const char *dev_name,void *data,size_t data_size) { -return mount_single (fs_type, flags, data, bm_fill_super); +return mount_single (fs_type, flags, data, data_size, bm_fill_super); }static struct linux_binfmt misc_format = {
fs/block_dev.c +1 -1
@@ -786,7 +786,7 @@ static const struct super_operations bdev_sops = { };static struct dentry *bd_mount (struct file_system_type *fs_type, -int flags,const char *dev_name,void *data) +int flags,const char *dev_name,void *data,size_t data_size) {struct dentry *dent; dent =mount_pseudo (fs_type,"bdev:" , &bdev_sops,NULL ,BDEVFS_MAGIC );
fs/btrfs/super.c +18 -12
@@ -64,7 +64,8 @@ static const struct super_operations btrfs_super_ops;static struct file_system_type btrfs_fs_type;static struct file_system_type btrfs_root_fs_type; -static int btrfs_remount (struct super_block *sb,int *flags,char *data); +static int btrfs_remount (struct super_block *sb,int *flags, +char *data,size_t data_size);const char *btrfs_decode_error (int errno) {
@@ -1453,7 +1454,7 @@ static struct dentry *mount_subvol(const char *subvol_name, u64 subvol_objectid,return root; } -static int parse_security_options (char *orig_opts, +static int parse_security_options (char *orig_opts,size_t data_size,struct security_mnt_opts *sec_opts) {char *secdata =NULL ;
@@ -1462,7 +1463,7 @@ static int parse_security_options(char *orig_opts, secdata =alloc_secdata ();if (!secdata)return -ENOMEM ; - ret =security_sb_copy_data (orig_opts, secdata); + ret =security_sb_copy_data (orig_opts, data_size, secdata);if (ret) {free_secdata (secdata);return ret;
@@ -1510,7 +1511,8 @@ static int setup_security_options(struct btrfs_fs_info *fs_info,* for multiple device setup. Make sure to keep it in sync. */ static struct dentry *btrfs_mount_root (struct file_system_type *fs_type, -int flags,const char *device_name,void *data) +int flags,const char *device_name, +void *data,size_t data_size) {struct block_device *bdev =NULL ;struct super_block *s;
@@ -1531,7 +1533,7 @@ static struct dentry *btrfs_mount_root(struct file_system_type *fs_type,security_init_mnt_opts (&new_sec_opts);if (data) { - error =parse_security_options (data, &new_sec_opts); + error =parse_security_options (data, data_size, &new_sec_opts);if (error)return ERR_PTR (error); }
@@ -1635,7 +1637,7 @@ static struct dentry *btrfs_mount_root(struct file_system_type *fs_type,* "btrfs subvolume set-default", mount_subvol() is called always. */ static struct dentry *btrfs_mount (struct file_system_type *fs_type,int flags, -const char *device_name,void *data) +const char *device_name,void *data,size_t data_size) {struct vfsmount *mnt_root;struct dentry *root;
@@ -1655,21 +1657,24 @@ static struct dentry *btrfs_mount(struct file_system_type *fs_type, int flags, }/* mount device's root (/) */ - mnt_root =vfs_kern_mount (&btrfs_root_fs_type, flags, device_name, data); + mnt_root =vfs_kern_mount (&btrfs_root_fs_type, flags, device_name, + data, data_size);if (PTR_ERR_OR_ZERO (mnt_root) == -EBUSY ) {if (flags &SB_RDONLY ) { mnt_root =vfs_kern_mount (&btrfs_root_fs_type, - flags & ~SB_RDONLY , device_name, data); + flags & ~SB_RDONLY , device_name, + data, data_size); }else { mnt_root =vfs_kern_mount (&btrfs_root_fs_type, - flags |SB_RDONLY , device_name, data); + flags |SB_RDONLY , device_name, + data, data_size);if (IS_ERR (mnt_root)) { root =ERR_CAST (mnt_root); goto out; }down_write (&mnt_root->mnt_sb->s_umount); - error =btrfs_remount (mnt_root->mnt_sb, &flags,NULL ); + error =btrfs_remount (mnt_root->mnt_sb, &flags,NULL ,0 );up_write (&mnt_root->mnt_sb->s_umount);if (error <0 ) { root =ERR_PTR (error);
@@ -1751,7 +1756,8 @@ static inline void btrfs_remount_cleanup(struct btrfs_fs_info *fs_info,clear_bit (BTRFS_FS_STATE_REMOUNTING , &fs_info->fs_state); } -static int btrfs_remount (struct super_block *sb,int *flags,char *data) +static int btrfs_remount (struct super_block *sb,int *flags, +char *data,size_t data_size) {struct btrfs_fs_info *fs_info =btrfs_sb (sb);struct btrfs_root *root = fs_info->tree_root;
@@ -1770,7 +1776,7 @@ static int btrfs_remount(struct super_block *sb, int *flags, char *data)struct security_mnt_opts new_sec_opts;security_init_mnt_opts (&new_sec_opts); - ret =parse_security_options (data, &new_sec_opts); + ret =parse_security_options (data, data_size, &new_sec_opts);if (ret) goto restore; ret = setup_security_options(fs_info, sb,
fs/btrfs/tests/btrfs-tests.c +1 -1
@@ -24,7 +24,7 @@ static const struct super_operations btrfs_test_super_ops = {static struct dentry *btrfs_test_mount (struct file_system_type *fs_type,int flags,const char *dev_name, -void *data) +void *data,size_t data_size) {return mount_pseudo (fs_type,"btrfs_test:" , &btrfs_test_super_ops,NULL ,BTRFS_TEST_MAGIC );
fs/ceph/super.c +2 -1
@@ -1002,7 +1002,8 @@ static int ceph_setup_bdi(struct super_block *sb, struct ceph_fs_client *fsc) }static struct dentry *ceph_mount (struct file_system_type *fs_type, -int flags,const char *dev_name,void *data) +int flags,const char *dev_name, +void *data,size_t data_size) {struct super_block *sb;struct ceph_fs_client *fsc;
fs/cifs/cifs_dfs_ref.c +2 -1
@@ -260,7 +260,8 @@ static struct vfsmount *cifs_dfs_do_refmount(struct dentry *mntpt,if (IS_ERR (mountdata))return (struct vfsmount *)mountdata; - mnt =vfs_submount (mntpt, &cifs_fs_type, devname, mountdata); + mnt =vfs_submount (mntpt, &cifs_fs_type, devname, + mountdata,strlen (mountdata) +1 );kfree (mountdata);kfree (devname);return mnt;
fs/cifs/cifsfs.c +3 -2
@@ -572,7 +572,8 @@ static int cifs_show_stats(struct seq_file *s, struct dentry *root) }#endif -static int cifs_remount (struct super_block *sb,int *flags,char *data) +static int cifs_remount (struct super_block *sb,int *flags, +char *data,size_t data_size) {sync_filesystem (sb); *flags |=SB_NODIRATIME ;
@@ -675,7 +676,7 @@ static int cifs_set_super(struct super_block *sb, void *data)static struct dentry *cifs_do_mount (struct file_system_type *fs_type, -int flags,const char *dev_name,void *data) +int flags,const char *dev_name,void *data,size_t data_size) {int rc;struct super_block *sb;
fs/coda/inode.c +7 -4
@@ -93,7 +93,8 @@ void coda_destroy_inodecache(void)kmem_cache_destroy (coda_inode_cachep); } -static int coda_remount (struct super_block *sb,int *flags,char *data) +static int coda_remount (struct super_block *sb,int *flags, +char *data,size_t data_size) {sync_filesystem (sb); *flags |=SB_NOATIME ;
@@ -150,7 +151,8 @@ static int get_device_index(struct coda_mount_data *data)return -1 ; } -static int coda_fill_super (struct super_block *sb,void *data,int silent) +static int coda_fill_super (struct super_block *sb,void *data,size_t data_size, +int silent) {struct inode *root =NULL ;struct venus_comm *vc;
@@ -316,9 +318,10 @@ static int coda_statfs(struct dentry *dentry, struct kstatfs *buf)/* init_coda: used by filesystems.c to register coda */ static struct dentry *coda_mount (struct file_system_type *fs_type, -int flags,const char *dev_name,void *data) +int flags,const char *dev_name, +void *data,size_t data_size) { -return mount_nodev (fs_type, flags, data, coda_fill_super); +return mount_nodev (fs_type, flags, data, data_size, coda_fill_super); }struct file_system_type coda_fs_type = {
fs/configfs/mount.c +4 -3
@@ -66,7 +66,8 @@ static struct configfs_dirent configfs_root = { .s_iattr = NULL, }; -static int configfs_fill_super (struct super_block *sb,void *data,int silent) +static int configfs_fill_super (struct super_block *sb, +void *data,size_t data_size,int silent) {struct inode *inode;struct dentry *root;
@@ -103,9 +104,9 @@ static int configfs_fill_super(struct super_block *sb, void *data, int silent) }static struct dentry *configfs_do_mount (struct file_system_type *fs_type, -int flags,const char *dev_name,void *data) +int flags,const char *dev_name,void *data,size_t data_size) { -return mount_single (fs_type, flags, data, configfs_fill_super); +return mount_single (fs_type, flags, data, data_size, configfs_fill_super); }static struct file_system_type configfs_fs_type = {
fs/cramfs/inode.c +10 -7
@@ -502,7 +502,8 @@ static void cramfs_kill_sb(struct super_block *sb)kfree (sbi); } -static int cramfs_remount (struct super_block *sb,int *flags,char *data) +static int cramfs_remount (struct super_block *sb,int *flags, +char *data,size_t data_size) {sync_filesystem (sb); *flags |=SB_RDONLY ;
@@ -603,7 +604,8 @@ static int cramfs_finalize_super(struct super_block *sb,return 0 ; } -static int cramfs_blkdev_fill_super (struct super_block *sb,void *data, +static int cramfs_blkdev_fill_super (struct super_block *sb, +void *data,size_t data_size,int silent) {struct cramfs_sb_info *sbi;
@@ -625,8 +627,8 @@ static int cramfs_blkdev_fill_super(struct super_block *sb, void *data,return cramfs_finalize_super (sb, &super.root); } -static int cramfs_mtd_fill_super (struct super_block *sb,void *data, -int silent) +static int cramfs_mtd_fill_super (struct super_block *sb, +void *data,size_t data_size,int silent) {struct cramfs_sb_info *sbi;struct cramfs_super super;
@@ -951,18 +953,19 @@ static const struct super_operations cramfs_ops = { };static struct dentry *cramfs_mount (struct file_system_type *fs_type,int flags, -const char *dev_name,void *data) +const char *dev_name, +void *data,size_t data_size) {struct dentry *ret =ERR_PTR (-ENOPROTOOPT );if (IS_ENABLED (CONFIG_CRAMFS_MTD )) { - ret =mount_mtd (fs_type, flags, dev_name, data, + ret =mount_mtd (fs_type, flags, dev_name, data, data_size, cramfs_mtd_fill_super);if (!IS_ERR (ret))return ret; }if (IS_ENABLED (CONFIG_CRAMFS_BLOCKDEV )) { - ret =mount_bdev (fs_type, flags, dev_name, data, + ret =mount_bdev (fs_type, flags, dev_name, data, data_size, cramfs_blkdev_fill_super); }return ret;
fs/debugfs/inode.c +8 -6
@@ -130,7 +130,8 @@ static int debugfs_apply_options(struct super_block *sb)return 0 ; } -static int debugfs_remount (struct super_block *sb,int *flags,char *data) +static int debugfs_remount (struct super_block *sb,int *flags, +char *data,size_t data_size) {int err;struct debugfs_fs_info *fsi = sb->s_fs_info;
@@ -190,7 +191,7 @@ static struct vfsmount *debugfs_automount(struct path *path) {debugfs_automount_t f; f = (debugfs_automount_t )path->dentry->d_fsdata; -return f (path->dentry,d_inode (path->dentry)->i_private); +return f (path->dentry,d_inode (path->dentry)->i_private,0 ); }static const struct dentry_operations debugfs_dops = {
@@ -199,7 +200,8 @@ static const struct dentry_operations debugfs_dops = { .d_automount = debugfs_automount, }; -static int debug_fill_super (struct super_block *sb,void *data,int silent) +static int debug_fill_super (struct super_block *sb, +void *data,size_t data_size,int silent) {static const struct tree_descr debug_files[] = {{"" }};struct debugfs_fs_info *fsi;
@@ -235,9 +237,9 @@ static int debug_fill_super(struct super_block *sb, void *data, int silent)static struct dentry *debug_mount (struct file_system_type *fs_type,int flags,const char *dev_name, -void *data) +void *data,size_t data_size) { -return mount_single (fs_type, flags, data, debug_fill_super); +return mount_single (fs_type, flags, data, data_size, debug_fill_super); }static struct file_system_type debug_fs_type = {
@@ -539,7 +541,7 @@ EXPORT_SYMBOL_GPL(debugfs_create_dir);struct dentry *debugfs_create_automount (const char *name,struct dentry *parent,debugfs_automount_t f, -void *data) +void *data,size_t data_size) {struct dentry *dentry =start_creating (name, parent);struct inode *inode;
fs/devpts/inode.c +6 -4
@@ -386,7 +386,8 @@ static void update_ptmx_mode(struct pts_fs_info *fsi) } } -static int devpts_remount (struct super_block *sb,int *flags,char *data) +static int devpts_remount (struct super_block *sb,int *flags, +char *data,size_t data_size) {int err;struct pts_fs_info *fsi =DEVPTS_SB (sb);
@@ -447,7 +448,8 @@ static void *new_pts_fs_info(struct super_block *sb) }static int -devpts_fill_super (struct super_block *s,void *data,int silent) +devpts_fill_super (struct super_block *s,void *data,size_t data_size, +int silent) {struct inode *inode;int error;
@@ -504,9 +506,9 @@ devpts_fill_super(struct super_block *s, void *data, int silent)* instance are independent of the PTYs in other devpts instances. */ static struct dentry *devpts_mount (struct file_system_type *fs_type, -int flags,const char *dev_name,void *data) +int flags,const char *dev_name,void *data,size_t data_size) { -return mount_nodev (fs_type, flags, data, devpts_fill_super); +return mount_nodev (fs_type, flags, data, data_size, devpts_fill_super); }static void devpts_kill_sb (struct super_block *sb)
fs/ecryptfs/main.c +1 -1
@@ -488,7 +488,7 @@ static struct file_system_type ecryptfs_fs_type;* @raw_data: The options passed into the kernel */ static struct dentry *ecryptfs_mount (struct file_system_type *fs_type,int flags, -const char *dev_name,void *raw_data) +const char *dev_name,void *raw_data,size_t data_size) {struct super_block *s;struct ecryptfs_sb_info *sbi;
fs/efivarfs/super.c +6 -3
@@ -191,7 +191,8 @@ static int efivarfs_destroy(struct efivar_entry *entry, void *data)return 0 ; } -static int efivarfs_fill_super (struct super_block *sb,void *data,int silent) +static int efivarfs_fill_super (struct super_block *sb, +void *data,size_t data_size,int silent) {struct inode *inode =NULL ;struct dentry *root;
@@ -227,9 +228,11 @@ static int efivarfs_fill_super(struct super_block *sb, void *data, int silent) }static struct dentry *efivarfs_mount (struct file_system_type *fs_type, -int flags,const char *dev_name,void *data) +int flags,const char *dev_name, +void *data,size_t data_size) { -return mount_single (fs_type, flags, data, efivarfs_fill_super); +return mount_single (fs_type, flags, data, data_size, + efivarfs_fill_super); }static void efivarfs_kill_sb (struct super_block *sb)
fs/efs/super.c +9 -5
@@ -19,12 +19,14 @@#include <linux/efs_fs_sb.h> static int efs_statfs (struct dentry *dentry,struct kstatfs *buf); -static int efs_fill_super (struct super_block *s,void *d,int silent); +static int efs_fill_super (struct super_block *s,void *d,size_t data_size, +int silent);static struct dentry *efs_mount (struct file_system_type *fs_type, -int flags,const char *dev_name,void *data) +int flags,const char *dev_name,void *data,size_t data_size) { -return mount_bdev (fs_type, flags, dev_name, data, efs_fill_super); +return mount_bdev (fs_type, flags, dev_name, data, data_size, + efs_fill_super); }static void efs_kill_sb (struct super_block *s)
@@ -113,7 +115,8 @@ static void destroy_inodecache(void)kmem_cache_destroy (efs_inode_cachep); } -static int efs_remount (struct super_block *sb,int *flags,char *data) +static int efs_remount (struct super_block *sb,int *flags, +char *data,size_t data_size) {sync_filesystem (sb); *flags |=SB_RDONLY ;
@@ -253,7 +256,8 @@ static int efs_validate_super(struct efs_sb_info *sb, struct efs_super *super) {return 0 ; } -static int efs_fill_super (struct super_block *s,void *d,int silent) +static int efs_fill_super (struct super_block *s,void *d,size_t data_size, +int silent) {struct efs_sb_info *sb;struct buffer_head *bh;
fs/exofs/super.c +4 -3
@@ -705,7 +705,8 @@ static int exofs_read_lookup_dev_table(struct exofs_sb_info *sbi,/* * Read the superblock from the OSD and fill in the fields */ -static int exofs_fill_super (struct super_block *sb,void *data,int silent) +static int exofs_fill_super (struct super_block *sb,void *data,size_t data_size, +int silent) {struct inode *root;struct exofs_mountopt *opts = data;
@@ -861,7 +862,7 @@ static int exofs_fill_super(struct super_block *sb, void *data, int silent)*/ static struct dentry *exofs_mount (struct file_system_type *type,int flags,const char *dev_name, -void *data) +void *data,size_t data_size) {struct exofs_mountopt opts;int ret;
@@ -872,7 +873,7 @@ static struct dentry *exofs_mount(struct file_system_type *type,if (!opts.dev_name) opts.dev_name = dev_name; -return mount_nodev (type, flags, &opts, exofs_fill_super); +return mount_nodev (type, flags, &opts,0 , exofs_fill_super); }/*
fs/ext2/super.c +9 -5
@@ -39,7 +39,8 @@#include "acl.h" static void ext2_write_super (struct super_block *sb); -static int ext2_remount (struct super_block * sb,int * flags,char * data); +static int ext2_remount (struct super_block * sb,int * flags, +char * data,size_t data_size);static int ext2_statfs (struct dentry * dentry,struct kstatfs * buf);static int ext2_sync_fs (struct super_block *sb,int wait);static int ext2_freeze (struct super_block *sb);
@@ -815,7 +816,8 @@ static unsigned long descriptor_loc(struct super_block *sb,return ext2_group_first_block_no (sb, bg) + has_super; } -static int ext2_fill_super (struct super_block *sb,void *data,int silent) +static int ext2_fill_super (struct super_block *sb,void *data,size_t data_size, +int silent) {struct dax_device *dax_dev =fs_dax_get_by_bdev (sb->s_bdev);struct buffer_head * bh;
@@ -1319,7 +1321,8 @@ static void ext2_write_super(struct super_block *sb)ext2_sync_fs (sb,1 ); } -static int ext2_remount (struct super_block * sb,int * flags,char * data) +static int ext2_remount (struct super_block * sb,int * flags, +char *data,size_t data_size) {struct ext2_sb_info * sbi =EXT2_SB (sb);struct ext2_super_block * es;
@@ -1473,9 +1476,10 @@ static int ext2_statfs (struct dentry * dentry, struct kstatfs * buf) }static struct dentry *ext2_mount (struct file_system_type *fs_type, -int flags,const char *dev_name,void *data) +int flags,const char *dev_name,void *data,size_t data_size) { -return mount_bdev (fs_type, flags, dev_name, data, ext2_fill_super); +return mount_bdev (fs_type, flags, dev_name, data, data_size, + ext2_fill_super); }#ifdef CONFIG_QUOTA
fs/ext4/super.c +10 -6
@@ -70,12 +70,13 @@ static void ext4_mark_recovery_complete(struct super_block *sb,static void ext4_clear_journal_err (struct super_block *sb,struct ext4_super_block *es);static int ext4_sync_fs (struct super_block *sb,int wait); -static int ext4_remount (struct super_block *sb,int *flags,char *data); +static int ext4_remount (struct super_block *sb,int *flags, +char *data,size_t data_size);static int ext4_statfs (struct dentry *dentry,struct kstatfs *buf);static int ext4_unfreeze (struct super_block *sb);static int ext4_freeze (struct super_block *sb);static struct dentry *ext4_mount (struct file_system_type *fs_type,int flags, -const char *dev_name,void *data); +const char *dev_name,void *data,size_t data_size);static inline int ext2_feature_set_ok (struct super_block *sb);static inline int ext3_feature_set_ok (struct super_block *sb);static int ext4_feature_set_ok (struct super_block *sb,int readonly);
@@ -3405,7 +3406,8 @@ static void ext4_set_resv_clusters(struct super_block *sb)atomic64_set (&sbi->s_resv_clusters, resv_clusters); } -static int ext4_fill_super (struct super_block *sb,void *data,int silent) +static int ext4_fill_super (struct super_block *sb,void *data,size_t data_size, +int silent) {struct dax_device *dax_dev =fs_dax_get_by_bdev (sb->s_bdev);char *orig_data =kstrdup (data,GFP_KERNEL );
@@ -4976,7 +4978,8 @@ struct ext4_mount_options {#endif }; -static int ext4_remount (struct super_block *sb,int *flags,char *data) +static int ext4_remount (struct super_block *sb,int *flags, +char *data,size_t data_size) {struct ext4_super_block *es;struct ext4_sb_info *sbi =EXT4_SB (sb);
@@ -5735,9 +5738,10 @@ static int ext4_get_next_id(struct super_block *sb, struct kqid *qid)#endif static struct dentry *ext4_mount (struct file_system_type *fs_type,int flags, -const char *dev_name,void *data) +const char *dev_name,void *data,size_t data_size) { -return mount_bdev (fs_type, flags, dev_name, data, ext4_fill_super); +return mount_bdev (fs_type, flags, dev_name, data, data_size, + ext4_fill_super); }#if !defined(CONFIG_EXT2_FS ) && !defined(CONFIG_EXT2_FS_MODULE ) && defined(CONFIG_EXT4_USE_FOR_EXT2 )
fs/f2fs/super.c +7 -4
@@ -1384,7 +1384,8 @@ static void default_options(struct f2fs_sb_info *sbi)#ifdef CONFIG_QUOTA static int f2fs_enable_quotas (struct super_block *sb);#endif -static int f2fs_remount (struct super_block *sb,int *flags,char *data) +static int f2fs_remount (struct super_block *sb,int *flags, +char *data,size_t data_size) {struct f2fs_sb_info *sbi =F2FS_SB (sb);struct f2fs_mount_info org_mount_opt;
@@ -2589,7 +2590,8 @@ static void f2fs_tuning_parameters(struct f2fs_sb_info *sbi) } } -static int f2fs_fill_super (struct super_block *sb,void *data,int silent) +static int f2fs_fill_super (struct super_block *sb,void *data,size_t data_size, +int silent) {struct f2fs_sb_info *sbi;struct f2fs_super_block *raw_super;
@@ -3015,9 +3017,10 @@ static int f2fs_fill_super(struct super_block *sb, void *data, int silent) }static struct dentry *f2fs_mount (struct file_system_type *fs_type,int flags, -const char *dev_name,void *data) +const char *dev_name,void *data,size_t data_size) { -return mount_bdev (fs_type, flags, dev_name, data, f2fs_fill_super); +return mount_bdev (fs_type, flags, dev_name, data, data_size, + f2fs_fill_super); }static void kill_f2fs_super (struct super_block *sb)
fs/fat/inode.c +2 -1
@@ -778,7 +778,8 @@ static void __exit fat_destroy_inodecache(void)kmem_cache_destroy (fat_inode_cachep); } -static int fat_remount (struct super_block *sb,int *flags,char *data) +static int fat_remount (struct super_block *sb,int *flags, +char *data,size_t data_size) {bool new_rdonly;struct msdos_sb_info *sbi =MSDOS_SB (sb);
fs/fat/namei_msdos.c +5 -3
@@ -646,16 +646,18 @@ static void setup(struct super_block *sb) sb->s_flags |=SB_NOATIME ; } -static int msdos_fill_super (struct super_block *sb,void *data,int silent) +static int msdos_fill_super (struct super_block *sb,void *data,size_t data_size, +int silent) {return fat_fill_super (sb, data, silent,0 , setup); }static struct dentry *msdos_mount (struct file_system_type *fs_type,int flags,const char *dev_name, -void *data) +void *data,size_t data_size) { -return mount_bdev (fs_type, flags, dev_name, data, msdos_fill_super); +return mount_bdev (fs_type, flags, dev_name, data, data_size, + msdos_fill_super); }static struct file_system_type msdos_fs_type = {
fs/fat/namei_vfat.c +5 -3
@@ -1043,16 +1043,18 @@ static void setup(struct super_block *sb) sb->s_d_op = &vfat_dentry_ops; } -static int vfat_fill_super (struct super_block *sb,void *data,int silent) +static int vfat_fill_super (struct super_block *sb,void *data,size_t data_size, +int silent) {return fat_fill_super (sb, data, silent,1 , setup); }static struct dentry *vfat_mount (struct file_system_type *fs_type,int flags,const char *dev_name, -void *data) +void *data,size_t data_size) { -return mount_bdev (fs_type, flags, dev_name, data, vfat_fill_super); +return mount_bdev (fs_type, flags, dev_name, data, data_size, + vfat_fill_super); }static struct file_system_type vfat_fs_type = {
fs/freevxfs/vxfs_super.c +8 -4
@@ -113,7 +113,8 @@ vxfs_statfs(struct dentry *dentry, struct kstatfs *bufp)return 0 ; } -static int vxfs_remount (struct super_block *sb,int *flags,char *data) +static int vxfs_remount (struct super_block *sb,int *flags, +char *data,size_t data_size) {sync_filesystem (sb); *flags |=SB_RDONLY ;
@@ -199,6 +200,7 @@ static int vxfs_try_sb_magic(struct super_block *sbp, int silent,* vxfs_read_super - read superblock into memory and initialize filesystem * @sbp: VFS superblock (to fill) * @dp: fs private mount data +* @data_size: size of mount data * @silent: do not complain loudly when sth is wrong * * Description:
@@ -211,7 +213,8 @@ static int vxfs_try_sb_magic(struct super_block *sbp, int silent,* Locking: * We are under @sbp->s_lock. */ -static int vxfs_fill_super (struct super_block *sbp,void *dp,int silent) +static int vxfs_fill_super (struct super_block *sbp,void *dp,size_t data_size, +int silent) {struct vxfs_sb_info *infp;struct vxfs_sb *rsbp;
@@ -312,9 +315,10 @@ static int vxfs_fill_super(struct super_block *sbp, void *dp, int silent)* The usual module blurb. */ static struct dentry *vxfs_mount (struct file_system_type *fs_type, -int flags,const char *dev_name,void *data) +int flags,const char *dev_name,void *data,size_t data_size) { -return mount_bdev (fs_type, flags, dev_name, data, vxfs_fill_super); +return mount_bdev (fs_type, flags, dev_name, data, data_size, + vxfs_fill_super); }static struct file_system_type vxfs_fs_type = {
fs/fuse/control.c +6 -3
@@ -290,7 +290,8 @@ void fuse_ctl_remove_conn(struct fuse_conn *fc)drop_nlink (d_inode (fuse_control_sb->s_root)); } -static int fuse_ctl_fill_super (struct super_block *sb,void *data,int silent) +static int fuse_ctl_fill_super (struct super_block *sb, +void *data,size_t data_size,int silent) {static const struct tree_descr empty_descr = {"" };struct fuse_conn *fc;
@@ -317,9 +318,11 @@ static int fuse_ctl_fill_super(struct super_block *sb, void *data, int silent) }static struct dentry *fuse_ctl_mount (struct file_system_type *fs_type, -int flags,const char *dev_name,void *raw_data) +int flags,const char *dev_name, +void *raw_data,size_t data_size) { -return mount_single (fs_type, flags, raw_data, fuse_ctl_fill_super); +return mount_single (fs_type, flags, raw_data, data_size, + fuse_ctl_fill_super); }static void fuse_ctl_kill_sb (struct super_block *sb)
fs/fuse/inode.c +10 -6
@@ -138,7 +138,8 @@ static void fuse_evict_inode(struct inode *inode) } } -static int fuse_remount_fs (struct super_block *sb,int *flags,char *data) +static int fuse_remount_fs (struct super_block *sb,int *flags, +char *data,size_t data_size) {sync_filesystem (sb);if (*flags &SB_MANDLOCK )
@@ -1043,7 +1044,8 @@ void fuse_dev_free(struct fuse_dev *fud) }EXPORT_SYMBOL_GPL (fuse_dev_free); -static int fuse_fill_super (struct super_block *sb,void *data,int silent) +static int fuse_fill_super (struct super_block *sb,void *data,size_t data_size, +int silent) {struct fuse_dev *fud;struct fuse_conn *fc;
@@ -1187,9 +1189,10 @@ static int fuse_fill_super(struct super_block *sb, void *data, int silent)static struct dentry *fuse_mount (struct file_system_type *fs_type,int flags,const char *dev_name, -void *raw_data) +void *raw_data,size_t data_size) { -return mount_nodev (fs_type, flags, raw_data, fuse_fill_super); +return mount_nodev (fs_type, flags, raw_data, data_size, + fuse_fill_super); }static void fuse_kill_sb_anon (struct super_block *sb)
@@ -1217,9 +1220,10 @@ MODULE_ALIAS_FS("fuse");#ifdef CONFIG_BLOCK static struct dentry *fuse_mount_blk (struct file_system_type *fs_type,int flags,const char *dev_name, -void *raw_data) +void *raw_data,size_t data_size) { -return mount_bdev (fs_type, flags, dev_name, raw_data, fuse_fill_super); +return mount_bdev (fs_type, flags, dev_name, raw_data, data_size, + fuse_fill_super); }static void fuse_kill_sb_blk (struct super_block *sb)
fs/gfs2/ops_fstype.c +4 -2
@@ -1239,6 +1239,7 @@ static int test_gfs2_super(struct super_block *s, void *ptr)* @flags: Mount flags * @dev_name: The name of the device * @data: The mount arguments +* @data_size: The size of the mount arguments * * Q. Why not use get_sb_bdev() ? * A. We need to select one of two root directories to mount, independent
@@ -1248,7 +1249,7 @@ static int test_gfs2_super(struct super_block *s, void *ptr)*/ static struct dentry *gfs2_mount (struct file_system_type *fs_type,int flags, -const char *dev_name,void *data) +const char *dev_name,void *data,size_t data_size) {struct block_device *bdev;struct super_block *s;
@@ -1345,7 +1346,8 @@ static int set_meta_super(struct super_block *s, void *ptr) }static struct dentry *gfs2_mount_meta (struct file_system_type *fs_type, -int flags,const char *dev_name,void *data) +int flags,const char *dev_name, +void *data,size_t data_size) {struct super_block *s;struct gfs2_sbd *sdp;
fs/gfs2/super.c +3 -1
@@ -1228,11 +1228,13 @@ static int gfs2_statfs(struct dentry *dentry, struct kstatfs *buf)* @sb: the filesystem * @flags: the remount flags * @data: extra data passed in (not used right now) +* @data_size: size of the extra data * * Returns: errno */ -static int gfs2_remount_fs (struct super_block *sb,int *flags,char *data) +static int gfs2_remount_fs (struct super_block *sb,int *flags, +char *data,size_t data_size) {struct gfs2_sbd *sdp = sb->s_fs_info;struct gfs2_args args = sdp->sd_args;/* Default to current settings */
fs/hfs/super.c +8 -4
@@ -111,7 +111,8 @@ static int hfs_statfs(struct dentry *dentry, struct kstatfs *buf)return 0 ; } -static int hfs_remount (struct super_block *sb,int *flags,char *data) +static int hfs_remount (struct super_block *sb,int *flags, +char *data,size_t data_size) {sync_filesystem (sb); *flags |=SB_NODIRATIME ;
@@ -382,7 +383,8 @@ static int parse_options(char *options, struct hfs_sb_info *hsb)* hfs_btree_init() to get the necessary data about the extents and * catalog B-trees and, finally, reading the root inode into memory. */ -static int hfs_fill_super (struct super_block *sb,void *data,int silent) +static int hfs_fill_super (struct super_block *sb,void *data,size_t data_size, +int silent) {struct hfs_sb_info *sbi;struct hfs_find_data fd;
@@ -458,9 +460,11 @@ static int hfs_fill_super(struct super_block *sb, void *data, int silent) }static struct dentry *hfs_mount (struct file_system_type *fs_type, -int flags,const char *dev_name,void *data) +int flags,const char *dev_name, +void *data,size_t data_size) { -return mount_bdev (fs_type, flags, dev_name, data, hfs_fill_super); +return mount_bdev (fs_type, flags, dev_name, data, data_size, + hfs_fill_super); }static struct file_system_type hfs_fs_type = {
fs/hfsplus/super.c +8 -4
@@ -326,7 +326,8 @@ static int hfsplus_statfs(struct dentry *dentry, struct kstatfs *buf)return 0 ; } -static int hfsplus_remount (struct super_block *sb,int *flags,char *data) +static int hfsplus_remount (struct super_block *sb,int *flags, +char *data,size_t data_size) {sync_filesystem (sb);if ((bool )(*flags &SB_RDONLY ) ==sb_rdonly (sb))
@@ -371,7 +372,8 @@ static const struct super_operations hfsplus_sops = { .show_options = hfsplus_show_options, }; -static int hfsplus_fill_super (struct super_block *sb,void *data,int silent) +static int hfsplus_fill_super (struct super_block *sb, +void *data,size_t data_size,int silent) {struct hfsplus_vh *vhdr;struct hfsplus_sb_info *sbi;
@@ -640,9 +642,11 @@ static void hfsplus_destroy_inode(struct inode *inode)#define HFSPLUS_INODE_SIZE sizeof(struct hfsplus_inode_info)static struct dentry *hfsplus_mount (struct file_system_type *fs_type, -int flags,const char *dev_name,void *data) +int flags,const char *dev_name, +void *data,size_t data_size) { -return mount_bdev (fs_type, flags, dev_name, data, hfsplus_fill_super); +return mount_bdev (fs_type, flags, dev_name, data, data_size, + hfsplus_fill_super); }static struct file_system_type hfsplus_fs_type = {
fs/hostfs/hostfs_kern.c +4 -3
@@ -923,7 +923,8 @@ static const struct inode_operations hostfs_link_iops = { .get_link = hostfs_get_link, }; -static int hostfs_fill_sb_common (struct super_block *sb,void *d,int silent) +static int hostfs_fill_sb_common (struct super_block *sb, +void *d,size_t data_size,int silent) {struct inode *root_inode;char *host_root_path, *req_root = d;
@@ -983,9 +984,9 @@ static int hostfs_fill_sb_common(struct super_block *sb, void *d, int silent)static struct dentry *hostfs_read_sb (struct file_system_type *type,int flags,const char *dev_name, -void *data) +void *data,size_t data_size) { -return mount_nodev (type, flags, data, hostfs_fill_sb_common); +return mount_nodev (type, flags, data, data_size, hostfs_fill_sb_common); }static void hostfs_kill_sb (struct super_block *s)
fs/hpfs/super.c +7 -4
@@ -445,7 +445,8 @@ HPFS filesystem options:\n\ \n"); } -static int hpfs_remount_fs (struct super_block *s,int *flags,char *data) +static int hpfs_remount_fs (struct super_block *s,int *flags, +char *data,size_t data_size) {kuid_t uid;kgid_t gid;
@@ -540,7 +541,8 @@ static const struct super_operations hpfs_sops = .show_options = hpfs_show_options, }; -static int hpfs_fill_super (struct super_block *s,void *options,int silent) +static int hpfs_fill_super (struct super_block *s, +void *options,size_t data_size,int silent) {struct buffer_head *bh0, *bh1, *bh2;struct hpfs_boot_block *bootblock;
@@ -757,9 +759,10 @@ bail2: brelse(bh0); }static struct dentry *hpfs_mount (struct file_system_type *fs_type, -int flags,const char *dev_name,void *data) +int flags,const char *dev_name,void *data,size_t data_size) { -return mount_bdev (fs_type, flags, dev_name, data, hpfs_fill_super); +return mount_bdev (fs_type, flags, dev_name, data, data_size, + hpfs_fill_super); }static struct file_system_type hpfs_fs_type = {
fs/hugetlbfs/inode.c +8 -5
@@ -1220,7 +1220,8 @@ hugetlbfs_parse_options(char *options, struct hugetlbfs_config *pconfig) }static int -hugetlbfs_fill_super (struct super_block *sb,void *data,int silent) +hugetlbfs_fill_super (struct super_block *sb,void *data,size_t data_size, +int silent) {int ret;struct hugetlbfs_config config;
@@ -1279,9 +1280,10 @@ hugetlbfs_fill_super(struct super_block *sb, void *data, int silent) }static struct dentry *hugetlbfs_mount (struct file_system_type *fs_type, -int flags,const char *dev_name,void *data) +int flags,const char *dev_name,void *data,size_t data_size) { -return mount_nodev (fs_type, flags, data, hugetlbfs_fill_super); +return mount_nodev (fs_type, flags, data, data_size, + hugetlbfs_fill_super); }static struct file_system_type hugetlbfs_fs_type = {
@@ -1420,10 +1422,11 @@ static int __init init_hugetlbfs_fs(void)for_each_hstate (h) {char buf[50 ];unsigned ps_kb =1U << (h->order +PAGE_SHIFT -10 ); +int n; -snprintf (buf,sizeof (buf),"pagesize=%uK" , ps_kb); + n =snprintf (buf,sizeof (buf),"pagesize=%uK" , ps_kb); hugetlbfs_vfsmount[i] =kern_mount_data (&hugetlbfs_fs_type, - buf); + buf, n +1 );if (IS_ERR (hugetlbfs_vfsmount[i])) { pr_err("Cannot mount internal hugetlbfs for "
fs/internal.h +2 -2
@@ -98,10 +98,10 @@ extern struct file *get_empty_filp(void);/* * super.c */ -extern int do_remount_sb (struct super_block *,int ,void *,int ); +extern int do_remount_sb (struct super_block *,int ,void *,size_t ,int );extern bool trylock_super (struct super_block *sb);extern struct dentry *mount_fs (struct file_system_type *, -int ,const char *,void *); +int ,const char *,void *,size_t );extern struct super_block *user_get_super (dev_t );/*
fs/isofs/inode.c +7 -4
@@ -111,7 +111,8 @@ static void destroy_inodecache(void)kmem_cache_destroy (isofs_inode_cachep); } -static int isofs_remount (struct super_block *sb,int *flags,char *data) +static int isofs_remount (struct super_block *sb,int *flags, +char *data,size_t data_size) {sync_filesystem (sb);if (!(*flags &SB_RDONLY ))
@@ -619,7 +620,8 @@ static bool rootdir_empty(struct super_block *sb, unsigned long block)* Note: a check_disk_change() has been done immediately prior * to this call, so we don't need to check again. */ -static int isofs_fill_super (struct super_block *s,void *data,int silent) +static int isofs_fill_super (struct super_block *s,void *data,size_t data_size, +int silent) {struct buffer_head *bh =NULL , *pri_bh =NULL ;struct hs_primary_descriptor *h_pri =NULL ;
@@ -1558,9 +1560,10 @@ struct inode *__isofs_iget(struct super_block *sb, }static struct dentry *isofs_mount (struct file_system_type *fs_type, -int flags,const char *dev_name,void *data) +int flags,const char *dev_name,void *data,size_t data_size) { -return mount_bdev (fs_type, flags, dev_name, data, isofs_fill_super); +return mount_bdev (fs_type, flags, dev_name, data, data_size, + isofs_fill_super); }static struct file_system_type iso9660_fs_type = {
fs/jffs2/super.c +6 -4
@@ -238,7 +238,8 @@ static int jffs2_parse_options(struct jffs2_sb_info *c, char *data)return 0 ; } -static int jffs2_remount_fs (struct super_block *sb,int *flags,char *data) +static int jffs2_remount_fs (struct super_block *sb,int *flags, +char *data,size_t data_size) {struct jffs2_sb_info *c =JFFS2_SB_INFO (sb);int err;
@@ -267,7 +268,8 @@ static const struct super_operations jffs2_super_operations =/* * fill in the superblock */ -static int jffs2_fill_super (struct super_block *sb,void *data,int silent) +static int jffs2_fill_super (struct super_block *sb, +void *data,size_t data_size,int silent) {struct jffs2_sb_info *c;int ret;
@@ -312,9 +314,9 @@ static int jffs2_fill_super(struct super_block *sb, void *data, int silent)static struct dentry *jffs2_mount (struct file_system_type *fs_type,int flags,const char *dev_name, -void *data) +void *data,size_t data_size) { -return mount_mtd (fs_type, flags, dev_name, data, jffs2_fill_super); +return mount_mtd (fs_type, flags, dev_name, data, data_size, jffs2_fill_super); }static void jffs2_put_super (struct super_block *sb)
fs/jfs/super.c +7 -4
@@ -456,7 +456,8 @@ static int parse_options(char *options, struct super_block *sb, s64 *newLVSize,return 0 ; } -static int jfs_remount (struct super_block *sb,int *flags,char *data) +static int jfs_remount (struct super_block *sb,int *flags, +char *data,size_t data_size) {s64 newLVSize =0 ;int rc =0 ;
@@ -516,7 +517,8 @@ static int jfs_remount(struct super_block *sb, int *flags, char *data)return 0 ; } -static int jfs_fill_super (struct super_block *sb,void *data,int silent) +static int jfs_fill_super (struct super_block *sb,void *data,size_t data_size, +int silent) {struct jfs_sb_info *sbi;struct inode *inode;
@@ -698,9 +700,10 @@ static int jfs_unfreeze(struct super_block *sb) }static struct dentry *jfs_do_mount (struct file_system_type *fs_type, -int flags,const char *dev_name,void *data) +int flags,const char *dev_name,void *data,size_t data_size) { -return mount_bdev (fs_type, flags, dev_name, data, jfs_fill_super); +return mount_bdev (fs_type, flags, dev_name, data, data_size, + jfs_fill_super); }static int jfs_sync_fs (struct super_block *sb,int wait)
fs/kernfs/mount.c +2 -1
@@ -22,7 +22,8 @@struct kmem_cache *kernfs_node_cache; -static int kernfs_sop_remount_fs (struct super_block *sb,int *flags,char *data) +static int kernfs_sop_remount_fs (struct super_block *sb,int *flags, +char *data,size_t data_size) {struct kernfs_root *root =kernfs_info (sb)->root;struct kernfs_syscall_ops *scops = root->syscall_ops;
fs/libfs.c +1 -1
@@ -578,7 +578,7 @@ int simple_pin_fs(struct file_system_type *type, struct vfsmount **mount, int *cspin_lock (&pin_fs_lock);if (unlikely (!*mount)) {spin_unlock (&pin_fs_lock); - mnt =vfs_kern_mount (type,SB_KERNMOUNT , type->name,NULL ); + mnt =vfs_kern_mount (type,SB_KERNMOUNT , type->name,NULL ,0 );if (IS_ERR (mnt))return PTR_ERR (mnt);spin_lock (&pin_fs_lock);
fs/minix/inode.c +9 -5
@@ -22,7 +22,8 @@static int minix_write_inode (struct inode *inode,struct writeback_control *wbc);static int minix_statfs (struct dentry *dentry,struct kstatfs *buf); -static int minix_remount (struct super_block * sb,int * flags,char * data); +static int minix_remount (struct super_block * sb,int * flags, +char * data,size_t data_size);static void minix_evict_inode (struct inode *inode) {
@@ -118,7 +119,8 @@ static const struct super_operations minix_sops = { .remount_fs = minix_remount, }; -static int minix_remount (struct super_block * sb,int * flags,char * data) +static int minix_remount (struct super_block * sb,int * flags, +char * data,size_t data_size) {struct minix_sb_info * sbi =minix_sb (sb);struct minix_super_block * ms;
@@ -155,7 +157,8 @@ static int minix_remount (struct super_block * sb, int * flags, char * data)return 0 ; } -static int minix_fill_super (struct super_block *s,void *data,int silent) +static int minix_fill_super (struct super_block *s,void *data,size_t data_size, +int silent) {struct buffer_head *bh;struct buffer_head **map;
@@ -651,9 +654,10 @@ void minix_truncate(struct inode * inode) }static struct dentry *minix_mount (struct file_system_type *fs_type, -int flags,const char *dev_name,void *data) +int flags,const char *dev_name,void *data,size_t data_size) { -return mount_bdev (fs_type, flags, dev_name, data, minix_fill_super); +return mount_bdev (fs_type, flags, dev_name, data, data_size, + minix_fill_super); }static struct file_system_type minix_fs_type = {
fs/namespace.c +21 -17
@@ -1020,7 +1020,8 @@ static struct mount *skip_mnt_tree(struct mount *p) }struct vfsmount * -vfs_kern_mount (struct file_system_type *type,int flags,const char *name,void *data) +vfs_kern_mount (struct file_system_type *type,int flags,const char *name, +void *data,size_t data_size) {struct mount *mnt;struct dentry *root;
@@ -1035,7 +1036,7 @@ vfs_kern_mount(struct file_system_type *type, int flags, const char *name, voidif (flags &SB_KERNMOUNT ) mnt->mnt.mnt_flags =MNT_INTERNAL ; - root =mount_fs (type, flags, name, data); + root =mount_fs (type, flags, name, data, data_size);if (IS_ERR (root)) {mnt_free_id (mnt);free_vfsmnt (mnt);
@@ -1055,7 +1056,7 @@ EXPORT_SYMBOL_GPL(vfs_kern_mount);struct vfsmount *vfs_submount (const struct dentry *mountpoint,struct file_system_type *type, -const char *name,void *data) +const char *name,void *data,size_t data_size) {/* Until it is worked out how to pass the user namespace * through from the parent mount to the submount don't support
@@ -1064,7 +1065,7 @@ vfs_submount(const struct dentry *mountpoint, struct file_system_type *type,if (mountpoint->d_sb->s_user_ns != &init_user_ns)return ERR_PTR (-EPERM ); -return vfs_kern_mount (type,SB_SUBMOUNT , name, data); +return vfs_kern_mount (type,SB_SUBMOUNT , name, data, data_size); }EXPORT_SYMBOL_GPL (vfs_submount);
@@ -1595,7 +1596,7 @@ static int do_umount(struct mount *mnt, int flags)return -EPERM ;down_write (&sb->s_umount);if (!sb_rdonly (sb)) - retval =do_remount_sb (sb,SB_RDONLY ,NULL ,0 ); + retval =do_remount_sb (sb,SB_RDONLY ,NULL ,0 ,0 );up_write (&sb->s_umount);return retval; }
@@ -2288,7 +2289,7 @@ static int change_mount_flags(struct vfsmount *mnt, int ms_flags)* on it - tough luck. */ static int do_remount (struct path *path,int ms_flags,int sb_flags, -int mnt_flags,void *data) +int mnt_flags,void *data,size_t data_size) {int err;struct super_block *sb = path->mnt->mnt_sb;
@@ -2327,7 +2328,7 @@ static int do_remount(struct path *path, int ms_flags, int sb_flags,return -EPERM ; } - err =security_sb_remount (sb, data); + err =security_sb_remount (sb, data, data_size);if (err)return err;
@@ -2337,7 +2338,7 @@ static int do_remount(struct path *path, int ms_flags, int sb_flags,else if (!capable (CAP_SYS_ADMIN )) err = -EPERM ;else - err =do_remount_sb (sb, sb_flags, data,0 ); + err =do_remount_sb (sb, sb_flags, data, data_size,0 );if (!err) {lock_mount_hash (); mnt_flags |= mnt->mnt.mnt_flags & ~MNT_USER_SETTABLE_MASK ;
@@ -2503,7 +2504,8 @@ static bool mount_too_revealing(struct vfsmount *mnt, int *new_mnt_flags);* namespace's tree */ static int do_new_mount (struct path *path,const char *fstype,int sb_flags, -int mnt_flags,const char *name,void *data) +int mnt_flags,const char *name, +void *data,size_t data_size) {struct file_system_type *type;struct vfsmount *mnt;
@@ -2516,7 +2518,7 @@ static int do_new_mount(struct path *path, const char *fstype, int sb_flags,if (!type)return -ENODEV ; - mnt =vfs_kern_mount (type, sb_flags, name, data); + mnt =vfs_kern_mount (type, sb_flags, name, data, data_size);if (!IS_ERR (mnt) && (type->fs_flags &FS_HAS_SUBTYPE ) && !mnt->mnt_sb->s_subtype) mnt =fs_set_subtype (mnt, fstype);
@@ -2772,6 +2774,7 @@ long do_mount(const char *dev_name, const char __user *dir_name, {struct path path;unsigned int mnt_flags =0 , sb_flags; +size_t data_size = data_page ?PAGE_SIZE :0 ;int retval =0 ;/* Discard magic */
@@ -2790,8 +2793,8 @@ long do_mount(const char *dev_name, const char __user *dir_name,if (retval)return retval; - retval =security_sb_mount (dev_name, &path, - type_page, flags, data_page); + retval =security_sb_mount (dev_name, &path, type_page, flags, + data_page, data_size);if (!retval && !may_mount ()) retval = -EPERM ;if (!retval && (flags &SB_MANDLOCK ) && !may_mandlock ())
@@ -2838,7 +2841,7 @@ long do_mount(const char *dev_name, const char __user *dir_name,if (flags &MS_REMOUNT ) retval =do_remount (&path, flags, sb_flags, mnt_flags, - data_page); + data_page, data_size);else if (flags &MS_BIND ) retval =do_loopback (&path, dev_name, flags &MS_REC );else if (flags & (MS_SHARED |MS_PRIVATE |MS_SLAVE |MS_UNBINDABLE ))
@@ -2847,7 +2850,7 @@ long do_mount(const char *dev_name, const char __user *dir_name, retval =do_move_mount (&path, dev_name); else retval =do_new_mount (&path, type_page, sb_flags, mnt_flags, - dev_name, data_page); + dev_name, data_page, data_size); dput_out:path_put (&path);return retval;
@@ -3237,7 +3240,7 @@ static void __init init_mount_tree(void) type =get_fs_type ("rootfs" );if (!type)panic ("Can't find rootfs type" ); - mnt =vfs_kern_mount (type,0 ,"rootfs" ,NULL ); + mnt =vfs_kern_mount (type,0 ,"rootfs" ,NULL ,0 );put_filesystem (type);if (IS_ERR (mnt))panic ("Can't create rootfs" );
@@ -3299,10 +3302,11 @@ void put_mnt_ns(struct mnt_namespace *ns)free_mnt_ns (ns); } -struct vfsmount *kern_mount_data (struct file_system_type *type,void *data) +struct vfsmount *kern_mount_data (struct file_system_type *type, +void *data,size_t data_size) {struct vfsmount *mnt; - mnt =vfs_kern_mount (type,SB_KERNMOUNT , type->name, data); + mnt =vfs_kern_mount (type,SB_KERNMOUNT , type->name, data, data_size);if (!IS_ERR (mnt)) {/* * it is a longterm mount, don't release mnt until
fs/nfs/internal.h +2 -2
@@ -405,7 +405,7 @@ int nfs_set_sb_security(struct super_block *, struct dentry *, struct nfs_mount_int nfs_clone_sb_security (struct super_block *,struct dentry *,struct nfs_mount_info *);struct dentry *nfs_fs_mount_common (struct nfs_server *,int ,const char *,struct nfs_mount_info *,struct nfs_subversion *); -struct dentry *nfs_fs_mount (struct file_system_type *,int ,const char *,void *); +struct dentry *nfs_fs_mount (struct file_system_type *,int ,const char *,void *,size_t );struct dentry *nfs_xdev_mount_common (struct file_system_type *,int ,const char *,struct nfs_mount_info *);void nfs_kill_super (struct super_block *);
@@ -466,7 +466,7 @@ int nfs_show_options(struct seq_file *, struct dentry *);int nfs_show_devname (struct seq_file *,struct dentry *);int nfs_show_path (struct seq_file *,struct dentry *);int nfs_show_stats (struct seq_file *,struct dentry *); -int nfs_remount (struct super_block *sb,int *flags,char *raw_data); +int nfs_remount (struct super_block *sb,int *flags,char *raw_data,size_t data_size);/* write.c */ extern void nfs_pageio_init_write(struct nfs_pageio_descriptor *pgio,
fs/nfs/namespace.c +2 -1
@@ -216,7 +216,8 @@ static struct vfsmount *nfs_do_clone_mount(struct nfs_server *server,const char *devname, struct nfs_clone_mount *mountdata) { - return vfs_submount(mountdata->dentry, &nfs_xdev_fs_type, devname, mountdata); + return vfs_submount(mountdata->dentry, &nfs_xdev_fs_type, devname, + mountdata, 0); }/**
fs/nfs/nfs4namespace.c +2 -1
@@ -278,7 +278,8 @@ static struct vfsmount *try_location(struct nfs_clone_mount *mountdata, mountdata->hostname, mountdata->mnt_path); - mnt =vfs_submount (mountdata->dentry, &nfs4_referral_fs_type, page, mountdata); + mnt =vfs_submount (mountdata->dentry, &nfs4_referral_fs_type, page, + mountdata,0 );if (!IS_ERR (mnt))break ; }
fs/nfs/nfs4super.c +15 -12
@@ -18,11 +18,11 @@static int nfs4_write_inode (struct inode *inode,struct writeback_control *wbc);static void nfs4_evict_inode (struct inode *inode);static struct dentry *nfs4_remote_mount (struct file_system_type *fs_type, -int flags,const char *dev_name,void *raw_data); +int flags,const char *dev_name,void *raw_data,size_t data_size);static struct dentry *nfs4_referral_mount (struct file_system_type *fs_type, -int flags,const char *dev_name,void *raw_data); +int flags,const char *dev_name,void *raw_data,size_t data_size);static struct dentry *nfs4_remote_referral_mount (struct file_system_type *fs_type, -int flags,const char *dev_name,void *raw_data); +int flags,const char *dev_name,void *raw_data,size_t data_size);static struct file_system_type nfs4_remote_fs_type = { .owner =THIS_MODULE ,
@@ -105,7 +105,7 @@ static void nfs4_evict_inode(struct inode *inode)*/ static struct dentry *nfs4_remote_mount (struct file_system_type *fs_type,int flags, -const char *dev_name,void *info) +const char *dev_name,void *info,size_t data_size) {struct nfs_mount_info *mount_info = info;struct nfs_server *server;
@@ -127,7 +127,7 @@ nfs4_remote_mount(struct file_system_type *fs_type, int flags, }static struct vfsmount *nfs_do_root_mount (struct file_system_type *fs_type, -int flags,void *data,const char *hostname) +int flags,void *data,size_t data_size,const char *hostname) {struct vfsmount *root_mnt;char *root_devname;
@@ -142,7 +142,8 @@ static struct vfsmount *nfs_do_root_mount(struct file_system_type *fs_type,snprintf (root_devname, len,"[%s]:/" , hostname); else snprintf(root_devname, len, "%s:/", hostname); - root_mnt =vfs_kern_mount (fs_type, flags, root_devname, data); + root_mnt =vfs_kern_mount (fs_type, flags, root_devname, + data, data_size);kfree (root_devname);return root_mnt; }
@@ -247,8 +248,8 @@ struct dentry *nfs4_try_mount(int flags, const char *dev_name, export_path = data->nfs_server.export_path; data->nfs_server.export_path ="/" ; - root_mnt =nfs_do_root_mount (&nfs4_remote_fs_type, flags, mount_info, - data->nfs_server.hostname); + root_mnt =nfs_do_root_mount (&nfs4_remote_fs_type, flags, mount_info,0 , + data->nfs_server.hostname); data->nfs_server.export_path = export_path; res =nfs_follow_remote_path (root_mnt, export_path);
@@ -261,7 +262,8 @@ struct dentry *nfs4_try_mount(int flags, const char *dev_name,static struct dentry *nfs4_remote_referral_mount (struct file_system_type *fs_type,int flags, -const char *dev_name,void *raw_data) +const char *dev_name, +void *raw_data,size_t data_size) {struct nfs_mount_info mount_info = { .fill_super = nfs_fill_super,
@@ -294,7 +296,8 @@ nfs4_remote_referral_mount(struct file_system_type *fs_type, int flags,* Create an NFS4 server record on referral traversal */ static struct dentry *nfs4_referral_mount (struct file_system_type *fs_type, -int flags,const char *dev_name,void *raw_data) +int flags,const char *dev_name, +void *raw_data,size_t data_size) {struct nfs_clone_mount *data = raw_data;char *export_path;
@@ -306,8 +309,8 @@ static struct dentry *nfs4_referral_mount(struct file_system_type *fs_type, export_path = data->mnt_path; data->mnt_path ="/" ; - root_mnt =nfs_do_root_mount (&nfs4_remote_referral_fs_type, - flags, data, data->hostname); + root_mnt =nfs_do_root_mount (&nfs4_remote_referral_fs_type, flags, + data,0 , data->hostname); data->mnt_path = export_path; res =nfs_follow_remote_path (root_mnt, export_path);
fs/nfs/super.c +12 -10
@@ -287,7 +287,8 @@ static match_table_t nfs_vers_tokens = { };static struct dentry *nfs_xdev_mount (struct file_system_type *fs_type, -int flags,const char *dev_name,void *raw_data); +int flags,const char *dev_name, +void *raw_data,size_t data_size);struct file_system_type nfs_fs_type = { .owner =THIS_MODULE ,
@@ -1203,7 +1204,7 @@ static int nfs_get_option_ul_bound(substring_t args[], unsigned long *option,* skipped as they are encountered. If there were no errors, return 1; * otherwise return 0 (zero). */ -static int nfs_parse_mount_options (char *raw, +static int nfs_parse_mount_options (char *raw,size_t raw_size,struct nfs_parsed_mount_data *mnt) {char *p, *string, *secdata;
@@ -1221,7 +1222,7 @@ static int nfs_parse_mount_options(char *raw,if (!secdata) goto out_nomem; - rc =security_sb_copy_data (raw, secdata); + rc =security_sb_copy_data (raw, raw_size, secdata);if (rc) goto out_security_failure;
@@ -2151,7 +2152,7 @@ static int nfs_validate_mount_data(struct file_system_type *fs_type, }#endif -static int nfs_validate_text_mount_data (void *options, +static int nfs_validate_text_mount_data (void *options,size_t data_size,struct nfs_parsed_mount_data *args,const char *dev_name) {
@@ -2160,7 +2161,7 @@ static int nfs_validate_text_mount_data(void *options,int max_pathlen =NFS_MAXPATHLEN ;struct sockaddr *sap = (struct sockaddr *)&args->nfs_server.address; -if (nfs_parse_mount_options ((char *)options, args) ==0 ) +if (nfs_parse_mount_options ((char *)options, data_size, args) ==0 )return -EINVAL ;if (!nfs_verify_server_address (sap))
@@ -2243,7 +2244,7 @@ nfs_compare_remount_data(struct nfs_server *nfss, }int -nfs_remount (struct super_block *sb,int *flags,char *raw_data) +nfs_remount (struct super_block *sb,int *flags,char *raw_data,size_t data_size) {int error;struct nfs_server *nfss = sb->s_fs_info;
@@ -2290,7 +2291,7 @@ nfs_remount(struct super_block *sb, int *flags, char *raw_data)/* overwrite those values with any that were specified */ error = -EINVAL ; -if (!nfs_parse_mount_options ((char *)options, data)) +if (!nfs_parse_mount_options ((char *)options, data_size, data)) goto out;/*
@@ -2662,7 +2663,7 @@ struct dentry *nfs_fs_mount_common(struct nfs_server *server,EXPORT_SYMBOL_GPL (nfs_fs_mount_common);struct dentry *nfs_fs_mount (struct file_system_type *fs_type, -int flags,const char *dev_name,void *raw_data) +int flags,const char *dev_name,void *raw_data,size_t data_size) {struct nfs_mount_info mount_info = { .fill_super = nfs_fill_super,
@@ -2680,7 +2681,8 @@ struct dentry *nfs_fs_mount(struct file_system_type *fs_type,/* Validate the mount data */ error =nfs_validate_mount_data (fs_type, raw_data, mount_info.parsed, mount_info.mntfh, dev_name);if (error ==NFS_TEXT_DATA ) - error =nfs_validate_text_mount_data (raw_data, mount_info.parsed, dev_name); + error =nfs_validate_text_mount_data (raw_data, data_size, + mount_info.parsed, dev_name);if (error <0 ) { mntroot =ERR_PTR (error); goto out;
@@ -2724,7 +2726,7 @@ EXPORT_SYMBOL_GPL(nfs_kill_super);*/ static struct dentry *nfs_xdev_mount (struct file_system_type *fs_type,int flags, -const char *dev_name,void *raw_data) +const char *dev_name,void *raw_data,size_t data_size) {struct nfs_clone_mount *data = raw_data;struct nfs_mount_info mount_info = {
fs/nfsd/nfsctl.c +5 -3
@@ -1144,7 +1144,8 @@ static ssize_t write_v4_end_grace(struct file *file, char *buf, size_t size)* populating the filesystem. */ -static int nfsd_fill_super (struct super_block * sb,void * data,int silent) +static int nfsd_fill_super (struct super_block * sb, +void * data,size_t data_size,int silent) {static const struct tree_descr nfsd_files[] = { [NFSD_List] = {"exports" , &exports_nfsd_operations,S_IRUGO },
@@ -1179,10 +1180,11 @@ static int nfsd_fill_super(struct super_block * sb, void * data, int silent) }static struct dentry *nfsd_mount (struct file_system_type *fs_type, -int flags,const char *dev_name,void *data) +int flags,const char *dev_name,void *data,size_t data_size) {struct net *net = current->nsproxy->net_ns; -return mount_ns (fs_type, flags, data, net, net->user_ns, nfsd_fill_super); +return mount_ns (fs_type, flags, data, data_size, + net, net->user_ns, nfsd_fill_super); }static void nfsd_umount (struct super_block *sb)
fs/nilfs2/super.c +6 -4
@@ -69,7 +69,8 @@ struct kmem_cache *nilfs_segbuf_cachep;struct kmem_cache *nilfs_btree_path_cache;static int nilfs_setup_super (struct super_block *sb,int is_mount); -static int nilfs_remount (struct super_block *sb,int *flags,char *data); +static int nilfs_remount (struct super_block *sb,int *flags, +char *data,size_t data_size);void __nilfs_msg (struct super_block *sb,const char *level,const char *fmt, ...)
@@ -1118,7 +1119,8 @@ nilfs_fill_super(struct super_block *sb, void *data, int silent)return err; } -static int nilfs_remount (struct super_block *sb,int *flags,char *data) +static int nilfs_remount (struct super_block *sb,int *flags, +char *data,size_t data_size) {struct the_nilfs *nilfs = sb->s_fs_info;unsigned long old_sb_flags;
@@ -1278,7 +1280,7 @@ static int nilfs_test_bdev_super(struct super_block *s, void *data)static struct dentry *nilfs_mount (struct file_system_type *fs_type,int flags, -const char *dev_name,void *data) +const char *dev_name,void *data,size_t data_size) {struct nilfs_super_data sd;struct super_block *s;
@@ -1346,7 +1348,7 @@ nilfs_mount(struct file_system_type *fs_type, int flags,* Try remount to setup mount states if the current * tree is not mounted and only snapshots use this sb. */ - err =nilfs_remount (s, &flags, data); + err =nilfs_remount (s, &flags, data, data_size);if (err) goto failed_super; }
fs/nsfs.c +2 -1
@@ -263,7 +263,8 @@ static const struct super_operations nsfs_ops = { .show_path = nsfs_show_path, };static struct dentry *nsfs_mount (struct file_system_type *fs_type, -int flags,const char *dev_name,void *data) +int flags,const char *dev_name, +void *data,size_t data_size) {return mount_pseudo (fs_type,"nsfs:" , &nsfs_ops, &ns_dentry_operations,NSFS_MAGIC );
fs/ntfs/super.c +9 -4
@@ -456,6 +456,7 @@ static inline int ntfs_clear_volume_flags(ntfs_volume *vol, VOLUME_FLAGS flags)* @sb: superblock of mounted ntfs filesystem * @flags: remount flags * @opt: remount options string +* @data_size: size of the options string * * Change the mount options of an already mounted ntfs filesystem. *
@@ -463,7 +464,8 @@ static inline int ntfs_clear_volume_flags(ntfs_volume *vol, VOLUME_FLAGS flags)* ntfs_remount() returns successfully (i.e. returns 0). Otherwise, * @sb->s_flags are not changed. */ -static int ntfs_remount (struct super_block *sb,int *flags,char *opt) +static int ntfs_remount (struct super_block *sb,int *flags, +char *opt,size_t data_size) {ntfs_volume *vol =NTFS_SB (sb);
@@ -2694,6 +2696,7 @@ static const struct super_operations ntfs_sops = {* ntfs_fill_super - mount an ntfs filesystem * @sb: super block of ntfs filesystem to mount * @opt: string containing the mount options +* @data_size: size of the mount options string * @silent: silence error output * * ntfs_fill_super() is called by the VFS to mount the device described by @sb
@@ -2708,7 +2711,8 @@ static const struct super_operations ntfs_sops = {* * NOTE: @sb->s_flags contains the mount options flags. */ -static int ntfs_fill_super (struct super_block *sb,void *opt,const int silent) +static int ntfs_fill_super (struct super_block *sb,void *opt,size_t data_size, +const int silent) {ntfs_volume *vol;struct buffer_head *bh;
@@ -3060,9 +3064,10 @@ struct kmem_cache *ntfs_index_ctx_cache;DEFINE_MUTEX (ntfs_lock);static struct dentry *ntfs_mount (struct file_system_type *fs_type, -int flags,const char *dev_name,void *data) +int flags,const char *dev_name,void *data,size_t data_size) { -return mount_bdev (fs_type, flags, dev_name, data, ntfs_fill_super); +return mount_bdev (fs_type, flags, dev_name, data, data_size, + ntfs_fill_super); }static struct file_system_type ntfs_fs_type = {
fs/ocfs2/dlmfs/dlmfs.c +3 -2
@@ -568,6 +568,7 @@ static int dlmfs_unlink(struct inode *dir,static int dlmfs_fill_super (struct super_block * sb,void * data, +size_t data_size,int silent) { sb->s_maxbytes =MAX_LFS_FILESIZE ;
@@ -617,9 +618,9 @@ static const struct inode_operations dlmfs_file_inode_operations = { };static struct dentry *dlmfs_mount (struct file_system_type *fs_type, -int flags,const char *dev_name,void *data) +int flags,const char *dev_name,void *data,size_t data_size) { -return mount_nodev (fs_type, flags, data, dlmfs_fill_super); +return mount_nodev (fs_type, flags, data, data_size, dlmfs_fill_super); }static struct file_system_type dlmfs_fs_type = {
fs/ocfs2/super.c +9 -5
@@ -107,7 +107,8 @@ static int ocfs2_check_set_options(struct super_block *sb,static int ocfs2_show_options (struct seq_file *s,struct dentry *root);static void ocfs2_put_super (struct super_block *sb);static int ocfs2_mount_volume (struct super_block *sb); -static int ocfs2_remount (struct super_block *sb,int *flags,char *data); +static int ocfs2_remount (struct super_block *sb,int *flags, +char *data,size_t data_size);static void ocfs2_dismount_volume (struct super_block *sb,int mnt_err);static int ocfs2_initialize_mem_caches (void );static void ocfs2_free_mem_caches (void );
@@ -633,7 +634,8 @@ static unsigned long long ocfs2_max_file_offset(unsigned int bbits,return (((unsigned long long )bytes) << bitshift) - trim; } -static int ocfs2_remount (struct super_block *sb,int *flags,char *data) +static int ocfs2_remount (struct super_block *sb,int *flags, +char *data,size_t data_size) {int incompat_features;int ret =0 ;
@@ -999,7 +1001,8 @@ static void ocfs2_disable_quotas(struct ocfs2_super *osb) } } -static int ocfs2_fill_super (struct super_block *sb,void *data,int silent) +static int ocfs2_fill_super (struct super_block *sb,void *data,size_t data_size, +int silent) {struct dentry *root;int status, sector_size;
@@ -1236,9 +1239,10 @@ static int ocfs2_fill_super(struct super_block *sb, void *data, int silent)static struct dentry *ocfs2_mount (struct file_system_type *fs_type,int flags,const char *dev_name, -void *data) +void *data,size_t data_size) { -return mount_bdev (fs_type, flags, dev_name, data, ocfs2_fill_super); +return mount_bdev (fs_type, flags, dev_name, data, data_size, + ocfs2_fill_super); }static struct file_system_type ocfs2_fs_type = {
fs/omfs/inode.c +6 -3
@@ -454,7 +454,8 @@ static int parse_options(char *options, struct omfs_sb_info *sbi)return 1 ; } -static int omfs_fill_super (struct super_block *sb,void *data,int silent) +static int omfs_fill_super (struct super_block *sb,void *data,size_t data_size, +int silent) {struct buffer_head *bh, *bh2;struct omfs_super_block *omfs_sb;
@@ -596,9 +597,11 @@ static int omfs_fill_super(struct super_block *sb, void *data, int silent) }static struct dentry *omfs_mount (struct file_system_type *fs_type, -int flags,const char *dev_name,void *data) +int flags,const char *dev_name, +void *data,size_t data_size) { -return mount_bdev (fs_type, flags, dev_name, data, omfs_fill_super); +return mount_bdev (fs_type, flags, dev_name, data, data_size, + omfs_fill_super); }static struct file_system_type omfs_fs_type = {
fs/openpromfs/inode.c +7 -4
@@ -366,7 +366,8 @@ static struct inode *openprom_iget(struct super_block *sb, ino_t ino)return inode; } -static int openprom_remount (struct super_block *sb,int *flags,char *data) +static int openprom_remount (struct super_block *sb,int *flags, +char *data,size_t data_size) {sync_filesystem (sb); *flags |=SB_NOATIME ;
@@ -380,7 +381,8 @@ static const struct super_operations openprom_sops = { .remount_fs = openprom_remount, }; -static int openprom_fill_super (struct super_block *s,void *data,int silent) +static int openprom_fill_super (struct super_block *s, +void *data,size_t data_size,int silent) {struct inode *root_inode;struct op_inode_info *oi;
@@ -415,9 +417,10 @@ static int openprom_fill_super(struct super_block *s, void *data, int silent) }static struct dentry *openprom_mount (struct file_system_type *fs_type, -int flags,const char *dev_name,void *data) +int flags,const char *dev_name,void *data,size_t data_size) { -return mount_single (fs_type, flags, data, openprom_fill_super); +return mount_single (fs_type, flags, data, data_size, + openprom_fill_super); }static struct file_system_type openprom_fs_type = {
fs/orangefs/orangefs-kernel.h +1 -1
@@ -319,7 +319,7 @@ extern uint64_t orangefs_features;struct dentry *orangefs_mount (struct file_system_type *fst,int flags,const char *devname, -void *data); +void *data,size_t data_size);void orangefs_kill_sb (struct super_block *sb);int orangefs_remount (struct orangefs_sb_info_s *);
fs/orangefs/super.c +3 -2
@@ -206,7 +206,8 @@ static int orangefs_statfs(struct dentry *dentry, struct kstatfs *buf)* Remount as initiated by VFS layer. We just need to reparse the mount * options, no need to signal pvfs2-client-core about it. */ -static int orangefs_remount_fs (struct super_block *sb,int *flags,char *data) +static int orangefs_remount_fs (struct super_block *sb,int *flags, +char *data,size_t data_size) {gossip_debug (GOSSIP_SUPER_DEBUG ,"orangefs_remount_fs: called\n" );return parse_mount_options (sb, data,1 );
@@ -456,7 +457,7 @@ static int orangefs_fill_sb(struct super_block *sb,struct dentry *orangefs_mount (struct file_system_type *fst,int flags,const char *devname, -void *data) +void *data,size_t data_size) {int ret = -EINVAL ;struct super_block *sb =ERR_PTR (-EINVAL );
fs/overlayfs/super.c +7 -4
@@ -379,7 +379,8 @@ static int ovl_show_options(struct seq_file *m, struct dentry *dentry)return 0 ; } -static int ovl_remount (struct super_block *sb,int *flags,char *data) +static int ovl_remount (struct super_block *sb,int *flags, +char *data,size_t data_size) {struct ovl_fs *ofs = sb->s_fs_info;
@@ -1355,7 +1356,8 @@ static struct ovl_entry *ovl_get_lowerstack(struct super_block *sb, goto out; } -static int ovl_fill_super (struct super_block *sb,void *data,int silent) +static int ovl_fill_super (struct super_block *sb,void *data,size_t data_size, +int silent) {struct path upperpath = { };struct dentry *root_dentry;
@@ -1493,9 +1495,10 @@ static int ovl_fill_super(struct super_block *sb, void *data, int silent) }static struct dentry *ovl_mount (struct file_system_type *fs_type,int flags, -const char *dev_name,void *raw_data) +const char *dev_name, +void *raw_data,size_t data_size) { -return mount_nodev (fs_type, flags, raw_data, ovl_fill_super); +return mount_nodev (fs_type, flags, raw_data, data_size, ovl_fill_super); }static struct file_system_type ovl_fs_type = {
fs/pipe.c +2 -1
@@ -1179,7 +1179,8 @@ static const struct super_operations pipefs_ops = {* d_name - pipe: will go nicely and kill the special-casing in procfs. */ static struct dentry *pipefs_mount (struct file_system_type *fs_type, -int flags,const char *dev_name,void *data) +int flags,const char *dev_name, +void *data,size_t data_size) {return mount_pseudo (fs_type,"pipe:" , &pipefs_ops, &pipefs_dentry_operations,PIPEFS_MAGIC );
fs/proc/inode.c +2 -1
@@ -490,7 +490,8 @@ struct inode *proc_get_inode(struct super_block *sb, struct proc_dir_entry *de)return inode; } -int proc_fill_super (struct super_block *s,void *data,int silent) +int proc_fill_super (struct super_block *s,void *data,size_t data_size, +int silent) {struct pid_namespace *ns =get_pid_ns (s->s_fs_info);struct inode *root_inode;
fs/proc/internal.h +2 -2
@@ -206,7 +206,7 @@ extern const struct inode_operations proc_pid_link_inode_operations;void proc_init_kmemcache (void );void set_proc_pid_nlink (void );extern struct inode *proc_get_inode (struct super_block *,struct proc_dir_entry *); -extern int proc_fill_super (struct super_block *,void *data,int flags); +extern int proc_fill_super (struct super_block *,void *,size_t ,int );extern void proc_entry_rundown (struct proc_dir_entry *);/*
@@ -267,7 +267,7 @@ extern struct proc_dir_entry proc_root;extern int proc_parse_options (char *options,struct pid_namespace *pid);extern void proc_self_init (void ); -extern int proc_remount (struct super_block *,int *,char *); +extern int proc_remount (struct super_block *,int *,char *,size_t );/* * task_[no]mmu.c
fs/proc/root.c +7 -4
@@ -78,7 +78,8 @@ int proc_parse_options(char *options, struct pid_namespace *pid)return 1 ; } -int proc_remount (struct super_block *sb,int *flags,char *data) +int proc_remount (struct super_block *sb,int *flags, +char *data,size_t data_size) {struct pid_namespace *pid = sb->s_fs_info;
@@ -87,7 +88,8 @@ int proc_remount(struct super_block *sb, int *flags, char *data) }static struct dentry *proc_mount (struct file_system_type *fs_type, -int flags,const char *dev_name,void *data) +int flags,const char *dev_name, +void *data,size_t data_size) {struct pid_namespace *ns;
@@ -98,7 +100,8 @@ static struct dentry *proc_mount(struct file_system_type *fs_type, ns =task_active_pid_ns (current); } -return mount_ns (fs_type, flags, data, ns, ns->user_ns, proc_fill_super); +return mount_ns (fs_type, flags, data, data_size, ns, ns->user_ns, + proc_fill_super); }static void proc_kill_sb (struct super_block *sb)
@@ -212,7 +215,7 @@ int pid_ns_prepare_proc(struct pid_namespace *ns) {struct vfsmount *mnt; - mnt =kern_mount_data (&proc_fs_type, ns); + mnt =kern_mount_data (&proc_fs_type, ns,0 );if (IS_ERR (mnt))return PTR_ERR (mnt);
fs/pstore/inode.c +6 -4
@@ -271,7 +271,8 @@ static int pstore_show_options(struct seq_file *m, struct dentry *root)return 0 ; } -static int pstore_remount (struct super_block *sb,int *flags,char *data) +static int pstore_remount (struct super_block *sb,int *flags, +char *data,size_t data_size) {sync_filesystem (sb);parse_options (data);
@@ -432,7 +433,8 @@ void pstore_get_records(int quiet)inode_unlock (d_inode (root)); } -static int pstore_fill_super (struct super_block *sb,void *data,int silent) +static int pstore_fill_super (struct super_block *sb, +void *data,size_t data_size,int silent) {struct inode *inode;
@@ -464,9 +466,9 @@ static int pstore_fill_super(struct super_block *sb, void *data, int silent) }static struct dentry *pstore_mount (struct file_system_type *fs_type, -int flags,const char *dev_name,void *data) +int flags,const char *dev_name,void *data,size_t data_size) { -return mount_single (fs_type, flags, data, pstore_fill_super); +return mount_single (fs_type, flags, data, data_size, pstore_fill_super); }static void pstore_kill_sb (struct super_block *sb)
fs/qnx4/inode.c +9 -5
@@ -29,7 +29,8 @@ static const struct super_operations qnx4_sops;static struct inode *qnx4_alloc_inode (struct super_block *sb);static void qnx4_destroy_inode (struct inode *inode); -static int qnx4_remount (struct super_block *sb,int *flags,char *data); +static int qnx4_remount (struct super_block *sb,int *flags, +char *data,size_t data_size);static int qnx4_statfs (struct dentry *,struct kstatfs *); static const struct super_operations qnx4_sops =
@@ -40,7 +41,8 @@ static const struct super_operations qnx4_sops = .remount_fs = qnx4_remount, }; -static int qnx4_remount (struct super_block *sb,int *flags,char *data) +static int qnx4_remount (struct super_block *sb,int *flags, +char *data,size_t data_size) {struct qnx4_sb_info *qs;
@@ -183,7 +185,8 @@ static const char *qnx4_checkroot(struct super_block *sb,return "bitmap file not found." ; } -static int qnx4_fill_super (struct super_block *s,void *data,int silent) +static int qnx4_fill_super (struct super_block *s,void *data,size_t data_size, +int silent) {struct buffer_head *bh;struct inode *root;
@@ -383,9 +386,10 @@ static void destroy_inodecache(void) }static struct dentry *qnx4_mount (struct file_system_type *fs_type, -int flags,const char *dev_name,void *data) +int flags,const char *dev_name,void *data,size_t data_size) { -return mount_bdev (fs_type, flags, dev_name, data, qnx4_fill_super); +return mount_bdev (fs_type, flags, dev_name, data, data_size, + qnx4_fill_super); }static struct file_system_type qnx4_fs_type = {
fs/qnx6/inode.c +9 -5
@@ -30,7 +30,8 @@ static const struct super_operations qnx6_sops;static void qnx6_put_super (struct super_block *sb);static struct inode *qnx6_alloc_inode (struct super_block *sb);static void qnx6_destroy_inode (struct inode *inode); -static int qnx6_remount (struct super_block *sb,int *flags,char *data); +static int qnx6_remount (struct super_block *sb,int *flags, +char *data,size_t data_size);static int qnx6_statfs (struct dentry *dentry,struct kstatfs *buf);static int qnx6_show_options (struct seq_file *seq,struct dentry *root);
@@ -53,7 +54,8 @@ static int qnx6_show_options(struct seq_file *seq, struct dentry *root)return 0 ; } -static int qnx6_remount (struct super_block *sb,int *flags,char *data) +static int qnx6_remount (struct super_block *sb,int *flags, +char *data,size_t data_size) {sync_filesystem (sb); *flags |=SB_RDONLY ;
@@ -294,7 +296,8 @@ static struct buffer_head *qnx6_check_first_superblock(struct super_block *s,static struct inode *qnx6_private_inode (struct super_block *s,struct qnx6_root_node *p); -static int qnx6_fill_super (struct super_block *s,void *data,int silent) +static int qnx6_fill_super (struct super_block *s,void *data,size_t data_size, +int silent) {struct buffer_head *bh1 =NULL , *bh2 =NULL ;struct qnx6_super_block *sb1 =NULL , *sb2 =NULL ;
@@ -643,9 +646,10 @@ static void destroy_inodecache(void) }static struct dentry *qnx6_mount (struct file_system_type *fs_type, -int flags,const char *dev_name,void *data) +int flags,const char *dev_name,void *data,size_t data_size) { -return mount_bdev (fs_type, flags, dev_name, data, qnx6_fill_super); +return mount_bdev (fs_type, flags, dev_name, data, data_size, + qnx6_fill_super); }static struct file_system_type qnx6_fs_type = {
fs/ramfs/inode.c +3 -3
@@ -217,7 +217,7 @@ static int ramfs_parse_options(char *data, struct ramfs_mount_opts *opts)return 0 ; } -int ramfs_fill_super (struct super_block *sb,void *data,int silent) +int ramfs_fill_super (struct super_block *sb,void *data,size_t data_size,int silent) {struct ramfs_fs_info *fsi;struct inode *inode;
@@ -248,9 +248,9 @@ int ramfs_fill_super(struct super_block *sb, void *data, int silent) }struct dentry *ramfs_mount (struct file_system_type *fs_type, -int flags,const char *dev_name,void *data) +int flags,const char *dev_name,void *data,size_t data_size) { -return mount_nodev (fs_type, flags, data, ramfs_fill_super); +return mount_nodev (fs_type, flags, data, data_size, ramfs_fill_super); }static void ramfs_kill_sb (struct super_block *sb)
fs/reiserfs/super.c +9 -5
@@ -61,7 +61,8 @@ static int is_any_reiserfs_magic_string(struct reiserfs_super_block *rs) is_reiserfs_jr(rs)); } -static int reiserfs_remount (struct super_block *s,int *flags,char *data); +static int reiserfs_remount (struct super_block *s,int *flags, +char *data,size_t data_size);static int reiserfs_statfs (struct dentry *dentry,struct kstatfs *buf);static int reiserfs_sync_fs (struct super_block *s,int wait)
@@ -1433,7 +1434,8 @@ static void handle_quota_files(struct super_block *s, char **qf_names, }#endif -static int reiserfs_remount (struct super_block *s,int *mount_flags,char *arg) +static int reiserfs_remount (struct super_block *s,int *mount_flags, +char *arg,size_t data_size) {struct reiserfs_super_block *rs;struct reiserfs_transaction_handle th;
@@ -1898,7 +1900,8 @@ static int function2code(hashf_t func)if (!(silent)) \ reiserfs_warning(s, id, __VA_ARGS__) -static int reiserfs_fill_super (struct super_block *s,void *data,int silent) +static int reiserfs_fill_super (struct super_block *s,void *data,size_t data_size, +int silent) {struct inode *root_inode;struct reiserfs_transaction_handle th;
@@ -2600,9 +2603,10 @@ static ssize_t reiserfs_quota_write(struct super_block *sb, int type,static struct dentry *get_super_block (struct file_system_type *fs_type,int flags,const char *dev_name, -void *data) +void *data,size_t data_size) { -return mount_bdev (fs_type, flags, dev_name, data, reiserfs_fill_super); +return mount_bdev (fs_type, flags, dev_name, data, data_size, + reiserfs_fill_super); }static int __init init_reiserfs_fs (void )
fs/romfs/super.c +8 -5
@@ -448,7 +448,8 @@ static int romfs_statfs(struct dentry *dentry, struct kstatfs *buf)/* * remounting must involve read-only */ -static int romfs_remount (struct super_block *sb,int *flags,char *data) +static int romfs_remount (struct super_block *sb,int *flags, +char *data,size_t data_size) {sync_filesystem (sb); *flags |=SB_RDONLY ;
@@ -482,7 +483,8 @@ static __u32 romfs_checksum(const void *data, int size)/* * fill in the superblock */ -static int romfs_fill_super (struct super_block *sb,void *data,int silent) +static int romfs_fill_super (struct super_block *sb,void *data,size_t data_size, +int silent) {struct romfs_super_block *rsb;struct inode *root;
@@ -575,16 +577,17 @@ static int romfs_fill_super(struct super_block *sb, void *data, int silent)*/ static struct dentry *romfs_mount (struct file_system_type *fs_type,int flags,const char *dev_name, -void *data) +void *data,size_t data_size) {struct dentry *ret =ERR_PTR (-EINVAL );#ifdef CONFIG_ROMFS_ON_MTD - ret =mount_mtd (fs_type, flags, dev_name, data, romfs_fill_super); + ret =mount_mtd (fs_type, flags, dev_name, data, data_size, + romfs_fill_super);#endif #ifdef CONFIG_ROMFS_ON_BLOCK if (ret ==ERR_PTR (-EINVAL )) - ret =mount_bdev (fs_type, flags, dev_name, data, + ret =mount_bdev (fs_type, flags, dev_name, data, data_size, romfs_fill_super);#endif return ret;
fs/squashfs/super.c +8 -4
@@ -76,7 +76,8 @@ static const struct squashfs_decompressor *supported_squashfs_filesystem(short } -static int squashfs_fill_super (struct super_block *sb,void *data,int silent) +static int squashfs_fill_super (struct super_block *sb, +void *data,size_t data_size,int silent) {struct squashfs_sb_info *msblk;struct squashfs_super_block *sblk =NULL ;
@@ -370,7 +371,8 @@ static int squashfs_statfs(struct dentry *dentry, struct kstatfs *buf) } -static int squashfs_remount (struct super_block *sb,int *flags,char *data) +static int squashfs_remount (struct super_block *sb,int *flags, +char *data,size_t data_size) {sync_filesystem (sb); *flags |=SB_RDONLY ;
@@ -398,9 +400,11 @@ static void squashfs_put_super(struct super_block *sb)static struct dentry *squashfs_mount (struct file_system_type *fs_type, -int flags,const char *dev_name,void *data) +int flags,const char *dev_name, +void *data,size_t data_size) { -return mount_bdev (fs_type, flags, dev_name, data, squashfs_fill_super); +return mount_bdev (fs_type, flags, dev_name, data, data_size, + squashfs_fill_super); }
fs/super.c +24 -20
142 lines not on this page · raw message
fs/sysfs/mount.c +1 -1
@@ -21,7 +21,7 @@ static struct kernfs_root *sysfs_root;struct kernfs_node *sysfs_root_kn;static struct dentry *sysfs_mount (struct file_system_type *fs_type, -int flags,const char *dev_name,void *data) +int flags,const char *dev_name,void *data,size_t data_size) {struct dentry *root;void *ns;
fs/sysv/inode.c +2 -1
@@ -57,7 +57,8 @@ static int sysv_sync_fs(struct super_block *sb, int wait)return 0 ; } -static int sysv_remount (struct super_block *sb,int *flags,char *data) +static int sysv_remount (struct super_block *sb,int *flags, +char *data,size_t data_size) {struct sysv_sb_info *sbi =SYSV_SB (sb);
fs/sysv/super.c +10 -6
@@ -349,7 +349,8 @@ static int complete_read_super(struct super_block *sb, int silent, int size)return 1 ; } -static int sysv_fill_super (struct super_block *sb,void *data,int silent) +static int sysv_fill_super (struct super_block *sb,void *data,size_t data_size, +int silent) {struct buffer_head *bh1, *bh =NULL ;struct sysv_sb_info *sbi;
@@ -470,7 +471,8 @@ static int v7_sanity_check(struct super_block *sb, struct buffer_head *bh)return 1 ; } -static int v7_fill_super (struct super_block *sb,void *data,int silent) +static int v7_fill_super (struct super_block *sb,void *data,size_t data_size, +int silent) {struct sysv_sb_info *sbi;struct buffer_head *bh;
@@ -528,15 +530,17 @@ static int v7_fill_super(struct super_block *sb, void *data, int silent)/* Every kernel module contains stuff like this. */ static struct dentry *sysv_mount (struct file_system_type *fs_type, -int flags,const char *dev_name,void *data) +int flags,const char *dev_name,void *data,size_t data_size) { -return mount_bdev (fs_type, flags, dev_name, data, sysv_fill_super); +return mount_bdev (fs_type, flags, dev_name, data, data_size, + sysv_fill_super); }static struct dentry *v7_mount (struct file_system_type *fs_type, -int flags,const char *dev_name,void *data) +int flags,const char *dev_name,void *data,size_t data_size) { -return mount_bdev (fs_type, flags, dev_name, data, v7_fill_super); +return mount_bdev (fs_type, flags, dev_name, data, data_size, + v7_fill_super); }static struct file_system_type sysv_fs_type = {
fs/tracefs/inode.c +6 -4
@@ -225,7 +225,8 @@ static int tracefs_apply_options(struct super_block *sb)return 0 ; } -static int tracefs_remount (struct super_block *sb,int *flags,char *data) +static int tracefs_remount (struct super_block *sb,int *flags, +char *data,size_t data_size) {int err;struct tracefs_fs_info *fsi = sb->s_fs_info;
@@ -264,7 +265,8 @@ static const struct super_operations tracefs_super_operations = { .show_options = tracefs_show_options, }; -static int trace_fill_super (struct super_block *sb,void *data,int silent) +static int trace_fill_super (struct super_block *sb, +void *data,size_t data_size,int silent) {static const struct tree_descr trace_files[] = {{"" }};struct tracefs_fs_info *fsi;
@@ -299,9 +301,9 @@ static int trace_fill_super(struct super_block *sb, void *data, int silent)static struct dentry *trace_mount (struct file_system_type *fs_type,int flags,const char *dev_name, -void *data) +void *data,size_t data_size) { -return mount_single (fs_type, flags, data, trace_fill_super); +return mount_single (fs_type, flags, data, data_size, trace_fill_super); }static struct file_system_type trace_fs_type = {
fs/ubifs/super.c +3 -2
@@ -1842,7 +1842,8 @@ static void ubifs_put_super(struct super_block *sb)mutex_unlock (&c->umount_mutex); } -static int ubifs_remount_fs (struct super_block *sb,int *flags,char *data) +static int ubifs_remount_fs (struct super_block *sb,int *flags, +char *data,size_t data_size) {int err;struct ubifs_info *c = sb->s_fs_info;
@@ -2105,7 +2106,7 @@ static int sb_set(struct super_block *sb, void *data) }static struct dentry *ubifs_mount (struct file_system_type *fs_type,int flags, -const char *name,void *data) +const char *name,void *data,size_t data_size) {struct ubi_volume_desc *ubi;struct ubifs_info *c;
fs/udf/super.c +10 -6
@@ -87,10 +87,10 @@ enum {enum {UDF_MAX_LINKS =0xffff };/* These are the "meat" - everything else is stuffing */ -static int udf_fill_super (struct super_block *,void *,int ); +static int udf_fill_super (struct super_block *,void *,size_t ,int );static void udf_put_super (struct super_block *);static int udf_sync_fs (struct super_block *,int ); -static int udf_remount_fs (struct super_block *,int *,char *); +static int udf_remount_fs (struct super_block *,int *,char *,size_t );static void udf_load_logicalvolint (struct super_block *,struct kernel_extent_ad );static int udf_find_fileset (struct super_block *,struct kernel_lb_addr *,struct kernel_lb_addr *);
@@ -126,9 +126,11 @@ struct logicalVolIntegrityDescImpUse *udf_sb_lvidiu(struct super_block *sb)/* UDF filesystem type */ static struct dentry *udf_mount (struct file_system_type *fs_type, -int flags,const char *dev_name,void *data) +int flags,const char *dev_name, +void *data,size_t data_size) { -return mount_bdev (fs_type, flags, dev_name, data, udf_fill_super); +return mount_bdev (fs_type, flags, dev_name, data, data_size, + udf_fill_super); }static struct file_system_type udf_fstype = {
@@ -610,7 +612,8 @@ static int udf_parse_options(char *options, struct udf_options *uopt,return 1 ; } -static int udf_remount_fs (struct super_block *sb,int *flags,char *options) +static int udf_remount_fs (struct super_block *sb,int *flags, +char *options,size_t data_size) {struct udf_options uopt;struct udf_sb_info *sbi =UDF_SB (sb);
@@ -2083,7 +2086,8 @@ u64 lvid_get_unique_id(struct super_block *sb)return ret; } -static int udf_fill_super (struct super_block *sb,void *options,int silent) +static int udf_fill_super (struct super_block *sb, +void *options,size_t data_size,int silent) {int ret = -EINVAL ;struct inode *inode =NULL ;
fs/ufs/super.c +7 -4
@@ -772,7 +772,8 @@ static u64 ufs_max_bytes(struct super_block *sb)return res << uspi->s_bshift; } -static int ufs_fill_super (struct super_block *sb,void *data,int silent) +static int ufs_fill_super (struct super_block *sb,void *data,size_t data_size, +int silent) {struct ufs_sb_info * sbi;struct ufs_sb_private_info * uspi;
@@ -1295,7 +1296,8 @@ static int ufs_fill_super(struct super_block *sb, void *data, int silent)return -ENOMEM ; } -static int ufs_remount (struct super_block *sb,int *mount_flags,char *data) +static int ufs_remount (struct super_block *sb,int *mount_flags, +char *data,size_t data_size) {struct ufs_sb_private_info * uspi;struct ufs_super_block_first * usb1;
@@ -1503,9 +1505,10 @@ static const struct super_operations ufs_super_ops = { };static struct dentry *ufs_mount (struct file_system_type *fs_type, -int flags,const char *dev_name,void *data) +int flags,const char *dev_name,void *data,size_t data_size) { -return mount_bdev (fs_type, flags, dev_name, data, ufs_fill_super); +return mount_bdev (fs_type, flags, dev_name, data, data_size, + ufs_fill_super); }static struct file_system_type ufs_fs_type = {
fs/xfs/xfs_super.c +7 -3
@@ -1268,7 +1268,8 @@ STATIC intxfs_fs_remount ( struct super_block *sb, int *flags, - char *options) + char *options, + size_t data_size) { struct xfs_mount *mp = XFS_M(sb);xfs_sb_t *sbp = &mp->m_sb;
@@ -1607,6 +1608,7 @@ STATIC intxfs_fs_fill_super ( struct super_block *sb, void *data, + size_t data_size, int silent) { struct inode *root;
@@ -1796,9 +1798,11 @@ xfs_fs_mount(struct file_system_type *fs_type, int flags, const char *dev_name, - void *data) + void *data, + size_t data_size) { - return mount_bdev(fs_type, flags, dev_name, data, xfs_fs_fill_super); + return mount_bdev(fs_type, flags, dev_name, data, data_size, +xfs_fs_fill_super ); } static long
include/linux/debugfs.h +4 -4
@@ -75,11 +75,11 @@ struct dentry *debugfs_create_dir(const char *name, struct dentry *parent);struct dentry *debugfs_create_symlink (const char *name,struct dentry *parent,const char *dest); -typedef struct vfsmount *(*debugfs_automount_t )(struct dentry *,void *); +typedef struct vfsmount *(*debugfs_automount_t )(struct dentry *,void *,size_t );struct dentry *debugfs_create_automount (const char *name,struct dentry *parent,debugfs_automount_t f, -void *data); +void *data,size_t data_size);void debugfs_remove (struct dentry *dentry);void debugfs_remove_recursive (struct dentry *dentry);
@@ -204,8 +204,8 @@ static inline struct dentry *debugfs_create_symlink(const char *name,static inline struct dentry *debugfs_create_automount (const char *name,struct dentry *parent, -struct vfsmount *(*f)(void *), -void *data) +struct vfsmount *(*f)(void *,size_t ), +void *data,size_t data_size) {return ERR_PTR (-ENODEV ); }
include/linux/fs.h +15 -14
@@ -1827,7 +1827,7 @@ struct super_operations {int (*thaw_super) (struct super_block *);int (*unfreeze_fs) (struct super_block *);int (*statfs) (struct dentry *,struct kstatfs *); -int (*remount_fs) (struct super_block *,int *,char *); +int (*remount_fs) (struct super_block *,int *,char *,size_t );void (*umount_begin) (struct super_block *);int (*show_options)(struct seq_file *,struct dentry *);
@@ -2075,7 +2075,7 @@ struct file_system_type {#define FS_USERNS_MOUNT 8/* Can be mounted by userns root */ #define FS_RENAME_DOES_D_MOVE 32768/* FS will handle d_move() during rename() internally. */ struct dentry *(*mount) (struct file_system_type *,int , -const char *,void *); +const char *,void *,size_t );void (*kill_sb) (struct super_block *);struct module *owner;struct file_system_type * next;
@@ -2094,26 +2094,27 @@ struct file_system_type {#define MODULE_ALIAS_FS (NAME ) MODULE_ALIAS("fs-" NAME)extern struct dentry *mount_ns (struct file_system_type *fs_type, -int flags,void *data,void *ns,struct user_namespace *user_ns, -int (*fill_super)(struct super_block *,void *,int )); +int flags,void *data,size_t data_size, +void *ns,struct user_namespace *user_ns, +int (*fill_super)(struct super_block *,void *,size_t ,int ));#ifdef CONFIG_BLOCK extern struct dentry *mount_bdev (struct file_system_type *fs_type, -int flags,const char *dev_name,void *data, -int (*fill_super)(struct super_block *,void *,int )); +int flags,const char *dev_name,void *data,size_t data_size, +int (*fill_super)(struct super_block *,void *,size_t ,int ));#else static inline struct dentry *mount_bdev (struct file_system_type *fs_type, -int flags,const char *dev_name,void *data, -int (*fill_super)(struct super_block *,void *,int )) +int flags,const char *dev_name,void *data,size_t data_size, +int (*fill_super)(struct super_block *,void *,size_t ,int )) {return ERR_PTR (-ENODEV ); }#endif extern struct dentry *mount_single (struct file_system_type *fs_type, -int flags,void *data, -int (*fill_super)(struct super_block *,void *,int )); +int flags,void *data,size_t data_size, +int (*fill_super)(struct super_block *,void *,size_t ,int ));extern struct dentry *mount_nodev (struct file_system_type *fs_type, -int flags,void *data, -int (*fill_super)(struct super_block *,void *,int )); +int flags,void *data,size_t data_size, +int (*fill_super)(struct super_block *,void *,size_t ,int ));extern struct dentry *mount_subtree (struct vfsmount *mnt,const char *path);void generic_shutdown_super (struct super_block *sb);#ifdef CONFIG_BLOCK
@@ -2173,8 +2174,8 @@ mount_pseudo(struct file_system_type *fs_type, char *name,extern int register_filesystem (struct file_system_type *);extern int unregister_filesystem (struct file_system_type *); -extern struct vfsmount *kern_mount_data (struct file_system_type *,void *data); -#define kern_mount (type) kern_mount_data(type, NULL) +extern struct vfsmount *kern_mount_data (struct file_system_type *,void *,size_t ); +#define kern_mount (type) kern_mount_data(type, NULL, 0)extern void kern_unmount (struct vfsmount *mnt);extern int may_umount_tree (struct vfsmount *);extern int may_umount (struct vfsmount *);
include/linux/lsm_hooks.h +9 -4
@@ -155,6 +155,7 @@* @type contains the filesystem type. * @flags contains the mount flags. * @data contains the filesystem-specific data. +* @data_size contains the size of the data. * Return 0 if permission is granted. * @sb_copy_data: * Allow mount option data to be copied prior to parsing by the filesystem,
@@ -164,6 +165,7 @@* specific options to avoid having to make filesystems aware of them. * @type the type of filesystem being mounted. * @orig the original mount data copied from userspace. +* @orig_data is the size of the original data * @copy copied data which will be passed to the security module. * Returns 0 if the copy was successful. * @sb_remount:
@@ -171,6 +173,7 @@* are being made to those options. * @sb superblock being remounted * @data contains the filesystem-specific data. +* @data_size contains the size of the data. * Return 0 if permission is granted. * @sb_umount: * Check permission before the @mnt file system is unmounted.
@@ -1514,13 +1517,15 @@ union security_list_options {int (*sb_alloc_security)(struct super_block *sb);void (*sb_free_security)(struct super_block *sb); -int (*sb_copy_data)(char *orig,char *copy); -int (*sb_remount)(struct super_block *sb,void *data); -int (*sb_kern_mount)(struct super_block *sb,int flags,void *data); +int (*sb_copy_data)(char *orig,size_t orig_size,char *copy); +int (*sb_remount)(struct super_block *sb,void *data,size_t data_size); +int (*sb_kern_mount)(struct super_block *sb,int flags, +void *data,size_t data_size);int (*sb_show_options)(struct seq_file *m,struct super_block *sb);int (*sb_statfs)(struct dentry *dentry);int (*sb_mount)(const char *dev_name,const struct path *path, -const char *type,unsigned long flags,void *data); +const char *type,unsigned long flags, +void *data,size_t data_size);int (*sb_umount)(struct vfsmount *mnt,int flags);int (*sb_pivotroot)(const struct path *old_path,const struct path *new_path); int (*sb_set_mnt_opts)(struct super_block *sb,
include/linux/mount.h +3 -2
@@ -90,10 +90,11 @@ extern struct vfsmount *clone_private_mount(const struct path *path);struct file_system_type ; extern struct vfsmount *vfs_kern_mount(struct file_system_type *type,
Lines of this file are not shown. View the raw message.
The rest of this diff is not shown. View the raw message.
Part of the diff is not shown here. View the raw message.
David Howells
maintainerPATCH 10/32 VFS: Implement a filesystem superblock creation/configuration context [ver #8]
In reply to David HowellsImplement a filesystem context concept to be used during superblock creation for mount and superblock reconfiguration for remount.
The mounting procedure then becomes:
(1) Allocate new fs_context context.
(2) Configure the context.
(3) Create superblock.
(4) Mount the superblock any number of times.
(5) Destroy the context.
Rather than calling fs_type->mount(), an fs_context struct is created and fs_type->init_fs_context() is called to set it up. fs_type->fs_context_size says how much space should be allocated for the config context. The fs_context struct is placed at the beginning and any extra space is for the filesystem's use.
A set of operations has to be set by ->init_fs_context() to provide freeing, duplication, option parsing, binary data parsing, validation, mounting and superblock filling.
Legacy filesystems are supported by the provision of a set of legacy fs_context operations that build up a list of mount options and then invoke fs_type->mount() from within the fs_context ->get_tree() operation. This allows all filesystems to be accessed using fs_context.
It should be noted that, whilst this patch adds a lot of lines of code, there is quite a bit of duplication with existing code that can be eliminated should all filesystems be converted over.
---
fs/Makefile | 3 fs/fs_context.c | 599 ++++++++++++++++++++++++++++++++++++++++++++ fs/internal.h | 3 fs/libfs.c | 17 + fs/namespace.c | 350 +++++++++++++++++--------- fs/super.c | 311 ++++++++++++++++++++++- include/linux/fs.h | 13 + include/linux/fs_context.h | 45 +++ include/linux/mount.h | 3 9 files changed, 1201 insertions(+), 143 deletions(-) create mode 100644 fs/fs_context.c
fs/Makefile +2 -1
@@ -12,7 +12,8 @@ obj-y := open.o read_write.o file_table.o super.o \ attr.o bad_inode.o file.o filesystems.o namespace.o \ seq_file.o xattr.o libfs.o fs-writeback.o \ pnode.o splice.o sync.o utimes.o d_path.o \ - stack.o fs_struct.o statfs.o fs_pin.o nsfs.o + stack.o fs_struct.o statfs.o fs_pin.o nsfs.o \ + fs_context.o ifeq ($(CONFIG_BLOCK),y) obj-y += buffer.o block_dev.o direct-io.o mpage.o
fs/fs_context.c new file +599 -0
599 lines not on this page · raw message
fs/internal.h +2 -1
@@ -98,7 +98,8 @@ extern struct file *get_empty_filp(void);/* * super.c */ -extern int do_remount_sb (struct super_block *,int ,void *,size_t ,int ); +extern int do_remount_sb (struct super_block *,int ,void *,size_t ,int , +struct fs_context *);extern bool trylock_super (struct super_block *sb);extern struct dentry *mount_fs (struct file_system_type *,int ,const char *,void *,size_t );
fs/libfs.c +16 -1
@@ -9,6 +9,7 @@#include <linux/slab.h> #include <linux/cred.h> #include <linux/mount.h> +#include <linux/fs_context.h> #include <linux/vfs.h> #include <linux/quotaops.h> #include <linux/mutex.h>
@@ -574,13 +575,27 @@ static DEFINE_SPINLOCK(pin_fs_lock);int simple_pin_fs (struct file_system_type *type,struct vfsmount **mount,int *count) { +struct fs_context *fc;struct vfsmount *mnt =NULL ; +int ret; +spin_lock (&pin_fs_lock);if (unlikely (!*mount)) {spin_unlock (&pin_fs_lock); - mnt =vfs_kern_mount (type,SB_KERNMOUNT , type->name,NULL ,0 ); + + fc =vfs_new_fs_context (type,NULL ,0 ,FS_CONTEXT_FOR_KERNEL_MOUNT ); +if (IS_ERR (fc)) +return PTR_ERR (fc); + + ret =vfs_get_tree (fc); +if (ret <0 ) +return ret; + + mnt =vfs_create_mount (fc,0 ); +put_fs_context (fc);if (IS_ERR (mnt))return PTR_ERR (mnt); +spin_lock (&pin_fs_lock);if (!*mount) *mount = mnt;
fs/namespace.c +229 -121
473 lines not on this page · raw message
fs/super.c +294 -17
399 lines not on this page · raw message
include/linux/fs.h +12 -1
@@ -60,6 +60,7 @@ struct workqueue_struct;struct iov_iter ;struct fscrypt_info ;struct fscrypt_operations ; +struct fs_context ;extern void __init inode_init (void );extern void __init inode_init_early (void );
@@ -718,6 +719,11 @@ static inline void inode_unlock(struct inode *inode)up_write (&inode->i_rwsem); } +static inline int inode_lock_killable (struct inode *inode) +{ +return down_write_killable (&inode->i_rwsem); +} +static inline void inode_lock_shared (struct inode *inode) {down_read (&inode->i_rwsem);
@@ -1828,6 +1834,7 @@ struct super_operations {int (*unfreeze_fs) (struct super_block *);int (*statfs) (struct dentry *,struct kstatfs *);int (*remount_fs) (struct super_block *,int *,char *,size_t ); +int (*reconfigure) (struct super_block *,struct fs_context *);void (*umount_begin) (struct super_block *);int (*show_options)(struct seq_file *,struct dentry *);
@@ -2074,6 +2081,7 @@ struct file_system_type {#define FS_HAS_SUBTYPE 4#define FS_USERNS_MOUNT 8/* Can be mounted by userns root */ #define FS_RENAME_DOES_D_MOVE 32768/* FS will handle d_move() during rename() internally. */ +int (*init_fs_context)(struct fs_context *,struct dentry *);struct dentry *(*mount) (struct file_system_type *,int ,const char *,void *,size_t );void (*kill_sb) (struct super_block *);
@@ -2132,6 +2140,9 @@ void deactivate_locked_super(struct super_block *sb);int set_anon_super (struct super_block *s,void *data);int get_anon_bdev (dev_t *);void free_anon_bdev (dev_t ); +struct super_block *sget_fc (struct fs_context *fc, +int (*test)(struct super_block *,struct fs_context *), +int (*set)(struct super_block *,struct fs_context *)); struct super_block *sget_userns(struct file_system_type *type, int (*test)(struct super_block *,void *), int (*set)(struct super_block *,void *),
@@ -2174,8 +2185,8 @@ mount_pseudo(struct file_system_type *fs_type, char *name,extern int register_filesystem (struct file_system_type *);extern int unregister_filesystem (struct file_system_type *); +extern struct vfsmount *kern_mount (struct file_system_type *);extern struct vfsmount *kern_mount_data (struct file_system_type *,void *,size_t ); -#define kern_mount (type) kern_mount_data(type, NULL, 0)extern void kern_unmount (struct vfsmount *mnt);extern int may_umount_tree (struct vfsmount *);extern int may_umount (struct vfsmount *);
include/linux/fs_context.h +44 -1
71 lines not on this page · raw message
include/linux/mount.h +3 -0
@@ -21,6 +21,7 @@ struct super_block;struct vfsmount ;struct dentry ;struct mnt_namespace ; +struct fs_context ;#define MNT_NOSUID 0x01#define MNT_NODEV 0x02
@@ -88,6 +89,8 @@ struct path;extern struct vfsmount *clone_private_mount (const struct path *path);struct file_system_type ; +extern struct vfsmount *vfs_create_mount (struct fs_context *fc, +unsigned int mnt_flags);extern struct vfsmount *vfs_kern_mount (struct file_system_type *type,int flags,const char *name,void *data,size_t data_size);
Miklos Szeredi
maintainerRe: [PATCH 10/32] VFS: Implement a filesystem superblock creation/configuration context [ver #8]
Quoted 200 lines · David Howells
Implement a filesystem context concept to be used during superblock creation for mount and superblock reconfiguration for remount.
The mounting procedure then becomes:
(1) Allocate new
fs_contextcontext.(2) Configure the context.
(3) Create superblock.
(4) Mount the superblock any number of times.
(5) Destroy the context.
Rather than calling
fs_type->mount(), anfs_contextstruct is created andfs_type->init_fs_context()is called to set it up.fs_type->fs_context_sizesays how much space should be allocated for the config context. Thefs_contextstruct is placed at the beginning and any extra space is for the filesystem's use.A set of operations has to be set by ->init_fs_context() to provide freeing, duplication, option parsing, binary data parsing, validation, mounting and superblock filling.
Legacy filesystems are supported by the provision of a set of legacy
fs_contextoperations that build up a list of mount options and then invokefs_type->mount()from within thefs_context->get_tree() operation. This allows all filesystems to be accessed usingfs_context.It should be noted that, whilst this patch adds a lot of lines of code, there is quite a bit of duplication with existing code that can be eliminated should all filesystems be converted over.
Signed-off-by David Howells <[email protected]>---
fs/Makefile | 3 fs/fs_context.c | 599 ++++++++++++++++++++++++++++++++++++++++++++ fs/internal.h | 3 fs/libfs.c | 17 + fs/namespace.c | 350 +++++++++++++++++--------- fs/super.c | 311 ++++++++++++++++++++++- include/linux/fs.h | 13 + include/linux/fs_context.h | 45 +++ include/linux/mount.h | 3 9 files changed, 1201 insertions(+), 143 deletions(-) create mode 100644 fs/fs_context.cfs/Makefile +2
-1@@ -12,7 +12,8 @@ obj-y := open.o read_write.o file_table.o super.o \ attr.o bad_inode.o file.o filesystems.o namespace.o \ seq_file.o xattr.o libfs.o fs-writeback.o \ pnode.o splice.o sync.o utimes.o d_path.o \ - stack.o fs_struct.o statfs.o fs_pin.o nsfs.o + stack.o fs_struct.o statfs.o fs_pin.o nsfs.o \ + fs_context.o ifeq ($(CONFIG_BLOCK),y) obj-y += buffer.o block_dev.o direct-io.o mpage.ofs/fs_context.c new file +131
-0@@ -0,0 +1,599 @@ +/* Provide a way to create a superblock configuration context within the kernel +* that allows a superblock to be set up prior to mounting. +* +* Copyright (C) 2017 Red Hat, Inc. All Rights Reserved. +* Written by David Howells ([email protected]) +* +* This program is free software; you can redistribute it and/or +* modify it under the terms of the GNU General Public Licence +* as published by the Free Software Foundation; either version +* 2 of the Licence, or (at your option) any later version. +*/ + +#define pr_fmt (fmt) KBUILD_MODNAME ": " fmt +#include <linux/fs_context.h> +#include <linux/fs.h> +#include <linux/mount.h> +#include <linux/nsproxy.h> +#include <linux/slab.h> +#include <linux/magic.h> +#include <linux/security.h> +#include <linux/parser.h> +#include <linux/mnt_namespace.h> +#include <linux/pid_namespace.h> +#include <linux/user_namespace.h> +#include <net/net_namespace.h> +#include "mount.h" + +enum legacy_fs_param { +LEGACY_FS_UNSET_PARAMS , +LEGACY_FS_NO_PARAMS , +LEGACY_FS_MONOLITHIC_PARAMS , +LEGACY_FS_INDIVIDUAL_PARAMS , +LEGACY_FS_MAGIC_PARAMS , +}; + +struct legacy_fs_context { +struct fs_context fc; +char *legacy_data;/* Data page for legacy filesystems */ +char *secdata; +size_t data_size; +enum legacy_fs_param param_type; +}; + +static const struct fs_context_operations legacy_fs_context_ops; + +static const match_table_t common_set_sb_flag = { + {SB_DIRSYNC ,"dirsync" }, + {SB_LAZYTIME ,"lazytime" }, + {SB_MANDLOCK ,"mand" }, + {SB_POSIXACL ,"posixacl" }, + {SB_RDONLY ,"ro" }, + {SB_SYNCHRONOUS ,"sync" }, + { }, +}; + +static const match_table_t common_clear_sb_flag = { + {SB_LAZYTIME ,"nolazytime" }, + {SB_MANDLOCK ,"nomand" }, + {SB_RDONLY ,"rw" }, + {SB_SILENT ,"silent" }, + {SB_SYNCHRONOUS ,"async" }, + { }, +}; + +static const match_table_t forbidden_sb_flag = { + {0 ,"bind" }, + {0 ,"move" }, + {0 ,"private" }, + {0 ,"remount" }, + {0 ,"shared" }, + {0 ,"slave" }, + {0 ,"unbindable" }, + {0 ,"rec" }, + {0 ,"noatime" }, + {0 ,"relatime" }, + {0 ,"norelatime" }, + {0 ,"strictatime" }, + {0 ,"nostrictatime" }, + {0 ,"nodiratime" }, + {0 ,"dev" }, + {0 ,"nodev" }, + {0 ,"exec" }, + {0 ,"noexec" }, + {0 ,"suid" }, + {0 ,"nosuid" }, + { }, +}; + +/* +* Check for a common mount option that manipulates s_flags. +*/ +static int vfs_parse_sb_flag_option (struct fs_context *fc,char *data) +{ +substring_t args[MAX_OPT_ARGS ]; +unsigned int token; + + token =match_token (data, common_set_sb_flag, args); +if (token) { + fc->sb_flags |= token; +return 1 ; + } + + token =match_token (data, common_clear_sb_flag, args); +if (token) { + fc->sb_flags &= ~token; +return 1 ; + } + + token =match_token (data, forbidden_sb_flag, args); +if (token) +return -EINVAL ; + +return 0 ; +} + +/** +* vfs_parse_fs_option - Add a single mount option to a superblock config +* @fc: The filesystem context to modify +* @opt: The option to apply. +* @len: The length of the option. +* +* A single mount option in string form is applied to the filesystem context +* being set up. Certain standard options (for example "ro") are translated +* into flag bits without going to the filesystem. The active security module +* is allowed to observe and poach options. Any other options are passed over +* to the filesystem to parse. +* +* This may be called multiple times for a context. +* +* Returns 0 on success and a negative error code on failure. In the event of +* failure, supplementary error information may have been set.
fs/fs_context.c line 141
Quoted 10 lines
fs/fs_context.c new file +10
-0+*/ +int vfs_parse_fs_option (struct fs_context *fc,char *opt,size_t len) +{ +int ret; + + ret =vfs_parse_sb_flag_option (fc, opt); +if (ret <0 ) +return ret; +if (ret ==1 ) +return 0 ;
Why is vfs_parse_sb_flag_option() not called from ->parse_option()?
That way, filesystem can reject unsupported generic options. We don't have that in the current API, but that doesn't mean the new API
shouldn't handle that case. Yeah, need to worry about backward
compat, so need a flag to say whether this comes from monolithic option block or fsfd write.
Also thinking: if we are giving this brand new API to fs developers, why not also give some helpers, so option parsing becomes easier, more consistent, etc... I'm thinking along the lines of module_param_*(). I.e. we give the parser a structure pointer and an array of {option name, structure member name, type} or {option name, get/set ops} and the helpers take care of the rest (parse, show). That isn't going to cover everything, but it might be good enough for most.
Of course, that can come later, while doing the conversion of filesystems to the new API.
Thanks,
Miklos
Re: [PATCH 10/32] VFS: Implement a filesystem superblock creation/configuration context [ver #8]
In reply to David HowellsQuoted 40 lines · David Howells
fs/super.c +40
-0+/** +* sget_fc - Find or create a superblock +* @fc: Filesystem context. +* @test: Comparison callback +* @set: Setup callback +* +* Find or create a superblock using the parameters stored in the filesystem +* context and the two callback functions. +* +* If an extant superblock is matched, then that will be returned with an +* elevated reference count that the caller must transfer or discard. +* +* If no match is made, a new superblock will be allocated and basic +* initialisation will be performed (s_type, s_fs_info and s_id will be set and +* the set() callback will be invoked), the superblock will be published and it +* will be returned in a partially constructed state with SB_BORN and SB_ACTIVE +* as yet unset. +*/ +struct super_block *sget_fc (struct fs_context *fc, +int (*test)(struct super_block *,struct fs_context *), +int (*set)(struct super_block *,struct fs_context *)) +{ +struct super_block *s =NULL ; +struct super_block *old; +int err; + +if (!(fc->sb_flags &SB_KERNMOUNT ) && + fc->purpose !=FS_CONTEXT_FOR_SUBMOUNT ) { +/* Don't allow mounting unless the caller has CAP_SYS_ADMIN +* over the namespace. +*/ +if (!(fc->fs_type->fs_flags &FS_USERNS_MOUNT ) && + !capable (CAP_SYS_ADMIN )) +return ERR_PTR (-EPERM ); +else if (!ns_capable (fc->user_ns,CAP_SYS_ADMIN )) +return ERR_PTR (-EPERM ); + } + +retry: +spin_lock (&sb_lock);
fs/super.c void generic_shutdown_super(struct super_block *sb) · line 522
Quoted 10 lines
fs/super.c +10
-0+if (test) { +hlist_for_each_entry (old, &fc->fs_type->fs_supers, s_instances) { +if (!test (old, fc)) +continue ; +if (fc->user_ns != old->s_user_ns) { +spin_unlock (&sb_lock); +if (s) { +up_write (&s->s_umount); +destroy_unused_super (s); + }
->s_umount is released once here and again in destroy_unused_super().
fs/super.c void generic_shutdown_super(struct super_block *sb) · line 529
Quoted 7 lines
fs/super.c +7
-0+return ERR_PTR (-EBUSY ); + } +if (!grab_super (old)) + goto retry; +if (s) { +up_write (&s->s_umount); +destroy_unused_super (s);
Same bug here.
Review
Quoted 2 lines
(quoted diff) +2
-0+ up_write(&s->s_umount); + destroy_unused_super(s);
And here.
- Eric
David Howells
maintainerRe: [PATCH 10/32] VFS: Implement a filesystem superblock creation/configuration context [ver #8]
Quoted 1 line · Eric Biggers
->s_umount is released once here and again in
destroy_unused_super().
Good catch, thanks. The interface has changed over the lifetime of the patches. How about the attached patch?
David
---
commit b3899e214a6a0e0551f6dc707b28d61b11e718a5
Author: David Howells <[email protected]> Date: Tue Jul 3 22:35:28 2018 +0100
vfs: Locking fix for sget_fc()
In sget_fc(), don't drop the s_umount lock before calling destroy_unused_super() as that will drop the lock.
fs/super.c +2 -8
@@ -516,19 +516,14 @@ struct super_block *sget_fc(struct fs_context *fc,continue ;if (fc->user_ns != old->s_user_ns) {spin_unlock (&sb_lock); -if (s) { -up_write (&s->s_umount); +if (s)destroy_unused_super (s); - }return ERR_PTR (-EBUSY ); }if (!grab_super (old)) goto retry; -if (s) { -up_write (&s->s_umount); +if (s)destroy_unused_super (s); - s =NULL ; - }return old; } }
@@ -545,7 +540,6 @@ struct super_block *sget_fc(struct fs_context *fc,if (err) { s->s_fs_info =NULL ;spin_unlock (&sb_lock); -up_write (&s->s_umount);destroy_unused_super (s);return ERR_PTR (err); }
Al Viro
maintainerRe: [PATCH 10/32] VFS: Implement a filesystem superblock creation/configuration context [ver #8]
fs/super.c struct super_block *sget_fc(struct fs_context *fc, · line 520
Quoted 4 lines · David Howells
fs/super.c +1
-2-if (s) { -up_write (&s->s_umount); +if (s)destroy_unused_super (s);
static void destroy_unused_super(struct super_block *s)
{
if (!s)
return;
...
}IOW, all of those should be unconditional.
David Howells
maintainerRe: [PATCH 10/32] VFS: Implement a filesystem superblock creation/configuration context [ver #8]
Quoted 1 line · Al Viro
IOW, all of those should be unconditional.
Fair point. How about the attached, then?
David
---
commit 1aa76514c426150af429d111cec256e81729fa6f
Author: David Howells <[email protected]> Date: Tue Jul 3 22:35:28 2018 +0100
vfs: Locking fix for sget_fc()
In sget_fc(), don't drop the s_umount lock before calling destroy_unused_super() as that will drop the lock.
fs/super.c +2 -10
@@ -516,19 +516,12 @@ struct super_block *sget_fc(struct fs_context *fc,continue ;if (fc->user_ns != old->s_user_ns) {spin_unlock (&sb_lock); -if (s) { -up_write (&s->s_umount); -destroy_unused_super (s); - } +destroy_unused_super (s);return ERR_PTR (-EBUSY ); }if (!grab_super (old)) goto retry; -if (s) { -up_write (&s->s_umount); -destroy_unused_super (s); - s =NULL ; - } +destroy_unused_super (s);return old; } }
@@ -545,7 +538,6 @@ struct super_block *sget_fc(struct fs_context *fc,if (err) { s->s_fs_info =NULL ;spin_unlock (&sb_lock); -up_write (&s->s_umount);destroy_unused_super (s);return ERR_PTR (err); }
David Howells
maintainerPATCH 11/32 VFS: Remove unused code after filesystem context changes [ver #8]
In reply to David HowellsRemove code that is now unused after the filesystem context changes.
---
fs/internal.h | 2 - fs/super.c | 62 -------------------------------------------- include/linux/lsm_hooks.h | 3 -- include/linux/security.h | 7 ----- security/security.c | 5 ---- security/selinux/hooks.c | 20 -------------- security/smack/smack_lsm.c | 33 ----------------------- 7 files changed, 132 deletions(-)
fs/internal.h +0 -2
@@ -101,8 +101,6 @@ extern struct file *get_empty_filp(void);extern int do_remount_sb (struct super_block *,int ,void *,size_t ,int ,struct fs_context *);extern bool trylock_super (struct super_block *sb); -extern struct dentry *mount_fs (struct file_system_type *, -int ,const char *,void *,size_t );extern struct super_block *user_get_super (dev_t );/*
fs/super.c +0 -62
68 lines not on this page · raw message
include/linux/lsm_hooks.h +0 -3
@@ -1519,8 +1519,6 @@ union security_list_options {void (*sb_free_security)(struct super_block *sb);int (*sb_copy_data)(char *orig,size_t orig_size,char *copy);int (*sb_remount)(struct super_block *sb,void *data,size_t data_size); -int (*sb_kern_mount)(struct super_block *sb,int flags, -void *data,size_t data_size);int (*sb_show_options)(struct seq_file *m,struct super_block *sb);int (*sb_statfs)(struct dentry *dentry); int (*sb_mount)(const char *dev_name, const struct path *path,
@@ -1867,7 +1865,6 @@ struct security_hook_heads {struct hlist_head sb_free_security;struct hlist_head sb_copy_data;struct hlist_head sb_remount; -struct hlist_head sb_kern_mount;struct hlist_head sb_show_options;struct hlist_head sb_statfs;struct hlist_head sb_mount;
include/linux/security.h +0 -7
@@ -246,7 +246,6 @@ int security_sb_alloc(struct super_block *sb);void security_sb_free (struct super_block *sb);int security_sb_copy_data (char *orig,size_t orig_size,char *copy);int security_sb_remount (struct super_block *sb,void *data,size_t data_size); -int security_sb_kern_mount (struct super_block *sb,int flags,void *data,size_t data_size);int security_sb_show_options (struct seq_file *m,struct super_block *sb);int security_sb_statfs (struct dentry *dentry); int security_sb_mount(const char *dev_name, const struct path *path,
@@ -606,12 +605,6 @@ static inline int security_sb_remount(struct super_block *sb, void *data, size_treturn 0 ; } -static inline int security_sb_kern_mount (struct super_block *sb,int flags, -void *data,size_t data_size) -{ -return 0 ; -} -static inline int security_sb_show_options (struct seq_file *m,struct super_block *sb) {
security/security.c +0 -5
@@ -425,11 +425,6 @@ int security_sb_remount(struct super_block *sb, void *data, size_t data_size)return call_int_hook (sb_remount,0 , sb, data, data_size); } -int security_sb_kern_mount (struct super_block *sb,int flags,void *data,size_t data_size) -{ -return call_int_hook (sb_kern_mount,0 , sb, flags, data, data_size); -} -int security_sb_show_options (struct seq_file *m,struct super_block *sb) {return call_int_hook (sb_show_options,0 , m, sb);
security/selinux/hooks.c +0 -20
@@ -2920,25 +2920,6 @@ static int selinux_sb_remount(struct super_block *sb, void *data, size_t data_si goto out_free_opts; } -static int selinux_sb_kern_mount (struct super_block *sb,int flags,void *data,size_t data_size) -{ -const struct cred *cred =current_cred (); -struct common_audit_data ad; -int rc; - - rc =superblock_doinit (sb, data); -if (rc) -return rc; - -/* Allow all mounts performed by the kernel */ -if (flags &MS_KERNMOUNT ) -return 0 ; - - ad.type =LSM_AUDIT_DATA_DENTRY ; - ad.u.dentry = sb->s_root; -return superblock_has_perm (cred, sb,FILESYSTEM__MOUNT , &ad); -} -static int selinux_sb_statfs (struct dentry *dentry) {const struct cred *cred =current_cred ();
@@ -7149,7 +7130,6 @@ static struct security_hook_list selinux_hooks[] __lsm_ro_after_init = {LSM_HOOK_INIT (sb_free_security, selinux_sb_free_security),LSM_HOOK_INIT (sb_copy_data, selinux_sb_copy_data),LSM_HOOK_INIT (sb_remount, selinux_sb_remount), -LSM_HOOK_INIT (sb_kern_mount, selinux_sb_kern_mount),LSM_HOOK_INIT (sb_show_options, selinux_sb_show_options),LSM_HOOK_INIT (sb_statfs, selinux_sb_statfs), LSM_HOOK_INIT(sb_mount, selinux_mount),
security/smack/smack_lsm.c +0 -33
@@ -1150,38 +1150,6 @@ static int smack_set_mnt_opts(struct super_block *sb,return 0 ; } -/** -* smack_sb_kern_mount - Smack specific mount processing -* @sb: the file system superblock -* @flags: the mount flags -* @data: the smack mount options -* -* Returns 0 on success, an error code on failure -*/ -static int smack_sb_kern_mount (struct super_block *sb,int flags, -void *data,size_t data_size) -{ -int rc =0 ; -char *options = data; -struct security_mnt_opts opts; - -security_init_mnt_opts (&opts); - -if (!options) - goto out; - - rc =smack_parse_opts_str (options, &opts); -if (rc) - goto out_err; - -out: - rc =smack_set_mnt_opts (sb, &opts,0 ,NULL ); - -out_err: -security_free_mnt_opts (&opts); -return rc; -} -/** * smack_sb_statfs - Smack check on statfs * @dentry: identifies the file system in question
@@ -4942,7 +4910,6 @@ static struct security_hook_list smack_hooks[] __lsm_ro_after_init = {LSM_HOOK_INIT (sb_alloc_security, smack_sb_alloc_security),LSM_HOOK_INIT (sb_free_security, smack_sb_free_security),LSM_HOOK_INIT (sb_copy_data, smack_sb_copy_data), -LSM_HOOK_INIT (sb_kern_mount, smack_sb_kern_mount),LSM_HOOK_INIT (sb_statfs, smack_sb_statfs),LSM_HOOK_INIT (sb_set_mnt_opts, smack_set_mnt_opts), LSM_HOOK_INIT(sb_parse_opts_str, smack_parse_opts_str),
David Howells
maintainerPATCH 12/32 procfs: Move proc_fill_super() to fs/proc/root.c [ver #8]
In reply to David HowellsMove proc_fill_super() to fs/proc/root.c as that's where the other superblock stuff is.
---
fs/proc/inode.c | 49 +------------------------------------------------ fs/proc/internal.h | 4 +--- fs/proc/root.c | 48 +++++++++++++++++++++++++++++++++++++++++++++++- 3 files changed, 49 insertions(+), 52 deletions(-)
fs/proc/inode.c +1 -48
@@ -24,7 +24,6 @@#include <linux/seq_file.h> #include <linux/slab.h> #include <linux/mount.h> -#include <linux/magic.h> #include <linux/uaccess.h>
@@ -123,7 +122,7 @@ static int proc_show_options(struct seq_file *seq, struct dentry *root)return 0 ; } -static const struct super_operations proc_sops = { +const struct super_operations proc_sops = { .alloc_inode = proc_alloc_inode, .destroy_inode = proc_destroy_inode, .drop_inode = generic_delete_inode,
@@ -489,49 +488,3 @@ struct inode *proc_get_inode(struct super_block *sb, struct proc_dir_entry *de)pde_put (de);return inode; } - -int proc_fill_super (struct super_block *s,void *data,size_t data_size, -int silent) -{ -struct pid_namespace *ns =get_pid_ns (s->s_fs_info); -struct inode *root_inode; -int ret; - -if (!proc_parse_options (data, ns)) -return -EINVAL ; - -/* User space would break if executables or devices appear on proc */ - s->s_iflags |=SB_I_USERNS_VISIBLE |SB_I_NOEXEC |SB_I_NODEV ; - s->s_flags |=SB_NODIRATIME |SB_NOSUID |SB_NOEXEC ; - s->s_blocksize =1024 ; - s->s_blocksize_bits =10 ; - s->s_magic =PROC_SUPER_MAGIC ; - s->s_op = &proc_sops; - s->s_time_gran =1 ; - -/* -* procfs isn't actually a stacking filesystem; however, there is -* too much magic going on inside it to permit stacking things on -* top of it -*/ - s->s_stack_depth =FILESYSTEM_MAX_STACK_DEPTH ; - -pde_get (&proc_root); - root_inode =proc_get_inode (s, &proc_root); -if (!root_inode) { -pr_err ("proc_fill_super: get root inode failed\n" ); -return -ENOMEM ; - } - - s->s_root =d_make_root (root_inode); -if (!s->s_root) { -pr_err ("proc_fill_super: allocate dentry failed\n" ); -return -ENOMEM ; - } - - ret =proc_setup_self (s); -if (ret) { -return ret; - } -return proc_setup_thread_self (s); -}
fs/proc/internal.h +1 -3
@@ -200,13 +200,12 @@ struct pde_opener {struct completion *c; } __randomize_layout;extern const struct inode_operations proc_link_inode_operations; -extern const struct inode_operations proc_pid_link_inode_operations; +extern const struct super_operations proc_sops;void proc_init_kmemcache (void );void set_proc_pid_nlink (void );extern struct inode *proc_get_inode (struct super_block *,struct proc_dir_entry *); -extern int proc_fill_super (struct super_block *,void *,size_t ,int );extern void proc_entry_rundown (struct proc_dir_entry *);/*
@@ -264,7 +263,6 @@ static inline void proc_tty_init(void) {}* root.c */ extern struct proc_dir_entry proc_root; -extern int proc_parse_options (char *options,struct pid_namespace *pid);extern void proc_self_init (void );extern int proc_remount (struct super_block *,int *,char *,size_t );
fs/proc/root.c +47 -1
66 lines not on this page · raw message
David Howells
maintainerPATCH 13/32 proc: Add fs_context support to procfs [ver #8]
In reply to David HowellsAdd fs_context support to procfs.
---
fs/proc/inode.c | 2 - fs/proc/internal.h | 2 - fs/proc/root.c | 179 ++++++++++++++++++++++++++++++++++------------------ 3 files changed, 120 insertions(+), 63 deletions(-)
fs/proc/inode.c +1 -1
@@ -128,7 +128,7 @@ const struct super_operations proc_sops = { .drop_inode = generic_delete_inode, .evict_inode = proc_evict_inode, .statfs = simple_statfs, - .remount_fs = proc_remount, + .reconfigure = proc_reconfigure, .show_options = proc_show_options, };
fs/proc/internal.h +1 -1
@@ -265,7 +265,7 @@ static inline void proc_tty_init(void) {}extern struct proc_dir_entry proc_root;extern void proc_self_init (void ); -extern int proc_remount (struct super_block *,int *,char *,size_t ); +extern int proc_reconfigure (struct super_block *,struct fs_context *);/* * task_[no]mmu.c
fs/proc/root.c +118 -61
251 lines not on this page · raw message
David Howells
maintainerPATCH 14/32 ipc: Convert mqueue fs to fs_context [ver #8]
In reply to David HowellsConvert the mqueue filesystem to use the filesystem context stuff.
Notes:
(1) The relevant ipc namespace is selected in when the context is initialised (and it defaults to the current task's ipc namespace). The caller can override this before calling vfs_get_tree().
(2) Rather than simply calling kern_mount_data(), mq_init_ns() and mq_internal_mount() create a context, adjust it and then do the rest of the mount procedure.
(3) The lazy mqueue mounting on creation of a new namespace is retained from a previous patch, but the avoidance of sget() if no superblock yet exists is reverted and the superblock is again keyed on the namespace pointer.
Yes, there was a performance gain in not searching the superblock hash, but it's only paid once per ipc namespace - and only if someone uses mqueue within that namespace, so I'm not sure it's worth it, especially as calling sget() allows avoidance of recursion.
---
ipc/mqueue.c | 121 +++++++++++++++++++++++++++++++++++++++++++++++----------- 1 file changed, 99 insertions(+), 22 deletions(-)
ipc/mqueue.c +99 -22
@@ -18,6 +18,7 @@#include <linux/pagemap.h> #include <linux/file.h> #include <linux/mount.h> +#include <linux/fs_context.h> #include <linux/namei.h> #include <linux/sysctl.h> #include <linux/poll.h>
@@ -42,6 +43,10 @@#include <net/sock.h> #include "util.h" +struct mqueue_fs_context { +struct ipc_namespace *ipc_ns; +}; +#define MQUEUE_MAGIC 0x19800202#define DIRENT_SIZE 20#define FILENT_SIZE 80
@@ -87,9 +92,11 @@ struct mqueue_inode_info {unsigned long qsize;/* size of queue in memory (sum of all msgs) */ }; +static struct file_system_type mqueue_fs_type;static const struct inode_operations mqueue_dir_inode_operations;static const struct file_operations mqueue_file_operations;static const struct super_operations mqueue_super_ops; +static const struct fs_context_operations mqueue_fs_context_ops;static void remove_notification (struct mqueue_inode_info *info);static struct kmem_cache *mqueue_inode_cachep;
@@ -322,7 +329,7 @@ static struct inode *mqueue_get_inode(struct super_block *sb,return ERR_PTR (ret); } -static int mqueue_fill_super (struct super_block *sb,void *data,size_t data_size,int silent) +static int mqueue_fill_super (struct super_block *sb,struct fs_context *fc) {struct inode *inode;struct ipc_namespace *ns = sb->s_fs_info;
@@ -343,19 +350,84 @@ static int mqueue_fill_super(struct super_block *sb, void *data, size_t data_sizreturn 0 ; } -static struct dentry *mqueue_mount (struct file_system_type *fs_type, -int flags,const char *dev_name, -void *data,size_t data_size) +static int mqueue_get_tree (struct fs_context *fc) { -struct ipc_namespace *ns; -if (flags &SB_KERNMOUNT ) { - ns = data; - data =NULL ; - }else { - ns = current->nsproxy->ipc_ns; +struct mqueue_fs_context *ctx = fc->fs_private; + +/* As a shortcut, if the namespace already has a superblock created, +* use the root from that directly rather than invoking sget() again. +*/ +spin_lock (&mq_lock); +if (ctx->ipc_ns->mq_mnt) { + fc->root =dget (ctx->ipc_ns->mq_mnt->mnt_sb->s_root); +atomic_inc (&fc->root->d_sb->s_active); } -return mount_ns (fs_type, flags, data, data_size, ns, ns->user_ns, - mqueue_fill_super); +spin_unlock (&mq_lock); +if (fc->root) { +down_write (&fc->root->d_sb->s_umount); +return 0 ; + } + + fc->s_fs_info = ctx->ipc_ns; +return vfs_get_super (fc, vfs_get_keyed_super, mqueue_fill_super); +} + +static void mqueue_fs_context_free (struct fs_context *fc) +{ +struct mqueue_fs_context *ctx = fc->fs_private; + +if (ctx->ipc_ns) +put_ipc_ns (ctx->ipc_ns); +kfree (ctx); +} + +static int mqueue_init_fs_context (struct fs_context *fc, +struct dentry *reference) +{ +struct mqueue_fs_context *ctx; + + ctx =kzalloc (sizeof (struct mqueue_fs_context ),GFP_KERNEL ); +if (!ctx) +return -ENOMEM ; + + ctx->ipc_ns =get_ipc_ns (current->nsproxy->ipc_ns); + fc->fs_private = ctx; + fc->ops = &mqueue_fs_context_ops; +return 0 ; +} + +static struct vfsmount *mq_create_mount (struct ipc_namespace *ns) +{ +struct mqueue_fs_context *ctx; +struct fs_context *fc; +struct vfsmount *mnt; +int ret; + + fc =vfs_new_fs_context (&mqueue_fs_type,NULL ,0 , +FS_CONTEXT_FOR_KERNEL_MOUNT ); +if (IS_ERR (fc)) +return ERR_CAST (fc); + + ctx = fc->fs_private; +put_ipc_ns (ctx->ipc_ns); + ctx->ipc_ns =get_ipc_ns (ns); + + ret =vfs_get_tree (fc); +if (ret <0 ) + goto err_fc; + + mnt =vfs_create_mount (fc,0 ); +if (IS_ERR (mnt)) { + ret =PTR_ERR (mnt); + goto err_fc; + } + +put_fs_context (fc); +return mnt; + +err_fc: +put_fs_context (fc); +return ERR_PTR (ret); }static void init_once (void *foo)
@@ -1521,15 +1593,22 @@ static const struct super_operations mqueue_super_ops = { .statfs = simple_statfs, }; +static const struct fs_context_operations mqueue_fs_context_ops = { + .free = mqueue_fs_context_free, + .get_tree = mqueue_get_tree, +}; +static struct file_system_type mqueue_fs_type = { - .name ="mqueue" , - .mount = mqueue_mount, - .kill_sb = kill_litter_super, - .fs_flags =FS_USERNS_MOUNT , + .name ="mqueue" , + .init_fs_context = mqueue_init_fs_context, + .kill_sb = kill_litter_super, + .fs_flags =FS_USERNS_MOUNT , };int mq_init_ns (struct ipc_namespace *ns) { +struct vfsmount *m; + ns->mq_queues_count =0 ; ns->mq_queues_max =DFLT_QUEUESMAX ; ns->mq_msg_max =DFLT_MSGMAX ;
@@ -1537,12 +1616,10 @@ int mq_init_ns(struct ipc_namespace *ns) ns->mq_msg_default =DFLT_MSG ; ns->mq_msgsize_default =DFLT_MSGSIZE ; - ns->mq_mnt =kern_mount_data (&mqueue_fs_type, ns,0 ); -if (IS_ERR (ns->mq_mnt)) { -int err =PTR_ERR (ns->mq_mnt); - ns->mq_mnt =NULL ; -return err; - } + m =mq_create_mount (&init_ipc_ns); +if (IS_ERR (m)) +return PTR_ERR (ns->mq_mnt); + ns->mq_mnt = m;return 0 ; }
David Howells
maintainerPATCH 15/32 cpuset: Use fs_context [ver #8]
In reply to David HowellsMake the cpuset filesystem use the filesystem context. This is potentially tricky as the cpuset fs is almost an alias for the cgroup filesystem, but with some special parameters.
This can, however, be handled by setting up an appropriate cgroup filesystem and returning the root directory of that as the root dir of this one.
---
kernel/cgroup/cpuset.c | 66 ++++++++++++++++++++++++++++++++++++++---------- 1 file changed, 52 insertions(+), 14 deletions(-)
kernel/cgroup/cpuset.c +52 -14
@@ -38,7 +38,7 @@#include <linux/mm.h> #include <linux/memory.h> #include <linux/export.h> -#include <linux/mount.h> +#include <linux/fs_context.h> #include <linux/namei.h> #include <linux/pagemap.h> #include <linux/proc_fs.h>
@@ -315,26 +315,64 @@ static inline bool is_in_v2_mode(void)* users. If someone tries to mount the "cpuset" filesystem, we * silently switch it to mount "cgroup" instead */ -static struct dentry *cpuset_mount (struct file_system_type *fs_type, -int flags,const char *unused_dev_name, -void *data,size_t data_size) +static int cpuset_get_tree (struct fs_context *fc) { -struct file_system_type *cgroup_fs =get_fs_type ("cgroup" ); -struct dentry *ret =ERR_PTR (-ENODEV ); +static const char opts[] ="cpuset,noprefix,release_agent=/sbin/cpuset_release_agent" ; +struct file_system_type *cgroup_fs; +struct fs_context *cg_fc; +char *p; +int ret = -ENODEV ; + + cgroup_fs =get_fs_type ("cgroup" );if (cgroup_fs) { -char mountopts[] = -"cpuset,noprefix," -"release_agent=/sbin/cpuset_release_agent" ; - ret = cgroup_fs->mount (cgroup_fs, flags, unused_dev_name, - mountopts, data_size); -put_filesystem (cgroup_fs); + ret =PTR_ERR (cgroup_fs); + goto out; + } + + cg_fc =vfs_new_fs_context (cgroup_fs,NULL , fc->sb_flags, fc->purpose); +put_filesystem (cgroup_fs); +if (IS_ERR (cg_fc)) { + ret =PTR_ERR (cg_fc); + goto out; } + + ret = -ENOMEM ; + p =kstrdup (opts,GFP_KERNEL ); +if (!p) + goto out_fc; + + ret =generic_parse_monolithic (fc, p,sizeof (opts) -1 ); +kfree (p); +if (ret <0 ) + goto out_fc; + + ret =vfs_get_tree (cg_fc); +if (ret <0 ) + goto out_fc; + + fc->root =dget (cg_fc->root); + ret =0 ; + +out_fc: +put_fs_context (cg_fc); +out:return ret; } +static const struct fs_context_operations cpuset_fs_context_ops = { + .get_tree = cpuset_get_tree, +}; + +static int cpuset_init_fs_context (struct fs_context *fc, +struct dentry *reference) +{ + fc->ops = &cpuset_fs_context_ops; +return 0 ; +} +static struct file_system_type cpuset_fs_type = { - .name ="cpuset" , - .mount = cpuset_mount, + .name ="cpuset" , + .init_fs_context = cpuset_init_fs_context, };/*
David Howells
maintainerPATCH 16/32 kernfs, sysfs, cgroup, intel_rdt: Support fs_context [ver #8]
In reply to David HowellsMake kernfs support superblock creation/mount/remount with fs_context.
This requires that sysfs, cgroup and intel_rdt, which are built on kernfs, be made to support fs_context also.
Notes:
(1) A kernfs_fs_context struct is created to wrap fs_context and the kernfs mount parameters are moved in here (or are in fs_context).
(2) kernfs_mount{,_ns}() are made into kernfs_get_tree(). The extra namespace tag parameter is passed in the context if desired
(3) kernfs_free_fs_context() is provided as a destructor for the kernfs_fs_context struct, but for the moment it does nothing except get called in the right places.
(4) sysfs doesn't wrap kernfs_fs_context since it has no parameters to pass, but possibly this should be done anyway in case someone wants to add a parameter in future.
(5) A cgroup_fs_context struct is created to wrap kernfs_fs_context and the cgroup v1 and v2 mount parameters are all moved there.
(6) cgroup1 parameter parsing error messages are now handled by invalf(), which allows userspace to collect them directly.
(7) cgroup1 parameter cleanup is now done in the context destructor rather than in the mount/get_tree and remount functions.
Weirdies:
(*) cgroup_do_get_tree() calls cset_cgroup_from_root() with locks held,
but then uses the resulting pointer after dropping the locks. I'm told this is okay and needs commenting.
(*) The cgroup refcount web. This really needs documenting.
(*) cgroup2 only has one root?
---
arch/x86/kernel/cpu/intel_rdt_rdtgroup.c | 129 +++++++------ fs/kernfs/mount.c | 89 +++++---- fs/sysfs/mount.c | 64 +++++- include/linux/cgroup.h | 3 include/linux/kernfs.h | 36 ++-- kernel/cgroup/cgroup-internal.h | 42 +++- kernel/cgroup/cgroup-v1.c | 296 ++++++++++++++---------------- kernel/cgroup/cgroup.c | 224 +++++++++++++---------- 8 files changed, 483 insertions(+), 400 deletions(-)
arch/x86/kernel/cpu/intel_rdt_rdtgroup.c +71 -58
@@ -36,6 +36,12 @@#include <asm/intel_rdt_sched.h> #include "intel_rdt.h" +struct rdt_fs_context { +struct kernfs_fs_context kfc; +bool enable_cdpl2; +bool enable_cdpl3; +}; +DEFINE_STATIC_KEY_FALSE (rdt_enable_key);DEFINE_STATIC_KEY_FALSE (rdt_mon_enable_key);DEFINE_STATIC_KEY_FALSE (rdt_alloc_enable_key);
@@ -1104,39 +1110,6 @@ static void cdp_disable_all(void)cdpl2_disable (); } -static int parse_rdtgroupfs_options (char *data) -{ -char *token, *o = data; -int ret =0 ; - -while ((token =strsep (&o,"," )) !=NULL ) { -if (!*token) { - ret = -EINVAL ; - goto out; - } - -if (!strcmp (token,"cdp" )) { - ret =cdpl3_enable (); -if (ret) - goto out; - }else if (!strcmp (token,"cdpl2" )) { - ret =cdpl2_enable (); -if (ret) - goto out; - }else { - ret = -EINVAL ; - goto out; - } - } - -return 0 ; - -out: -pr_err ("Invalid mount option \"%s\"\n" , token); - -return ret; -} -/* * We don't allow rdtgroup directories to be created anywhere * except the root directory. Thus when looking for the rdtgroup
@@ -1205,13 +1178,11 @@ static int mkdir_mondata_all(struct kernfs_node *parent_kn,struct rdtgroup *prgrp, struct kernfs_node **mon_data_kn); -static struct dentry *rdt_mount (struct file_system_type *fs_type, -int flags,const char *unused_dev_name, -void *data,size_t data_size) +static int rdt_get_tree (struct fs_context *fc) { +struct rdt_fs_context *ctx = fc->fs_private;struct rdt_domain *dom;struct rdt_resource *r; -struct dentry *dentry;int ret;cpus_read_lock ();
@@ -1220,47 +1191,46 @@ static struct dentry *rdt_mount(struct file_system_type *fs_type,* resctrl file system can only be mounted once. */ if (static_branch_unlikely (&rdt_enable_key)) { - dentry =ERR_PTR (-EBUSY ); + ret = -EBUSY ; goto out; } - ret =parse_rdtgroupfs_options (data); -if (ret) { - dentry =ERR_PTR (ret); - goto out_cdp; +if (ctx->enable_cdpl2) { + ret =cdpl2_enable (); +if (ret <0 ) + goto out_cdp; + } + +if (ctx->enable_cdpl3) { + ret =cdpl3_enable (); +if (ret <0 ) + goto out_cdp; }closid_init (); ret =rdtgroup_create_info_dir (rdtgroup_default.kn); -if (ret) { - dentry =ERR_PTR (ret); +if (ret <0 ) goto out_cdp; - }if (rdt_mon_capable) { ret =mongroup_create_dir (rdtgroup_default.kn,NULL ,"mon_groups" , &kn_mongrp); -if (ret) { - dentry =ERR_PTR (ret); +if (ret <0 ) goto out_info; - }kernfs_get (kn_mongrp); ret =mkdir_mondata_all (rdtgroup_default.kn, &rdtgroup_default, &kn_mondata); -if (ret) { - dentry =ERR_PTR (ret); +if (ret <0 ) goto out_mongrp; - }kernfs_get (kn_mondata); rdtgroup_default.mon.mon_data_kn = kn_mondata; } - dentry =kernfs_mount (fs_type, flags, rdt_root, -RDTGROUP_SUPER_MAGIC ,NULL ); -if (IS_ERR (dentry)) + ret =kernfs_get_tree (fc); +if (ret <0 ) goto out_mondata;if (rdt_alloc_capable)
@@ -1293,8 +1263,51 @@ static struct dentry *rdt_mount(struct file_system_type *fs_type,rdt_last_cmd_clear ();mutex_unlock (&rdtgroup_mutex);cpus_read_unlock (); +return ret; +} + +static int rdt_parse_option (struct fs_context *fc,char *opt,size_t len) +{ +struct rdt_fs_context *ctx = fc->fs_private; + +if (strcmp (opt,"cdp" ) ==0 ) { + ctx->enable_cdpl3 = true; +return 0 ; + } +if (strcmp (opt,"cdpl2" ) ==0 ) { + ctx->enable_cdpl2 = true; +return 0 ; + } + +return -EINVAL ; +} + +static void rdt_fs_context_free (struct fs_context *fc) +{ +struct rdt_fs_context *ctx = fc->fs_private; -return dentry; +kernfs_free_fs_context (&ctx->kfc); +} + +static const struct fs_context_operations rdt_fs_context_ops = { + .free = rdt_fs_context_free, + .parse_option = rdt_parse_option, + .get_tree = rdt_get_tree, +}; + +static int rdt_init_fs_context (struct fs_context *fc,struct dentry *reference) +{ +struct rdt_fs_context *ctx; + + ctx =kzalloc (sizeof (struct rdt_fs_context ),GFP_KERNEL ); +if (!ctx) +return -ENOMEM ; + + ctx->kfc.root = rdt_root; + ctx->kfc.magic =RDTGROUP_SUPER_MAGIC ; + fc->fs_private = ctx; + fc->ops = &rdt_fs_context_ops; +return 0 ; }static int reset_all_ctrls (struct rdt_resource *r)
@@ -1459,9 +1472,9 @@ static void rdt_kill_sb(struct super_block *sb) }static struct file_system_type rdt_fs_type = { - .name ="resctrl" , - .mount = rdt_mount, - .kill_sb = rdt_kill_sb, + .name ="resctrl" , + .init_fs_context = rdt_init_fs_context, + .kill_sb = rdt_kill_sb, }; static int mon_addfile(struct kernfs_node *parent_kn, const char *name,
fs/kernfs/mount.c +45 -44
163 lines not on this page · raw message
fs/sysfs/mount.c +45 -19
88 lines not on this page · raw message
include/linux/cgroup.h +2 -1
@@ -821,10 +821,11 @@ copy_cgroup_ns(unsigned long flags, struct user_namespace *user_ns,#endif /* !CONFIG_CGROUPS */ -static inline void get_cgroup_ns (struct cgroup_namespace *ns) +static inline struct cgroup_namespace *get_cgroup_ns (struct cgroup_namespace *ns) {if (ns)refcount_inc (&ns->count); +return ns; }static inline void put_cgroup_ns (struct cgroup_namespace *ns)
include/linux/kernfs.h +21 -15
@@ -16,6 +16,7 @@#include <linux/rbtree.h> #include <linux/atomic.h> #include <linux/wait.h> +#include <linux/fs_context.h> struct file ;struct dentry ;
@@ -25,6 +26,7 @@ struct vm_area_struct;struct super_block ;struct file_system_type ; +struct kernfs_fs_context ;struct kernfs_open_node ;struct kernfs_iattrs ;
@@ -166,7 +168,7 @@ struct kernfs_node {* kernfs_node parameter. */ struct kernfs_syscall_ops { -int (*remount_fs)(struct kernfs_root *root,int *flags,char *data); +int (*reconfigure)(struct kernfs_root *root,struct kernfs_fs_context *kfc);int (*show_options)(struct seq_file *sf,struct kernfs_root *root); int (*mkdir)(struct kernfs_node *parent, const char *name,
@@ -267,6 +269,19 @@ struct kernfs_ops {#endif }; +/* +* The kernfs superblock creation/mount parameter context. +*/ +struct kernfs_fs_context { +struct kernfs_root *root;/* Root of the hierarchy being mounted */ +void *ns_tag;/* Namespace tag of the mount (or NULL) */ +unsigned long magic;/* File system specific magic number */ + +/* The following are set/used by kernfs_mount() */ +struct kernfs_super_info *info;/* The new superblock info */ +bool new_sb_created;/* Set to T if we allocated a new sb */ +}; +#ifdef CONFIG_KERNFS static inline enum kernfs_node_type kernfs_type (struct kernfs_node *kn)
@@ -350,9 +365,7 @@ int kernfs_setattr(struct kernfs_node *kn, const struct iattr *iattr);void kernfs_notify (struct kernfs_node *kn);const void *kernfs_super_ns (struct super_block *sb); -struct dentry *kernfs_mount_ns (struct file_system_type *fs_type,int flags, -struct kernfs_root *root,unsigned long magic, -bool *new_sb_created,const void *ns); +int kernfs_get_tree (struct fs_context *fc);void kernfs_kill_sb (struct super_block *sb);struct super_block *kernfs_pin_sb (struct kernfs_root *root,const void *ns);
@@ -454,11 +467,8 @@ static inline void kernfs_notify(struct kernfs_node *kn) { }static inline const void *kernfs_super_ns (struct super_block *sb) {return NULL ; } -static inline struct dentry * -kernfs_mount_ns (struct file_system_type *fs_type,int flags, -struct kernfs_root *root,unsigned long magic, -bool *new_sb_created,const void *ns) -{return ERR_PTR (-ENOSYS ); } +static inline int kernfs_get_tree (struct kernfs_fs_context *fc) +{return -ENOSYS ; }static inline void kernfs_kill_sb (struct super_block *sb) { }
@@ -535,13 +545,9 @@ static inline int kernfs_rename(struct kernfs_node *kn, return kernfs_rename_ns(kn, new_parent, new_name, NULL); } -static inline struct dentry * -kernfs_mount (struct file_system_type *fs_type,int flags, -struct kernfs_root *root,unsigned long magic, -bool *new_sb_created) +static inline void kernfs_free_fs_context (struct kernfs_fs_context *kfc) { -return kernfs_mount_ns (fs_type, flags, root, - magic, new_sb_created,NULL ); +/* Note that we don't deal with kfc->ns_tag here. */ }#endif /* __LINUX_KERNFS_H */
kernel/cgroup/cgroup-internal.h +25 -17
67 lines not on this page · raw message
kernel/cgroup/cgroup-v1.c +143 -153
460 lines not on this page · raw message
kernel/cgroup/cgroup.c +131 -93
320 lines not on this page · raw message
Re: [16/32] kernfs, sysfs, cgroup, intel_rdt: Support fs_context [ver #8]
On Fri, May 25, 2018 at 01:07:08AM +0100, David Howells wrote:
...
Quoted 5 lines
(quoted diff) +0
-1@@ -1972,57 +1957,51 @@ int cgroup_setup_root(struct cgroup_root *root, u16 ss_mask, int ref_flags) return ret; } -struct dentry *cgroup_do_mount(struct file_system_type *fs_type, int flags,
Review int cgroup_setup_root(struct cgroup_root *root, u16 ss_mask, int ref_flags) · line 1965
Quoted 10 lines
(quoted diff) +5
-4- struct cgroup_root *root, unsigned long magic, - struct cgroup_namespace *ns) +int cgroup_do_get_tree(struct fs_context *fc) { - struct dentry *dentry; - bool new_sb; + struct cgroup_fs_context *ctx = fc->fs_private; + int ret; + + ctx->kfc.root = ctx->root->kf_root;
[root@fc24 ~]# mount -t cgroup -o none,name=zdtmtst xxx /mnt/test [root@fc24 ~]# mkdir /mnt/test/holder
[root@fc24 ~]# umount /mnt/test
[root@fc24 ~]# mount -t cgroup -o none,name=zdtmtst xxx /mnt/test Killed
ctx->root can be NULL here
[ 93.719897] BUG: unable to handle kernel NULL pointer dereference at 0000000000000000 [ 93.720097] PGD 80000002115f5067 P4D 80000002115f5067 PUD 1ef421067 PMD 0 [ 93.720179] Oops: 0000 [#1] SMP PTI [ 93.720257] CPU: 1 PID: 13843 Comm: cgroup04 Not tainted 4.18.0-rc1-next-20180621+ #1 [ 93.720342] Hardware name: Google Google Compute Engine/Google Compute Engine, BIOS Google 01/01/2011 [ 93.720432] RIP: 0010:cgroup_do_get_tree+0x1b/0xf0 [ 93.720515] Code: 00 00 02 5b 5d c3 66 0f 1f 84 00 00 00 00 00 0f 1f 44 00 00 41 54 55 49 89 fc 53 48 83 ec 08 48 8b 9f 90 00 00 00 48 8b 43 20 <48> 8b 00 48 89 03 e8 8a cc 1e 00 85 c0 0f 88 97 00 00 00 48 81 7b [ 93.720655] RSP: 0018:ffffb07941b03df8 EFLAGS: 00010292 [ 93.720740] RAX: 0000000000000000 RBX: ffff9ba3527da300 RCX: 0000000000000000 [ 93.720819] RDX: 0000000000000000 RSI: 0000000000000001 RDI: ffff9ba34d47b400 [ 93.720897] RBP: ffffb07941b03e58 R08: 0000000000000000 R09: 0000000000000002 [ 93.720975] R10: 0000000000000000 R11: 4aee8a3cb0beb9ec R12: ffff9ba34d47b400 [ 93.721053] R13: ffff9ba351518000 R14: ffffffff961705d4 R15: ffff9ba35143f000 [ 93.721131] FS: 000015418d893740(0000) GS:ffff9ba35fd00000(0000) knlGS:0000000000000000 [ 93.721233] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 [ 93.721336] CR2: 0000000000000000 CR3: 00000001c4658004 CR4: 00000000001606e0 [ 93.721421] Call Trace: [ 93.721508] cgroup1_get_tree+0x57c/0x640 [ 93.721587] vfs_get_tree+0x6e/0x180 [ 93.721665] do_mount+0x76b/0xa80 [ 93.721753] ksys_mount+0x80/0xd0 [ 93.721831] __x64_sys_mount+0x21/0x30 [ 93.721908] do_syscall_64+0x60/0x1b0 [ 93.721987] entry_SYSCALL_64_after_hwframe+0x49/0xbe [ 93.722065] RIP: 0033:0x15418d3bc85a
I think we need something like this:
kernel/cgroup/cgroup-v1.c +2 -0
@@ -1192,6 +1192,7 @@ int cgroup1_get_tree(struct fs_context *fc) } ret =0 ; + ctx->root = root; goto out_unlock; }
@@ -1241,6 +1242,7 @@ int cgroup1_get_tree(struct fs_context *fc)percpu_ref_reinit (&root->cgrp.self.refcnt);mutex_unlock (&cgroup_mutex); } +cgroup_get (&root->cgrp);/* * If @pinned_sb, we're reusing an existing root and holding an
Quoted 11 lines
(quoted diff) +3
-2- dentry = kernfs_mount(fs_type, flags, root->kf_root, magic, &new_sb); + ret = kernfs_get_tree(fc); + if (ret < 0) + goto out_cgrp; /* * In non-init cgroup namespace, instead of root cgroup's dentry, * we return the dentry corresponding to the cgroupns->root_cgrp. */ - if (!IS_ERR(dentry) && ns != &init_cgroup_ns) {
David Howells
maintainerRe: [16/32] kernfs, sysfs, cgroup, intel_rdt: Support fs_context [ver #8]
Quoted 3 lines · Andrei Vagin
ret = 0;
+ ctx->root = root;
goto out_unlock;Okay, I can see that.
Quoted 4 lines
percpu_ref_reinit(&root->cgrp.self.refcnt); mutex_unlock(&cgroup_mutex); }+
cgroup_get(&root->cgrp);
This probably needs to be conditional on ret == 0.
Which version are you testing btw? The patches in git have been fixed a little from what was last posted.
David
Re: [16/32] kernfs, sysfs, cgroup, intel_rdt: Support fs_context [ver #8]
Quoted 6 lines · David Howells
Quoted 3 lines · Andrei Vagin
ret = 0; + ctx->root = root; goto out_unlock;
Quoted 8 lines
Okay, I can see that.
Quoted 4 lines
percpu_ref_reinit(&root->cgrp.self.refcnt); mutex_unlock(&cgroup_mutex); }+
cgroup_get(&root->cgrp);This probably needs to be conditional on ret == 0.
yes, you are right
Quoted 3 lines
Which version are you testing btw? The patches in git have been fixed a little from what was last posted.
I'm testing linux-next-20180621
commit 8439c34f07a3f58245e933ca2703239417288363 (tag: next-20180621, linux-next/master)
Author: Stephen Rothwell <[email protected]> Date: Thu Jun 21 14:09:41 2018 +1000
Add linux-next specific files for 20180621
Quoted 2 lines
David
Re: [16/32] kernfs, sysfs, cgroup, intel_rdt: Support fs_context [ver #8]
Quoted 9 lines · Andrei Vagin
Quoted 8 lines · David Howells
Quoted 3 lines · Andrei Vagin
ret = 0; + ctx->root = root; goto out_unlock;Okay, I can see that.
Quoted 8 lines
Quoted 6 lines
Quoted 4 lines
percpu_ref_reinit(&root->cgrp.self.refcnt); mutex_unlock(&cgroup_mutex); }+
cgroup_get(&root->cgrp);This probably needs to be conditional on ret == 0.
yes, you are right
I've read the code and I think it isn't obvious. A reference will be released id cgroup_fs_context_free() even if ret isn't zero here.
I look at do_new_mount()
vfs_new_fs_context()
...
if (vfs_get_tree())
goto out_fc; .... out_fc: put_fs_context(fc); fc->ops->free(fc); cgroup_fs_context_free() cgroup_put(&ctx->root->cgrp);
Quoted 18 lines
Quoted 4 lines
Which version are you testing btw? The patches in git have been fixed a little from what was last posted.
I'm testing linux-next-20180621
commit
8439c34f07a3f58245e933ca2703239417288363(tag: next-20180621, linux-next/master)Author: Stephen Rothwell <[email protected]> Date: Thu Jun 21 14:09:41 2018 +1000Add linux-next specific files for 20180621
Signed-off-by Stephen Rothwell <[email protected]>Quoted 2 lines
David
David Howells
maintainerRe: [16/32] kernfs, sysfs, cgroup, intel_rdt: Support fs_context [ver #8]
Quoted 18 lines · Andrei Vagin
Quoted 8 lines
Quoted 6 lines
Quoted 4 lines
percpu_ref_reinit(&root->cgrp.self.refcnt); mutex_unlock(&cgroup_mutex); }+
cgroup_get(&root->cgrp);This probably needs to be conditional on ret == 0.
yes, you are right
I've read the code and I think it isn't obvious. A reference will be released id
cgroup_fs_context_free()even if ret isn't zero here.I look at
do_new_mount()
vfs_new_fs_context()
...
if (vfs_get_tree())
Quoted 7 lines
goto out_fc; .... out_fc: put_fs_context(fc); fc->ops->free(fc); cgroup_fs_context_free() cgroup_put(&ctx->root->cgrp);
Yeah, you're right: ctx->root is set above, so the put will trigger anyway. I'll fold both of these changes in.
David
David Howells
maintainerPATCH 17/32 hugetlbfs: Convert to fs_context [ver #8]
In reply to David HowellsConvert the hugetlbfs to use the fs_context during mount.
---
fs/hugetlbfs/inode.c | 340 +++++++++++++++++++++++++++++--------------------- 1 file changed, 194 insertions(+), 146 deletions(-)
fs/hugetlbfs/inode.c +194 -146
@@ -45,11 +45,17 @@ const struct file_operations hugetlbfs_file_operations;static const struct inode_operations hugetlbfs_dir_inode_operations;static const struct inode_operations hugetlbfs_inode_operations; -struct hugetlbfs_config { +enum hugetlbfs_size_type {NO_SIZE ,SIZE_STD ,SIZE_PERCENT }; + +struct hugetlbfs_fs_context {struct hstate *hstate; +unsigned long long max_size_opt; +unsigned long long min_size_opt;long max_hpages;long nr_inodes;long min_hpages; +enum hugetlbfs_size_type max_val_type; +enum hugetlbfs_size_type min_val_type;kuid_t uid;kgid_t gid;umode_t mode;
@@ -708,16 +714,16 @@ static int hugetlbfs_setattr(struct dentry *dentry, struct iattr *attr) }static struct inode *hugetlbfs_get_root (struct super_block *sb, -struct hugetlbfs_config *config) +struct hugetlbfs_fs_context *ctx) {struct inode *inode; inode =new_inode (sb);if (inode) { inode->i_ino =get_next_ino (); - inode->i_mode =S_IFDIR | config->mode; - inode->i_uid = config->uid; - inode->i_gid = config->gid; + inode->i_mode =S_IFDIR | ctx->mode; + inode->i_uid = ctx->uid; + inode->i_gid = ctx->gid; inode->i_atime = inode->i_mtime = inode->i_ctime =current_time (inode); inode->i_op = &hugetlbfs_dir_inode_operations; inode->i_fop = &simple_dir_operations;
@@ -1081,8 +1087,6 @@ static const struct super_operations hugetlbfs_ops = { .show_options = hugetlbfs_show_options, }; -enum hugetlbfs_size_type {NO_SIZE ,SIZE_STD ,SIZE_PERCENT }; -/* * Convert size option passed from command line to number of huge pages * in the pool specified by hstate. Size option could be in bytes
@@ -1105,171 +1109,156 @@ hugetlbfs_size_to_hpages(struct hstate *h, unsigned long long size_opt,return size_opt; } -static int -hugetlbfs_parse_options (char *options,struct hugetlbfs_config *pconfig) +/* +* Parse one mount option. +*/ +static int hugetlbfs_parse_option (struct fs_context *fc,char *opt,size_t len) { -char *p, *rest; +struct hugetlbfs_fs_context *ctx = fc->fs_private; +char *rest; +unsigned long ps;substring_t args[MAX_OPT_ARGS ]; -int option; -unsigned long long max_size_opt =0 , min_size_opt =0 ; -enum hugetlbfs_size_type max_val_type =NO_SIZE , min_val_type =NO_SIZE ; - -if (!options) +int token, option; + + token =match_token (opt, tokens, args); +switch (token) { +case Opt_uid: +if (match_int (&args[0 ], &option)) + goto bad_val; + ctx->uid =make_kuid (current_user_ns (), option); +if (!uid_valid (ctx->uid)) + goto bad_val;return 0 ; -while ((p =strsep (&options,"," )) !=NULL ) { -int token; -if (!*p) -continue ; +case Opt_gid: +if (match_int (&args[0 ], &option)) + goto bad_val; + ctx->gid =make_kgid (current_user_ns (), option); +if (!gid_valid (ctx->gid)) + goto bad_val; +return 0 ; - token =match_token (p, tokens, args); -switch (token) { -case Opt_uid: -if (match_int (&args[0 ], &option)) - goto bad_val; - pconfig->uid =make_kuid (current_user_ns (), option); -if (!uid_valid (pconfig->uid)) - goto bad_val; -break ; +case Opt_mode: +if (match_octal (&args[0 ], &option)) + goto bad_val; + ctx->mode = option &01777U ; +return 0 ; -case Opt_gid: -if (match_int (&args[0 ], &option)) - goto bad_val; - pconfig->gid =make_kgid (current_user_ns (), option); -if (!gid_valid (pconfig->gid)) - goto bad_val; -break ; +case Opt_size: +/* memparse() will accept a K/M/G without a digit */ +if (!isdigit (*args[0 ].from)) + goto bad_val; + ctx->max_size_opt =memparse (args[0 ].from, &rest); + ctx->max_val_type =SIZE_STD ; +if (*rest =='%' ) + ctx->max_val_type =SIZE_PERCENT ; +return 0 ; -case Opt_mode: -if (match_octal (&args[0 ], &option)) - goto bad_val; - pconfig->mode = option &01777U ; -break ; +case Opt_nr_inodes: +/* memparse() will accept a K/M/G without a digit */ +if (!isdigit (*args[0 ].from)) + goto bad_val; + ctx->nr_inodes =memparse (args[0 ].from, &rest); +return 0 ; -case Opt_size: { -/* memparse() will accept a K/M/G without a digit */ -if (!isdigit (*args[0 ].from)) - goto bad_val; - max_size_opt =memparse (args[0 ].from, &rest); - max_val_type =SIZE_STD ; -if (*rest =='%' ) - max_val_type =SIZE_PERCENT ; -break ; +case Opt_pagesize: + ps =memparse (args[0 ].from, &rest); + ctx->hstate =size_to_hstate (ps); +if (!ctx->hstate) { +pr_err ("Unsupported page size %lu MB\n" , ps >>20 ); +return -EINVAL ; } +return 0 ; -case Opt_nr_inodes: -/* memparse() will accept a K/M/G without a digit */ -if (!isdigit (*args[0 ].from)) - goto bad_val; - pconfig->nr_inodes =memparse (args[0 ].from, &rest); -break ; +case Opt_min_size: +/* memparse() will accept a K/M/G without a digit */ +if (!isdigit (*args[0 ].from)) + goto bad_val; + ctx->min_size_opt =memparse (args[0 ].from, &rest); + ctx->min_val_type =SIZE_STD ; +if (*rest =='%' ) + ctx->min_val_type =SIZE_PERCENT ; +return 0 ; -case Opt_pagesize: { -unsigned long ps; - ps =memparse (args[0 ].from, &rest); - pconfig->hstate =size_to_hstate (ps); -if (!pconfig->hstate) { -pr_err ("Unsupported page size %lu MB\n" , - ps >>20 ); -return -EINVAL ; - } -break ; - } +default : +pr_err ("Bad mount option: \"%s\"\n" , opt); +return -EINVAL ; + } -case Opt_min_size: { -/* memparse() will accept a K/M/G without a digit */ -if (!isdigit (*args[0 ].from)) - goto bad_val; - min_size_opt =memparse (args[0 ].from, &rest); - min_val_type =SIZE_STD ; -if (*rest =='%' ) - min_val_type =SIZE_PERCENT ; -break ; - } +bad_val: +pr_err ("Bad value '%s' for mount option '%s'\n" , args[0 ].from, opt); +return -EINVAL ; +} -default : -pr_err ("Bad mount option: \"%s\"\n" , p); -return -EINVAL ; -break ; - } - } +/* +* Validate the parsed options. +*/ +static int hugetlbfs_validate (struct fs_context *fc) +{ +struct hugetlbfs_fs_context *ctx = fc->fs_private;/* * Use huge page pool size (in hstate) to convert the size * options to number of huge pages. If NO_SIZE, -1 is returned. */ - pconfig->max_hpages =hugetlbfs_size_to_hpages (pconfig->hstate, - max_size_opt, max_val_type); - pconfig->min_hpages =hugetlbfs_size_to_hpages (pconfig->hstate, - min_size_opt, min_val_type); + ctx->max_hpages =hugetlbfs_size_to_hpages (ctx->hstate, + ctx->max_size_opt, + ctx->max_val_type); + ctx->min_hpages =hugetlbfs_size_to_hpages (ctx->hstate, + ctx->min_size_opt, + ctx->min_val_type);/* * If max_size was specified, then min_size must be smaller */ -if (max_val_type >NO_SIZE && - pconfig->min_hpages > pconfig->max_hpages) { -pr_err ("minimum size can not be greater than maximum size\n" ); +if (ctx->max_val_type >NO_SIZE && + ctx->min_hpages > ctx->max_hpages) { +pr_err ("Minimum size can not be greater than maximum size\n" );return -EINVAL ; }return 0 ; - -bad_val: -pr_err ("Bad value '%s' for mount option '%s'\n" , args[0 ].from, p); -return -EINVAL ; }static int -hugetlbfs_fill_super (struct super_block *sb,void *data,size_t data_size, -int silent) +hugetlbfs_fill_super (struct super_block *sb,struct fs_context *fc) { -int ret; -struct hugetlbfs_config config; +struct hugetlbfs_fs_context *ctx = + fc->fs_private;struct hugetlbfs_sb_info *sbinfo; - config.max_hpages =-1 ;/* No limit on size by default */ - config.nr_inodes =-1 ;/* No limit on number of inodes by default */ - config.uid =current_fsuid (); - config.gid =current_fsgid (); - config.mode =0755 ; - config.hstate = &default_hstate; - config.min_hpages =-1 ;/* No default minimum size */ - ret =hugetlbfs_parse_options (data, &config); -if (ret) -return ret; - sbinfo =kmalloc (sizeof (struct hugetlbfs_sb_info ),GFP_KERNEL );if (!sbinfo)return -ENOMEM ; sb->s_fs_info = sbinfo; - sbinfo->hstate = config.hstate;spin_lock_init (&sbinfo->stat_lock); - sbinfo->max_inodes = config.nr_inodes; - sbinfo->free_inodes = config.nr_inodes; - sbinfo->spool =NULL ; - sbinfo->uid = config.uid; - sbinfo->gid = config.gid; - sbinfo->mode = config.mode; + sbinfo->hstate = ctx->hstate; + sbinfo->max_inodes = ctx->nr_inodes; + sbinfo->free_inodes = ctx->nr_inodes; + sbinfo->spool =NULL ; + sbinfo->uid = ctx->uid; + sbinfo->gid = ctx->gid; + sbinfo->mode = ctx->mode;/* * Allocate and initialize subpool if maximum or minimum size is * specified. Any needed reservations (for minimim size) are taken * taken when the subpool is created. */ -if (config.max_hpages !=-1 || config.min_hpages !=-1 ) { - sbinfo->spool =hugepage_new_subpool (config.hstate, - config.max_hpages, - config.min_hpages); +if (ctx->max_hpages !=-1 || ctx->min_hpages !=-1 ) { + sbinfo->spool =hugepage_new_subpool (ctx->hstate, + ctx->max_hpages, + ctx->min_hpages);if (!sbinfo->spool) goto out_free; } sb->s_maxbytes =MAX_LFS_FILESIZE ; - sb->s_blocksize =huge_page_size (config.hstate); - sb->s_blocksize_bits =huge_page_shift (config.hstate); + sb->s_blocksize =huge_page_size (ctx->hstate); + sb->s_blocksize_bits =huge_page_shift (ctx->hstate); sb->s_magic =HUGETLBFS_MAGIC ; sb->s_op = &hugetlbfs_ops; sb->s_time_gran =1 ; - sb->s_root =d_make_root (hugetlbfs_get_root (sb, &config)); + sb->s_root =d_make_root (hugetlbfs_get_root (sb, ctx));if (!sb->s_root) goto out_free;return 0 ;
@@ -1279,17 +1268,50 @@ hugetlbfs_fill_super(struct super_block *sb, void *data, size_t data_size,return -ENOMEM ; } -static struct dentry *hugetlbfs_mount (struct file_system_type *fs_type, -int flags,const char *dev_name,void *data,size_t data_size) +static int hugetlbfs_get_tree (struct fs_context *fc) +{ +return vfs_get_super (fc, vfs_get_independent_super, hugetlbfs_fill_super); +} + +static void hugetlbfs_fs_context_free (struct fs_context *fc) { -return mount_nodev (fs_type, flags, data, data_size, - hugetlbfs_fill_super); +kfree (fc->fs_private); +} + +static const struct fs_context_operations hugetlbfs_fs_context_ops = { + .free = hugetlbfs_fs_context_free, + .parse_option = hugetlbfs_parse_option, + .validate = hugetlbfs_validate, + .get_tree = hugetlbfs_get_tree, +}; + +static int hugetlbfs_init_fs_context (struct fs_context *fc, +struct dentry *reference) +{ +struct hugetlbfs_fs_context *ctx; + + ctx =kzalloc (sizeof (struct hugetlbfs_fs_context ),GFP_KERNEL ); +if (!ctx) +return -ENOMEM ; + + ctx->max_hpages =-1 ;/* No limit on size by default */ + ctx->nr_inodes =-1 ;/* No limit on number of inodes by default */ + ctx->uid =current_fsuid (); + ctx->gid =current_fsgid (); + ctx->mode =0755 ; + ctx->hstate = &default_hstate; + ctx->min_hpages =-1 ;/* No default minimum size */ + ctx->max_val_type =NO_SIZE ; + ctx->min_val_type =NO_SIZE ; + fc->fs_private = ctx; + fc->ops = &hugetlbfs_fs_context_ops; +return 0 ; }static struct file_system_type hugetlbfs_fs_type = { - .name ="hugetlbfs" , - .mount = hugetlbfs_mount, - .kill_sb = kill_litter_super, + .name ="hugetlbfs" , + .init_fs_context = hugetlbfs_init_fs_context, + .kill_sb = kill_litter_super, };static struct vfsmount *hugetlbfs_vfsmount[HUGE_MAX_HSTATE ];
@@ -1396,8 +1418,47 @@ struct file *hugetlb_file_setup(const char *name, size_t size,return file; } +static struct vfsmount *__init mount_one_hugetlbfs (struct hstate *h) +{ +struct hugetlbfs_fs_context *ctx; +struct fs_context *fc; +struct vfsmount *mnt; +int ret; + + fc =vfs_new_fs_context (&hugetlbfs_fs_type,NULL ,0 , +FS_CONTEXT_FOR_KERNEL_MOUNT ); +if (IS_ERR (fc)) { + ret =PTR_ERR (fc); + goto err; + } + + ctx = fc->fs_private; + ctx->hstate = h; + + ret =vfs_get_tree (fc); +if (ret <0 ) + goto err_fc; + + mnt =vfs_create_mount (fc,0 ); +if (IS_ERR (mnt)) { + ret =PTR_ERR (mnt); + goto err_fc; + } + +put_fs_context (fc); +return mnt; + +err_fc: +put_fs_context (fc); +err: +pr_err ("Cannot mount internal hugetlbfs for page size %uK" , +1U << (h->order +PAGE_SHIFT -10 )); +return ERR_PTR (ret); +} +static int __init init_hugetlbfs_fs (void ) { +struct vfsmount *mnt;struct hstate *h;int error;int i;
@@ -1420,25 +1481,12 @@ static int __init init_hugetlbfs_fs(void) i =0 ;for_each_hstate (h) { -char buf[50 ]; -unsigned ps_kb =1U << (h->order +PAGE_SHIFT -10 ); -int n; - - n =snprintf (buf,sizeof (buf),"pagesize=%uK" , ps_kb); - hugetlbfs_vfsmount[i] =kern_mount_data (&hugetlbfs_fs_type, - buf, n +1 ); - -if (IS_ERR (hugetlbfs_vfsmount[i])) { -pr_err ("Cannot mount internal hugetlbfs for " -"page size %uK" , ps_kb); - error =PTR_ERR (hugetlbfs_vfsmount[i]); - hugetlbfs_vfsmount[i] =NULL ; - } + mnt =mount_one_hugetlbfs (h); +if (IS_ERR (mnt) && i ==0 ) + goto out; + hugetlbfs_vfsmount[i] = mnt; i++; } -/* Non default hstates are optional */ -if (!IS_ERR_OR_NULL (hugetlbfs_vfsmount[default_hstate_idx])) -return 0 ; out:kmem_cache_destroy (hugetlbfs_inode_cachep);
David Howells
maintainerPATCH 18/32 VFS: Remove kern_mount_data() [ver #8]
In reply to David HowellsThe kern_mount_data() isn't used any more so remove it.
---
fs/namespace.c | 7 ------- include/linux/fs.h | 1 - 2 files changed, 8 deletions(-)
fs/namespace.c +0 -7
@@ -3198,13 +3198,6 @@ struct vfsmount *kern_mount(struct file_system_type *type) }EXPORT_SYMBOL_GPL (kern_mount); -struct vfsmount *kern_mount_data (struct file_system_type *type, -void *data,size_t data_size) -{ -return vfs_kern_mount (type,SB_KERNMOUNT , type->name, data, data_size); -} -EXPORT_SYMBOL_GPL (kern_mount_data); -/* * Return true if path is reachable from root *
include/linux/fs.h +0 -1
@@ -2186,7 +2186,6 @@ mount_pseudo(struct file_system_type *fs_type, char *name,extern int register_filesystem (struct file_system_type *);extern int unregister_filesystem (struct file_system_type *);extern struct vfsmount *kern_mount (struct file_system_type *); -extern struct vfsmount *kern_mount_data (struct file_system_type *,void *,size_t );extern void kern_unmount (struct vfsmount *mnt);extern int may_umount_tree (struct vfsmount *);extern int may_umount (struct vfsmount *);
David Howells
maintainerPATCH 19/32 VFS: Implement fsopen() to prepare for a mount [ver #8]
In reply to David HowellsProvide an fsopen() system call that starts the process of preparing to mount, using an fd as a context handle. fsopen() is given the name of the filesystem that will be used:
int mfd = fsopen(const char *fsname, int open_flags,
void *reserved3, void *reserved4, void *reserved5);
where open_flags can be 0 or O_CLOEXEC and reserved* should all be NULL for the moment.
For example:
mfd = fsopen("ext4", O_CLOEXEC, NULL, NULL, NULL);
write(mfd, "s /dev/sdb1"); // note I'm ignoring write's length arg
write(mfd, "o noatime");
write(mfd, "o acl");
write(mfd, "o user_attr");
write(mfd, "o iversion");
write(mfd, "o ");
write(mfd, "r /my/container"); // root inside the fs
write(mfd, "x create"); // create the superblock
fsmount(mfd, container_fd, "/mnt", AT_NO_FOLLOW);
mfd = fsopen("afs", -1);
write(mfd, "s %grand.central.org:root.cell");
write(mfd, "o cell=grand.central.org");
write(mfd, "r /");
write(mfd, "x create");
fsmount(mfd, AT_FDCWD, "/mnt", 0);If an error is reported at any step, an error message may be available to be read() back (ENODATA will be reported if there isn't an error available) in the form:
"e <subsys>:<problem>" "e SELinux:Mount on mountpoint not permitted"
Once fsmount() has been called, further write() calls will incur EBUSY, even if the fsmount() fails. read() is still possible to retrieve error information.
The fsopen() syscall creates a mount context and hangs it of the fd that it returns.
Netlink is not used because it is optional.
Note that, for the moment, the caller must have SYS_CAP_ADMIN to use fsopen().
---
arch/x86/entry/syscalls/syscall_32.tbl | 1 arch/x86/entry/syscalls/syscall_64.tbl | 1 fs/Makefile | 2 fs/fsopen.c | 352 ++++++++++++++++++++++++++++++++ include/linux/syscalls.h | 2 include/uapi/linux/magic.h | 1 kernel/sys_ni.c | 3 7 files changed, 361 insertions(+), 1 deletion(-) create mode 100644 fs/fsopen.c
arch/x86/entry/syscalls/syscall_32.tbl +1 -0
@@ -397,3 +397,4 @@ 383 i386 statx sys_statx __ia32_sys_statx 384 i386 arch_prctl sys_arch_prctl __ia32_compat_sys_arch_prctl 385 i386 io_pgetevents sys_io_pgetevents __ia32_compat_sys_io_pgetevents +386 i386 fsopen sys_fsopen __ia32_sys_fsopen
arch/x86/entry/syscalls/syscall_64.tbl +1 -0
@@ -342,6 +342,7 @@ 331 common pkey_free __x64_sys_pkey_free 332 common statx __x64_sys_statx 333 common io_pgetevents __x64_sys_io_pgetevents +334 common fsopen __x64_sys_fsopen # # x32-specific system call numbers start at 512 to avoid cache impact
fs/Makefile +1 -1
@@ -13,7 +13,7 @@ obj-y := open.o read_write.o file_table.o super.o \ seq_file.o xattr.o libfs.o fs-writeback.o \ pnode.o splice.o sync.o utimes.o d_path.o \ stack.o fs_struct.o statfs.o fs_pin.o nsfs.o \ - fs_context.o + fs_context.o fsopen.o ifeq ($(CONFIG_BLOCK),y) obj-y += buffer.o block_dev.o direct-io.o mpage.o
fs/fsopen.c new file +352 -0
352 lines not on this page · raw message
include/linux/syscalls.h +2 -0
@@ -896,6 +896,8 @@ asmlinkage long sys_pkey_alloc(unsigned long flags, unsigned long init_val);asmlinkage long sys_pkey_free (int pkey);asmlinkage long sys_statx (int dfd,const char __user *path,unsigned flags,unsigned mask,struct statx __user *buffer); +asmlinkage long sys_fsopen (const char *fs_name,unsigned int flags, +void *reserved3,void *reserved4,void *reserved5);/*
include/uapi/linux/magic.h +1 -0
@@ -89,5 +89,6 @@#define UDF_SUPER_MAGIC 0x15013346#define BALLOON_KVM_MAGIC 0x13661366#define ZSMALLOC_MAGIC 0x58295829 +#define FSCONTEXT_FS_MAGIC 0x66736673#endif /* __LINUX_MAGIC_H__ */
kernel/sys_ni.c +3 -0
@@ -432,3 +432,6 @@ COND_SYSCALL(setresgid16);COND_SYSCALL (setresuid16);COND_SYSCALL (setreuid16);COND_SYSCALL (setuid16); + +/* fd-based mount */ +COND_SYSCALL (sys_fsopen);
Al Viro
maintainerRe: [PATCH 19/32] VFS: Implement fsopen() to prepare for a mount [ver #8]
fs/fsopen.c line 193
Quoted 4 lines · David Howells
fs/fsopen.c new file +4
-0+ inode =alloc_anon_inode (fscontext_fs_mnt->mnt_sb); +if (IS_ERR (inode)) +return ERR_CAST (inode); + inode->i_fop = &fscontext_fs_fops;
That's almost certainly wrong - you need it only if you want it possible to reopen via /proc/*/fd/*
fs/fsopen.c line 205
Quoted 11 lines
fs/fsopen.c new file +11
-0+ fc->phase =FS_CONTEXT_CREATE_PARAMS ; + + ret = -ENOMEM ; + path.dentry =d_alloc_pseudo (fscontext_fs_mnt->mnt_sb, &empty_name); +if (!path.dentry) + goto err_inode; + path.mnt =mntget (fscontext_fs_mnt); + +d_instantiate (path.dentry, inode); + + f =alloc_file (&path,FMODE_READ |FMODE_WRITE , &fscontext_fs_fops);
Re your question on IRC - we might want that fs in longer run, but for now just go with anon_inode_getfile() here. Easier that way and we can always switch later.
David Howells
maintainerPATCH 20/32 vfs: Make close() unmount the attached mount if so flagged [ver #8]
In reply to David Howells---
fs/file_table.c | 4 ++++ include/linux/fs.h | 4 +++- 2 files changed, 7 insertions(+), 1 deletion(-)
fs/file_table.c +4 -0
@@ -30,6 +30,7 @@#include <linux/atomic.h> #include "internal.h" +#include "mount.h" /* sysctl tunables... */ struct files_stat_struct files_stat = {
@@ -200,6 +201,9 @@ static void __fput(struct file *file)eventpoll_release (file);locks_remove_file (file); +if (unlikely (file->f_mode &FMODE_NEED_UNMOUNT )) +__detach_mounts (dentry); +ima_file_free (file);if (unlikely (file->f_flags &FASYNC )) {if (file->f_op->fasync)
include/linux/fs.h +3 -1
@@ -152,7 +152,9 @@ typedef int (dio_iodone_t)(struct kiocb *iocb, loff_t offset,#define FMODE_NONOTIFY ((__force fmode_t)0x4000000)/* File is capable of returning -EAGAIN if I/O will block */ -#define FMODE_NOWAIT ((__force fmode_t)0x8000000) +#define FMODE_NOWAIT ((__force fmode_t)0x8000000) +/* File represents mount that needs unmounting */ +#define FMODE_NEED_UNMOUNT ((__force fmode_t)0x10000000)/* * Flag for rw_copy_check_uvector and compat_rw_copy_check_uvector
Al Viro
maintainerRe: [PATCH 20/32] vfs: Make close() unmount the attached mount if so flagged [ver #8]
fs/file_table.c static void __fput(struct file *file) · line 206
Quoted 3 lines · David Howells
fs/file_table.c +3
-0+if (unlikely (file->f_mode &FMODE_NEED_UNMOUNT )) +__detach_mounts (dentry); +
This is completely wrong. First of all, you want to dissolve the mount tree on file->f_path.mount, not every tree rooted at dentry equal to file->f_path.dentry. This is easily done - it would be a simple call of drop_collected_mounts(mnt) if not for one detail. You want it to happen only if the sucker isn't attached anywhere by that point. IOW,
namespace_lock();
lock_mount_hash();
if (!real_mount(mnt)->mnt_ns)
umount_tree(real_mount(mnt), UMOUNT_SYNC);
unlock_mount_hash();
namespace_unlock();and that's it. You don't need that magical mystery turd in move_mount() later in the series and all the infrastructure you grow for it.
FWIW, I would've suggested this
void drop_collected_mounts(struct vfsmount *mnt)
{
namespace_lock();
lock_mount_hash();
+ if (!real_mount(mnt)->mnt_ns)
+ umount_tree(real_mount(mnt), UMOUNT_SYNC);
- umount_tree(real_mount(mnt), UMOUNT_SYNC);
unlock_mount_hash();
namespace_unlock();
}
and in __fput()
if (unlikely(file->f_mode & FMODE_NEED_UNMOUNT)) drop_collected_mounts(mnt);
All there is to it, AFAICS...
Al Viro
maintainerRe: [PATCH 20/32] vfs: Make close() unmount the attached mount if so flagged [ver #8]
Quoted 31 lines · Al Viro
fs/file_table.c static void __fput(struct file *file) · line 206
Quoted 3 lines · David Howells
fs/file_table.c +3
-0+if (unlikely (file->f_mode &FMODE_NEED_UNMOUNT )) +__detach_mounts (dentry); +This is completely wrong. First of all, you want to dissolve the mount tree on
file->f_path.mount, not every tree rooted at dentry equal tofile->f_path.dentry. This is easily done - it would be a simple call ofdrop_collected_mounts(mnt)if not for one detail. You want it to happen only if the sucker isn't attached anywhere by that point. IOW,namespace_lock(); lock_mount_hash(); if (!real_mount(mnt)->mnt_ns) umount_tree(real_mount(mnt), UMOUNT_SYNC); unlock_mount_hash(); namespace_unlock();and that's it. You don't need that magical mystery turd in
move_mount()later in the series and all the infrastructure you grow for it.FWIW, I would've suggested this
voiddrop_collected_mounts(struct vfsmount *mnt)
{(quoted diff) +2
-1namespace_lock(); lock_mount_hash(); + if (!real_mount(mnt)->mnt_ns) + umount_tree(real_mount(mnt), UMOUNT_SYNC); - umount_tree(real_mount(mnt), UMOUNT_SYNC); unlock_mount_hash(); namespace_unlock(); }
Quoted 5 lines
and in
__fput()if (unlikely(file->f_mode & FMODE_NEED_UNMOUNT)) drop_collected_mounts(mnt);All there is to it, AFAICS...
... and that eliminates #27 and #28 entirely, with #31 becoming simpler - no move_mount_lookup(), no dfd_ref, the check in do_move_mount() becomes
+ if (!mnt_has_parent(old) && old->mnt_ns) {
+ /* We need to allow open(O_PATH|O_CLONE_MOUNT) or fsmount()
+ * followed by move_mount(), but mustn't allow "/" to be moved. + */ + goto out1;
+ }
and I wouldn't be surprised if move_mount_old()/move_mount() split turns out to be not needed at all, seeing that the whole "clear FMODE_NEED_UNMOUNT on success" part goes away.
Al Viro
maintainerRe: [PATCH 20/32] vfs: Make close() unmount the attached mount if so flagged [ver #8]
In reply to Al ViroQuoted 31 lines · Al Viro
fs/file_table.c static void __fput(struct file *file) · line 206
Quoted 3 lines · David Howells
fs/file_table.c +3
-0+if (unlikely (file->f_mode &FMODE_NEED_UNMOUNT )) +__detach_mounts (dentry); +This is completely wrong. First of all, you want to dissolve the mount tree on
file->f_path.mount, not every tree rooted at dentry equal tofile->f_path.dentry. This is easily done - it would be a simple call ofdrop_collected_mounts(mnt)if not for one detail. You want it to happen only if the sucker isn't attached anywhere by that point. IOW,namespace_lock(); lock_mount_hash(); if (!real_mount(mnt)->mnt_ns) umount_tree(real_mount(mnt), UMOUNT_SYNC); unlock_mount_hash(); namespace_unlock();and that's it. You don't need that magical mystery turd in
move_mount()later in the series and all the infrastructure you grow for it.FWIW, I would've suggested this
voiddrop_collected_mounts(struct vfsmount *mnt)
{(quoted diff) +2
-1namespace_lock(); lock_mount_hash(); + if (!real_mount(mnt)->mnt_ns) + umount_tree(real_mount(mnt), UMOUNT_SYNC); - umount_tree(real_mount(mnt), UMOUNT_SYNC); unlock_mount_hash(); namespace_unlock(); }
Quoted 5 lines
and in
__fput()if (unlikely(file->f_mode & FMODE_NEED_UNMOUNT)) drop_collected_mounts(mnt);All there is to it, AFAICS...
... except that it should be a separate primitive - drop_collected_mounts() is used put_mnt_ns(), where the root definitely has non-NULL ->mnt_ns.
Another thing: the same issue (misuse of __detach_mounts()) exists in cleanup path of do_o_path(). What's more, doing it there is pointless - if do_dentry_open() has set FMODE_NEED_UNMOUNT, it either succeeds or calls fput() itself. Either way, the caller should *not* do the cleanups done by fput().
Another thing: copy_mount_for_o_path() is bogus. Horrible calling conventions aside, what the hell is that lock_mount() for? In do_loopback() we lock the *mountpoint*; here the source gets locked, for no visible reason. What we should do is something like this:
1) common helper -
static struct mount *__do_loopback(struct path *from, bool recurse)
{
struct mount *mnt = ERR_PTR(-EINVAL), *f = real_mount(from->mnt);
if (IS_MNT_UNBINDABLE(f))
return mnt;
if (!check_mnt(f) && from->dentry->d_op != &ns_dentry_operations)
return mnt;
if (!recurse && has_locked_children(f, from->dentry))
return mnt;
if (recurse)
mnt = copy_tree(f, from->dentry, CL_COPY_MNT_NS_FILE);
else
mnt = clone_mnt(f, from->dentry, 0);
if (!IS_ERR(mnt))
mnt->mnt.mnt_flags &= ~MNT_LOCKED;
return mnt;
}2) in do_loopback() we are left with
static int do_loopback(struct path *path, const char *old_name,
int recurse)
{
struct path old_path;
struct mount *mnt, *parent;
struct mountpoint *mp;
int err;
if (!old_name || !*old_name)
return -EINVAL;
err = kern_path(old_name, LOOKUP_FOLLOW|LOOKUP_AUTOMOUNT, &old_path);
if (err)
return err;
err = -EINVAL;
if (mnt_ns_loop(old_path.dentry))
goto out;
mp = lock_mount(path);
if (IS_ERR(mp)) {
err = PTR_ERR(mp);
goto out;
}
parent = real_mount(path->mnt);
if (!check_mnt(parent))
goto out2;
mnt = __do_loopback(&old_path, recurse);
if (IS_ERR(mnt)) {
err = PTR_ERR(mnt);
goto out2;
}
err = graft_tree(mnt, parent, mp);
if (err) {
lock_mount_hash();
umount_tree(mnt, UMOUNT_SYNC);
unlock_mount_hash();
}
out2:
unlock_mount(mp);
out:
path_put(&old_path);
return err;
}3) copy_mount_for_o_path() with saner calling conventions:
int copy_mount_for_o_path(struct path *path, bool recurse)
{
struct mount *mnt = __do_loopback(path, recurse);
if (IS_ERR(mnt)) {
path_put(path);
return PTR_ERR(mnt);
}
mntput(path->mnt);
path->mnt = &mnt->mnt;
return 0;
}4) in do_o_path():
static int do_o_path(struct nameidata *nd, unsigned flags, struct file *file)
{
struct path path;
int error = path_lookupat(nd, flags, &path);
if (error)
return error;
if (file->f_flags & O_CLONE_MOUNT) {
error = copy_mount_for_o_path(&path,
!(file->f_flags & O_NON_RECURSIVE));
if (error < 0)
return error;
}
audit_inode(nd->name, path.dentry, 0);
error = vfs_open(&path, file, current_cred());
path_put(&path);
return error;
}Al Viro
maintainerRe: [PATCH 20/32] vfs: Make close() unmount the attached mount if so flagged [ver #8]
FWIW, this on top of your current branch (I'll fold and reorder) gets your move_mount(2) test work, AFAICS:
fs/file_table.c +4 -4
@@ -200,9 +200,6 @@ static void __fput(struct file *file)eventpoll_release (file);locks_remove_file (file); -if (unlikely (file->f_mode &FMODE_NEED_UNMOUNT )) -drop_collected_mounts (mnt); -ima_file_free (file);if (unlikely (file->f_flags &FASYNC )) {if (file->f_op->fasync)
@@ -228,7 +225,10 @@ static void __fput(struct file *file) file->f_inode =NULL ;file_free (file);dput (dentry); -mntput (mnt); +if (unlikely (file->f_mode &FMODE_NEED_UNMOUNT )) +umount_on_fput (mnt); +else +mntput (mnt); }static LLIST_HEAD (delayed_fput_list);
fs/internal.h +3 -1
@@ -75,7 +75,7 @@ extern struct vfsmount *lookup_mnt(const struct path *);extern int finish_automount (struct vfsmount *,struct path *);extern int sb_prepare_remount_readonly (struct super_block *); -extern int copy_mount_for_o_path (struct path *,struct path *,bool ); +extern int copy_mount_for_o_path (struct path *,bool );extern void __init mnt_init (void );
@@ -86,6 +86,8 @@ extern void __mnt_drop_write(struct vfsmount *);extern void __mnt_drop_write_file (struct file *);extern void mnt_drop_write_file_path (struct file *); +extern void umount_on_fput (struct vfsmount *); +/* * fs_struct.c */
fs/namei.c +4 -12
@@ -3454,28 +3454,20 @@ static int do_tmpfile(struct nameidata *nd, unsigned flags,static int do_o_path (struct nameidata *nd,unsigned flags,struct file *file) { -struct path path, tmp; -int error; - - error =path_lookupat (nd, flags, &path); +struct path path; +int error =path_lookupat (nd, flags, &path);if (error)return error;if (file->f_flags &O_CLONE_MOUNT ) { - error =copy_mount_for_o_path ( - &path, &tmp, !(file->f_flags &O_NON_RECURSIVE )); -path_put (&path); + error =copy_mount_for_o_path (&path, + !(file->f_flags &O_NON_RECURSIVE ));if (error <0 )return error; - path = tmp; }audit_inode (nd->name, path.dentry,0 ); error =vfs_open (&path, file,current_cred ()); -if (error <0 && - (flags &O_CLONE_MOUNT ) && - !(file->f_mode &FMODE_NEED_UNMOUNT )) -__detach_mounts (path.dentry);path_put (&path);return error; }
fs/namespace.c +52 -62
195 lines not on this page · raw message
Al Viro
maintainerRe: [PATCH 20/32] vfs: Make close() unmount the attached mount if so flagged [ver #8]
Quoted 2 lines · Al Viro
+void
umount_on_fput(struct vfsmount *mnt)
{
.... which needs to do mntput() in case if it's attached.
David Howells
maintainerPATCH 21/32 VFS: Implement fsmount() to effect a pre-configured mount [ver #8]
In reply to David HowellsProvide a system call by which a filesystem opened with fsopen() and configured by a series of writes can be mounted:
int ret = fsmount(int fsfd, int dfd, const char *path, unsigned int at_flags, unsigned int flags);
where fsfd is the fd returned by fsopen(), dfd, path and at_flags locate the mountpoint and flags are the applicable MS_* flags. dfd can be AT_FDCWD or an fd open to a directory.
In the event that fsmount() fails, it may be possible to get an error message by calling read(). If no message is available, ENODATA will be reported.
---
arch/x86/entry/syscalls/syscall_32.tbl | 1 arch/x86/entry/syscalls/syscall_64.tbl | 1 fs/namespace.c | 133 ++++++++++++++++++++++++++++++++ include/linux/fs_context.h | 2 include/linux/syscalls.h | 2 include/uapi/linux/fs.h | 7 ++ kernel/sys_ni.c | 1 7 files changed, 147 insertions(+)
arch/x86/entry/syscalls/syscall_32.tbl +1 -0
@@ -398,3 +398,4 @@ 384 i386 arch_prctl sys_arch_prctl __ia32_compat_sys_arch_prctl 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
arch/x86/entry/syscalls/syscall_64.tbl +1 -0
@@ -343,6 +343,7 @@ 332 common statx __x64_sys_statx 333 common io_pgetevents __x64_sys_io_pgetevents 334 common fsopen __x64_sys_fsopen +335 common fsmount __x64_sys_fsmount # # x32-specific system call numbers start at 512 to avoid cache impact
fs/namespace.c +133 -0
139 lines not on this page · raw message
include/linux/fs_context.h +2 -0
@@ -115,4 +115,6 @@ extern int vfs_get_super(struct fs_context *fc,int (*fill_super)(struct super_block *sb, struct fs_context *fc)); +extern const struct file_operations fscontext_fs_fops; +#endif /* _LINUX_FS_CONTEXT_H */
include/linux/syscalls.h +2 -0
@@ -898,6 +898,8 @@ asmlinkage long sys_statx(int dfd, const char __user *path, unsigned flags, unsigned mask, struct statx __user *buffer);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);/*
include/uapi/linux/fs.h +7 -0
@@ -338,4 +338,11 @@ typedef int __bitwise __kernel_rwf_t;#define RWF_SUPPORTED (RWF_HIPRI | RWF_DSYNC | RWF_SYNC | RWF_NOWAIT |\ RWF_APPEND) +/* +* Flags for fsopen() and co. +*/ +#define FSOPEN_CLOEXEC 0x00000001 + +#define FSMOUNT_CLOEXEC 0x00000001 +#endif /* _UAPI_LINUX_FS_H */
kernel/sys_ni.c +1 -0
@@ -435,3 +435,4 @@ COND_SYSCALL(setuid16);/* fd-based mount */ COND_SYSCALL (sys_fsopen); +COND_SYSCALL (sys_fsmount);
Arnd Bergmann
maintainerRe: [PATCH 21/32] VFS: Implement fsmount() to effect a pre-configured mount [ver #8]
Quoted 16 lines · David Howells
Provide a system call by which a filesystem opened with
fsopen()and configured by a series of writes can be mounted:int ret = fsmount(int fsfd, int dfd, const char *path,
unsigned intat_flags, unsigned int flags);fs/namespace.c +7
-0+/* +* Create a kernel mount representation for a new, prepared superblock +* (specified by fs_fd) and attach to an O_PATH-class file descriptor. +*/ +SYSCALL_DEFINE5(fsmount, int, fs_fd, unsigned int, flags, unsigned int, ms_flags, + void *, spare_4, void *, spare_5) +++ b/include/linux/syscalls.h
fs/namespace.c asmlinkage long sys_statx(int dfd, const char __user *path, unsigned flags, · line 903
Quoted 6 lines
fs/namespace.c +2
-0@@ -898,6 +898,8 @@ asmlinkage long sys_statx(int dfd, const char __user *path, unsigned flags, unsigned mask, struct statx __user *buffer);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);
The prototype in the header doesn't match the one in the implementation, which should cause a compile-time error, at least if syscalls.h is included in namespace.c
Do you have a particular use case in mind for the spare_4/spare_5 arguments? If not, we can probably skip them. If we end up needing them after all, we can always add a new syscall entry point, or use one of the flag bits to decide whether
the additional arguments are valid or not.
kernel/sys_ni.c COND_SYSCALL(setuid16); · line 438
Quoted 7 lines
kernel/sys_ni.c +1
-0@@ -435,3 +435,4 @@ COND_SYSCALL(setuid16);/* fd-based mount */ COND_SYSCALL (sys_fsopen); +COND_SYSCALL (sys_fsmount);
This should only be needed if the syscall is optional, which it doesn't seem to be (same for the other ones here).
Arnd
David Howells
maintainerRe: [PATCH 21/32] VFS: Implement fsmount() to effect a pre-configured mount [ver #8]
Quoted 3 lines · Arnd Bergmann
The prototype in the header doesn't match the one in the implementation, which should cause a compile-time error, at least if
syscalls.his included innamespace.c
I've fixed that sort of thing up from kbuild warnings.
Quoted 4 lines
Do you have a particular use case in mind for the spare_4/spare_5 arguments? If not, we can probably skip them. If we end up needing them after all, we can always add a new syscall entry point, or use one of the flag bits to decide whether the additional arguments are valid or not.
Whilst that is true, these aren't really (or probably shouldn't be) hot path syscalls, so I would contend that just clearing the extra arguments shouldn't be much of a performance loss. On the other hand, syscall numbers are to some extent precious. If we hit ~512 syscalls we start to have an issue as we start to get overlaps.
And, yes, I do have ideas for them involving ID mapping on mounts (ie. killing off shiftfs).
Quoted 5 lines
Quoted 2 lines
COND_SYSCALL(sys_fsopen);
+COND_SYSCALL(sys_fsmount);This should only be needed if the syscall is optional, which it doesn't seem to be (same for the other ones here).
Al removed them.
David
David Howells
maintainerPATCH 22/32 vfs: Provide an fspick() system call [ver #8]
In reply to David HowellsProvide 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.
---
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(-)
arch/x86/entry/syscalls/syscall_32.tbl +1 -0
@@ -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
arch/x86/entry/syscalls/syscall_64.tbl +1 -0
@@ -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
fs/fsopen.c +74 -20
124 lines not on this page · raw message
include/linux/syscalls.h +1 -0
@@ -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);/*
include/uapi/linux/fs.h +5 -0
@@ -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 */
kernel/sys_ni.c +1 -0
@@ -436,3 +436,4 @@ COND_SYSCALL(setuid16);/* fd-based mount */ COND_SYSCALL (sys_fsopen);COND_SYSCALL (sys_fsmount); +COND_SYSCALL (sys_fspick);
David Howells
maintainerPATCH 23/32 VFS: Implement logging through fs_context [ver #8]
In reply to David HowellsImplement the ability for filesystems to log error, warning and informational messages through the fs_context. These can be extracted by userspace by reading from an fd created by fsopen().
Error messages are prefixed with "e ", warnings with "w " and informational messages with "i ".
Inside the kernel, formatted messages are malloc'd but unformatted messages are not copied if they're either in the core .rodata section or in the .rodata section of the filesystem module pinned by fs_context::fs_type. The messages are only good till the fs_type is released.
Note that the logging object is shared between duplicated fs_context structures. This is so that such as NFS which do a mount within a mount can get at least some of the errors from the inner mount.
Five logging functions are provided for this:
(1) void logfc(struct fs_context *fc, const char *fmt, ...);
This logs a message into the context. If the buffer is full, the earliest message is discarded.
(2) void errorf(fc, fmt, ...);
This wraps logfc() to log an error.
(3) void invalf(fc, fmt, ...);
This wraps errorf() and returns -EINVAL for convenience.
(4) void warnf(fc, fmt, ...);
This wraps logfc() to log a warning.
(5) void infof(fc, fmt, ...);
This wraps logfc() to log an informational message.
---
fs/fs_context.c | 92 ++++++++++++++++++++++++++++++++++++++++++++ fs/fsopen.c | 71 ++++++++++++++++++++++++++++++++++ include/linux/fs_context.h | 58 ++++++++++++++++++++++++++++ 3 files changed, 220 insertions(+), 1 deletion(-)
fs/fs_context.c +91 -1
@@ -11,6 +11,7 @@*/ #define pr_fmt (fmt) KBUILD_MODNAME ": " fmt +#include <linux/module.h> #include <linux/fs_context.h> #include <linux/fs.h> #include <linux/mount.h>
@@ -23,6 +24,7 @@#include <linux/pid_namespace.h> #include <linux/user_namespace.h> #include <net/net_namespace.h> +#include <asm/sections.h> #include "mount.h" enum legacy_fs_param {
@@ -327,7 +329,7 @@ struct fs_context *vfs_dup_fs_context(struct fs_context *src_fc)int ret;if (!src_fc->ops->dup) -return ERR_PTR (-ENOTSUPP ); +return ERR_PTR (-EOPNOTSUPP ); fc =kmemdup (src_fc,sizeof (struct legacy_fs_context ),GFP_KERNEL );if (!fc)
@@ -340,6 +342,8 @@ struct fs_context *vfs_dup_fs_context(struct fs_context *src_fc)get_net (fc->net_ns);get_user_ns (fc->user_ns);get_cred (fc->cred); +if (fc->log) +refcount_inc (&fc->log->usage);/* Can't call put until we've called ->dup */ ret = fc->ops->dup (fc, src_fc);
@@ -357,6 +361,91 @@ struct fs_context *vfs_dup_fs_context(struct fs_context *src_fc) }EXPORT_SYMBOL (vfs_dup_fs_context); +/** +* logfc - Log a message to a filesystem context +* @fc: The filesystem context to log to. +* @fmt: The format of the buffer. +*/ +void logfc (struct fs_context *fc,const char *fmt, ...) +{ +static const char store_failure[] ="OOM: Can't store error string" ; +struct fc_log *log = fc->log; +unsigned int logsize =ARRAY_SIZE (log->buffer); +const char *p; +va_list va; +char *q; +u8 freeable, index; + +if (!log) +return ; + +va_start (va, fmt); +if (!strchr (fmt,'%' )) { + p = fmt; + goto unformatted_string; + } +if (strcmp (fmt,"%s" ) ==0 ) { + p = va_arg(va, const char *); + goto unformatted_string; + } + + q =kvasprintf (GFP_KERNEL , fmt, va); +copied_string: +if (!q) + goto store_failure; + freeable =1 ; + goto store_string; + +unformatted_string: +if ((unsigned long )p >= (unsigned long )__start_rodata && + (unsigned long )p < (unsigned long )__end_rodata) + goto const_string; +if (within_module_core ((unsigned long )p, log->owner)) + goto const_string; + q =kstrdup (p,GFP_KERNEL ); + goto copied_string; + +store_failure: + p = store_failure; +const_string: + q = (char *)p; + freeable =0 ; +store_string: + index = log->head & (logsize -1 ); +if ((int )log->head - (int )log->tail ==8 ) { +/* The buffer is full, discard the oldest message */ +if (log->need_free & (1 << index)) +kfree (log->buffer[index]); + log->tail++; + } + + log->buffer[index] = q; + log->need_free &= ~(1 << index); + log->need_free |= freeable << index; + log->head++; +va_end (va); +} +EXPORT_SYMBOL (logfc); + +/* +* Free a logging structure. +*/ +static void put_fc_log (struct fs_context *fc) +{ +struct fc_log *log = fc->log; +int i; + +if (log) { +if (refcount_dec_and_test (&log->usage)) { + fc->log =NULL ; +for (i =0 ; i <=7 ; i++) +if (log->need_free & (1 << i)) +kfree (log->buffer[i]); +kfree (log); + } + } +} +/** * put_fs_context - Dispose of a superblock configuration context. * @fc: The context to dispose of.
@@ -385,6 +474,7 @@ void put_fs_context(struct fs_context *fc)if (fc->cred)put_cred (fc->cred);kfree (fc->subtype); +put_fc_log (fc);put_filesystem (fc->fs_type);kfree (fc->source);kfree (fc);
fs/fsopen.c +71 -0
100 lines not on this page · raw message
include/linux/fs_context.h +58 -0
74 lines not on this page · raw message
Re: [PATCH 23/32] VFS: Implement logging through fs_context [ver #8]
Quoted 6 lines · David Howells
Implement the ability for filesystems to log error, warning and informational messages through the
fs_context. These can be extracted by userspace by reading from an fd created byfsopen().Error messages are prefixed with "e ", warnings with "w " and informational messages with "i ".
[]
fs/fs_context.c
Quoted 1 line
fs/fs_context.c +0
-0
[]
Quoted 55 lines
fs/fs_context.c +55
-0+/** +* logfc - Log a message to a filesystem context +* @fc: The filesystem context to log to. +* @fmt: The format of the buffer. +*/ +void logfc (struct fs_context *fc,const char *fmt, ...) +{ +static const char store_failure[] ="OOM: Can't store error string" ; +struct fc_log *log = fc->log; +unsigned int logsize =ARRAY_SIZE (log->buffer); +const char *p; +va_list va; +char *q; +u8 freeable, index; + +if (!log) +return ; + +va_start (va, fmt); +if (!strchr (fmt,'%' )) { + p = fmt; + goto unformatted_string; + } +if (strcmp (fmt,"%s" ) ==0 ) { + p = va_arg(va, const char *); + goto unformatted_string; + } + + q =kvasprintf (GFP_KERNEL , fmt, va); +copied_string: +if (!q) + goto store_failure; + freeable =1 ; + goto store_string; + +unformatted_string: +if ((unsigned long )p >= (unsigned long )__start_rodata && + (unsigned long )p < (unsigned long )__end_rodata) + goto const_string; +if (within_module_core ((unsigned long )p, log->owner)) + goto const_string; + q =kstrdup (p,GFP_KERNEL ); + goto copied_string; + +store_failure: + p = store_failure; +const_string: + q = (char *)p; + freeable =0 ; +store_string: + index = log->head & (logsize -1 ); +if ((int )log->head - (int )log->tail ==8 ) { +/* The buffer is full, discard the oldest message */ +if (log->need_free & (1 << index)) +kfree (log->buffer[index]);
fs/fs_context.c struct fs_context *vfs_dup_fs_context(struct fs_context *src_fc) · line 428
Quoted 10 lines
fs/fs_context.c +10
-0+ log->tail++; + } + + log->buffer[index] = q; + log->need_free &= ~(1 << index); + log->need_free |= freeable << index; + log->head++; +va_end (va); +} +EXPORT_SYMBOL (logfc);
Perhaps this could be renamed to something more obviously associated to fs_context
[]
fs/fsopen.c
Quoted 1 line
fs/fsopen.c +0
-0
[]
Quoted 4 lines
fs/fsopen.c +0
-0@@ -159,7 +159,57 @@ static ssize_t fscontext_fs_write(struct file *file, goto err_unlock; }
fs/fsopen.c static ssize_t fscontext_fs_write(struct file *file, · line 171
Quoted 10 lines
fs/fsopen.c +10
-0+/* +* Allow the user to read back any error, warning or informational messages. +*/ +static ssize_t fscontext_fs_read (struct file *file, +char __user *_buf,size_t len,loff_t *pos) +{ +struct fs_context *fc = file->private_data; +struct fc_log *log = fc->log; +struct inode *inode =file_inode (file); +unsigned int logsize =ARRAY_SIZE (log->buffer);
logsize isn't modified, could be removed and ARRAY_SIZE used in-place.
fs/fsopen.c static ssize_t fscontext_fs_write(struct file *file, · line 174
Quoted 3 lines
fs/fsopen.c +3
-0+ssize_t ret; +char *p; +bool need_free;
It _looks_ like need_free isn't set by all codepaths, but it doesn't need to be given the goto/return.
It also seems the the logic isn't straightforward here and could be rewritten to be more obvious.
Quoted 56 lines
fs/fsopen.c +41
-0+int index, n; + + ret =inode_lock_killable (inode); +if (ret <0 ) +return ret; + + ret = -ENODATA ; +if (log->head != log->tail) { + index = log->tail & (logsize -1 ); + p = log->buffer[index]; + need_free = log->need_free & (1 << index); + log->buffer[index] =NULL ; + log->need_free &= ~(1 << index); + log->tail++; + ret =0 ; + } + +inode_unlock (inode); +if (ret <0 ) +return ret; + + ret = -EMSGSIZE ; + n =strlen (p); +if (n > len) + goto err_free; + ret = -EFAULT ; +if (copy_to_user (_buf, p, n) !=0 ) + goto err_free; + ret = n; + +err_free: +if (need_free) +kfree (p); +return ret; +} +const struct file_operations fscontext_fs_fops = { + .read = fscontext_fs_read, .write = fscontext_fs_write, .release = fscontext_fs_release, .llseek = no_llseek,@@ -330,6 +380,7 @@ SYSCALL_DEFINE5(fsopen, const char __user *, _fs_name, unsigned int, flags,struct file_system_type *fs_type;struct fs_context *fc;const char *fs_name; +int ret;if (!ns_capable (current->nsproxy->mnt_ns->user_ns,CAP_SYS_ADMIN ))return -EPERM ;@@ -353,7 +404,18 @@ SYSCALL_DEFINE5(fsopen, const char __user *, _fs_name, unsigned int, flags, fc->phase =FS_CONTEXT_CREATE_PARAMS ; + ret = -ENOMEM ; + fc->log =kzalloc (sizeof (*fc->log),GFP_KERNEL ); +if (!fc->log)
fs/fsopen.c SYSCALL_DEFINE5(fsopen, const char __user *, _fs_name, unsigned int, flags, · line 419
Quoted 10 lines
fs/fsopen.c +8
-0+ goto err_fc; +refcount_set (&fc->log->usage,1 ); + fc->log->owner = fs_type->owner; +return fsopen_create_fd (fc, flags &FSOPEN_CLOEXEC ); + +err_fc: +put_fs_context (fc); +return ret; }
[]
Quoted 10 lines
include/linux/fs_context.h +4
-0@@ -117,4 +119,60 @@ extern int vfs_get_super(struct fs_context *fc,extern const struct file_operations fscontext_fs_fops; +/* +* Mount error, warning and informational message logging. This structure is +* shareable between a mount and a subordinate mount. +*/
include/linux/fs_context.h extern int vfs_get_super(struct fs_context *fc, · line 135
Quoted 10 lines
include/linux/fs_context.h +10
-0+struct fc_log { +refcount_t usage; +u8 head;/* Insertion index in buffer[] */ +u8 tail;/* Removal index in buffer[] */ +u8 need_free;/* Mask of kfree'able items in buffer[] */ +struct module *owner;/* Owner module for strings that don't then need freeing */ +char *buffer[8 ]; +}; + +extern __attribute__((format(printf, 2, 3)))
__printf(2, 3)
include/linux/fs_context.h extern int vfs_get_super(struct fs_context *fc, · line 146
Quoted 11 lines
include/linux/fs_context.h +11
-0+void logfc (struct fs_context *fc,const char *fmt, ...); + +/** +* infof - Store supplementary informational message +* @fc: The context in which to log the informational message +* @fmt: The format string +* +* Store the supplementary informational message for the process if the process +* has enabled the facility. +*/ +#define infof (fc, fmt, ...) ({ logfc(fc, "i "fmt, ## __VA_ARGS__); })
Why a statement expression macro and not just
#define infof(fc, fmt, ...) logfc(fc, "i " fmt, ##__VA_ARGS__)
etc...
David Howells
maintainerPATCH 24/32 vfs: Add some logging to the core users of the fs_context log [ver #8]
In reply to David HowellsAdd some logging to the core users of the fs_context log so that information can be extracted from them as to the reason for failure.
---
fs/super.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-)
fs/super.c +3 -1
@@ -1743,8 +1743,10 @@ int vfs_get_tree(struct fs_context *fc)struct super_block *sb;int ret; -if (fc->fs_type->fs_flags &FS_REQUIRES_DEV && !fc->source) +if (fc->fs_type->fs_flags &FS_REQUIRES_DEV && !fc->source) { +errorf (fc,"Filesystem requires source device" );return -ENOENT ; + }if (fc->root)return -EBUSY ;
David Howells
maintainerPATCH 25/32 afs: Add fs_context support [ver #8]
In reply to David HowellsAdd fs_context support to the AFS filesystem, converting the parameter parsing to store options there.
This will form the basis for namespace propagation over mountpoints within the AFS model, thereby allowing AFS to be used in containers more easily.
---
fs/afs/internal.h | 8 - fs/afs/super.c | 444 ++++++++++++++++++++++++++++++----------------------- fs/afs/volume.c | 4 3 files changed, 256 insertions(+), 200 deletions(-)
fs/afs/internal.h +4 -4
@@ -34,15 +34,15 @@struct pagevec ;struct afs_call ; -struct afs_mount_params { +struct afs_fs_context {bool rwpath;/* T if the parent should be considered R/W */ bool force;/* T to force cell type */ bool autocell;/* T if set auto mount operation */ bool dyn_root;/* T if dynamic root */ +bool no_cell;/* T if the source is "none" (for dynroot) */ afs_voltype_t type;/* type of volume requested */ -int volnamesz;/* size of volume name */ +unsigned int volnamesz;/* size of volume name */ const char *volname;/* name of volume to mount */ -struct net *net_ns;/* Network namespace in effect */ struct afs_net *net;/* the AFS net namespace stuff */ struct afs_cell *cell;/* cell in which to find volume */ struct afs_volume *volume;/* volume record */
@@ -1012,7 +1012,7 @@ static inline struct afs_volume *__afs_get_volume(struct afs_volume *volume)return volume; } -extern struct afs_volume *afs_create_volume (struct afs_mount_params *); +extern struct afs_volume *afs_create_volume (struct afs_fs_context *);extern void afs_activate_volume (struct afs_volume *);extern void afs_deactivate_volume (struct afs_volume *);extern void afs_put_volume (struct afs_cell *,struct afs_volume *);
fs/afs/super.c +250 -194
626 lines not on this page · raw message
fs/afs/volume.c +2 -2
@@ -21,7 +21,7 @@ static const char *const afs_voltypes[] = { "R/W", "R/O", "BAK" };/* * Allocate a volume record and load it up from a vldb record. */ -static struct afs_volume *afs_alloc_volume (struct afs_mount_params *params, +static struct afs_volume *afs_alloc_volume (struct afs_fs_context *params,struct afs_vldb_entry *vldb,unsigned long type_mask) {
@@ -149,7 +149,7 @@ static struct afs_vldb_entry *afs_vl_lookup_vldb(struct afs_cell *cell,* - Rule 3: If parent volume is R/W, then only mount R/W volume unless * explicitly told otherwise */ -struct afs_volume *afs_create_volume (struct afs_mount_params *params) +struct afs_volume *afs_create_volume (struct afs_fs_context *params) {struct afs_vldb_entry *vldb;struct afs_volume *volume;
David Howells
maintainerPATCH 26/32 afs: Use fs_context to pass parameters over automount [ver #8]
In reply to David HowellsAlter the AFS automounting code to create and modify an fs_context struct when parameterising a new mount triggered by an AFS mountpoint rather than constructing device name and option strings.
Also remove the cell=, vol= and rwpath options as they are then redundant. The reason they existed is because the 'device name' may be derived literally from a mountpoint object in the filesystem, so default cell and parent-type information needed to be passed in by some other method from the automount routines. The vol= option didn't end up being used.
---
fs/afs/internal.h | 1 fs/afs/mntpt.c | 148 +++++++++++++++++++++++++++-------------------------- fs/afs/super.c | 43 +-------------- 3 files changed, 79 insertions(+), 113 deletions(-)
fs/afs/internal.h +0 -1
@@ -35,7 +35,6 @@ struct pagevec;struct afs_call ;struct afs_fs_context { -bool rwpath;/* T if the parent should be considered R/W */ bool force;/* T to force cell type */ bool autocell;/* T if set auto mount operation */ bool dyn_root;/* T if dynamic root */
fs/afs/mntpt.c +75 -73
188 lines not on this page · raw message
fs/afs/super.c +4 -39
85 lines not on this page · raw message
Re: [PATCH 26/32] afs: Use fs_context to pass parameters over automount [ver #8]
Quoted 202 lines · David Howells
Alter the AFS automounting code to create and modify an
fs_contextstruct when parameterising a new mount triggered by an AFS mountpoint rather than constructing device name and option strings.Also remove the cell=, vol= and rwpath options as they are then redundant. The reason they existed is because the 'device name' may be derived literally from a mountpoint object in the filesystem, so default cell and parent-type information needed to be passed in by some other method from the automount routines. The vol= option didn't end up being used.
Signed-off-by David Howells <[email protected]>cc Eric W. Biederman <[email protected]>---
fs/afs/internal.h | 1 fs/afs/mntpt.c | 148 +++++++++++++++++++++++++++-------------------------- fs/afs/super.c | 43 +-------------- 3 files changed, 79 insertions(+), 113 deletions(-)fs/afs/internal.h +0
-1@@ -35,7 +35,6 @@ struct pagevec;struct afs_call ;struct afs_fs_context { -bool rwpath;/* T if the parent should be considered R/W */ bool force;/* T to force cell type */ bool autocell;/* T if set auto mount operation */ bool dyn_root;/* T if dynamic root */ fs/afs/mntpt.c +69
-62@@ -47,6 +47,8 @@ static DECLARE_DELAYED_WORK(afs_mntpt_expiry_timer, afs_mntpt_expiry_timed_out);static unsigned long afs_mntpt_expiry_timeout =10 *60 ; +static const char afs_root_volume[] ="root.cell" ; +/* * no valid lookup procedure on this sort of dir */ @@ -68,107 +70,107 @@ static int afs_mntpt_open(struct inode *inode, struct file *file) }/* -* create a vfsmount to be automounted +* Set the parameters for the proposed superblock. */ -static struct vfsmount *afs_mntpt_do_automount (struct dentry *mntpt) +static int afs_mntpt_set_params (struct fs_context *fc,struct dentry *mntpt) { -struct afs_super_info *as; -struct vfsmount *mnt; -struct afs_vnode *vnode; -struct page *page; -char *devname, *options; -bool rwpath = false; +struct afs_fs_context *ctx = fc->fs_private; +struct afs_vnode *vnode =AFS_FS_I (d_inode (mntpt)); +struct afs_cell *cell; +const char *p;int ret; -_enter ("{%pd}" , mntpt); - -BUG_ON (!d_inode (mntpt)); - - ret = -ENOMEM ; - devname = (char *)get_zeroed_page (GFP_KERNEL ); -if (!devname) - goto error_no_devname; - - options = (char *)get_zeroed_page (GFP_KERNEL ); -if (!options) - goto error_no_options; - - vnode =AFS_FS_I (d_inode (mntpt));if (test_bit (AFS_VNODE_PSEUDODIR , &vnode->flags)) {/* if the directory is a pseudo directory, use the d_name */ -static const char afs_root_cell[] =":root.cell." ;unsigned size = mntpt->d_name.len; - ret = -ENOENT ; -if (size <2 || size >AFS_MAXCELLNAME ) - goto error_no_page; +if (size <2 ) +return -ENOENT ; + p = mntpt->d_name.name;if (mntpt->d_name.name[0 ] =='.' ) { - devname[0 ] ='%' ; -memcpy (devname +1 , mntpt->d_name.name +1 , size -1 ); -memcpy (devname + size, afs_root_cell, -sizeof (afs_root_cell)); - rwpath = true; - }else { - devname[0 ] ='#' ; -memcpy (devname +1 , mntpt->d_name.name, size); -memcpy (devname + size +1 , afs_root_cell, -sizeof (afs_root_cell)); + size--; + p++; + ctx->type =AFSVL_RWVOL ; + ctx->force = true; + } +if (size >AFS_MAXCELLNAME ) +return -ENAMETOOLONG ; + + cell =afs_lookup_cell (ctx->net, p, size,NULL , false); +if (IS_ERR (cell)) { +pr_err ("kAFS: unable to lookup cell '%pd'\n" , mntpt); +return PTR_ERR (cell); } +afs_put_cell (ctx->net, ctx->cell); + ctx->cell = cell; + + ctx->volname = afs_root_volume; + ctx->volnamesz =sizeof (afs_root_volume) -1 ; }else {/* read the contents of the AFS special symlink */ +struct page *page;loff_t size =i_size_read (d_inode (mntpt));char *buf; - ret = -EINVAL ;if (size >PAGE_SIZE -1 ) - goto error_no_page; +return -EINVAL ; page =read_mapping_page (d_inode (mntpt)->i_mapping,0 ,NULL ); -if (IS_ERR (page)) { - ret =PTR_ERR (page); - goto error_no_page; - } +if (IS_ERR (page)) +return PTR_ERR (page); - ret = -EIO ; -if (PageError (page)) - goto error; +if (PageError (page)) { +put_page (page); +return -EIO ; + } - buf =kmap_atomic (page); -memcpy (devname, buf, size); -kunmap_atomic (buf); + buf =kmap (page); + ret =vfs_set_fs_source (fc, buf, size); +kunmap (page);put_page (page); - page =NULL ; +if (ret <0 ) +return ret; } -/* work out what options we want */ - as =AFS_FS_S (mntpt->d_sb); -if (as->cell) { -memcpy (options,"cell=" ,5 ); -strcpy (options +5 , as->cell->name); -if ((as->volume && as->volume->type ==AFSVL_RWVOL ) || rwpath) -strcat (options,",rwpath" ); - } +return 0 ; +} -/* try and do the mount */ -_debug ("--- attempting mount %s -o %s ---" , devname, options); - mnt =vfs_submount (mntpt, &afs_fs_type, devname, - options,strlen (options) +1 ); -_debug ("--- mount result %p ---" , mnt); +/* +* create a vfsmount to be automounted +*/ +static struct vfsmount *afs_mntpt_do_automount (struct dentry *mntpt) +{ +struct fs_context *fc; +struct vfsmount *mnt; +int ret; + +BUG_ON (!d_inode (mntpt)); + + fc =vfs_new_fs_context (&afs_fs_type, mntpt,0 , +FS_CONTEXT_FOR_SUBMOUNT ); +if (IS_ERR (fc)) +return ERR_CAST (fc); + + ret =afs_mntpt_set_params (fc, mntpt); +if (ret <0 ) + goto error_fc; + + ret =vfs_get_tree (fc); +if (ret <0 ) + goto error_fc; + + mnt =vfs_create_mount (fc,0 ); +if (IS_ERR (mnt)) {
fs/afs/mntpt.c static int afs_mntpt_open(struct inode *inode, struct file *file) · line 171
Quoted 10 lines
fs/afs/mntpt.c +4
-3+ ret =PTR_ERR (mnt); + goto error_fc; + } -free_page ((unsigned long ) devname); -free_page ((unsigned long ) options); -_leave (" = %p" , mnt); +put_fs_context (fc);return mnt;
Why are you performing a put_fs_context(fc) in the success code path? Do we not need a reference of fc anymore?
Quoted 13 lines
fs/afs/mntpt.c +2
-8-error: -put_page (page); -error_no_page: -free_page ((unsigned long ) options); -error_no_options: -free_page ((unsigned long ) devname); -error_no_devname: -_leave (" = %d" , ret); +error_fc: +put_fs_context (fc);return ERR_PTR (ret); }
Signature · 1 line
Goldwyn
David Howells
maintainerRe: [PATCH 26/32] afs: Use fs_context to pass parameters over automount [ver #8]
Goldwyn Rodrigues <[email protected]> wrote:
Quoted 27 lines · Goldwyn Rodrigues
Quoted 27 lines
fs/afs/mntpt.c +26
-0+static struct vfsmount *afs_mntpt_do_automount (struct dentry *mntpt) +{ +struct fs_context *fc; +struct vfsmount *mnt; +int ret; + +BUG_ON (!d_inode (mntpt)); + + fc =vfs_new_fs_context (&afs_fs_type, mntpt,0 , +FS_CONTEXT_FOR_SUBMOUNT ); +if (IS_ERR (fc)) +return ERR_CAST (fc); + + ret =afs_mntpt_set_params (fc, mntpt); +if (ret <0 ) + goto error_fc; + + ret =vfs_get_tree (fc); +if (ret <0 ) + goto error_fc; + + mnt =vfs_create_mount (fc,0 ); +if (IS_ERR (mnt)) { + ret =PTR_ERR (mnt); + goto error_fc; + }
Quoted 8 lines
fs/afs/mntpt.c static int afs_mntpt_open(struct inode *inode, struct file *file) · line 170
Quoted 6 lines
fs/afs/mntpt.c +1
-3-free_page ((unsigned long ) devname); -free_page ((unsigned long ) options); -_leave (" = %p" , mnt); +put_fs_context (fc);return mnt;Why are you performing a
put_fs_context(fc)in the success code path? Do we not need a reference of fc anymore?
No. This is the ->d_automount() hook. The context is created at the top of the function, configuration is done, the superblock is obtained, a mount object is created (for which we get a ref returned). After that point, we don't need the context any more and no one else is going to clean it up for us.
David
David Howells
maintainerPATCH 27/32 vfs: Use a 'struct fd_cookie *' type for light fd handling [ver #8]
In reply to David HowellsUse a 'struct fd_cookie *' type for light fd handling rather than an unsigned long so that confusion doesn't arise with integer fd numbers.
I have a use case where I want to store this in struct nameidata, but don't want to expand it to a struct fd to save space.
---
fs/file.c | 20 +++++++++++--------- include/linux/file.h | 31 ++++++++++++++++++++++++------- 2 files changed, 35 insertions(+), 16 deletions(-)
fs/file.c +11 -9
@@ -727,7 +727,7 @@ EXPORT_SYMBOL(fget_raw);* The fput_needed flag returned by fget_light should be passed to the * corresponding fput_light. */ -static unsigned long __fget_light (unsigned int fd,fmode_t mask) +static struct fd_cookie *__fget_light (unsigned int fd,fmode_t mask) {struct files_struct *files = current->files;struct file *file;
@@ -736,33 +736,35 @@ static unsigned long __fget_light(unsigned int fd, fmode_t mask) file =__fcheck_files (files, fd);if (!file ||unlikely (file->f_mode & mask))return 0 ; -return (unsigned long )file; +return (struct fd_cookie *)file; }else { file =__fget (fd, mask);if (!file)return 0 ; -return FDPUT_FPUT | (unsigned long )file; +return (struct fd_cookie *)(FDPUT_FPUT | (unsigned long )file); } } -unsigned long __fdget (unsigned int fd) + +struct fd_cookie *__fdget (unsigned int fd) {return __fget_light (fd,FMODE_PATH ); }EXPORT_SYMBOL (__fdget); -unsigned long __fdget_raw (unsigned int fd) +struct fd_cookie *__fdget_raw (unsigned int fd) {return __fget_light (fd,0 ); } -unsigned long __fdget_pos (unsigned int fd) +struct fd_cookie *__fdget_pos (unsigned int fd) { -unsigned long v =__fdget (fd); -struct file *file = (struct file *)(v & ~3 ); +struct fd_cookie *v =__fdget (fd); +struct file *file =__fdfile (v);if (file && (file->f_mode &FMODE_ATOMIC_POS )) {if (file_count (file) >1 ) { - v |=FDPUT_POS_UNLOCK ; + v = (struct fd_cookie *) + ((unsigned long )v |FDPUT_POS_UNLOCK );mutex_lock (&file->f_pos_lock); } }
include/linux/file.h +24 -7
@@ -11,6 +11,7 @@#include <linux/posix_types.h> struct file ; +struct fd_cookie ;/* Deliberately undefined structure */ extern void fput (struct file *);
@@ -31,8 +32,24 @@ struct fd {struct file *file;unsigned int flags; }; -#define FDPUT_FPUT 1 -#define FDPUT_POS_UNLOCK 2 +#define FDPUT_FPUT 1 +#define FDPUT_POS_UNLOCK 2 +#define FDPUT__MASK 3 + +static inline unsigned long __fdflags (struct fd_cookie *f) +{ +return (unsigned long )f &FDPUT__MASK ; +} + +static inline struct file *__fdfile (struct fd_cookie *f) +{ +return (struct file *)((unsigned long )f & ~FDPUT__MASK ); +} + +static inline void __fdput (struct fd_cookie *f) +{ +fput_light (__fdfile (f),__fdflags (f) &FDPUT_FPUT ); +}static inline void fdput (struct fd fd) {
@@ -42,14 +59,14 @@ static inline void fdput(struct fd fd)extern struct file *fget (unsigned int fd);extern struct file *fget_raw (unsigned int fd); -extern unsigned long __fdget (unsigned int fd); -extern unsigned long __fdget_raw (unsigned int fd); -extern unsigned long __fdget_pos (unsigned int fd); +extern struct fd_cookie *__fdget (unsigned int fd); +extern struct fd_cookie *__fdget_raw (unsigned int fd); +extern struct fd_cookie *__fdget_pos (unsigned int fd);extern void __f_unlock_pos (struct file *); -static inline struct fd __to_fd (unsigned long v) +static inline struct fd __to_fd (struct fd_cookie *v) { -return (struct fd ){(struct file *)(v & ~3 ),v &3 }; +return (struct fd ){__fdfile (v),__fdflags (v)}; }static inline struct fd fdget (unsigned int fd)
David Howells
maintainerPATCH 28/32 vfs: Store the fd_cookie in nameidata, not the dfd int [ver #8]
In reply to David HowellsLook up dfd in set_nameidata() if not AT_FDCWD and store the resultant fd_cookie in struct nameidata. LOOKUP_AT_FDCWD is set if AT_FDCWD was supplied. The fd_cookie is released in restore_nameidata().
This means that where the fd points in a construct like the following:
set_nameidata(&nd, dfd, name); retval = path_lookupat(&nd, flags | LOOKUP_RCU, path); if (unlikely(retval == -ECHILD)) retval = path_lookupat(&nd, flags, path); if (unlikely(retval == -ESTALE)) retval = path_lookupat(&nd, flags | LOOKUP_REVAL, path);
doesn't change between the three calls to path_lookupat() or similar.
It also allows us to fish the fd_cookie out for the upcoming move_mount() syscall which needs to clear a file flag if successful.
---
fs/namei.c | 38 +++++++++++++++++++++----------------- 1 file changed, 21 insertions(+), 17 deletions(-)
fs/namei.c +21 -17
@@ -53,8 +53,8 @@* The new code replaces the old recursive symlink resolution with * an iterative one (in case of non-nested symlink chains). It does * this with calls to <fs>_follow_link(). -* As a side effect, dir_namei(), _namei() and follow_link() are now -* replaced with a single function lookup_dentry() that can handle all +* As a side effect, dir_namei(), _namei() and follow_link() are now +* replaced with a single function lookup_dentry() that can handle all * the special cases of the former code. * * With the new dcache, the pathname is stored at each inode, at least as
@@ -506,25 +506,34 @@ struct nameidata {struct filename *name;struct nameidata *saved;struct inode *link_inode; +struct fd_cookie *dfd; +bool have_dfd;unsigned root_seq; -int dfd; } __randomize_layout;static void set_nameidata (struct nameidata *p,int dfd,struct filename *name) {struct nameidata *old = current->nameidata; p->stack = p->internal; - p->dfd = dfd; p->name = name; p->total_link_count = old ? old->total_link_count :0 ; p->saved = old; current->nameidata = p; + +if (likely (dfd ==AT_FDCWD )) { + p->dfd =NULL ; + p->have_dfd = false; + }else { + p->dfd =__fdget_raw (dfd);/* Error are dealt with later */ + p->have_dfd = true; + } }static void restore_nameidata (void ) {struct nameidata *now = current->nameidata, *old = now->saved; +__fdput (now->dfd); current->nameidata = old;if (old) old->total_link_count = now->total_link_count;
@@ -2165,7 +2174,7 @@ static const char *path_init(struct nameidata *nd, unsigned flags) nd->root.mnt =NULL ;rcu_read_unlock ();return ERR_PTR (-ECHILD ); - }else if (nd->dfd ==AT_FDCWD ) { + }else if (!nd->have_dfd) {if (flags &LOOKUP_RCU ) {struct fs_struct *fs = current->fs;unsigned seq;
@@ -2185,22 +2194,18 @@ static const char *path_init(struct nameidata *nd, unsigned flags)return s; }else {/* Caller must check execute permissions on the starting path component */ -struct fd f =fdget_raw (nd->dfd);struct dentry *dentry; +struct file *file =__fdfile (nd->dfd); -if (!f.file) +if (!nd->dfd)return ERR_PTR (-EBADF ); - dentry = f.file->f_path.dentry; + dentry = file->f_path.dentry; -if (*s) { -if (!d_can_lookup (dentry)) { -fdput (f); -return ERR_PTR (-ENOTDIR ); - } - } +if (*s && !d_can_lookup (dentry)) +return ERR_PTR (-ENOTDIR ); - nd->path = f.file->f_path; + nd->path = file->f_path;if (flags &LOOKUP_RCU ) {rcu_read_lock (); nd->inode = nd->path.dentry->d_inode;
@@ -2209,7 +2214,6 @@ static const char *path_init(struct nameidata *nd, unsigned flags)path_get (&nd->path); nd->inode = nd->path.dentry->d_inode; } -fdput (f);return s; } }
@@ -3557,7 +3561,7 @@ struct file *do_file_open_root(struct dentry *dentry, struct vfsmount *mnt,if (IS_ERR (filename))return ERR_CAST (filename); -set_nameidata (&nd,-1 , filename); +set_nameidata (&nd,AT_FDCWD , filename); file =path_openat (&nd, op, flags |LOOKUP_RCU );if (unlikely (file ==ERR_PTR (-ECHILD ))) file =path_openat (&nd, op, flags);
David Howells
maintainerPATCH 29/32 vfs: Don't mix FMODE_* flags with O_* flags [ver #8]
In reply to David Howellsbuild_open_flags() has a weird bit in it:
/* Must never be set by userspace */ flags &= ~FMODE_NONOTIFY & ~O_CLOEXEC;
This didn't used to have the O_CLOEXEC removal in it, but just used to be:
/* Must never be set by userspace */ flags &= ~FMODE_NONOTIFY;
but this flag should be only from file->f_mode and should have nothing to do with the O_* flags.
Further, this check is redundant with:
flags &= VALID_OPEN_FLAGS;
a few lines above.
Fix this by splitting the f_mode flags (FMODE_*) from the f_flags flags (O_*) internally.
---
drivers/dma-buf/dma-buf.c | 2 +- drivers/dma-buf/sync_file.c | 2 +- drivers/gpu/drm/drm_syncobj.c | 2 +- drivers/staging/lustre/lustre/mdc/mdc_lib.c | 2 +- drivers/staging/lustre/lustre/mdc/mdc_locks.c | 2 +- drivers/tty/pty.c | 4 ++-- fs/anon_inodes.c | 20 +++++++++++-------- fs/autofs4/dev-ioctl.c | 2 +- fs/cachefiles/rdwr.c | 2 +- fs/eventfd.c | 2 +- fs/eventpoll.c | 2 +- fs/exec.c | 6 ++++-- fs/exportfs/expfs.c | 2 +- fs/fcntl.c | 6 ++---- fs/internal.h | 1 + fs/namei.c | 1 + fs/namespace.c | 2 +- fs/nfs/dir.c | 15 ++++++++------ fs/nfs/nfs4proc.c | 9 +++------ fs/notify/fanotify/fanotify_user.c | 10 ++++++---- fs/notify/inotify/inotify_user.c | 2 +- fs/nsfs.c | 2 +- fs/open.c | 24 +++++++++++++++-------- fs/signalfd.c | 3 ++- fs/timerfd.c | 2 +- fs/xfs/xfs_ioctl.c | 2 +- include/linux/anon_inodes.h | 6 +++--- include/linux/fs.h | 26 ++++++++++++++++++------- include/linux/fsnotify.h | 8 ++++---- include/linux/nfs_fs.h | 3 ++- include/uapi/asm-generic/fcntl.h | 1 - ipc/mqueue.c | 6 ++---- kernel/bpf/syscall.c | 6 +++--- kernel/events/core.c | 2 +- net/unix/af_unix.c | 2 +- security/apparmor/file.c | 2 +- security/keys/big_key.c | 2 +- security/selinux/hooks.c | 2 +- 38 files changed, 109 insertions(+), 86 deletions(-)
drivers/dma-buf/dma-buf.c +1 -1
@@ -436,7 +436,7 @@ struct dma_buf *dma_buf_export(const struct dma_buf_export_info *exp_info) dmabuf->resv = resv; file =anon_inode_getfile ("dmabuf" , &dma_buf_fops, dmabuf, - exp_info->flags); + exp_info->flags,0 );if (IS_ERR (file)) { ret =PTR_ERR (file); goto err_dmabuf;
drivers/dma-buf/sync_file.c +1 -1
@@ -37,7 +37,7 @@ static struct sync_file *sync_file_alloc(void)return NULL ; sync_file->file =anon_inode_getfile ("sync_file" , &sync_file_fops, - sync_file,0 ); + sync_file,0 ,0 );if (IS_ERR (sync_file->file)) goto err;
drivers/gpu/drm/drm_syncobj.c +1 -1
@@ -419,7 +419,7 @@ int drm_syncobj_get_fd(struct drm_syncobj *syncobj, int *p_fd) file =anon_inode_getfile ("syncobj_file" , &drm_syncobj_file_fops, - syncobj,0 ); + syncobj,0 ,0 );if (IS_ERR (file)) {put_unused_fd (fd);return PTR_ERR (file);
drivers/staging/lustre/lustre/mdc/mdc_lib.c +1 -1
@@ -176,7 +176,7 @@ static inline __u64 mds_pack_open_flags(__u64 flags) cr_flags |=MDS_OPEN_SYNC ;if (flags &O_DIRECTORY ) cr_flags |=MDS_OPEN_DIRECTORY ; -if (flags & __FMODE_EXEC) +if (flags &FMODE_EXEC ) cr_flags |=MDS_FMODE_EXEC ;if (cl_is_lov_delay_create (flags)) cr_flags |=MDS_OPEN_DELAY_CREATE ;
drivers/staging/lustre/lustre/mdc/mdc_locks.c +1 -1
@@ -257,7 +257,7 @@ mdc_intent_open_pack(struct obd_export *exp, struct lookup_intent *it, }else {if (it->it_flags & (FMODE_WRITE |MDS_OPEN_TRUNC )) mode =LCK_CW ; -else if (it->it_flags & __FMODE_EXEC) +else if (it->it_flags &FMODE_EXEC ) mode =LCK_PR ;else mode =LCK_CR ;
drivers/tty/pty.c +2 -2
@@ -636,7 +636,7 @@ int ptm_open_peer(struct file *master, struct tty_struct *tty, int flags) } path.dentry = tty->link->driver_data; - filp =dentry_open (&path, flags,current_cred ()); + filp =dentry_open (&path, flags,0 ,current_cred ());mntput (path.mnt);if (IS_ERR (filp)) { retval =PTR_ERR (filp);
@@ -806,7 +806,7 @@ static int ptmx_open(struct inode *inode, struct file *filp)nonseekable_open (inode, filp);/* We refuse fsnotify events on ptmx, since it's a shared resource */ - filp->f_mode |=FMODE_NONOTIFY ; + filp->f_mode |=FMODE_DONT_NOTIFY ; retval =tty_alloc_file (filp);if (retval)
fs/anon_inodes.c +11 -9
@@ -60,7 +60,8 @@ static struct file_system_type anon_inode_fs_type = {* @name: [in] name of the "class" of the new file * @fops: [in] file operations for the new file * @priv: [in] private data for the new file (will be file's private_data) -* @flags: [in] flags +* @f_flags: [in] O_* flags +* @f_mode: [in] FMODE_* flags * * Creates a new file by hooking it on a single inode. This is useful for files * that do not need to have a full-fledged inode in order to operate correctly.
@@ -69,8 +70,8 @@ static struct file_system_type anon_inode_fs_type = {* setup. Returns the newly created file* or an error pointer. */ struct file *anon_inode_getfile (const char *name, -const struct file_operations *fops, -void *priv,int flags) +const struct file_operations *fops,void *priv, +unsigned int f_flags,fmode_t f_mode) {struct qstr this;struct path path;
@@ -103,12 +104,12 @@ struct file *anon_inode_getfile(const char *name,d_instantiate (path.dentry, anon_inode_inode); - file =alloc_file (&path,OPEN_FMODE (flags), fops); + file =alloc_file (&path, f_mode |OPEN_FMODE (f_flags), fops);if (IS_ERR (file)) goto err_dput; file->f_mapping = anon_inode_inode->i_mapping; - file->f_flags = flags & (O_ACCMODE |O_NONBLOCK ); + file->f_flags = f_flags & (O_ACCMODE |O_NONBLOCK ); file->private_data = priv;return file;
@@ -129,7 +130,8 @@ EXPORT_SYMBOL_GPL(anon_inode_getfile);* @name: [in] name of the "class" of the new file * @fops: [in] file operations for the new file * @priv: [in] private data for the new file (will be file's private_data) -* @flags: [in] flags +* @f_flags: [in] O_* flags +* @f_mode: [in] FMODE_* flags * * Creates a new file by hooking it on a single inode. This is useful for files * that do not need to have a full-fledged inode in order to operate correctly.
@@ -138,17 +140,17 @@ EXPORT_SYMBOL_GPL(anon_inode_getfile);* setup. Returns new descriptor or an error code. */ int anon_inode_getfd (const char *name,const struct file_operations *fops, -void *priv,int flags) +void *priv,unsigned int f_flags,fmode_t f_mode) {int error, fd;struct file *file; - error =get_unused_fd_flags (flags); + error =get_unused_fd_flags (f_flags);if (error <0 )return error; fd = error; - file =anon_inode_getfile (name, fops, priv, flags); + file =anon_inode_getfile (name, fops, priv, f_flags, f_mode);if (IS_ERR (file)) { error =PTR_ERR (file); goto err_put_unused_fd;
fs/autofs4/dev-ioctl.c +1 -1
@@ -258,7 +258,7 @@ static int autofs_dev_ioctl_open_mountpoint(const char *name, dev_t devid)if (err) goto out; - filp =dentry_open (&path,O_RDONLY ,current_cred ()); + filp =dentry_open (&path,O_RDONLY ,0 ,current_cred ());path_put (&path);if (IS_ERR (filp)) { err =PTR_ERR (filp);
fs/cachefiles/rdwr.c +1 -1
@@ -910,7 +910,7 @@ int cachefiles_write_page(struct fscache_storage *op, struct page *page)* own time */ path.mnt = cache->mnt; path.dentry = object->backer; - file =dentry_open (&path,O_RDWR |O_LARGEFILE , cache->cache_cred); + file =dentry_open (&path,O_RDWR |O_LARGEFILE ,0 , cache->cache_cred);if (IS_ERR (file)) { ret =PTR_ERR (file); goto error_2;
fs/eventfd.c +1 -1
@@ -402,7 +402,7 @@ static int do_eventfd(unsigned int count, int flags) ctx->flags = flags; fd =anon_inode_getfd ("[eventfd]" , &eventfd_fops, ctx, -O_RDWR | (flags &EFD_SHARED_FCNTL_FLAGS )); +O_RDWR | (flags &EFD_SHARED_FCNTL_FLAGS ),0 );if (fd <0 )eventfd_free_ctx (ctx);
fs/eventpoll.c +1 -1
@@ -1963,7 +1963,7 @@ static int do_epoll_create(int flags) goto out_free_ep; } file =anon_inode_getfile ("[eventpoll]" , &eventpoll_fops, ep, -O_RDWR | (flags &O_CLOEXEC )); +O_RDWR | (flags &O_CLOEXEC ),0 );if (IS_ERR (file)) { error =PTR_ERR (file); goto out_free_fd;
fs/exec.c +4 -2
@@ -124,7 +124,8 @@ SYSCALL_DEFINE1(uselib, const char __user *, library)struct filename *tmp =getname (library);int error =PTR_ERR (tmp);static const struct open_flags uselib_flags = { - .open_flag =O_LARGEFILE |O_RDONLY | __FMODE_EXEC, + .open_flag =O_LARGEFILE |O_RDONLY , + .f_mode =FMODE_EXEC , .acc_mode =MAY_READ |MAY_EXEC , .intent =LOOKUP_OPEN , .lookup_flags =LOOKUP_FOLLOW ,
@@ -838,7 +839,8 @@ static struct file *do_open_execat(int fd, struct filename *name, int flags)struct file *file;int err;struct open_flags open_exec_flags = { - .open_flag =O_LARGEFILE |O_RDONLY | __FMODE_EXEC, + .open_flag =O_LARGEFILE |O_RDONLY , + .f_mode =FMODE_EXEC , .acc_mode =MAY_EXEC , .intent =LOOKUP_OPEN , .lookup_flags =LOOKUP_FOLLOW ,
fs/exportfs/expfs.c +1 -1
@@ -308,7 +308,7 @@ static int get_name(const struct path *path, char *name, struct dentry *child)/* * Open the directory ... */ - file =dentry_open (path,O_RDONLY , cred); + file =dentry_open (path,O_RDONLY ,0 , cred); error =PTR_ERR (file);if (IS_ERR (file)) goto out;
fs/fcntl.c +2 -4
@@ -1028,10 +1028,8 @@ static int __init fcntl_init(void)* Exceptions: O_NONBLOCK is a two bit define on parisc; O_NDELAY * is defined as O_NONBLOCK on some platforms and not on others. */ -BUILD_BUG_ON (21 -1 /* for O_RDONLY being 0 */ != -HWEIGHT32 ( - (VALID_OPEN_FLAGS & ~(O_NONBLOCK |O_NDELAY )) | - __FMODE_EXEC | __FMODE_NONOTIFY)); +BUILD_BUG_ON (19 -1 /* for O_RDONLY being 0 */ != +HWEIGHT32 (VALID_OPEN_FLAGS & ~(O_NONBLOCK |O_NDELAY ))); fasync_cache =kmem_cache_create ("fasync_cache" ,sizeof (struct fasync_struct ),0 ,SLAB_PANIC ,NULL );
fs/internal.h +1 -0
@@ -110,6 +110,7 @@ struct open_flags {int open_flag;umode_t mode;int acc_mode; +fmode_t f_mode;int intent;int lookup_flags; };
fs/namei.c +1 -0
@@ -3481,6 +3481,7 @@ static struct file *path_openat(struct nameidata *nd,return file; file->f_flags = op->open_flag; + file->f_mode = op->f_mode;if (unlikely (file->f_flags & __O_TMPFILE)) { error =do_tmpfile (nd, flags, op, file, &opened);
fs/namespace.c +1 -1
@@ -3309,7 +3309,7 @@ SYSCALL_DEFINE5(fsmount, int, fs_fd, unsigned int, flags, unsigned int, ms_flags/* Attach to an apparent O_PATH fd with a note that we need to unmount * it, not just simply put it. */ - file =dentry_open (&newmount,O_PATH , fc->cred); + file =dentry_open (&newmount,O_PATH ,0 , fc->cred);if (IS_ERR (file)) goto err_path; file->f_mode |=FMODE_NEED_UNMOUNT ;
fs/nfs/dir.c +8 -7
@@ -1395,9 +1395,9 @@ const struct dentry_operations nfs4_dentry_operations = { };EXPORT_SYMBOL_GPL (nfs4_dentry_operations); -static fmode_t flags_to_mode (int flags) +static fmode_t flags_to_mode (int flags,fmode_t f_mode) { -fmode_t res = (__force fmode_t )flags &FMODE_EXEC ; +fmode_t res = f_mode &FMODE_EXEC ;if ((flags &O_ACCMODE ) !=O_WRONLY ) res |=FMODE_READ ;if ((flags &O_ACCMODE ) !=O_RDONLY )
@@ -1407,7 +1407,7 @@ static fmode_t flags_to_mode(int flags)static struct nfs_open_context *create_nfs_open_context (struct dentry *dentry,int open_flags,struct file *filp) { -return alloc_nfs_open_context (dentry,flags_to_mode (open_flags), filp); +return alloc_nfs_open_context (dentry,flags_to_mode (open_flags, filp->f_mode), filp); }static int do_open (struct inode *inode,struct file *filp)
@@ -2441,11 +2441,11 @@ static int nfs_do_access(struct inode *inode, struct rpc_cred *cred, int mask)return status; } -static int nfs_open_permission_mask (int openflags) +static int nfs_open_permission_mask (fmode_t f_mode,int openflags) {int mask =0 ; -if (openflags & __FMODE_EXEC) { +if (f_mode &FMODE_EXEC ) {/* ONLY check exec rights */ mask =MAY_EXEC ; }else {
@@ -2458,9 +2458,10 @@ static int nfs_open_permission_mask(int openflags)return mask; } -int nfs_may_open (struct inode *inode,struct rpc_cred *cred,int openflags) +int nfs_may_open (struct inode *inode,struct rpc_cred *cred,fmode_t f_mode, +int openflags) { -return nfs_do_access (inode, cred,nfs_open_permission_mask (openflags)); +return nfs_do_access (inode, cred,nfs_open_permission_mask (f_mode, openflags)); }EXPORT_SYMBOL_GPL (nfs_may_open);
fs/nfs/nfs4proc.c +3 -6
@@ -1712,7 +1712,8 @@ static struct nfs4_state *nfs4_try_open_cached(struct nfs4_opendata *opendata)rcu_read_unlock ();nfs_release_seqid (opendata->o_arg.seqid);if (!opendata->is_recover) { - ret =nfs_may_open (state->inode, state->owner->so_cred, open_mode); + ret =nfs_may_open (state->inode, state->owner->so_cred, + fmode, open_mode);if (ret !=0 ) goto out; }
@@ -2414,11 +2415,7 @@ static int nfs4_opendata_access(struct rpc_cred *cred,return 0 ; mask =0 ; -/* -* Use openflags to check for exec, because fmode won't -* always have FMODE_EXEC set when file open for exec. -*/ -if (openflags & __FMODE_EXEC) { +if (fmode &FMODE_EXEC ) {/* ONLY check for exec rights */ if (S_ISDIR (state->inode->i_mode)) mask =NFS4_ACCESS_LOOKUP ;
fs/notify/fanotify/fanotify_user.c +6 -4
@@ -32,7 +32,7 @@* * Internal and external open flags are stored together in field f_flags of * struct file. Only external open flags shall be allowed in event_f_flags. -* Internal flags like FMODE_NONOTIFY, FMODE_EXEC, FMODE_NOCMTIME shall be +* Internal flags like FMODE_DONT_NOTIFY, FMODE_EXEC, FMODE_NOCMTIME shall be * excluded. */ #define FANOTIFY_INIT_ALL_EVENT_F_BITS ( \
@@ -92,7 +92,8 @@ static int create_fd(struct fsnotify_group *group,* are NULL; That's fine, just don't call dentry open */ if (event->path.dentry && event->path.mnt) new_file =dentry_open (&event->path, - group->fanotify_data.f_flags |FMODE_NONOTIFY , + group->fanotify_data.f_flags, +FMODE_DONT_NOTIFY ,current_cred ());else new_file =ERR_PTR (-EOVERFLOW );
@@ -741,7 +742,7 @@ SYSCALL_DEFINE2(fanotify_init, unsigned int, flags, unsigned int, event_f_flags)return -EMFILE ; } - f_flags =O_RDWR |FMODE_NONOTIFY ; + f_flags =O_RDWR ;if (flags &FAN_CLOEXEC ) f_flags |=O_CLOEXEC ;if (flags &FAN_NONBLOCK )
@@ -809,7 +810,8 @@ SYSCALL_DEFINE2(fanotify_init, unsigned int, flags, unsigned int, event_f_flags) group->fanotify_data.audit = true; } - fd =anon_inode_getfd ("[fanotify]" , &fanotify_fops, group, f_flags); + fd =anon_inode_getfd ("[fanotify]" , &fanotify_fops, group, f_flags, +FMODE_DONT_NOTIFY );if (fd <0 ) goto out_destroy_group;
fs/notify/inotify/inotify_user.c +1 -1
@@ -667,7 +667,7 @@ static int do_inotify_init(int flags)return PTR_ERR (group); ret =anon_inode_getfd ("inotify" , &inotify_fops, group, -O_RDONLY | flags); +O_RDONLY | flags,0 );if (ret <0 )fsnotify_destroy_group (group);
fs/nsfs.c +1 -1
@@ -174,7 +174,7 @@ int open_related_ns(struct ns_common *ns,return PTR_ERR (err); } - f =dentry_open (&path,O_RDONLY ,current_cred ()); + f =dentry_open (&path,O_RDONLY ,0 ,current_cred ());path_put (&path);if (IS_ERR (f)) {put_unused_fd (fd);
fs/open.c +16 -8
@@ -34,6 +34,13 @@#include "internal.h" +const u8 acc_mode[O_ACCMODE +1 ] = { + [O_RDONLY ] =MAY_READ , + [O_WRONLY ] =MAY_WRITE , + [O_RDWR ] =MAY_READ |MAY_WRITE , + [3 ] =MAY_READ |MAY_WRITE , +}; +int do_truncate (struct dentry *dentry,loff_t length,unsigned int time_attrs,struct file *filp) {
@@ -732,9 +739,6 @@ static int do_dentry_open(struct file *f,static const struct file_operations empty_fops = {};int error; - f->f_mode =OPEN_FMODE (f->f_flags) |FMODE_LSEEK | -FMODE_PREAD |FMODE_PWRITE ; -path_get (&f->f_path); f->f_inode = inode; f->f_mapping = inode->i_mapping;
@@ -743,11 +747,14 @@ static int do_dentry_open(struct file *f, f->f_wb_err =filemap_sample_wb_err (f->f_mapping);if (unlikely (f->f_flags &O_PATH )) { - f->f_mode =FMODE_PATH ; + f->f_mode |=FMODE_PATH ; f->f_op = &empty_fops; goto done; } + f->f_mode |=OPEN_FMODE (f->f_flags) |FMODE_LSEEK | +FMODE_PREAD |FMODE_PWRITE ; +if (f->f_mode &FMODE_WRITE && !special_file (inode->i_mode)) { error =get_write_access (inode);if (unlikely (error))
@@ -906,8 +913,8 @@ int vfs_open(const struct path *path, struct file *file,return do_dentry_open (file,d_backing_inode (dentry),NULL , cred); } -struct file *dentry_open (const struct path *path,int flags, -const struct cred *cred) +struct file *dentry_open (const struct path *path,unsigned int flags, +fmode_t f_mode,const struct cred *cred) {int error;struct file *f;
@@ -941,14 +948,15 @@ static inline int build_open_flags(int flags, umode_t mode, struct open_flags *o* them in fcntl(F_GETFD) or similar interfaces. */ flags &=VALID_OPEN_FLAGS ; + op->f_mode =0 ;if (flags & (O_CREAT | __O_TMPFILE)) op->mode = (mode &S_IALLUGO ) |S_IFREG ;else op->mode =0 ; -/* Must never be set by userspace */ - flags &= ~FMODE_NONOTIFY & ~O_CLOEXEC ; +/* Don't leak O_CLOEXEC into ->f_flags */ + flags &= ~O_CLOEXEC ;/* * O_SYNC is implemented as __O_SYNC|O_DSYNC. As many places only
fs/signalfd.c +2 -1
@@ -287,7 +287,8 @@ static int do_signalfd4(int ufd, sigset_t __user *user_mask, size_t sizemask,* anon_inode_getfd() will install the fd. */ ufd =anon_inode_getfd ("[signalfd]" , &signalfd_fops, ctx, -O_RDWR | (flags & (O_CLOEXEC |O_NONBLOCK ))); +O_RDWR | (flags & (O_CLOEXEC |O_NONBLOCK )), +0 );if (ufd <0 )kfree (ctx); }else {
fs/timerfd.c +1 -1
@@ -425,7 +425,7 @@ SYSCALL_DEFINE2(timerfd_create, int, clockid, int, flags) ctx->moffs =ktime_mono_to_real (0 ); ufd =anon_inode_getfd ("[timerfd]" , &timerfd_fops, ctx, -O_RDWR | (flags &TFD_SHARED_FCNTL_FLAGS )); +O_RDWR | (flags &TFD_SHARED_FCNTL_FLAGS ),0 );if (ufd <0 )kfree (ctx);
fs/xfs/xfs_ioctl.c +1 -1
@@ -255,7 +255,7 @@ xfs_open_by_handle( path.mnt = parfilp->f_path.mnt; path.dentry = dentry; - filp =dentry_open (&path, hreq->oflags, cred); + filp =dentry_open (&path, hreq->oflags,0 , cred);dput (dentry);if (IS_ERR (filp)) {put_unused_fd (fd);
include/linux/anon_inodes.h +3 -3
@@ -12,10 +12,10 @@struct file_operations ;struct file *anon_inode_getfile (const char *name, -const struct file_operations *fops, -void *priv,int flags); +const struct file_operations *fops,void *priv, +unsigned int f_flags,fmode_t f_mode);int anon_inode_getfd (const char *name,const struct file_operations *fops, -void *priv,int flags); +void *priv,unsigned int f_flags,fmode_t f_mode);#endif /* _LINUX_ANON_INODES_H */
include/linux/fs.h +19 -7
@@ -149,7 +149,7 @@ typedef int (dio_iodone_t)(struct kiocb *iocb, loff_t offset,#define FMODE_CAN_WRITE ((__force fmode_t)0x40000)/* File was opened by fanotify and shouldn't generate fanotify events */ -#define FMODE_NONOTIFY ((__force fmode_t)0x4000000) +#define FMODE_DONT_NOTIFY ((__force fmode_t)0x4000000)/* File is capable of returning -EAGAIN if I/O will block */ #define FMODE_NOWAIT ((__force fmode_t)0x8000000)
@@ -2413,7 +2413,8 @@ 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 *,const char *,int ,umode_t ); -extern struct file *dentry_open (const struct path *,int ,const struct cred *); +extern struct file *dentry_open (const struct path *,unsigned int ,fmode_t , +const struct cred *);extern int filp_close (struct file *,fl_owner_t id);extern struct filename *getname_flags (const char __user *,int ,int *);
@@ -3349,12 +3350,23 @@ int proc_nr_inodes(struct ctl_table *table, int write, void __user *buffer, size_t *lenp, loff_t *ppos);int __init get_filesystem_list (char *buf); -#define __FMODE_EXEC ((__force int) FMODE_EXEC) -#define __FMODE_NONOTIFY ((__force int) FMODE_NONOTIFY) +extern const u8 acc_mode[O_ACCMODE +1 ]; -#define ACC_MODE (x) ("\004\002\006\006"[(x)&O_ACCMODE]) -#define OPEN_FMODE (flag) ((__force fmode_t)(((flag + 1) & O_ACCMODE) | \ - (flag & __FMODE_NONOTIFY))) +/* +* Turn { O_RDONLY, O_WRONLY, O_RDWD, 3 } into MAY_READ and/or MAY_WRITE +*/ +static inline unsigned int ACC_MODE (int x) +{ +return acc_mode[(x) &O_ACCMODE ]; +} + +/* +* Turn { O_RDONLY, O_WRONLY, O_RDWD, 3 } into FMODE_READ and/or FMODE_WRITE +*/ +static inline fmode_t OPEN_FMODE (unsigned int O_flags) +{ +return (__force fmode_t)((O_flags +1 ) &O_ACCMODE ); +}static inline bool is_sxid (umode_t mode) {
include/linux/fsnotify.h +4 -4
@@ -38,7 +38,7 @@ static inline int fsnotify_perm(struct file *file, int mask)__u32 fsnotify_mask =0 ;int ret; -if (file->f_mode &FMODE_NONOTIFY ) +if (file->f_mode &FMODE_DONT_NOTIFY )return 0 ;if (!(mask & (MAY_READ |MAY_OPEN )))return 0 ;
@@ -184,7 +184,7 @@ static inline void fsnotify_access(struct file *file)if (S_ISDIR (inode->i_mode)) mask |=FS_ISDIR ; -if (!(file->f_mode &FMODE_NONOTIFY )) { +if (!(file->f_mode &FMODE_DONT_NOTIFY )) {fsnotify_parent (path,NULL , mask);fsnotify (inode, mask, path,FSNOTIFY_EVENT_PATH ,NULL ,0 ); }
@@ -202,7 +202,7 @@ static inline void fsnotify_modify(struct file *file)if (S_ISDIR (inode->i_mode)) mask |=FS_ISDIR ; -if (!(file->f_mode &FMODE_NONOTIFY )) { +if (!(file->f_mode &FMODE_DONT_NOTIFY )) {fsnotify_parent (path,NULL , mask);fsnotify (inode, mask, path,FSNOTIFY_EVENT_PATH ,NULL ,0 ); }
@@ -237,7 +237,7 @@ static inline void fsnotify_close(struct file *file)if (S_ISDIR (inode->i_mode)) mask |=FS_ISDIR ; -if (!(file->f_mode &FMODE_NONOTIFY )) { +if (!(file->f_mode &FMODE_DONT_NOTIFY )) {fsnotify_parent (path,NULL , mask);fsnotify (inode, mask, path,FSNOTIFY_EVENT_PATH ,NULL ,0 ); }
include/linux/nfs_fs.h +2 -1
@@ -477,7 +477,8 @@ extern const struct dentry_operations nfs_dentry_operations;extern void nfs_force_lookup_revalidate (struct inode *dir);extern int nfs_instantiate (struct dentry *dentry,struct nfs_fh *fh,struct nfs_fattr *fattr,struct nfs4_label *label); -extern int nfs_may_open (struct inode *inode,struct rpc_cred *cred,int openflags); +extern int nfs_may_open (struct inode *inode,struct rpc_cred *cred, +fmode_t mode,int openflags);extern void nfs_access_zap_cache (struct inode *inode);/*
include/uapi/asm-generic/fcntl.h +0 -1
@@ -6,7 +6,6 @@/* * FMODE_EXEC is 0x20 -* FMODE_NONOTIFY is 0x4000000 * These cannot be used by userspace O_* until internal and external open * flags are split. * -Eric Paris
ipc/mqueue.c +2 -4
@@ -791,8 +791,6 @@ static int prepare_open(struct dentry *dentry, int oflag, int ro, umode_t mode, struct filename *name, struct mq_attr *attr) { - static const int oflag2acc[O_ACCMODE] = { MAY_READ, MAY_WRITE, -MAY_READ |MAY_WRITE }; int acc;if (d_really_is_negative (dentry)) {
@@ -810,7 +808,7 @@ static int prepare_open(struct dentry *dentry, int oflag, int ro,return -EEXIST ;if ((oflag &O_ACCMODE ) == (O_RDWR |O_WRONLY ))return -EINVAL ; - acc = oflag2acc[oflag &O_ACCMODE ]; + acc =ACC_MODE (oflag);return inode_permission (d_inode (dentry), acc); }
@@ -843,7 +841,7 @@ static int do_mq_open(const char __user *u_name, int oflag, umode_t mode, path.mnt =mntget (mnt); error =prepare_open (path.dentry, oflag, ro, mode, name, attr);if (!error) { -struct file *file =dentry_open (&path, oflag,current_cred ()); +struct file *file =dentry_open (&path, oflag,0 ,current_cred ());if (!IS_ERR (file))fd_install (fd, file);else
kernel/bpf/syscall.c +3 -3
@@ -373,7 +373,7 @@ int bpf_map_new_fd(struct bpf_map *map, int flags)return ret;return anon_inode_getfd ("bpf-map" , &bpf_map_fops, map, - flags |O_CLOEXEC ); + flags |O_CLOEXEC ,0 ); }int bpf_get_file_flag (int flags)
@@ -1068,7 +1068,7 @@ int bpf_prog_new_fd(struct bpf_prog *prog)return ret;return anon_inode_getfd ("bpf-prog" , &bpf_prog_fops, prog, -O_RDWR |O_CLOEXEC ); +O_RDWR |O_CLOEXEC ,0 ); }static struct bpf_prog *____bpf_prog_get (struct fd f)
@@ -1445,7 +1445,7 @@ static int bpf_raw_tracepoint_open(const union bpf_attr *attr) raw_tp->prog = prog; tp_fd =anon_inode_getfd ("bpf-raw-tracepoint" , &bpf_raw_tp_fops, raw_tp, -O_CLOEXEC ); +O_CLOEXEC ,0 );if (tp_fd <0 ) {bpf_probe_unregister (raw_tp->btp, prog); err = tp_fd;
kernel/events/core.c +1 -1
@@ -10612,7 +10612,7 @@ SYSCALL_DEFINE5(perf_event_open, } event_file =anon_inode_getfile ("[perf_event]" , &perf_fops, event, - f_flags); + f_flags,0 );if (IS_ERR (event_file)) { err =PTR_ERR (event_file); event_file =NULL ;
net/unix/af_unix.c +1 -1
@@ -2588,7 +2588,7 @@ static int unix_open_file(struct sock *sk)if (fd <0 ) goto out; - f =dentry_open (&path,O_PATH ,current_cred ()); + f =dentry_open (&path,O_PATH ,0 ,current_cred ());if (IS_ERR (f)) {put_unused_fd (fd); fd =PTR_ERR (f);
security/apparmor/file.c +1 -1
@@ -692,7 +692,7 @@ void aa_inherit_files(const struct cred *cred, struct files_struct *files)if (!n)/* none found? */ goto out; - devnull =dentry_open (&aa_null,O_RDWR , cred); + devnull =dentry_open (&aa_null,O_RDWR ,0 , cred);if (IS_ERR (devnull)) devnull =NULL ;/* replace all the matching ones with this */
security/keys/big_key.c +1 -1
@@ -374,7 +374,7 @@ long big_key_read(const struct key *key, char __user *buffer, size_t buflen)if (!buf)return -ENOMEM ; - file =dentry_open (path,O_RDONLY ,current_cred ()); + file =dentry_open (path,O_RDONLY ,0 ,current_cred ());if (IS_ERR (file)) { ret =PTR_ERR (file); goto error;
security/selinux/hooks.c +1 -1
@@ -2625,7 +2625,7 @@ static inline void flush_unauthorized_files(const struct cred *cred,if (!n)/* none found? */ return ; - devnull =dentry_open (&selinux_null,O_RDWR , cred); + devnull =dentry_open (&selinux_null,O_RDWR ,0 , cred);if (IS_ERR (devnull)) devnull =NULL ;/* replace all the matching ones with this */
David Howells
maintainerPATCH 30/32 vfs: Allow cloning of a mount tree with open(O_PATH|O_CLONE_MOUNT) [ver #8]
In reply to David HowellsMake it possible to clone a mount tree with a new pair of open flags that are used in conjunction with O_PATH:
(1) O_CLONE_MOUNT - Clone the mount or mount tree at the path.
(2) O_NON_RECURSIVE - Don't clone recursively.
Note that it's not a good idea to reuse other flags (such as O_CREAT) because the open routine for O_PATH does not give an error if any other flags are used in conjunction with O_PATH, but rather just masks off any it doesn't use.
The resultant file struct is marked FMODE_NEED_UNMOUNT to as it pins an extra reference for the mount. This will be cleared by the upcoming move_mount() syscall when it successfully moves a cloned mount into the filesystem tree.
Note that care needs to be taken with the error handling in do_o_path() in the case that vfs_open() fails as the path may or may not have been attached to the file struct and FMODE_NEED_UNMOUNT may or may not be set. Note that O_DIRECT | O_PATH could be a problem with error handling too.
---
fs/fcntl.c | 2 +- fs/internal.h | 1 + fs/namei.c | 26 ++++++++++++++++++---- fs/namespace.c | 44 ++++++++++++++++++++++++++++++++++++++ fs/open.c | 7 +++++- include/linux/fcntl.h | 3 ++- include/uapi/asm-generic/fcntl.h | 8 +++++++ 7 files changed, 83 insertions(+), 8 deletions(-)
fs/fcntl.c +1 -1
@@ -1028,7 +1028,7 @@ static int __init fcntl_init(void)* Exceptions: O_NONBLOCK is a two bit define on parisc; O_NDELAY * is defined as O_NONBLOCK on some platforms and not on others. */ -BUILD_BUG_ON (19 -1 /* for O_RDONLY being 0 */ != +BUILD_BUG_ON (20 -1 /* for O_RDONLY being 0 */ !=HWEIGHT32 (VALID_OPEN_FLAGS & ~(O_NONBLOCK |O_NDELAY ))); fasync_cache = kmem_cache_create("fasync_cache",
fs/internal.h +1 -0
@@ -75,6 +75,7 @@ extern struct vfsmount *lookup_mnt(const struct path *);extern int finish_automount (struct vfsmount *,struct path *);extern int sb_prepare_remount_readonly (struct super_block *); +extern int copy_mount_for_o_path (struct path *,struct path *,bool );extern void __init mnt_init (void );
fs/namei.c +21 -5
@@ -3458,13 +3458,29 @@ static int do_tmpfile(struct nameidata *nd, unsigned flags,static int do_o_path (struct nameidata *nd,unsigned flags,struct file *file) { -struct path path; -int error =path_lookupat (nd, flags, &path); -if (!error) { -audit_inode (nd->name, path.dentry,0 ); - error =vfs_open (&path, file,current_cred ()); +struct path path, tmp; +int error; + + error =path_lookupat (nd, flags, &path); +if (error) +return error; + +if (file->f_flags &O_CLONE_MOUNT ) { + error =copy_mount_for_o_path ( + &path, &tmp, !(file->f_flags &O_NON_RECURSIVE ));path_put (&path); +if (error <0 ) +return error; + path = tmp; } + +audit_inode (nd->name, path.dentry,0 ); + error =vfs_open (&path, file,current_cred ()); +if (error <0 && + (flags &O_CLONE_MOUNT ) && + !(file->f_mode &FMODE_NEED_UNMOUNT )) +__detach_mounts (path.dentry); +path_put (&path);return error; }
fs/namespace.c +44 -0
50 lines not on this page · raw message
fs/open.c +6 -1
@@ -748,6 +748,8 @@ static int do_dentry_open(struct file *f,if (unlikely (f->f_flags &O_PATH )) { f->f_mode |=FMODE_PATH ; +if (f->f_flags &O_CLONE_MOUNT ) + f->f_mode |=FMODE_NEED_UNMOUNT ; f->f_op = &empty_fops; goto done; }
@@ -977,8 +979,11 @@ static inline int build_open_flags(int flags, umode_t mode, struct open_flags *o* If we have O_PATH in the open flag. Then we * cannot have anything other than the below set of flags */ - flags &=O_DIRECTORY |O_NOFOLLOW |O_PATH ; + flags &= (O_DIRECTORY |O_NOFOLLOW |O_PATH | +O_CLONE_MOUNT |O_NON_RECURSIVE ); acc_mode =0 ; + }else if (flags & (O_CLONE_MOUNT |O_NON_RECURSIVE )) { +return -EINVAL ; } op->open_flag = flags;
include/linux/fcntl.h +2 -1
@@ -9,7 +9,8 @@ (O_RDONLY |O_WRONLY |O_RDWR |O_CREAT |O_EXCL |O_NOCTTY |O_TRUNC | \O_APPEND |O_NDELAY |O_NONBLOCK |O_NDELAY | __O_SYNC |O_DSYNC | \FASYNC |O_DIRECT |O_LARGEFILE |O_DIRECTORY |O_NOFOLLOW | \ - O_NOATIME | O_CLOEXEC | O_PATH | __O_TMPFILE) +O_NOATIME |O_CLOEXEC |O_PATH | __O_TMPFILE | \ + O_CLONE_MOUNT | O_NON_RECURSIVE)#ifndef force_o_largefile#define force_o_largefile () (BITS_PER_LONG != 32)
include/uapi/asm-generic/fcntl.h +8 -0
@@ -88,6 +88,14 @@#define __O_TMPFILE 020000000#endif +#ifndef O_CLONE_MOUNT +#define O_CLONE_MOUNT 040000000/* Used with O_PATH to clone the mount subtree at path */ +#endif + +#ifndef O_NON_RECURSIVE +#define O_NON_RECURSIVE 0100000000/* Used with O_CLONE_MOUNT to only clone one mount */ +#endif +/* a horrid kludge trying to make sure that this will fail on old kernels */ #define O_TMPFILE (__O_TMPFILE | O_DIRECTORY)#define O_TMPFILE_MASK (__O_TMPFILE | O_DIRECTORY | O_CREAT)
Re: [PATCH 30/32] vfs: Allow cloning of a mount tree with open(O_PATH|O_CLONE_MOUNT) [ver #8]
Quoted 6 lines · David Howells
Make it possible to clone a mount tree with a new pair of open flags that are used in conjunction with
O_PATH:(1)
O_CLONE_MOUNT- Clone the mount or mount tree at the path.(2)
O_NON_RECURSIVE- Don't clone recursively.
Err. I don't think we should use up two O_* flags for something only useful for your new mount API. Don't we have a better place to for these flags?
Instead of overloading this on open having a specific syscalls just seems like a much saner idea.
Al Viro
maintainerRe: [PATCH 30/32] vfs: Allow cloning of a mount tree with open(O_PATH|O_CLONE_MOUNT) [ver #8]
Quoted 6 lines · Christoph Hellwig
Quoted 5 lines · David Howells
Make it possible to clone a mount tree with a new pair of open flags that are used in conjunction with
O_PATH:(1)
O_CLONE_MOUNT- Clone the mount or mount tree at the path.
Quoted 8 lines
Quoted 1 line
(2)
O_NON_RECURSIVE- Don't clone recursively.Err. I don't think we should use up two O_* flags for something only useful for your new mount API. Don't we have a better place to for these flags?
Instead of overloading this on open having a specific syscalls just seems like a much saner idea.
It's not just mount API; these can be used independently of that. Think of the uses where you pass those to ...at() and you'll see a bunch of applications of that thing.
David Howells
maintainerRe: [PATCH 30/32] vfs: Allow cloning of a mount tree with open(O_PATH|O_CLONE_MOUNT) [ver #8]
Quoted 6 lines · Al Viro
Quoted 2 lines
Instead of overloading this on open having a specific syscalls just seems like a much saner idea.
It's not just mount API; these can be used independently of that. Think of the uses where you pass those to ...at() and you'll see a bunch of applications of that thing.
I kind of agree with Christoph on this point. Yes, you can use the resultant fd for other things, but that doesn't mean it has to be obtained initially through open() or openat() rather than, say, a new pick_mount() syscall.
Further, having more parameters available gives us the opportunity to change the settings on any mounts we create at the point of creation.
David
Al Viro
maintainerRe: [PATCH 30/32] vfs: Allow cloning of a mount tree with open(O_PATH|O_CLONE_MOUNT) [ver #8]
Quoted 9 lines · David Howells
Quoted 6 lines · Al Viro
Quoted 2 lines
Instead of overloading this on open having a specific syscalls just seems like a much saner idea.
It's not just mount API; these can be used independently of that. Think of the uses where you pass those to ...at() and you'll see a bunch of applications of that thing.
Quoted 6 lines
I kind of agree with Christoph on this point. Yes, you can use the resultant fd for other things, but that doesn't mean it has to be obtained initially through
open()oropenat()rather than, say, a newpick_mount()syscall.Further, having more parameters available gives us the opportunity to change the settings on any mounts we create at the point of creation.
open_subtree(int dirfd, const char *pathname, int flags), then? How would flags be interpreted? What I see mapping at that thing is
* equivalent of O_PATH open
* clone subtree, O_PATH open root
* clone one mount, O_PATH open root
and apparently you want to add (orthogonal to that)
* make shared/slave/private/unbindable
* ditto with recursion?
* same for nodev/nosuid/noexec/noatime/nodiratime/relatime/ro/?
as well as usual AT_... flags (empty path, follow)
Choose the encoding...
Al Viro
maintainerRe: [PATCH 30/32] vfs: Allow cloning of a mount tree with open(O_PATH|O_CLONE_MOUNT) [ver #8]
Quoted 28 lines · Al Viro
Quoted 9 lines · David Howells
Quoted 6 lines · Al Viro
Quoted 2 lines
Instead of overloading this on open having a specific syscalls just seems like a much saner idea.
It's not just mount API; these can be used independently of that. Think of the uses where you pass those to ...at() and you'll see a bunch of applications of that thing.
Quoted 6 lines
I kind of agree with Christoph on this point. Yes, you can use the resultant fd for other things, but that doesn't mean it has to be obtained initially through
open()oropenat()rather than, say, a newpick_mount()syscall.Further, having more parameters available gives us the opportunity to change the settings on any mounts we create at the point of creation.
open_subtree(int dirfd, const char *pathname, int flags), then? How would flags be interpreted? What I see mapping at that thing is
* equivalent ofO_PATHopen
* clone subtree,O_PATHopen root
* clone one mount,O_PATHopen root
and apparently you want to add (orthogonal to that)
* make shared/slave/private/unbindable
* ditto with recursion?
* same for nodev/nosuid/noexec/noatime/nodiratime/relatime/ro/?
as well as usualAT_... flags (empty path, follow)
Quoted 1 line
Choose the encoding...
_If_ I'm interpreting that correctly, that should be something like a bitmap of attributes to modify + values to set for each. Let's see -
propagation 1 + 2 bits nodev 1 + 1 noexec 1 + 1 nosuid 1 + 1 ro 1 + 1 atime 1 + 3
That's 15 bits. On top of that, we have 1 bit for "clone or original" and 1 bit for "recursive or single-mount". As well as AT_EMPTY_PATH, and AT_NO_AUTOMOUNT (inconvenient, since these are fixed bits). In principle, that does fit into int, with some space to spare...
Is that what you have in mind?
Al Viro
maintainerRe: [PATCH 30/32] vfs: Allow cloning of a mount tree with open(O_PATH|O_CLONE_MOUNT) [ver #8]
Quoted 8 lines · Al Viro
_If_ I'm interpreting that correctly, that should be something like a bitmap of attributes to modify + values to set for each. Let's see -
propagation 1 + 2 bits nodev 1 + 1 noexec 1 + 1 nosuid 1 + 1 ro 1 + 1 atime 1 + 3
Quoted 6 lines
That's 15 bits. On top of that, we have 1 bit for "clone or original" and 1 bit for "recursive or single-mount". As well as
AT_EMPTY_PATH, andAT_NO_AUTOMOUNT(inconvenient, since these are fixed bits). In principle, that does fit into int, with some space to spare...Is that what you have in mind?
TBH, I would probably prefer separate mount_setattr(2) for that kind of work, with something like
int mount_setattr(int dirfd, const char *path, int flags, int attr)
*not* opening any files.
flags:
AT_EMPTY_PATH, AT_NO_AUTOMOUNT, AT_RECURSIVE
attr:
MOUNT_SETATTR_DEV (1<<0) MOUNT_SETATTR_NODEV (1<<0)|(1<<1) MOUNT_SETATTR_EXEC (1<<2) MOUNT_SETATTR_NOEXEC (1<<2)|(1<<3) MOUNT_SETATTR_SUID (1<<4) MOUNT_SETATTR_NOSUID (1<<4)|(1<<5) MOUNT_SETATTR_RW (1<<6) MOUNT_SETATTR_RO (1<<6)|(1<<7) MOUNT_SETATTR_RELATIME (1<<8) MOUNT_SETATTR_NOATIME (1<<8)|(1<<9) MOUNT_SETATTR_NODIRATIME (1<<8)|(2<<9) MOUNT_SETATTR_STRICTATIME (1<<8)|(3<<9) MOUNT_SETATTR_PRIVATE (1<<11) MOUNT_SETATTR_SHARED (1<<11)|(1<<12) MOUNT_SETATTR_SLAVE (1<<11)|(2<<12) MOUNT_SETATTR_UNBINDABLE (1<<11)|(3<<12)
With either openat() used as in this series, or explicit
int open_tree(int dirfd, const char *path, int flags)
returning a descriptor, with flags being
AT_EMPTY_PATH, AT_NO_AUTOMOUNT, AT_RECURSIVE, AT_CLONE
with AT_RECURSIVE without AT_CLONE being an error. Hell, might even add AT_UMOUNT for "open root and detach, to be dissolved on close", incompatible with AT_CLONE.
Comments?
David Howells
maintainerRe: [PATCH 30/32] vfs: Allow cloning of a mount tree with open(O_PATH|O_CLONE_MOUNT) [ver #8]
Quoted 6 lines · Al Viro
TBH, I would probably prefer separate
mount_setattr(2)for that kind of work, with something like
intmount_setattr(int dirfd, const char *path, int flags, int attr)
*not* opening any files.
flags:
AT_EMPTY_PATH,AT_NO_AUTOMOUNT,AT_RECURSIVE
I would call these MOUNT_SETATTR_* rather than AT_*.
Quoted 17 lines
attr:
MOUNT_SETATTR_DEV (1<<0) MOUNT_SETATTR_NODEV (1<<0)|(1<<1) MOUNT_SETATTR_EXEC (1<<2) MOUNT_SETATTR_NOEXEC (1<<2)|(1<<3) MOUNT_SETATTR_SUID (1<<4) MOUNT_SETATTR_NOSUID (1<<4)|(1<<5) MOUNT_SETATTR_RW (1<<6) MOUNT_SETATTR_RO (1<<6)|(1<<7) MOUNT_SETATTR_RELATIME (1<<8) MOUNT_SETATTR_NOATIME (1<<8)|(1<<9) MOUNT_SETATTR_NODIRATIME (1<<8)|(2<<9) MOUNT_SETATTR_STRICTATIME (1<<8)|(3<<9) MOUNT_SETATTR_PRIVATE (1<<11) MOUNT_SETATTR_SHARED (1<<11)|(1<<12) MOUNT_SETATTR_SLAVE (1<<11)|(2<<12) MOUNT_SETATTR_UNBINDABLE (1<<11)|(3<<12)
So, I like this generally, some notes though:
I wonder if this should be two separate parameters, a mask and the settings? I'm not sure that's worth it since some of the mask bits would cover multiple settings.
Also, should NODIRATIME be separate from the other *ATIME flags? I do also like treating some of these settings as enumerations rather than a set of bits.
I would make the prototype:
int mount_setattr(int dirfd, const char *path,
unsigned int flags, unsigned int attr, void *reserved5);
Further, do we want to say you can either change the propagation type *or* reconfigure the mountpoint restrictions, but not both at the same time?
Quoted 2 lines
With either
openat()used as in this series, or explicit
intopen_tree(int dirfd, const char *path, int flags)
Maybe open_mount(), grab_mount() or pick_mount()?
I wonder if fsopen()/fspick() should be create_fs()/open_fs()...
Quoted 3 lines
returning a descriptor, with flags being
AT_EMPTY_PATH,AT_NO_AUTOMOUNT,AT_RECURSIVE,AT_CLONE
withAT_RECURSIVEwithoutAT_CLONEbeing an error.
You also need an O_CLOEXEC equivalent.
I would make it:
OPEN_TREE_CLOEXEC 0x00000001 OPEN_TREE_EMPTY_PATH 0x00000002 OPEN_TREE_FOLLOW_SYMLINK 0x00000004 OPEN_TREE_NO_AUTOMOUNT 0x00000008 OPEN_TREE_CLONE 0x00000010 OPEN_TREE_RECURSIVE 0x00000020
adding the follow-symlinks so that you don't grab a symlink target by accident. (Can you actually mount on top of a symlink?)
Quoted 2 lines
Hell, might even add
AT_UMOUNTfor "open root and detach, to be dissolved on close", incompatible withAT_CLONE.
Cute. Guess you could do:
fd = open_mount(..., OPEN_TREE_DETACH); mount_setattr(fd, "", MOUNT_SETATTR_EMPTY_PATH, MOUNT_SETATTR_NOSUID, NULL); move_mount(fd, "", ...);
David
Al Viro
maintainerRe: [PATCH 30/32] vfs: Allow cloning of a mount tree with open(O_PATH|O_CLONE_MOUNT) [ver #8]
Quoted 10 lines · David Howells
Quoted 6 lines · Al Viro
TBH, I would probably prefer separate
mount_setattr(2)for that kind of work, with something like
intmount_setattr(int dirfd, const char *path, int flags, int attr)
*not* opening any files.
flags:
AT_EMPTY_PATH,AT_NO_AUTOMOUNT,AT_RECURSIVEI would call these MOUNT_SETATTR_* rather than AT_*.
Why? AT_EMPTY_PATH/AT_NO_AUTOMOUNT are common with other ...at() syscalls; AT_RECURSIVE - maybe, but it's still more like AT_... namespace fodder, IMO.
Quoted 18 lines
Quoted 17 lines
attr:
MOUNT_SETATTR_DEV (1<<0) MOUNT_SETATTR_NODEV (1<<0)|(1<<1) MOUNT_SETATTR_EXEC (1<<2) MOUNT_SETATTR_NOEXEC (1<<2)|(1<<3) MOUNT_SETATTR_SUID (1<<4) MOUNT_SETATTR_NOSUID (1<<4)|(1<<5) MOUNT_SETATTR_RW (1<<6) MOUNT_SETATTR_RO (1<<6)|(1<<7) MOUNT_SETATTR_RELATIME (1<<8) MOUNT_SETATTR_NOATIME (1<<8)|(1<<9) MOUNT_SETATTR_NODIRATIME (1<<8)|(2<<9) MOUNT_SETATTR_STRICTATIME (1<<8)|(3<<9) MOUNT_SETATTR_PRIVATE (1<<11) MOUNT_SETATTR_SHARED (1<<11)|(1<<12) MOUNT_SETATTR_SLAVE (1<<11)|(2<<12) MOUNT_SETATTR_UNBINDABLE (1<<11)|(3<<12)
Quoted 5 lines
So, I like this generally, some notes though:
I wonder if this should be two separate parameters, a mask and the settings? I'm not sure that's worth it since some of the mask bits would cover multiple settings.
Nah, better put those bits in the same word, as in above. Here bits 0, 2, 4, 6, 8 and 11 tell which attributes are to be modified, with values to set living in bits 1, 3, 5, 7, 9--10 and 12--13. Look at the constants above..
Quoted 3 lines
Also, should NODIRATIME be separate from the other *ATIME flags? I do also like treating some of these settings as enumerations rather than a set of bits.
Huh? That's precisely what I'm doing there: bit 8 is "want to change atime settings", bits 9 and 10 hold a 4-element enumeration (rel/no/nodir/strict). Similar for propagation settings (bit 11 indicates that we want to set those, bits 12 and 13 - 4-element enum)...
Quoted 8 lines
I would make the prototype:
int mount_setattr(int dirfd, const char *path,
unsigned int flags, unsigned int attr, void *reserved5);Further, do we want to say you can either change the propagation type *or* reconfigure the mountpoint restrictions, but not both at the same time?
Why? MOUNT_SETATTR_PRIVATE | MOUNT_NOATIME | MOUNT_SUID, i.e. 00101100010000, i.e. 0xb10 for "turn nosuid off, switch atime polcy to noatime, change propagation to private, leave everything else as-is"...
And for fsck sake, what's that "void *reserved5" for?
Quoted 5 lines
Quoted 2 lines
With either
openat()used as in this series, or explicit
intopen_tree(int dirfd, const char *path, int flags)Maybe
open_mount(),grab_mount()orpick_mount()?
Quoted 7 lines
I wonder if fsopen()/fspick() should be create_fs()/open_fs()...
Quoted 3 lines
returning a descriptor, with flags being
AT_EMPTY_PATH,AT_NO_AUTOMOUNT,AT_RECURSIVE,AT_CLONE
withAT_RECURSIVEwithoutAT_CLONEbeing an error.You also need an
O_CLOEXECequivalent.
Point.
Quoted 3 lines
I would make it:
OPEN_TREE_CLOEXEC 0x00000001
Why not O_CLOEXEC, as with epoll_create()/timerfd_create()/etc.?
Quoted 3 lines
OPEN_TREE_EMPTY_PATH 0x00000002 OPEN_TREE_FOLLOW_SYMLINK 0x00000004 OPEN_TREE_NO_AUTOMOUNT 0x00000008
Why? How are those different from normal AT_EMPTY_PATH/AT_NO_AUTOMOUNT?
Quoted 5 lines
OPEN_TREE_CLONE 0x00000010 OPEN_TREE_RECURSIVE 0x00000020adding the follow-symlinks so that you don't grab a symlink target by accident. (Can you actually mount on top of a symlink?)
You can't - mount(2) uses LOOKUP_FOLLOW for mountpoint (well, user_path(), actually).
Quoted 10 lines
Quoted 2 lines
Hell, might even add
AT_UMOUNTfor "open root and detach, to be dissolved on close", incompatible withAT_CLONE.Cute. Guess you could do:
fd = open_mount(..., OPEN_TREE_DETACH); mount_setattr(fd, "", MOUNT_SETATTR_EMPTY_PATH, MOUNT_SETATTR_NOSUID, NULL); move_mount(fd, "", ...);
Al Viro
maintainerRFC PATCH 1/1 open_tree(2) (was Re: [PATCH 30/32] vfs: Allow cloning of a mount tree with open(O_PATH|O_CLONE_MOUNT) [ver #8])
Quoted 10 lines · Al Viro
Quoted 10 lines
Quoted 2 lines
Hell, might even add
AT_UMOUNTfor "open root and detach, to be dissolved on close", incompatible withAT_CLONE.Cute. Guess you could do:
fd = open_mount(..., OPEN_TREE_DETACH); mount_setattr(fd, "", MOUNT_SETATTR_EMPTY_PATH, MOUNT_SETATTR_NOSUID, NULL); move_mount(fd, "", ...);
Hadn't added that yet, but as for the rest of open_tree() - see vfs.git#mount-open_tree. open() and its flags are not touched at all. Other changes compared to the previous:
* may_mount() is required for OPEN_TREE_CLONE
* sys_ni.c cruft is dropped - those make no sense until and unless
those syscalls become conditional.
Appears to work, combined with move_mount() it yields eqiuvalents of mount --{move,bind,rbind}. Combined with mount_setattr(2) (when that gets added) we'll get mount -o remount,bind,nodev et.al. (including the currently absent whole-subtree versions) and mount --make-{r,}{shared,slave,private,unbindable}
It also can be used to get an isolated subtree usable for ....at() stuff.
The addition of syscall itself is done by the following and I'd really like linux-abi folks to comment on that puppy
commit 6cfba4dd99b10278c2156c8d4fced2eddedf167f
Author: Al Viro <[email protected]> Date: Sat Jun 2 19:42:22 2018 -0400
new syscall: open_tree(2)
open_tree(dfd, pathname, flags)
Returns an O_PATH-opened file descriptor or an error. dfd and pathname specify the location to open, in usual fashion (see e.g. fstatat(2)). flags should be an OR of some of the following:
* AT_PATH_EMPTY, AT_NO_AUTOMOUNT, AT_SYMLINK_NOFOLLOW -
same meanings as usual
* OPEN_TREE_CLOEXEC - make the resulting descriptor
close-on-exec
* OPEN_TREE_CLONE or OPEN_TREE_CLONE | AT_RECURSIVE -
instead of opening the location in question, create a detached mount tree matching the subtree rooted at location specified by dfd/pathname. With AT_RECURSIVE the entire subtree is cloned, without it - only the part within in the mount containing the location in question. In other words, the same as mount --rbind or mount --bind would've taken. The detached tree will be dissolved on the final close of obtained file. Creation of such detached trees requires the same capabilities as doing mount --bind.
arch/x86/entry/syscalls/syscall_32.tbl +1 -0
@@ -397,3 +397,4 @@ 383 i386 statx sys_statx __ia32_sys_statx 384 i386 arch_prctl sys_arch_prctl __ia32_compat_sys_arch_prctl 385 i386 io_pgetevents sys_io_pgetevents __ia32_compat_sys_io_pgetevents +391 i386 open_tree sys_open_tree __ia32_sys_open_tree
arch/x86/entry/syscalls/syscall_64.tbl +1 -0
@@ -342,6 +342,7 @@ 331 common pkey_free __x64_sys_pkey_free 332 common statx __x64_sys_statx 333 common io_pgetevents __x64_sys_io_pgetevents +339 common open_tree __x64_sys_open_tree # # x32-specific system call numbers start at 512 to avoid cache impact
fs/file_table.c +6 -3
@@ -189,6 +189,7 @@ static void __fput(struct file *file)struct dentry *dentry = file->f_path.dentry;struct vfsmount *mnt = file->f_path.mnt;struct inode *inode = file->f_inode; +fmode_t mode = file->f_mode;might_sleep ();
@@ -209,14 +210,14 @@ static void __fput(struct file *file) file->f_op->release (inode, file);security_file_free (file);if (unlikely (S_ISCHR (inode->i_mode) && inode->i_cdev !=NULL && - !(file->f_mode &FMODE_PATH ))) { + !(mode &FMODE_PATH ))) {cdev_put (inode->i_cdev); }fops_put (file->f_op);put_pid (file->f_owner.pid); -if ((file->f_mode & (FMODE_READ |FMODE_WRITE )) ==FMODE_READ ) +if ((mode & (FMODE_READ |FMODE_WRITE )) ==FMODE_READ )i_readcount_dec (inode); -if (file->f_mode &FMODE_WRITER ) { +if (mode &FMODE_WRITER ) {put_write_access (inode);__mnt_drop_write (mnt); }
@@ -224,6 +225,8 @@ static void __fput(struct file *file) file->f_path.mnt =NULL ; file->f_inode =NULL ;file_free (file); +if (unlikely (mode &FMODE_NEED_UNMOUNT )) +dissolve_on_fput (mnt);dput (dentry);mntput (mnt); }
fs/internal.h +1 -0
@@ -85,6 +85,7 @@ extern void __mnt_drop_write(struct vfsmount *);extern void __mnt_drop_write_file (struct file *);extern void mnt_drop_write_file_path (struct file *); +extern void dissolve_on_fput (struct vfsmount *);/* * fs_struct.c */
fs/namespace.c +110 -22
185 lines not on this page · raw message
include/linux/fs.h +3 -0
@@ -154,6 +154,9 @@ typedef int (dio_iodone_t)(struct kiocb *iocb, loff_t offset,/* File is capable of returning -EAGAIN if I/O will block */ #define FMODE_NOWAIT ((__force fmode_t)0x8000000) +/* File represents mount that needs unmounting */ +#define FMODE_NEED_UNMOUNT ((__force fmode_t)0x10000000) +/* * Flag for rw_copy_check_uvector and compat_rw_copy_check_uvector * that indicates that they should check the contents of the iovec are
include/linux/syscalls.h +1 -1
@@ -896,7 +896,7 @@ asmlinkage long sys_pkey_alloc(unsigned long flags, unsigned long init_val);asmlinkage long sys_pkey_free (int pkey);asmlinkage long sys_statx (int dfd,const char __user *path,unsigned flags,unsigned mask,struct statx __user *buffer); - +asmlinkage long sys_open_tree (int dfd,const char __user *path,unsigned flags);/* * Architecture-specific system calls
include/uapi/linux/fcntl.h +2 -0
@@ -90,5 +90,7 @@#define AT_STATX_FORCE_SYNC 0x2000/* - Force the attributes to be sync'd with the server */ #define AT_STATX_DONT_SYNC 0x4000/* - Don't sync attributes with the server */ +#define AT_RECURSIVE 0x8000/* Apply to the entire subtree */ +#endif /* _UAPI_LINUX_FCNTL_H */
include/uapi/linux/mount.h new file +7 -0
@@ -0,0 +1,7 @@ +#ifndef _UAPI_LINUX_MOUNT_H +#define _UAPI_LINUX_MOUNT_H + +#define OPEN_TREE_CLONE 1 +#define OPEN_TREE_CLOEXEC O_CLOEXEC + +#endif /* _UAPI_LINUX_MOUNT_H */
Miklos Szeredi
maintainerRe: [PATCH][RFC] open_tree(2) (was Re: [PATCH 30/32] vfs: Allow cloning of a mount tree with open(O_PATH|O_CLONE_MOUNT) [ver #8])
Quoted 20 lines · Al Viro
Quoted 10 lines · Al Viro
Quoted 10 lines
Quoted 2 lines
Hell, might even add
AT_UMOUNTfor "open root and detach, to be dissolved on close", incompatible withAT_CLONE.Cute. Guess you could do:
fd = open_mount(..., OPEN_TREE_DETACH); mount_setattr(fd, "", MOUNT_SETATTR_EMPTY_PATH, MOUNT_SETATTR_NOSUID, NULL); move_mount(fd, "", ...);Hadn't added that yet, but as for the rest of
open_tree()- see vfs.git#mount-open_tree.open()and its flags are not touched at all. Other changes compared to the previous:
*may_mount()is required forOPEN_TREE_CLONE
*sys_ni.ccruft is dropped - those make no sense until and unless
those syscalls become conditional.
Quoted 3 lines
Appears to work, combined with
move_mount()it yields eqiuvalents of mount --{move,bind,rbind}. Combined withmount_setattr(2)(when that gets added) we'll get mount -o remount,bind,nodev et.al.
fsopen = create fsfd
fsmount = fsfd -> mountfd & set attr on mountfd & attach mountfd fspick = path -> fsfdmove_mount = attach mountfd or move existing
fsinfo = info from pathopen_tree = new mountfd from path or clone mount_setattr = set attr on mountfd
Notice that fsmount() encompasses mount_setattr() + move_mount()
functionality. Split those out and leave fsmount() to actually do
the "fsfd ->mountfd" translation?
fsinfo() name suggests it's in the same class as fsopen/fsmount/fspick, operating on fsfd object, but's it's not and I think that's slightly confusing.
Rename move_mount() -> mount_move()?
Also does it make sense to make the cloning behavior of open_tree() optional? Without cloning it's just a plain open(O_PATH). That way it could be renamed mount_clone().
Thanks,
Miklos
David Howells
maintainerRe: [PATCH][RFC] open_tree(2) (was Re: [PATCH 30/32] vfs: Allow cloning of a mount tree with open(O_PATH|O_CLONE_MOUNT) [ver #8])
Quoted 1 line · Miklos Szeredi
fsinfo = info from path
Actually, I was thinking of making fsinfo() detect if it's been given an fsfd and go through an fs_context operation instead in that case.
David
Al Viro
maintainerRe: [PATCH][RFC] open_tree(2) (was Re: [PATCH 30/32] vfs: Allow cloning of a mount tree with open(O_PATH|O_CLONE_MOUNT) [ver #8])
In reply to Miklos SzerediQuoted 11 lines · Miklos Szeredi
fsopen = create fsfd
fsmount = fsfd -> mountfd & set attr on mountfd & attach mountfd fspick = path -> fsfdmove_mount= attach mountfd or move existing
fsinfo = info from pathopen_tree= new mountfd from path or clonemount_setattr= set attr on mountfdNotice that
fsmount()encompassesmount_setattr()+move_mount()
functionality. Split those out and leavefsmount()to actually do
the "fsfd ->mountfd" translation?
Might make sense.
Quoted 5 lines
fsinfo()name suggests it's in the same class as fsopen/fsmount/fspick, operating on fsfd object, but's it's not and I think that's slightly confusing.Rename
move_mount()->mount_move()?
mount_move_bikeshed_bikeshed_bikeshed(), surely?
Quoted 3 lines
Also does it make sense to make the cloning behavior of
open_tree()optional? Without cloning it's just a plainopen(O_PATH). That way it could be renamedmount_clone().
Umm... I'm not sure about that one. If nothing else, OPEN_TREE_DETACH might be a good idea, in which case cloning is not the primary effect; hell knows.
Al Viro
maintainerRe: [PATCH][RFC] open_tree(2) (was Re: [PATCH 30/32] vfs: Allow cloning of a mount tree with open(O_PATH|O_CLONE_MOUNT) [ver #8])
Quoted 10 lines · Al Viro
Quoted 8 lines · Miklos Szeredi
fsopen = create fsfd
fsmount = fsfd -> mountfd & set attr on mountfd & attach mountfd fspick = path -> fsfdmove_mount= attach mountfd or move existing
fsinfo = info from pathopen_tree= new mountfd from path or clonemount_setattr= set attr on mountfd
Quoted 5 lines
Quoted 3 lines
Notice that
fsmount()encompassesmount_setattr()+move_mount()
functionality. Split those out and leavefsmount()to actually do
the "fsfd ->mountfd" translation?Might make sense.
FWIW, to make it clear: fsmount(2) in this series actually does *NOT* attach it to the tree. Commit message definitely needs updating - as it is, it's
+SYSCALL_DEFINE5(fsmount, int, fs_fd, unsigned int, flags, unsigned int, ms_flags,
+ void *, reserved4, void *, reserved5)
PS: IMO these reserved... arguments are in bad taste; if anyone has good reasons for that practice in ABI design, I'd like to hear those.
Miklos Szeredi
maintainerRe: [PATCH][RFC] open_tree(2) (was Re: [PATCH 30/32] vfs: Allow cloning of a mount tree with open(O_PATH|O_CLONE_MOUNT) [ver #8])
In reply to Al ViroQuoted 10 lines · Al Viro
Quoted 8 lines · Miklos Szeredi
fsopen = create fsfd
fsmount = fsfd -> mountfd & set attr on mountfd & attach mountfd fspick = path -> fsfdmove_mount= attach mountfd or move existing
fsinfo = info from pathopen_tree= new mountfd from path or clonemount_setattr= set attr on mountfd
Quoted 8 lines
Quoted 3 lines
Notice that
fsmount()encompassesmount_setattr()+move_mount()
functionality. Split those out and leavefsmount()to actually do
the "fsfd ->mountfd" translation?Might make sense.
FWIW, to make it clear: fsmount(2) in this series actually does *NOT* attach it to the tree.
Ah, that leaves the mount_setattr() functionality to split out. I'd
be more happy to rid this new API of all the old MS_* crap and have
have a new set of attributes, that just apply to mounts. It will
also need two args: a bitmap of new attributes and a mask to tell us which attributes to change.
Quoted 8 lines
Commit message definitely needs updating - as it
is, it's(quoted diff) +2
-0+SYSCALL_DEFINE5(fsmount, int, fs_fd, unsigned int, flags, unsigned int, ms_flags, + void *, reserved4, void *, reserved5)PS: IMO these reserved... arguments are in bad taste; if anyone has good reasons for that practice in ABI design, I'd like to hear those.
Agreed. A flags argument is often wise to add even if currently unused (and should be checked for undefined flags), but adding a random number of pointers doesn't seem to make a lot of sense.
Quoted 8 lines
Quoted 6 lines
fsinfo()name suggests it's in the same class as fsopen/fsmount/fspick, operating on fsfd object, but's it's not and I think that's slightly confusing.Rename
move_mount()->mount_move()?
mount_move_bikeshed_bikeshed_bikeshed(), surely?
Consistent naming for related functions... not unheard of in API design. The above set definitely does not qualify.
Quoted 7 lines
Quoted 3 lines
Also does it make sense to make the cloning behavior of
open_tree()optional? Without cloning it's just a plainopen(O_PATH). That way it could be renamedmount_clone().Umm... I'm not sure about that one. If nothing else,
OPEN_TREE_DETACHmight be a good idea, in which case cloning is not the primary effect; hell knows.
So conceptually we have the following distinct mount tree operations:
treefd = clone(path);
treefd = detach(path);attach(treefd, path);move(path1, path2);
The detach/move/attach trio are more related in functionality, while clone and detach have the same signature. I'm not sure either.
Thanks,
Miklos
Re: [PATCH][RFC] open_tree(2) (was Re: [PATCH 30/32] vfs: Allow cloning of a mount tree with open(O_PATH|O_CLONE_MOUNT) [ver #8])
In reply to Al Virofs/namespace.c static int do_loopback(struct path *path, const char *old_name, · line 2295
Quoted 10 lines · Al Viro
fs/namespace.c +10
-0+SYSCALL_DEFINE3(open_tree, int, dfd, const char *, filename, unsigned, flags) +{ +struct file *file; +struct path path; +int lookup_flags =LOOKUP_AUTOMOUNT |LOOKUP_FOLLOW ; +bool detached = flags &OPEN_TREE_CLONE ; +int error; +int fd; + +BUILD_BUG_ON (OPEN_TREE_CLOEXEC !=O_CLOEXEC );
Why do we need OPEN_TREE_CLOEXEC? Wouldn't we be better off just making the fd returned by open_tree implicitly close-on-exec? I can think of no good reason for these file descriptors to be inherited across exec() and if someone comes up with such a reason, fcntl(F_SETFD) is not an expensive call to make.
Al Viro
maintainerRe: [PATCH][RFC] open_tree(2) (was Re: [PATCH 30/32] vfs: Allow cloning of a mount tree with open(O_PATH|O_CLONE_MOUNT) [ver #8])
Quoted 15 lines · Matthew Wilcox
fs/namespace.c static int do_loopback(struct path *path, const char *old_name, · line 2295
Quoted 10 lines · Al Viro
fs/namespace.c +10
-0+SYSCALL_DEFINE3(open_tree, int, dfd, const char *, filename, unsigned, flags) +{ +struct file *file; +struct path path; +int lookup_flags =LOOKUP_AUTOMOUNT |LOOKUP_FOLLOW ; +bool detached = flags &OPEN_TREE_CLONE ; +int error; +int fd; + +BUILD_BUG_ON (OPEN_TREE_CLOEXEC !=O_CLOEXEC );Why do we need
OPEN_TREE_CLOEXEC? Wouldn't we be better off just making the fd returned byopen_treeimplicitly close-on-exec? I can think of no good reason for these file descriptors to be inherited acrossexec()
How are they different from any file descriptor? It's not as if it was something usable only for mounting stuff - again, you can use them with any ...at() syscalls.
Quoted 2 lines
and if someone comes up with such a reason,
fcntl(F_SETFD)is not an expensive call to make.
Miklos Szeredi
maintainerRe: [PATCH][RFC] open_tree(2) (was Re: [PATCH 30/32] vfs: Allow cloning of a mount tree with open(O_PATH|O_CLONE_MOUNT) [ver #8])
Quoted 17 lines · Al Viro
Quoted 15 lines · Matthew Wilcox
fs/namespace.c static int do_loopback(struct path *path, const char *old_name, · line 2295
Quoted 10 lines · Al Viro
fs/namespace.c +10
-0+SYSCALL_DEFINE3(open_tree, int, dfd, const char *, filename, unsigned, flags) +{ +struct file *file; +struct path path; +int lookup_flags =LOOKUP_AUTOMOUNT |LOOKUP_FOLLOW ; +bool detached = flags &OPEN_TREE_CLONE ; +int error; +int fd; + +BUILD_BUG_ON (OPEN_TREE_CLOEXEC !=O_CLOEXEC );Why do we need
OPEN_TREE_CLOEXEC? Wouldn't we be better off just making the fd returned byopen_treeimplicitly close-on-exec? I can think of no good reason for these file descriptors to be inherited acrossexec()
Quoted 3 lines
How are they different from any file descriptor? It's not as if it was something usable only for mounting stuff - again, you can use them with any ...at() syscalls.
Defaulting to close on exec helps keep out clutter from the API.
Is there a disadvantage to needing an explicit fcntl(F_SETFD) call to disable close on exec?
Thanks,
Miklos
Amir Goldstein
maintainerRe: [PATCH 30/32] vfs: Allow cloning of a mount tree with open(O_PATH|O_CLONE_MOUNT) [ver #8]
In reply to David Howells[added linux-api]
Quoted 25 lines · David Howells
Make it possible to clone a mount tree with a new pair of open flags that are used in conjunction with
O_PATH:(1)
O_CLONE_MOUNT- Clone the mount or mount tree at the path.(2)
O_NON_RECURSIVE- Don't clone recursively.Note that it's not a good idea to reuse other flags (such as
O_CREAT) because the open routine forO_PATHdoes not give an error if any other flags are used in conjunction withO_PATH, but rather just masks off any it doesn't use.The resultant file struct is marked
FMODE_NEED_UNMOUNTto as it pins an extra reference for the mount. This will be cleared by the upcomingmove_mount()syscall when it successfully moves a cloned mount into the filesystem tree.Note that care needs to be taken with the error handling in
do_o_path()in the case thatvfs_open()fails as the path may or may not have been attached to the file struct andFMODE_NEED_UNMOUNTmay or may not be set. Note thatO_DIRECT|O_PATHcould be a problem with error handling too.Signed-off-by David Howells <[email protected]>---
[...]
fs/open.c static inline int build_open_flags(int flags, umode_t mode, struct open_flags *o · line 986
Quoted 10 lines
fs/open.c +4
-1@@ -977,8 +979,11 @@ static inline int build_open_flags(int flags, umode_t mode, struct open_flags *o* If we have O_PATH in the open flag. Then we * cannot have anything other than the below set of flags */ - flags &=O_DIRECTORY |O_NOFOLLOW |O_PATH ; + flags &= (O_DIRECTORY |O_NOFOLLOW |O_PATH | +O_CLONE_MOUNT |O_NON_RECURSIVE ); acc_mode =0 ; + }else if (flags & (O_CLONE_MOUNT |O_NON_RECURSIVE )) { +return -EINVAL ;
Reject O_NON_RECURSIVE without O_CLONE_MOUNT?
That would free at least one flag combination for future use.
Doesn't it make more sense for user API to opt-into O_RECURSIVE_CLONE, rather than opt-out of it?
Quoted 27 lines
fs/open.c +0
-0} op->open_flag = flags;include/linux/fcntl.h +2
-1@@ -9,7 +9,8 @@ (O_RDONLY |O_WRONLY |O_RDWR |O_CREAT |O_EXCL |O_NOCTTY |O_TRUNC | \O_APPEND |O_NDELAY |O_NONBLOCK |O_NDELAY | __O_SYNC |O_DSYNC | \FASYNC |O_DIRECT |O_LARGEFILE |O_DIRECTORY |O_NOFOLLOW | \ - O_NOATIME | O_CLOEXEC | O_PATH | __O_TMPFILE) +O_NOATIME |O_CLOEXEC |O_PATH | __O_TMPFILE | \ + O_CLONE_MOUNT | O_NON_RECURSIVE)#ifndef force_o_largefile#define force_o_largefile () (BITS_PER_LONG != 32)include/uapi/asm-generic/fcntl.h +1
-0@@ -88,6 +88,14 @@#define __O_TMPFILE 020000000#endif +#ifndef O_CLONE_MOUNT
include/uapi/asm-generic/fcntl.h line 101
Quoted 10 lines
include/uapi/asm-generic/fcntl.h +7
-0+#define O_CLONE_MOUNT 040000000/* Used with O_PATH to clone the mount subtree at path */ +#endif + +#ifndef O_NON_RECURSIVE +#define O_NON_RECURSIVE 0100000000/* Used with O_CLONE_MOUNT to only clone one mount */ +#endif +/* a horrid kludge trying to make sure that this will fail on old kernels */ #define O_TMPFILE (__O_TMPFILE | O_DIRECTORY)#define O_TMPFILE_MASK (__O_TMPFILE | O_DIRECTORY | O_CREAT)
I am not sure what are the consequences of opening O_PATH with old kernel and getting an open file, can't think of anything bad.
Can the same be claimed for O_PATH|O_CLONE_MOUNT?
Wouldn't it be better to apply the O_TMPFILE kludge to the new open flag, so that apps can check if O_CLONE_MOUNT feature is supported by kernel?
Thanks,
Amir.
David Howells
maintainerRe: [PATCH 30/32] vfs: Allow cloning of a mount tree with open(O_PATH|O_CLONE_MOUNT) [ver #8]
Quoted 1 line · Amir Goldstein
Reject
O_NON_RECURSIVEwithoutO_CLONE_MOUNT?
Yes, I should add that.
Quoted 3 lines
I am not sure what are the consequences of opening
O_PATHwith old kernel and getting an open file, can't think of anything bad.
Can the same be claimed for O_PATH|O_CLONE_MOUNT?
Yes, actually, there can be consequences. Some files have side effects. Think open("/dev/foobar", O_PATH).
Quoted 3 lines
Wouldn't it be better to apply the
O_TMPFILEkludge to the new open flag, so that apps can check ifO_CLONE_MOUNTfeature is supported by kernel?
Ugh. The problem is that the O_TMPFILE kludge can't be done because O_PATH currently just masks off any bits it's not interested in rather than giving an error.
Even the O_TMPFILE kludge doesn't protect you against someone having set random unassigned bits when testing on a kernel that didn't support it.
And this bit:
/* * Clear out all open flags we don't know about so that we don't report * them in fcntl(F_GETFD) or similar interfaces. */ flags &= VALID_OPEN_FLAGS;
is just plain wrong. Effectively, it allows userspace to set random reserved bits without consequences. It should give an error instead.
Probably we should really replace open() and openat() both before we can allocate any further open flags.
</grumble>
David
David Howells
maintainerRFC PATCH 31/32 fs: Add a move_mount() system call [ver #8]
In reply to David Howells[!] NOTE: This patch doesn't quite work to move an O_CLONE_MOUNT-produced
vfsmount as move_mount() checks that the source vfsmount mnt_ns matches the calling process's mnt_ns - but the vfsmount's mnt_ns isn't set until one attempts to actually mount it into the namespace.
Add a move_mount() system call that will move a mount from one place to another and change the flags, where one or both of those places may be selected by an O_PATH open.
To this end, two additional open()/openat() flags are defined that can be used with O_PATH:
(*) O_CLONE_MOUNT - Clone a mount (subtree) and attach it to the file
descriptor. This can be used to turn a move_mount() into a copy operation.
(*) O_NON_RECURSIVE - Clone only the targetted mount, and not the entire
subtree.
Unfortunately, the other extant open flags cannot be reused as when O_PATH was added, no check was provided that would give an error if any other flag was given other than O_TMPFILE, O_DIRECTORY, O_NOFOLLOW and O_CLOEXEC - rather, the flags are just masked off - so there's no guarantee that userspace isn't attempting to do this somewhere. Further, O_CREAT has an effect before the O_PATH handling clears it - though this may be later ignored.
The new system call looks like the following:
int move_mount(int from_dfd, const char *from_path,
int to_dfd, const char *to_path, unsigned int ms_flags);
As from_dfd and to_dfd can both be obtained from openat(O_PATH), there is no need to have two sets of AT_NO_FOLLOW-style flags here also. Further, either fd can be obtained from the new fsmount() syscall.
New mounts are a case of:
sbfd = fsopen(); ... mfd = fsmount(, MS_RDONLY); move_mount(mfd, NULL, AT_FDCWD, "/mnt", MS_RDONLY);
---
arch/x86/entry/syscalls/syscall_32.tbl | 1 arch/x86/entry/syscalls/syscall_64.tbl | 1 fs/internal.h | 3 + fs/namei.c | 40 ++++++++++ fs/namespace.c | 125 ++++++++++++++++++++++++++++---- include/linux/lsm_hooks.h | 6 ++ include/linux/security.h | 7 ++ include/linux/syscalls.h | 3 + include/uapi/linux/mount.h | 11 +++ kernel/sys_ni.c | 1 security/security.c | 5 + 11 files changed, 186 insertions(+), 17 deletions(-)
arch/x86/entry/syscalls/syscall_32.tbl +1 -0
@@ -400,3 +400,4 @@ 386 i386 fsopen sys_fsopen __ia32_sys_fsopen 387 i386 fsmount sys_fsmount __ia32_sys_fsmount 388 i386 fspick sys_fspick __ia32_sys_fspick +389 i386 move_mount sys_move_mount __ia32_sys_move_mount
arch/x86/entry/syscalls/syscall_64.tbl +1 -0
@@ -345,6 +345,7 @@ 334 common fsopen __x64_sys_fsopen 335 common fsmount __x64_sys_fsmount 336 common fspick __x64_sys_fspick +337 common move_mount __x64_sys_move_mount # # x32-specific system call numbers start at 512 to avoid cache impact
fs/internal.h +3 -0
@@ -17,6 +17,7 @@ struct linux_binprm;struct path ;struct mount ;struct shrink_control ; +struct fd_cookie ;/* * block_dev.c
@@ -55,6 +56,8 @@ extern void __init chrdev_init(void);extern int user_path_mountpoint_at (int ,const char __user *,unsigned int ,struct path *);extern int vfs_path_lookup (struct dentry *,struct vfsmount *,const char *,unsigned int ,struct path *); +extern int move_mount_lookup (int ,const char __user *,unsigned , +struct path *,struct fd_cookie **);long do_mknodat (int dfd,const char __user *filename,umode_t mode,unsigned int dev);long do_mkdirat (int dfd,const char __user *pathname,umode_t mode);
fs/namei.c +40 -0
@@ -2333,6 +2333,46 @@ static int filename_lookup(int dfd, struct filename *name, unsigned flags,return retval; } +/* +* Look up the from for move_mount(). This is a bit tricky as move_mount() +* needs to clear FMODE_NEED_UNMOUNT on the file struct pointed to by dfd - if +* the pathname is empty and if the move completed successfully, so we need to +* pass back the fd information to the caller. +*/ +int move_mount_lookup (int dfd,const char __user *from_name,unsigned flags, +struct path *path,struct fd_cookie **_dfd_f) +{ +struct nameidata nd; +struct filename *name; +struct file *file; +int retval; + + name =getname_flags (from_name, flags,NULL ); +if (IS_ERR (name)) +return PTR_ERR (name); +set_nameidata (&nd, dfd, name); + retval =path_lookupat (&nd, flags |LOOKUP_RCU , path); +if (unlikely (retval == -ECHILD )) + retval =path_lookupat (&nd, flags, path); +if (unlikely (retval == -ESTALE )) + retval =path_lookupat (&nd, flags |LOOKUP_REVAL , path); + +if (likely (!retval)) { +audit_inode (name, path->dentry, flags &LOOKUP_PARENT ); + file =__fdfile (nd.dfd); +if (file && + file->f_path.mnt == path->mnt && + file->f_path.dentry == path->dentry) { + *_dfd_f = nd.dfd; + nd.dfd =NULL ; + } + } + +restore_nameidata (); +putname (name); +return retval; +} +/* Returns 0 and nd will be valid on success; Retuns error, otherwise. */ static int path_parentat (struct nameidata *nd,unsigned flags,struct path *parent)
fs/namespace.c +108 -17
174 lines not on this page · raw message
include/linux/lsm_hooks.h +6 -0
@@ -198,6 +198,10 @@* Parse a string of security data filling in the opts structure * @options string containing all mount options known by the LSM * @opts binary data structure usable by the LSM +* @move_mount: +* Check permission before a mount is moved. +* @from_path indicates the mount that is going to be moved. +* @to_path indicates the mountpoint that will be mounted upon. * @dentry_init_security: * Compute a context for a dentry as the inode is not yet available * since NFSv4 has no label backed by an EA anyway.
@@ -1535,6 +1539,7 @@ union security_list_options {unsigned long kern_flags, unsigned long *set_kern_flags);int (*sb_parse_opts_str)(char *options,struct security_mnt_opts *opts); +int (*move_mount)(const struct path *from_path,const struct path *to_path);int (*dentry_init_security)(struct dentry *dentry,int mode,const struct qstr *name,void **ctx,u32 *ctxlen);
@@ -1873,6 +1878,7 @@ struct security_hook_heads {struct hlist_head sb_set_mnt_opts;struct hlist_head sb_clone_mnt_opts;struct hlist_head sb_parse_opts_str; +struct hlist_head move_mount;struct hlist_head dentry_init_security;struct hlist_head dentry_create_files_as;#ifdef CONFIG_SECURITY_PATH
include/linux/security.h +7 -0
@@ -261,6 +261,7 @@ int security_sb_clone_mnt_opts(const struct super_block *oldsb,unsigned long kern_flags, unsigned long *set_kern_flags);int security_sb_parse_opts_str (char *options,struct security_mnt_opts *opts); +int security_move_mount (const struct path *from_path,const struct path *to_path);int security_dentry_init_security (struct dentry *dentry,int mode,const struct qstr *name,void **ctx,u32 *ctxlen);
@@ -655,6 +656,12 @@ static inline int security_sb_parse_opts_str(char *options, struct security_mnt_return 0 ; } +static inline int security_move_mount (const struct path *from_path, +const struct path *to_path) +{ +return 0 ; +} +static inline int security_inode_alloc (struct inode *inode) {return 0 ;
include/linux/syscalls.h +3 -0
@@ -901,6 +901,9 @@ asmlinkage long sys_fsopen(const char *fs_name, unsigned int flags,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); +asmlinkage long sys_move_mount (int from_dfd,const char *from_path, +int to_dfd,const char *to_path, +unsigned int ms_flags);/*
include/uapi/linux/mount.h +11 -0
@@ -55,4 +55,15 @@#define MS_MGC_VAL 0xC0ED0000#define MS_MGC_MSK 0xffff0000 +/* +* move_mount() flags. +*/ +#define MOVE_MOUNT_F_SYMLINKS 0x00000001/* Follow symlinks on from path */ +#define MOVE_MOUNT_F_AUTOMOUNTS 0x00000002/* Follow automounts on from path */ +#define MOVE_MOUNT_F_EMPTY_PATH 0x00000004/* Empty from path permitted */ +#define MOVE_MOUNT_T_SYMLINKS 0x00000010/* Follow symlinks on to path */ +#define MOVE_MOUNT_T_AUTOMOUNTS 0x00000020/* Follow automounts on to path */ +#define MOVE_MOUNT_T_EMPTY_PATH 0x00000040/* Empty to path permitted */ +#define MOVE_MOUNT__MASK 0x00000077 +#endif /* _UAPI_LINUX_MOUNT_H */
kernel/sys_ni.c +1 -0
@@ -437,3 +437,4 @@ COND_SYSCALL(setuid16);COND_SYSCALL (sys_fsopen);COND_SYSCALL (sys_fsmount);COND_SYSCALL (sys_fspick); +COND_SYSCALL (sys_move_mount);
security/security.c +5 -0
@@ -480,6 +480,11 @@ int security_sb_parse_opts_str(char *options, struct security_mnt_opts *opts) }EXPORT_SYMBOL (security_sb_parse_opts_str); +int security_move_mount (const struct path *from_path,const struct path *to_path) +{ +return call_int_hook (move_mount,0 , from_path, to_path); +} +int security_inode_alloc (struct inode *inode) { inode->i_security =NULL ;
David Howells
maintainerTest program for move_mount()
/* move_mount test.
*
* Copyright (C) 2018 Red Hat, Inc. All Rights Reserved.
* Written by David Howells ([email protected])
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public Licence
* as published by the Free Software Foundation; either version
* 2 of the Licence, or (at your option) any later version. */
#define _GNU_SOURCE
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#include <fcntl.h>
#include <sys/prctl.h>
#include <sys/wait.h>
#define O_CLONE_MOUNT 040000000 /* Used with O_PATH to clone the mount subtree at path */
#define O_NON_RECURSIVE 0100000000 /* Used with O_CLONE_MOUNT to only clone one mount */
#define MOVE_MOUNT_F_SYMLINKS 0x00000001 /* Follow symlinks on from path */
#define MOVE_MOUNT_F_AUTOMOUNTS 0x00000002 /* Follow automounts on from path */
#define MOVE_MOUNT_F_EMPTY_PATH 0x00000004 /* Empty from path permitted */
#define MOVE_MOUNT_T_SYMLINKS 0x00000010 /* Follow symlinks on to path */
#define MOVE_MOUNT_T_AUTOMOUNTS 0x00000020 /* Follow automounts on to path */
#define MOVE_MOUNT_T_EMPTY_PATH 0x00000040 /* Empty to path permitted */
#define MOVE_MOUNT__MASK 0x00000077
static inline int move_mount(int from_dfd, const char *from_pathname,
int to_dfd, const char *to_pathname, unsigned int flags)
{
return syscall(337, from_dfd, from_pathname, to_dfd, to_pathname, flags);
}void format(void)
{
printf("Format: move_mount [-a] [-c] [-r]\n");
exit(2);
}int main(int argc, char *argv[])
{
bool preopen = false;
int ret, fd;
int o_flags = O_PATH;
if (argc < 3)
format();
for (; argc > 3; argc--, argv++) {
if (strcmp(argv[1], "-a") == 0)
preopen = true;
else if (strcmp(argv[1], "-c") == 0)
o_flags |= O_CLONE_MOUNT;
else if (strcmp(argv[1], "-r") == 0)
o_flags |= O_NON_RECURSIVE;
else
format();
}
if (preopen) {
fd = open(argv[1], o_flags);
if (fd < 0) {
fprintf(stderr, "open(%s, O_PATH|...): %m\n", argv[1]);
exit(1);
}
ret = move_mount(fd, "", AT_FDCWD, argv[2],
MOVE_MOUNT_F_EMPTY_PATH);
if (ret != 0) {
fprintf(stderr, "move_mount([%s],%s) = %d: %m\n",
argv[1], argv[2], ret);
exit(1);
}
} else {
ret = move_mount(AT_FDCWD, argv[1], AT_FDCWD, argv[2],
MOVE_MOUNT_F_EMPTY_PATH);
if (ret != 0) {
fprintf(stderr, "move_mount(%s,%s) = %d: %m\n",
argv[1], argv[2], ret);
exit(1);
}
}
exit(0);
}Al Viro
maintainerRe: [PATCH 31/32] [RFC] fs: Add a move_mount() system call [ver #8]
In reply to David HowellsQuoted 4 lines · David Howells
[!] NOTE: This patch doesn't quite work to move an O_CLONE_MOUNT-produced
vfsmount asmove_mount()checks that the source vfsmountmnt_nsmatches the calling process'smnt_ns- but the vfsmount'smnt_nsisn't set until one attempts to actually mount it into the namespace.
*shrug*
Turn those checks into
error = -EINVAL; /* mountpoint should be ours */ if (!check_mnt(p)) goto out1; /* and the thing moved should be either ours or completely unattached */ if (old->mnt_ns && !check_mnt(old)) goto out1;
David Howells
maintainerRFC PATCH 32/32 fsinfo: Add a system call to allow querying of filesystem information [ver #8]
In reply to David HowellsAdd a system call to allow filesystem information to be queried. This is implemented as a function switch where the desired attribute value or values is nominated.
===============
NEW SYSTEM CALL
===============
The new system call looks like:
int ret = fsinfo(int dfd,
const char *filename, const struct fsinfo_params *params, void *buffer,
size_t buf_size);
The params parameter optionally points to a block of parameters:
struct fsinfo_params {
enum fsinfo_attribute request;
__u32 Nth;
__u32 at_flags;
__u32 __spare[6];
};If params is NULL, it is assumed params->request should be fsinfo_attr_statfs, params->Nth should be 0 and params->at_flags should be 0.
If params is given, all of params->__spare[] must be 0.
dfd, filename and params->at_flags indicate the file to query. There is no equivalent of lstat() as that can be emulated with fsinfo() by setting AT_SYMLINK_NOFOLLOW in params->at_flags. There is also no equivalent of fstat() as that can be emulated by passing a NULL filename to fsinfo() with the fd of interest in dfd. AT_NO_AUTOMOUNT can also be used to an allow automount point to be queried without triggering it.
AT_FORCE_ATTR_SYNC can be set in params->at_flags. This will require a network filesystem to synchronise its attributes with the server.
AT_NO_ATTR_SYNC can be set in params->at_flags. This will suppress synchronisation with the server in a network filesystem. The resulting values should be considered approximate.
params->request indicates the attribute/attributes to be queried. This can be one of:
fsinfo_attr_statfs - statfs-style info
fsinfo_attr_fsinfo - Information about fsinfo()
fsinfo_attr_limits - Filesystem limits
fsinfo_attr_capabilities - Filesystem capabilities
fsinfo_attr_timestamp_info - Inode timestamp info
fsinfo_attr_volume_id - Volume ID (var length)
fsinfo_attr_volume_uuid - Volume UUID
fsinfo_attr_volume_name - Volume name (string)
fsinfo_attr_cell_name - Cell name (string)
fsinfo_attr_domain_name - Domain name (string)
fsinfo_attr_realm_name - Realm name (string)
fsinfo_attr_server_name - Name of the Nth server (string)
fsinfo_attr_server_addresses - Addresses of the Nth server
fsinfo_attr_error_state - Error state
fsinfo_attr_parameter - Nth mount parameter (string)
fsinfo_attr_source - Nth mount source name (string)
fsinfo_attr_name_encoding - Filename encoding (string)
fsinfo_attr_name_codepage - Filename codepage (string)
fsinfo_attr_io_size - Optimal I/O sizes
Some attributes (such as the servers backing a network filesystem) can have multiple values. These can be enumerated by setting params->Nth to 0, 1, ... until ENODATA is returned.
buffer and buf_size point to the reply buffer. The buffer is filled up to the specified size, even if this means truncating the reply. The full size of the reply is returned. In future versions, this will allow extra fields to be tacked on to the end of the reply, but anyone not expecting them will only get the subset they're expecting. If either buffer of buf_size are 0, no copy will take place and the data size will be returned.
At the moment, this will only work on x86_64 and i386 as it requires the system call to be wired up.
---
arch/x86/entry/syscalls/syscall_32.tbl | 1 arch/x86/entry/syscalls/syscall_64.tbl | 1 fs/statfs.c | 431 ++++++++++++++++++++++++++++++++ include/linux/fs.h | 4 include/linux/fsinfo.h | 25 ++ include/linux/syscalls.h | 3 include/uapi/linux/fsinfo.h | 231 +++++++++++++++++ samples/statx/Makefile | 5 samples/statx/test-fsinfo.c | 179 +++++++++++++ 9 files changed, 879 insertions(+), 1 deletion(-) create mode 100644 include/linux/fsinfo.h create mode 100644 include/uapi/linux/fsinfo.h create mode 100644 samples/statx/test-fsinfo.c
arch/x86/entry/syscalls/syscall_32.tbl +1 -0
@@ -401,3 +401,4 @@ 387 i386 fsmount sys_fsmount __ia32_sys_fsmount 388 i386 fspick sys_fspick __ia32_sys_fspick 389 i386 move_mount sys_move_mount __ia32_sys_move_mount +390 i386 fsinfo sys_fsinfo __ia32_sys_fsinfo
arch/x86/entry/syscalls/syscall_64.tbl +1 -0
@@ -346,6 +346,7 @@ 335 common fsmount __x64_sys_fsmount 336 common fspick __x64_sys_fspick 337 common move_mount __x64_sys_move_mount +338 common fsinfo __x64_sys_fsinfo # # x32-specific system call numbers start at 512 to avoid cache impact
fs/statfs.c +431 -0
440 lines not on this page · raw message
include/linux/fs.h +4 -0
@@ -61,6 +61,8 @@ struct iov_iter;struct fscrypt_info ;struct fscrypt_operations ;struct fs_context ; +struct fsinfo_kparams ; +enum fsinfo_attribute ;extern void __init inode_init (void );extern void __init inode_init_early (void );
@@ -1835,6 +1837,7 @@ struct super_operations {int (*thaw_super) (struct super_block *);int (*unfreeze_fs) (struct super_block *);int (*statfs) (struct dentry *,struct kstatfs *); +int (*get_fsinfo) (struct dentry *,struct fsinfo_kparams *);int (*remount_fs) (struct super_block *,int *,char *,size_t );int (*reconfigure) (struct super_block *,struct fs_context *);void (*umount_begin) (struct super_block *);
@@ -2200,6 +2203,7 @@ extern int iterate_mounts(int (*)(struct vfsmount *, void *), void *,extern int vfs_statfs (const struct path *,struct kstatfs *);extern int user_statfs (const char __user *,struct kstatfs *);extern int fd_statfs (int ,struct kstatfs *); +extern int vfs_fsinfo (const struct path *,struct fsinfo_kparams *);extern int freeze_super (struct super_block *super);extern int thaw_super (struct super_block *super);extern bool our_mnt (struct vfsmount *mnt);
include/linux/fsinfo.h new file +25 -0
@@ -0,0 +1,25 @@ +/* Filesystem information query +* +* Copyright (C) 2018 Red Hat, Inc. All Rights Reserved. +* Written by David Howells ([email protected]) +* +* This program is free software; you can redistribute it and/or +* modify it under the terms of the GNU General Public Licence +* as published by the Free Software Foundation; either version +* 2 of the Licence, or (at your option) any later version. +*/ + +#ifndef _LINUX_FSINFO_H +#define _LINUX_FSINFO_H + +#include <uapi/linux/fsinfo.h> + +struct fsinfo_kparams { +enum fsinfo_attribute request;/* What is being asking for */ +__u32 Nth;/* Instance of it (some may have multiple) */ +__u32 at_flags;/* AT_SYMLINK_NOFOLLOW and similar */ +void *buffer;/* Where to place the reply */ +size_t buf_size;/* Size of the buffer */ +}; + +#endif /* _LINUX_FSINFO_H */
include/linux/syscalls.h +3 -0
@@ -49,6 +49,7 @@ struct stat64;struct statfs ;struct statfs64 ;struct statx ; +struct fsinfo_params ;struct __sysctl_args ;struct sysinfo ;struct timespec ;
@@ -904,6 +905,8 @@ asmlinkage long sys_fspick(int dfd, const char *path, unsigned int at_flags);asmlinkage long sys_move_mount (int from_dfd,const char *from_path,int to_dfd,const char *to_path,unsigned int ms_flags); +asmlinkage long sys_fsinfo (int dfd,const char *path,struct fsinfo_params *params, +void *buffer,size_t buf_size);/*
include/uapi/linux/fsinfo.h new file +231 -0
231 lines not on this page · raw message
samples/statx/Makefile +4 -1
@@ -1,7 +1,10 @@ # List of programs to build -hostprogs-$(CONFIG_SAMPLE_STATX) := test-statx +hostprogs-$(CONFIG_SAMPLE_STATX) := test-statx test-fsinfo # Tell kbuild to always build the programs always := $(hostprogs-y) HOSTCFLAGS_test-statx.o += -I$(objtree)/usr/include + +HOSTCFLAGS_test-fsinfo.o += -I$(objtree)/usr/include +HOSTLOADLIBES_test-fsinfo += -lm
samples/statx/test-fsinfo.c new file +179 -0
179 lines not on this page · raw message
David Howells
maintainerfsinfo test program
/* Test the fsinfo() system call
*
* Copyright (C) 2018 Red Hat, Inc. All Rights Reserved.
* Written by David Howells ([email protected])
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public Licence
* as published by the Free Software Foundation; either version
* 2 of the Licence, or (at your option) any later version. */
#define _GNU_SOURCE
#define _ATFILE_SOURCE
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
#include <unistd.h>
#include <ctype.h>
#include <errno.h>
#include <time.h>
#include <math.h>
#include <fcntl.h>
#include <sys/syscall.h>
#include <linux/stat.h>
#include <linux/socket.h>
#include <sys/stat.h>
#define __NR_fsinfo 338
enum fsinfo_attribute {
fsinfo_attr_statfs = 0, /* statfs()-style state */
fsinfo_attr_fsinfo = 1, /* Information about fsinfo() */
fsinfo_attr_ids = 2, /* Filesystem IDs */
fsinfo_attr_limits = 3, /* Filesystem limits */
fsinfo_attr_supports = 4, /* What's supported in statx, iocflags, ... */
fsinfo_attr_capabilities = 5, /* Filesystem capabilities (bits) */
fsinfo_attr_timestamp_info = 6, /* Inode timestamp info */
fsinfo_attr_volume_id = 7, /* Volume ID (string) */
fsinfo_attr_volume_uuid = 8, /* Volume UUID (LE uuid) */
fsinfo_attr_volume_name = 9, /* Volume name (string) */
fsinfo_attr_cell_name = 10, /* Cell name (string) */
fsinfo_attr_domain_name = 11, /* Domain name (string) */
fsinfo_attr_realm_name = 12, /* Realm name (string) */
fsinfo_attr_server_name = 13, /* Name of the Nth server */
fsinfo_attr_server_address = 14, /* Mth address of the Nth server */
fsinfo_attr_error_state = 15, /* Error state */
fsinfo_attr_parameter = 16, /* Nth mount parameter (string) */
fsinfo_attr_source = 17, /* Nth mount source name (string) */
fsinfo_attr_name_encoding = 18, /* Filename encoding (string) */
fsinfo_attr_name_codepage = 19, /* Filename codepage (string) */
fsinfo_attr_io_size = 20, /* Optimal I/O sizes */
fsinfo_attr__nr
};
struct fsinfo_params {
enum fsinfo_attribute request; /* What is being asking for */
__u32 Nth; /* Instance of it (some may have multiple) */
__u32 Mth; /* Subinstance of Nth instance */
__u32 at_flags; /* AT_SYMLINK_NOFOLLOW and similar flags */
__u32 __reserved[6]; /* Reserved params; all must be 0 */
};struct fsinfo_statfs {
__u64 f_blocks; /* Total number of blocks in fs */
__u64 f_bfree; /* Total number of free blocks */
__u64 f_bavail; /* Number of free blocks available to ordinary user */
__u64 f_files; /* Total number of file nodes in fs */
__u64 f_ffree; /* Number of free file nodes */
__u64 f_favail; /* Number of free file nodes available to ordinary user */
__u32 f_bsize; /* Optimal block size */
__u32 f_frsize; /* Fragment size */
};
struct fsinfo_ids {
char f_fs_name[15 + 1];
__u64 f_flags; /* Filesystem mount flags (MS_*) */
__u64 f_fsid; /* Short 64-bit Filesystem ID (as statfs) */
__u64 f_sb_id; /* Internal superblock ID for sbnotify()/mntnotify() */
__u32 f_fstype; /* Filesystem type from linux/magic.h [uncond] */
__u32 f_dev_major; /* As st_dev_* from struct statx [uncond] */
__u32 f_dev_minor;
};struct fsinfo_limits {
__u64 max_file_size; /* Maximum file size */
__u64 max_uid; /* Maximum UID supported */
__u64 max_gid; /* Maximum GID supported */
__u64 max_projid; /* Maximum project ID supported */
__u32 max_dev_major; /* Maximum device major representable */
__u32 max_dev_minor; /* Maximum device minor representable */
__u32 max_hard_links; /* Maximum number of hard links on a file */
__u32 max_xattr_body_len; /* Maximum xattr content length */
__u16 max_xattr_name_len; /* Maximum xattr name length */
__u16 max_filename_len; /* Maximum filename length */
__u16 max_symlink_len; /* Maximum symlink content length */
__u16 __spare;
};struct fsinfo_supports {
__u64 supported_stx_attributes; /* What statx::stx_attributes are supported */
__u32 supported_stx_mask; /* What statx::stx_mask bits are supported */
__u32 supported_ioc_flags; /* What FS_IOC_* flags are supported */
};
enum fsinfo_capability {
fsinfo_cap_is_kernel_fs = 0, /* fs is kernel-special filesystem */
fsinfo_cap_is_block_fs = 1, /* fs is block-based filesystem */
fsinfo_cap_is_flash_fs = 2, /* fs is flash filesystem */
fsinfo_cap_is_network_fs = 3, /* fs is network filesystem */
fsinfo_cap_is_automounter_fs = 4, /* fs is automounter special filesystem */
fsinfo_cap_automounts = 5, /* fs supports automounts */
fsinfo_cap_adv_locks = 6, /* fs supports advisory file locking */
fsinfo_cap_mand_locks = 7, /* fs supports mandatory file locking */
fsinfo_cap_leases = 8, /* fs supports file leases */
fsinfo_cap_uids = 9, /* fs supports numeric uids */
fsinfo_cap_gids = 10, /* fs supports numeric gids */
fsinfo_cap_projids = 11, /* fs supports numeric project ids */
fsinfo_cap_id_names = 12, /* fs supports user names */
fsinfo_cap_id_guids = 13, /* fs supports user guids */
fsinfo_cap_windows_attrs = 14, /* fs has windows attributes */
fsinfo_cap_user_quotas = 15, /* fs has per-user quotas */
fsinfo_cap_group_quotas = 16, /* fs has per-group quotas */
fsinfo_cap_project_quotas = 17, /* fs has per-project quotas */
fsinfo_cap_xattrs = 18, /* fs has xattrs */
fsinfo_cap_journal = 19, /* fs has a journal */
fsinfo_cap_data_is_journalled = 20, /* fs is using data journalling */
fsinfo_cap_o_sync = 21, /* fs supports O_SYNC */
fsinfo_cap_o_direct = 22, /* fs supports O_DIRECT */
fsinfo_cap_volume_id = 23, /* fs has a volume ID */
fsinfo_cap_volume_uuid = 24, /* fs has a volume UUID */
fsinfo_cap_volume_name = 25, /* fs has a volume name */
fsinfo_cap_volume_fsid = 26, /* fs has a volume FSID */
fsinfo_cap_cell_name = 27, /* fs has a cell name */
fsinfo_cap_domain_name = 28, /* fs has a domain name */
fsinfo_cap_realm_name = 29, /* fs has a realm name */
fsinfo_cap_iver_all_change = 30, /* i_version represents data + meta changes */
fsinfo_cap_iver_data_change = 31, /* i_version represents data changes only */
fsinfo_cap_iver_mono_incr = 32, /* i_version incremented monotonically */
fsinfo_cap_symlinks = 33, /* fs supports symlinks */
fsinfo_cap_hard_links = 34, /* fs supports hard links */
fsinfo_cap_hard_links_1dir = 35, /* fs supports hard links in same dir only */
fsinfo_cap_device_files = 36, /* fs supports bdev, cdev */
fsinfo_cap_unix_specials = 37, /* fs supports pipe, fifo, socket */
fsinfo_cap_resource_forks = 38, /* fs supports resource forks/streams */
fsinfo_cap_name_case_indep = 39, /* Filename case independence is mandatory */
fsinfo_cap_name_non_utf8 = 40, /* fs has non-utf8 names */
fsinfo_cap_name_has_codepage = 41, /* fs has a filename codepage */
fsinfo_cap_sparse = 42, /* fs supports sparse files */
fsinfo_cap_not_persistent = 43, /* fs is not persistent */
fsinfo_cap_no_unix_mode = 44, /* fs does not support unix mode bits */
fsinfo_cap_has_atime = 45, /* fs supports access time */
fsinfo_cap_has_btime = 46, /* fs supports birth/creation time */
fsinfo_cap_has_ctime = 47, /* fs supports change time */
fsinfo_cap_has_mtime = 48, /* fs supports modification time */
fsinfo_cap__nr
};
struct fsinfo_capabilities {
__u8 capabilities[(fsinfo_cap__nr + 7) / 8];
};struct fsinfo_timestamp_info {
__s64 minimum_timestamp; /* Minimum timestamp value in seconds */
__s64 maximum_timestamp; /* Maximum timestamp value in seconds */
__u16 atime_gran_mantissa; /* Granularity(secs) = mant * 10^exp */
__u16 btime_gran_mantissa;
__u16 ctime_gran_mantissa;
__u16 mtime_gran_mantissa;
__s8 atime_gran_exponent;
__s8 btime_gran_exponent;
__s8 ctime_gran_exponent;
__s8 mtime_gran_exponent;
};struct fsinfo_volume_uuid {
__u8 uuid[16];
};struct fsinfo_server_address {
struct __kernel_sockaddr_storage address;
};struct fsinfo_error_state {
__u32 io_error; /* General I/O error counter */
__u32 wb_error; /* Writeback error counter */
__u32 bdev_error; /* Blockdev error counter */
};struct fsinfo_io_size {
__u32 block_size; /* Minimum block granularity for O_DIRECT */
__u32 max_single_read_size; /* Maximum size of a single unbuffered read */
__u32 max_single_write_size; /* Maximum size of a single unbuffered write */
__u32 best_read_size; /* Optimal read size */
__u32 best_write_size; /* Optimal write size */
};
struct fsinfo_fsinfo {
enum fsinfo_attribute max_attr; /* Number of supported attributes */
enum fsinfo_capability max_cap; /* Number of supported capabilities */
};
/*****************************************************************************/ /*****************************************************************************/ /*****************************************************************************/ static __attribute__((unused))ssize_t fsinfo(int dfd, const char *filename, struct fsinfo_params *params,
void *buffer, size_t buf_size)
{
return syscall(__NR_fsinfo, dfd, filename, params, buffer, buf_size);
}#define FSINFO_STRING(N) [fsinfo_attr_##N] = 0x00
#define FSINFO_STRUCT(N) [fsinfo_attr_##N] = sizeof(struct fsinfo_##N)/sizeof(__u32)
#define FSINFO_STRING_N(N) [fsinfo_attr_##N] = 0x40
#define FSINFO_STRUCT_N(N) [fsinfo_attr_##N] = 0x40 | sizeof(struct fsinfo_##N)/sizeof(__u32)
#define FSINFO_STRUCT_NM(N) [fsinfo_attr_##N] = 0x80 | sizeof(struct fsinfo_##N)/sizeof(__u32)
static const __u8 fsinfo_buffer_sizes[fsinfo_attr__nr] = {
FSINFO_STRUCT (statfs),
FSINFO_STRUCT (fsinfo),
FSINFO_STRUCT (ids),
FSINFO_STRUCT (limits),
FSINFO_STRUCT (supports),
FSINFO_STRUCT (capabilities),
FSINFO_STRUCT (timestamp_info),
FSINFO_STRING (volume_id),
FSINFO_STRUCT (volume_uuid),
FSINFO_STRING (volume_name),
FSINFO_STRING (cell_name),
FSINFO_STRING (domain_name),
FSINFO_STRING (realm_name),
FSINFO_STRING_N (server_name),
FSINFO_STRUCT_NM (server_address),
FSINFO_STRUCT (error_state),
FSINFO_STRING_N (parameter),
FSINFO_STRING_N (source),
FSINFO_STRING (name_encoding),
FSINFO_STRING (name_codepage),
FSINFO_STRUCT (io_size),
};#define FSINFO_NAME(N) [fsinfo_attr_##N] = #N static const char *fsinfo_attr_names[fsinfo_attr__nr] = {
FSINFO_NAME(statfs), FSINFO_NAME(fsinfo),
FSINFO_NAME(ids),
FSINFO_NAME(limits), FSINFO_NAME(supports), FSINFO_NAME(capabilities), FSINFO_NAME(timestamp_info), FSINFO_NAME(volume_id), FSINFO_NAME(volume_uuid), FSINFO_NAME(volume_name), FSINFO_NAME(cell_name), FSINFO_NAME(domain_name), FSINFO_NAME(realm_name), FSINFO_NAME(server_name), FSINFO_NAME(server_address), FSINFO_NAME(error_state), FSINFO_NAME(parameter), FSINFO_NAME(source), FSINFO_NAME(name_encoding), FSINFO_NAME(name_codepage), FSINFO_NAME(io_size),
};
union reply {
char buffer[4096];
struct fsinfo_statfs statfs;
struct fsinfo_fsinfo fsinfo;
struct fsinfo_ids ids;
struct fsinfo_limits limits;
struct fsinfo_supports supports;
struct fsinfo_capabilities caps;
struct fsinfo_timestamp_info timestamps;
struct fsinfo_volume_uuid uuid;
struct fsinfo_server_address srv_addr;
struct fsinfo_error_state errors;
struct fsinfo_io_size io_size;
};/*
* Dump as hex.
*/
static void dump_hex(unsigned int *data, int from, int to)
{
unsigned offset, print_offset = 1, col = 0;
from /= 4;
to = (to + 3) / 4;
for (offset = from; offset < to; offset++) {
if (print_offset) {
printf("%04x: ", offset * 8);
print_offset = 0;
}
printf("%08x", data[offset]);
col++;
if ((col & 3) == 0) {
printf("\n");
print_offset = 1;
} else {
printf(" ");
}
}
if (!print_offset)
printf("\n");
}#if 0
static void dump_fsinfo(struct fsinfo *f)
{
printf("ioc : %llx\n", (unsigned long long)f->f_supported_ioc_flags);
if (f->f_mask & FSINFO_VOLUME_ID) {
int printable = 1, loop;
printf("volid : ");
for (loop = 0; loop < sizeof(f->f_volume_id); loop++)
if (!isprint(f->f_volume_id[loop]))
printable = 0;
if (printable) {
printf("'%.*s'", 16, f->f_volume_id);
} else {
for (loop = 0; loop < sizeof(f->f_volume_id); loop++) {
if (loop % 4 == 0 && loop != 0)
printf(" ");
printf("%02x", f->f_volume_id[loop]);
}
}
printf("\n");
}
}#endif
static void dump_attr_statfs(union reply *r, int size)
{
struct fsinfo_statfs *f = &r->statfs;
printf("\tblocks: n=%llu fr=%llu av=%llu\n",
(unsigned long long)f->f_blocks,
(unsigned long long)f->f_bfree,
(unsigned long long)f->f_bavail);
printf("\tfiles : n=%llu fr=%llu av=%llu\n",
(unsigned long long)f->f_files,
(unsigned long long)f->f_ffree,
(unsigned long long)f->f_favail);
printf("\tbsize : %u\n", f->f_bsize);
printf("\tfrsize: %u\n", f->f_frsize);
}static void dump_attr_fsinfo(union reply *r, int size)
{
struct fsinfo_fsinfo *f = &r->fsinfo;
printf("max_attr=%u max_cap=%u\n", f->max_attr, f->max_cap);
}static void dump_attr_ids(union reply *r, int size)
{
struct fsinfo_ids *f = &r->ids;
printf("dev : %02x:%02x\n", f->f_dev_major, f->f_dev_minor);
printf("\tfs : type=%x name=%s\n", f->f_fstype, f->f_fs_name);
printf("\tflags : %llx\n", (unsigned long long)f->f_flags);
printf("\tfsid : %llx\n", (unsigned long long)f->f_fsid);
}static void dump_attr_limits(union reply *r, int size)
{
struct fsinfo_limits *f = &r->limits;
printf("max file size: %llx\n", f->max_file_size);
}static void dump_attr_supports(union reply *r, int size)
{
struct fsinfo_supports *f = &r->supports;
printf("stx_attr=%llx\n", f->supported_stx_attributes);
}#define FSINFO_CAP_NAME(C) [fsinfo_cap_##C] = #C
static const char *fsinfo_cap_names[fsinfo_cap__nr] = {
FSINFO_CAP_NAME(is_kernel_fs),
FSINFO_CAP_NAME(is_block_fs),
FSINFO_CAP_NAME(is_flash_fs),
FSINFO_CAP_NAME(is_network_fs),
FSINFO_CAP_NAME(is_automounter_fs),
FSINFO_CAP_NAME(automounts),
FSINFO_CAP_NAME(adv_locks),
FSINFO_CAP_NAME(mand_locks),
FSINFO_CAP_NAME(leases),
FSINFO_CAP_NAME(uids),
FSINFO_CAP_NAME(gids),
FSINFO_CAP_NAME(projids),
FSINFO_CAP_NAME(id_names),
FSINFO_CAP_NAME(id_guids),
FSINFO_CAP_NAME(windows_attrs),
FSINFO_CAP_NAME(user_quotas),
FSINFO_CAP_NAME(group_quotas),
FSINFO_CAP_NAME(project_quotas),
FSINFO_CAP_NAME(xattrs),
FSINFO_CAP_NAME(journal),
FSINFO_CAP_NAME(data_is_journalled),
FSINFO_CAP_NAME(o_sync),
FSINFO_CAP_NAME(o_direct),
FSINFO_CAP_NAME(volume_id),
FSINFO_CAP_NAME(volume_uuid),
FSINFO_CAP_NAME(volume_name),
FSINFO_CAP_NAME(volume_fsid),
FSINFO_CAP_NAME(cell_name),
FSINFO_CAP_NAME(domain_name),
FSINFO_CAP_NAME(realm_name),
FSINFO_CAP_NAME(iver_all_change),
FSINFO_CAP_NAME(iver_data_change),
FSINFO_CAP_NAME(iver_mono_incr),
FSINFO_CAP_NAME(symlinks),
FSINFO_CAP_NAME(hard_links),
FSINFO_CAP_NAME(hard_links_1dir),
FSINFO_CAP_NAME(device_files),
FSINFO_CAP_NAME(unix_specials),
FSINFO_CAP_NAME(resource_forks),
FSINFO_CAP_NAME(name_case_indep),
FSINFO_CAP_NAME(name_non_utf8),
FSINFO_CAP_NAME(name_has_codepage),
FSINFO_CAP_NAME(sparse),
FSINFO_CAP_NAME(not_persistent),
FSINFO_CAP_NAME(no_unix_mode),
FSINFO_CAP_NAME(has_atime),
FSINFO_CAP_NAME(has_btime),
FSINFO_CAP_NAME(has_ctime),
FSINFO_CAP_NAME(has_mtime),
};static void dump_attr_capabilities(union reply *r, int size)
{
struct fsinfo_capabilities *f = &r->caps;
int i;
for (i = 0; i < sizeof(f->capabilities); i++)
printf("%02x", f->capabilities[i]);
printf("\n");
for (i = 0; i < fsinfo_cap__nr; i++)
if (f->capabilities[i / 8] & (1 << (i % 8)))
printf("\t- %s\n", fsinfo_cap_names[i]);
}static void dump_attr_timestamp_info(union reply *r, int size)
{
struct fsinfo_timestamp_info *f = &r->timestamps;
printf("range=%llx-%llx\n",
(unsigned long long)f->minimum_timestamp,
(unsigned long long)f->maximum_timestamp);#define print_time(G) \
printf("\t"#G"time : gran=%gs\n", \
(f->G##time_gran_mantissa * \
pow(10., f->G##time_gran_exponent)))
print_time(a);
print_time(b);
print_time(c);
print_time(m);
}static void dump_attr_volume_uuid(union reply *r, int size)
{
struct fsinfo_volume_uuid *f = &r->uuid;
printf("%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x"
"-%02x%02x%02x%02x%02x%02x\n",
f->uuid[ 0], f->uuid[ 1],
f->uuid[ 2], f->uuid[ 3],
f->uuid[ 4], f->uuid[ 5],
f->uuid[ 6], f->uuid[ 7],
f->uuid[ 8], f->uuid[ 9],
f->uuid[10], f->uuid[11],
f->uuid[12], f->uuid[13],
f->uuid[14], f->uuid[15]);
}static void dump_attr_server_address(union reply *r, int size)
{
struct fsinfo_server_address *f = &r->srv_addr;
printf("family=%u\n", f->address.ss_family);
}static void dump_attr_error_state(union reply *r, int size)
{
struct fsinfo_error_state *f = &r->errors;
printf("io=%u wb=%u bdev=%u\n", f->io_error, f->wb_error, f->bdev_error);
}static void dump_attr_io_size(union reply *r, int size)
{
struct fsinfo_io_size *f = &r->io_size;
printf("bs=%u\n", f->block_size);
}/*
*
*/
typedef void (*dumper_t)(union reply *r, int size);
#define FSINFO_DUMPER(N) [fsinfo_attr_##N] = dump_attr_##N static const dumper_t fsinfo_attr_dumper[fsinfo_attr__nr] = {
FSINFO_DUMPER(statfs), FSINFO_DUMPER(fsinfo),
FSINFO_DUMPER(ids),
FSINFO_DUMPER(limits), FSINFO_DUMPER(supports), FSINFO_DUMPER(capabilities), FSINFO_DUMPER(timestamp_info), FSINFO_DUMPER(volume_uuid), FSINFO_DUMPER(server_address), FSINFO_DUMPER(error_state), FSINFO_DUMPER(io_size),
};
static void dump_fsinfo(enum fsinfo_attribute attr, __u8 about,
union reply *r, int size)
{
dumper_t dumper = fsinfo_attr_dumper[attr];
unsigned int len;
if (!dumper) {
printf("<no dumper>\n");
return;
}
len = (about & 0x3f) * sizeof(__u32);
if (size < len) {
printf("<short data %u/%u>\n", size, len);
return;
}
dumper(r, size);
}/*
* Try one subinstance of an attribute.
*/
static int try_one(const char *file, struct fsinfo_params *params, bool raw)
{
union reply r;
char *p;
int ret;
__u8 about;
memset(&r.buffer, 0xbd, sizeof(r.buffer));
errno = 0;
ret = fsinfo(AT_FDCWD, file, params, r.buffer, sizeof(r.buffer));
if (params->request >= fsinfo_attr__nr) {
if (ret == -1 && errno == EOPNOTSUPP)
exit(0);
fprintf(stderr, "Unexpected error for too-large command %u: %m\n",
params->request);
exit(1);
}
//printf("fsinfo(%s,%s,%u,%u) = %d: %m\n",
// file, fsinfo_attr_names[params->request],
// params->Nth, params->Mth, ret);
about = fsinfo_buffer_sizes[params->request];
if (ret == -1) {
if (errno == ENODATA) {
switch (about & 0xc0) {
case 0x00:
if (params->Nth == 0 && params->Mth == 0) {
fprintf(stderr,
"Unexpected ENODATA1 (%u[%u][%u])\n",
params->request, params->Nth, params->Mth);
exit(1);
}
break;
case 0x40:
if (params->Nth == 0 && params->Mth == 0) {
fprintf(stderr,
"Unexpected ENODATA2 (%u[%u][%u])\n",
params->request, params->Nth, params->Mth);
exit(1);
}
break;
}
return (params->Mth == 0) ? 2 : 1;
}
if (errno == EOPNOTSUPP) {
if (params->Nth > 0 || params->Mth > 0) {
fprintf(stderr,
"Should return -ENODATA (%u[%u][%u])\n",
params->request, params->Nth, params->Mth);
exit(1);
}
//printf("\e[33m%s\e[m: <not supported>\n",
// fsinfo_attr_names[attr]);
return 2;
}
perror(file);
exit(1);
}
if (raw) {
if (ret > 4096)
ret = 4096;
dump_hex((unsigned int *)&r.buffer, 0, ret);
return 0;
}
switch (about & 0xc0) {
case 0x00:
printf("\e[33m%s\e[m: ", fsinfo_attr_names[params->request]);
break;
case 0x40:
printf("\e[33m%s[%u]\e[m: ",
fsinfo_attr_names[params->request],
params->Nth);
break;
case 0x80:
printf("\e[33m%s[%u][%u]\e[m: ",
fsinfo_attr_names[params->request],
params->Nth, params->Mth);
break;
}
switch (about) {
/* Struct */
case 0x01 ... 0x3f:
case 0x41 ... 0x7f:
case 0x81 ... 0xbf:
dump_fsinfo(params->request, about, &r, ret);
return 0;
/* String */
case 0x00:
case 0x40:
case 0x80:
if (ret >= 4096) {
ret = 4096;
r.buffer[4092] = '.';
r.buffer[4093] = '.';
r.buffer[4094] = '.';
r.buffer[4095] = 0;
} else {
r.buffer[ret] = 0;
}
for (p = r.buffer; *p; p++) {
if (!isprint(*p)) {
printf("<non-printable>\n");
continue;
}
}
printf("%s\n", r.buffer);
return 0;
default:
fprintf(stderr, "Fishy about %u %02x\n", params->request, about);
exit(1);
}
}/*
*
*/
int main(int argc, char **argv)
{
struct fsinfo_params params = {
.at_flags = AT_SYMLINK_NOFOLLOW,
};
unsigned int attr;
int raw = 0, opt, Nth, Mth;
while ((opt = getopt(argc, argv, "alr"))) {
switch (opt) {
case 'a':
params.at_flags |= AT_NO_AUTOMOUNT;
continue;
case 'l':
params.at_flags &= ~AT_SYMLINK_NOFOLLOW;
continue;
case 'r':
raw = 1;
continue;
}
break;
}
argc -= optind;
argv += optind;
if (argc != 1) {
printf("Format: test-fsinfo [-alr] <file>\n");
exit(2);
}
for (attr = 0; attr <= fsinfo_attr__nr; attr++) {
Nth = 0;
do {
Mth = 0;
do {
params.request = attr;
params.Nth = Nth;
params.Mth = Mth;
switch (try_one(argv[0], ¶ms, raw)) {
case 0:
continue;
case 1:
goto done_M;
case 2:
goto done_N;
}
} while (++Mth < 100);
done_M:
if (Mth >= 100) {
fprintf(stderr, "Fishy: Mth == %u\n", Mth);
break;
}
} while (++Nth < 100);
done_N:
if (Nth >= 100) {
fprintf(stderr, "Fishy: Nth == %u\n", Nth);
break;
}
}
return 0;
}Arnd Bergmann
maintainerRe: [PATCH 32/32] [RFC] fsinfo: Add a system call to allow querying of filesystem information [ver #8]
In reply to David HowellsQuoted 10 lines · David Howells
fs/statfs.c +10
-0+ +static int fsinfo_generic_timestamp_info (struct dentry *dentry, +struct fsinfo_timestamp_info *ts) +{ +struct super_block *sb = dentry->d_sb; + +/* If unset, assume 1s granularity */ +u16 mantissa =1 ; +s8 exponent =0 ; +
fs/statfs.c COMPAT_SYSCALL_DEFINE2(ustat, unsigned, dev, struct compat_ustat __user *, u) · line 494
Quoted 10 lines
fs/statfs.c +10
-0+ ts->minimum_timestamp =S64_MIN ; + ts->maximum_timestamp =S64_MAX ; +if (sb->s_time_gran <1000000000 ) { +if (sb->s_time_gran <1000 ) + exponent =-9 ; +else if (sb->s_time_gran <1000000 ) + exponent =-6 ; +else + exponent =-3 ; + }
ntfs has sb->s_time_gran=100, and vfat should really have sb->s_time_gran=2000000000 but that doesn't seem to be set right at the moment.
include/uapi/linux/fsinfo.h line 48
Quoted 12 lines
include/uapi/linux/fsinfo.h new file +12
-0+/* +* Optional fsinfo() parameter structure. +* +* If this is not given, it is assumed that fsinfo_attr_statfs instance 0 is +* desired. +*/ +struct fsinfo_params { +enum fsinfo_attribute request;/* What is being asking for */ +__u32 Nth;/* Instance of it (some may have multiple) */ +__u32 at_flags;/* AT_SYMLINK_NOFOLLOW and similar flags */ +__u32 __spare[6 ];/* Spare params; all must be 0 */ +};
I fear the 'enum' in the uapi structure may have a different size depending on the architecture. Maybe turn that into a __u32 as well?
include/uapi/linux/fsinfo.h line 163
Quoted 6 lines
include/uapi/linux/fsinfo.h new file +6
-0+struct fsinfo_capabilities { +__u64 supported_stx_attributes;/* What statx::stx_attributes are supported */ +__u32 supported_stx_mask;/* What statx::stx_mask bits are supported */ +__u32 supported_ioc_flags;/* What FS_IOC_* flags are supported */ +__u8 capabilities[(fsinfo_cap__nr +7 ) /8 ]; +};
This looks a bit odd: with the 44 capabilities, you end up having a six-byte array
followed by two bytes of implicit padding. If the number of capabilities grows beyond
64, you have a nine byte array with more padding to the next alignof(__u64). Is that intentional?
How about making it a fixed size with either 64 or 128 capability bits?
Quoted 5 lines
include/uapi/linux/fsinfo.h new file +5
-0+/* +* Information struct for fsinfo(fsinfo_attr_timestamp_info). +*/ +struct fsinfo_timestamp_info { +__s64 minimum_timestamp;/* Minimum timestamp value in seconds */
include/uapi/linux/fsinfo.h line 179
Quoted 10 lines
include/uapi/linux/fsinfo.h new file +10
-0+__s64 maximum_timestamp;/* Maximum timestamp value in seconds */ +__u16 atime_gran_mantissa;/* Granularity(secs) = mant * 10^exp */ +__u16 btime_gran_mantissa; +__u16 ctime_gran_mantissa; +__u16 mtime_gran_mantissa; +__s8 atime_gran_exponent; +__s8 btime_gran_exponent; +__s8 ctime_gran_exponent; +__s8 mtime_gran_exponent; +};
This structure has a slightly inconsistent amount of padding at the end:
on x86-32 it has no padding, everywhere else it has 32 bits of padding to make it 64-bit aligned. Maybe add a __u32 reserved field?
samples/statx/test-fsinfo.c line 28
Quoted 2 lines
samples/statx/test-fsinfo.c new file +2
-0+ +#define __NR_fsinfo 326
Hardcoding the syscall number in the example makes it architecture specific. Could you include <asm/unistd.h> to get the real number?
Arnd
David Howells
maintainerRe: [PATCH 32/32] [RFC] fsinfo: Add a system call to allow querying of filesystem information [ver #8]
Quoted 3 lines · Arnd Bergmann
ntfs has sb->s_time_gran=100, and vfat should really have sb->s_time_gran=2000000000 but that doesn't seem to be set right at the moment.
(V)FAT actually has a different granularity on each timestamp.
Quoted 2 lines
I fear the 'enum' in the uapi structure may have a different size depending on the architecture. Maybe turn that into a
__u32as well?
Fair enough. Done.
Quoted 11 lines
Review
Quoted 6 lines
(quoted diff) +6
-0+struct fsinfo_capabilities { + __u64 supported_stx_attributes; /* What statx::stx_attributes are supported */ + __u32 supported_stx_mask; /* What statx::stx_mask bits are supported */ + __u32 supported_ioc_flags; /* What FS_IOC_* flags are supported */ + __u8 capabilities[(fsinfo_cap__nr + 7) / 8]; +};This looks a bit odd: with the 44 capabilities, you end up having a six-byte array followed by two bytes of implicit padding. If the number of capabilities grows beyond 64, you have a nine byte array with more padding to the next
alignof(__u64). Is that intentional?
I've split the capabilities out into their own thing. I've attached the revised patch below.
Quoted 8 lines
Quoted 8 lines
(quoted diff) +8
-0+struct fsinfo_timestamp_info { + __s64 minimum_timestamp; /* Minimum timestamp value in seconds */ + __s64 maximum_timestamp; /* Maximum timestamp value in seconds */ + __u16 atime_gran_mantissa; /* Granularity(secs) = mant * 10^exp */ + __u16 btime_gran_mantissa; + __u16 ctime_gran_mantissa; + __u16 mtime_gran_mantissa; + __s8 atime_gran_exponent;
Quoted 8 lines
Review
Quoted 4 lines
(quoted diff) +4
-0+ __s8 btime_gran_exponent; + __s8 ctime_gran_exponent; + __s8 mtime_gran_exponent; +};This structure has a slightly inconsistent amount of padding at the end:
on x86-32 it has no padding, everywhere else it has 32 bits of padding to make it 64-bit aligned. Maybe add a__u32reserved field?
It occurs to me that the min and max may be different for each timestamp. Maybe I should have:
struct fsinfo_timestamp_info {
char name[7 + 1];
__s64 minimum_timestamp;
__s64 maximum_timestamp;
__u16 granularity_mantissa;
__s8 granularity_exponent;
__u8 __reserved[5];
};and then you iterate through them by setting Nth. I could just put a:
__u64 granularity;
field, expressed in nS, rather than mantissa and exponent, but doing it this way allows me to express granularities less that 1nS very simply (something Dave Chinner was talking about).
It might also be worth putting minimum_timestamp and maximum_timestamp in terms of granularity rather than nS.
Quoted 4 lines
Quoted 1 line
+#define
__NR_fsinfo326Hardcoding the syscall number in the example makes it architecture specific. Could you include <
asm/unistd.h> to get the real number?
Yeah, I've fixed that already.
David
---
commit 61ad926e92c6985acd7093e7349c8480e3b1f827
Author: David Howells <[email protected]> Date: Thu May 31 22:53:51 2018 +0100
fsinfo: Add a system call to allow querying of filesystem information
Add a system call to allow filesystem information to be queried. This is implemented as a function switch where the desired attribute value or values is nominated.
===============
NEW SYSTEM CALL
===============
The new system call looks like:
int ret = fsinfo(int dfd,
const char *filename, const struct fsinfo_params *params, void *buffer,
size_t buf_size);
The params parameter optionally points to a block of parameters:
struct fsinfo_params {
enum fsinfo_attribute request;
__u32 Nth;
__u32 Mth;
__u32 at_flags;
__u32 __reserved[6];
};
If params is NULL, it is assumed params->request should be fsinfo_attr_statfs, params->Nth should be 0, params->Mth should be 0 and params->at_flags should be 0.
If params is given, all of params->__reserved[] must be 0.
dfd, filename and params->at_flags indicate the file to query. There is no equivalent of lstat() as that can be emulated with fsinfo() by setting AT_SYMLINK_NOFOLLOW in params->at_flags. There is also no equivalent of fstat() as that can be emulated by passing a NULL filename to fsinfo() with the fd of interest in dfd. AT_NO_AUTOMOUNT can also be used to an allow automount point to be queried without triggering it.
AT_FORCE_ATTR_SYNC can be set in params->at_flags. This will require a network filesystem to synchronise its attributes with the server.
AT_NO_ATTR_SYNC can be set in params->at_flags. This will suppress synchronisation with the server in a network filesystem. The resulting values should be considered approximate.
params->request indicates the attribute/attributes to be queried. This can be one of:
fsinfo_attr_statfs - statfs-style info
fsinfo_attr_fsinfo - Information about fsinfo()
fsinfo_attr_ids - Filesystem IDs
fsinfo_attr_limits - Filesystem limits
fsinfo_attr_supports - What's supported in statx(), IOC flags
fsinfo_attr_capabilities - Filesystem capabilities
fsinfo_attr_timestamp_info - Inode timestamp info
fsinfo_attr_volume_id - Volume ID (string)
fsinfo_attr_volume_uuid - Volume UUID
fsinfo_attr_volume_name - Volume name (string)
fsinfo_attr_cell_name - Cell name (string)
fsinfo_attr_domain_name - Domain name (string)
fsinfo_attr_realm_name - Realm name (string)
fsinfo_attr_server_name - Name of the Nth server (string)
fsinfo_attr_server_address - Mth address of the Nth server
fsinfo_attr_parameter - Nth mount parameter (string)
fsinfo_attr_source - Nth mount source name (string)
fsinfo_attr_name_encoding - Filename encoding (string)
fsinfo_attr_name_codepage - Filename codepage (string)
fsinfo_attr_io_size - Optimal I/O sizes
Some attributes (such as the servers backing a network filesystem) can have multiple values. These can be enumerated by setting params->Nth and params->Mth to 0, 1, ... until ENODATA is returned.
buffer and buf_size point to the reply buffer. The buffer is filled up to the specified size, even if this means truncating the reply. The full size of the reply is returned. In future versions, this will allow extra fields to be tacked on to the end of the reply, but anyone not expecting them will only get the subset they're expecting. If either buffer of buf_size are 0, no copy will take place and the data size will be returned.
At the moment, this will only work on x86_64 and i386 as it requires the system call to be wired up.
arch/x86/entry/syscalls/syscall_32.tbl +1 -0
@@ -401,4 +401,5 @@ 387 i386 fsmount sys_fsmount __ia32_sys_fsmount 388 i386 fspick sys_fspick __ia32_sys_fspick 389 i386 move_mount sys_move_mount __ia32_sys_move_mount +390 i386 fsinfo sys_fsinfo __ia32_sys_fsinfo 391 i386 open_tree sys_open_tree __ia32_sys_open_tree
arch/x86/entry/syscalls/syscall_64.tbl +1 -0
@@ -346,6 +346,7 @@ 335 common fsmount __x64_sys_fsmount 336 common fspick __x64_sys_fspick 337 common move_mount __x64_sys_move_mount +338 common fsinfo __x64_sys_fsinfo 339 common open_tree __x64_sys_open_tree #
fs/statfs.c +467 -0
476 lines not on this page · raw message
include/linux/fs.h +4 -0
@@ -62,6 +62,8 @@ struct iov_iter;struct fscrypt_info ;struct fscrypt_operations ;struct fs_context ; +struct fsinfo_kparams ; +enum fsinfo_attribute ;extern void __init inode_init (void );extern void __init inode_init_early (void );
@@ -1840,6 +1842,7 @@ struct super_operations {int (*thaw_super) (struct super_block *);int (*unfreeze_fs) (struct super_block *);int (*statfs) (struct dentry *,struct kstatfs *); +int (*get_fsinfo) (struct dentry *,struct fsinfo_kparams *);int (*remount_fs) (struct super_block *,int *,char *,size_t );int (*reconfigure) (struct super_block *,struct fs_context *);void (*umount_begin) (struct super_block *);
@@ -2216,6 +2219,7 @@ extern int iterate_mounts(int (*)(struct vfsmount *, void *), void *,extern int vfs_statfs (const struct path *,struct kstatfs *);extern int user_statfs (const char __user *,struct kstatfs *);extern int fd_statfs (int ,struct kstatfs *); +extern int vfs_fsinfo (const struct path *,struct fsinfo_kparams *);extern int freeze_super (struct super_block *super);extern int thaw_super (struct super_block *super);extern bool our_mnt (struct vfsmount *mnt);
include/linux/fsinfo.h new file +40 -0
@@ -0,0 +1,40 @@ +/* Filesystem information query +* +* Copyright (C) 2018 Red Hat, Inc. All Rights Reserved. +* Written by David Howells ([email protected]) +* +* This program is free software; you can redistribute it and/or +* modify it under the terms of the GNU General Public Licence +* as published by the Free Software Foundation; either version +* 2 of the Licence, or (at your option) any later version. +*/ + +#ifndef _LINUX_FSINFO_H +#define _LINUX_FSINFO_H + +#include <uapi/linux/fsinfo.h> + +struct fsinfo_kparams { +enum fsinfo_attribute request;/* What is being asking for */ +__u32 Nth;/* Instance of it (some may have multiple) */ +__u32 Mth;/* Subinstance */ +__u32 at_flags;/* AT_SYMLINK_NOFOLLOW and similar */ +void *buffer;/* Where to place the reply */ +size_t buf_size;/* Size of the buffer */ +}; + +extern int generic_fsinfo (struct dentry *,struct fsinfo_kparams *); + +static inline void fsinfo_set_cap (struct fsinfo_capabilities *c, +enum fsinfo_capability cap) +{ + c->capabilities[cap /8 ] |=1 << (cap %8 ); +} + +static inline void fsinfo_clear_cap (struct fsinfo_capabilities *c, +enum fsinfo_capability cap) +{ + c->capabilities[cap /8 ] &= ~(1 << (cap %8 )); +} + +#endif /* _LINUX_FSINFO_H */
include/linux/syscalls.h +4 -0
@@ -49,6 +49,7 @@ struct stat64;struct statfs ;struct statfs64 ;struct statx ; +struct fsinfo_params ;struct __sysctl_args ;struct sysinfo ;struct timespec ;
@@ -905,6 +906,9 @@ asmlinkage long sys_fspick(int dfd, const char __user *path, unsigned int at_flaasmlinkage long sys_move_mount (int from_dfd,const char __user *from_path,int to_dfd,const char __user *to_path,unsigned int ms_flags); +asmlinkage long sys_fsinfo (int dfd,const char __user *path, +struct fsinfo_params __user *params, +void __user *buffer,size_t buf_size);/* * Architecture-specific system calls
include/uapi/linux/fsinfo.h new file +235 -0
235 lines not on this page · raw message
samples/statx/Makefile +4 -1
@@ -1,7 +1,10 @@ # List of programs to build -hostprogs-$(CONFIG_SAMPLE_STATX) := test-statx +hostprogs-$(CONFIG_SAMPLE_STATX) := test-statx test-fsinfo # Tell kbuild to always build the programs always := $(hostprogs-y) HOSTCFLAGS_test-statx.o += -I$(objtree)/usr/include + +HOSTCFLAGS_test-fsinfo.o += -I$(objtree)/usr/include +HOSTLOADLIBES_test-fsinfo += -lm
samples/statx/test-fsinfo.c new file +538 -0
538 lines not on this page · raw message
Arnd Bergmann
maintainerRe: [PATCH 32/32] [RFC] fsinfo: Add a system call to allow querying of filesystem information [ver #8]
Quoted 7 lines · David Howells
Quoted 3 lines · Arnd Bergmann
ntfs has sb->s_time_gran=100, and vfat should really have sb->s_time_gran=2000000000 but that doesn't seem to be set right at the moment.
(V)FAT actually has a different granularity on each timestamp.
Ah, right. I guess I missed the fact that the file system can override it, so FAT doesn't actually have to do it this way.
Quoted 12 lines
Quoted 11 lines
include/uapi/linux/fsinfo.h line 177
Quoted 6 lines
include/uapi/linux/fsinfo.h new file +6
-0+struct fsinfo_capabilities { +__u64 supported_stx_attributes;/* What statx::stx_attributes are supported */ +__u32 supported_stx_mask;/* What statx::stx_mask bits are supported */ +__u32 supported_ioc_flags;/* What FS_IOC_* flags are supported */ +__u8 capabilities[(fsinfo_cap__nr +7 ) /8 ]; +};This looks a bit odd: with the 44 capabilities, you end up having a six-byte array followed by two bytes of implicit padding. If the number of capabilities grows beyond 64, you have a nine byte array with more padding to the next
alignof(__u64). Is that intentional?
Quoted 2 lines
I've split the capabilities out into their own thing. I've attached the revised patch below.
I'm still not completely clear on how variable-length structures are supposed to be handled by the fsinfo syscall. It seems like a possible source of bugs to return
a structure from the kernel that has a different size in kernel and user space depending on the fsinfo_cap__nr value at compile time. How does one e.g. guarantee there is no out of bounds access when you run new user space on an older kernel that has a smaller structure?
Quoted 20 lines
Quoted 8 lines
Quoted 8 lines
include/uapi/linux/fsinfo.h new file +8
-0+struct fsinfo_timestamp_info { +__s64 minimum_timestamp;/* Minimum timestamp value in seconds */ +__s64 maximum_timestamp;/* Maximum timestamp value in seconds */ +__u16 atime_gran_mantissa;/* Granularity(secs) = mant * 10^exp */ +__u16 btime_gran_mantissa; +__u16 ctime_gran_mantissa; +__u16 mtime_gran_mantissa; +__s8 atime_gran_exponent;Quoted 8 lines
include/uapi/linux/fsinfo.h line 194
Quoted 4 lines
include/uapi/linux/fsinfo.h new file +4
-0+__s8 btime_gran_exponent; +__s8 ctime_gran_exponent; +__s8 mtime_gran_exponent; +};This structure has a slightly inconsistent amount of padding at the end:
on x86-32 it has no padding, everywhere else it has 32 bits of padding to make it 64-bit aligned. Maybe add a__u32reserved field?It occurs to me that the min and max may be different for each timestamp. Maybe I should have:
Quoted 9 lines
struct fsinfo_timestamp_info {
char name[7 + 1];
__s64 minimum_timestamp;
__s64 maximum_timestamp;
__u16 granularity_mantissa;
__s8 granularity_exponent;
__u8 __reserved[5];
};I don't particularly like having a string in there, that seems to add unnecessary complexity compared to using an integer. Having four min/max values would make it more generic but I don't think we have a need for that at the moment with any of the file systems we support.
In any case, it would be nice to have a trivial way to query which of the four timestamp types are supported at all, and returning them separately would be one way of doing that.
Quoted 10 lines
and then you iterate through them by setting Nth. I could just put a:
__u64 granularity;field, expressed in nS, rather than mantissa and exponent, but doing it this way allows me to express granularities less that 1nS very simply (something Dave Chinner was talking about).
It might also be worth putting
minimum_timestampandmaximum_timestampin terms of granularity rather than nS.
Expressing the granularity in nanoseconds (or something smaller) would seem more natural to me, but I don't really care much either way.
Arnd
David Howells
maintainerRe: [PATCH 32/32] [RFC] fsinfo: Add a system call to allow querying of filesystem information [ver #8]
Quoted 9 lines · Arnd Bergmann
Quoted 2 lines
I've split the capabilities out into their own thing. I've attached the revised patch below.
I'm still not completely clear on how variable-length structures are supposed to be handled by the fsinfo syscall. It seems like a possible source of bugs to return a structure from the kernel that has a different size in kernel and user space depending on the
fsinfo_cap__nrvalue at compile time. How does one e.g. guarantee there is no out of bounds access when you run new user space on an older kernel that has a smaller structure?
There's a buffer size parameter:
int ret = fsinfo(int dfd,
const char *filename, const struct fsinfo_params *params, void *buffer,
size_t buf_size);
For a fixed-size buffer request (as opposed to a string), the fsinfo syscall allocates an internal buffer sized for the size of the buffer that the internal kernel code is expecting, and *not* what the user asked for:
/* Allocate an appropriately-sized buffer. We will truncate the
* contents when we write the contents back to userspace.
*/
size = fsinfo_buffer_sizes[params.request];
...
if (buf_size > 0) {
params.buf_size = size;
params.buffer = kzalloc(size, GFP_KERNEL);
if (!params.buffer)
return -ENOMEM;
}so that the filesystems don't have to concern themselves with anything other than the kernel's idea of the size.
The fsinfo() syscall truncates the reply buffer to the size the user requested if the user requested a smaller amount. Take the fsinfo_supports struct for example:
struct fsinfo_supports {
__u64 supported_stx_attributes;
__u32 supported_stx_mask;
__u32 supported_ioc_flags;
};Now imagine that in future we want to add another field, say the mask of the windows file attributes a filesystem supports. We can extend the struct like so:
struct fsinfo_supports_v2 {
__u64 supported_stx_attributes;
__u32 supported_stx_mask;
__u32 supported_ioc_flags;
__u32 supported_win_file_atts;
__u32 __reserved[1];
};Note that the start of the new struct *must* correspond in layout to the original struct. An application that doesn't know about v2 would just ask for v1:
struct fsinfo_supports foo; fsinfo(.... &foo, sizeof(foo));
and would only ever get those bits - though it would be told that there is more data available. An application that does know about v2 might do:
struct fsinfo_supports_v2 foo2; fsinfo(.... &foo2, sizeof(foo2));
If all of v2 was available, all fields will be filled in and the return value will == sizeof(foo2). If not all fields are available, the return value will == sizeof(foo). If a v3 was added, the return value would == sizeof(v3), and so on.
I can improve this such that if you asked for a fixed-length option and the kernel doesn't have enough data to fill the user buffer provided, then it clears the remainder of the buffer. That way at least any unsupported fields will be initialised to 0.
For the capabilities bitmask, it's not really any different conceptually. If you want to test capability bit 47, you need to ask for 6 bytes of data. If the kernel doesn't support that many bits, it won't necessarily give you that many bytes. If it has, say, 13 bytes-worth of caps available, it will only give you the first 6 bytes-worth if that's all you ask for. You presumably weren't interested or didn't know about any more than that.
As for strings, they're completely variable length anyway, so I don't think there's a problem there.
Quoted 3 lines
In any case, it would be nice to have a trivial way to query which of the four timestamp types are supported at all, and returning them separately would be one way of doing that.
fsinfo_cap_has_atime = 45, /* fs supports access time */
fsinfo_cap_has_btime = 46, /* fs supports birth/creation time */
fsinfo_cap_has_ctime = 47, /* fs supports change time */
fsinfo_cap_has_mtime = 48, /* fs supports modification time */
David
Arnd Bergmann
maintainerRe: [PATCH 32/32] [RFC] fsinfo: Add a system call to allow querying of filesystem information [ver #8]
Quoted 15 lines · David Howells
Arnd Bergmann <[email protected]> wrote:
Thefsinfo()syscall truncates the reply buffer to the size the user requested if the user requested a smaller amount. Take thefsinfo_supportsstruct for example:struct fsinfo_supports { __u64 supported_stx_attributes; __u32 supported_stx_mask; __u32 supported_ioc_flags; };Now imagine that in future we want to add another field, say the mask of the windows file attributes a filesystem supports. We can extend the struct like so:
Quoted 7 lines
struct fsinfo_supports_v2 {
__u64 supported_stx_attributes;
__u32 supported_stx_mask;
__u32 supported_ioc_flags;
__u32 supported_win_file_atts;
__u32 __reserved[1];
};Looking at the code again, I realized my misunderstanding: I somehow expected the system call to return multiple structures at once, which would get really messy with groups of arrays of variable-sized structures. Since we only really get back a single structure per call, that is not an issue.
There is also no need to be concerned about the system call overhead, right? Even if we query all data from all mounted file systems, I suppose the total number of syscall roundtrips will be small enough that there is no need for complicating the interface to make it slightly faster.
Quoted 4 lines
I can improve this such that if you asked for a fixed-length option and the kernel doesn't have enough data to fill the user buffer provided, then it clears the remainder of the buffer. That way at least any unsupported fields will be initialised to 0.
Yes, I think that would make sense here. It's not quite a read() based interface since the return value for a short read is still the size of the whole buffer that could have been accessed. By zeroing the extra data, the kernel always writes the amount of data that the user asks for, and the return value always shows how much data would have been available.
It might be necessary to limit the size of the buffer though, to prevent bad things from happening when the user asks for e.g. -1ull bytes of data.
Quoted 8 lines
Quoted 3 lines
In any case, it would be nice to have a trivial way to query which of the four timestamp types are supported at all, and returning them separately would be one way of doing that.
fsinfo_cap_has_atime = 45, /* fs supports access time */ fsinfo_cap_has_btime = 46, /* fs supports birth/creation time */ fsinfo_cap_has_ctime = 47, /* fs supports change time */ fsinfo_cap_has_mtime = 48, /* fs supports modification time */
Ok.
Arnd
Quoted 4 lines · David Howells
Here are a set of patches to create a filesystem context prior to setting up a new mount, populating it with the parsed options/binary data, creating the superblock and then effecting the mount. This is also used for remount since much of the parsing stuff is common in many filesystems.
Dave,
I have read through these patches and I noticed a significant issue.
Today in mount_bdev we do something that looks like:
mount_bdev(...)
{
s = sget(..., bdev);
if (s->s_root) {
/* Noop */
} else {
err = fill_super(s, ...);
if (err) {
deactivate_locked_super(s);
return ERR_PTR(err);
}
s->s_flags |= SB_ATTIVE;
bdev->bd_super = s;
}
return dget(s->s_root);
}The key point is that we don't process the mount options at all if a super block already exists in the kernel. Similar to what your fscontext changes are doing (after parsing the options).
Your fscontext changes do not improve upon this area of the mount api at all and that concerns me. This is an area where people can and already do shoot themselves in their feet.
The real world security issue we had in with this involved devpts. The devpts filesystem requires the mode and gid parameters for new ttys to be specified to be posix compliant. People were setting up chroot environments and mounting devpts with the wrong arguments. As these two devpts mounts shared a super block a change of arguments on one was a change of arguments on the other. Which mean the chroots were periodically breaking the primary devpts and causing new terminals to be opened with essentially unusable permissions. Fun when you are trying to ssh in to a box.
Creating a new mount and finding an old mount are the same operation in the kernel today. This is fundamentally confusing. In the new api could we please separate these two operations?
Perhaps someting like:
x create
x find
With the "x create" case failing if the filesystem already exists, still allowing "x find"? And with the "x find" case failing if the superblock is not already created in the kernel.
That should make it clear to a userspace program what is going on and give it a chance to mount a filesystem anyway.
In a similar vein could we please clarify the rules for changing mount options for an existing superblock are in the new api?
Today mount assumes that it has to provide all of the existing options to reconfigure a mount. What people want to do and what most filesystems support is just specifying the options that need to be changed. Can we please make this the rule of how this are expected to work for fscontext? That only changing mount options need to be specified before: "x reconfigure"
Eric