summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--drivers/base/devtmpfs.c16
-rw-r--r--fs/ramfs/inode.c99
-rw-r--r--include/linux/ramfs.h4
-rw-r--r--include/linux/shmem_fs.h4
-rw-r--r--init/do_mounts.c9
-rw-r--r--mm/shmem.c187
6 files changed, 180 insertions, 139 deletions
diff --git a/drivers/base/devtmpfs.c b/drivers/base/devtmpfs.c
index dabf5006a254..30d0523014e0 100644
--- a/drivers/base/devtmpfs.c
+++ b/drivers/base/devtmpfs.c
@@ -67,19 +67,15 @@ static struct dentry *public_dev_mount(struct file_system_type *fs_type, int fla
return dget(s->s_root);
}
-static struct dentry *dev_mount(struct file_system_type *fs_type, int flags,
- const char *dev_name, void *data)
-{
+static struct file_system_type internal_fs_type = {
+ .name = "devtmpfs",
#ifdef CONFIG_TMPFS
- return shmem_mount(fs_type, flags, dev_name, data);
+ .init_fs_context = shmem_init_fs_context,
+ .parameters = &shmem_fs_parameters,
#else
- return ramfs_mount(fs_type, flags, dev_name, data);
+ .init_fs_context = ramfs_init_fs_context,
+ .parameters = &ramfs_fs_parameters,
#endif
-}
-
-static struct file_system_type internal_fs_type = {
- .name = "devtmpfs",
- .mount = dev_mount,
.kill_sb = kill_litter_super,
};
diff --git a/fs/ramfs/inode.c b/fs/ramfs/inode.c
index b85d1e77e934..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;
}
-static 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 @@ static 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/include/linux/ramfs.h b/include/linux/ramfs.h
index e4d7d141545e..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,6 +16,7 @@ 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;
diff --git a/include/linux/shmem_fs.h b/include/linux/shmem_fs.h
index 88cb98b0e49b..de8e4b71e3ba 100644
--- a/include/linux/shmem_fs.h
+++ b/include/linux/shmem_fs.h
@@ -49,9 +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 struct dentry *shmem_mount(struct file_system_type *fs_type,
- int flags, const char *dev_name, void *data);
+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 16c29e57f224..9634ecf3743d 100644
--- a/init/do_mounts.c
+++ b/init/do_mounts.c
@@ -627,18 +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)
{
if (IS_ENABLED(CONFIG_TMPFS) && is_tmpfs)
- return shmem_mount(fs_type, flags, dev_name, data);
+ return shmem_init_fs_context(fc);
- return ramfs_mount(fs_type, flags, dev_name, data);
+ 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 6a41595dd1b3..0f7fd4a85db6 100644
--- a/mm/shmem.c
+++ b/mm/shmem.c
@@ -3401,22 +3401,17 @@ const struct fs_parameter_description shmem_fs_parameters = {
.enums = shmem_param_enums,
};
-static int shmem_parse_one(struct shmem_options *ctx,
- struct fs_parameter *param)
+static int shmem_parse_one(struct fs_context *fc, struct fs_parameter *param)
{
- struct fs_context *fc = NULL;
+ 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) {
- if (opt == -ENOPARAM)
- return invalf(fc, "tmpfs: Unknown parameter '%s'",
- param->key);
+ if (opt < 0)
return opt;
- }
switch (opt) {
case Opt_size:
@@ -3483,8 +3478,10 @@ bad_value:
return invalf(fc, "tmpfs: Bad value for '%s'", param->key);
}
-static int shmem_parse_options(char *options, struct shmem_options *ctx)
+static int shmem_parse_options(struct fs_context *fc, void *data)
{
+ char *options = data;
+
while (options != NULL) {
char *this_char = options;
for (;;) {
@@ -3504,85 +3501,81 @@ static int shmem_parse_options(char *options, struct shmem_options *ctx)
}
if (*this_char) {
char *value = strchr(this_char,'=');
- struct fs_parameter param = {
- .key = this_char,
- .type = fs_value_is_string,
- };
+ size_t len = 0;
int err;
if (value) {
*value++ = '\0';
- param.size = strlen(value);
- param.string = kstrdup(value, GFP_KERNEL);
- if (!param.string)
- goto error;
+ len = strlen(value);
}
- err = shmem_parse_one(ctx, &param);
- kfree(param.string);
- if (err)
- goto error;
+ err = vfs_parse_fs_string(fc, this_char, value, len);
+ if (err < 0)
+ return err;
}
}
return 0;
-
-error:
- mpol_put(ctx->mpol);
- ctx->mpol = NULL;
- 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_options ctx = {.seen = 0};
+ struct shmem_options *ctx = fc->fs_private;
+ struct shmem_sb_info *sbinfo = SHMEM_SB(fc->root->d_sb);
unsigned long inodes;
- int error = -EINVAL;
-
- if (shmem_parse_options(data, &ctx))
- return error;
+ const char *err;
spin_lock(&sbinfo->stat_lock);
inodes = sbinfo->max_inodes - sbinfo->free_inodes;
- /*
- * 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 ((ctx.seen & SHMEM_SEEN_BLOCKS) && ctx.blocks) {
- if (!sbinfo->max_blocks)
+ 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)
+ 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)
+ if ((ctx->seen & SHMEM_SEEN_INODES) && ctx->inodes) {
+ if (!sbinfo->max_inodes) {
+ err = "Cannot retroactively limit inodes";
goto out;
- if (ctx.inodes < inodes)
+ }
+ if (ctx->inodes < inodes) {
+ err = "Too few inodes for current use";
goto out;
+ }
}
- error = 0;
- 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;
+ 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 (ctx.mpol) {
+ if (ctx->mpol) {
mpol_put(sbinfo->mpol);
- sbinfo->mpol = ctx.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)
@@ -3623,13 +3616,11 @@ static void shmem_put_super(struct super_block *sb)
sb->s_fs_info = NULL;
}
-static 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;
- struct shmem_options ctx = {.mode = 0777 | S_ISVTX,
- .uid = current_fsuid(),
- .gid = current_fsgid()};
int err = -ENOMEM;
/* Round up to L1_CACHE_BYTES to resist false sharing */
@@ -3647,12 +3638,10 @@ static 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)) {
- ctx.blocks = shmem_default_max_blocks();
- ctx.inodes = shmem_default_max_inodes();
- if (shmem_parse_options(data, &ctx)) {
- 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;
}
@@ -3661,13 +3650,14 @@ static 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;
+ 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))
@@ -3704,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)
@@ -3820,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,
@@ -3841,16 +3855,30 @@ static const struct vm_operations_struct shmem_vm_ops = {
#endif
};
-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,
};
@@ -3994,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,
};