diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2019-07-19 10:42:02 -0700 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2019-07-19 10:42:02 -0700 |
commit | 933a90bf4f3505f8ec83bda21a3c7d70d7c2b426 (patch) | |
tree | ca81c209000a15670e3582760ad9bae1a9cde215 | |
parent | 5f4fc6d440d77a2cf74fe4ea56955674ac7e35e7 (diff) | |
parent | 037f11b4752f717201143a1dc5d6acf3cb71ddfa (diff) |
Merge branch 'work.mount0' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs
Pull vfs mount updates from Al Viro:
"The first part of mount updates.
Convert filesystems to use the new mount API"
* 'work.mount0' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs: (63 commits)
mnt_init(): call shmem_init() unconditionally
constify ksys_mount() string arguments
don't bother with registering rootfs
init_rootfs(): don't bother with init_ramfs_fs()
vfs: Convert smackfs to use the new mount API
vfs: Convert selinuxfs to use the new mount API
vfs: Convert securityfs to use the new mount API
vfs: Convert apparmorfs to use the new mount API
vfs: Convert openpromfs to use the new mount API
vfs: Convert xenfs to use the new mount API
vfs: Convert gadgetfs to use the new mount API
vfs: Convert oprofilefs to use the new mount API
vfs: Convert ibmasmfs to use the new mount API
vfs: Convert qib_fs/ipathfs to use the new mount API
vfs: Convert efivarfs to use the new mount API
vfs: Convert configfs to use the new mount API
vfs: Convert binfmt_misc to use the new mount API
convenience helper: get_tree_single()
convenience helper get_tree_nodev()
vfs: Kill sget_userns()
...
60 files changed, 581 insertions, 533 deletions
diff --git a/arch/ia64/kernel/perfmon.c b/arch/ia64/kernel/perfmon.c index 7c52bd2695a2..a23c3938a1c4 100644 --- a/arch/ia64/kernel/perfmon.c +++ b/arch/ia64/kernel/perfmon.c @@ -39,6 +39,7 @@ #include <linux/smp.h> #include <linux/pagemap.h> #include <linux/mount.h> +#include <linux/pseudo_fs.h> #include <linux/bitops.h> #include <linux/capability.h> #include <linux/rcupdate.h> @@ -600,17 +601,19 @@ pfm_unprotect_ctx_ctxsw(pfm_context_t *x, unsigned long f) /* forward declaration */ 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) +static int pfmfs_init_fs_context(struct fs_context *fc) { - return mount_pseudo(fs_type, "pfm:", NULL, &pfmfs_dentry_operations, - PFMFS_MAGIC); + struct pseudo_fs_context *ctx = init_pseudo(fc, PFMFS_MAGIC); + if (!ctx) + return -ENOMEM; + ctx->dops = &pfmfs_dentry_operations; + return 0; } static struct file_system_type pfm_fs_type = { - .name = "pfmfs", - .mount = pfmfs_mount, - .kill_sb = kill_anon_super, + .name = "pfmfs", + .init_fs_context = pfmfs_init_fs_context, + .kill_sb = kill_anon_super, }; MODULE_ALIAS_FS("pfmfs"); diff --git a/arch/x86/kernel/cpu/resctrl/rdtgroup.c b/arch/x86/kernel/cpu/resctrl/rdtgroup.c index bf3034994754..a46dee8e78db 100644 --- a/arch/x86/kernel/cpu/resctrl/rdtgroup.c +++ b/arch/x86/kernel/cpu/resctrl/rdtgroup.c @@ -2104,8 +2104,7 @@ static int rdt_init_fs_context(struct fs_context *fc) ctx->kfc.magic = RDTGROUP_SUPER_MAGIC; fc->fs_private = &ctx->kfc; fc->ops = &rdt_fs_context_ops; - if (fc->user_ns) - put_user_ns(fc->user_ns); + put_user_ns(fc->user_ns); fc->user_ns = get_user_ns(&init_user_ns); fc->global = true; return 0; diff --git a/drivers/base/devtmpfs.c b/drivers/base/devtmpfs.c index 0dbc43068eeb..ba5c80903efe 100644 --- a/drivers/base/devtmpfs.c +++ b/drivers/base/devtmpfs.c @@ -357,8 +357,7 @@ int devtmpfs_mount(const char *mntdir) if (!thread) return 0; - err = ksys_mount("devtmpfs", (char *)mntdir, "devtmpfs", MS_SILENT, - NULL); + err = ksys_mount("devtmpfs", mntdir, "devtmpfs", MS_SILENT, NULL); if (err) printk(KERN_INFO "devtmpfs: error mounting %i\n", err); else diff --git a/drivers/dax/super.c b/drivers/dax/super.c index 8ab12068eea3..26a654dbc69a 100644 --- a/drivers/dax/super.c +++ b/drivers/dax/super.c @@ -5,6 +5,7 @@ #include <linux/pagemap.h> #include <linux/module.h> #include <linux/mount.h> +#include <linux/pseudo_fs.h> #include <linux/magic.h> #include <linux/genhd.h> #include <linux/pfn_t.h> @@ -469,16 +470,19 @@ static const struct super_operations dax_sops = { .drop_inode = generic_delete_inode, }; -static struct dentry *dax_mount(struct file_system_type *fs_type, - int flags, const char *dev_name, void *data) +static int dax_init_fs_context(struct fs_context *fc) { - return mount_pseudo(fs_type, "dax:", &dax_sops, NULL, DAXFS_MAGIC); + struct pseudo_fs_context *ctx = init_pseudo(fc, DAXFS_MAGIC); + if (!ctx) + return -ENOMEM; + ctx->ops = &dax_sops; + return 0; } static struct file_system_type dax_fs_type = { - .name = "dax", - .mount = dax_mount, - .kill_sb = kill_anon_super, + .name = "dax", + .init_fs_context = dax_init_fs_context, + .kill_sb = kill_anon_super, }; static int dax_test(struct inode *inode, void *data) @@ -665,10 +669,6 @@ static int dax_fs_init(void) if (!dax_cache) return -ENOMEM; - rc = register_filesystem(&dax_fs_type); - if (rc) - goto err_register_fs; - dax_mnt = kern_mount(&dax_fs_type); if (IS_ERR(dax_mnt)) { rc = PTR_ERR(dax_mnt); @@ -679,8 +679,6 @@ static int dax_fs_init(void) return 0; err_mount: - unregister_filesystem(&dax_fs_type); - err_register_fs: kmem_cache_destroy(dax_cache); return rc; @@ -689,7 +687,6 @@ static int dax_fs_init(void) static void dax_fs_exit(void) { kern_unmount(dax_mnt); - unregister_filesystem(&dax_fs_type); kmem_cache_destroy(dax_cache); } diff --git a/drivers/dma-buf/dma-buf.c b/drivers/dma-buf/dma-buf.c index dc4b2c521d79..f45bfb29ef96 100644 --- a/drivers/dma-buf/dma-buf.c +++ b/drivers/dma-buf/dma-buf.c @@ -24,6 +24,7 @@ #include <linux/reservation.h> #include <linux/mm.h> #include <linux/mount.h> +#include <linux/pseudo_fs.h> #include <uapi/linux/dma-buf.h> #include <uapi/linux/magic.h> @@ -59,16 +60,20 @@ static const struct dentry_operations dma_buf_dentry_ops = { static struct vfsmount *dma_buf_mnt; -static struct dentry *dma_buf_fs_mount(struct file_system_type *fs_type, - int flags, const char *name, void *data) +static int dma_buf_fs_init_context(struct fs_context *fc) { - return mount_pseudo(fs_type, "dmabuf:", NULL, &dma_buf_dentry_ops, - DMA_BUF_MAGIC); + struct pseudo_fs_context *ctx; + + ctx = init_pseudo(fc, DMA_BUF_MAGIC); + if (!ctx) + return -ENOMEM; + ctx->dops = &dma_buf_dentry_ops; + return 0; } static struct file_system_type dma_buf_fs_type = { .name = "dmabuf", - .mount = dma_buf_fs_mount, + .init_fs_context = dma_buf_fs_init_context, .kill_sb = kill_anon_super, }; diff --git a/drivers/gpu/drm/drm_drv.c b/drivers/gpu/drm/drm_drv.c index fe0ce86c280f..9d00947ca447 100644 --- a/drivers/gpu/drm/drm_drv.c +++ b/drivers/gpu/drm/drm_drv.c @@ -31,6 +31,7 @@ #include <linux/module.h> #include <linux/moduleparam.h> #include <linux/mount.h> +#include <linux/pseudo_fs.h> #include <linux/slab.h> #include <linux/srcu.h> @@ -535,28 +536,15 @@ EXPORT_SYMBOL(drm_dev_unplug); static int drm_fs_cnt; static struct vfsmount *drm_fs_mnt; -static const struct dentry_operations drm_fs_dops = { - .d_dname = simple_dname, -}; - -static const struct super_operations drm_fs_sops = { - .statfs = simple_statfs, -}; - -static struct dentry *drm_fs_mount(struct file_system_type *fs_type, int flags, - const char *dev_name, void *data) +static int drm_fs_init_fs_context(struct fs_context *fc) { - return mount_pseudo(fs_type, - "drm:", - &drm_fs_sops, - &drm_fs_dops, - 0x010203ff); + return init_pseudo(fc, 0x010203ff) ? 0 : -ENOMEM; } static struct file_system_type drm_fs_type = { .name = "drm", .owner = THIS_MODULE, - .mount = drm_fs_mount, + .init_fs_context = drm_fs_init_fs_context, .kill_sb = kill_anon_super, }; diff --git a/drivers/infiniband/hw/qib/qib_fs.c b/drivers/infiniband/hw/qib/qib_fs.c index ceb42d948412..41a569558a15 100644 --- a/drivers/infiniband/hw/qib/qib_fs.c +++ b/drivers/infiniband/hw/qib/qib_fs.c @@ -34,6 +34,7 @@ #include <linux/module.h> #include <linux/fs.h> +#include <linux/fs_context.h> #include <linux/mount.h> #include <linux/pagemap.h> #include <linux/init.h> @@ -506,7 +507,7 @@ bail: * 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, struct fs_context *fc) { struct qib_devdata *dd; unsigned long index; @@ -534,17 +535,24 @@ bail: return ret; } -static struct dentry *qibfs_mount(struct file_system_type *fs_type, int flags, - const char *dev_name, void *data) +static int qibfs_get_tree(struct fs_context *fc) { - struct dentry *ret; - - ret = mount_single(fs_type, flags, data, qibfs_fill_super); - if (!IS_ERR(ret)) - qib_super = ret->d_sb; + int ret = get_tree_single(fc, qibfs_fill_super); + if (ret == 0) + qib_super = fc->root->d_sb; return ret; } +static const struct fs_context_operations qibfs_context_ops = { + .get_tree = qibfs_get_tree, +}; + +static int qibfs_init_fs_context(struct fs_context *fc) +{ + fc->ops = &qibfs_context_ops; + return 0; +} + static void qibfs_kill_super(struct super_block *s) { kill_litter_super(s); @@ -583,7 +591,7 @@ int qibfs_remove(struct qib_devdata *dd) static struct file_system_type qibfs_fs_type = { .owner = THIS_MODULE, .name = "ipathfs", - .mount = qibfs_mount, + .init_fs_context = qibfs_init_fs_context, .kill_sb = qibfs_kill_super, }; MODULE_ALIAS_FS("ipathfs"); diff --git a/drivers/misc/cxl/api.c b/drivers/misc/cxl/api.c index a450694d5a62..b493de962153 100644 --- a/drivers/misc/cxl/api.c +++ b/drivers/misc/cxl/api.c @@ -9,6 +9,7 @@ #include <misc/cxl.h> #include <linux/module.h> #include <linux/mount.h> +#include <linux/pseudo_fs.h> #include <linux/sched/mm.h> #include <linux/mmu_context.h> @@ -33,21 +34,15 @@ static int cxl_fs_cnt; static struct vfsmount *cxl_vfs_mount; -static const struct dentry_operations cxl_fs_dops = { - .d_dname = simple_dname, -}; - -static struct dentry *cxl_fs_mount(struct file_system_type *fs_type, int flags, - const char *dev_name, void *data) +static int cxl_fs_init_fs_context(struct fs_context *fc) { - return mount_pseudo(fs_type, "cxl:", NULL, &cxl_fs_dops, - CXL_PSEUDO_FS_MAGIC); + return init_pseudo(fc, CXL_PSEUDO_FS_MAGIC) ? 0 : -ENOMEM; } static struct file_system_type cxl_fs_type = { .name = "cxl", .owner = THIS_MODULE, - .mount = cxl_fs_mount, + .init_fs_context = cxl_fs_init_fs_context, .kill_sb = kill_anon_super, }; diff --git a/drivers/misc/ibmasm/ibmasmfs.c b/drivers/misc/ibmasm/ibmasmfs.c index 4989dcb2df14..35fec1bf1b3d 100644 --- a/drivers/misc/ibmasm/ibmasmfs.c +++ b/drivers/misc/ibmasm/ibmasmfs.c @@ -60,6 +60,7 @@ */ #include <linux/fs.h> +#include <linux/fs_context.h> #include <linux/pagemap.h> #include <linux/slab.h> #include <linux/uaccess.h> @@ -74,13 +75,21 @@ 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, struct fs_context *fc); +static int ibmasmfs_get_tree(struct fs_context *fc) +{ + return get_tree_single(fc, ibmasmfs_fill_super); +} -static struct dentry *ibmasmfs_mount(struct file_system_type *fst, - int flags, const char *name, void *data) +static const struct fs_context_operations ibmasmfs_context_ops = { + .get_tree = ibmasmfs_get_tree, +}; + +static int ibmasmfs_init_fs_context(struct fs_context *fc) { - return mount_single(fst, flags, data, ibmasmfs_fill_super); + fc->ops = &ibmasmfs_context_ops; + return 0; } static const struct super_operations ibmasmfs_s_ops = { @@ -93,12 +102,12 @@ static const struct file_operations *ibmasmfs_dir_ops = &simple_dir_operations; static struct file_system_type ibmasmfs_type = { .owner = THIS_MODULE, .name = "ibmasmfs", - .mount = ibmasmfs_mount, + .init_fs_context = ibmasmfs_init_fs_context, .kill_sb = kill_litter_super, }; 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, struct fs_context *fc) { struct inode *root; diff --git a/drivers/misc/vmw_balloon.c b/drivers/misc/vmw_balloon.c index 97b58e7ad901..8840299420e0 100644 --- a/drivers/misc/vmw_balloon.c +++ b/drivers/misc/vmw_balloon.c @@ -29,6 +29,7 @@ #include <linux/slab.h> #include <linux/spinlock.h> #include <linux/mount.h> +#include <linux/pseudo_fs.h> #include <linux/balloon_compaction.h> #include <linux/vmw_vmci_defs.h> #include <linux/vmw_vmci_api.h> @@ -1728,22 +1729,15 @@ static inline void vmballoon_debugfs_exit(struct vmballoon *b) #ifdef CONFIG_BALLOON_COMPACTION -static struct dentry *vmballoon_mount(struct file_system_type *fs_type, - int flags, const char *dev_name, - void *data) +static int vmballoon_init_fs_context(struct fs_context *fc) { - static const struct dentry_operations ops = { - .d_dname = simple_dname, - }; - - return mount_pseudo(fs_type, "balloon-vmware:", NULL, &ops, - BALLOON_VMW_MAGIC); + return init_pseudo(fc, BALLOON_VMW_MAGIC) ? 0 : -ENOMEM; } static struct file_system_type vmballoon_fs = { - .name = "balloon-vmware", - .mount = vmballoon_mount, - .kill_sb = kill_anon_super, + .name = "balloon-vmware", + .init_fs_context = vmballoon_init_fs_context, + .kill_sb = kill_anon_super, }; static struct vfsmount *vmballoon_mnt; diff --git a/drivers/oprofile/oprofilefs.c b/drivers/oprofile/oprofilefs.c index 4ea08979312c..0875f2f122b3 100644 --- a/drivers/oprofile/oprofilefs.c +++ b/drivers/oprofile/oprofilefs.c @@ -14,6 +14,7 @@ #include <linux/module.h> #include <linux/oprofile.h> #include <linux/fs.h> +#include <linux/fs_context.h> #include <linux/pagemap.h> #include <linux/uaccess.h> @@ -238,7 +239,7 @@ 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, struct fs_context *fc) { struct inode *root_inode; @@ -263,18 +264,25 @@ static int oprofilefs_fill_super(struct super_block *sb, void *data, int silent) return 0; } - -static struct dentry *oprofilefs_mount(struct file_system_type *fs_type, - int flags, const char *dev_name, void *data) +static int oprofilefs_get_tree(struct fs_context *fc) { - return mount_single(fs_type, flags, data, oprofilefs_fill_super); + return get_tree_single(fc, oprofilefs_fill_super); } +static const struct fs_context_operations oprofilefs_context_ops = { + .get_tree = oprofilefs_get_tree, +}; + +static int oprofilefs_init_fs_context(struct fs_context *fc) +{ + fc->ops = &oprofilefs_context_ops; + return 0; +} static struct file_system_type oprofilefs_type = { .owner = THIS_MODULE, .name = "oprofilefs", - .mount = oprofilefs_mount, + .init_fs_context = oprofilefs_init_fs_context, .kill_sb = kill_litter_super, }; MODULE_ALIAS_FS("oprofilefs"); diff --git a/drivers/scsi/cxlflash/ocxl_hw.c b/drivers/scsi/cxlflash/ocxl_hw.c index 96740c6fcd92..7018cd802569 100644 --- a/drivers/scsi/cxlflash/ocxl_hw.c +++ b/drivers/scsi/cxlflash/ocxl_hw.c @@ -12,6 +12,7 @@ #include <linux/idr.h> #include <linux/module.h> #include <linux/mount.h> +#include <linux/pseudo_fs.h> #include <linux/poll.h> #include <linux/sched/signal.h> @@ -31,31 +32,15 @@ static int ocxlflash_fs_cnt; static struct vfsmount *ocxlflash_vfs_mount; -static const struct dentry_operations ocxlflash_fs_dops = { - .d_dname = simple_dname, -}; - -/* - * ocxlflash_fs_mount() - mount the pseudo-filesystem - * @fs_type: File system type. - * @flags: Flags for the filesystem. - * @dev_name: Device name associated with the filesystem. - * @data: Data pointer. - * - * Return: pointer to the directory entry structure - */ -static struct dentry *ocxlflash_fs_mount(struct file_system_type *fs_type, - int flags, const char *dev_name, - void *data) +static int ocxlflash_fs_init_fs_context(struct fs_context *fc) { - return mount_pseudo(fs_type, "ocxlflash:", NULL, &ocxlflash_fs_dops, - OCXLFLASH_FS_MAGIC); + return init_pseudo(fc, OCXLFLASH_FS_MAGIC) ? 0 : -ENOMEM; } static struct file_system_type ocxlflash_fs_type = { .name = "ocxlflash", .owner = THIS_MODULE, - .mount = ocxlflash_fs_mount, + .init_fs_context = ocxlflash_fs_init_fs_context, .kill_sb = kill_anon_super, }; diff --git a/drivers/usb/gadget/legacy/inode.c b/drivers/usb/gadget/legacy/inode.c index 249277d0e53f..b47938dff1a2 100644 --- a/drivers/usb/gadget/legacy/inode.c +++ b/drivers/usb/gadget/legacy/inode.c @@ -12,6 +12,7 @@ #include <linux/init.h> #include <linux/module.h> #include <linux/fs.h> +#include <linux/fs_context.h> #include <linux/pagemap.h> #include <linux/uts.h> #include <linux/wait.h> @@ -1990,7 +1991,7 @@ 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, struct fs_context *fc) { struct inode *inode; struct dev_data *dev; @@ -2044,11 +2045,19 @@ Enomem: } /* "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) +static int gadgetfs_get_tree(struct fs_context *fc) { - return mount_single (t, flags, opts, gadgetfs_fill_super); + return get_tree_single(fc, gadgetfs_fill_super); +} + +static const struct fs_context_operations gadgetfs_context_ops = { + .get_tree = gadgetfs_get_tree, +}; + +static int gadgetfs_init_fs_context(struct fs_context *fc) +{ + fc->ops = &gadgetfs_context_ops; + return 0; } static void @@ -2068,7 +2077,7 @@ gadgetfs_kill_sb (struct super_block *sb) static struct file_system_type gadgetfs_type = { .owner = THIS_MODULE, .name = shortname, - .mount = gadgetfs_mount, + .init_fs_context = gadgetfs_init_fs_context, .kill_sb = gadgetfs_kill_sb, }; MODULE_ALIAS_FS("gadgetfs"); diff --git a/drivers/virtio/virtio_balloon.c b/drivers/virtio/virtio_balloon.c index 44339fc87cc7..226fbb995fb0 100644 --- a/drivers/virtio/virtio_balloon.c +++ b/drivers/virtio/virtio_balloon.c @@ -18,6 +18,7 @@ #include <linux/mm.h> #include <linux/mount.h> #include <linux/magic.h> +#include <linux/pseudo_fs.h> /* * Balloon device works in 4K page units. So each page is pointed to by @@ -745,20 +746,14 @@ static int virtballoon_migratepage(struct balloon_dev_info *vb_dev_info, return MIGRATEPAGE_SUCCESS; } -static struct dentry *balloon_mount(struct file_system_type *fs_type, - int flags, const char *dev_name, void *data) +static int balloon_init_fs_context(struct fs_context *fc) { - static const struct dentry_operations ops = { - .d_dname = simple_dname, - }; - - return mount_pseudo(fs_type, "balloon-kvm:", NULL, &ops, - BALLOON_KVM_MAGIC); + return init_pseudo(fc, BALLOON_KVM_MAGIC) ? 0 : -ENOMEM; } static struct file_system_type balloon_fs = { .name = "balloon-kvm", - .mount = balloon_mount, + .init_fs_context = balloon_init_fs_context, .kill_sb = kill_anon_super, }; diff --git a/drivers/xen/xenfs/super.c b/drivers/xen/xenfs/super.c index 20c1448f1ce7..d7d64235010d 100644 --- a/drivers/xen/xenfs/super.c +++ b/drivers/xen/xenfs/super.c @@ -14,6 +14,7 @@ #include <linux/errno.h> #include <linux/module.h> #include <linux/fs.h> +#include <linux/fs_context.h> #include <linux/magic.h> #include <xen/xen.h> @@ -43,7 +44,7 @@ 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, struct fs_context *fc) { static const struct tree_descr xenfs_files[] = { [2] = { "xenbus", &xen_xenbus_fops, S_IRUSR|S_IWUSR }, @@ -68,17 +69,25 @@ static int xenfs_fill_super(struct super_block *sb, void *data, int silent) xen_initial_domain() ? xenfs_init_files : xenfs_files); } -static struct dentry *xenfs_mount(struct file_system_type *fs_type, - int flags, const char *dev_name, - void *data) +static int xenfs_get_tree(struct fs_context *fc) { - return mount_single(fs_type, flags, data, xenfs_fill_super); + return get_tree_single(fc, xenfs_fill_super); +} + +static const struct fs_context_operations xenfs_context_ops = { + .get_tree = xenfs_get_tree, +}; + +static int xenfs_init_fs_context(struct fs_context *fc) +{ + fc->ops = &xenfs_context_ops; + return 0; } static struct file_system_type xenfs_type = { .owner = THIS_MODULE, .name = "xenfs", - .mount = xenfs_mount, + .init_fs_context = xenfs_init_fs_context, .kill_sb = kill_litter_super, }; MODULE_ALIAS_FS("xenfs"); @@ -42,6 +42,7 @@ #include <linux/ramfs.h> #include <linux/percpu-refcount.h> #include <linux/mount.h> +#include <linux/pseudo_fs.h> #include <asm/kmap_types.h> #include <linux/uaccess.h> @@ -249,15 +250,12 @@ static struct file *aio_private_file(struct kioctx *ctx, loff_t nr_pages) return file; } -static struct dentry *aio_mount(struct file_system_type *fs_type, - int flags, const char *dev_name, void *data) +static int aio_init_fs_context(struct fs_context *fc) { - struct dentry *root = mount_pseudo(fs_type, "aio:", NULL, NULL, - AIO_RING_MAGIC); - - if (!IS_ERR(root)) - root->d_sb->s_iflags |= SB_I_NOEXEC; - return root; + if (!init_pseudo(fc, AIO_RING_MAGIC)) + return -ENOMEM; + fc->s_iflags |= SB_I_NOEXEC; + return 0; } /* aio_setup @@ -268,7 +266,7 @@ static int __init aio_setup(void) { static struct file_system_type aio_fs = { .name = "aio", - .mount = aio_mount, + .init_fs_context = aio_init_fs_context, .kill_sb = kill_anon_super, }; aio_mnt = kern_mount(&aio_fs); diff --git a/fs/anon_inodes.c b/fs/anon_inodes.c index c2b8663f5b00..89714308c25b 100644 --- a/fs/anon_inodes.c +++ b/fs/anon_inodes.c @@ -20,6 +20,7 @@ #include <linux/kernel.h> #include <linux/magic.h> #include <linux/anon_inodes.h> +#include <linux/pseudo_fs.h> #include <linux/uaccess.h> @@ -39,16 +40,18 @@ static const struct dentry_operations anon_inodefs_dentry_operations = { .d_dname = anon_inodefs_dname, }; -static struct dentry *anon_inodefs_mount(struct file_system_type *fs_type, - int flags, const char *dev_name, void *data) +static int anon_inodefs_init_fs_context(struct fs_context *fc) { - return mount_pseudo(fs_type, "anon_inode:", NULL, - &anon_inodefs_dentry_operations, ANON_INODE_FS_MAGIC); + struct pseudo_fs_context *ctx = init_pseudo(fc, ANON_INODE_FS_MAGIC); + if (!ctx) + return -ENOMEM; + ctx->dops = &anon_inodefs_dentry_operations; + return 0; } static struct file_system_type anon_inode_fs_type = { .name = "anon_inodefs", - .mount = anon_inodefs_mount, + .init_fs_context = anon_inodefs_init_fs_context, .kill_sb = kill_anon_super, }; diff --git a/fs/binfmt_misc.c b/fs/binfmt_misc.c index b8e145552ec7..cdb45829354d 100644 --- a/fs/binfmt_misc.c +++ b/fs/binfmt_misc.c @@ -23,6 +23,7 @@ #include <linux/pagemap.h> #include <linux/namei.h> #include <linux/mount.h> +#include <linux/fs_context.h> #include <linux/syscalls.h> #include <linux/fs.h> #include <linux/uaccess.h> @@ -821,7 +822,7 @@ 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, struct fs_context *fc) { int err; static const struct tree_descr bm_files[] = { @@ -836,10 +837,19 @@ static int bm_fill_super(struct super_block *sb, void *data, int silent) return err; } -static struct dentry *bm_mount(struct file_system_type *fs_type, - int flags, const char *dev_name, void *data) +static int bm_get_tree(struct fs_context *fc) { - return mount_single(fs_type, flags, data, bm_fill_super); + return get_tree_single(fc, bm_fill_super); +} + +static const struct fs_context_operations bm_context_ops = { + .get_tree = bm_get_tree, +}; + +static int bm_init_fs_context(struct fs_context *fc) +{ + fc->ops = &bm_context_ops; + return 0; } static struct linux_binfmt misc_format = { @@ -850,7 +860,7 @@ static struct linux_binfmt misc_format = { static struct file_system_type bm_fs_type = { .owner = THIS_MODULE, .name = "binfmt_misc", - .mount = bm_mount, + .init_fs_context = bm_init_fs_context, .kill_sb = kill_litter_super, }; MODULE_ALIAS_FS("binfmt_misc"); diff --git a/fs/block_dev.c b/fs/block_dev.c index f00b569a9f89..4707dfff991b 100644 --- a/fs/block_dev.c +++ b/fs/block_dev.c @@ -26,6 +26,7 @@ #include <linux/writeback.h> #include <linux/mpage.h> #include <linux/mount.h> +#include <linux/pseudo_fs.h> #include <linux/uio.h> #include <linux/namei.h> #include <linux/log2.h> @@ -821,19 +822,19 @@ static const struct super_operations bdev_sops = { .evict_inode = bdev_evict_inode, }; -static struct dentry *bd_mount(struct file_system_type *fs_type, - int flags, const char *dev_name, void *data) +static int bd_init_fs_context(struct fs_context *fc) { - struct dentry *dent; - dent = mount_pseudo(fs_type, "bdev:", &bdev_sops, NULL, BDEVFS_MAGIC); - if (!IS_ERR(dent)) - dent->d_sb->s_iflags |= SB_I_CGROUPWB; - return dent; + struct pseudo_fs_context *ctx = init_pseudo(fc, BDEVFS_MAGIC); + if (!ctx) + return -ENOMEM; + fc->s_iflags |= SB_I_CGROUPWB; + ctx->ops = &bdev_sops; + return 0; } static struct file_system_type bd_type = { .name = "bdev", - .mount = bd_mount, + .init_fs_context = bd_init_fs_context, .kill_sb = kill_anon_super, }; diff --git a/fs/btrfs/tests/btrfs-tests.c b/fs/btrfs/tests/btrfs-tests.c index 9238fd4f1734..1e3ba4949399 100644 --- a/fs/btrfs/tests/btrfs-tests.c +++ b/fs/btrfs/tests/btrfs-tests.c @@ -5,6 +5,7 @@ #include <linux/fs.h> #include <linux/mount.h> +#include <linux/pseudo_fs.h> #include <linux/magic.h> #include "btrfs-tests.h" #include "../ctree.h" @@ -32,17 +33,19 @@ static const struct super_operations btrfs_test_super_ops = { .destroy_inode = btrfs_test_destroy_inode, }; -static struct dentry *btrfs_test_mount(struct file_system_type *fs_type, - int flags, const char *dev_name, - void *data) + +static int btrfs_test_init_fs_context(struct fs_context *fc) { - return mount_pseudo(fs_type, "btrfs_test:", &btrfs_test_super_ops, - NULL, BTRFS_TEST_MAGIC); + struct pseudo_fs_context *ctx = init_pseudo(fc, BTRFS_TEST_MAGIC); + if (!ctx) + return -ENOMEM; + ctx->ops = &btrfs_test_super_ops; + return 0; } static struct file_system_type test_type = { .name = "btrfs_test_fs", - .mount = btrfs_test_mount, + .init_fs_context = btrfs_test_init_fs_context, .kill_sb = kill_anon_super, }; diff --git a/fs/configfs/mount.c b/fs/configfs/mount.c index 791304fdde9d..55438dd58189 100644 --- a/fs/configfs/mount.c +++ b/fs/configfs/mount.c @@ -13,6 +13,7 @@ #include <linux/fs.h> #include <linux/module.h> #include <linux/mount.h> +#include <linux/fs_context.h> #include <linux/pagemap.h> #include <linux/init.h> #include <linux/slab.h> @@ -52,7 +53,7 @@ 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, struct fs_context *fc) { struct inode *inode; struct dentry *root; @@ -88,16 +89,25 @@ static int configfs_fill_super(struct super_block *sb, void *data, int silent) return 0; } -static struct dentry *configfs_do_mount(struct file_system_type *fs_type, - int flags, const char *dev_name, void *data) +static int configfs_get_tree(struct fs_context *fc) { - return mount_single(fs_type, flags, data, configfs_fill_super); + return get_tree_single(fc, configfs_fill_super); +} + +static const struct fs_context_operations configfs_context_ops = { + .get_tree = configfs_get_tree, +}; + +static int configfs_init_fs_context(struct fs_context *fc) +{ + fc->ops = &configfs_context_ops; + return 0; } static struct file_system_type configfs_fs_type = { .owner = THIS_MODULE, .name = "configfs", - .mount = configfs_do_mount, + .init_fs_context = configfs_init_fs_context, .kill_sb = kill_litter_super, }; MODULE_ALIAS_FS("configfs"); diff --git a/fs/d_path.c b/fs/d_path.c index e8fce6b1174f..a7d0a96b35ce 100644 --- a/fs/d_path.c +++ b/fs/d_path.c @@ -316,7 +316,6 @@ char *simple_dname(struct dentry *dentry, char *buffer, int buflen) end = ERR_PTR(-ENAMETOOLONG); return end; } -EXPORT_SYMBOL(simple_dname); /* * Write full pathname from the root of the filesystem into the buffer. diff --git a/fs/efivarfs/super.c b/fs/efivarfs/super.c index 5bc3c4a4c563..fa4f6447ddad 100644 --- a/fs/efivarfs/super.c +++ b/fs/efivarfs/super.c @@ -7,6 +7,7 @@ #include <linux/ctype.h> #include <linux/efi.h> #include <linux/fs.h> +#include <linux/fs_context.h> #include <linux/module.h> #include <linux/pagemap.h> #include <linux/ucs2_string.h> @@ -28,8 +29,6 @@ static const struct super_operations efivarfs_ops = { .evict_inode = efivarfs_evict_inode, }; -static struct super_block *efivarfs_sb; - /* * Compare two efivarfs file names. * @@ -188,14 +187,12 @@ 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, struct fs_context *fc) { struct inode *inode = NULL; struct dentry *root; int err; - efivarfs_sb = sb; - sb->s_maxbytes = MAX_LFS_FILESIZE; sb->s_blocksize = PAGE_SIZE; sb->s_blocksize_bits = PAGE_SHIFT; @@ -223,16 +220,24 @@ static int efivarfs_fill_super(struct super_block *sb, void *data, int silent) return err; } -static struct dentry *efivarfs_mount(struct file_system_type *fs_type, - int flags, const char *dev_name, void *data) +static int efivarfs_get_tree(struct fs_context *fc) +{ + return get_tree_single(fc, efivarfs_fill_super); +} + +static const struct fs_context_operations efivarfs_context_ops = { + .get_tree = efivarfs_get_tree, +}; + +static int efivarfs_init_fs_context(struct fs_context *fc) { - return mount_single(fs_type, flags, data, efivarfs_fill_super); + fc->ops = &efivarfs_context_ops; + return 0; } static void efivarfs_kill_sb(struct super_block *sb) { kill_litter_super(sb); - efivarfs_sb = NULL; /* Remove all entries and destroy */ __efivar_entry_iter(efivarfs_destroy, &efivarfs_list, NULL, NULL); @@ -241,7 +246,7 @@ static void efivarfs_kill_sb(struct super_block *sb) static struct file_system_type efivarfs_type = { .owner = THIS_MODULE, .name = "efivarfs", - .mount = efivarfs_mount, + .init_fs_context = efivarfs_init_fs_context, .kill_sb = efivarfs_kill_sb, }; diff --git a/fs/fs_parser.c b/fs/fs_parser.c index 0d388faa25d1..460ea4206fa2 100644 --- a/fs/fs_parser.c +++ b/fs/fs_parser.c @@ -264,6 +264,7 @@ int fs_lookup_param(struct fs_context *fc, return invalf(fc, "%s: not usable as path", param->key); } + f->refcnt++; /* filename_lookup() drops our ref. */ ret = filename_lookup(param->dirfd, f, flags, _path, NULL); if (ret < 0) { errorf(fc, "%s: Lookup failure for '%s'", param->key, f->name); diff --git a/fs/fsopen.c b/fs/fsopen.c index a8bf83ce8d4e..043ffa8dc263 100644 --- a/fs/fsopen.c +++ b/fs/fsopen.c @@ -226,6 +226,8 @@ static int vfs_fsconfig_locked(struct fs_context *fc, int cmd, case FSCONFIG_CMD_CREATE: if (fc->phase != FS_CONTEXT_CREATE_PARAMS) return -EBUSY; + if (!mount_capable(fc)) + return -EPERM; fc->phase = FS_CONTEXT_CREATING; ret = vfs_get_tree(fc); if (ret) diff --git a/fs/fuse/control.c b/fs/fuse/control.c index 14ce1e47f980..c23f6f243ad4 100644 --- a/fs/fuse/control.c +++ b/fs/fuse/control.c @@ -346,7 +346,7 @@ static int fuse_ctl_fill_super(struct super_block *sb, struct fs_context *fctx) static int fuse_ctl_get_tree(struct fs_context *fc) { - return vfs_get_super(fc, vfs_get_single_super, fuse_ctl_fill_super); + return get_tree_single(fc, fuse_ctl_fill_super); } static const struct fs_context_operations fuse_ctl_context_ops = { diff --git a/fs/hugetlbfs/inode.c b/fs/hugetlbfs/inode.c index 1dcc57189382..a478df035651 100644 --- a/fs/hugetlbfs/inode.c +++ b/fs/hugetlbfs/inode.c @@ -1299,7 +1299,7 @@ static int hugetlbfs_get_tree(struct fs_context *fc) int err = hugetlbfs_validate(fc); if (err) return err; - return vfs_get_super(fc, vfs_get_independent_super, hugetlbfs_fill_super); + return get_tree_nodev(fc, hugetlbfs_fill_super); } static void hugetlbfs_fs_context_free(struct fs_context *fc) diff --git a/fs/internal.h b/fs/internal.h index 2f3c3de51fad..b9bad2d30cef 100644 --- a/fs/internal.h +++ b/fs/internal.h @@ -14,6 +14,7 @@ struct path; struct mount; struct shrink_control; struct fs_context; +struct user_namespace; /* * block_dev.c @@ -107,6 +108,7 @@ extern struct file *alloc_empty_file_noaccount(int, const struct cred *); extern int reconfigure_super(struct fs_context *); extern bool trylock_super(struct super_block *sb); extern struct super_block *user_get_super(dev_t); +extern bool mount_capable(struct fs_context *); /* * open.c @@ -154,6 +156,7 @@ extern int d_set_mounted(struct dentry *dentry); extern long prune_dcache_sb(struct super_block *sb, struct shrink_control *sc); extern struct dentry *d_alloc_cursor(struct dentry *); extern struct dentry * d_alloc_pseudo(struct super_block *, const struct qstr *); +extern char *simple_dname(struct dentry *, char *, int); /* * read_write.c diff --git a/fs/libfs.c b/fs/libfs.c index 7e52e77692ec..c9b2850c0f7c 100644 --- a/fs/libfs.c +++ b/fs/libfs.c @@ -17,6 +17,8 @@ #include <linux/exportfs.h> #include <linux/writeback.h> #include <linux/buffer_head.h> /* sync_mapping_buffers */ +#include <linux/fs_context.h> +#include <linux/pseudo_fs.h> #include <linux/uaccess.h> @@ -236,34 +238,22 @@ static const struct super_operations simple_super_operations = { .statfs = simple_statfs, }; -/* - * Common helper for pseudo-filesystems (sockfs, pipefs, bdev - stuff that - * will never be mountable) - */ -struct dentry *mount_pseudo_xattr(struct file_system_type *fs_type, char *name, - const struct super_operations *ops, const struct xattr_handler **xattr, - const struct dentry_operations *dops, unsigned long magic) +static int pseudo_fs_fill_super(struct super_block *s, struct fs_context *fc) { - struct super_block *s; - struct dentry *dentry; + struct pseudo_fs_context *ctx = fc->fs_private; struct inode *root; - struct qstr d_name = QSTR_INIT(name, strlen(name)); - - s = sget_userns(fs_type, NULL, set_anon_super, SB_KERNMOUNT|SB_NOUSER, - &init_user_ns, NULL); - if (IS_ERR(s)) - return ERR_CAST(s); s->s_maxbytes = MAX_LFS_FILESIZE; s->s_blocksize = PAGE_SIZE; s->s_blocksize_bits = PAGE_SHIFT; - s->s_magic = magic; - s->s_op = ops ? ops : &simple_super_operations; - s->s_xattr = xattr; + s->s_magic = ctx->magic; + s->s_op = ctx->ops ?: &simple_super_operations; + s->s_xattr = ctx->xattr; s->s_time_gran = 1; root = new_inode(s); if (!root) - goto Enomem; + return -ENOMEM; + /* * since this is the first inode, make it number 1. New inodes created * after this must take care not to collide with it (by passing @@ -272,22 +262,48 @@ struct dentry *mount_pseudo_xattr(struct file_system_type *fs_type, char *name, root->i_ino = 1; root->i_mode = S_IFDIR | S_IRUSR | S_IWUSR; root->i_atime = root->i_mtime = root->i_ctime = current_time(root); - dentry = __d_alloc(s, &d_name); - if (!dentry) { - iput(root); - goto Enomem; + s->s_root = d_make_root(root); + if (!s->s_root) + return -ENOMEM; + s->s_d_op = ctx->dops; + return 0; +} + +static int pseudo_fs_get_tree(struct fs_context *fc) +{ + return get_tree_nodev(fc, pseudo_fs_fill_super); +} + +static void pseudo_fs_free(struct fs_context *fc) +{ + kfree(fc->fs_private); +} + +static const struct fs_context_operations pseudo_fs_context_ops = { + .free = pseudo_fs_free, + .get_tree = pseudo_fs_get_tree, +}; + +/* + * Common helper for pseudo-filesystems (sockfs, pipefs, bdev - stuff that + * will never be mountable) + */ +struct pseudo_fs_context *init_pseudo(struct fs_context *fc, + unsigned long magic) +{ + struct pseudo_fs_context *ctx; + + ctx = kzalloc(sizeof(struct pseudo_fs_context), GFP_KERNEL); + if (likely(ctx)) { + ctx->magic = magic; + fc->fs_private = ctx; + fc->ops = &pseudo_fs_context_ops; + fc->sb_flags |= SB_NOUSER; + fc->global = true; } - d_instantiate(dentry, root); - s->s_root = dentry; - s->s_d_op = dops; - s->s_flags |= SB_ACTIVE; - return dget(s->s_root); - -Enomem: - deactivate_locked_super(s); - return ERR_PTR(-ENOMEM); + return ctx; } -EXPORT_SYMBOL(mount_pseudo_xattr); +EXPORT_SYMBOL(init_pseudo); int simple_open(struct inode *inode, struct file *file) { diff --git a/fs/namespace.c b/fs/namespace.c index 6fbc9126367a..f0d664adb9ba 100644 --- a/fs/namespace.c +++ b/fs/namespace.c @@ -29,6 +29,7 @@ #include <linux/sched/task.h> #include <uapi/linux/mount.h> #include <linux/fs_context.h> +#include <linux/shmem_fs.h> #include "pnode.h" #include "internal.h" @@ -2788,6 +2789,8 @@ static int do_new_mount(struct path *path, const char *fstype, int sb_flags, err = vfs_parse_fs_string(fc, "source", name, strlen(name)); if (!err) err = parse_monolithic_mount_data(fc, data); + if (!err && !mount_capable(fc)) + err = -EPERM; if (!err) err = vfs_get_tree(fc); if (!err) @@ -3295,8 +3298,8 @@ struct dentry *mount_subtree(struct vfsmount *m, const char *name) } EXPORT_SYMBOL(mount_subtree); -int ksys_mount(char __user *dev_name, char __user *dir_name, char __user *type, - unsigned long flags, void __user *data) +int ksys_mount(const char __user *dev_name, const char __user *dir_name, + const char __user *type, unsigned long flags, void __user *data) { int ret; char *kernel_type; @@ -3687,13 +3690,8 @@ static void __init init_mount_tree(void) struct mount *m; struct mnt_namespace *ns; struct path root; - struct file_system_type *type; - type = get_fs_type("rootfs"); - if (!type) - panic("Can't find rootfs type"); - mnt = vfs_kern_mount(type, 0, "rootfs", NULL); - put_filesystem(type); + mnt = vfs_kern_mount(&rootfs_fs_type, 0, "rootfs", NULL); if (IS_ERR(mnt)) panic("Can't create rootfs"); @@ -3746,6 +3744,7 @@ void __init mnt_init(void) fs_kobj = kobject_create_and_add("fs", NULL); if (!fs_kobj) printk(KERN_WARNING "%s: kobj create error\n", __func__); + shmem_init(); init_rootfs(); init_mount_tree(); } diff --git a/fs/nfsd/nfsctl.c b/fs/nfsd/nfsctl.c index 0a9a49ded546..13c548733860 100644 --- a/fs/nfsd/nfsctl.c +++ b/fs/nfsd/nfsctl.c @@ -8,6 +8,7 @@ #include <linux/slab.h> #include <linux/namei.h> #include <linux/ctype.h> +#include <linux/fs_context.h> #include <linux/sunrpc/svcsock.h> #include <linux/lockd/lockd.h> @@ -1337,7 +1338,7 @@ void nfsd_client_rmdir(struct dentry *dentry) inode_unlock(dir); } -static int nfsd_fill_super(struct super_block * sb, void * data, int silent) +static int nfsd_fill_super(struct super_block *sb, struct fs_context *fc) { struct nfsd_net *nn = net_generic(current->nsproxy->net_ns, nfsd_net_id); @@ -1372,7 +1373,7 @@ static int nfsd_fill_super(struct super_block * sb, void * data, int silent) #endif /* last one */ {""} }; - get_net(sb->s_fs_info); + ret = simple_fill_super(sb, 0x6e667364, nfsd_files); if (ret) return ret; @@ -1381,14 +1382,31 @@ static int nfsd_fill_super(struct super_block * sb, void * data, int silent) return PTR_ERR(dentry); nn->nfsd_client_dir = dentry; return 0; +} +static int nfsd_fs_get_tree(struct fs_context *fc) +{ + fc->s_fs_info = get_net(fc->net_ns); + return vfs_get_super(fc, vfs_get_keyed_super, nfsd_fill_super); } -static struct dentry *nfsd_mount(struct file_system_type *fs_type, - int flags, const char *dev_name, void *data) +static void nfsd_fs_free_fc(struct fs_context *fc) { - struct net *net = current->nsproxy->net_ns; - return mount_ns(fs_type, flags, data, net, net->user_ns, nfsd_fill_super); + if (fc->s_fs_info) + put_net(fc->s_fs_info); +} + +static const struct fs_context_operations nfsd_fs_context_ops = { + .free = nfsd_fs_free_fc, + .get_tree = nfsd_fs_get_tree, +}; + +static int nfsd_init_fs_context(struct fs_context *fc) +{ + put_user_ns(fc->user_ns); + fc->user_ns = get_user_ns(fc->net_ns->user_ns); + fc->ops = &nfsd_fs_context_ops; + return 0; } static void nfsd_umount(struct super_block *sb) @@ -1402,7 +1420,7 @@ static void nfsd_umount(struct super_block *sb) static struct file_system_type nfsd_fs_type = { .owner = THIS_MODULE, .name = "nfsd", - .mount = nfsd_mount, + .init_fs_context = nfsd_init_fs_context, .kill_sb = nfsd_umount, }; MODULE_ALIAS_FS("nfsd"); diff --git a/fs/nsfs.c b/fs/nsfs.c index e3bf08c5af41..a0431642c6b5 100644 --- a/fs/nsfs.c +++ b/fs/nsfs.c @@ -1,5 +1,6 @@ // SPDX-License-Identifier: GPL-2.0 #include <linux/mount.h> +#include <linux/pseudo_fs.h> #include <linux/file.h> #include <linux/fs.h> #include <linux/proc_ns.h> @@ -258,15 +259,20 @@ static const struct super_operations nsfs_ops = { .evict_inode = nsfs_evict, .show_path = nsfs_show_path, }; -static struct dentry *nsfs_mount(struct file_system_type *fs_type, - int flags, const char *dev_name, void *data) + +static int nsfs_init_fs_context(struct fs_context *fc) { - return mount_pseudo(fs_type, "nsfs:", &nsfs_ops, - &ns_dentry_operations, NSFS_MAGIC); + struct pseudo_fs_context *ctx = init_pseudo(fc, NSFS_MAGIC); + if (!ctx) + return -ENOMEM; + ctx->ops = &nsfs_ops; + ctx->dops = &ns_dentry_operations; + return 0; } + static struct file_system_type nsfs = { .name = "nsfs", - .mount = nsfs_mount, + .init_fs_context = nsfs_init_fs_context, .kill_sb = kill_anon_super, }; diff --git a/fs/openpromfs/inode.c b/fs/openpromfs/inode.c index e6cb7689fec4..40c8c2e32fa3 100644 --- a/fs/openpromfs/inode.c +++ b/fs/openpromfs/inode.c @@ -9,6 +9,7 @@ #include <linux/types.h> #include <linux/string.h> #include <linux/fs.h> +#include <linux/fs_context.h> #include <linux/init.h> #include <linux/slab.h> #include <linux/seq_file.h> @@ -375,7 +376,7 @@ 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, struct fs_context *fc) { struct inode *root_inode; struct op_inode_info *oi; @@ -409,16 +410,25 @@ out_no_root: return ret; } -static struct dentry *openprom_mount(struct file_system_type *fs_type, - int flags, const char *dev_name, void *data) +static int openpromfs_get_tree(struct fs_context *fc) { - return mount_single(fs_type, flags, data, openprom_fill_super); + return get_tree_single(fc, openprom_fill_super); +} + +static const struct fs_context_operations openpromfs_context_ops = { + .get_tree = openpromfs_get_tree, +}; + +static int openpromfs_init_fs_context(struct fs_context *fc) +{ + fc->ops = &openpromfs_context_ops; + return 0; } static struct file_system_type openprom_fs_type = { .owner = THIS_MODULE, .name = "openpromfs", - .mount = openprom_mount, + .init_fs_context = openpromfs_init_fs_context, .kill_sb = kill_anon_super, }; MODULE_ALIAS_FS("openpromfs"); diff --git a/fs/pipe.c b/fs/pipe.c index 41065901106b..8a2ab2f974bd 100644 --- a/fs/pipe.c +++ b/fs/pipe.c @@ -14,6 +14,7 @@ #include <linux/fs.h> #include <linux/log2.h> #include <linux/mount.h> +#include <linux/pseudo_fs.h> #include <linux/magic.h> #include <linux/pipe_fs_i.h> #include <linux/uio.h> @@ -1182,16 +1183,20 @@ static const struct super_operations pipefs_ops = { * any operations on the root directory. However, we need a non-trivial * 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) + +static int pipefs_init_fs_context(struct fs_context *fc) { - return mount_pseudo(fs_type, "pipe:", &pipefs_ops, - &pipefs_dentry_operations, PIPEFS_MAGIC); + struct pseudo_fs_context *ctx = init_pseudo(fc, PIPEFS_MAGIC); + if (!ctx) + return -ENOMEM; + ctx->ops = &pipefs_ops; + ctx->dops = &pipefs_dentry_operations; + return 0; } static struct file_system_type pipe_fs_type = { .name = "pipefs", - .mount = pipefs_mount, + .init_fs_context = pipefs_init_fs_context, .kill_sb = kill_anon_super, }; diff --git a/fs/proc/root.c b/fs/proc/root.c index 522199e9525e..33f72d1b92cc 100644 --- a/fs/proc/root.c +++ b/fs/proc/root.c @@ -157,8 +157,6 @@ static int proc_get_tree(struct fs_context *fc) { struct proc_fs_context *ctx = fc->fs_private; - put_user_ns(fc->user_ns); - fc->user_ns = get_user_ns(ctx->pid_ns->user_ns); fc->s_fs_info = ctx->pid_ns; return vfs_get_super(fc, vfs_get_keyed_super, proc_fill_super); } @@ -167,8 +165,7 @@ static void proc_fs_context_free(struct fs_context *fc) { struct proc_fs_context *ctx = fc->fs_private; - if (ctx->pid_ns) - put_pid_ns(ctx->pid_ns); + put_pid_ns(ctx->pid_ns); kfree(ctx); } @@ -188,6 +185,8 @@ static int proc_init_fs_context(struct fs_context *fc) return -ENOMEM; ctx->pid_ns = get_pid_ns(task_active_pid_ns(current)); + put_user_ns(fc->user_ns); + fc->user_ns = get_user_ns(ctx->pid_ns->user_ns); fc->fs_private = ctx; fc->ops = &proc_fs_context_ops; return 0; diff --git a/fs/ramfs/inode.c b/fs/ramfs/inode.c index 11201b2d06b9..733c6b4193dc 100644 --- a/fs/ramfs/inode.c +++ b/fs/ramfs/inode.c @@ -266,12 +266,8 @@ static struct file_system_type ramfs_fs_type = { .fs_flags = FS_USERNS_MOUNT, }; -int __init init_ramfs_fs(void) +static int __init init_ramfs_fs(void) { - static unsigned long once; - - if (test_and_set_bit(0, &once)) - return 0; return register_filesystem(&ramfs_fs_type); } fs_initcall(init_ramfs_fs); diff --git a/fs/super.c b/fs/super.c index 2739f57515f8..113c58f19425 100644 --- a/fs/super.c +++ b/fs/super.c @@ -476,6 +476,17 @@ void generic_shutdown_super(struct super_block *sb) EXPORT_SYMBOL(generic_shutdown_super); +bool mount_capable(struct fs_context *fc) +{ + struct user_namespace *user_ns = fc->global ? &init_user_ns + : fc->user_ns; + + if (!(fc->fs_type->fs_flags & FS_USERNS_MOUNT)) + return capable(CAP_SYS_ADMIN); + else + return ns_capable(user_ns, CAP_SYS_ADMIN); +} + /** * sget_fc - Find or create a superblock * @fc: Filesystem context. @@ -503,20 +514,6 @@ struct super_block *sget_fc(struct fs_context *fc, struct user_namespace *user_ns = fc->global ? &init_user_ns : fc->user_ns; 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)) { - if (!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); if (test) { @@ -543,6 +540,7 @@ retry: } fc->s_fs_info = NULL; s->s_type = fc->fs_type; + s->s_iflags |= fc->s_iflags; strlcpy(s->s_id, s->s_type->name, sizeof(s->s_id)); list_add_tail(&s->s_list, &super_blocks); hlist_add_head(&s->s_instances, &s->s_type->fs_supers); @@ -565,28 +563,31 @@ share_extant_sb: EXPORT_SYMBOL(sget_fc); /** - * sget_userns - find or create a superblock - * @type: filesystem type superblock should belong to - * @test: comparison callback - * @set: setup callback - * @flags: mount flags - * @user_ns: User namespace for the super_block - * @data: argument to each of them + * sget - find or create a superblock + * @type: filesystem type superblock should belong to + * @test: comparison callback + * @set: setup callback + * @flags: mount flags + * @data: argument to each of them */ -struct super_block *sget_userns(struct file_system_type *type, +struct super_block *sget(struct file_system_type *type, int (*test)(struct super_block *,void *), int (*set)(struct super_block *,void *), - int flags, struct user_namespace *user_ns, + int flags, void *data) { + struct user_namespace *user_ns = current_user_ns(); struct super_block *s = NULL; struct super_block *old; int err; - if (!(flags & (SB_KERNMOUNT|SB_SUBMOUNT)) && - !(type->fs_flags & FS_USERNS_MOUNT) && - !capable(CAP_SYS_ADMIN)) - return ERR_PTR(-EPERM); + /* We don't yet pass the user namespace of the parent + * mount through to here so always use &init_user_ns + * until that changes. + */ + if (flags & SB_SUBMOUNT) + user_ns = &init_user_ns; + retry: spin_lock(&sb_lock); if (test) { @@ -627,39 +628,6 @@ retry: register_shrinker_prepared(&s->s_shrink); return s; } - -EXPORT_SYMBOL(sget_userns); - -/** - * sget - find or create a superblock - * @type: filesystem type superblock should belong to - * @test: comparison callback - * @set: setup callback - * @flags: mount flags - * @data: argument to each of them - */ -struct super_block *sget(struct file_system_type *type, - int (*test)(struct super_block *,void *), - int (*set)(struct super_block *,void *), - int flags, - void *data) -{ - struct user_namespace *user_ns = current_user_ns(); - - /* We don't yet pass the user namespace of the parent - * mount through to here so always use &init_user_ns - * until that changes. - */ - if (flags & SB_SUBMOUNT) - user_ns = &init_user_ns; - - /* Ensure the requestor has permissions over the target filesystem */ - if (!(flags & (SB_KERNMOUNT|SB_SUBMOUNT)) && !ns_capable(user_ns, CAP_SYS_ADMIN)) - return ERR_PTR(-EPERM); - - return sget_userns(type, test, set, flags, user_ns, data); -} - EXPORT_SYMBOL(sget); void drop_super(struct super_block *sb) @@ -1147,50 +1115,6 @@ void kill_litter_super(struct super_block *sb) } EXPORT_SYMBOL(kill_litter_super); -static int ns_test_super(struct super_block *sb, void *data) -{ - return sb->s_fs_info == data; -} - -static int ns_set_super(struct super_block *sb, void *data) -{ - sb->s_fs_info = data; - return set_anon_super(sb, NULL); -} - -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)) -{ - struct super_block *sb; - - /* Don't allow mounting unless the caller has CAP_SYS_ADMIN - * over the namespace. - */ - if (!(flags & SB_KERNMOUNT) && !ns_capable(user_ns, CAP_SYS_ADMIN)) - return ERR_PTR(-EPERM); - - sb = sget_userns(fs_type, ns_test_super, ns_set_super, flags, - user_ns, ns); - if (IS_ERR(sb)) - return ERR_CAST(sb); - - if (!sb->s_root) { - int err; - err = fill_super(sb, data, flags & SB_SILENT ? 1 : 0); - if (err) { - deactivate_locked_super(sb); - return ERR_PTR(err); - } - - sb->s_flags |= SB_ACTIVE; - } - - return dget(sb->s_root); -} - -EXPORT_SYMBOL(mount_ns); - int set_anon_super_fc(struct super_block *sb, struct fs_context *fc) { return set_anon_super(sb, NULL); @@ -1274,6 +1198,22 @@ int vfs_get_super(struct fs_context *fc, } EXPORT_SYMBOL(vfs_get_super); +int get_tree_nodev(struct fs_context *fc, + int (*fill_super)(struct super_block *sb, + struct fs_context *fc)) +{ + return vfs_get_super(fc, vfs_get_independent_super, fill_super); +} +EXPORT_SYMBOL(get_tree_nodev); + +int get_tree_single(struct fs_context *fc, + int (*fill_super)(struct super_block *sb, + struct fs_context *fc)) +{ + return vfs_get_super(fc, vfs_get_single_super, fill_super); +} +EXPORT_SYMBOL(get_tree_single); + #ifdef CONFIG_BLOCK static int set_bdev_super(struct super_block *s, void *data) { diff --git a/fs/sysfs/mount.c b/fs/sysfs/mount.c index 1b56686ab178..db81cfbab9d6 100644 --- a/fs/sysfs/mount.c +++ b/fs/sysfs/mount.c @@ -72,8 +72,7 @@ static int sysfs_init_fs_context(struct fs_context *fc) fc->fs_private = kfc; fc->ops = &sysfs_fs_context_ops; if (netns) { - if (fc->user_ns) - put_user_ns(fc->user_ns); + put_user_ns(fc->user_ns); fc->user_ns = get_user_ns(netns->user_ns); } fc->global = true; diff --git a/include/linux/dcache.h b/include/linux/dcache.h index 5e0eadf7de55..9451011ac014 100644 --- a/include/linux/dcache.h +++ b/include/linux/dcache.h @@ -291,7 +291,6 @@ static inline unsigned d_count(const struct dentry *dentry) */ extern __printf(4, 5) char *dynamic_dname(struct dentry *, char *, int, const char *, ...); -extern char *simple_dname(struct dentry *, char *, int); extern char *__d_path(const struct path *, const struct path *, char *, int); extern char *d_absolute_path(const struct path *, char *, int); diff --git a/include/linux/fs.h b/include/linux/fs.h index 75f2ed289a3f..56b8e358af5c 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -2210,9 +2210,6 @@ 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)); #ifdef CONFIG_BLOCK extern struct dentry *mount_bdev(struct file_system_type *fs_type, int flags, const char *dev_name, void *data, @@ -2252,28 +2249,10 @@ 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 *), - int flags, struct user_namespace *user_ns, - void *data); struct super_block *sget(struct file_system_type *type, int (*test)(struct super_block *,void *), int (*set)(struct super_block *,void *), int flags, void *data); -extern struct dentry *mount_pseudo_xattr(struct file_system_type *, char *, - const struct super_operations *ops, - const struct xattr_handler **xattr, - const struct dentry_operations *dops, - unsigned long); - -static inline struct dentry * -mount_pseudo(struct file_system_type *fs_type, char *name, - const struct super_operations *ops, - const struct dentry_operations *dops, unsigned long magic) -{ - return mount_pseudo_xattr(fs_type, name, ops, NULL, dops, magic); -} /* Alas, no aliases. Too much hassle with bringing module.h everywhere */ #define fops_get(fops) \ diff --git a/include/linux/fs_context.h b/include/linux/fs_context.h index 4933187d5b9a..7c6fe3d47fa6 100644 --- a/include/linux/fs_context.h +++ b/include/linux/fs_context.h @@ -99,6 +99,7 @@ struct fs_context { void *s_fs_info; /* Proposed s_fs_info */ unsigned int sb_flags; /* Proposed superblock flags (SB_*) */ unsigned int sb_flags_mask; /* Superblock flags that were changed */ + unsigned int s_iflags; /* OR'd with sb->s_iflags */ unsigned int lsm_flags; /* Information flags from the fs to the LSM */ enum fs_context_purpose purpose:8; enum fs_context_phase phase:8; /* The phase the context is in */ @@ -146,6 +147,12 @@ extern int vfs_get_super(struct fs_context *fc, enum vfs_get_super_keying keying, int (*fill_super)(struct super_block *sb, struct fs_context *fc)); +extern int get_tree_nodev(struct fs_context *fc, + int (*fill_super)(struct super_block *sb, + struct fs_context *fc)); +extern int get_tree_single(struct fs_context *fc, + int (*fill_super)(struct super_block *sb, + struct fs_context *fc)); extern const struct file_operations fscontext_fops; diff --git a/include/linux/init.h b/include/linux/init.h index 5255069f5a9f..212fc9e2f691 100644 --- a/include/linux/init.h +++ b/include/linux/init.h @@ -137,6 +137,8 @@ extern initcall_entry_t __con_initcall_start[], __con_initcall_end[]; /* Used for contructor calls. */ typedef void (*ctor_fn_t)(void); +struct file_system_type; + /* Defined in init/main.c */ extern int do_one_initcall(initcall_t fn); extern char __initdata boot_command_line[]; @@ -146,7 +148,8 @@ extern unsigned int reset_devices; /* used by init/main.c */ void setup_arch(char **); void prepare_namespace(void); -int __init init_rootfs(void); +void __init init_rootfs(void); +extern struct file_system_type rootfs_fs_type; #if defined(CONFIG_STRICT_KERNEL_RWX) || defined(CONFIG_STRICT_MODULE_RWX) extern bool rodata_enabled; diff --git a/include/linux/pseudo_fs.h b/include/linux/pseudo_fs.h new file mode 100644 index 000000000000..eceda1d1407a --- /dev/null +++ b/include/linux/pseudo_fs.h @@ -0,0 +1,16 @@ +#ifndef __LINUX_PSEUDO_FS__ +#define __LINUX_PSEUDO_FS__ + +#include <linux/fs_context.h> + +struct pseudo_fs_context { + const struct super_operations *ops; + const struct xattr_handler **xattr; + const struct dentry_operations *dops; + unsigned long magic; +}; + +struct pseudo_fs_context *init_pseudo(struct fs_context *fc, + unsigned long magic); + +#endif diff --git a/include/linux/ramfs.h b/include/linux/ramfs.h index 5ef7d54caac2..ee582bdb7fda 100644 --- a/include/linux/ramfs.h +++ b/include/linux/ramfs.h @@ -19,7 +19,6 @@ extern int ramfs_nommu_expand_for_mapping(struct inode *inode, size_t newsize); extern const struct file_operations ramfs_file_operations; extern const struct vm_operations_struct generic_file_vm_ops; -extern int __init init_ramfs_fs(void); int ramfs_fill_super(struct super_block *sb, void *data, int silent); diff --git a/include/linux/syscalls.h b/include/linux/syscalls.h index b01d54a5732e..88145da7d140 100644 --- a/include/linux/syscalls.h +++ b/include/linux/syscalls.h @@ -1231,8 +1231,8 @@ asmlinkage long sys_ni_syscall(void); * the ksys_xyzyyz() functions prototyped below. */ -int ksys_mount(char __user *dev_name, char __user *dir_name, char __user *type, - unsigned long flags, void __user *data); +int ksys_mount(const char __user *dev_name, const char __user *dir_name, + const char __user *type, unsigned long flags, void __user *data); int ksys_umount(char __user *name, int flags); int ksys_dup(unsigned int fildes); int ksys_chroot(const char __user *filename); diff --git a/include/uapi/linux/magic.h b/include/uapi/linux/magic.h index 665e18627f78..1274c692e59c 100644 --- a/include/uapi/linux/magic.h +++ b/include/uapi/linux/magic.h @@ -92,5 +92,6 @@ #define BALLOON_KVM_MAGIC 0x13661366 #define ZSMALLOC_MAGIC 0x58295829 #define DMA_BUF_MAGIC 0x444d4142 /* "DMAB" */ +#define Z3FOLD_MAGIC 0x33 #endif /* __LINUX_MAGIC_H__ */ diff --git a/init/do_mounts.c b/init/do_mounts.c index 2d1ea3028454..53cb37b66227 100644 --- a/init/do_mounts.c +++ b/init/do_mounts.c @@ -630,41 +630,23 @@ static bool is_tmpfs; static struct dentry *rootfs_mount(struct file_system_type *fs_type, int flags, const char *dev_name, void *data) { - static unsigned long once; void *fill = ramfs_fill_super; - if (test_and_set_bit(0, &once)) - return ERR_PTR(-ENODEV); - if (IS_ENABLED(CONFIG_TMPFS) && is_tmpfs) fill = shmem_fill_super; return mount_nodev(fs_type, flags, data, fill); } -static struct file_system_type rootfs_fs_type = { +struct file_system_type rootfs_fs_type = { .name = "rootfs", .mount = rootfs_mount, .kill_sb = kill_litter_super, }; -int __init init_rootfs(void) +void __init init_rootfs(void) { - int err = register_filesystem(&rootfs_fs_type); - - if (err) - return err; - if (IS_ENABLED(CONFIG_TMPFS) && !saved_root_name[0] && - (!root_fs_names || strstr(root_fs_names, "tmpfs"))) { - err = shmem_init(); + (!root_fs_names || strstr(root_fs_names, "tmpfs"))) is_tmpfs = true; - } else { - err = init_ramfs_fs(); - } - - if (err) - unregister_filesystem(&rootfs_fs_type); - - return err; } diff --git a/init/main.c b/init/main.c index ff5803b0841c..96f8d5af52d6 100644 --- a/init/main.c +++ b/init/main.c @@ -1025,7 +1025,6 @@ static void __init do_initcalls(void) static void __init do_basic_setup(void) { cpuset_init_smp(); - shmem_init(); driver_init(); init_irq_proc(); do_ctors(); diff --git a/ipc/mqueue.c b/ipc/mqueue.c index 65c351564ad0..7a5a8edc3de3 100644 --- a/ipc/mqueue.c +++ b/ipc/mqueue.c @@ -364,8 +364,6 @@ static int mqueue_get_tree(struct fs_context *fc) { struct mqueue_fs_context *ctx = fc->fs_private; - put_user_ns(fc->user_ns); - fc->user_ns = get_user_ns(ctx->ipc_ns->user_ns); fc->s_fs_info = ctx->ipc_ns; return vfs_get_super(fc, vfs_get_keyed_super, mqueue_fill_super); } @@ -374,8 +372,7 @@ 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); + put_ipc_ns(ctx->ipc_ns); kfree(ctx); } @@ -388,6 +385,8 @@ static int mqueue_init_fs_context(struct fs_context *fc) return -ENOMEM; ctx->ipc_ns = get_ipc_ns(current->nsproxy->ipc_ns); + put_user_ns(fc->user_ns); + fc->user_ns = get_user_ns(ctx->ipc_ns->user_ns); fc->fs_private = ctx; fc->ops = &mqueue_fs_context_ops; return 0; @@ -406,6 +405,8 @@ static struct vfsmount *mq_create_mount(struct ipc_namespace *ns) ctx = fc->fs_private; put_ipc_ns(ctx->ipc_ns); ctx->ipc_ns = get_ipc_ns(ns); + put_user_ns(fc->user_ns); + fc->user_ns = get_user_ns(ctx->ipc_ns->user_ns); mnt = fc_mount(fc); put_fs_context(fc); diff --git a/kernel/cgroup/cgroup.c b/kernel/cgroup/cgroup.c index 300b0c416341..753afbca549f 100644 --- a/kernel/cgroup/cgroup.c +++ b/kernel/cgroup/cgroup.c @@ -2201,8 +2201,7 @@ static int cgroup_init_fs_context(struct fs_context *fc) fc->ops = &cgroup_fs_context_ops; else fc->ops = &cgroup1_fs_context_ops; - if (fc->user_ns) - put_user_ns(fc->user_ns); + put_user_ns(fc->user_ns); fc->user_ns = get_user_ns(ctx->ns->user_ns); fc->global = true; return 0; @@ -2243,6 +2242,50 @@ static struct file_system_type cgroup2_fs_type = { .fs_flags = FS_USERNS_MOUNT, }; +#ifdef CONFIG_CPUSETS +static const struct fs_context_operations cpuset_fs_context_ops = { + .get_tree = cgroup1_get_tree, + .free = cgroup_fs_context_free, +}; + +/* + * This is ugly, but preserves the userspace API for existing cpuset + * users. If someone tries to mount the "cpuset" filesystem, we + * silently switch it to mount "cgroup" instead + */ +static int cpuset_init_fs_context(struct fs_context *fc) +{ + char *agent = kstrdup("/sbin/cpuset_release_agent", GFP_USER); + struct cgroup_fs_context *ctx; + int err; + + err = cgroup_init_fs_context(fc); + if (err) { + kfree(agent); + return err; + } + + fc->ops = &cpuset_fs_context_ops; + + ctx = cgroup_fc2context(fc); + ctx->subsys_mask = 1 << cpuset_cgrp_id; + ctx->flags |= CGRP_ROOT_NOPREFIX; + ctx->release_agent = agent; + + get_filesystem(&cgroup_fs_type); + put_filesystem(fc->fs_type); + fc->fs_type = &cgroup_fs_type; + + return 0; +} + +static struct file_system_type cpuset_fs_type = { + .name = "cpuset", + .init_fs_context = cpuset_init_fs_context, + .fs_flags = FS_USERNS_MOUNT, +}; +#endif + int cgroup_path_ns_locked(struct cgroup *cgrp, char *buf, size_t buflen, struct cgroup_namespace *ns) { @@ -5761,6 +5804,9 @@ int __init cgroup_init(void) WARN_ON(register_filesystem(&cgroup_fs_type)); WARN_ON(register_filesystem(&cgroup2_fs_type)); WARN_ON(!proc_create_single("cgroups", 0, NULL, proc_cgroupstats_show)); +#ifdef CONFIG_CPUSETS + WARN_ON(register_filesystem(&cpuset_fs_type)); +#endif return 0; } diff --git a/kernel/cgroup/cpuset.c b/kernel/cgroup/cpuset.c index 863e434a6020..5aa37531ce76 100644 --- a/kernel/cgroup/cpuset.c +++ b/kernel/cgroup/cpuset.c @@ -356,59 +356,6 @@ static inline bool is_in_v2_mode(void) } /* - * This is ugly, but preserves the userspace API for existing cpuset - * users. If someone tries to mount the "cpuset" filesystem, we - * silently switch it to mount "cgroup" instead - */ -static int cpuset_get_tree(struct fs_context *fc) -{ - struct file_system_type *cgroup_fs; - struct fs_context *new_fc; - int ret; - - cgroup_fs = get_fs_type("cgroup"); - if (!cgroup_fs) - return -ENODEV; - - new_fc = fs_context_for_mount(cgroup_fs, fc->sb_flags); - if (IS_ERR(new_fc)) { - ret = PTR_ERR(new_fc); - } else { - static const char agent_path[] = "/sbin/cpuset_release_agent"; - ret = vfs_parse_fs_string(new_fc, "cpuset", NULL, 0); - if (!ret) - ret = vfs_parse_fs_string(new_fc, "noprefix", NULL, 0); - if (!ret) - ret = vfs_parse_fs_string(new_fc, "release_agent", - agent_path, sizeof(agent_path) - 1); - if (!ret) - ret = vfs_get_tree(new_fc); - if (!ret) { /* steal the result */ - fc->root = new_fc->root; - new_fc->root = NULL; - } - put_fs_context(new_fc); - } - put_filesystem(cgroup_fs); - 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) -{ - fc->ops = &cpuset_fs_context_ops; - return 0; -} - -static struct file_system_type cpuset_fs_type = { - .name = "cpuset", - .init_fs_context = cpuset_init_fs_context, -}; - -/* * Return in pmask the portion of a cpusets's cpus_allowed that * are online. If none are online, walk up the cpuset hierarchy * until we find one that does have some online cpus. @@ -2853,13 +2800,11 @@ struct cgroup_subsys cpuset_cgrp_subsys = { /** * cpuset_init - initialize cpusets at system boot * - * Description: Initialize top_cpuset and the cpuset internal file system, + * Description: Initialize top_cpuset **/ int __init cpuset_init(void) { - int err = 0; - BUG_ON(!alloc_cpumask_var(&top_cpuset.cpus_allowed, GFP_KERNEL)); BUG_ON(!alloc_cpumask_var(&top_cpuset.effective_cpus, GFP_KERNEL)); BUG_ON(!zalloc_cpumask_var(&top_cpuset.subparts_cpus, GFP_KERNEL)); @@ -2873,10 +2818,6 @@ int __init cpuset_init(void) set_bit(CS_SCHED_LOAD_BALANCE, &top_cpuset.flags); top_cpuset.relax_domain_level = -1; - err = register_filesystem(&cpuset_fs_type); - if (err < 0) - return err; - BUG_ON(!alloc_cpumask_var(&cpus_attach, GFP_KERNEL)); return 0; diff --git a/mm/shmem.c b/mm/shmem.c index c88a30919ae5..626d8c74b973 100644 --- a/mm/shmem.c +++ b/mm/shmem.c @@ -3777,10 +3777,6 @@ int __init shmem_init(void) { int error; - /* If rootfs called this, don't re-init */ - if (shmem_inode_cachep) - return 0; - shmem_init_inodecache(); error = register_filesystem(&shmem_fs_type); diff --git a/mm/z3fold.c b/mm/z3fold.c index 6c72b18d8b9c..1a029a7432ee 100644 --- a/mm/z3fold.c +++ b/mm/z3fold.c @@ -26,7 +26,6 @@ #include <linux/atomic.h> #include <linux/sched.h> #include <linux/cpumask.h> -#include <linux/dcache.h> #include <linux/list.h> #include <linux/mm.h> #include <linux/module.h> @@ -36,12 +35,14 @@ #include <linux/compaction.h> #include <linux/percpu.h> #include <linux/mount.h> +#include <linux/pseudo_fs.h> #include <linux/fs.h> #include <linux/preempt.h> #include <linux/workqueue.h> #include <linux/slab.h> #include <linux/spinlock.h> #include <linux/zpool.h> +#include <linux/magic.h> /* * NCHUNKS_ORDER determines the internal allocation granularity, effectively @@ -245,19 +246,14 @@ static inline void free_handle(unsigned long handle) } } -static struct dentry *z3fold_do_mount(struct file_system_type *fs_type, - int flags, const char *dev_name, void *data) +static int z3fold_init_fs_context(struct fs_context *fc) { - static const struct dentry_operations ops = { - .d_dname = simple_dname, - }; - - return mount_pseudo(fs_type, "z3fold:", NULL, &ops, 0x33); + return init_pseudo(fc, Z3FOLD_MAGIC) ? 0 : -ENOMEM; } static struct file_system_type z3fold_fs = { .name = "z3fold", - .mount = z3fold_do_mount, + .init_fs_context = z3fold_init_fs_context, .kill_sb = kill_anon_super, }; diff --git a/mm/zsmalloc.c b/mm/zsmalloc.c index db09eb3669c5..57fbb7ced69f 100644 --- a/mm/zsmalloc.c +++ b/mm/zsmalloc.c @@ -52,6 +52,7 @@ #include <linux/zsmalloc.h> #include <linux/zpool.h> #include <linux/mount.h> +#include <linux/pseudo_fs.h> #include <linux/migrate.h> #include <linux/pagemap.h> #include <linux/fs.h> @@ -1798,19 +1799,14 @@ static void lock_zspage(struct zspage *zspage) } while ((page = get_next_page(page)) != NULL); } -static struct dentry *zs_mount(struct file_system_type *fs_type, - int flags, const char *dev_name, void *data) +static int zs_init_fs_context(struct fs_context *fc) { - static const struct dentry_operations ops = { - .d_dname = simple_dname, - }; - - return mount_pseudo(fs_type, "zsmalloc:", NULL, &ops, ZSMALLOC_MAGIC); + return init_pseudo(fc, ZSMALLOC_MAGIC) ? 0 : -ENOMEM; } static struct file_system_type zsmalloc_fs = { .name = "zsmalloc", - .mount = zs_mount, + .init_fs_context = zs_init_fs_context, .kill_sb = kill_anon_super, }; diff --git a/net/socket.c b/net/socket.c index 293d56836f01..6a9ab7a8b1d2 100644 --- a/net/socket.c +++ b/net/socket.c @@ -73,6 +73,7 @@ #include <linux/module.h> #include <linux/highmem.h> #include <linux/mount.h> +#include <linux/pseudo_fs.h> #include <linux/security.h> #include <linux/syscalls.h> #include <linux/compat.h> @@ -338,19 +339,22 @@ static const struct xattr_handler *sockfs_xattr_handlers[] = { NULL }; -static struct dentry *sockfs_mount(struct file_system_type *fs_type, - int flags, const char *dev_name, void *data) +static int sockfs_init_fs_context(struct fs_context *fc) { - return mount_pseudo_xattr(fs_type, "socket:", &sockfs_ops, - sockfs_xattr_handlers, - &sockfs_dentry_operations, SOCKFS_MAGIC); + struct pseudo_fs_context *ctx = init_pseudo(fc, SOCKFS_MAGIC); + if (!ctx) + return -ENOMEM; + ctx->ops = &sockfs_ops; + ctx->dops = &sockfs_dentry_operations; + ctx->xattr = sockfs_xattr_handlers; + return 0; } static struct vfsmount *sock_mnt __read_mostly; static struct file_system_type sock_fs_type = { .name = "sockfs", - .mount = sockfs_mount, + .init_fs_context = sockfs_init_fs_context, .kill_sb = kill_anon_super, }; diff --git a/net/sunrpc/rpc_pipe.c b/net/sunrpc/rpc_pipe.c index 73bd62979fe7..748bac601e47 100644 --- a/net/sunrpc/rpc_pipe.c +++ b/net/sunrpc/rpc_pipe.c @@ -14,6 +14,7 @@ #include <linux/string.h> #include <linux/pagemap.h> #include <linux/mount.h> +#include <linux/fs_context.h> #include <linux/namei.h> #include <linux/fsnotify.h> #include <linux/kernel.h> @@ -1352,11 +1353,11 @@ rpc_gssd_dummy_depopulate(struct dentry *pipe_dentry) } static int -rpc_fill_super(struct super_block *sb, void *data, int silent) +rpc_fill_super(struct super_block *sb, struct fs_context *fc) { struct inode *inode; struct dentry *root, *gssd_dentry; - struct net *net = get_net(sb->s_fs_info); + struct net *net = sb->s_fs_info; struct sunrpc_net *sn = net_generic(net, sunrpc_net_id); int err; @@ -1413,12 +1414,29 @@ gssd_running(struct net *net) } EXPORT_SYMBOL_GPL(gssd_running); -static struct dentry * -rpc_mount(struct file_system_type *fs_type, - int flags, const char *dev_name, void *data) +static int rpc_fs_get_tree(struct fs_context *fc) +{ + fc->s_fs_info = get_net(fc->net_ns); + return vfs_get_super(fc, vfs_get_keyed_super, rpc_fill_super); +} + +static void rpc_fs_free_fc(struct fs_context *fc) { - struct net *net = current->nsproxy->net_ns; - return mount_ns(fs_type, flags, data, net, net->user_ns, rpc_fill_super); + if (fc->s_fs_info) + put_net(fc->s_fs_info); +} + +static const struct fs_context_operations rpc_fs_context_ops = { + .free = rpc_fs_free_fc, + .get_tree = rpc_fs_get_tree, +}; + +static int rpc_init_fs_context(struct fs_context *fc) +{ + put_user_ns(fc->user_ns); + fc->user_ns = get_user_ns(fc->net_ns->user_ns); + fc->ops = &rpc_fs_context_ops; + return 0; } static void rpc_kill_sb(struct super_block *sb) @@ -1446,7 +1464,7 @@ out: static struct file_system_type rpc_pipe_fs_type = { .owner = THIS_MODULE, .name = "rpc_pipefs", - .mount = rpc_mount, + .init_fs_context = rpc_init_fs_context, .kill_sb = rpc_kill_sb, }; MODULE_ALIAS_FS("rpc_pipefs"); diff --git a/security/apparmor/apparmorfs.c b/security/apparmor/apparmorfs.c index 66d0b4245ef6..45d13b6462aa 100644 --- a/security/apparmor/apparmorfs.c +++ b/security/apparmor/apparmorfs.c @@ -19,6 +19,7 @@ #include <linux/capability.h> #include <linux/rcupdate.h> #include <linux/fs.h> +#include <linux/fs_context.h> #include <linux/poll.h> #include <uapi/linux/major.h> #include <uapi/linux/magic.h> @@ -132,7 +133,7 @@ static const struct super_operations aafs_super_ops = { .show_path = aafs_show_path, }; -static int fill_super(struct super_block *sb, void *data, int silent) +static int apparmorfs_fill_super(struct super_block *sb, struct fs_context *fc) { static struct tree_descr files[] = { {""} }; int error; @@ -145,16 +146,25 @@ static int fill_super(struct super_block *sb, void *data, int silent) return 0; } -static struct dentry *aafs_mount(struct file_system_type *fs_type, - int flags, const char *dev_name, void *data) +static int apparmorfs_get_tree(struct fs_context *fc) { - return mount_single(fs_type, flags, data, fill_super); + return get_tree_single(fc, apparmorfs_fill_super); +} + +static const struct fs_context_operations apparmorfs_context_ops = { + .get_tree = apparmorfs_get_tree, +}; + +static int apparmorfs_init_fs_context(struct fs_context *fc) +{ + fc->ops = &apparmorfs_context_ops; + return 0; } static struct file_system_type aafs_ops = { .owner = THIS_MODULE, .name = AAFS_NAME, - .mount = aafs_mount, + .init_fs_context = apparmorfs_init_fs_context, .kill_sb = kill_anon_super, }; diff --git a/security/inode.c b/security/inode.c index fcff7f08bb1c..6c326939750d 100644 --- a/security/inode.c +++ b/security/inode.c @@ -13,6 +13,7 @@ #include <linux/sysfs.h> #include <linux/kobject.h> #include <linux/fs.h> +#include <linux/fs_context.h> #include <linux/mount.h> #include <linux/pagemap.h> #include <linux/init.h> @@ -36,7 +37,7 @@ static const struct super_operations securityfs_super_operations = { .free_inode = securityfs_free_inode, }; -static int fill_super(struct super_block *sb, void *data, int silent) +static int securityfs_fill_super(struct super_block *sb, struct fs_context *fc) { static const struct tree_descr files[] = {{""}}; int error; @@ -50,17 +51,25 @@ static int fill_super(struct super_block *sb, void *data, int silent) return 0; } -static struct dentry *get_sb(struct file_system_type *fs_type, - int flags, const char *dev_name, - void *data) +static int securityfs_get_tree(struct fs_context *fc) { - return mount_single(fs_type, flags, data, fill_super); + return get_tree_single(fc, securityfs_fill_super); +} + +static const struct fs_context_operations securityfs_context_ops = { + .get_tree = securityfs_get_tree, +}; + +static int securityfs_init_fs_context(struct fs_context *fc) +{ + fc->ops = &securityfs_context_ops; + return 0; } static struct file_system_type fs_type = { .owner = THIS_MODULE, .name = "securityfs", - .mount = get_sb, + .init_fs_context = securityfs_init_fs_context, .kill_sb = kill_litter_super, }; diff --git a/security/selinux/selinuxfs.c b/security/selinux/selinuxfs.c index 6f195c7915de..e6c7643c3fc0 100644 --- a/security/selinux/selinuxfs.c +++ b/security/selinux/selinuxfs.c @@ -17,6 +17,7 @@ #include <linux/slab.h> #include <linux/vmalloc.h> #include <linux/fs.h> +#include <linux/fs_context.h> #include <linux/mount.h> #include <linux/mutex.h> #include <linux/init.h> @@ -1891,7 +1892,7 @@ static struct dentry *sel_make_dir(struct dentry *dir, const char *name, #define NULL_FILE_NAME "null" -static int sel_fill_super(struct super_block *sb, void *data, int silent) +static int sel_fill_super(struct super_block *sb, struct fs_context *fc) { struct selinux_fs_info *fsi; int ret; @@ -2007,10 +2008,19 @@ err: return ret; } -static struct dentry *sel_mount(struct file_system_type *fs_type, - int flags, const char *dev_name, void *data) +static int sel_get_tree(struct fs_context *fc) { - return mount_single(fs_type, flags, data, sel_fill_super); + return get_tree_single(fc, sel_fill_super); +} + +static const struct fs_context_operations sel_context_ops = { + .get_tree = sel_get_tree, +}; + +static int sel_init_fs_context(struct fs_context *fc) +{ + fc->ops = &sel_context_ops; + return 0; } static void sel_kill_sb(struct super_block *sb) @@ -2021,7 +2031,7 @@ static void sel_kill_sb(struct super_block *sb) static struct file_system_type sel_fs_type = { .name = "selinuxfs", - .mount = sel_mount, + .init_fs_context = sel_init_fs_context, .kill_sb = sel_kill_sb, }; diff --git a/security/smack/smackfs.c b/security/smack/smackfs.c index ef0d8712d318..e3e05c04dbd1 100644 --- a/security/smack/smackfs.c +++ b/security/smack/smackfs.c @@ -23,6 +23,7 @@ #include <linux/ctype.h> #include <linux/audit.h> #include <linux/magic.h> +#include <linux/fs_context.h> #include "smack.h" #define BEBITS (sizeof(__be32) * 8) @@ -2816,14 +2817,13 @@ static const struct file_operations smk_ptrace_ops = { /** * smk_fill_super - fill the smackfs superblock * @sb: the empty superblock - * @data: unused - * @silent: unused + * @fc: unused * * Fill in the well known entries for the smack filesystem * * Returns 0 on success, an error code on failure */ -static int smk_fill_super(struct super_block *sb, void *data, int silent) +static int smk_fill_super(struct super_block *sb, struct fs_context *fc) { int rc; @@ -2893,25 +2893,35 @@ static int smk_fill_super(struct super_block *sb, void *data, int silent) } /** - * smk_mount - get the smackfs superblock - * @fs_type: passed along without comment - * @flags: passed along without comment - * @dev_name: passed along without comment - * @data: passed along without comment + * smk_get_tree - get the smackfs superblock + * @fc: The mount context, including any options * * Just passes everything along. * * Returns what the lower level code does. */ -static struct dentry *smk_mount(struct file_system_type *fs_type, - int flags, const char *dev_name, void *data) +static int smk_get_tree(struct fs_context *fc) { - return mount_single(fs_type, flags, data, smk_fill_super); + return get_tree_single(fc, smk_fill_super); +} + +static const struct fs_context_operations smk_context_ops = { + .get_tree = smk_get_tree, +}; + +/** + * smk_init_fs_context - Initialise a filesystem context for smackfs + * @fc: The blank mount context + */ +static int smk_init_fs_context(struct fs_context *fc) +{ + fc->ops = &smk_context_ops; + return 0; } static struct file_system_type smk_fs_type = { .name = "smackfs", - .mount = smk_mount, + .init_fs_context = smk_init_fs_context, .kill_sb = kill_litter_super, }; |