2017-01-08 12:13:18 +03:00
|
|
|
|
|
|
|
#include <linux/kernel.h>
|
|
|
|
|
|
|
|
#include "opts.h"
|
|
|
|
#include "util.h"
|
|
|
|
|
|
|
|
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
|
|
|
|
};
|
|
|
|
|
2017-02-02 06:16:42 +03:00
|
|
|
const char * const bch_cache_replacement_policies[] = {
|
|
|
|
"lru",
|
|
|
|
"fifo",
|
|
|
|
"random",
|
|
|
|
NULL
|
|
|
|
};
|
|
|
|
|
|
|
|
/* Default is -1; we skip past it for struct cached_dev's cache mode */
|
|
|
|
const char * const bch_cache_modes[] = {
|
|
|
|
"default",
|
|
|
|
"writethrough",
|
|
|
|
"writeback",
|
|
|
|
"writearound",
|
|
|
|
"none",
|
|
|
|
NULL
|
|
|
|
};
|
|
|
|
|
|
|
|
const char * const bch_cache_state[] = {
|
|
|
|
"active",
|
|
|
|
"readonly",
|
|
|
|
"failed",
|
|
|
|
"spare",
|
|
|
|
NULL
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
const char * const bch_bool_opt[] = {
|
|
|
|
"0",
|
|
|
|
"1",
|
|
|
|
NULL
|
|
|
|
};
|
|
|
|
|
|
|
|
const char * const bch_uint_opt[] = {
|
|
|
|
NULL
|
|
|
|
};
|
|
|
|
|
2017-01-08 12:13:18 +03:00
|
|
|
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;
|
|
|
|
}
|