From 0f89589a8c6f1033cb847a606517998efb0da8ee Mon Sep 17 00:00:00 2001 From: Al Viro Date: Tue, 17 Dec 2019 14:15:04 -0500 Subject: Pass consistent param->type to fs_parse() As it is, vfs_parse_fs_string() makes "foo" and "foo=" indistinguishable; both get fs_value_is_string for ->type and NULL for ->string. To make it even more unpleasant, that combination is impossible to produce with fsconfig(). Much saner rules would be "foo" => fs_value_is_flag, NULL "foo=" => fs_value_is_string, "" "foo=bar" => fs_value_is_string, "bar" All cases are distinguishable, all results are expressable by fsconfig(), ->has_value checks are much simpler that way (to the point of the field being useless) and quite a few regressions go away (gfs2 has no business accepting -o nodebug=, for example). Partially based upon patches from Miklos. Signed-off-by: Al Viro --- fs/fs_parser.c | 23 +++++++++++------------ 1 file changed, 11 insertions(+), 12 deletions(-) (limited to 'fs/fs_parser.c') diff --git a/fs/fs_parser.c b/fs/fs_parser.c index d1930adce68d..07ae041b83a8 100644 --- a/fs/fs_parser.c +++ b/fs/fs_parser.c @@ -85,7 +85,6 @@ int fs_parse(struct fs_context *fc, const struct fs_parameter_enum *e; int ret = -ENOPARAM, b; - result->has_value = !!param->string; result->negated = false; result->uint_64 = 0; @@ -95,7 +94,7 @@ int fs_parse(struct fs_context *fc, * "xxx" takes the "no"-form negative - but only if there * wasn't an value. */ - if (result->has_value) + if (param->type != fs_value_is_flag) goto unknown_parameter; if (param->key[0] != 'n' || param->key[1] != 'o' || !param->key[2]) goto unknown_parameter; @@ -127,14 +126,18 @@ int fs_parse(struct fs_context *fc, case fs_param_is_u64: case fs_param_is_enum: case fs_param_is_string: - if (param->type != fs_value_is_string) - goto bad_value; - if (!result->has_value) { + if (param->type == fs_value_is_string) { + if (p->flags & fs_param_v_optional) + break; + if (!*param->string) + goto bad_value; + break; + } + if (param->type == fs_value_is_flag) { if (p->flags & fs_param_v_optional) goto okay; - goto bad_value; } - /* Fall through */ + goto bad_value; default: break; } @@ -144,8 +147,7 @@ int fs_parse(struct fs_context *fc, */ switch (p->type) { case fs_param_is_flag: - if (param->type != fs_value_is_flag && - (param->type != fs_value_is_string || result->has_value)) + if (param->type != fs_value_is_flag) return invalf(fc, "%s: Unexpected value for '%s'", desc->name, param->key); result->boolean = true; @@ -206,9 +208,6 @@ int fs_parse(struct fs_context *fc, case fs_param_is_fd: { switch (param->type) { case fs_value_is_string: - if (!result->has_value) - goto bad_value; - ret = kstrtouint(param->string, 0, &result->uint_32); break; case fs_value_is_file: -- cgit v1.2.1 From 2710c957a8ef4fb00f21acb306e3bd6bcf80c81f Mon Sep 17 00:00:00 2001 From: Al Viro Date: Fri, 6 Sep 2019 22:12:08 -0400 Subject: fs_parse: get rid of ->enums Don't do a single array; attach them to fsparam_enum() entry instead. And don't bother trying to embed the names into those - it actually loses memory, with no real speedup worth mentioning. Simplifies validation as well. Signed-off-by: Al Viro --- fs/fs_parser.c | 72 ++++++++-------------------------------------------------- 1 file changed, 9 insertions(+), 63 deletions(-) (limited to 'fs/fs_parser.c') diff --git a/fs/fs_parser.c b/fs/fs_parser.c index 07ae041b83a8..34275191697f 100644 --- a/fs/fs_parser.c +++ b/fs/fs_parser.c @@ -189,9 +189,8 @@ int fs_parse(struct fs_context *fc, goto maybe_okay; case fs_param_is_enum: - for (e = desc->enums; e->name[0]; e++) { - if (e->opt == p->opt && - strcmp(e->name, param->string) == 0) { + for (e = p->data; e->name; e++) { + if (strcmp(e->name, param->string) == 0) { result->uint_32 = e->value; goto okay; } @@ -359,10 +358,8 @@ bool validate_constant_table(const struct constant_table *tbl, size_t tbl_size, bool fs_validate_description(const struct fs_parameter_description *desc) { const struct fs_parameter_spec *param, *p2; - const struct fs_parameter_enum *e; const char *name = desc->name; - unsigned int nr_params = 0; - bool good = true, enums = false; + bool good = true; pr_notice("*** VALIDATE %s ***\n", name); @@ -383,7 +380,12 @@ bool fs_validate_description(const struct fs_parameter_description *desc) name, param->name, t); good = false; } else if (t == fs_param_is_enum) { - enums = true; + const struct fs_parameter_enum *e = param->data; + if (!e || !e->name) { + pr_err("VALIDATE %s: PARAM[%s] enum with no values\n", + name, param->name); + good = false; + } } /* Check for duplicate parameter names */ @@ -395,63 +397,7 @@ bool fs_validate_description(const struct fs_parameter_description *desc) } } } - - nr_params = param - desc->specs; - } - - if (desc->enums) { - if (!nr_params) { - pr_err("VALIDATE %s: Enum table but no parameters\n", - name); - good = false; - goto no_enums; - } - if (!enums) { - pr_err("VALIDATE %s: Enum table but no enum-type values\n", - name); - good = false; - goto no_enums; - } - - for (e = desc->enums; e->name[0]; e++) { - /* Check that all entries in the enum table have at - * least one parameter that uses them. - */ - for (param = desc->specs; param->name; param++) { - if (param->opt == e->opt && - param->type != fs_param_is_enum) { - pr_err("VALIDATE %s: e[%tu] enum val for %s\n", - name, e - desc->enums, param->name); - good = false; - } - } - } - - /* Check that all enum-type parameters have at least one enum - * value in the enum table. - */ - for (param = desc->specs; param->name; param++) { - if (param->type != fs_param_is_enum) - continue; - for (e = desc->enums; e->name[0]; e++) - if (e->opt == param->opt) - break; - if (!e->name[0]) { - pr_err("VALIDATE %s: PARAM[%s] enum with no values\n", - name, param->name); - good = false; - } - } - } else { - if (enums) { - pr_err("VALIDATE %s: enum-type values, but no enum table\n", - name); - good = false; - goto no_enums; - } } - -no_enums: return good; } #endif /* CONFIG_VALIDATE_FS_PARSER */ -- cgit v1.2.1 From 5eede625297f4d21dc12ea7a7418fd21672f131d Mon Sep 17 00:00:00 2001 From: Al Viro Date: Mon, 16 Dec 2019 13:33:32 -0500 Subject: fold struct fs_parameter_enum into struct constant_table no real difference now Signed-off-by: Al Viro --- fs/fs_parser.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'fs/fs_parser.c') diff --git a/fs/fs_parser.c b/fs/fs_parser.c index 34275191697f..d032ac4a758d 100644 --- a/fs/fs_parser.c +++ b/fs/fs_parser.c @@ -82,7 +82,7 @@ int fs_parse(struct fs_context *fc, struct fs_parse_result *result) { const struct fs_parameter_spec *p; - const struct fs_parameter_enum *e; + const struct constant_table *e; int ret = -ENOPARAM, b; result->negated = false; @@ -380,7 +380,7 @@ bool fs_validate_description(const struct fs_parameter_description *desc) name, param->name, t); good = false; } else if (t == fs_param_is_enum) { - const struct fs_parameter_enum *e = param->data; + const struct constant_table *e = param->data; if (!e || !e->name) { pr_err("VALIDATE %s: PARAM[%s] enum with no values\n", name, param->name); -- cgit v1.2.1 From 34264ae3fa22429ec4fd9151602342d1f21486eb Mon Sep 17 00:00:00 2001 From: Al Viro Date: Mon, 16 Dec 2019 13:45:41 -0500 Subject: don't bother with explicit length argument for __lookup_constant() Have the arrays of constant_table self-terminated (by NULL ->name in the final entry). Simplifies lookup_constant() and allows to reuse the search for enum params as well. Signed-off-by: Al Viro --- fs/fs_parser.c | 33 ++++++++++++++++++--------------- 1 file changed, 18 insertions(+), 15 deletions(-) (limited to 'fs/fs_parser.c') diff --git a/fs/fs_parser.c b/fs/fs_parser.c index d032ac4a758d..065ce6c22587 100644 --- a/fs/fs_parser.c +++ b/fs/fs_parser.c @@ -20,27 +20,31 @@ static const struct constant_table bool_names[] = { { "no", false }, { "true", true }, { "yes", true }, + { }, }; +static const struct constant_table * +__lookup_constant(const struct constant_table *tbl, const char *name) +{ + for ( ; tbl->name; tbl++) + if (strcmp(name, tbl->name) == 0) + return tbl; + return NULL; +} + /** * lookup_constant - Look up a constant by name in an ordered table * @tbl: The table of constants to search. - * @tbl_size: The size of the table. * @name: The name to look up. * @not_found: The value to return if the name is not found. */ -int __lookup_constant(const struct constant_table *tbl, size_t tbl_size, - const char *name, int not_found) +int lookup_constant(const struct constant_table *tbl, const char *name, int not_found) { - unsigned int i; + const struct constant_table *p = __lookup_constant(tbl, name); - for (i = 0; i < tbl_size; i++) - if (strcmp(name, tbl[i].name) == 0) - return tbl[i].value; - - return not_found; + return p ? p->value : not_found; } -EXPORT_SYMBOL(__lookup_constant); +EXPORT_SYMBOL(lookup_constant); static const struct fs_parameter_spec *fs_lookup_key( const struct fs_parameter_description *desc, @@ -189,11 +193,10 @@ int fs_parse(struct fs_context *fc, goto maybe_okay; case fs_param_is_enum: - for (e = p->data; e->name; e++) { - if (strcmp(e->name, param->string) == 0) { - result->uint_32 = e->value; - goto okay; - } + e = __lookup_constant(p->data, param->string); + if (e) { + result->uint_32 = e->value; + goto okay; } goto bad_value; -- cgit v1.2.1 From aa1918f9491442a007a0cbe41a31539233209777 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Tue, 17 Dec 2019 20:09:08 -0500 Subject: get rid of fs_value_is_filename_empty Its behaviour is identical to that of fs_value_is_filename. It makes no sense, anyway - LOOKUP_EMPTY affects nothing whatsoever once the pathname has been imported from userland. And both fs_value_is_filename and fs_value_is_filename_empty carry an already imported pathname. Signed-off-by: Al Viro --- fs/fs_parser.c | 3 --- 1 file changed, 3 deletions(-) (limited to 'fs/fs_parser.c') diff --git a/fs/fs_parser.c b/fs/fs_parser.c index 065ce6c22587..dc5c6737c280 100644 --- a/fs/fs_parser.c +++ b/fs/fs_parser.c @@ -268,9 +268,6 @@ int fs_lookup_param(struct fs_context *fc, return PTR_ERR(f); put_f = true; break; - case fs_value_is_filename_empty: - flags = LOOKUP_EMPTY; - /* Fall through */ case fs_value_is_filename: f = param->name; put_f = false; -- cgit v1.2.1 From 7f5d38141e309bb4ba995d9726928af85a299c50 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Fri, 20 Dec 2019 23:52:55 -0500 Subject: new primitive: __fs_parse() fs_parse() analogue taking p_log instead of fs_context. fs_parse() turned into a wrapper, callers in ceph_common and rbd switched to __fs_parse(). As the result, fs_parse() never gets NULL fs_context and neither do fs_context-based logging primitives Signed-off-by: Al Viro --- fs/fs_parser.c | 21 +++++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) (limited to 'fs/fs_parser.c') diff --git a/fs/fs_parser.c b/fs/fs_parser.c index dc5c6737c280..dadb6582874d 100644 --- a/fs/fs_parser.c +++ b/fs/fs_parser.c @@ -80,7 +80,7 @@ static const struct fs_parameter_spec *fs_lookup_key( * unknown parameters are okay and -EINVAL if there was a conversion issue or * the parameter wasn't recognised and unknowns aren't okay. */ -int fs_parse(struct fs_context *fc, +int __fs_parse(struct p_log *log, const struct fs_parameter_description *desc, struct fs_parameter *param, struct fs_parse_result *result) @@ -113,8 +113,7 @@ int fs_parse(struct fs_context *fc, } if (p->flags & fs_param_deprecated) - warnf(fc, "%s: Deprecated parameter '%s'", - desc->name, param->key); + warn_plog(log, "Deprecated parameter '%s'", param->key); if (result->negated) goto okay; @@ -152,8 +151,8 @@ int fs_parse(struct fs_context *fc, switch (p->type) { case fs_param_is_flag: if (param->type != fs_value_is_flag) - return invalf(fc, "%s: Unexpected value for '%s'", - desc->name, param->key); + return inval_plog(log, "Unexpected value for '%s'", + param->key); result->boolean = true; goto okay; @@ -238,10 +237,20 @@ okay: return p->opt; bad_value: - return invalf(fc, "%s: Bad value for '%s'", desc->name, param->key); + return inval_plog(log, "Bad value for '%s'", param->key); unknown_parameter: return -ENOPARAM; } +EXPORT_SYMBOL(__fs_parse); + +int fs_parse(struct fs_context *fc, + const struct fs_parameter_description *desc, + struct fs_parameter *param, + struct fs_parse_result *result) +{ + struct p_log log = {.prefix = desc->name, .log = fc->log}; + return __fs_parse(&log, desc, param, result); +} EXPORT_SYMBOL(fs_parse); /** -- cgit v1.2.1 From cc3c0b533ab9142eac2e291628fbfca3685f38cd Mon Sep 17 00:00:00 2001 From: Al Viro Date: Sat, 21 Dec 2019 00:16:49 -0500 Subject: add prefix to fs_context->log ... turning it into struct p_log embedded into fs_context. Initialize the prefix with fs_type->name, turning fs_parse() into a trivial inline wrapper for __fs_parse(). This makes fs_parameter_description->name completely unused. Signed-off-by: Al Viro --- fs/fs_parser.c | 10 ---------- 1 file changed, 10 deletions(-) (limited to 'fs/fs_parser.c') diff --git a/fs/fs_parser.c b/fs/fs_parser.c index dadb6582874d..4c410eef0173 100644 --- a/fs/fs_parser.c +++ b/fs/fs_parser.c @@ -243,16 +243,6 @@ unknown_parameter: } EXPORT_SYMBOL(__fs_parse); -int fs_parse(struct fs_context *fc, - const struct fs_parameter_description *desc, - struct fs_parameter *param, - struct fs_parse_result *result) -{ - struct p_log log = {.prefix = desc->name, .log = fc->log}; - return __fs_parse(&log, desc, param, result); -} -EXPORT_SYMBOL(fs_parse); - /** * fs_lookup_param - Look up a path referred to by a parameter * @fc: The filesystem context to log errors through. -- cgit v1.2.1 From 96cafb9ccb153f6a82ff2c9bde68916d9d65501e Mon Sep 17 00:00:00 2001 From: Eric Sandeen Date: Fri, 6 Dec 2019 10:45:01 -0600 Subject: fs_parser: remove fs_parameter_description name field Unused now. Signed-off-by: Eric Sandeen Acked-by: David Howells Signed-off-by: Al Viro --- fs/fs_parser.c | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) (limited to 'fs/fs_parser.c') diff --git a/fs/fs_parser.c b/fs/fs_parser.c index 4c410eef0173..3ed1e49d8267 100644 --- a/fs/fs_parser.c +++ b/fs/fs_parser.c @@ -354,20 +354,14 @@ bool validate_constant_table(const struct constant_table *tbl, size_t tbl_size, * fs_validate_description - Validate a parameter description * @desc: The parameter description to validate. */ -bool fs_validate_description(const struct fs_parameter_description *desc) +bool fs_validate_description(const char *name, + const struct fs_parameter_description *desc) { const struct fs_parameter_spec *param, *p2; - const char *name = desc->name; bool good = true; pr_notice("*** VALIDATE %s ***\n", name); - if (!name[0]) { - pr_err("VALIDATE Parser: No name\n"); - name = "Unknown"; - good = false; - } - if (desc->specs) { for (param = desc->specs; param->name; param++) { enum fs_parameter_type t = param->type; -- cgit v1.2.1 From d7167b149943e38ad610191ecbb0800c78bbced9 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Sat, 7 Sep 2019 07:23:15 -0400 Subject: fs_parse: fold fs_parameter_desc/fs_parameter_spec The former contains nothing but a pointer to an array of the latter... Signed-off-by: Al Viro --- fs/fs_parser.c | 53 +++++++++++++++++++++++++---------------------------- 1 file changed, 25 insertions(+), 28 deletions(-) (limited to 'fs/fs_parser.c') diff --git a/fs/fs_parser.c b/fs/fs_parser.c index 3ed1e49d8267..5f8c06a1fb93 100644 --- a/fs/fs_parser.c +++ b/fs/fs_parser.c @@ -47,15 +47,14 @@ int lookup_constant(const struct constant_table *tbl, const char *name, int not_ EXPORT_SYMBOL(lookup_constant); static const struct fs_parameter_spec *fs_lookup_key( - const struct fs_parameter_description *desc, + const struct fs_parameter_spec *desc, const char *name) { const struct fs_parameter_spec *p; - - if (!desc->specs) + if (!desc) return NULL; - for (p = desc->specs; p->name; p++) + for (p = desc; p->name; p++) if (strcmp(p->name, name) == 0) return p; @@ -81,7 +80,7 @@ static const struct fs_parameter_spec *fs_lookup_key( * the parameter wasn't recognised and unknowns aren't okay. */ int __fs_parse(struct p_log *log, - const struct fs_parameter_description *desc, + const struct fs_parameter_spec *desc, struct fs_parameter *param, struct fs_parse_result *result) { @@ -355,39 +354,37 @@ bool validate_constant_table(const struct constant_table *tbl, size_t tbl_size, * @desc: The parameter description to validate. */ bool fs_validate_description(const char *name, - const struct fs_parameter_description *desc) + const struct fs_parameter_spec *desc) { const struct fs_parameter_spec *param, *p2; bool good = true; pr_notice("*** VALIDATE %s ***\n", name); - if (desc->specs) { - for (param = desc->specs; param->name; param++) { - enum fs_parameter_type t = param->type; + for (param = desc; param->name; param++) { + enum fs_parameter_type t = param->type; - /* Check that the type is in range */ - if (t == __fs_param_wasnt_defined || - t >= nr__fs_parameter_type) { - pr_err("VALIDATE %s: PARAM[%s] Bad type %u\n", - name, param->name, t); + /* Check that the type is in range */ + if (t == __fs_param_wasnt_defined || + t >= nr__fs_parameter_type) { + pr_err("VALIDATE %s: PARAM[%s] Bad type %u\n", + name, param->name, t); + good = false; + } else if (t == fs_param_is_enum) { + const struct constant_table *e = param->data; + if (!e || !e->name) { + pr_err("VALIDATE %s: PARAM[%s] enum with no values\n", + name, param->name); good = false; - } else if (t == fs_param_is_enum) { - const struct constant_table *e = param->data; - if (!e || !e->name) { - pr_err("VALIDATE %s: PARAM[%s] enum with no values\n", - name, param->name); - good = false; - } } + } - /* Check for duplicate parameter names */ - for (p2 = desc->specs; p2 < param; p2++) { - if (strcmp(param->name, p2->name) == 0) { - pr_err("VALIDATE %s: PARAM[%s]: Duplicate\n", - name, param->name); - good = false; - } + /* Check for duplicate parameter names */ + for (p2 = desc; p2 < param; p2++) { + if (strcmp(param->name, p2->name) == 0) { + pr_err("VALIDATE %s: PARAM[%s]: Duplicate\n", + name, param->name); + good = false; } } } -- cgit v1.2.1 From 48ce73b1bef20331007b35de7ade8fe26cd55e84 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Tue, 17 Dec 2019 20:03:59 -0500 Subject: fs_parse: handle optional arguments sanely Don't bother with "mixed" options that would allow both the form with and without argument (i.e. both -o foo and -o foo=bar). Rather than trying to shove both into a single fs_parameter_spec, allow having with-argument and no-argument specs with the same name and teach fs_parse to handle that. There are very few options of that sort, and they are actually easier to handle that way - callers end up with less postprocessing. Signed-off-by: Al Viro --- fs/fs_parser.c | 142 +++++++++++++++++++++++---------------------------------- 1 file changed, 58 insertions(+), 84 deletions(-) (limited to 'fs/fs_parser.c') diff --git a/fs/fs_parser.c b/fs/fs_parser.c index 5f8c06a1fb93..db940fac84c3 100644 --- a/fs/fs_parser.c +++ b/fs/fs_parser.c @@ -46,19 +46,40 @@ int lookup_constant(const struct constant_table *tbl, const char *name, int not_ } EXPORT_SYMBOL(lookup_constant); +static inline bool is_flag(const struct fs_parameter_spec *p) +{ + return p->type == fs_param_is_flag; +} + static const struct fs_parameter_spec *fs_lookup_key( const struct fs_parameter_spec *desc, - const char *name) + struct fs_parameter *param, bool *negated) { - const struct fs_parameter_spec *p; - if (!desc) - return NULL; - - for (p = desc; p->name; p++) - if (strcmp(p->name, name) == 0) + const struct fs_parameter_spec *p, *other = NULL; + const char *name = param->key; + bool want_flag = param->type == fs_value_is_flag; + + *negated = false; + for (p = desc; p->name; p++) { + if (strcmp(p->name, name) != 0) + continue; + if (likely(is_flag(p) == want_flag)) return p; - - return NULL; + other = p; + } + if (want_flag) { + if (name[0] == 'n' && name[1] == 'o' && name[2]) { + for (p = desc; p->name; p++) { + if (strcmp(p->name, name + 2) != 0) + continue; + if (!(p->flags & fs_param_neg_with_no)) + continue; + *negated = true; + return p; + } + } + } + return other; } /* @@ -88,123 +109,77 @@ int __fs_parse(struct p_log *log, const struct constant_table *e; int ret = -ENOPARAM, b; - result->negated = false; result->uint_64 = 0; - p = fs_lookup_key(desc, param->key); - if (!p) { - /* If we didn't find something that looks like "noxxx", see if - * "xxx" takes the "no"-form negative - but only if there - * wasn't an value. - */ - if (param->type != fs_value_is_flag) - goto unknown_parameter; - if (param->key[0] != 'n' || param->key[1] != 'o' || !param->key[2]) - goto unknown_parameter; - - p = fs_lookup_key(desc, param->key + 2); - if (!p) - goto unknown_parameter; - if (!(p->flags & fs_param_neg_with_no)) - goto unknown_parameter; - result->boolean = false; - result->negated = true; - } + p = fs_lookup_key(desc, param, &result->negated); + if (!p) + return -ENOPARAM; if (p->flags & fs_param_deprecated) warn_plog(log, "Deprecated parameter '%s'", param->key); - if (result->negated) - goto okay; - - /* Certain parameter types only take a string and convert it. */ - switch (p->type) { - case __fs_param_wasnt_defined: - return -EINVAL; - case fs_param_is_u32: - case fs_param_is_u32_octal: - case fs_param_is_u32_hex: - case fs_param_is_s32: - case fs_param_is_u64: - case fs_param_is_enum: - case fs_param_is_string: - if (param->type == fs_value_is_string) { - if (p->flags & fs_param_v_optional) - break; - if (!*param->string) - goto bad_value; - break; - } - if (param->type == fs_value_is_flag) { - if (p->flags & fs_param_v_optional) - goto okay; - } - goto bad_value; - default: - break; - } - /* Try to turn the type we were given into the type desired by the * parameter and give an error if we can't. */ switch (p->type) { + case __fs_param_wasnt_defined: + return -EINVAL; case fs_param_is_flag: if (param->type != fs_value_is_flag) return inval_plog(log, "Unexpected value for '%s'", param->key); - result->boolean = true; + result->boolean = !result->negated; goto okay; - case fs_param_is_bool: - switch (param->type) { - case fs_value_is_flag: - result->boolean = true; - goto okay; - case fs_value_is_string: - if (param->size == 0) { - result->boolean = true; - goto okay; - } - b = lookup_constant(bool_names, param->string, -1); - if (b == -1) - goto bad_value; - result->boolean = b; - goto okay; - default: + if (param->type != fs_value_is_string) goto bad_value; - } - + b = lookup_constant(bool_names, param->string, -1); + if (b == -1) + goto bad_value; + result->boolean = b; + goto okay; case fs_param_is_u32: + if (param->type != fs_value_is_string) + goto bad_value; ret = kstrtouint(param->string, 0, &result->uint_32); goto maybe_okay; case fs_param_is_u32_octal: + if (param->type != fs_value_is_string) + goto bad_value; ret = kstrtouint(param->string, 8, &result->uint_32); goto maybe_okay; case fs_param_is_u32_hex: + if (param->type != fs_value_is_string) + goto bad_value; ret = kstrtouint(param->string, 16, &result->uint_32); goto maybe_okay; case fs_param_is_s32: + if (param->type != fs_value_is_string) + goto bad_value; ret = kstrtoint(param->string, 0, &result->int_32); goto maybe_okay; case fs_param_is_u64: + if (param->type != fs_value_is_string) + goto bad_value; ret = kstrtoull(param->string, 0, &result->uint_64); goto maybe_okay; - case fs_param_is_enum: + if (param->type != fs_value_is_string) + goto bad_value; e = __lookup_constant(p->data, param->string); if (e) { result->uint_32 = e->value; goto okay; } goto bad_value; - case fs_param_is_string: + if (param->type != fs_value_is_string || !*param->string) + goto bad_value; goto okay; case fs_param_is_blob: if (param->type != fs_value_is_blob) goto bad_value; goto okay; - case fs_param_is_fd: { switch (param->type) { case fs_value_is_string: @@ -221,7 +196,6 @@ int __fs_parse(struct p_log *log, goto bad_value; goto maybe_okay; } - case fs_param_is_blockdev: case fs_param_is_path: goto okay; @@ -237,8 +211,6 @@ okay: bad_value: return inval_plog(log, "Bad value for '%s'", param->key); -unknown_parameter: - return -ENOPARAM; } EXPORT_SYMBOL(__fs_parse); @@ -382,6 +354,8 @@ bool fs_validate_description(const char *name, /* Check for duplicate parameter names */ for (p2 = desc; p2 < param; p2++) { if (strcmp(param->name, p2->name) == 0) { + if (is_flag(param) != is_flag(p2)) + continue; pr_err("VALIDATE %s: PARAM[%s]: Duplicate\n", name, param->name); good = false; -- cgit v1.2.1 From 328de5287b10abc967c517461cf2948bd8a5b4e9 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Wed, 18 Dec 2019 00:02:31 -0500 Subject: turn fs_param_is_... into functions Signed-off-by: Al Viro --- fs/fs_parser.c | 228 +++++++++++++++++++++++++++++++-------------------------- 1 file changed, 124 insertions(+), 104 deletions(-) (limited to 'fs/fs_parser.c') diff --git a/fs/fs_parser.c b/fs/fs_parser.c index db940fac84c3..7e6fb43f9541 100644 --- a/fs/fs_parser.c +++ b/fs/fs_parser.c @@ -48,7 +48,7 @@ EXPORT_SYMBOL(lookup_constant); static inline bool is_flag(const struct fs_parameter_spec *p) { - return p->type == fs_param_is_flag; + return p->type == NULL; } static const struct fs_parameter_spec *fs_lookup_key( @@ -106,8 +106,6 @@ int __fs_parse(struct p_log *log, struct fs_parse_result *result) { const struct fs_parameter_spec *p; - const struct constant_table *e; - int ret = -ENOPARAM, b; result->uint_64 = 0; @@ -121,96 +119,17 @@ int __fs_parse(struct p_log *log, /* Try to turn the type we were given into the type desired by the * parameter and give an error if we can't. */ - switch (p->type) { - case __fs_param_wasnt_defined: - return -EINVAL; - case fs_param_is_flag: + if (is_flag(p)) { if (param->type != fs_value_is_flag) return inval_plog(log, "Unexpected value for '%s'", param->key); result->boolean = !result->negated; - goto okay; - case fs_param_is_bool: - if (param->type != fs_value_is_string) - goto bad_value; - b = lookup_constant(bool_names, param->string, -1); - if (b == -1) - goto bad_value; - result->boolean = b; - goto okay; - case fs_param_is_u32: - if (param->type != fs_value_is_string) - goto bad_value; - ret = kstrtouint(param->string, 0, &result->uint_32); - goto maybe_okay; - case fs_param_is_u32_octal: - if (param->type != fs_value_is_string) - goto bad_value; - ret = kstrtouint(param->string, 8, &result->uint_32); - goto maybe_okay; - case fs_param_is_u32_hex: - if (param->type != fs_value_is_string) - goto bad_value; - ret = kstrtouint(param->string, 16, &result->uint_32); - goto maybe_okay; - case fs_param_is_s32: - if (param->type != fs_value_is_string) - goto bad_value; - ret = kstrtoint(param->string, 0, &result->int_32); - goto maybe_okay; - case fs_param_is_u64: - if (param->type != fs_value_is_string) - goto bad_value; - ret = kstrtoull(param->string, 0, &result->uint_64); - goto maybe_okay; - case fs_param_is_enum: - if (param->type != fs_value_is_string) - goto bad_value; - e = __lookup_constant(p->data, param->string); - if (e) { - result->uint_32 = e->value; - goto okay; - } - goto bad_value; - case fs_param_is_string: - if (param->type != fs_value_is_string || !*param->string) - goto bad_value; - goto okay; - case fs_param_is_blob: - if (param->type != fs_value_is_blob) - goto bad_value; - goto okay; - case fs_param_is_fd: { - switch (param->type) { - case fs_value_is_string: - ret = kstrtouint(param->string, 0, &result->uint_32); - break; - case fs_value_is_file: - result->uint_32 = param->dirfd; - ret = 0; - default: - goto bad_value; - } - - if (result->uint_32 > INT_MAX) - goto bad_value; - goto maybe_okay; + } else { + int ret = p->type(log, p, param, result); + if (ret) + return ret; } - case fs_param_is_blockdev: - case fs_param_is_path: - goto okay; - default: - BUG(); - } - -maybe_okay: - if (ret < 0) - goto bad_value; -okay: return p->opt; - -bad_value: - return inval_plog(log, "Bad value for '%s'", param->key); } EXPORT_SYMBOL(__fs_parse); @@ -270,6 +189,124 @@ out: } EXPORT_SYMBOL(fs_lookup_param); +int fs_param_bad_value(struct p_log *log, struct fs_parameter *param) +{ + return inval_plog(log, "Bad value for '%s'", param->key); +} + +int fs_param_is_bool(struct p_log *log, const struct fs_parameter_spec *p, + struct fs_parameter *param, struct fs_parse_result *result) +{ + int b; + if (param->type != fs_value_is_string) + return fs_param_bad_value(log, param); + b = lookup_constant(bool_names, param->string, -1); + if (b == -1) + return fs_param_bad_value(log, param); + result->boolean = b; + return 0; +} +EXPORT_SYMBOL(fs_param_is_bool); + +int fs_param_is_u32(struct p_log *log, const struct fs_parameter_spec *p, + struct fs_parameter *param, struct fs_parse_result *result) +{ + int base = (unsigned long)p->data; + if (param->type != fs_value_is_string || + kstrtouint(param->string, base, &result->uint_32) < 0) + return fs_param_bad_value(log, param); + return 0; +} +EXPORT_SYMBOL(fs_param_is_u32); + +int fs_param_is_s32(struct p_log *log, const struct fs_parameter_spec *p, + struct fs_parameter *param, struct fs_parse_result *result) +{ + if (param->type != fs_value_is_string || + kstrtoint(param->string, 0, &result->int_32) < 0) + return fs_param_bad_value(log, param); + return 0; +} +EXPORT_SYMBOL(fs_param_is_s32); + +int fs_param_is_u64(struct p_log *log, const struct fs_parameter_spec *p, + struct fs_parameter *param, struct fs_parse_result *result) +{ + if (param->type != fs_value_is_string || + kstrtoull(param->string, 0, &result->uint_64) < 0) + return fs_param_bad_value(log, param); + return 0; +} +EXPORT_SYMBOL(fs_param_is_u64); + +int fs_param_is_enum(struct p_log *log, const struct fs_parameter_spec *p, + struct fs_parameter *param, struct fs_parse_result *result) +{ + const struct constant_table *c; + if (param->type != fs_value_is_string) + return fs_param_bad_value(log, param); + c = __lookup_constant(p->data, param->string); + if (!c) + return fs_param_bad_value(log, param); + result->uint_32 = c->value; + return 0; +} +EXPORT_SYMBOL(fs_param_is_enum); + +int fs_param_is_string(struct p_log *log, const struct fs_parameter_spec *p, + struct fs_parameter *param, struct fs_parse_result *result) +{ + if (param->type != fs_value_is_string || !*param->string) + return fs_param_bad_value(log, param); + return 0; +} +EXPORT_SYMBOL(fs_param_is_string); + +int fs_param_is_blob(struct p_log *log, const struct fs_parameter_spec *p, + struct fs_parameter *param, struct fs_parse_result *result) +{ + if (param->type != fs_value_is_blob) + return fs_param_bad_value(log, param); + return 0; +} +EXPORT_SYMBOL(fs_param_is_blob); + +int fs_param_is_fd(struct p_log *log, const struct fs_parameter_spec *p, + struct fs_parameter *param, struct fs_parse_result *result) +{ + switch (param->type) { + case fs_value_is_string: + if (kstrtouint(param->string, 0, &result->uint_32) < 0) + break; + if (result->uint_32 <= INT_MAX) + return 0; + break; + case fs_value_is_file: + result->uint_32 = param->dirfd; + if (result->uint_32 <= INT_MAX) + return 0; + break; + default: + break; + } + return fs_param_bad_value(log, param); +} +EXPORT_SYMBOL(fs_param_is_fd); + +int fs_param_is_blockdev(struct p_log *log, const struct fs_parameter_spec *p, + struct fs_parameter *param, struct fs_parse_result *result) +{ + return 0; +} +EXPORT_SYMBOL(fs_param_is_blockdev); + +int fs_param_is_path(struct p_log *log, const struct fs_parameter_spec *p, + struct fs_parameter *param, struct fs_parse_result *result) +{ + return 0; +} +EXPORT_SYMBOL(fs_param_is_path); + #ifdef CONFIG_VALIDATE_FS_PARSER /** * validate_constant_table - Validate a constant table @@ -334,23 +371,6 @@ bool fs_validate_description(const char *name, pr_notice("*** VALIDATE %s ***\n", name); for (param = desc; param->name; param++) { - enum fs_parameter_type t = param->type; - - /* Check that the type is in range */ - if (t == __fs_param_wasnt_defined || - t >= nr__fs_parameter_type) { - pr_err("VALIDATE %s: PARAM[%s] Bad type %u\n", - name, param->name, t); - good = false; - } else if (t == fs_param_is_enum) { - const struct constant_table *e = param->data; - if (!e || !e->name) { - pr_err("VALIDATE %s: PARAM[%s] enum with no values\n", - name, param->name); - good = false; - } - } - /* Check for duplicate parameter names */ for (p2 = desc; p2 < param; p2++) { if (strcmp(param->name, p2->name) == 0) { -- cgit v1.2.1