diff options
author | Al Viro <viro@zeniv.linux.org.uk> | 2019-09-08 20:28:06 -0400 |
---|---|---|
committer | Al Viro <viro@zeniv.linux.org.uk> | 2019-09-12 21:01:32 -0400 |
commit | 626c3920aeb4575f53c96b0d4ad4e651a21cbb66 (patch) | |
tree | b49fe10845e92e8515f9c2a1f8599ac9f5757e2d | |
parent | e04dc423ae2c0fc862fef6b43ed9083226375e98 (diff) |
shmem_parse_one(): switch to use of fs_parse()
This thing will eventually become our ->parse_param(), while
shmem_parse_options() - ->parse_monolithic(). At that point
shmem_parse_options() will start calling vfs_parse_fs_string(),
rather than calling shmem_parse_one() directly.
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
-rw-r--r-- | mm/shmem.c | 183 |
1 files changed, 116 insertions, 67 deletions
diff --git a/mm/shmem.c b/mm/shmem.c index b392a8263329..6a41595dd1b3 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 | ||
@@ -3363,15 +3364,63 @@ static const struct export_operations shmem_export_ops = { | |||
3363 | .fh_to_dentry = shmem_fh_to_dentry, | 3364 | .fh_to_dentry = shmem_fh_to_dentry, |
3364 | }; | 3365 | }; |
3365 | 3366 | ||
3366 | static int shmem_parse_one(struct shmem_options *ctx, char *opt, char *value) | 3367 | enum shmem_param { |
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 shmem_options *ctx, | ||
3405 | struct fs_parameter *param) | ||
3367 | { | 3406 | { |
3407 | struct fs_context *fc = NULL; | ||
3408 | struct fs_parse_result result; | ||
3409 | unsigned long long size; | ||
3368 | char *rest; | 3410 | char *rest; |
3369 | uid_t uid; | 3411 | int opt; |
3370 | gid_t gid; | 3412 | |
3413 | opt = fs_parse(fc, &shmem_fs_parameters, param, &result); | ||
3414 | if (opt < 0) { | ||
3415 | if (opt == -ENOPARAM) | ||
3416 | return invalf(fc, "tmpfs: Unknown parameter '%s'", | ||
3417 | param->key); | ||
3418 | return opt; | ||
3419 | } | ||
3371 | 3420 | ||
3372 | if (!strcmp(opt, "size")) { | 3421 | switch (opt) { |
3373 | unsigned long long size; | 3422 | case Opt_size: |
3374 | size = memparse(value,&rest); | 3423 | size = memparse(param->string, &rest); |
3375 | if (*rest == '%') { | 3424 | if (*rest == '%') { |
3376 | size <<= PAGE_SHIFT; | 3425 | size <<= PAGE_SHIFT; |
3377 | size *= totalram_pages(); | 3426 | size *= totalram_pages(); |
@@ -3379,74 +3428,65 @@ static int shmem_parse_one(struct shmem_options *ctx, char *opt, char *value) | |||
3379 | rest++; | 3428 | rest++; |
3380 | } | 3429 | } |
3381 | if (*rest) | 3430 | if (*rest) |
3382 | goto bad_val; | 3431 | goto bad_value; |
3383 | ctx->blocks = DIV_ROUND_UP(size, PAGE_SIZE); | 3432 | ctx->blocks = DIV_ROUND_UP(size, PAGE_SIZE); |
3384 | ctx->seen |= SHMEM_SEEN_BLOCKS; | 3433 | ctx->seen |= SHMEM_SEEN_BLOCKS; |
3385 | } else if (!strcmp(opt, "nr_blocks")) { | 3434 | break; |
3386 | ctx->blocks = memparse(value, &rest); | 3435 | case Opt_nr_blocks: |
3436 | ctx->blocks = memparse(param->string, &rest); | ||
3387 | if (*rest) | 3437 | if (*rest) |
3388 | goto bad_val; | 3438 | goto bad_value; |
3389 | ctx->seen |= SHMEM_SEEN_BLOCKS; | 3439 | ctx->seen |= SHMEM_SEEN_BLOCKS; |
3390 | } else if (!strcmp(opt, "nr_inodes")) { | 3440 | break; |
3391 | ctx->inodes = memparse(value, &rest); | 3441 | case Opt_nr_inodes: |
3442 | ctx->inodes = memparse(param->string, &rest); | ||
3392 | if (*rest) | 3443 | if (*rest) |
3393 | goto bad_val; | 3444 | goto bad_value; |
3394 | ctx->seen |= SHMEM_SEEN_INODES; | 3445 | ctx->seen |= SHMEM_SEEN_INODES; |
3395 | } else if (!strcmp(opt, "mode")) { | 3446 | break; |
3396 | ctx->mode = simple_strtoul(value, &rest, 8) & 07777; | 3447 | case Opt_mode: |
3397 | if (*rest) | 3448 | ctx->mode = result.uint_32 & 07777; |
3398 | goto bad_val; | 3449 | break; |
3399 | } else if (!strcmp(opt, "uid")) { | 3450 | case Opt_uid: |
3400 | uid = simple_strtoul(value, &rest, 0); | 3451 | ctx->uid = make_kuid(current_user_ns(), result.uint_32); |
3401 | if (*rest) | ||
3402 | goto bad_val; | ||
3403 | ctx->uid = make_kuid(current_user_ns(), uid); | ||
3404 | if (!uid_valid(ctx->uid)) | 3452 | if (!uid_valid(ctx->uid)) |
3405 | goto bad_val; | 3453 | goto bad_value; |
3406 | } else if (!strcmp(opt, "gid")) { | 3454 | break; |
3407 | gid = simple_strtoul(value, &rest, 0); | 3455 | case Opt_gid: |
3408 | if (*rest) | 3456 | ctx->gid = make_kgid(current_user_ns(), result.uint_32); |
3409 | goto bad_val; | ||
3410 | ctx->gid = make_kgid(current_user_ns(), gid); | ||
3411 | if (!gid_valid(ctx->gid)) | 3457 | if (!gid_valid(ctx->gid)) |
3412 | goto bad_val; | 3458 | goto bad_value; |
3413 | #ifdef CONFIG_TRANSPARENT_HUGE_PAGECACHE | 3459 | break; |
3414 | } else if (!strcmp(opt, "huge")) { | 3460 | case Opt_huge: |
3415 | int huge; | 3461 | ctx->huge = result.uint_32; |
3416 | huge = shmem_parse_huge(value); | 3462 | if (ctx->huge != SHMEM_HUGE_NEVER && |
3417 | if (huge < 0) | 3463 | !(IS_ENABLED(CONFIG_TRANSPARENT_HUGE_PAGECACHE) && |
3418 | goto bad_val; | 3464 | has_transparent_hugepage())) |
3419 | if (!has_transparent_hugepage() && | 3465 | goto unsupported_parameter; |
3420 | huge != SHMEM_HUGE_NEVER) | ||
3421 | goto bad_val; | ||
3422 | ctx->huge = huge; | ||
3423 | ctx->seen |= SHMEM_SEEN_HUGE; | 3466 | ctx->seen |= SHMEM_SEEN_HUGE; |
3424 | #endif | 3467 | break; |
3425 | #ifdef CONFIG_NUMA | 3468 | case Opt_mpol: |
3426 | } else if (!strcmp(opt, "mpol")) { | 3469 | if (IS_ENABLED(CONFIG_NUMA)) { |
3427 | mpol_put(ctx->mpol); | 3470 | mpol_put(ctx->mpol); |
3428 | ctx->mpol = NULL; | 3471 | ctx->mpol = NULL; |
3429 | if (mpol_parse_str(value, &ctx->mpol)) | 3472 | if (mpol_parse_str(param->string, &ctx->mpol)) |
3430 | goto bad_val; | 3473 | goto bad_value; |
3431 | #endif | 3474 | break; |
3432 | } else { | 3475 | } |
3433 | pr_err("tmpfs: Bad mount option %s\n", opt); | 3476 | goto unsupported_parameter; |
3434 | return -EINVAL; | ||
3435 | } | 3477 | } |
3436 | return 0; | 3478 | return 0; |
3437 | 3479 | ||
3438 | bad_val: | 3480 | unsupported_parameter: |
3439 | pr_err("tmpfs: Bad value '%s' for mount option '%s'\n", | 3481 | return invalf(fc, "tmpfs: Unsupported parameter '%s'", param->key); |
3440 | value, opt); | 3482 | bad_value: |
3441 | return -EINVAL; | 3483 | return invalf(fc, "tmpfs: Bad value for '%s'", param->key); |
3442 | } | 3484 | } |
3443 | 3485 | ||
3444 | static int shmem_parse_options(char *options, struct shmem_options *ctx) | 3486 | static int shmem_parse_options(char *options, struct shmem_options *ctx) |
3445 | { | 3487 | { |
3446 | char *this_char, *value; | ||
3447 | |||
3448 | while (options != NULL) { | 3488 | while (options != NULL) { |
3449 | this_char = options; | 3489 | char *this_char = options; |
3450 | for (;;) { | 3490 | for (;;) { |
3451 | /* | 3491 | /* |
3452 | * NUL-terminate this option: unfortunately, | 3492 | * NUL-terminate this option: unfortunately, |
@@ -3462,17 +3502,26 @@ static int shmem_parse_options(char *options, struct shmem_options *ctx) | |||
3462 | break; | 3502 | break; |
3463 | } | 3503 | } |
3464 | } | 3504 | } |
3465 | if (!*this_char) | 3505 | if (*this_char) { |
3466 | continue; | 3506 | char *value = strchr(this_char,'='); |
3467 | if ((value = strchr(this_char,'=')) != NULL) { | 3507 | struct fs_parameter param = { |
3468 | *value++ = 0; | 3508 | .key = this_char, |
3469 | } else { | 3509 | .type = fs_value_is_string, |
3470 | pr_err("tmpfs: No value for mount option '%s'\n", | 3510 | }; |
3471 | this_char); | 3511 | int err; |
3472 | goto error; | 3512 | |
3513 | if (value) { | ||
3514 | *value++ = '\0'; | ||
3515 | param.size = strlen(value); | ||
3516 | param.string = kstrdup(value, GFP_KERNEL); | ||
3517 | if (!param.string) | ||
3518 | goto error; | ||
3519 | } | ||
3520 | err = shmem_parse_one(ctx, ¶m); | ||
3521 | kfree(param.string); | ||
3522 | if (err) | ||
3523 | goto error; | ||
3473 | } | 3524 | } |
3474 | if (shmem_parse_one(ctx, this_char, value) < 0) | ||
3475 | goto error; | ||
3476 | } | 3525 | } |
3477 | return 0; | 3526 | return 0; |
3478 | 3527 | ||