Skip to content

Commit

Permalink
vfs: Convert ramfs, shmem, tmpfs, devtmpfs, rootfs to use the new mou…
Browse files Browse the repository at this point in the history
…nt API

Convert the ramfs, shmem, tmpfs, devtmpfs and rootfs filesystems to the new
internal mount API as the old one will be obsoleted and removed.  This
allows greater flexibility in communication of mount parameters between
userspace, the VFS and the filesystem.

See Documentation/filesystems/mount_api.txt for more information.

Note that tmpfs is slightly tricky as it can contain embedded commas, so it
can't be trivially split up using strsep() to break on commas in
generic_parse_monolithic().  Instead, tmpfs has to supply its own generic
parser.

However, if tmpfs changes, then devtmpfs and rootfs, which are wrappers
around tmpfs or ramfs, must change too - and thus so must ramfs, so these
had to be converted also.

[AV: rewritten]

Signed-off-by: David Howells <dhowells@redhat.com>
cc: Hugh Dickins <hughd@google.com>
cc: linux-mm@kvack.org
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
  • Loading branch information
dhowells authored and Al Viro committed Sep 13, 2019
1 parent 626c392 commit f323562
Show file tree
Hide file tree
Showing 6 changed files with 180 additions and 139 deletions.
16 changes: 6 additions & 10 deletions drivers/base/devtmpfs.c
Original file line number Diff line number Diff line change
Expand Up @@ -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,
};

Expand Down
99 changes: 58 additions & 41 deletions fs/ramfs/inode.c
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down Expand Up @@ -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;
Expand All @@ -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)
Expand All @@ -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,
};
Expand Down
4 changes: 2 additions & 2 deletions include/linux/ramfs.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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;

Expand Down
4 changes: 2 additions & 2 deletions include/linux/shmem_fs.h
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
9 changes: 4 additions & 5 deletions init/do_mounts.c
Original file line number Diff line number Diff line change
Expand Up @@ -627,18 +627,17 @@ void __init prepare_namespace(void)
}

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,
};

Expand Down
Loading

0 comments on commit f323562

Please sign in to comment.