diff options
Diffstat (limited to 'mm/shmem.c')
-rw-r--r-- | mm/shmem.c | 385 |
1 files changed, 248 insertions, 137 deletions
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 @@ | |||
37 | #include <linux/khugepaged.h> | 37 | #include <linux/khugepaged.h> |
38 | #include <linux/hugetlb.h> | 38 | #include <linux/hugetlb.h> |
39 | #include <linux/frontswap.h> | 39 | #include <linux/frontswap.h> |
40 | #include <linux/fs_parser.h> | ||
40 | 41 | ||
41 | #include <asm/tlbflush.h> /* for arch/microblaze update_mmu_cache() */ | 42 | #include <asm/tlbflush.h> /* for arch/microblaze update_mmu_cache() */ |
42 | 43 | ||
@@ -107,6 +108,20 @@ struct shmem_falloc { | |||
107 | pgoff_t nr_unswapped; /* how often writepage refused to swap out */ | 108 | pgoff_t nr_unswapped; /* how often writepage refused to swap out */ |
108 | }; | 109 | }; |
109 | 110 | ||
111 | struct shmem_options { | ||
112 | unsigned long long blocks; | ||
113 | unsigned long long inodes; | ||
114 | struct mempolicy *mpol; | ||
115 | kuid_t uid; | ||
116 | kgid_t gid; | ||
117 | umode_t mode; | ||
118 | int huge; | ||
119 | int seen; | ||
120 | #define SHMEM_SEEN_BLOCKS 1 | ||
121 | #define SHMEM_SEEN_INODES 2 | ||
122 | #define SHMEM_SEEN_HUGE 4 | ||
123 | }; | ||
124 | |||
110 | #ifdef CONFIG_TMPFS | 125 | #ifdef CONFIG_TMPFS |
111 | static unsigned long shmem_default_max_blocks(void) | 126 | static unsigned long shmem_default_max_blocks(void) |
112 | { | 127 | { |
@@ -3349,16 +3364,126 @@ static const struct export_operations shmem_export_ops = { | |||
3349 | .fh_to_dentry = shmem_fh_to_dentry, | 3364 | .fh_to_dentry = shmem_fh_to_dentry, |
3350 | }; | 3365 | }; |
3351 | 3366 | ||
3352 | static int shmem_parse_options(char *options, struct shmem_sb_info *sbinfo, | 3367 | enum shmem_param { |
3353 | bool remount) | 3368 | Opt_gid, |
3369 | Opt_huge, | ||
3370 | Opt_mode, | ||
3371 | Opt_mpol, | ||
3372 | Opt_nr_blocks, | ||
3373 | Opt_nr_inodes, | ||
3374 | Opt_size, | ||
3375 | Opt_uid, | ||
3376 | }; | ||
3377 | |||
3378 | static const struct fs_parameter_spec shmem_param_specs[] = { | ||
3379 | fsparam_u32 ("gid", Opt_gid), | ||
3380 | fsparam_enum ("huge", Opt_huge), | ||
3381 | fsparam_u32oct("mode", Opt_mode), | ||
3382 | fsparam_string("mpol", Opt_mpol), | ||
3383 | fsparam_string("nr_blocks", Opt_nr_blocks), | ||
3384 | fsparam_string("nr_inodes", Opt_nr_inodes), | ||
3385 | fsparam_string("size", Opt_size), | ||
3386 | fsparam_u32 ("uid", Opt_uid), | ||
3387 | {} | ||
3388 | }; | ||
3389 | |||
3390 | static const struct fs_parameter_enum shmem_param_enums[] = { | ||
3391 | { Opt_huge, "never", SHMEM_HUGE_NEVER }, | ||
3392 | { Opt_huge, "always", SHMEM_HUGE_ALWAYS }, | ||
3393 | { Opt_huge, "within_size", SHMEM_HUGE_WITHIN_SIZE }, | ||
3394 | { Opt_huge, "advise", SHMEM_HUGE_ADVISE }, | ||
3395 | {} | ||
3396 | }; | ||
3397 | |||
3398 | const struct fs_parameter_description shmem_fs_parameters = { | ||
3399 | .name = "tmpfs", | ||
3400 | .specs = shmem_param_specs, | ||
3401 | .enums = shmem_param_enums, | ||
3402 | }; | ||
3403 | |||
3404 | static int shmem_parse_one(struct fs_context *fc, struct fs_parameter *param) | ||
3354 | { | 3405 | { |
3355 | char *this_char, *value, *rest; | 3406 | struct shmem_options *ctx = fc->fs_private; |
3356 | struct mempolicy *mpol = NULL; | 3407 | struct fs_parse_result result; |
3357 | uid_t uid; | 3408 | unsigned long long size; |
3358 | gid_t gid; | 3409 | char *rest; |
3410 | int opt; | ||
3411 | |||
3412 | opt = fs_parse(fc, &shmem_fs_parameters, param, &result); | ||
3413 | if (opt < 0) | ||
3414 | return opt; | ||
3415 | |||
3416 | switch (opt) { | ||
3417 | case Opt_size: | ||
3418 | size = memparse(param->string, &rest); | ||
3419 | if (*rest == '%') { | ||
3420 | size <<= PAGE_SHIFT; | ||
3421 | size *= totalram_pages(); | ||
3422 | do_div(size, 100); | ||
3423 | rest++; | ||
3424 | } | ||
3425 | if (*rest) | ||
3426 | goto bad_value; | ||
3427 | ctx->blocks = DIV_ROUND_UP(size, PAGE_SIZE); | ||
3428 | ctx->seen |= SHMEM_SEEN_BLOCKS; | ||
3429 | break; | ||
3430 | case Opt_nr_blocks: | ||
3431 | ctx->blocks = memparse(param->string, &rest); | ||
3432 | if (*rest) | ||
3433 | goto bad_value; | ||
3434 | ctx->seen |= SHMEM_SEEN_BLOCKS; | ||
3435 | break; | ||
3436 | case Opt_nr_inodes: | ||
3437 | ctx->inodes = memparse(param->string, &rest); | ||
3438 | if (*rest) | ||
3439 | goto bad_value; | ||
3440 | ctx->seen |= SHMEM_SEEN_INODES; | ||
3441 | break; | ||
3442 | case Opt_mode: | ||
3443 | ctx->mode = result.uint_32 & 07777; | ||
3444 | break; | ||
3445 | case Opt_uid: | ||
3446 | ctx->uid = make_kuid(current_user_ns(), result.uint_32); | ||
3447 | if (!uid_valid(ctx->uid)) | ||
3448 | goto bad_value; | ||
3449 | break; | ||
3450 | case Opt_gid: | ||
3451 | ctx->gid = make_kgid(current_user_ns(), result.uint_32); | ||
3452 | if (!gid_valid(ctx->gid)) | ||
3453 | goto bad_value; | ||
3454 | break; | ||
3455 | case Opt_huge: | ||
3456 | ctx->huge = result.uint_32; | ||
3457 | if (ctx->huge != SHMEM_HUGE_NEVER && | ||
3458 | !(IS_ENABLED(CONFIG_TRANSPARENT_HUGE_PAGECACHE) && | ||
3459 | has_transparent_hugepage())) | ||
3460 | goto unsupported_parameter; | ||
3461 | ctx->seen |= SHMEM_SEEN_HUGE; | ||
3462 | break; | ||
3463 | case Opt_mpol: | ||
3464 | if (IS_ENABLED(CONFIG_NUMA)) { | ||
3465 | mpol_put(ctx->mpol); | ||
3466 | ctx->mpol = NULL; | ||
3467 | if (mpol_parse_str(param->string, &ctx->mpol)) | ||
3468 | goto bad_value; | ||
3469 | break; | ||
3470 | } | ||
3471 | goto unsupported_parameter; | ||
3472 | } | ||
3473 | return 0; | ||
3474 | |||
3475 | unsupported_parameter: | ||
3476 | return invalf(fc, "tmpfs: Unsupported parameter '%s'", param->key); | ||
3477 | bad_value: | ||
3478 | return invalf(fc, "tmpfs: Bad value for '%s'", param->key); | ||
3479 | } | ||
3480 | |||
3481 | static int shmem_parse_options(struct fs_context *fc, void *data) | ||
3482 | { | ||
3483 | char *options = data; | ||
3359 | 3484 | ||
3360 | while (options != NULL) { | 3485 | while (options != NULL) { |
3361 | this_char = options; | 3486 | char *this_char = options; |
3362 | for (;;) { | 3487 | for (;;) { |
3363 | /* | 3488 | /* |
3364 | * NUL-terminate this option: unfortunately, | 3489 | * NUL-terminate this option: unfortunately, |
@@ -3374,139 +3499,83 @@ static int shmem_parse_options(char *options, struct shmem_sb_info *sbinfo, | |||
3374 | break; | 3499 | break; |
3375 | } | 3500 | } |
3376 | } | 3501 | } |
3377 | if (!*this_char) | 3502 | if (*this_char) { |
3378 | continue; | 3503 | char *value = strchr(this_char,'='); |
3379 | if ((value = strchr(this_char,'=')) != NULL) { | 3504 | size_t len = 0; |
3380 | *value++ = 0; | 3505 | int err; |
3381 | } else { | 3506 | |
3382 | pr_err("tmpfs: No value for mount option '%s'\n", | 3507 | if (value) { |
3383 | this_char); | 3508 | *value++ = '\0'; |
3384 | goto error; | 3509 | len = strlen(value); |
3385 | } | ||
3386 | |||
3387 | if (!strcmp(this_char,"size")) { | ||
3388 | unsigned long long size; | ||
3389 | size = memparse(value,&rest); | ||
3390 | if (*rest == '%') { | ||
3391 | size <<= PAGE_SHIFT; | ||
3392 | size *= totalram_pages(); | ||
3393 | do_div(size, 100); | ||
3394 | rest++; | ||
3395 | } | 3510 | } |
3396 | if (*rest) | 3511 | err = vfs_parse_fs_string(fc, this_char, value, len); |
3397 | goto bad_val; | 3512 | if (err < 0) |
3398 | sbinfo->max_blocks = | 3513 | return err; |
3399 | DIV_ROUND_UP(size, PAGE_SIZE); | ||
3400 | } else if (!strcmp(this_char,"nr_blocks")) { | ||
3401 | sbinfo->max_blocks = memparse(value, &rest); | ||
3402 | if (*rest) | ||
3403 | goto bad_val; | ||
3404 | } else if (!strcmp(this_char,"nr_inodes")) { | ||
3405 | sbinfo->max_inodes = memparse(value, &rest); | ||
3406 | if (*rest) | ||
3407 | goto bad_val; | ||
3408 | } else if (!strcmp(this_char,"mode")) { | ||
3409 | if (remount) | ||
3410 | continue; | ||
3411 | sbinfo->mode = simple_strtoul(value, &rest, 8) & 07777; | ||
3412 | if (*rest) | ||
3413 | goto bad_val; | ||
3414 | } else if (!strcmp(this_char,"uid")) { | ||
3415 | if (remount) | ||
3416 | continue; | ||
3417 | uid = simple_strtoul(value, &rest, 0); | ||
3418 | if (*rest) | ||
3419 | goto bad_val; | ||
3420 | sbinfo->uid = make_kuid(current_user_ns(), uid); | ||
3421 | if (!uid_valid(sbinfo->uid)) | ||
3422 | goto bad_val; | ||
3423 | } else if (!strcmp(this_char,"gid")) { | ||
3424 | if (remount) | ||
3425 | continue; | ||
3426 | gid = simple_strtoul(value, &rest, 0); | ||
3427 | if (*rest) | ||
3428 | goto bad_val; | ||
3429 | sbinfo->gid = make_kgid(current_user_ns(), gid); | ||
3430 | if (!gid_valid(sbinfo->gid)) | ||
3431 | goto bad_val; | ||
3432 | #ifdef CONFIG_TRANSPARENT_HUGE_PAGECACHE | ||
3433 | } else if (!strcmp(this_char, "huge")) { | ||
3434 | int huge; | ||
3435 | huge = shmem_parse_huge(value); | ||
3436 | if (huge < 0) | ||
3437 | goto bad_val; | ||
3438 | if (!has_transparent_hugepage() && | ||
3439 | huge != SHMEM_HUGE_NEVER) | ||
3440 | goto bad_val; | ||
3441 | sbinfo->huge = huge; | ||
3442 | #endif | ||
3443 | #ifdef CONFIG_NUMA | ||
3444 | } else if (!strcmp(this_char,"mpol")) { | ||
3445 | mpol_put(mpol); | ||
3446 | mpol = NULL; | ||
3447 | if (mpol_parse_str(value, &mpol)) | ||
3448 | goto bad_val; | ||
3449 | #endif | ||
3450 | } else { | ||
3451 | pr_err("tmpfs: Bad mount option %s\n", this_char); | ||
3452 | goto error; | ||
3453 | } | 3514 | } |
3454 | } | 3515 | } |
3455 | sbinfo->mpol = mpol; | ||
3456 | return 0; | 3516 | return 0; |
3457 | |||
3458 | bad_val: | ||
3459 | pr_err("tmpfs: Bad value '%s' for mount option '%s'\n", | ||
3460 | value, this_char); | ||
3461 | error: | ||
3462 | mpol_put(mpol); | ||
3463 | return 1; | ||
3464 | |||
3465 | } | 3517 | } |
3466 | 3518 | ||
3467 | static 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 | */ | ||
3526 | static int shmem_reconfigure(struct fs_context *fc) | ||
3468 | { | 3527 | { |
3469 | struct shmem_sb_info *sbinfo = SHMEM_SB(sb); | 3528 | struct shmem_options *ctx = fc->fs_private; |
3470 | struct shmem_sb_info config = *sbinfo; | 3529 | struct shmem_sb_info *sbinfo = SHMEM_SB(fc->root->d_sb); |
3471 | unsigned long inodes; | 3530 | unsigned long inodes; |
3472 | int error = -EINVAL; | 3531 | const char *err; |
3473 | |||
3474 | config.mpol = NULL; | ||
3475 | if (shmem_parse_options(data, &config, true)) | ||
3476 | return error; | ||
3477 | 3532 | ||
3478 | spin_lock(&sbinfo->stat_lock); | 3533 | spin_lock(&sbinfo->stat_lock); |
3479 | inodes = sbinfo->max_inodes - sbinfo->free_inodes; | 3534 | inodes = sbinfo->max_inodes - sbinfo->free_inodes; |
3480 | if (percpu_counter_compare(&sbinfo->used_blocks, config.max_blocks) > 0) | 3535 | if ((ctx->seen & SHMEM_SEEN_BLOCKS) && ctx->blocks) { |
3481 | goto out; | 3536 | if (!sbinfo->max_blocks) { |
3482 | if (config.max_inodes < inodes) | 3537 | err = "Cannot retroactively limit size"; |
3483 | goto out; | 3538 | goto out; |
3484 | /* | 3539 | } |
3485 | * Those tests disallow limited->unlimited while any are in use; | 3540 | if (percpu_counter_compare(&sbinfo->used_blocks, |
3486 | * but we must separately disallow unlimited->limited, because | 3541 | ctx->blocks) > 0) { |
3487 | * in that case we have no record of how much is already in use. | 3542 | err = "Too small a size for current use"; |
3488 | */ | 3543 | goto out; |
3489 | if (config.max_blocks && !sbinfo->max_blocks) | 3544 | } |
3490 | goto out; | 3545 | } |
3491 | if (config.max_inodes && !sbinfo->max_inodes) | 3546 | if ((ctx->seen & SHMEM_SEEN_INODES) && ctx->inodes) { |
3492 | goto out; | 3547 | if (!sbinfo->max_inodes) { |
3548 | err = "Cannot retroactively limit inodes"; | ||
3549 | goto out; | ||
3550 | } | ||
3551 | if (ctx->inodes < inodes) { | ||
3552 | err = "Too few inodes for current use"; | ||
3553 | goto out; | ||
3554 | } | ||
3555 | } | ||
3493 | 3556 | ||
3494 | error = 0; | 3557 | if (ctx->seen & SHMEM_SEEN_HUGE) |
3495 | sbinfo->huge = config.huge; | 3558 | sbinfo->huge = ctx->huge; |
3496 | sbinfo->max_blocks = config.max_blocks; | 3559 | if (ctx->seen & SHMEM_SEEN_BLOCKS) |
3497 | sbinfo->max_inodes = config.max_inodes; | 3560 | sbinfo->max_blocks = ctx->blocks; |
3498 | sbinfo->free_inodes = config.max_inodes - inodes; | 3561 | if (ctx->seen & SHMEM_SEEN_INODES) { |
3562 | sbinfo->max_inodes = ctx->inodes; | ||
3563 | sbinfo->free_inodes = ctx->inodes - inodes; | ||
3564 | } | ||
3499 | 3565 | ||
3500 | /* | 3566 | /* |
3501 | * Preserve previous mempolicy unless mpol remount option was specified. | 3567 | * Preserve previous mempolicy unless mpol remount option was specified. |
3502 | */ | 3568 | */ |
3503 | if (config.mpol) { | 3569 | if (ctx->mpol) { |
3504 | mpol_put(sbinfo->mpol); | 3570 | mpol_put(sbinfo->mpol); |
3505 | sbinfo->mpol = config.mpol; /* transfers initial ref */ | 3571 | sbinfo->mpol = ctx->mpol; /* transfers initial ref */ |
3572 | ctx->mpol = NULL; | ||
3506 | } | 3573 | } |
3574 | spin_unlock(&sbinfo->stat_lock); | ||
3575 | return 0; | ||
3507 | out: | 3576 | out: |
3508 | spin_unlock(&sbinfo->stat_lock); | 3577 | spin_unlock(&sbinfo->stat_lock); |
3509 | return error; | 3578 | return invalf(fc, "tmpfs: %s", err); |
3510 | } | 3579 | } |
3511 | 3580 | ||
3512 | static int shmem_show_options(struct seq_file *seq, struct dentry *root) | 3581 | 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) | |||
3547 | sb->s_fs_info = NULL; | 3616 | sb->s_fs_info = NULL; |
3548 | } | 3617 | } |
3549 | 3618 | ||
3550 | int shmem_fill_super(struct super_block *sb, void *data, int silent) | 3619 | static int shmem_fill_super(struct super_block *sb, struct fs_context *fc) |
3551 | { | 3620 | { |
3621 | struct shmem_options *ctx = fc->fs_private; | ||
3552 | struct inode *inode; | 3622 | struct inode *inode; |
3553 | struct shmem_sb_info *sbinfo; | 3623 | struct shmem_sb_info *sbinfo; |
3554 | int err = -ENOMEM; | 3624 | int err = -ENOMEM; |
@@ -3559,9 +3629,6 @@ int shmem_fill_super(struct super_block *sb, void *data, int silent) | |||
3559 | if (!sbinfo) | 3629 | if (!sbinfo) |
3560 | return -ENOMEM; | 3630 | return -ENOMEM; |
3561 | 3631 | ||
3562 | sbinfo->mode = 0777 | S_ISVTX; | ||
3563 | sbinfo->uid = current_fsuid(); | ||
3564 | sbinfo->gid = current_fsgid(); | ||
3565 | sb->s_fs_info = sbinfo; | 3632 | sb->s_fs_info = sbinfo; |
3566 | 3633 | ||
3567 | #ifdef CONFIG_TMPFS | 3634 | #ifdef CONFIG_TMPFS |
@@ -3571,12 +3638,10 @@ int shmem_fill_super(struct super_block *sb, void *data, int silent) | |||
3571 | * but the internal instance is left unlimited. | 3638 | * but the internal instance is left unlimited. |
3572 | */ | 3639 | */ |
3573 | if (!(sb->s_flags & SB_KERNMOUNT)) { | 3640 | if (!(sb->s_flags & SB_KERNMOUNT)) { |
3574 | sbinfo->max_blocks = shmem_default_max_blocks(); | 3641 | if (!(ctx->seen & SHMEM_SEEN_BLOCKS)) |
3575 | sbinfo->max_inodes = shmem_default_max_inodes(); | 3642 | ctx->blocks = shmem_default_max_blocks(); |
3576 | if (shmem_parse_options(data, sbinfo, false)) { | 3643 | if (!(ctx->seen & SHMEM_SEEN_INODES)) |
3577 | err = -EINVAL; | 3644 | ctx->inodes = shmem_default_max_inodes(); |
3578 | goto failed; | ||
3579 | } | ||
3580 | } else { | 3645 | } else { |
3581 | sb->s_flags |= SB_NOUSER; | 3646 | sb->s_flags |= SB_NOUSER; |
3582 | } | 3647 | } |
@@ -3585,11 +3650,18 @@ int shmem_fill_super(struct super_block *sb, void *data, int silent) | |||
3585 | #else | 3650 | #else |
3586 | sb->s_flags |= SB_NOUSER; | 3651 | sb->s_flags |= SB_NOUSER; |
3587 | #endif | 3652 | #endif |
3653 | sbinfo->max_blocks = ctx->blocks; | ||
3654 | sbinfo->free_inodes = sbinfo->max_inodes = ctx->inodes; | ||
3655 | sbinfo->uid = ctx->uid; | ||
3656 | sbinfo->gid = ctx->gid; | ||
3657 | sbinfo->mode = ctx->mode; | ||
3658 | sbinfo->huge = ctx->huge; | ||
3659 | sbinfo->mpol = ctx->mpol; | ||
3660 | ctx->mpol = NULL; | ||
3588 | 3661 | ||
3589 | spin_lock_init(&sbinfo->stat_lock); | 3662 | spin_lock_init(&sbinfo->stat_lock); |
3590 | if (percpu_counter_init(&sbinfo->used_blocks, 0, GFP_KERNEL)) | 3663 | if (percpu_counter_init(&sbinfo->used_blocks, 0, GFP_KERNEL)) |
3591 | goto failed; | 3664 | goto failed; |
3592 | sbinfo->free_inodes = sbinfo->max_inodes; | ||
3593 | spin_lock_init(&sbinfo->shrinklist_lock); | 3665 | spin_lock_init(&sbinfo->shrinklist_lock); |
3594 | INIT_LIST_HEAD(&sbinfo->shrinklist); | 3666 | INIT_LIST_HEAD(&sbinfo->shrinklist); |
3595 | 3667 | ||
@@ -3622,6 +3694,31 @@ failed: | |||
3622 | return err; | 3694 | return err; |
3623 | } | 3695 | } |
3624 | 3696 | ||
3697 | static int shmem_get_tree(struct fs_context *fc) | ||
3698 | { | ||
3699 | return get_tree_nodev(fc, shmem_fill_super); | ||
3700 | } | ||
3701 | |||
3702 | static 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 | |||
3712 | static 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 | |||
3625 | static struct kmem_cache *shmem_inode_cachep; | 3722 | static struct kmem_cache *shmem_inode_cachep; |
3626 | 3723 | ||
3627 | static struct inode *shmem_alloc_inode(struct super_block *sb) | 3724 | static struct inode *shmem_alloc_inode(struct super_block *sb) |
@@ -3738,7 +3835,6 @@ static const struct super_operations shmem_ops = { | |||
3738 | .destroy_inode = shmem_destroy_inode, | 3835 | .destroy_inode = shmem_destroy_inode, |
3739 | #ifdef CONFIG_TMPFS | 3836 | #ifdef CONFIG_TMPFS |
3740 | .statfs = shmem_statfs, | 3837 | .statfs = shmem_statfs, |
3741 | .remount_fs = shmem_remount_fs, | ||
3742 | .show_options = shmem_show_options, | 3838 | .show_options = shmem_show_options, |
3743 | #endif | 3839 | #endif |
3744 | .evict_inode = shmem_evict_inode, | 3840 | .evict_inode = shmem_evict_inode, |
@@ -3759,16 +3855,30 @@ static const struct vm_operations_struct shmem_vm_ops = { | |||
3759 | #endif | 3855 | #endif |
3760 | }; | 3856 | }; |
3761 | 3857 | ||
3762 | static struct dentry *shmem_mount(struct file_system_type *fs_type, | 3858 | int shmem_init_fs_context(struct fs_context *fc) |
3763 | int flags, const char *dev_name, void *data) | ||
3764 | { | 3859 | { |
3765 | 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; | ||
3766 | } | 3873 | } |
3767 | 3874 | ||
3768 | static struct file_system_type shmem_fs_type = { | 3875 | static struct file_system_type shmem_fs_type = { |
3769 | .owner = THIS_MODULE, | 3876 | .owner = THIS_MODULE, |
3770 | .name = "tmpfs", | 3877 | .name = "tmpfs", |
3771 | .mount = shmem_mount, | 3878 | .init_fs_context = shmem_init_fs_context, |
3879 | #ifdef CONFIG_TMPFS | ||
3880 | .parameters = &shmem_fs_parameters, | ||
3881 | #endif | ||
3772 | .kill_sb = kill_litter_super, | 3882 | .kill_sb = kill_litter_super, |
3773 | .fs_flags = FS_USERNS_MOUNT, | 3883 | .fs_flags = FS_USERNS_MOUNT, |
3774 | }; | 3884 | }; |
@@ -3912,7 +4022,8 @@ bool shmem_huge_enabled(struct vm_area_struct *vma) | |||
3912 | 4022 | ||
3913 | static struct file_system_type shmem_fs_type = { | 4023 | static struct file_system_type shmem_fs_type = { |
3914 | .name = "tmpfs", | 4024 | .name = "tmpfs", |
3915 | .mount = ramfs_mount, | 4025 | .init_fs_context = ramfs_init_fs_context, |
4026 | .parameters = &ramfs_fs_parameters, | ||
3916 | .kill_sb = kill_litter_super, | 4027 | .kill_sb = kill_litter_super, |
3917 | .fs_flags = FS_USERNS_MOUNT, | 4028 | .fs_flags = FS_USERNS_MOUNT, |
3918 | }; | 4029 | }; |