@@ -96,7 +96,9 @@ int vfs_parse_fs_param_source(struct fs_context *fc, struct fs_parameter *param)
if (strcmp(param->key, "source") != 0)
return -ENOPARAM;
- if (param->type != fs_value_is_string)
+ /* source value may be NULL */
+ if (param->type != fs_value_is_string &&
+ param->type != fs_value_is_empty)
return invalf(fc, "Non-string source");
if (fc->source)
@@ -175,10 +177,15 @@ int vfs_parse_fs_string(struct fs_context *fc, const char *key,
};
if (value) {
- param.string = kmemdup_nul(value, v_size, GFP_KERNEL);
- if (!param.string)
- return -ENOMEM;
- param.type = fs_value_is_string;
+ if (!v_size) {
+ param.string = NULL;
+ param.type = fs_value_is_empty;
+ } else {
+ param.string = kmemdup_nul(value, v_size, GFP_KERNEL);
+ if (!param.string)
+ return -ENOMEM;
+ param.type = fs_value_is_string;
+ }
}
ret = vfs_parse_fs_param(fc, ¶m);
@@ -197,6 +197,8 @@ 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_empty)
+ return 0;
if (param->type != fs_value_is_string)
return fs_param_bad_value(log, param);
if (!*param->string && (p->flags & fs_param_can_be_empty))
@@ -213,6 +215,8 @@ 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_empty)
+ return 0;
if (param->type != fs_value_is_string)
return fs_param_bad_value(log, param);
if (!*param->string && (p->flags & fs_param_can_be_empty))
@@ -226,6 +230,8 @@ 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_empty)
+ return 0;
if (param->type != fs_value_is_string)
return fs_param_bad_value(log, param);
if (!*param->string && (p->flags & fs_param_can_be_empty))
@@ -239,6 +245,8 @@ 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_empty)
+ return 0;
if (param->type != fs_value_is_string)
return fs_param_bad_value(log, param);
if (!*param->string && (p->flags & fs_param_can_be_empty))
@@ -253,6 +261,8 @@ 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_empty)
+ return 0;
if (param->type != fs_value_is_string)
return fs_param_bad_value(log, param);
if (!*param->string && (p->flags & fs_param_can_be_empty))
@@ -268,6 +278,8 @@ 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_empty)
+ return 0;
if (param->type != fs_value_is_string ||
(!*param->string && !(p->flags & fs_param_can_be_empty)))
return fs_param_bad_value(log, param);
@@ -278,6 +290,8 @@ 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_empty)
+ return 0;
if (param->type != fs_value_is_blob)
return fs_param_bad_value(log, param);
return 0;
@@ -287,6 +301,8 @@ 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)
{
+ if (param->type == fs_value_is_empty)
+ return 0;
switch (param->type) {
case fs_value_is_string:
if ((!*param->string && !(p->flags & fs_param_can_be_empty)) ||
@@ -50,7 +50,8 @@ enum fs_context_phase {
*/
enum fs_value_type {
fs_value_is_undefined,
- fs_value_is_flag, /* Value not given a value */
+ fs_value_is_flag, /* Does not take a value */
+ fs_value_is_empty, /* Value is not given */
fs_value_is_string, /* Value is a string */
fs_value_is_blob, /* Value is a binary blob */
fs_value_is_filename, /* Value is a filename* + dirfd */
Parsing an fs string that has zero length should result in the parameter being set to NULL so that downstream processing handles it correctly. For example, the proc mount table processing should print "(none)" in this case to preserve mount record field count, but if the value points to the NULL string this doesn't happen. Changes: v2: fix possible oops if conversion functions such as fs_param_is_u32() are called. Signed-off-by: Ian Kent <raven@themaw.net> --- fs/fs_context.c | 17 ++++++++++++----- fs/fs_parser.c | 16 ++++++++++++++++ include/linux/fs_context.h | 3 ++- 3 files changed, 30 insertions(+), 6 deletions(-)