diff options
Diffstat (limited to 'libbcache/opts.c')
-rw-r--r-- | libbcache/opts.c | 179 |
1 files changed, 179 insertions, 0 deletions
diff --git a/libbcache/opts.c b/libbcache/opts.c new file mode 100644 index 00000000..249dd5d9 --- /dev/null +++ b/libbcache/opts.c @@ -0,0 +1,179 @@ + +#include <linux/kernel.h> + +#include "opts.h" +#include "util.h" + +const char * const bch_bool_opt[] = { + "0", + "1", + NULL +}; + +const char * const bch_uint_opt[] = { + NULL +}; + +const char * const bch_error_actions[] = { + "continue", + "remount-ro", + "panic", + NULL +}; + +const char * const bch_csum_types[] = { + "none", + "crc32c", + "crc64", + NULL +}; + +const char * const bch_compression_types[] = { + "none", + "lz4", + "gzip", + NULL +}; + +const char * const bch_str_hash_types[] = { + "crc32c", + "crc64", + "siphash", + "sha1", + NULL +}; + +enum bch_opts { +#define CACHE_SET_OPT(_name, _choices, _min, _max, _sb_opt, _perm) \ + Opt_##_name, + + CACHE_SET_VISIBLE_OPTS() +#undef CACHE_SET_OPT + + Opt_bad_opt, +}; + +struct bch_option { + const char *name; + const char * const *opts; + unsigned long min, max; +}; + +struct bch_opt_result { + enum bch_opts opt; + unsigned val; +}; + +static int parse_bool_opt(const struct bch_option *opt, const char *s) +{ + if (!strcmp(opt->name, s)) + return true; + + if (!strncmp("no", s, 2) && !strcmp(opt->name, s + 2)) + return false; + + return -1; +} + +static int parse_uint_opt(const struct bch_option *opt, const char *s) +{ + unsigned long v; + int ret; + + if (strncmp(opt->name, s, strlen(opt->name))) + return -1; + + s += strlen(opt->name); + + if (*s != '=') + return -1; + + s++; + + ret = kstrtoul(s, 10, &v); + if (ret) + return ret; + + if (v < opt->min || v >= opt->max) + return -ERANGE; + + return 0; +} + +static int parse_string_opt(const struct bch_option *opt, const char *s) +{ + if (strncmp(opt->name, s, strlen(opt->name))) + return -1; + + s += strlen(opt->name); + + if (*s != '=') + return -1; + + s++; + + return bch_read_string_list(s, opt->opts); +} + +static struct bch_opt_result parse_one_opt(const char *opt) +{ + static const struct bch_option opt_table[] = { +#define CACHE_SET_OPT(_name, _choices, _min, _max, _sb_opt, _perm) \ + [Opt_##_name] = { \ + .name = #_name, \ + .opts = _choices, \ + .min = _min, \ + .max = _max, \ + }, + CACHE_SET_VISIBLE_OPTS() +#undef CACHE_SET_OPT + }, *i; + + for (i = opt_table; + i < opt_table + ARRAY_SIZE(opt_table); + i++) { + int res = i->opts == bch_bool_opt ? parse_bool_opt(i, opt) + : i->opts == bch_uint_opt ? parse_uint_opt(i, opt) + : parse_string_opt(i, opt); + + if (res >= 0) + return (struct bch_opt_result) { + i - opt_table, res + }; + } + + return (struct bch_opt_result) { Opt_bad_opt }; +} + +int bch_parse_options(struct cache_set_opts *opts, int flags, char *options) +{ + char *p; + + *opts = cache_set_opts_empty(); + + opts->read_only = (flags & MS_RDONLY) != 0; + + if (!options) + return 0; + + while ((p = strsep(&options, ",")) != NULL) { + struct bch_opt_result res = parse_one_opt(p); + + switch (res.opt) { +#define CACHE_SET_OPT(_name, _choices, _min, _max, _sb_opt, _perm) \ + case Opt_##_name: \ + opts->_name = res.val; \ + break; + + CACHE_SET_VISIBLE_OPTS() +#undef CACHE_SET_OPT + + case Opt_bad_opt: + return -EINVAL; + default: + BUG(); + } + } + + return 0; +} |