1
0
Fork 0

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>
alistair/sunxi64-5.4-dsi
Al Viro 2019-09-08 20:28:06 -04:00
parent e04dc423ae
commit 626c3920ae
1 changed files with 118 additions and 69 deletions

View File

@ -37,6 +37,7 @@
#include <linux/khugepaged.h> #include <linux/khugepaged.h>
#include <linux/hugetlb.h> #include <linux/hugetlb.h>
#include <linux/frontswap.h> #include <linux/frontswap.h>
#include <linux/fs_parser.h>
#include <asm/tlbflush.h> /* for arch/microblaze update_mmu_cache() */ #include <asm/tlbflush.h> /* for arch/microblaze update_mmu_cache() */
@ -3363,15 +3364,63 @@ static const struct export_operations shmem_export_ops = {
.fh_to_dentry = shmem_fh_to_dentry, .fh_to_dentry = shmem_fh_to_dentry,
}; };
static int shmem_parse_one(struct shmem_options *ctx, char *opt, char *value) enum shmem_param {
{ Opt_gid,
char *rest; Opt_huge,
uid_t uid; Opt_mode,
gid_t gid; Opt_mpol,
Opt_nr_blocks,
Opt_nr_inodes,
Opt_size,
Opt_uid,
};
if (!strcmp(opt, "size")) { static const struct fs_parameter_spec shmem_param_specs[] = {
unsigned long long size; fsparam_u32 ("gid", Opt_gid),
size = memparse(value,&rest); fsparam_enum ("huge", Opt_huge),
fsparam_u32oct("mode", Opt_mode),
fsparam_string("mpol", Opt_mpol),
fsparam_string("nr_blocks", Opt_nr_blocks),
fsparam_string("nr_inodes", Opt_nr_inodes),
fsparam_string("size", Opt_size),
fsparam_u32 ("uid", Opt_uid),
{}
};
static const struct fs_parameter_enum shmem_param_enums[] = {
{ Opt_huge, "never", SHMEM_HUGE_NEVER },
{ Opt_huge, "always", SHMEM_HUGE_ALWAYS },
{ Opt_huge, "within_size", SHMEM_HUGE_WITHIN_SIZE },
{ Opt_huge, "advise", SHMEM_HUGE_ADVISE },
{}
};
const struct fs_parameter_description shmem_fs_parameters = {
.name = "tmpfs",
.specs = shmem_param_specs,
.enums = shmem_param_enums,
};
static int shmem_parse_one(struct shmem_options *ctx,
struct fs_parameter *param)
{
struct fs_context *fc = NULL;
struct fs_parse_result result;
unsigned long long size;
char *rest;
int opt;
opt = fs_parse(fc, &shmem_fs_parameters, param, &result);
if (opt < 0) {
if (opt == -ENOPARAM)
return invalf(fc, "tmpfs: Unknown parameter '%s'",
param->key);
return opt;
}
switch (opt) {
case Opt_size:
size = memparse(param->string, &rest);
if (*rest == '%') { if (*rest == '%') {
size <<= PAGE_SHIFT; size <<= PAGE_SHIFT;
size *= totalram_pages(); size *= totalram_pages();
@ -3379,74 +3428,65 @@ static int shmem_parse_one(struct shmem_options *ctx, char *opt, char *value)
rest++; rest++;
} }
if (*rest) if (*rest)
goto bad_val; goto bad_value;
ctx->blocks = DIV_ROUND_UP(size, PAGE_SIZE); ctx->blocks = DIV_ROUND_UP(size, PAGE_SIZE);
ctx->seen |= SHMEM_SEEN_BLOCKS; ctx->seen |= SHMEM_SEEN_BLOCKS;
} else if (!strcmp(opt, "nr_blocks")) { break;
ctx->blocks = memparse(value, &rest); case Opt_nr_blocks:
ctx->blocks = memparse(param->string, &rest);
if (*rest) if (*rest)
goto bad_val; goto bad_value;
ctx->seen |= SHMEM_SEEN_BLOCKS; ctx->seen |= SHMEM_SEEN_BLOCKS;
} else if (!strcmp(opt, "nr_inodes")) { break;
ctx->inodes = memparse(value, &rest); case Opt_nr_inodes:
ctx->inodes = memparse(param->string, &rest);
if (*rest) if (*rest)
goto bad_val; goto bad_value;
ctx->seen |= SHMEM_SEEN_INODES; ctx->seen |= SHMEM_SEEN_INODES;
} else if (!strcmp(opt, "mode")) { break;
ctx->mode = simple_strtoul(value, &rest, 8) & 07777; case Opt_mode:
if (*rest) ctx->mode = result.uint_32 & 07777;
goto bad_val; break;
} else if (!strcmp(opt, "uid")) { case Opt_uid:
uid = simple_strtoul(value, &rest, 0); ctx->uid = make_kuid(current_user_ns(), result.uint_32);
if (*rest)
goto bad_val;
ctx->uid = make_kuid(current_user_ns(), uid);
if (!uid_valid(ctx->uid)) if (!uid_valid(ctx->uid))
goto bad_val; goto bad_value;
} else if (!strcmp(opt, "gid")) { break;
gid = simple_strtoul(value, &rest, 0); case Opt_gid:
if (*rest) ctx->gid = make_kgid(current_user_ns(), result.uint_32);
goto bad_val;
ctx->gid = make_kgid(current_user_ns(), gid);
if (!gid_valid(ctx->gid)) if (!gid_valid(ctx->gid))
goto bad_val; goto bad_value;
#ifdef CONFIG_TRANSPARENT_HUGE_PAGECACHE break;
} else if (!strcmp(opt, "huge")) { case Opt_huge:
int huge; ctx->huge = result.uint_32;
huge = shmem_parse_huge(value); if (ctx->huge != SHMEM_HUGE_NEVER &&
if (huge < 0) !(IS_ENABLED(CONFIG_TRANSPARENT_HUGE_PAGECACHE) &&
goto bad_val; has_transparent_hugepage()))
if (!has_transparent_hugepage() && goto unsupported_parameter;
huge != SHMEM_HUGE_NEVER)
goto bad_val;
ctx->huge = huge;
ctx->seen |= SHMEM_SEEN_HUGE; ctx->seen |= SHMEM_SEEN_HUGE;
#endif break;
#ifdef CONFIG_NUMA case Opt_mpol:
} else if (!strcmp(opt, "mpol")) { if (IS_ENABLED(CONFIG_NUMA)) {
mpol_put(ctx->mpol); mpol_put(ctx->mpol);
ctx->mpol = NULL; ctx->mpol = NULL;
if (mpol_parse_str(value, &ctx->mpol)) if (mpol_parse_str(param->string, &ctx->mpol))
goto bad_val; goto bad_value;
#endif break;
} else { }
pr_err("tmpfs: Bad mount option %s\n", opt); goto unsupported_parameter;
return -EINVAL;
} }
return 0; return 0;
bad_val: unsupported_parameter:
pr_err("tmpfs: Bad value '%s' for mount option '%s'\n", return invalf(fc, "tmpfs: Unsupported parameter '%s'", param->key);
value, opt); bad_value:
return -EINVAL; return invalf(fc, "tmpfs: Bad value for '%s'", param->key);
} }
static int shmem_parse_options(char *options, struct shmem_options *ctx) static int shmem_parse_options(char *options, struct shmem_options *ctx)
{ {
char *this_char, *value;
while (options != NULL) { while (options != NULL) {
this_char = options; char *this_char = options;
for (;;) { for (;;) {
/* /*
* NUL-terminate this option: unfortunately, * NUL-terminate this option: unfortunately,
@ -3462,17 +3502,26 @@ static int shmem_parse_options(char *options, struct shmem_options *ctx)
break; break;
} }
} }
if (!*this_char) if (*this_char) {
continue; char *value = strchr(this_char,'=');
if ((value = strchr(this_char,'=')) != NULL) { struct fs_parameter param = {
*value++ = 0; .key = this_char,
} else { .type = fs_value_is_string,
pr_err("tmpfs: No value for mount option '%s'\n", };
this_char); int err;
goto error;
if (value) {
*value++ = '\0';
param.size = strlen(value);
param.string = kstrdup(value, GFP_KERNEL);
if (!param.string)
goto error;
}
err = shmem_parse_one(ctx, &param);
kfree(param.string);
if (err)
goto error;
} }
if (shmem_parse_one(ctx, this_char, value) < 0)
goto error;
} }
return 0; return 0;