The sloppy option doesn't make sense for fsconfig() and knowedge of how to handle this case needs to be present in the caller. It does make sense in the legacy options parser, generic_parse_monolithic(), so it should allow for it. The sloppy option needs to be independent of the order in which it's given. The simplest way to do this in generic_parse_monolithic() is to check for it's presence, check if the file system supports it, then skip occurrances of it when walking the options string. Signed-off-by: Ian Kent <raven@xxxxxxxxxx> --- fs/cifs/fs_context.c | 2 +- fs/fs_context.c | 31 ++++++++++++++++++++++++++++++- fs/nfs/fs_context.c | 2 +- include/linux/fs.h | 1 + 4 files changed, 33 insertions(+), 3 deletions(-) diff --git a/fs/cifs/fs_context.c b/fs/cifs/fs_context.c index 6d13f8207e96..d7e9356797ab 100644 --- a/fs/cifs/fs_context.c +++ b/fs/cifs/fs_context.c @@ -866,7 +866,7 @@ static int smb3_fs_context_parse_param(struct fs_context *fc, if (!skip_parsing) { opt = fs_parse(fc, smb3_fs_parameters, param, &result); if (opt < 0) - return ctx->sloppy ? 1 : opt; + return opt; } switch (opt) { diff --git a/fs/fs_context.c b/fs/fs_context.c index 24ce12f0db32..fa179e1b8061 100644 --- a/fs/fs_context.c +++ b/fs/fs_context.c @@ -187,6 +187,28 @@ int vfs_parse_fs_string(struct fs_context *fc, const char *key, } EXPORT_SYMBOL(vfs_parse_fs_string); + +static bool check_for_sloppy_option(void *options) +{ + char *sloppy; + char last; + + sloppy = strstr(options, "sloppy"); + if (!sloppy) + return false; + + last = sloppy[6]; + + if (sloppy == options) { + if (last == 0 || last == ',') + return true; + } else if (*(--sloppy) == ',') { + if (last == 0 || last == ',') + return true; + } + return false; +} + /** * generic_parse_monolithic - Parse key[=val][,key[=val]]* mount data * @ctx: The superblock configuration to fill in. @@ -201,6 +223,7 @@ EXPORT_SYMBOL(vfs_parse_fs_string); int generic_parse_monolithic(struct fs_context *fc, void *data) { char *options = data, *key; + bool sloppy = false; int ret = 0; if (!options) @@ -210,11 +233,17 @@ int generic_parse_monolithic(struct fs_context *fc, void *data) if (ret) return ret; + if (fc->fs_type->fs_flags & FS_ALLOW_LEGACY_SLOPPY) + sloppy = check_for_sloppy_option(options); + while ((key = strsep(&options, ",")) != NULL) { if (*key) { size_t v_len = 0; char *value = strchr(key, '='); + if (sloppy && !strcmp(key, "sloppy")) + continue; + if (value) { if (value == key) continue; @@ -222,7 +251,7 @@ int generic_parse_monolithic(struct fs_context *fc, void *data) v_len = strlen(value); } ret = vfs_parse_fs_string(fc, key, value, v_len); - if (ret < 0) + if (!sloppy && ret < 0) break; } } diff --git a/fs/nfs/fs_context.c b/fs/nfs/fs_context.c index 9bcd53d5c7d4..e8818b68ce3f 100644 --- a/fs/nfs/fs_context.c +++ b/fs/nfs/fs_context.c @@ -485,7 +485,7 @@ static int nfs_fs_context_parse_param(struct fs_context *fc, opt = fs_parse(fc, nfs_fs_parameters, param, &result); if (opt < 0) - return (opt == -ENOPARAM && ctx->sloppy) ? 1 : opt; + return opt; if (fc->security) ctx->has_sec_mnt_opts = 1; diff --git a/include/linux/fs.h b/include/linux/fs.h index c1769a2c5d70..ca05111767cb 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -2533,6 +2533,7 @@ struct file_system_type { #define FS_USERNS_MOUNT 8 /* Can be mounted by userns root */ #define FS_DISALLOW_NOTIFY_PERM 16 /* Disable fanotify permission events */ #define FS_ALLOW_IDMAP 32 /* FS has been updated to handle vfs idmappings. */ +#define FS_ALLOW_LEGACY_SLOPPY 64 /* FS allows "sloppy" option handling behaviour */ #define FS_RENAME_DOES_D_MOVE 32768 /* FS will handle d_move() during rename() internally. */ int (*init_fs_context)(struct fs_context *); const struct fs_parameter_spec *parameters;