summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--drivers/base/devtmpfs.c38
-rw-r--r--drivers/mtd/mtdsuper.c189
-rw-r--r--fs/cramfs/inode.c69
-rw-r--r--fs/fs_parser.c18
-rw-r--r--fs/jffs2/fs.c21
-rw-r--r--fs/jffs2/os-linux.h4
-rw-r--r--fs/jffs2/super.c172
-rw-r--r--fs/ramfs/inode.c99
-rw-r--r--fs/romfs/super.c46
-rw-r--r--fs/squashfs/super.c100
-rw-r--r--fs/super.c35
-rw-r--r--include/linux/fs_context.h4
-rw-r--r--include/linux/mtd/super.h3
-rw-r--r--include/linux/ramfs.h6
-rw-r--r--include/linux/shmem_fs.h3
-rw-r--r--init/do_mounts.c11
-rw-r--r--mm/shmem.c385
17 files changed, 609 insertions, 594 deletions
diff --git a/drivers/base/devtmpfs.c b/drivers/base/devtmpfs.c
index ba5c80903efe..30d0523014e0 100644
--- a/drivers/base/devtmpfs.c
+++ b/drivers/base/devtmpfs.c
@@ -56,20 +56,32 @@ 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,
+static struct vfsmount *mnt;
+
+static struct dentry *public_dev_mount(struct file_system_type *fs_type, int flags,
const char *dev_name, void *data)
{
+ struct super_block *s = mnt->mnt_sb;
+ atomic_inc(&s->s_active);
+ down_write(&s->s_umount);
+ return dget(s->s_root);
+}
+
+static struct file_system_type internal_fs_type = {
+ .name = "devtmpfs",
#ifdef CONFIG_TMPFS
- return mount_single(fs_type, flags, data, shmem_fill_super);
+ .init_fs_context = shmem_init_fs_context,
+ .parameters = &shmem_fs_parameters,
#else
- return mount_single(fs_type, flags, data, ramfs_fill_super);
+ .init_fs_context = ramfs_init_fs_context,
+ .parameters = &ramfs_fs_parameters,
#endif
-}
+ .kill_sb = kill_litter_super,
+};
static struct file_system_type dev_fs_type = {
.name = "devtmpfs",
- .mount = dev_mount,
- .kill_sb = kill_litter_super,
+ .mount = public_dev_mount,
};
#ifdef CONFIG_BLOCK
@@ -378,12 +390,11 @@ static int handle(const char *name, umode_t mode, kuid_t uid, kgid_t gid,
static int devtmpfsd(void *p)
{
- char options[] = "mode=0755";
int *err = p;
*err = ksys_unshare(CLONE_NEWNS);
if (*err)
goto out;
- *err = ksys_mount("devtmpfs", "/", "devtmpfs", MS_SILENT, options);
+ *err = ksys_mount("devtmpfs", "/", "devtmpfs", MS_SILENT, NULL);
if (*err)
goto out;
ksys_chdir("/.."); /* will traverse into overmounted root */
@@ -420,7 +431,16 @@ out:
*/
int __init devtmpfs_init(void)
{
- int err = register_filesystem(&dev_fs_type);
+ char opts[] = "mode=0755";
+ int err;
+
+ mnt = vfs_kern_mount(&internal_fs_type, 0, "devtmpfs", opts);
+ if (IS_ERR(mnt)) {
+ printk(KERN_ERR "devtmpfs: unable to create devtmpfs %ld\n",
+ PTR_ERR(mnt));
+ return PTR_ERR(mnt);
+ }
+ err = register_filesystem(&dev_fs_type);
if (err) {
printk(KERN_ERR "devtmpfs: unable to register devtmpfs "
"type %i\n", err);
diff --git a/drivers/mtd/mtdsuper.c b/drivers/mtd/mtdsuper.c
index 3f9a3b7b12c5..c3e2098372f2 100644
--- a/drivers/mtd/mtdsuper.c
+++ b/drivers/mtd/mtdsuper.c
@@ -194,195 +194,6 @@ int get_tree_mtd(struct fs_context *fc,
EXPORT_SYMBOL_GPL(get_tree_mtd);
/*
- * compare superblocks to see if they're equivalent
- * - they are if the underlying MTD device is the same
- */
-static int get_sb_mtd_compare(struct super_block *sb, void *_mtd)
-{
- struct mtd_info *mtd = _mtd;
-
- if (sb->s_mtd == mtd) {
- pr_debug("MTDSB: Match on device %d (\"%s\")\n",
- mtd->index, mtd->name);
- return 1;
- }
-
- pr_debug("MTDSB: No match, device %d (\"%s\"), device %d (\"%s\")\n",
- sb->s_mtd->index, sb->s_mtd->name, mtd->index, mtd->name);
- return 0;
-}
-
-/*
- * mark the superblock by the MTD device it is using
- * - set the device number to be the correct MTD block device for pesuperstence
- * of NFS exports
- */
-static int get_sb_mtd_set(struct super_block *sb, void *_mtd)
-{
- struct mtd_info *mtd = _mtd;
-
- sb->s_mtd = mtd;
- sb->s_dev = MKDEV(MTD_BLOCK_MAJOR, mtd->index);
- sb->s_bdi = bdi_get(mtd_bdi);
-
- return 0;
-}
-
-/*
- * 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,
- struct mtd_info *mtd,
- int (*fill_super)(struct super_block *, void *, int))
-{
- struct super_block *sb;
- int ret;
-
- sb = sget(fs_type, get_sb_mtd_compare, get_sb_mtd_set, flags, mtd);
- if (IS_ERR(sb))
- goto out_error;
-
- if (sb->s_root)
- goto already_mounted;
-
- /* fresh new superblock */
- pr_debug("MTDSB: New superblock for device %d (\"%s\")\n",
- mtd->index, mtd->name);
-
- ret = fill_super(sb, data, flags & SB_SILENT ? 1 : 0);
- if (ret < 0) {
- deactivate_locked_super(sb);
- return ERR_PTR(ret);
- }
-
- /* go */
- sb->s_flags |= SB_ACTIVE;
- return dget(sb->s_root);
-
- /* new mountpoint for an already mounted superblock */
-already_mounted:
- pr_debug("MTDSB: Device %d (\"%s\") is already mounted\n",
- mtd->index, mtd->name);
- put_mtd_device(mtd);
- return dget(sb->s_root);
-
-out_error:
- put_mtd_device(mtd);
- return ERR_CAST(sb);
-}
-
-/*
- * 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))
-{
- struct mtd_info *mtd;
-
- mtd = get_mtd_device(NULL, mtdnr);
- if (IS_ERR(mtd)) {
- pr_debug("MTDSB: Device #%u doesn't appear to exist\n", mtdnr);
- return ERR_CAST(mtd);
- }
-
- return mount_mtd_aux(fs_type, flags, dev_name, data, 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))
-{
-#ifdef CONFIG_BLOCK
- struct block_device *bdev;
- int ret, major;
-#endif
- int mtdnr;
-
- if (!dev_name)
- return ERR_PTR(-EINVAL);
-
- pr_debug("MTDSB: dev_name \"%s\"\n", dev_name);
-
- /* the preferred way of mounting in future; especially when
- * CONFIG_BLOCK=n - we specify the underlying MTD device by number or
- * by name, so that we don't require block device support to be present
- * in the kernel. */
- if (dev_name[0] == 'm' && dev_name[1] == 't' && dev_name[2] == 'd') {
- if (dev_name[3] == ':') {
- struct mtd_info *mtd;
-
- /* mount by MTD device name */
- pr_debug("MTDSB: mtd:%%s, name \"%s\"\n",
- dev_name + 4);
-
- mtd = get_mtd_device_nm(dev_name + 4);
- if (!IS_ERR(mtd))
- return mount_mtd_aux(
- fs_type, flags,
- dev_name, data, mtd,
- fill_super);
-
- printk(KERN_NOTICE "MTD:"
- " MTD device with name \"%s\" not found.\n",
- dev_name + 4);
-
- } else if (isdigit(dev_name[3])) {
- /* mount by MTD device number name */
- char *endptr;
-
- mtdnr = simple_strtoul(dev_name + 3, &endptr, 0);
- if (!*endptr) {
- /* It was a valid number */
- pr_debug("MTDSB: mtd%%d, mtdnr %d\n",
- mtdnr);
- return mount_mtd_nr(fs_type, flags,
- dev_name, data,
- mtdnr, fill_super);
- }
- }
- }
-
-#ifdef CONFIG_BLOCK
- /* try the old way - the hack where we allowed users to mount
- * /dev/mtdblock$(n) but didn't actually _use_ the blockdev
- */
- bdev = lookup_bdev(dev_name);
- if (IS_ERR(bdev)) {
- ret = PTR_ERR(bdev);
- pr_debug("MTDSB: lookup_bdev() returned %d\n", ret);
- return ERR_PTR(ret);
- }
- pr_debug("MTDSB: lookup_bdev() returned 0\n");
-
- ret = -EINVAL;
-
- major = MAJOR(bdev->bd_dev);
- mtdnr = MINOR(bdev->bd_dev);
- bdput(bdev);
-
- if (major != MTD_BLOCK_MAJOR)
- goto not_an_MTD_device;
-
- return mount_mtd_nr(fs_type, flags, dev_name, data, mtdnr, fill_super);
-
-not_an_MTD_device:
-#endif /* CONFIG_BLOCK */
-
- if (!(flags & SB_SILENT))
- printk(KERN_NOTICE
- "MTD: Attempt to mount non-MTD device \"%s\"\n",
- dev_name);
- return ERR_PTR(-EINVAL);
-}
-
-EXPORT_SYMBOL_GPL(mount_mtd);
-
-/*
* destroy an MTD-based superblock
*/
void kill_mtd_super(struct super_block *sb)
diff --git a/fs/cramfs/inode.c b/fs/cramfs/inode.c
index 4d1d8b7761ed..d12ea28836a5 100644
--- a/fs/cramfs/inode.c
+++ b/fs/cramfs/inode.c
@@ -24,6 +24,7 @@
#include <linux/blkdev.h>
#include <linux/mtd/mtd.h>
#include <linux/mtd/super.h>
+#include <linux/fs_context.h>
#include <linux/slab.h>
#include <linux/vfs.h>
#include <linux/mutex.h>
@@ -506,18 +507,19 @@ 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_reconfigure(struct fs_context *fc)
{
- sync_filesystem(sb);
- *flags |= SB_RDONLY;
+ sync_filesystem(fc->root->d_sb);
+ fc->sb_flags |= SB_RDONLY;
return 0;
}
-static int cramfs_read_super(struct super_block *sb,
- struct cramfs_super *super, int silent)
+static int cramfs_read_super(struct super_block *sb, struct fs_context *fc,
+ struct cramfs_super *super)
{
struct cramfs_sb_info *sbi = CRAMFS_SB(sb);
unsigned long root_offset;
+ bool silent = fc->sb_flags & SB_SILENT;
/* We don't know the real size yet */
sbi->size = PAGE_SIZE;
@@ -532,7 +534,7 @@ static int cramfs_read_super(struct super_block *sb,
/* check for wrong endianness */
if (super->magic == CRAMFS_MAGIC_WEND) {
if (!silent)
- pr_err("wrong endianness\n");
+ errorf(fc, "cramfs: wrong endianness");
return -EINVAL;
}
@@ -544,22 +546,22 @@ static int cramfs_read_super(struct super_block *sb,
mutex_unlock(&read_mutex);
if (super->magic != CRAMFS_MAGIC) {
if (super->magic == CRAMFS_MAGIC_WEND && !silent)
- pr_err("wrong endianness\n");
+ errorf(fc, "cramfs: wrong endianness");
else if (!silent)
- pr_err("wrong magic\n");
+ errorf(fc, "cramfs: wrong magic");
return -EINVAL;
}
}
/* get feature flags first */
if (super->flags & ~CRAMFS_SUPPORTED_FLAGS) {
- pr_err("unsupported filesystem features\n");
+ errorf(fc, "cramfs: unsupported filesystem features");
return -EINVAL;
}
/* Check that the root inode is in a sane state */
if (!S_ISDIR(super->root.mode)) {
- pr_err("root is not a directory\n");
+ errorf(fc, "cramfs: root is not a directory");
return -EINVAL;
}
/* correct strange, hard-coded permissions of mkcramfs */
@@ -578,12 +580,12 @@ static int cramfs_read_super(struct super_block *sb,
sbi->magic = super->magic;
sbi->flags = super->flags;
if (root_offset == 0)
- pr_info("empty filesystem");
+ infof(fc, "cramfs: empty filesystem");
else if (!(super->flags & CRAMFS_FLAG_SHIFTED_ROOT_OFFSET) &&
((root_offset != sizeof(struct cramfs_super)) &&
(root_offset != 512 + sizeof(struct cramfs_super))))
{
- pr_err("bad root offset %lu\n", root_offset);
+ errorf(fc, "cramfs: bad root offset %lu", root_offset);
return -EINVAL;
}
@@ -609,8 +611,7 @@ static int cramfs_finalize_super(struct super_block *sb,
return 0;
}
-static int cramfs_blkdev_fill_super(struct super_block *sb, void *data,
- int silent)
+static int cramfs_blkdev_fill_super(struct super_block *sb, struct fs_context *fc)
{
struct cramfs_sb_info *sbi;
struct cramfs_super super;
@@ -625,14 +626,13 @@ static int cramfs_blkdev_fill_super(struct super_block *sb, void *data,
for (i = 0; i < READ_BUFFERS; i++)
buffer_blocknr[i] = -1;
- err = cramfs_read_super(sb, &super, silent);
+ err = cramfs_read_super(sb, fc, &super);
if (err)
return err;
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, struct fs_context *fc)
{
struct cramfs_sb_info *sbi;
struct cramfs_super super;
@@ -654,7 +654,7 @@ static int cramfs_mtd_fill_super(struct super_block *sb, void *data,
pr_info("checking physical address %pap for linear cramfs image\n",
&sbi->linear_phys_addr);
- err = cramfs_read_super(sb, &super, silent);
+ err = cramfs_read_super(sb, fc, &super);
if (err)
return err;
@@ -949,32 +949,41 @@ static const struct inode_operations cramfs_dir_inode_operations = {
};
static const struct super_operations cramfs_ops = {
- .remount_fs = cramfs_remount,
.statfs = cramfs_statfs,
};
-static struct dentry *cramfs_mount(struct file_system_type *fs_type, int flags,
- const char *dev_name, void *data)
+static int cramfs_get_tree(struct fs_context *fc)
{
- struct dentry *ret = ERR_PTR(-ENOPROTOOPT);
+ int ret = -ENOPROTOOPT;
if (IS_ENABLED(CONFIG_CRAMFS_MTD)) {
- ret = mount_mtd(fs_type, flags, dev_name, data,
- cramfs_mtd_fill_super);
- if (!IS_ERR(ret))
+ ret = get_tree_mtd(fc, cramfs_mtd_fill_super);
+ if (ret < 0)
return ret;
}
- if (IS_ENABLED(CONFIG_CRAMFS_BLOCKDEV)) {
- ret = mount_bdev(fs_type, flags, dev_name, data,
- cramfs_blkdev_fill_super);
- }
+ if (IS_ENABLED(CONFIG_CRAMFS_BLOCKDEV))
+ ret = get_tree_bdev(fc, cramfs_blkdev_fill_super);
return ret;
}
+static const struct fs_context_operations cramfs_context_ops = {
+ .get_tree = cramfs_get_tree,
+ .reconfigure = cramfs_reconfigure,
+};
+
+/*
+ * Set up the filesystem mount context.
+ */
+static int cramfs_init_fs_context(struct fs_context *fc)
+{
+ fc->ops = &cramfs_context_ops;
+ return 0;
+}
+
static struct file_system_type cramfs_fs_type = {
.owner = THIS_MODULE,
.name = "cramfs",
- .mount = cramfs_mount,
+ .init_fs_context = cramfs_init_fs_context,
.kill_sb = cramfs_kill_sb,
.fs_flags = FS_REQUIRES_DEV,
};
diff --git a/fs/fs_parser.c b/fs/fs_parser.c
index 460ea4206fa2..d1930adce68d 100644
--- a/fs/fs_parser.c
+++ b/fs/fs_parser.c
@@ -204,9 +204,23 @@ int fs_parse(struct fs_context *fc,
goto okay;
case fs_param_is_fd: {
- if (param->type != fs_value_is_file)
+ switch (param->type) {
+ case fs_value_is_string:
+ if (!result->has_value)
+ goto bad_value;
+
+ ret = kstrtouint(param->string, 0, &result->uint_32);
+ break;
+ case fs_value_is_file:
+ result->uint_32 = param->dirfd;
+ ret = 0;
+ default:
goto bad_value;
- goto okay;
+ }
+
+ if (result->uint_32 > INT_MAX)
+ goto bad_value;
+ goto maybe_okay;
}
case fs_param_is_blockdev:
diff --git a/fs/jffs2/fs.c b/fs/jffs2/fs.c
index d0b59d03a7a9..05fe6cf5f1ac 100644
--- a/fs/jffs2/fs.c
+++ b/fs/jffs2/fs.c
@@ -17,6 +17,7 @@
#include <linux/sched.h>
#include <linux/cred.h>
#include <linux/fs.h>
+#include <linux/fs_context.h>
#include <linux/list.h>
#include <linux/mtd/mtd.h>
#include <linux/pagemap.h>
@@ -184,7 +185,7 @@ int jffs2_do_setattr (struct inode *inode, struct iattr *iattr)
if (ivalid & ATTR_SIZE && inode->i_size > iattr->ia_size) {
truncate_setsize(inode, iattr->ia_size);
inode->i_blocks = (inode->i_size + 511) >> 9;
- }
+ }
return 0;
}
@@ -391,7 +392,7 @@ void jffs2_dirty_inode(struct inode *inode, int flags)
jffs2_do_setattr(inode, &iattr);
}
-int jffs2_do_remount_fs(struct super_block *sb, int *flags, char *data)
+int jffs2_do_remount_fs(struct super_block *sb, struct fs_context *fc)
{
struct jffs2_sb_info *c = JFFS2_SB_INFO(sb);
@@ -409,10 +410,10 @@ int jffs2_do_remount_fs(struct super_block *sb, int *flags, char *data)
mutex_unlock(&c->alloc_sem);
}
- if (!(*flags & SB_RDONLY))
+ if (!(fc->sb_flags & SB_RDONLY))
jffs2_start_garbage_collect_thread(c);
- *flags |= SB_NOATIME;
+ fc->sb_flags |= SB_NOATIME;
return 0;
}
@@ -509,7 +510,7 @@ static int calculate_inocache_hashsize(uint32_t flash_size)
return hashsize;
}
-int jffs2_do_fill_super(struct super_block *sb, void *data, int silent)
+int jffs2_do_fill_super(struct super_block *sb, struct fs_context *fc)
{
struct jffs2_sb_info *c;
struct inode *root_i;
@@ -524,11 +525,11 @@ int jffs2_do_fill_super(struct super_block *sb, void *data, int silent)
#ifndef CONFIG_JFFS2_FS_WRITEBUFFER
if (c->mtd->type == MTD_NANDFLASH) {
- pr_err("Cannot operate on NAND flash unless jffs2 NAND support is compiled in\n");
+ errorf(fc, "Cannot operate on NAND flash unless jffs2 NAND support is compiled in");
return -EINVAL;
}
if (c->mtd->type == MTD_DATAFLASH) {
- pr_err("Cannot operate on DataFlash unless jffs2 DataFlash support is compiled in\n");
+ errorf(fc, "Cannot operate on DataFlash unless jffs2 DataFlash support is compiled in");
return -EINVAL;
}
#endif
@@ -542,12 +543,12 @@ int jffs2_do_fill_super(struct super_block *sb, void *data, int silent)
*/
if ((c->sector_size * blocks) != c->flash_size) {
c->flash_size = c->sector_size * blocks;
- pr_info("Flash size not aligned to erasesize, reducing to %dKiB\n",
- c->flash_size / 1024);
+ infof(fc, "Flash size not aligned to erasesize, reducing to %dKiB",
+ c->flash_size / 1024);
}
if (c->flash_size < 5*c->sector_size) {
- pr_err("Too few erase blocks (%d)\n",
+ errorf(fc, "Too few erase blocks (%d)",
c->flash_size / c->sector_size);
return -EINVAL;
}
diff --git a/fs/jffs2/os-linux.h b/fs/jffs2/os-linux.h
index bd3d5f0ddc34..21071fc2975d 100644
--- a/fs/jffs2/os-linux.h
+++ b/fs/jffs2/os-linux.h
@@ -172,8 +172,8 @@ void jffs2_dirty_inode(struct inode *inode, int flags);
struct inode *jffs2_new_inode (struct inode *dir_i, umode_t mode,
struct jffs2_raw_inode *ri);
int jffs2_statfs (struct dentry *, struct kstatfs *);
-int jffs2_do_remount_fs(struct super_block *, int *, char *);
-int jffs2_do_fill_super(struct super_block *sb, void *data, int silent);
+int jffs2_do_remount_fs(struct super_block *sb, struct fs_context *fc);
+int jffs2_do_fill_super(struct super_block *sb, struct fs_context *fc);
void jffs2_gc_release_inode(struct jffs2_sb_info *c,
struct jffs2_inode_info *f);
struct jffs2_inode_info *jffs2_gc_fetch_inode(struct jffs2_sb_info *c,
diff --git a/fs/jffs2/super.c b/fs/jffs2/super.c
index af4aa6599473..cbe70637c117 100644
--- a/fs/jffs2/super.c
+++ b/fs/jffs2/super.c
@@ -19,7 +19,8 @@
#include <linux/fs.h>
#include <linux/err.h>
#include <linux/mount.h>
-#include <linux/parser.h>
+#include <linux/fs_context.h>
+#include <linux/fs_parser.h>
#include <linux/jffs2.h>
#include <linux/pagemap.h>
#include <linux/mtd/super.h>
@@ -157,96 +158,77 @@ static const struct export_operations jffs2_export_ops = {
/*
* JFFS2 mount options.
*
+ * Opt_source: The source device
* Opt_override_compr: override default compressor
* Opt_rp_size: size of reserved pool in KiB
- * Opt_err: just end of array marker
*/
enum {
+ Opt_source,
Opt_override_compr,
Opt_rp_size,
- Opt_err,
};
-static const match_table_t tokens = {
- {Opt_override_compr, "compr=%s"},
- {Opt_rp_size, "rp_size=%u"},
- {Opt_err, NULL},
+static const struct fs_parameter_spec jffs2_param_specs[] = {
+ fsparam_string ("source", Opt_source),
+ fsparam_enum ("compr", Opt_override_compr),
+ fsparam_u32 ("rp_size", Opt_rp_size),
+ {}
};
-static int jffs2_parse_options(struct jffs2_sb_info *c, char *data)
-{
- substring_t args[MAX_OPT_ARGS];
- char *p, *name;
- unsigned int opt;
-
- if (!data)
- return 0;
-
- while ((p = strsep(&data, ","))) {
- int token;
-
- if (!*p)
- continue;
-
- token = match_token(p, tokens, args);
- switch (token) {
- case Opt_override_compr:
- name = match_strdup(&args[0]);
-
- if (!name)
- return -ENOMEM;
- if (!strcmp(name, "none"))
- c->mount_opts.compr = JFFS2_COMPR_MODE_NONE;
+static const struct fs_parameter_enum jffs2_param_enums[] = {
+ { Opt_override_compr, "none", JFFS2_COMPR_MODE_NONE },
#ifdef CONFIG_JFFS2_LZO
- else if (!strcmp(name, "lzo"))
- c->mount_opts.compr = JFFS2_COMPR_MODE_FORCELZO;
+ { Opt_override_compr, "lzo", JFFS2_COMPR_MODE_FORCELZO },
#endif
#ifdef CONFIG_JFFS2_ZLIB
- else if (!strcmp(name, "zlib"))
- c->mount_opts.compr =
- JFFS2_COMPR_MODE_FORCEZLIB;
+ { Opt_override_compr, "zlib", JFFS2_COMPR_MODE_FORCEZLIB },
#endif
- else {
- pr_err("Error: unknown compressor \"%s\"\n",
- name);
- kfree(name);
- return -EINVAL;
- }
- kfree(name);
- c->mount_opts.override_compr = true;
- break;
- case Opt_rp_size:
- if (match_int(&args[0], &opt))
- return -EINVAL;
- opt *= 1024;
- if (opt > c->mtd->size) {
- pr_warn("Too large reserve pool specified, max "
- "is %llu KB\n", c->mtd->size / 1024);
- return -EINVAL;
- }
- c->mount_opts.rp_size = opt;
- break;
- default:
- pr_err("Error: unrecognized mount option '%s' or missing value\n",
- p);
- return -EINVAL;
- }
+ {}
+};
+
+const struct fs_parameter_description jffs2_fs_parameters = {
+ .name = "jffs2",
+ .specs = jffs2_param_specs,
+ .enums = jffs2_param_enums,
+};
+
+static int jffs2_parse_param(struct fs_context *fc, struct fs_parameter *param)
+{
+ struct fs_parse_result result;
+ struct jffs2_sb_info *c = fc->s_fs_info;
+ int opt;
+
+ opt = fs_parse(fc, &jffs2_fs_parameters, param, &result);
+ if (opt < 0)
+ return opt;
+
+ switch (opt) {
+ case Opt_override_compr:
+ c->mount_opts.compr = result.uint_32;
+ c->mount_opts.override_compr = true;
+ break;
+ case Opt_rp_size:
+ if (result.uint_32 > UINT_MAX / 1024)
+ return invalf(fc, "jffs2: rp_size unrepresentable");
+ opt = result.uint_32 * 1024;
+ if (opt > c->mtd->size)
+ return invalf(fc, "jffs2: Too large reserve pool specified, max is %llu KB",
+ c->mtd->size / 1024);
+ c->mount_opts.rp_size = opt;
+ break;
+ default:
+ return -EINVAL;
}
return 0;
}
-static int jffs2_remount_fs(struct super_block *sb, int *flags, char *data)
+static int jffs2_reconfigure(struct fs_context *fc)
{
- struct jffs2_sb_info *c = JFFS2_SB_INFO(sb);
- int err;
+ struct super_block *sb = fc->root->d_sb;
sync_filesystem(sb);
- err = jffs2_parse_options(c, data);
- if (err)
- return -EINVAL;
-
- return jffs2_do_remount_fs(sb, flags, data);
+ return jffs2_do_remount_fs(sb, fc);
}
static const struct super_operations jffs2_super_operations =
@@ -255,7 +237,6 @@ static const struct super_operations jffs2_super_operations =
.free_inode = jffs2_free_inode,
.put_super = jffs2_put_super,
.statfs = jffs2_statfs,
- .remount_fs = jffs2_remount_fs,
.evict_inode = jffs2_evict_inode,
.dirty_inode = jffs2_dirty_inode,
.show_options = jffs2_show_options,
@@ -265,26 +246,16 @@ 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, struct fs_context *fc)
{
- struct jffs2_sb_info *c;
- int ret;
+ struct jffs2_sb_info *c = sb->s_fs_info;
jffs2_dbg(1, "jffs2_get_sb_mtd():"
" New superblock for device %d (\"%s\")\n",
sb->s_mtd->index, sb->s_mtd->name);
- c = kzalloc(sizeof(*c), GFP_KERNEL);
- if (!c)
- return -ENOMEM;
-
c->mtd = sb->s_mtd;
c->os_priv = sb;
- sb->s_fs_info = c;
-
- ret = jffs2_parse_options(c, data);
- if (ret)
- return -EINVAL;
/* Initialize JFFS2 superblock locks, the further initialization will
* be done later */
@@ -302,15 +273,37 @@ static int jffs2_fill_super(struct super_block *sb, void *data, int silent)
#ifdef CONFIG_JFFS2_FS_POSIX_ACL
sb->s_flags |= SB_POSIXACL;
#endif
- ret = jffs2_do_fill_super(sb, data, silent);
- return ret;
+ return jffs2_do_fill_super(sb, fc);
}
-static struct dentry *jffs2_mount(struct file_system_type *fs_type,
- int flags, const char *dev_name,
- void *data)
+static int jffs2_get_tree(struct fs_context *fc)
{
- return mount_mtd(fs_type, flags, dev_name, data, jffs2_fill_super);
+ return get_tree_mtd(fc, jffs2_fill_super);
+}
+
+static void jffs2_free_fc(struct fs_context *fc)
+{
+ kfree(fc->s_fs_info);
+}
+
+static const struct fs_context_operations jffs2_context_ops = {
+ .free = jffs2_free_fc,
+ .parse_param = jffs2_parse_param,
+ .get_tree = jffs2_get_tree,
+ .reconfigure = jffs2_reconfigure,
+};
+
+static int jffs2_init_fs_context(struct fs_context *fc)
+{
+ struct jffs2_sb_info *ctx;
+
+ ctx = kzalloc(sizeof(struct jffs2_sb_info), GFP_KERNEL);
+ if (!ctx)
+ return -ENOMEM;
+
+ fc->s_fs_info = ctx;
+ fc->ops = &jffs2_context_ops;
+ return 0;
}
static void jffs2_put_super (struct super_block *sb)
@@ -347,7 +340,8 @@ static void jffs2_kill_sb(struct super_block *sb)
static struct file_system_type jffs2_fs_type = {
.owner = THIS_MODULE,
.name = "jffs2",
- .mount = jffs2_mount,
+ .init_fs_context = jffs2_init_fs_context,
+ .parameters = &jffs2_fs_parameters,
.kill_sb = jffs2_kill_sb,
};
MODULE_ALIAS_FS("jffs2");
diff --git a/fs/ramfs/inode.c b/fs/ramfs/inode.c
index 733c6b4193dc..d82636e8eb65 100644
--- a/fs/ramfs/inode.c
+++ b/fs/ramfs/inode.c
@@ -36,6 +36,8 @@
#include <linux/magic.h>
#include <linux/slab.h>
#include <linux/uaccess.h>
+#include <linux/fs_context.h>
+#include <linux/fs_parser.h>
#include "internal.h"
struct ramfs_mount_opts {
@@ -175,62 +177,52 @@ static const struct super_operations ramfs_ops = {
.show_options = ramfs_show_options,
};
-enum {
+enum ramfs_param {
Opt_mode,
- Opt_err
};
-static const match_table_t tokens = {
- {Opt_mode, "mode=%o"},
- {Opt_err, NULL}
+static const struct fs_parameter_spec ramfs_param_specs[] = {
+ fsparam_u32oct("mode", Opt_mode),
+ {}
};
-static int ramfs_parse_options(char *data, struct ramfs_mount_opts *opts)
+const struct fs_parameter_description ramfs_fs_parameters = {
+ .name = "ramfs",
+ .specs = ramfs_param_specs,
+};
+
+static int ramfs_parse_param(struct fs_context *fc, struct fs_parameter *param)
{
- substring_t args[MAX_OPT_ARGS];
- int option;
- int token;
- char *p;
-
- opts->mode = RAMFS_DEFAULT_MODE;
-
- while ((p = strsep(&data, ",")) != NULL) {
- if (!*p)
- continue;
-
- token = match_token(p, tokens, args);
- switch (token) {
- case Opt_mode:
- if (match_octal(&args[0], &option))
- return -EINVAL;
- opts->mode = option & S_IALLUGO;
- break;
+ struct fs_parse_result result;
+ struct ramfs_fs_info *fsi = fc->s_fs_info;
+ int opt;
+
+ opt = fs_parse(fc, &ramfs_fs_parameters, param, &result);
+ if (opt < 0) {
/*
* We might like to report bad mount options here;
* but traditionally ramfs has ignored all mount options,
* and as it is used as a !CONFIG_SHMEM simple substitute
* for tmpfs, better continue to ignore other mount options.
*/
- }
+ if (opt == -ENOPARAM)
+ opt = 0;
+ return opt;
+ }
+
+ switch (opt) {
+ case Opt_mode:
+ fsi->mount_opts.mode = result.uint_32 & S_IALLUGO;
+ break;
}
return 0;
}
-int ramfs_fill_super(struct super_block *sb, void *data, int silent)
+static int ramfs_fill_super(struct super_block *sb, struct fs_context *fc)
{
- struct ramfs_fs_info *fsi;
+ struct ramfs_fs_info *fsi = sb->s_fs_info;
struct inode *inode;
- int err;
-
- fsi = kzalloc(sizeof(struct ramfs_fs_info), GFP_KERNEL);
- sb->s_fs_info = fsi;
- if (!fsi)
- return -ENOMEM;
-
- err = ramfs_parse_options(data, &fsi->mount_opts);
- if (err)
- return err;
sb->s_maxbytes = MAX_LFS_FILESIZE;
sb->s_blocksize = PAGE_SIZE;
@@ -247,10 +239,34 @@ int ramfs_fill_super(struct super_block *sb, void *data, int silent)
return 0;
}
-struct dentry *ramfs_mount(struct file_system_type *fs_type,
- int flags, const char *dev_name, void *data)
+static int ramfs_get_tree(struct fs_context *fc)
{
- return mount_nodev(fs_type, flags, data, ramfs_fill_super);
+ return get_tree_nodev(fc, ramfs_fill_super);
+}
+
+static void ramfs_free_fc(struct fs_context *fc)
+{
+ kfree(fc->s_fs_info);
+}
+
+static const struct fs_context_operations ramfs_context_ops = {
+ .free = ramfs_free_fc,
+ .parse_param = ramfs_parse_param,
+ .get_tree = ramfs_get_tree,
+};
+
+int ramfs_init_fs_context(struct fs_context *fc)
+{
+ struct ramfs_fs_info *fsi;
+
+ fsi = kzalloc(sizeof(*fsi), GFP_KERNEL);
+ if (!fsi)
+ return -ENOMEM;
+
+ fsi->mount_opts.mode = RAMFS_DEFAULT_MODE;
+ fc->s_fs_info = fsi;
+ fc->ops = &ramfs_context_ops;
+ return 0;
}
static void ramfs_kill_sb(struct super_block *sb)
@@ -261,7 +277,8 @@ static void ramfs_kill_sb(struct super_block *sb)
static struct file_system_type ramfs_fs_type = {
.name = "ramfs",
- .mount = ramfs_mount,
+ .init_fs_context = ramfs_init_fs_context,
+ .parameters = &ramfs_fs_parameters,
.kill_sb = ramfs_kill_sb,
.fs_flags = FS_USERNS_MOUNT,
};
diff --git a/fs/romfs/super.c b/fs/romfs/super.c
index a42c0e3079dc..e582d001f792 100644
--- a/fs/romfs/super.c
+++ b/fs/romfs/super.c
@@ -65,7 +65,7 @@
#include <linux/slab.h>
#include <linux/init.h>
#include <linux/blkdev.h>
-#include <linux/parser.h>
+#include <linux/fs_context.h>
#include <linux/mount.h>
#include <linux/namei.h>
#include <linux/statfs.h>
@@ -423,10 +423,10 @@ 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_reconfigure(struct fs_context *fc)
{
- sync_filesystem(sb);
- *flags |= SB_RDONLY;
+ sync_filesystem(fc->root->d_sb);
+ fc->sb_flags |= SB_RDONLY;
return 0;
}
@@ -434,7 +434,6 @@ static const struct super_operations romfs_super_ops = {
.alloc_inode = romfs_alloc_inode,
.free_inode = romfs_free_inode,
.statfs = romfs_statfs,
- .remount_fs = romfs_remount,
};
/*
@@ -457,7 +456,7 @@ 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, struct fs_context *fc)
{
struct romfs_super_block *rsb;
struct inode *root;
@@ -506,8 +505,8 @@ static int romfs_fill_super(struct super_block *sb, void *data, int silent)
if (rsb->word0 != ROMSB_WORD0 || rsb->word1 != ROMSB_WORD1 ||
img_size < ROMFH_SIZE) {
- if (!silent)
- pr_warn("VFS: Can't find a romfs filesystem on dev %s.\n",
+ if (!(fc->sb_flags & SB_SILENT))
+ errorf(fc, "VFS: Can't find a romfs filesystem on dev %s.\n",
sb->s_id);
goto error_rsb_inval;
}
@@ -520,7 +519,7 @@ static int romfs_fill_super(struct super_block *sb, void *data, int silent)
storage = sb->s_mtd ? "MTD" : "the block layer";
len = strnlen(rsb->name, ROMFS_MAXFN);
- if (!silent)
+ if (!(fc->sb_flags & SB_SILENT))
pr_notice("Mounting image '%*.*s' through %s\n",
(unsigned) len, (unsigned) len, rsb->name, storage);
@@ -550,23 +549,34 @@ error_rsb:
/*
* get a superblock for mounting
*/
-static struct dentry *romfs_mount(struct file_system_type *fs_type,
- int flags, const char *dev_name,
- void *data)
+static int romfs_get_tree(struct fs_context *fc)
{
- struct dentry *ret = ERR_PTR(-EINVAL);
+ int ret = -EINVAL;
#ifdef CONFIG_ROMFS_ON_MTD
- ret = mount_mtd(fs_type, flags, dev_name, data, romfs_fill_super);
+ ret = get_tree_mtd(fc, romfs_fill_super);
#endif
#ifdef CONFIG_ROMFS_ON_BLOCK
- if (ret == ERR_PTR(-EINVAL))
- ret = mount_bdev(fs_type, flags, dev_name, data,
- romfs_fill_super);
+ if (ret == -EINVAL)
+ ret = get_tree_bdev(fc, romfs_fill_super);
#endif
return ret;
}
+static const struct fs_context_operations romfs_context_ops = {
+ .get_tree = romfs_get_tree,
+ .reconfigure = romfs_reconfigure,
+};
+
+/*
+ * Set up the filesystem mount context.
+ */
+static int romfs_init_fs_context(struct fs_context *fc)
+{
+ fc->ops = &romfs_context_ops;
+ return 0;
+}
+
/*
* destroy a romfs superblock in the appropriate manner
*/
@@ -589,7 +599,7 @@ static void romfs_kill_sb(struct super_block *sb)
static struct file_system_type romfs_fs_type = {
.owner = THIS_MODULE,
.name = "romfs",
- .mount = romfs_mount,
+ .init_fs_context = romfs_init_fs_context,
.kill_sb = romfs_kill_sb,
.fs_flags = FS_REQUIRES_DEV,
};
diff --git a/fs/squashfs/super.c b/fs/squashfs/super.c
index a9e9837617a9..0cc4ceec0562 100644
--- a/fs/squashfs/super.c
+++ b/fs/squashfs/super.c
@@ -17,6 +17,7 @@
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
#include <linux/fs.h>
+#include <linux/fs_context.h>
#include <linux/vfs.h>
#include <linux/slab.h>
#include <linux/mutex.h>
@@ -36,26 +37,27 @@
static struct file_system_type squashfs_fs_type;
static const struct super_operations squashfs_super_ops;
-static const struct squashfs_decompressor *supported_squashfs_filesystem(short
- major, short minor, short id)
+static const struct squashfs_decompressor *supported_squashfs_filesystem(
+ struct fs_context *fc,
+ short major, short minor, short id)
{
const struct squashfs_decompressor *decompressor;
if (major < SQUASHFS_MAJOR) {
- ERROR("Major/Minor mismatch, older Squashfs %d.%d "
- "filesystems are unsupported\n", major, minor);
+ errorf(fc, "Major/Minor mismatch, older Squashfs %d.%d "
+ "filesystems are unsupported", major, minor);
return NULL;
} else if (major > SQUASHFS_MAJOR || minor > SQUASHFS_MINOR) {
- ERROR("Major/Minor mismatch, trying to mount newer "
- "%d.%d filesystem\n", major, minor);
- ERROR("Please update your kernel\n");
+ errorf(fc, "Major/Minor mismatch, trying to mount newer "
+ "%d.%d filesystem", major, minor);
+ errorf(fc, "Please update your kernel");
return NULL;
}
decompressor = squashfs_lookup_decompressor(id);
if (!decompressor->supported) {
- ERROR("Filesystem uses \"%s\" compression. This is not "
- "supported\n", decompressor->name);
+ errorf(fc, "Filesystem uses \"%s\" compression. This is not supported",
+ decompressor->name);
return NULL;
}
@@ -63,7 +65,7 @@ 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, struct fs_context *fc)
{
struct squashfs_sb_info *msblk;
struct squashfs_super_block *sblk = NULL;
@@ -98,7 +100,7 @@ static int squashfs_fill_super(struct super_block *sb, void *data, int silent)
sblk = squashfs_read_table(sb, SQUASHFS_START, sizeof(*sblk));
if (IS_ERR(sblk)) {
- ERROR("unable to read squashfs_super_block\n");
+ errorf(fc, "unable to read squashfs_super_block");
err = PTR_ERR(sblk);
sblk = NULL;
goto failed_mount;
@@ -109,14 +111,15 @@ static int squashfs_fill_super(struct super_block *sb, void *data, int silent)
/* Check it is a SQUASHFS superblock */
sb->s_magic = le32_to_cpu(sblk->s_magic);
if (sb->s_magic != SQUASHFS_MAGIC) {
- if (!silent)
- ERROR("Can't find a SQUASHFS superblock on %pg\n",
- sb->s_bdev);
+ if (!(fc->sb_flags & SB_SILENT))
+ errorf(fc, "Can't find a SQUASHFS superblock on %pg",
+ sb->s_bdev);
goto failed_mount;
}
/* Check the MAJOR & MINOR versions and lookup compression type */
msblk->decompressor = supported_squashfs_filesystem(
+ fc,
le16_to_cpu(sblk->s_major),
le16_to_cpu(sblk->s_minor),
le16_to_cpu(sblk->compression));
@@ -133,15 +136,15 @@ static int squashfs_fill_super(struct super_block *sb, void *data, int silent)
/* Check block size for sanity */
msblk->block_size = le32_to_cpu(sblk->block_size);
if (msblk->block_size > SQUASHFS_FILE_MAX_SIZE)
- goto failed_mount;
+ goto insanity;
/*
* Check the system page size is not larger than the filesystem
* block size (by default 128K). This is currently not supported.
*/
if (PAGE_SIZE > msblk->block_size) {
- ERROR("Page size > filesystem block size (%d). This is "
- "currently not supported!\n", msblk->block_size);
+ errorf(fc, "Page size > filesystem block size (%d). This is "
+ "currently not supported!", msblk->block_size);
goto failed_mount;
}
@@ -152,12 +155,12 @@ static int squashfs_fill_super(struct super_block *sb, void *data, int silent)
/* Check that block_size and block_log match */
if (msblk->block_size != (1 << msblk->block_log))
- goto failed_mount;
+ goto insanity;
/* Check the root inode for sanity */
root_inode = le64_to_cpu(sblk->root_inode);
if (SQUASHFS_INODE_OFFSET(root_inode) > SQUASHFS_METADATA_SIZE)
- goto failed_mount;
+ goto insanity;
msblk->inode_table = le64_to_cpu(sblk->inode_table_start);
msblk->directory_table = le64_to_cpu(sblk->directory_table_start);
@@ -199,7 +202,7 @@ static int squashfs_fill_super(struct super_block *sb, void *data, int silent)
msblk->read_page = squashfs_cache_init("data",
squashfs_max_decompressors(), msblk->block_size);
if (msblk->read_page == NULL) {
- ERROR("Failed to allocate read_page block\n");
+ errorf(fc, "Failed to allocate read_page block");
goto failed_mount;
}
@@ -207,7 +210,7 @@ static int squashfs_fill_super(struct super_block *sb, void *data, int silent)
if (IS_ERR(msblk->stream)) {
err = PTR_ERR(msblk->stream);
msblk->stream = NULL;
- goto failed_mount;
+ goto insanity;
}
/* Handle xattrs */
@@ -222,7 +225,7 @@ static int squashfs_fill_super(struct super_block *sb, void *data, int silent)
msblk->xattr_id_table = squashfs_read_xattr_id_table(sb,
xattr_id_table_start, &msblk->xattr_table, &msblk->xattr_ids);
if (IS_ERR(msblk->xattr_id_table)) {
- ERROR("unable to read xattr id index table\n");
+ errorf(fc, "unable to read xattr id index table");
err = PTR_ERR(msblk->xattr_id_table);
msblk->xattr_id_table = NULL;
if (err != -ENOTSUPP)
@@ -236,7 +239,7 @@ allocate_id_index_table:
le64_to_cpu(sblk->id_table_start), next_table,
le16_to_cpu(sblk->no_ids));
if (IS_ERR(msblk->id_table)) {
- ERROR("unable to read id index table\n");
+ errorf(fc, "unable to read id index table");
err = PTR_ERR(msblk->id_table);
msblk->id_table = NULL;
goto failed_mount;
@@ -252,7 +255,7 @@ allocate_id_index_table:
msblk->inode_lookup_table = squashfs_read_inode_lookup_table(sb,
lookup_table_start, next_table, msblk->inodes);
if (IS_ERR(msblk->inode_lookup_table)) {
- ERROR("unable to read inode lookup table\n");
+ errorf(fc, "unable to read inode lookup table");
err = PTR_ERR(msblk->inode_lookup_table);
msblk->inode_lookup_table = NULL;
goto failed_mount;
@@ -277,7 +280,7 @@ handle_fragments:
msblk->fragment_index = squashfs_read_fragment_index_table(sb,
le64_to_cpu(sblk->fragment_table_start), next_table, fragments);
if (IS_ERR(msblk->fragment_index)) {
- ERROR("unable to read fragment index table\n");
+ errorf(fc, "unable to read fragment index table");
err = PTR_ERR(msblk->fragment_index);
msblk->fragment_index = NULL;
goto failed_mount;
@@ -288,13 +291,13 @@ check_directory_table:
/* Sanity check directory_table */
if (msblk->directory_table > next_table) {
err = -EINVAL;
- goto failed_mount;
+ goto insanity;
}
/* Sanity check inode_table */
if (msblk->inode_table >= msblk->directory_table) {
err = -EINVAL;
- goto failed_mount;
+ goto insanity;
}
/* allocate root */
@@ -323,6 +326,8 @@ check_directory_table:
kfree(sblk);
return 0;
+insanity:
+ errorf(fc, "squashfs image failed sanity check");
failed_mount:
squashfs_cache_delete(msblk->block_cache);
squashfs_cache_delete(msblk->fragment_cache);
@@ -338,6 +343,28 @@ failed_mount:
return err;
}
+static int squashfs_get_tree(struct fs_context *fc)
+{
+ return get_tree_bdev(fc, squashfs_fill_super);
+}
+
+static int squashfs_reconfigure(struct fs_context *fc)
+{
+ sync_filesystem(fc->root->d_sb);
+ fc->sb_flags |= SB_RDONLY;
+ return 0;
+}
+
+static const struct fs_context_operations squashfs_context_ops = {
+ .get_tree = squashfs_get_tree,
+ .reconfigure = squashfs_reconfigure,
+};
+
+static int squashfs_init_fs_context(struct fs_context *fc)
+{
+ fc->ops = &squashfs_context_ops;
+ return 0;
+}
static int squashfs_statfs(struct dentry *dentry, struct kstatfs *buf)
{
@@ -360,14 +387,6 @@ static int squashfs_statfs(struct dentry *dentry, struct kstatfs *buf)
}
-static int squashfs_remount(struct super_block *sb, int *flags, char *data)
-{
- sync_filesystem(sb);
- *flags |= SB_RDONLY;
- return 0;
-}
-
-
static void squashfs_put_super(struct super_block *sb)
{
if (sb->s_fs_info) {
@@ -386,14 +405,6 @@ 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)
-{
- return mount_bdev(fs_type, flags, dev_name, data, squashfs_fill_super);
-}
-
-
static struct kmem_cache *squashfs_inode_cachep;
@@ -470,7 +481,7 @@ static void squashfs_free_inode(struct inode *inode)
static struct file_system_type squashfs_fs_type = {
.owner = THIS_MODULE,
.name = "squashfs",
- .mount = squashfs_mount,
+ .init_fs_context = squashfs_init_fs_context,
.kill_sb = kill_block_super,
.fs_flags = FS_REQUIRES_DEV
};
@@ -481,7 +492,6 @@ static const struct super_operations squashfs_super_ops = {
.free_inode = squashfs_free_inode,
.statfs = squashfs_statfs,
.put_super = squashfs_put_super,
- .remount_fs = squashfs_remount
};
module_init(init_squashfs_fs);
diff --git a/fs/super.c b/fs/super.c
index 2d679db9e8c7..8020974b2a68 100644
--- a/fs/super.c
+++ b/fs/super.c
@@ -1164,9 +1164,11 @@ int vfs_get_super(struct fs_context *fc,
{
int (*test)(struct super_block *, struct fs_context *);
struct super_block *sb;
+ int err;
switch (keying) {
case vfs_get_single_super:
+ case vfs_get_single_reconf_super:
test = test_single_super;
break;
case vfs_get_keyed_super:
@@ -1184,18 +1186,29 @@ int vfs_get_super(struct fs_context *fc,
return PTR_ERR(sb);
if (!sb->s_root) {
- int err = fill_super(sb, fc);
- if (err) {
- deactivate_locked_super(sb);
- return err;
- }
+ err = fill_super(sb, fc);
+ if (err)
+ goto error;
sb->s_flags |= SB_ACTIVE;
+ fc->root = dget(sb->s_root);
+ } else {
+ fc->root = dget(sb->s_root);
+ if (keying == vfs_get_single_reconf_super) {
+ err = reconfigure_super(fc);
+ if (err < 0) {
+ dput(fc->root);
+ fc->root = NULL;
+ goto error;
+ }
+ }
}
- BUG_ON(fc->root);
- fc->root = dget(sb->s_root);
return 0;
+
+error:
+ deactivate_locked_super(sb);
+ return err;
}
EXPORT_SYMBOL(vfs_get_super);
@@ -1215,6 +1228,14 @@ int get_tree_single(struct fs_context *fc,
}
EXPORT_SYMBOL(get_tree_single);
+int get_tree_single_reconf(struct fs_context *fc,
+ int (*fill_super)(struct super_block *sb,
+ struct fs_context *fc))
+{
+ return vfs_get_super(fc, vfs_get_single_reconf_super, fill_super);
+}
+EXPORT_SYMBOL(get_tree_single_reconf);
+
int get_tree_keyed(struct fs_context *fc,
int (*fill_super)(struct super_block *sb,
struct fs_context *fc),
diff --git a/include/linux/fs_context.h b/include/linux/fs_context.h
index 84a5eaa09f19..0424df7f6e6b 100644
--- a/include/linux/fs_context.h
+++ b/include/linux/fs_context.h
@@ -141,6 +141,7 @@ extern void put_fs_context(struct fs_context *fc);
*/
enum vfs_get_super_keying {
vfs_get_single_super, /* Only one such superblock may exist */
+ vfs_get_single_reconf_super, /* As above, but reconfigure if it exists */
vfs_get_keyed_super, /* Superblocks with different s_fs_info keys may exist */
vfs_get_independent_super, /* Multiple independent superblocks may exist */
};
@@ -155,6 +156,9 @@ extern int get_tree_nodev(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 int get_tree_single_reconf(struct fs_context *fc,
+ int (*fill_super)(struct super_block *sb,
+ struct fs_context *fc));
extern int get_tree_keyed(struct fs_context *fc,
int (*fill_super)(struct super_block *sb,
struct fs_context *fc),
diff --git a/include/linux/mtd/super.h b/include/linux/mtd/super.h
index 42db3f8e8136..3608a6c36fac 100644
--- a/include/linux/mtd/super.h
+++ b/include/linux/mtd/super.h
@@ -17,9 +17,6 @@
extern int get_tree_mtd(struct fs_context *fc,
int (*fill_super)(struct super_block *sb,
struct fs_context *fc));
-extern 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));
extern void kill_mtd_super(struct super_block *sb);
diff --git a/include/linux/ramfs.h b/include/linux/ramfs.h
index ee582bdb7fda..b806a0ff6554 100644
--- a/include/linux/ramfs.h
+++ b/include/linux/ramfs.h
@@ -4,8 +4,7 @@
struct inode *ramfs_get_inode(struct super_block *sb, const struct inode *dir,
umode_t mode, dev_t dev);
-extern struct dentry *ramfs_mount(struct file_system_type *fs_type,
- int flags, const char *dev_name, void *data);
+extern int ramfs_init_fs_context(struct fs_context *fc);
#ifdef CONFIG_MMU
static inline int
@@ -17,9 +16,8 @@ ramfs_nommu_expand_for_mapping(struct inode *inode, size_t newsize)
extern int ramfs_nommu_expand_for_mapping(struct inode *inode, size_t newsize);
#endif
+extern const struct fs_parameter_description ramfs_fs_parameters;
extern const struct file_operations ramfs_file_operations;
extern const struct vm_operations_struct generic_file_vm_ops;
-int ramfs_fill_super(struct super_block *sb, void *data, int silent);
-
#endif
diff --git a/include/linux/shmem_fs.h b/include/linux/shmem_fs.h
index 20d815a33145..de8e4b71e3ba 100644
--- a/include/linux/shmem_fs.h
+++ b/include/linux/shmem_fs.h
@@ -49,8 +49,9 @@ static inline struct shmem_inode_info *SHMEM_I(struct inode *inode)
/*
* Functions in mm/shmem.c called directly from elsewhere:
*/
+extern const struct fs_parameter_description shmem_fs_parameters;
extern int shmem_init(void);
-extern int shmem_fill_super(struct super_block *sb, void *data, int silent);
+extern int shmem_init_fs_context(struct fs_context *fc);
extern struct file *shmem_file_setup(const char *name,
loff_t size, unsigned long flags);
extern struct file *shmem_kernel_file_setup(const char *name, loff_t size,
diff --git a/init/do_mounts.c b/init/do_mounts.c
index 53cb37b66227..9634ecf3743d 100644
--- a/init/do_mounts.c
+++ b/init/do_mounts.c
@@ -627,20 +627,17 @@ out:
}
static bool is_tmpfs;
-static struct dentry *rootfs_mount(struct file_system_type *fs_type,
- int flags, const char *dev_name, void *data)
+static int rootfs_init_fs_context(struct fs_context *fc)
{
- void *fill = ramfs_fill_super;
-
if (IS_ENABLED(CONFIG_TMPFS) && is_tmpfs)
- fill = shmem_fill_super;
+ return shmem_init_fs_context(fc);
- return mount_nodev(fs_type, flags, data, fill);
+ return ramfs_init_fs_context(fc);
}
struct file_system_type rootfs_fs_type = {
.name = "rootfs",
- .mount = rootfs_mount,
+ .init_fs_context = rootfs_init_fs_context,
.kill_sb = kill_litter_super,
};
diff --git a/mm/shmem.c b/mm/shmem.c
index 2bed4761f279..0f7fd4a85db6 100644
--- a/mm/shmem.c
+++ b/mm/shmem.c
@@ -37,6 +37,7 @@
#include <linux/khugepaged.h>
#include <linux/hugetlb.h>
#include <linux/frontswap.h>
+#include <linux/fs_parser.h>
#include <asm/tlbflush.h> /* for arch/microblaze update_mmu_cache() */
@@ -107,6 +108,20 @@ struct shmem_falloc {
pgoff_t nr_unswapped; /* how often writepage refused to swap out */
};
+struct shmem_options {
+ unsigned long long blocks;
+ unsigned long long inodes;
+ struct mempolicy *mpol;
+ kuid_t uid;
+ kgid_t gid;
+ umode_t mode;
+ int huge;
+ int seen;
+#define SHMEM_SEEN_BLOCKS 1
+#define SHMEM_SEEN_INODES 2
+#define SHMEM_SEEN_HUGE 4
+};
+
#ifdef CONFIG_TMPFS
static unsigned long shmem_default_max_blocks(void)
{
@@ -3349,16 +3364,126 @@ static const struct export_operations shmem_export_ops = {
.fh_to_dentry = shmem_fh_to_dentry,
};
-static int shmem_parse_options(char *options, struct shmem_sb_info *sbinfo,
- bool remount)
+enum shmem_param {
+ Opt_gid,
+ Opt_huge,
+ Opt_mode,
+ Opt_mpol,
+ Opt_nr_blocks,
+ Opt_nr_inodes,
+ Opt_size,
+ Opt_uid,
+};
+
+static const struct fs_parameter_spec shmem_param_specs[] = {
+ fsparam_u32 ("gid", Opt_gid),
+ fsparam_enum ("huge", Opt_huge),
+ fsparam_u32oct("mode", Opt_mode),
+ fsparam_string("mpol", Opt_mpol),
+ fsparam_string("nr_blocks", Opt_nr_blocks),
+ fsparam_string("nr_inodes", Opt_nr_inodes),
+ fsparam_string("size", Opt_size),
+ fsparam_u32 ("uid", Opt_uid),
+ {}
+};
+
+static const struct fs_parameter_enum shmem_param_enums[] = {
+ { Opt_huge, "never", SHMEM_HUGE_NEVER },
+ { Opt_huge, "always", SHMEM_HUGE_ALWAYS },
+ { Opt_huge, "within_size", SHMEM_HUGE_WITHIN_SIZE },
+ { Opt_huge, "advise", SHMEM_HUGE_ADVISE },
+ {}
+};
+
+const struct fs_parameter_description shmem_fs_parameters = {
+ .name = "tmpfs",
+ .specs = shmem_param_specs,
+ .enums = shmem_param_enums,
+};
+
+static int shmem_parse_one(struct fs_context *fc, struct fs_parameter *param)
{
- char *this_char, *value, *rest;
- struct mempolicy *mpol = NULL;
- uid_t uid;
- gid_t gid;
+ struct shmem_options *ctx = fc->fs_private;
+ struct fs_parse_result result;
+ unsigned long long size;
+ char *rest;
+ int opt;
+
+ opt = fs_parse(fc, &shmem_fs_parameters, param, &result);
+ if (opt < 0)
+ return opt;
+
+ switch (opt) {
+ case Opt_size:
+ size = memparse(param->string, &rest);
+ if (*rest == '%') {
+ size <<= PAGE_SHIFT;
+ size *= totalram_pages();
+ do_div(size, 100);
+ rest++;
+ }
+ if (*rest)
+ goto bad_value;
+ ctx->blocks = DIV_ROUND_UP(size, PAGE_SIZE);
+ ctx->seen |= SHMEM_SEEN_BLOCKS;
+ break;
+ case Opt_nr_blocks:
+ ctx->blocks = memparse(param->string, &rest);
+ if (*rest)
+ goto bad_value;
+ ctx->seen |= SHMEM_SEEN_BLOCKS;
+ break;
+ case Opt_nr_inodes:
+ ctx->inodes = memparse(param->string, &rest);
+ if (*rest)
+ goto bad_value;
+ ctx->seen |= SHMEM_SEEN_INODES;
+ break;
+ case Opt_mode:
+ ctx->mode = result.uint_32 & 07777;
+ break;
+ case Opt_uid:
+ ctx->uid = make_kuid(current_user_ns(), result.uint_32);
+ if (!uid_valid(ctx->uid))
+ goto bad_value;
+ break;
+ case Opt_gid:
+ ctx->gid = make_kgid(current_user_ns(), result.uint_32);
+ if (!gid_valid(ctx->gid))
+ goto bad_value;
+ break;
+ case Opt_huge:
+ ctx->huge = result.uint_32;
+ if (ctx->huge != SHMEM_HUGE_NEVER &&
+ !(IS_ENABLED(CONFIG_TRANSPARENT_HUGE_PAGECACHE) &&
+ has_transparent_hugepage()))
+ goto unsupported_parameter;
+ ctx->seen |= SHMEM_SEEN_HUGE;
+ break;
+ case Opt_mpol:
+ if (IS_ENABLED(CONFIG_NUMA)) {
+ mpol_put(ctx->mpol);
+ ctx->mpol = NULL;
+ if (mpol_parse_str(param->string, &ctx->mpol))
+ goto bad_value;
+ break;
+ }
+ goto unsupported_parameter;
+ }
+ return 0;
+
+unsupported_parameter:
+ return invalf(fc, "tmpfs: Unsupported parameter '%s'", param->key);
+bad_value:
+ return invalf(fc, "tmpfs: Bad value for '%s'", param->key);
+}
+
+static int shmem_parse_options(struct fs_context *fc, void *data)
+{
+ char *options = data;
while (options != NULL) {
- this_char = options;
+ char *this_char = options;
for (;;) {
/*
* NUL-terminate this option: unfortunately,
@@ -3374,139 +3499,83 @@ static int shmem_parse_options(char *options, struct shmem_sb_info *sbinfo,
break;
}
}
- if (!*this_char)
- continue;
- if ((value = strchr(this_char,'=')) != NULL) {
- *value++ = 0;
- } else {
- pr_err("tmpfs: No value for mount option '%s'\n",
- this_char);
- goto error;
- }
-
- if (!strcmp(this_char,"size")) {
- unsigned long long size;
- size = memparse(value,&rest);
- if (*rest == '%') {
- size <<= PAGE_SHIFT;
- size *= totalram_pages();
- do_div(size, 100);
- rest++;
+ if (*this_char) {
+ char *value = strchr(this_char,'=');
+ size_t len = 0;
+ int err;
+
+ if (value) {
+ *value++ = '\0';
+ len = strlen(value);
}
- if (*rest)
- goto bad_val;
- sbinfo->max_blocks =
- DIV_ROUND_UP(size, PAGE_SIZE);
- } else if (!strcmp(this_char,"nr_blocks")) {
- sbinfo->max_blocks = memparse(value, &rest);
- if (*rest)
- goto bad_val;
- } else if (!strcmp(this_char,"nr_inodes")) {
- sbinfo->max_inodes = memparse(value, &rest);
- if (*rest)
- goto bad_val;
- } else if (!strcmp(this_char,"mode")) {
- if (remount)
- continue;
- sbinfo->mode = simple_strtoul(value, &rest, 8) & 07777;
- if (*rest)
- goto bad_val;
- } else if (!strcmp(this_char,"uid")) {
- if (remount)
- continue;
- uid = simple_strtoul(value, &rest, 0);
- if (*rest)
- goto bad_val;
- sbinfo->uid = make_kuid(current_user_ns(), uid);
- if (!uid_valid(sbinfo->uid))
- goto bad_val;
- } else if (!strcmp(this_char,"gid")) {
- if (remount)
- continue;
- gid = simple_strtoul(value, &rest, 0);
- if (*rest)
- goto bad_val;
- sbinfo->gid = make_kgid(current_user_ns(), gid);
- if (!gid_valid(sbinfo->gid))
- goto bad_val;
-#ifdef CONFIG_TRANSPARENT_HUGE_PAGECACHE
- } else if (!strcmp(this_char, "huge")) {
- int huge;
- huge = shmem_parse_huge(value);
- if (huge < 0)
- goto bad_val;
- if (!has_transparent_hugepage() &&
- huge != SHMEM_HUGE_NEVER)
- goto bad_val;
- sbinfo->huge = huge;
-#endif
-#ifdef CONFIG_NUMA
- } else if (!strcmp(this_char,"mpol")) {
- mpol_put(mpol);
- mpol = NULL;
- if (mpol_parse_str(value, &mpol))
- goto bad_val;
-#endif
- } else {
- pr_err("tmpfs: Bad mount option %s\n", this_char);
- goto error;
+ err = vfs_parse_fs_string(fc, this_char, value, len);
+ if (err < 0)
+ return err;
}
}
- sbinfo->mpol = mpol;
return 0;
-
-bad_val:
- pr_err("tmpfs: Bad value '%s' for mount option '%s'\n",
- value, this_char);
-error:
- mpol_put(mpol);
- return 1;
-
}
-static int shmem_remount_fs(struct super_block *sb, int *flags, char *data)
+/*
+ * Reconfigure a shmem filesystem.
+ *
+ * Note that we disallow change from limited->unlimited blocks/inodes while any
+ * are in use; but we must separately disallow unlimited->limited, because in
+ * that case we have no record of how much is already in use.
+ */
+static int shmem_reconfigure(struct fs_context *fc)
{
- struct shmem_sb_info *sbinfo = SHMEM_SB(sb);
- struct shmem_sb_info config = *sbinfo;
+ struct shmem_options *ctx = fc->fs_private;
+ struct shmem_sb_info *sbinfo = SHMEM_SB(fc->root->d_sb);
unsigned long inodes;
- int error = -EINVAL;
-
- config.mpol = NULL;
- if (shmem_parse_options(data, &config, true))
- return error;
+ const char *err;
spin_lock(&sbinfo->stat_lock);
inodes = sbinfo->max_inodes - sbinfo->free_inodes;
- if (percpu_counter_compare(&sbinfo->used_blocks, config.max_blocks) > 0)
- goto out;
- if (config.max_inodes < inodes)
- goto out;
- /*
- * Those tests disallow limited->unlimited while any are in use;
- * but we must separately disallow unlimited->limited, because
- * in that case we have no record of how much is already in use.
- */
- if (config.max_blocks && !sbinfo->max_blocks)
- goto out;
- if (config.max_inodes && !sbinfo->max_inodes)
- goto out;
+ if ((ctx->seen & SHMEM_SEEN_BLOCKS) && ctx->blocks) {
+ if (!sbinfo->max_blocks) {
+ err = "Cannot retroactively limit size";
+ goto out;
+ }
+ if (percpu_counter_compare(&sbinfo->used_blocks,
+ ctx->blocks) > 0) {
+ err = "Too small a size for current use";
+ goto out;
+ }
+ }
+ if ((ctx->seen & SHMEM_SEEN_INODES) && ctx->inodes) {
+ if (!sbinfo->max_inodes) {
+ err = "Cannot retroactively limit inodes";
+ goto out;
+ }
+ if (ctx->inodes < inodes) {
+ err = "Too few inodes for current use";
+ goto out;
+ }
+ }
- error = 0;
- sbinfo->huge = config.huge;
- sbinfo->max_blocks = config.max_blocks;
- sbinfo->max_inodes = config.max_inodes;
- sbinfo->free_inodes = config.max_inodes - inodes;
+ if (ctx->seen & SHMEM_SEEN_HUGE)
+ sbinfo->huge = ctx->huge;
+ if (ctx->seen & SHMEM_SEEN_BLOCKS)
+ sbinfo->max_blocks = ctx->blocks;
+ if (ctx->seen & SHMEM_SEEN_INODES) {
+ sbinfo->max_inodes = ctx->inodes;
+ sbinfo->free_inodes = ctx->inodes - inodes;
+ }
/*
* Preserve previous mempolicy unless mpol remount option was specified.
*/
- if (config.mpol) {
+ if (ctx->mpol) {
mpol_put(sbinfo->mpol);
- sbinfo->mpol = config.mpol; /* transfers initial ref */
+ sbinfo->mpol = ctx->mpol; /* transfers initial ref */
+ ctx->mpol = NULL;
}
+ spin_unlock(&sbinfo->stat_lock);
+ return 0;
out:
spin_unlock(&sbinfo->stat_lock);
- return error;
+ return invalf(fc, "tmpfs: %s", err);
}
static int shmem_show_options(struct seq_file *seq, struct dentry *root)
@@ -3547,8 +3616,9 @@ static void shmem_put_super(struct super_block *sb)
sb->s_fs_info = NULL;
}
-int shmem_fill_super(struct super_block *sb, void *data, int silent)
+static int shmem_fill_super(struct super_block *sb, struct fs_context *fc)
{
+ struct shmem_options *ctx = fc->fs_private;
struct inode *inode;
struct shmem_sb_info *sbinfo;
int err = -ENOMEM;
@@ -3559,9 +3629,6 @@ int shmem_fill_super(struct super_block *sb, void *data, int silent)
if (!sbinfo)
return -ENOMEM;
- sbinfo->mode = 0777 | S_ISVTX;
- sbinfo->uid = current_fsuid();
- sbinfo->gid = current_fsgid();
sb->s_fs_info = sbinfo;
#ifdef CONFIG_TMPFS
@@ -3571,12 +3638,10 @@ int shmem_fill_super(struct super_block *sb, void *data, int silent)
* but the internal instance is left unlimited.
*/
if (!(sb->s_flags & SB_KERNMOUNT)) {
- sbinfo->max_blocks = shmem_default_max_blocks();
- sbinfo->max_inodes = shmem_default_max_inodes();
- if (shmem_parse_options(data, sbinfo, false)) {
- err = -EINVAL;
- goto failed;
- }
+ if (!(ctx->seen & SHMEM_SEEN_BLOCKS))
+ ctx->blocks = shmem_default_max_blocks();
+ if (!(ctx->seen & SHMEM_SEEN_INODES))
+ ctx->inodes = shmem_default_max_inodes();
} else {
sb->s_flags |= SB_NOUSER;
}
@@ -3585,11 +3650,18 @@ int shmem_fill_super(struct super_block *sb, void *data, int silent)
#else
sb->s_flags |= SB_NOUSER;
#endif
+ sbinfo->max_blocks = ctx->blocks;
+ sbinfo->free_inodes = sbinfo->max_inodes = ctx->inodes;
+ sbinfo->uid = ctx->uid;
+ sbinfo->gid = ctx->gid;
+ sbinfo->mode = ctx->mode;
+ sbinfo->huge = ctx->huge;
+ sbinfo->mpol = ctx->mpol;
+ ctx->mpol = NULL;
spin_lock_init(&sbinfo->stat_lock);
if (percpu_counter_init(&sbinfo->used_blocks, 0, GFP_KERNEL))
goto failed;
- sbinfo->free_inodes = sbinfo->max_inodes;
spin_lock_init(&sbinfo->shrinklist_lock);
INIT_LIST_HEAD(&sbinfo->shrinklist);
@@ -3622,6 +3694,31 @@ failed:
return err;
}
+static int shmem_get_tree(struct fs_context *fc)
+{
+ return get_tree_nodev(fc, shmem_fill_super);
+}
+
+static void shmem_free_fc(struct fs_context *fc)
+{
+ struct shmem_options *ctx = fc->fs_private;
+
+ if (ctx) {
+ mpol_put(ctx->mpol);
+ kfree(ctx);
+ }
+}
+
+static const struct fs_context_operations shmem_fs_context_ops = {
+ .free = shmem_free_fc,
+ .get_tree = shmem_get_tree,
+#ifdef CONFIG_TMPFS
+ .parse_monolithic = shmem_parse_options,
+ .parse_param = shmem_parse_one,
+ .reconfigure = shmem_reconfigure,
+#endif
+};
+
static struct kmem_cache *shmem_inode_cachep;
static struct inode *shmem_alloc_inode(struct super_block *sb)
@@ -3738,7 +3835,6 @@ static const struct super_operations shmem_ops = {
.destroy_inode = shmem_destroy_inode,
#ifdef CONFIG_TMPFS
.statfs = shmem_statfs,
- .remount_fs = shmem_remount_fs,
.show_options = shmem_show_options,
#endif
.evict_inode = shmem_evict_inode,
@@ -3759,16 +3855,30 @@ static const struct vm_operations_struct shmem_vm_ops = {
#endif
};
-static struct dentry *shmem_mount(struct file_system_type *fs_type,
- int flags, const char *dev_name, void *data)
+int shmem_init_fs_context(struct fs_context *fc)
{
- return mount_nodev(fs_type, flags, data, shmem_fill_super);
+ struct shmem_options *ctx;
+
+ ctx = kzalloc(sizeof(struct shmem_options), GFP_KERNEL);
+ if (!ctx)
+ return -ENOMEM;
+
+ ctx->mode = 0777 | S_ISVTX;
+ ctx->uid = current_fsuid();
+ ctx->gid = current_fsgid();
+
+ fc->fs_private = ctx;
+ fc->ops = &shmem_fs_context_ops;
+ return 0;
}
static struct file_system_type shmem_fs_type = {
.owner = THIS_MODULE,
.name = "tmpfs",
- .mount = shmem_mount,
+ .init_fs_context = shmem_init_fs_context,
+#ifdef CONFIG_TMPFS
+ .parameters = &shmem_fs_parameters,
+#endif
.kill_sb = kill_litter_super,
.fs_flags = FS_USERNS_MOUNT,
};
@@ -3912,7 +4022,8 @@ bool shmem_huge_enabled(struct vm_area_struct *vma)
static struct file_system_type shmem_fs_type = {
.name = "tmpfs",
- .mount = ramfs_mount,
+ .init_fs_context = ramfs_init_fs_context,
+ .parameters = &ramfs_fs_parameters,
.kill_sb = kill_litter_super,
.fs_flags = FS_USERNS_MOUNT,
};