summaryrefslogtreecommitdiffstats
path: root/mm/shmem.c
diff options
context:
space:
mode:
authorDavid Howells <dhowells@redhat.com>2019-03-25 12:38:31 -0400
committerAl Viro <viro@zeniv.linux.org.uk>2019-09-12 21:05:34 -0400
commitf32356261d44d580649a7abce1156d15d49cf20f (patch)
tree140effa4ef1e1ff107ec8028d7c55862191264e6 /mm/shmem.c
parent626c3920aeb4575f53c96b0d4ad4e651a21cbb66 (diff)
vfs: Convert ramfs, shmem, tmpfs, devtmpfs, rootfs to use the new mount 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>
Diffstat (limited to 'mm/shmem.c')
-rw-r--r--mm/shmem.c187
1 files changed, 108 insertions, 79 deletions
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 = {
3401 .enums = shmem_param_enums, 3401 .enums = shmem_param_enums,
3402}; 3402};
3403 3403
3404static int shmem_parse_one(struct shmem_options *ctx, 3404static int shmem_parse_one(struct fs_context *fc, struct fs_parameter *param)
3405 struct fs_parameter *param)
3406{ 3405{
3407 struct fs_context *fc = NULL; 3406 struct shmem_options *ctx = fc->fs_private;
3408 struct fs_parse_result result; 3407 struct fs_parse_result result;
3409 unsigned long long size; 3408 unsigned long long size;
3410 char *rest; 3409 char *rest;
3411 int opt; 3410 int opt;
3412 3411
3413 opt = fs_parse(fc, &shmem_fs_parameters, param, &result); 3412 opt = fs_parse(fc, &shmem_fs_parameters, param, &result);
3414 if (opt < 0) { 3413 if (opt < 0)
3415 if (opt == -ENOPARAM)
3416 return invalf(fc, "tmpfs: Unknown parameter '%s'",
3417 param->key);
3418 return opt; 3414 return opt;
3419 }
3420 3415
3421 switch (opt) { 3416 switch (opt) {
3422 case Opt_size: 3417 case Opt_size:
@@ -3483,8 +3478,10 @@ bad_value:
3483 return invalf(fc, "tmpfs: Bad value for '%s'", param->key); 3478 return invalf(fc, "tmpfs: Bad value for '%s'", param->key);
3484} 3479}
3485 3480
3486static int shmem_parse_options(char *options, struct shmem_options *ctx) 3481static int shmem_parse_options(struct fs_context *fc, void *data)
3487{ 3482{
3483 char *options = data;
3484
3488 while (options != NULL) { 3485 while (options != NULL) {
3489 char *this_char = options; 3486 char *this_char = options;
3490 for (;;) { 3487 for (;;) {
@@ -3504,85 +3501,81 @@ static int shmem_parse_options(char *options, struct shmem_options *ctx)
3504 } 3501 }
3505 if (*this_char) { 3502 if (*this_char) {
3506 char *value = strchr(this_char,'='); 3503 char *value = strchr(this_char,'=');
3507 struct fs_parameter param = { 3504 size_t len = 0;
3508 .key = this_char,
3509 .type = fs_value_is_string,
3510 };
3511 int err; 3505 int err;
3512 3506
3513 if (value) { 3507 if (value) {
3514 *value++ = '\0'; 3508 *value++ = '\0';
3515 param.size = strlen(value); 3509 len = strlen(value);
3516 param.string = kstrdup(value, GFP_KERNEL);
3517 if (!param.string)
3518 goto error;
3519 } 3510 }
3520 err = shmem_parse_one(ctx, &param); 3511 err = vfs_parse_fs_string(fc, this_char, value, len);
3521 kfree(param.string); 3512 if (err < 0)
3522 if (err) 3513 return err;
3523 goto error;
3524 } 3514 }
3525 } 3515 }
3526 return 0; 3516 return 0;
3527
3528error:
3529 mpol_put(ctx->mpol);
3530 ctx->mpol = NULL;
3531 return 1;
3532
3533} 3517}
3534 3518
3535static int shmem_remount_fs(struct super_block *sb, int *flags, char *data) 3519/*
3520 * Reconfigure a shmem filesystem.
3521 *
3522 * Note that we disallow change from limited->unlimited blocks/inodes while any
3523 * are in use; but we must separately disallow unlimited->limited, because in
3524 * that case we have no record of how much is already in use.
3525 */
3526static int shmem_reconfigure(struct fs_context *fc)
3536{ 3527{
3537 struct shmem_sb_info *sbinfo = SHMEM_SB(sb); 3528 struct shmem_options *ctx = fc->fs_private;
3538 struct shmem_options ctx = {.seen = 0}; 3529 struct shmem_sb_info *sbinfo = SHMEM_SB(fc->root->d_sb);
3539 unsigned long inodes; 3530 unsigned long inodes;
3540 int error = -EINVAL; 3531 const char *err;
3541
3542 if (shmem_parse_options(data, &ctx))
3543 return error;
3544 3532
3545 spin_lock(&sbinfo->stat_lock); 3533 spin_lock(&sbinfo->stat_lock);
3546 inodes = sbinfo->max_inodes - sbinfo->free_inodes; 3534 inodes = sbinfo->max_inodes - sbinfo->free_inodes;
3547 /* 3535 if ((ctx->seen & SHMEM_SEEN_BLOCKS) && ctx->blocks) {
3548 * Those tests disallow limited->unlimited while any are in use; 3536 if (!sbinfo->max_blocks) {
3549 * but we must separately disallow unlimited->limited, because 3537 err = "Cannot retroactively limit size";
3550 * in that case we have no record of how much is already in use.
3551 */
3552 if ((ctx.seen & SHMEM_SEEN_BLOCKS) && ctx.blocks) {
3553 if (!sbinfo->max_blocks)
3554 goto out; 3538 goto out;
3539 }
3555 if (percpu_counter_compare(&sbinfo->used_blocks, 3540 if (percpu_counter_compare(&sbinfo->used_blocks,
3556 ctx.blocks) > 0) 3541 ctx->blocks) > 0) {
3542 err = "Too small a size for current use";
3557 goto out; 3543 goto out;
3544 }
3558 } 3545 }
3559 if ((ctx.seen & SHMEM_SEEN_INODES) && ctx.inodes) { 3546 if ((ctx->seen & SHMEM_SEEN_INODES) && ctx->inodes) {
3560 if (!sbinfo->max_inodes) 3547 if (!sbinfo->max_inodes) {
3548 err = "Cannot retroactively limit inodes";
3561 goto out; 3549 goto out;
3562 if (ctx.inodes < inodes) 3550 }
3551 if (ctx->inodes < inodes) {
3552 err = "Too few inodes for current use";
3563 goto out; 3553 goto out;
3554 }
3564 } 3555 }
3565 3556
3566 error = 0; 3557 if (ctx->seen & SHMEM_SEEN_HUGE)
3567 if (ctx.seen & SHMEM_SEEN_HUGE) 3558 sbinfo->huge = ctx->huge;
3568 sbinfo->huge = ctx.huge; 3559 if (ctx->seen & SHMEM_SEEN_BLOCKS)
3569 if (ctx.seen & SHMEM_SEEN_BLOCKS) 3560 sbinfo->max_blocks = ctx->blocks;
3570 sbinfo->max_blocks = ctx.blocks; 3561 if (ctx->seen & SHMEM_SEEN_INODES) {
3571 if (ctx.seen & SHMEM_SEEN_INODES) { 3562 sbinfo->max_inodes = ctx->inodes;
3572 sbinfo->max_inodes = ctx.inodes; 3563 sbinfo->free_inodes = ctx->inodes - inodes;
3573 sbinfo->free_inodes = ctx.inodes - inodes;
3574 } 3564 }
3575 3565
3576 /* 3566 /*
3577 * Preserve previous mempolicy unless mpol remount option was specified. 3567 * Preserve previous mempolicy unless mpol remount option was specified.
3578 */ 3568 */
3579 if (ctx.mpol) { 3569 if (ctx->mpol) {
3580 mpol_put(sbinfo->mpol); 3570 mpol_put(sbinfo->mpol);
3581 sbinfo->mpol = ctx.mpol; /* transfers initial ref */ 3571 sbinfo->mpol = ctx->mpol; /* transfers initial ref */
3572 ctx->mpol = NULL;
3582 } 3573 }
3574 spin_unlock(&sbinfo->stat_lock);
3575 return 0;
3583out: 3576out:
3584 spin_unlock(&sbinfo->stat_lock); 3577 spin_unlock(&sbinfo->stat_lock);
3585 return error; 3578 return invalf(fc, "tmpfs: %s", err);
3586} 3579}
3587 3580
3588static int shmem_show_options(struct seq_file *seq, struct dentry *root) 3581static int shmem_show_options(struct seq_file *seq, struct dentry *root)
@@ -3623,13 +3616,11 @@ static void shmem_put_super(struct super_block *sb)
3623 sb->s_fs_info = NULL; 3616 sb->s_fs_info = NULL;
3624} 3617}
3625 3618
3626static int shmem_fill_super(struct super_block *sb, void *data, int silent) 3619static int shmem_fill_super(struct super_block *sb, struct fs_context *fc)
3627{ 3620{
3621 struct shmem_options *ctx = fc->fs_private;
3628 struct inode *inode; 3622 struct inode *inode;
3629 struct shmem_sb_info *sbinfo; 3623 struct shmem_sb_info *sbinfo;
3630 struct shmem_options ctx = {.mode = 0777 | S_ISVTX,
3631 .uid = current_fsuid(),
3632 .gid = current_fsgid()};
3633 int err = -ENOMEM; 3624 int err = -ENOMEM;
3634 3625
3635 /* Round up to L1_CACHE_BYTES to resist false sharing */ 3626 /* 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)
3647 * but the internal instance is left unlimited. 3638 * but the internal instance is left unlimited.
3648 */ 3639 */
3649 if (!(sb->s_flags & SB_KERNMOUNT)) { 3640 if (!(sb->s_flags & SB_KERNMOUNT)) {
3650 ctx.blocks = shmem_default_max_blocks(); 3641 if (!(ctx->seen & SHMEM_SEEN_BLOCKS))
3651 ctx.inodes = shmem_default_max_inodes(); 3642 ctx->blocks = shmem_default_max_blocks();
3652 if (shmem_parse_options(data, &ctx)) { 3643 if (!(ctx->seen & SHMEM_SEEN_INODES))
3653 err = -EINVAL; 3644 ctx->inodes = shmem_default_max_inodes();
3654 goto failed;
3655 }
3656 } else { 3645 } else {
3657 sb->s_flags |= SB_NOUSER; 3646 sb->s_flags |= SB_NOUSER;
3658 } 3647 }
@@ -3661,13 +3650,14 @@ static int shmem_fill_super(struct super_block *sb, void *data, int silent)
3661#else 3650#else
3662 sb->s_flags |= SB_NOUSER; 3651 sb->s_flags |= SB_NOUSER;
3663#endif 3652#endif
3664 sbinfo->max_blocks = ctx.blocks; 3653 sbinfo->max_blocks = ctx->blocks;
3665 sbinfo->free_inodes = sbinfo->max_inodes = ctx.inodes; 3654 sbinfo->free_inodes = sbinfo->max_inodes = ctx->inodes;
3666 sbinfo->uid = ctx.uid; 3655 sbinfo->uid = ctx->uid;
3667 sbinfo->gid = ctx.gid; 3656 sbinfo->gid = ctx->gid;
3668 sbinfo->mode = ctx.mode; 3657 sbinfo->mode = ctx->mode;
3669 sbinfo->huge = ctx.huge; 3658 sbinfo->huge = ctx->huge;
3670 sbinfo->mpol = ctx.mpol; 3659 sbinfo->mpol = ctx->mpol;
3660 ctx->mpol = NULL;
3671 3661
3672 spin_lock_init(&sbinfo->stat_lock); 3662 spin_lock_init(&sbinfo->stat_lock);
3673 if (percpu_counter_init(&sbinfo->used_blocks, 0, GFP_KERNEL)) 3663 if (percpu_counter_init(&sbinfo->used_blocks, 0, GFP_KERNEL))
@@ -3704,6 +3694,31 @@ failed:
3704 return err; 3694 return err;
3705} 3695}
3706 3696
3697static int shmem_get_tree(struct fs_context *fc)
3698{
3699 return get_tree_nodev(fc, shmem_fill_super);
3700}
3701
3702static void shmem_free_fc(struct fs_context *fc)
3703{
3704 struct shmem_options *ctx = fc->fs_private;
3705
3706 if (ctx) {
3707 mpol_put(ctx->mpol);
3708 kfree(ctx);
3709 }
3710}
3711
3712static const struct fs_context_operations shmem_fs_context_ops = {
3713 .free = shmem_free_fc,
3714 .get_tree = shmem_get_tree,
3715#ifdef CONFIG_TMPFS
3716 .parse_monolithic = shmem_parse_options,
3717 .parse_param = shmem_parse_one,
3718 .reconfigure = shmem_reconfigure,
3719#endif
3720};
3721
3707static struct kmem_cache *shmem_inode_cachep; 3722static struct kmem_cache *shmem_inode_cachep;
3708 3723
3709static struct inode *shmem_alloc_inode(struct super_block *sb) 3724static struct inode *shmem_alloc_inode(struct super_block *sb)
@@ -3820,7 +3835,6 @@ static const struct super_operations shmem_ops = {
3820 .destroy_inode = shmem_destroy_inode, 3835 .destroy_inode = shmem_destroy_inode,
3821#ifdef CONFIG_TMPFS 3836#ifdef CONFIG_TMPFS
3822 .statfs = shmem_statfs, 3837 .statfs = shmem_statfs,
3823 .remount_fs = shmem_remount_fs,
3824 .show_options = shmem_show_options, 3838 .show_options = shmem_show_options,
3825#endif 3839#endif
3826 .evict_inode = shmem_evict_inode, 3840 .evict_inode = shmem_evict_inode,
@@ -3841,16 +3855,30 @@ static const struct vm_operations_struct shmem_vm_ops = {
3841#endif 3855#endif
3842}; 3856};
3843 3857
3844struct dentry *shmem_mount(struct file_system_type *fs_type, 3858int shmem_init_fs_context(struct fs_context *fc)
3845 int flags, const char *dev_name, void *data)
3846{ 3859{
3847 return mount_nodev(fs_type, flags, data, shmem_fill_super); 3860 struct shmem_options *ctx;
3861
3862 ctx = kzalloc(sizeof(struct shmem_options), GFP_KERNEL);
3863 if (!ctx)
3864 return -ENOMEM;
3865
3866 ctx->mode = 0777 | S_ISVTX;
3867 ctx->uid = current_fsuid();
3868 ctx->gid = current_fsgid();
3869
3870 fc->fs_private = ctx;
3871 fc->ops = &shmem_fs_context_ops;
3872 return 0;
3848} 3873}
3849 3874
3850static struct file_system_type shmem_fs_type = { 3875static struct file_system_type shmem_fs_type = {
3851 .owner = THIS_MODULE, 3876 .owner = THIS_MODULE,
3852 .name = "tmpfs", 3877 .name = "tmpfs",
3853 .mount = shmem_mount, 3878 .init_fs_context = shmem_init_fs_context,
3879#ifdef CONFIG_TMPFS
3880 .parameters = &shmem_fs_parameters,
3881#endif
3854 .kill_sb = kill_litter_super, 3882 .kill_sb = kill_litter_super,
3855 .fs_flags = FS_USERNS_MOUNT, 3883 .fs_flags = FS_USERNS_MOUNT,
3856}; 3884};
@@ -3994,7 +4022,8 @@ bool shmem_huge_enabled(struct vm_area_struct *vma)
3994 4022
3995static struct file_system_type shmem_fs_type = { 4023static struct file_system_type shmem_fs_type = {
3996 .name = "tmpfs", 4024 .name = "tmpfs",
3997 .mount = ramfs_mount, 4025 .init_fs_context = ramfs_init_fs_context,
4026 .parameters = &ramfs_fs_parameters,
3998 .kill_sb = kill_litter_super, 4027 .kill_sb = kill_litter_super,
3999 .fs_flags = FS_USERNS_MOUNT, 4028 .fs_flags = FS_USERNS_MOUNT,
4000}; 4029};