summaryrefslogtreecommitdiffstats
path: root/fs
diff options
context:
space:
mode:
Diffstat (limited to 'fs')
-rw-r--r--fs/afs/super.c32
-rw-r--r--fs/ceph/cache.c4
-rw-r--r--fs/ceph/super.c40
-rw-r--r--fs/cramfs/inode.c14
-rw-r--r--fs/filesystems.c3
-rw-r--r--fs/fs_context.c79
-rw-r--r--fs/fs_parser.c447
-rw-r--r--fs/fsopen.c26
-rw-r--r--fs/fuse/inode.c25
-rw-r--r--fs/gfs2/ops_fstype.c103
-rw-r--r--fs/hugetlbfs/inode.c13
-rw-r--r--fs/jffs2/super.c26
-rw-r--r--fs/nfs/fs_context.c93
-rw-r--r--fs/proc/root.c13
-rw-r--r--fs/ramfs/inode.c11
-rw-r--r--fs/xfs/xfs_super.c11
16 files changed, 392 insertions, 548 deletions
diff --git a/fs/afs/super.c b/fs/afs/super.c
index 7f8a9b3137bf..dda7a9a66848 100644
--- a/fs/afs/super.c
+++ b/fs/afs/super.c
@@ -38,13 +38,13 @@ static int afs_statfs(struct dentry *dentry, struct kstatfs *buf);
static int afs_show_devname(struct seq_file *m, struct dentry *root);
static int afs_show_options(struct seq_file *m, struct dentry *root);
static int afs_init_fs_context(struct fs_context *fc);
-static const struct fs_parameter_description afs_fs_parameters;
+static const struct fs_parameter_spec afs_fs_parameters[];
struct file_system_type afs_fs_type = {
.owner = THIS_MODULE,
.name = "afs",
.init_fs_context = afs_init_fs_context,
- .parameters = &afs_fs_parameters,
+ .parameters = afs_fs_parameters,
.kill_sb = afs_kill_super,
.fs_flags = FS_RENAME_DOES_D_MOVE,
};
@@ -73,28 +73,22 @@ enum afs_param {
Opt_source,
};
-static const struct fs_parameter_spec afs_param_specs[] = {
- fsparam_flag ("autocell", Opt_autocell),
- fsparam_flag ("dyn", Opt_dyn),
- fsparam_enum ("flock", Opt_flock),
- fsparam_string("source", Opt_source),
+static const struct constant_table afs_param_flock[] = {
+ {"local", afs_flock_mode_local },
+ {"openafs", afs_flock_mode_openafs },
+ {"strict", afs_flock_mode_strict },
+ {"write", afs_flock_mode_write },
{}
};
-static const struct fs_parameter_enum afs_param_enums[] = {
- { Opt_flock, "local", afs_flock_mode_local },
- { Opt_flock, "openafs", afs_flock_mode_openafs },
- { Opt_flock, "strict", afs_flock_mode_strict },
- { Opt_flock, "write", afs_flock_mode_write },
+static const struct fs_parameter_spec afs_fs_parameters[] = {
+ fsparam_flag ("autocell", Opt_autocell),
+ fsparam_flag ("dyn", Opt_dyn),
+ fsparam_enum ("flock", Opt_flock, afs_param_flock),
+ fsparam_string("source", Opt_source),
{}
};
-static const struct fs_parameter_description afs_fs_parameters = {
- .name = "kAFS",
- .specs = afs_param_specs,
- .enums = afs_param_enums,
-};
-
/*
* initialise the filesystem
*/
@@ -323,7 +317,7 @@ static int afs_parse_param(struct fs_context *fc, struct fs_parameter *param)
struct afs_fs_context *ctx = fc->fs_private;
int opt;
- opt = fs_parse(fc, &afs_fs_parameters, param, &result);
+ opt = fs_parse(fc, afs_fs_parameters, param, &result);
if (opt < 0)
return opt;
diff --git a/fs/ceph/cache.c b/fs/ceph/cache.c
index 73f24f307a4a..270b769607a2 100644
--- a/fs/ceph/cache.c
+++ b/fs/ceph/cache.c
@@ -67,7 +67,7 @@ int ceph_fscache_register_fs(struct ceph_fs_client* fsc, struct fs_context *fc)
if (uniq_len && memcmp(ent->uniquifier, fscache_uniq, uniq_len))
continue;
- errorf(fc, "ceph: fscache cookie already registered for fsid %pU, use fsc=<uniquifier> option",
+ errorfc(fc, "fscache cookie already registered for fsid %pU, use fsc=<uniquifier> option",
fsid);
err = -EBUSY;
goto out_unlock;
@@ -96,7 +96,7 @@ int ceph_fscache_register_fs(struct ceph_fs_client* fsc, struct fs_context *fc)
list_add_tail(&ent->list, &ceph_fscache_list);
} else {
kfree(ent);
- errorf(fc, "ceph: unable to register fscache cookie for fsid %pU",
+ errorfc(fc, "unable to register fscache cookie for fsid %pU",
fsid);
/* all other fs ignore this error */
}
diff --git a/fs/ceph/super.c b/fs/ceph/super.c
index bfb8aead0555..1d9f083b8a11 100644
--- a/fs/ceph/super.c
+++ b/fs/ceph/super.c
@@ -162,13 +162,13 @@ enum ceph_recover_session_mode {
ceph_recover_session_clean
};
-static const struct fs_parameter_enum ceph_mount_param_enums[] = {
- { Opt_recover_session, "no", ceph_recover_session_no },
- { Opt_recover_session, "clean", ceph_recover_session_clean },
+static const struct constant_table ceph_param_recover[] = {
+ { "no", ceph_recover_session_no },
+ { "clean", ceph_recover_session_clean },
{}
};
-static const struct fs_parameter_spec ceph_mount_param_specs[] = {
+static const struct fs_parameter_spec ceph_mount_parameters[] = {
fsparam_flag_no ("acl", Opt_acl),
fsparam_flag_no ("asyncreaddir", Opt_asyncreaddir),
fsparam_s32 ("caps_max", Opt_caps_max),
@@ -178,8 +178,8 @@ static const struct fs_parameter_spec ceph_mount_param_specs[] = {
fsparam_flag_no ("copyfrom", Opt_copyfrom),
fsparam_flag_no ("dcache", Opt_dcache),
fsparam_flag_no ("dirstat", Opt_dirstat),
- __fsparam (fs_param_is_string, "fsc", Opt_fscache,
- fs_param_neg_with_no | fs_param_v_optional),
+ fsparam_flag_no ("fsc", Opt_fscache), // fsc|nofsc
+ fsparam_string ("fsc", Opt_fscache), // fsc=...
fsparam_flag_no ("ino32", Opt_ino32),
fsparam_string ("mds_namespace", Opt_mds_namespace),
fsparam_flag_no ("poolperm", Opt_poolperm),
@@ -188,7 +188,7 @@ static const struct fs_parameter_spec ceph_mount_param_specs[] = {
fsparam_flag_no ("rbytes", Opt_rbytes),
fsparam_u32 ("readdir_max_bytes", Opt_readdir_max_bytes),
fsparam_u32 ("readdir_max_entries", Opt_readdir_max_entries),
- fsparam_enum ("recover_session", Opt_recover_session),
+ fsparam_enum ("recover_session", Opt_recover_session, ceph_param_recover),
fsparam_flag_no ("require_active_mds", Opt_require_active_mds),
fsparam_u32 ("rsize", Opt_rsize),
fsparam_string ("snapdirname", Opt_snapdirname),
@@ -197,12 +197,6 @@ static const struct fs_parameter_spec ceph_mount_param_specs[] = {
{}
};
-static const struct fs_parameter_description ceph_mount_parameters = {
- .name = "ceph",
- .specs = ceph_mount_param_specs,
- .enums = ceph_mount_param_enums,
-};
-
struct ceph_parse_opts_ctx {
struct ceph_options *copts;
struct ceph_mount_options *opts;
@@ -226,7 +220,7 @@ static int ceph_parse_source(struct fs_parameter *param, struct fs_context *fc)
dout("%s '%s'\n", __func__, dev_name);
if (!dev_name || !*dev_name)
- return invalf(fc, "ceph: Empty source");
+ return invalfc(fc, "Empty source");
dev_name_end = strchr(dev_name, '/');
if (dev_name_end) {
@@ -245,14 +239,14 @@ static int ceph_parse_source(struct fs_parameter *param, struct fs_context *fc)
dev_name_end--; /* back up to ':' separator */
if (dev_name_end < dev_name || *dev_name_end != ':')
- return invalf(fc, "ceph: No path or : separator in source");
+ return invalfc(fc, "No path or : separator in source");
dout("device name '%.*s'\n", (int)(dev_name_end - dev_name), dev_name);
if (fsopt->server_path)
dout("server path '%s'\n", fsopt->server_path);
ret = ceph_parse_mon_ips(param->string, dev_name_end - dev_name,
- pctx->copts, fc);
+ pctx->copts, fc->log.log);
if (ret)
return ret;
@@ -270,11 +264,11 @@ static int ceph_parse_mount_param(struct fs_context *fc,
unsigned int mode;
int token, ret;
- ret = ceph_parse_param(param, pctx->copts, fc);
+ ret = ceph_parse_param(param, pctx->copts, fc->log.log);
if (ret != -ENOPARAM)
return ret;
- token = fs_parse(fc, &ceph_mount_parameters, param, &result);
+ token = fs_parse(fc, ceph_mount_parameters, param, &result);
dout("%s fs_parse '%s' token %d\n", __func__, param->key, token);
if (token < 0)
return token;
@@ -301,7 +295,7 @@ static int ceph_parse_mount_param(struct fs_context *fc,
break;
case Opt_source:
if (fc->source)
- return invalf(fc, "ceph: Multiple sources specified");
+ return invalfc(fc, "Multiple sources specified");
return ceph_parse_source(param, fc);
case Opt_wsize:
if (result.uint_32 < PAGE_SIZE ||
@@ -392,7 +386,7 @@ static int ceph_parse_mount_param(struct fs_context *fc,
}
break;
#else
- return invalf(fc, "ceph: fscache support is disabled");
+ return invalfc(fc, "fscache support is disabled");
#endif
case Opt_poolperm:
if (!result.negated)
@@ -423,7 +417,7 @@ static int ceph_parse_mount_param(struct fs_context *fc,
#ifdef CONFIG_CEPH_FS_POSIX_ACL
fc->sb_flags |= SB_POSIXACL;
#else
- return invalf(fc, "ceph: POSIX ACL support is disabled");
+ return invalfc(fc, "POSIX ACL support is disabled");
#endif
} else {
fc->sb_flags &= ~SB_POSIXACL;
@@ -435,7 +429,7 @@ static int ceph_parse_mount_param(struct fs_context *fc,
return 0;
out_of_range:
- return invalf(fc, "ceph: %s out of range", param->key);
+ return invalfc(fc, "%s out of range", param->key);
}
static void destroy_mount_options(struct ceph_mount_options *args)
@@ -1101,7 +1095,7 @@ static int ceph_get_tree(struct fs_context *fc)
dout("ceph_get_tree\n");
if (!fc->source)
- return invalf(fc, "ceph: No source");
+ return invalfc(fc, "No source");
#ifdef CONFIG_CEPH_FS_POSIX_ACL
fc->sb_flags |= SB_POSIXACL;
diff --git a/fs/cramfs/inode.c b/fs/cramfs/inode.c
index 2f04024c3588..912308600d39 100644
--- a/fs/cramfs/inode.c
+++ b/fs/cramfs/inode.c
@@ -534,7 +534,7 @@ static int cramfs_read_super(struct super_block *sb, struct fs_context *fc,
/* check for wrong endianness */
if (super->magic == CRAMFS_MAGIC_WEND) {
if (!silent)
- errorf(fc, "cramfs: wrong endianness");
+ errorfc(fc, "wrong endianness");
return -EINVAL;
}
@@ -546,22 +546,22 @@ static int cramfs_read_super(struct super_block *sb, struct fs_context *fc,
mutex_unlock(&read_mutex);
if (super->magic != CRAMFS_MAGIC) {
if (super->magic == CRAMFS_MAGIC_WEND && !silent)
- errorf(fc, "cramfs: wrong endianness");
+ errorfc(fc, "wrong endianness");
else if (!silent)
- errorf(fc, "cramfs: wrong magic");
+ errorfc(fc, "wrong magic");
return -EINVAL;
}
}
/* get feature flags first */
if (super->flags & ~CRAMFS_SUPPORTED_FLAGS) {
- errorf(fc, "cramfs: unsupported filesystem features");
+ errorfc(fc, "unsupported filesystem features");
return -EINVAL;
}
/* Check that the root inode is in a sane state */
if (!S_ISDIR(super->root.mode)) {
- errorf(fc, "cramfs: root is not a directory");
+ errorfc(fc, "root is not a directory");
return -EINVAL;
}
/* correct strange, hard-coded permissions of mkcramfs */
@@ -580,12 +580,12 @@ static int cramfs_read_super(struct super_block *sb, struct fs_context *fc,
sbi->magic = super->magic;
sbi->flags = super->flags;
if (root_offset == 0)
- infof(fc, "cramfs: empty filesystem");
+ infofc(fc, "empty filesystem");
else if (!(super->flags & CRAMFS_FLAG_SHIFTED_ROOT_OFFSET) &&
((root_offset != sizeof(struct cramfs_super)) &&
(root_offset != 512 + sizeof(struct cramfs_super))))
{
- errorf(fc, "cramfs: bad root offset %lu", root_offset);
+ errorfc(fc, "bad root offset %lu", root_offset);
return -EINVAL;
}
diff --git a/fs/filesystems.c b/fs/filesystems.c
index 9135646e41ac..77bf5f95362d 100644
--- a/fs/filesystems.c
+++ b/fs/filesystems.c
@@ -74,7 +74,8 @@ int register_filesystem(struct file_system_type * fs)
int res = 0;
struct file_system_type ** p;
- if (fs->parameters && !fs_validate_description(fs->parameters))
+ if (fs->parameters &&
+ !fs_validate_description(fs->name, fs->parameters))
return -EINVAL;
BUG_ON(strchr(fs->name, '.'));
diff --git a/fs/fs_context.c b/fs/fs_context.c
index 138b5b4d621d..fc9f6ef93b55 100644
--- a/fs/fs_context.c
+++ b/fs/fs_context.c
@@ -45,6 +45,7 @@ static const struct constant_table common_set_sb_flag[] = {
{ "posixacl", SB_POSIXACL },
{ "ro", SB_RDONLY },
{ "sync", SB_SYNCHRONOUS },
+ { },
};
static const struct constant_table common_clear_sb_flag[] = {
@@ -53,6 +54,7 @@ static const struct constant_table common_clear_sb_flag[] = {
{ "nomand", SB_MANDLOCK },
{ "rw", SB_RDONLY },
{ "silent", SB_SILENT },
+ { },
};
static const char *const forbidden_sb_flag[] = {
@@ -175,14 +177,15 @@ int vfs_parse_fs_string(struct fs_context *fc, const char *key,
struct fs_parameter param = {
.key = key,
- .type = fs_value_is_string,
+ .type = fs_value_is_flag,
.size = v_size,
};
- if (v_size > 0) {
+ if (value) {
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, &param);
@@ -268,6 +271,7 @@ static struct fs_context *alloc_fs_context(struct file_system_type *fs_type,
fc->fs_type = get_filesystem(fs_type);
fc->cred = get_current_cred();
fc->net_ns = get_net(current->nsproxy->net_ns);
+ fc->log.prefix = fs_type->name;
mutex_init(&fc->uapi_mutex);
@@ -361,8 +365,8 @@ struct fs_context *vfs_dup_fs_context(struct fs_context *src_fc)
get_net(fc->net_ns);
get_user_ns(fc->user_ns);
get_cred(fc->cred);
- if (fc->log)
- refcount_inc(&fc->log->usage);
+ if (fc->log.log)
+ refcount_inc(&fc->log.log->usage);
/* Can't call put until we've called ->dup */
ret = fc->ops->dup(fc, src_fc);
@@ -385,64 +389,33 @@ EXPORT_SYMBOL(vfs_dup_fs_context);
* @fc: The filesystem context to log to.
* @fmt: The format of the buffer.
*/
-void logfc(struct fs_context *fc, const char *fmt, ...)
+void logfc(struct fc_log *log, const char *prefix, char level, const char *fmt, ...)
{
- static const char store_failure[] = "OOM: Can't store error string";
- struct fc_log *log = fc ? fc->log : NULL;
- const char *p;
va_list va;
- char *q;
- u8 freeable;
+ struct va_format vaf = {.fmt = fmt, .va = &va};
va_start(va, fmt);
- if (!strchr(fmt, '%')) {
- p = fmt;
- goto unformatted_string;
- }
- if (strcmp(fmt, "%s") == 0) {
- p = va_arg(va, const char *);
- goto unformatted_string;
- }
-
- q = kvasprintf(GFP_KERNEL, fmt, va);
-copied_string:
- if (!q)
- goto store_failure;
- freeable = 1;
- goto store_string;
-
-unformatted_string:
- if ((unsigned long)p >= (unsigned long)__start_rodata &&
- (unsigned long)p < (unsigned long)__end_rodata)
- goto const_string;
- if (log && within_module_core((unsigned long)p, log->owner))
- goto const_string;
- q = kstrdup(p, GFP_KERNEL);
- goto copied_string;
-
-store_failure:
- p = store_failure;
-const_string:
- q = (char *)p;
- freeable = 0;
-store_string:
if (!log) {
- switch (fmt[0]) {
+ switch (level) {
case 'w':
- printk(KERN_WARNING "%s\n", q + 2);
+ printk(KERN_WARNING "%s%s%pV\n", prefix ? prefix : "",
+ prefix ? ": " : "", &vaf);
break;
case 'e':
- printk(KERN_ERR "%s\n", q + 2);
+ printk(KERN_ERR "%s%s%pV\n", prefix ? prefix : "",
+ prefix ? ": " : "", &vaf);
break;
default:
- printk(KERN_NOTICE "%s\n", q + 2);
+ printk(KERN_NOTICE "%s%s%pV\n", prefix ? prefix : "",
+ prefix ? ": " : "", &vaf);
break;
}
- if (freeable)
- kfree(q);
} else {
unsigned int logsize = ARRAY_SIZE(log->buffer);
u8 index;
+ char *q = kasprintf(GFP_KERNEL, "%c %s%s%pV\n", level,
+ prefix ? prefix : "",
+ prefix ? ": " : "", &vaf);
index = log->head & (logsize - 1);
BUILD_BUG_ON(sizeof(log->head) != sizeof(u8) ||
@@ -454,9 +427,11 @@ store_string:
log->tail++;
}
- log->buffer[index] = q;
- log->need_free &= ~(1 << index);
- log->need_free |= freeable << index;
+ log->buffer[index] = q ? q : "OOM: Can't store error string";
+ if (q)
+ log->need_free |= 1 << index;
+ else
+ log->need_free &= ~(1 << index);
log->head++;
}
va_end(va);
@@ -468,12 +443,12 @@ EXPORT_SYMBOL(logfc);
*/
static void put_fc_log(struct fs_context *fc)
{
- struct fc_log *log = fc->log;
+ struct fc_log *log = fc->log.log;
int i;
if (log) {
if (refcount_dec_and_test(&log->usage)) {
- fc->log = NULL;
+ fc->log.log = NULL;
for (i = 0; i <= 7; i++)
if (log->need_free & (1 << i))
kfree(log->buffer[i]);
diff --git a/fs/fs_parser.c b/fs/fs_parser.c
index d1930adce68d..7e6fb43f9541 100644
--- a/fs/fs_parser.c
+++ b/fs/fs_parser.c
@@ -20,42 +20,66 @@ 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 p ? p->value : not_found;
+}
+EXPORT_SYMBOL(lookup_constant);
- return not_found;
+static inline bool is_flag(const struct fs_parameter_spec *p)
+{
+ return p->type == NULL;
}
-EXPORT_SYMBOL(__lookup_constant);
static const struct fs_parameter_spec *fs_lookup_key(
- const struct fs_parameter_description *desc,
- const char *name)
+ const struct fs_parameter_spec *desc,
+ struct fs_parameter *param, bool *negated)
{
- const struct fs_parameter_spec *p;
-
- if (!desc->specs)
- return NULL;
-
- for (p = desc->specs; 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;
}
/*
@@ -76,172 +100,38 @@ 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,
- const struct fs_parameter_description *desc,
+int __fs_parse(struct p_log *log,
+ const struct fs_parameter_spec *desc,
struct fs_parameter *param,
struct fs_parse_result *result)
{
const struct fs_parameter_spec *p;
- const struct fs_parameter_enum *e;
- int ret = -ENOPARAM, b;
- result->has_value = !!param->string;
- 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 (result->has_value)
- 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)
- warnf(fc, "%s: Deprecated parameter '%s'",
- desc->name, 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)
- goto bad_value;
- if (!result->has_value) {
- if (p->flags & fs_param_v_optional)
- goto okay;
- goto bad_value;
- }
- /* Fall through */
- default:
- break;
- }
+ warn_plog(log, "Deprecated parameter '%s'", param->key);
/* 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_is_flag:
- if (param->type != fs_value_is_flag &&
- (param->type != fs_value_is_string || result->has_value))
- return invalf(fc, "%s: Unexpected value for '%s'",
- desc->name, param->key);
- result->boolean = true;
- 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:
- goto bad_value;
- }
-
- case fs_param_is_u32:
- ret = kstrtouint(param->string, 0, &result->uint_32);
- goto maybe_okay;
- case fs_param_is_u32_octal:
- ret = kstrtouint(param->string, 8, &result->uint_32);
- goto maybe_okay;
- case fs_param_is_u32_hex:
- ret = kstrtouint(param->string, 16, &result->uint_32);
- goto maybe_okay;
- case fs_param_is_s32:
- ret = kstrtoint(param->string, 0, &result->int_32);
- goto maybe_okay;
- case fs_param_is_u64:
- ret = kstrtoull(param->string, 0, &result->uint_64);
- 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) {
- result->uint_32 = e->value;
- goto okay;
- }
- }
- goto bad_value;
-
- case fs_param_is_string:
- 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:
- if (!result->has_value)
- goto bad_value;
-
- 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;
- }
-
- case fs_param_is_blockdev:
- case fs_param_is_path:
- goto okay;
- default:
- BUG();
+ 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;
+ } else {
+ int ret = p->type(log, p, param, result);
+ if (ret)
+ return ret;
}
-
-maybe_okay:
- if (ret < 0)
- goto bad_value;
-okay:
return p->opt;
-
-bad_value:
- return invalf(fc, "%s: Bad value for '%s'", desc->name, param->key);
-unknown_parameter:
- return -ENOPARAM;
}
-EXPORT_SYMBOL(fs_parse);
+EXPORT_SYMBOL(__fs_parse);
/**
* fs_lookup_param - Look up a path referred to by a parameter
@@ -267,9 +157,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;
@@ -302,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
@@ -357,102 +362,26 @@ 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_spec *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);
- 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;
-
- /* 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) {
- enums = true;
- }
-
- /* 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;
- }
- }
- }
-
- 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",
+ for (param = desc; param->name; param++) {
+ /* 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;
}
}
- } 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 */
diff --git a/fs/fsopen.c b/fs/fsopen.c
index 043ffa8dc263..2fa3f241b762 100644
--- a/fs/fsopen.c
+++ b/fs/fsopen.c
@@ -25,7 +25,7 @@ static ssize_t fscontext_read(struct file *file,
char