Skip to content

Commit 626c392

Browse files
author
Al Viro
committed
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>
1 parent e04dc42 commit 626c392

File tree

1 file changed

+116
-67
lines changed

1 file changed

+116
-67
lines changed

mm/shmem.c

Lines changed: 116 additions & 67 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@
3737
#include <linux/khugepaged.h>
3838
#include <linux/hugetlb.h>
3939
#include <linux/frontswap.h>
40+
#include <linux/fs_parser.h>
4041

4142
#include <asm/tlbflush.h> /* for arch/microblaze update_mmu_cache() */
4243

@@ -3363,90 +3364,129 @@ static const struct export_operations shmem_export_ops = {
33633364
.fh_to_dentry = shmem_fh_to_dentry,
33643365
};
33653366

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)
33673406
{
3407+
struct fs_context *fc = NULL;
3408+
struct fs_parse_result result;
3409+
unsigned long long size;
33683410
char *rest;
3369-
uid_t uid;
3370-
gid_t gid;
3411+
int opt;
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+
}
33713420

3372-
if (!strcmp(opt, "size")) {
3373-
unsigned long long size;
3374-
size = memparse(value,&rest);
3421+
switch (opt) {
3422+
case Opt_size:
3423+
size = memparse(param->string, &rest);
33753424
if (*rest == '%') {
33763425
size <<= PAGE_SHIFT;
33773426
size *= totalram_pages();
33783427
do_div(size, 100);
33793428
rest++;
33803429
}
33813430
if (*rest)
3382-
goto bad_val;
3431+
goto bad_value;
33833432
ctx->blocks = DIV_ROUND_UP(size, PAGE_SIZE);
33843433
ctx->seen |= SHMEM_SEEN_BLOCKS;
3385-
} else if (!strcmp(opt, "nr_blocks")) {
3386-
ctx->blocks = memparse(value, &rest);
3434+
break;
3435+
case Opt_nr_blocks:
3436+
ctx->blocks = memparse(param->string, &rest);
33873437
if (*rest)
3388-
goto bad_val;
3438+
goto bad_value;
33893439
ctx->seen |= SHMEM_SEEN_BLOCKS;
3390-
} else if (!strcmp(opt, "nr_inodes")) {
3391-
ctx->inodes = memparse(value, &rest);
3440+
break;
3441+
case Opt_nr_inodes:
3442+
ctx->inodes = memparse(param->string, &rest);
33923443
if (*rest)
3393-
goto bad_val;
3444+
goto bad_value;
33943445
ctx->seen |= SHMEM_SEEN_INODES;
3395-
} else if (!strcmp(opt, "mode")) {
3396-
ctx->mode = simple_strtoul(value, &rest, 8) & 07777;
3397-
if (*rest)
3398-
goto bad_val;
3399-
} else if (!strcmp(opt, "uid")) {
3400-
uid = simple_strtoul(value, &rest, 0);
3401-
if (*rest)
3402-
goto bad_val;
3403-
ctx->uid = make_kuid(current_user_ns(), uid);
3446+
break;
3447+
case Opt_mode:
3448+
ctx->mode = result.uint_32 & 07777;
3449+
break;
3450+
case Opt_uid:
3451+
ctx->uid = make_kuid(current_user_ns(), result.uint_32);
34043452
if (!uid_valid(ctx->uid))
3405-
goto bad_val;
3406-
} else if (!strcmp(opt, "gid")) {
3407-
gid = simple_strtoul(value, &rest, 0);
3408-
if (*rest)
3409-
goto bad_val;
3410-
ctx->gid = make_kgid(current_user_ns(), gid);
3453+
goto bad_value;
3454+
break;
3455+
case Opt_gid:
3456+
ctx->gid = make_kgid(current_user_ns(), result.uint_32);
34113457
if (!gid_valid(ctx->gid))
3412-
goto bad_val;
3413-
#ifdef CONFIG_TRANSPARENT_HUGE_PAGECACHE
3414-
} else if (!strcmp(opt, "huge")) {
3415-
int huge;
3416-
huge = shmem_parse_huge(value);
3417-
if (huge < 0)
3418-
goto bad_val;
3419-
if (!has_transparent_hugepage() &&
3420-
huge != SHMEM_HUGE_NEVER)
3421-
goto bad_val;
3422-
ctx->huge = huge;
3458+
goto bad_value;
3459+
break;
3460+
case Opt_huge:
3461+
ctx->huge = result.uint_32;
3462+
if (ctx->huge != SHMEM_HUGE_NEVER &&
3463+
!(IS_ENABLED(CONFIG_TRANSPARENT_HUGE_PAGECACHE) &&
3464+
has_transparent_hugepage()))
3465+
goto unsupported_parameter;
34233466
ctx->seen |= SHMEM_SEEN_HUGE;
3424-
#endif
3425-
#ifdef CONFIG_NUMA
3426-
} else if (!strcmp(opt, "mpol")) {
3427-
mpol_put(ctx->mpol);
3428-
ctx->mpol = NULL;
3429-
if (mpol_parse_str(value, &ctx->mpol))
3430-
goto bad_val;
3431-
#endif
3432-
} else {
3433-
pr_err("tmpfs: Bad mount option %s\n", opt);
3434-
return -EINVAL;
3467+
break;
3468+
case Opt_mpol:
3469+
if (IS_ENABLED(CONFIG_NUMA)) {
3470+
mpol_put(ctx->mpol);
3471+
ctx->mpol = NULL;
3472+
if (mpol_parse_str(param->string, &ctx->mpol))
3473+
goto bad_value;
3474+
break;
3475+
}
3476+
goto unsupported_parameter;
34353477
}
34363478
return 0;
34373479

3438-
bad_val:
3439-
pr_err("tmpfs: Bad value '%s' for mount option '%s'\n",
3440-
value, opt);
3441-
return -EINVAL;
3480+
unsupported_parameter:
3481+
return invalf(fc, "tmpfs: Unsupported parameter '%s'", param->key);
3482+
bad_value:
3483+
return invalf(fc, "tmpfs: Bad value for '%s'", param->key);
34423484
}
34433485

34443486
static int shmem_parse_options(char *options, struct shmem_options *ctx)
34453487
{
3446-
char *this_char, *value;
3447-
34483488
while (options != NULL) {
3449-
this_char = options;
3489+
char *this_char = options;
34503490
for (;;) {
34513491
/*
34523492
* NUL-terminate this option: unfortunately,
@@ -3462,17 +3502,26 @@ static int shmem_parse_options(char *options, struct shmem_options *ctx)
34623502
break;
34633503
}
34643504
}
3465-
if (!*this_char)
3466-
continue;
3467-
if ((value = strchr(this_char,'=')) != NULL) {
3468-
*value++ = 0;
3469-
} else {
3470-
pr_err("tmpfs: No value for mount option '%s'\n",
3471-
this_char);
3472-
goto error;
3505+
if (*this_char) {
3506+
char *value = strchr(this_char,'=');
3507+
struct fs_parameter param = {
3508+
.key = this_char,
3509+
.type = fs_value_is_string,
3510+
};
3511+
int err;
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, &param);
3521+
kfree(param.string);
3522+
if (err)
3523+
goto error;
34733524
}
3474-
if (shmem_parse_one(ctx, this_char, value) < 0)
3475-
goto error;
34763525
}
34773526
return 0;
34783527

0 commit comments

Comments
 (0)