]> git.sesse.net Git - bcachefs-tools-debian/blobdiff - libbcachefs/opts.c
Fix building on musl
[bcachefs-tools-debian] / libbcachefs / opts.c
index eae63cf82c4042df063f28bce4c4e92c9b6b5e83..94d6c044a27daa935ed9dec7c01c2456fcdc20fa 100644 (file)
@@ -1,7 +1,12 @@
+// SPDX-License-Identifier: GPL-2.0
 
 #include <linux/kernel.h>
 
+#include "bcachefs.h"
+#include "compress.h"
+#include "disk_groups.h"
 #include "opts.h"
+#include "super-io.h"
 #include "util.h"
 
 const char * const bch2_error_actions[] = {
@@ -11,17 +16,24 @@ const char * const bch2_error_actions[] = {
        NULL
 };
 
-const char * const bch2_csum_types[] = {
+const char * const bch2_sb_features[] = {
+#define x(f, n) #f,
+       BCH_SB_FEATURES()
+#undef x
+       NULL
+};
+
+const char * const bch2_csum_opts[] = {
        "none",
        "crc32c",
        "crc64",
        NULL
 };
 
-const char * const bch2_compression_types[] = {
-       "none",
-       "lz4",
-       "gzip",
+const char * const bch2_compression_opts[] = {
+#define x(t, n) #t,
+       BCH_COMPRESSION_OPTS()
+#undef x
        NULL
 };
 
@@ -69,22 +81,22 @@ const char * const bch2_dev_state[] = {
 
 void bch2_opts_apply(struct bch_opts *dst, struct bch_opts src)
 {
-#define BCH_OPT(_name, ...)                                            \
+#define x(_name, ...)                                          \
        if (opt_defined(src, _name))                                    \
                opt_set(*dst, _name, src._name);
 
        BCH_OPTS()
-#undef BCH_OPT
+#undef x
 }
 
 bool bch2_opt_defined_by_id(const struct bch_opts *opts, enum bch_opt_id id)
 {
        switch (id) {
-#define BCH_OPT(_name, ...)                                            \
+#define x(_name, ...)                                          \
        case Opt_##_name:                                               \
                return opt_defined(*opts, _name);
        BCH_OPTS()
-#undef BCH_OPT
+#undef x
        default:
                BUG();
        }
@@ -93,11 +105,11 @@ bool bch2_opt_defined_by_id(const struct bch_opts *opts, enum bch_opt_id id)
 u64 bch2_opt_get_by_id(const struct bch_opts *opts, enum bch_opt_id id)
 {
        switch (id) {
-#define BCH_OPT(_name, ...)                                            \
+#define x(_name, ...)                                          \
        case Opt_##_name:                                               \
                return opts->_name;
        BCH_OPTS()
-#undef BCH_OPT
+#undef x
        default:
                BUG();
        }
@@ -106,12 +118,12 @@ u64 bch2_opt_get_by_id(const struct bch_opts *opts, enum bch_opt_id id)
 void bch2_opt_set_by_id(struct bch_opts *opts, enum bch_opt_id id, u64 v)
 {
        switch (id) {
-#define BCH_OPT(_name, ...)                                            \
+#define x(_name, ...)                                          \
        case Opt_##_name:                                               \
                opt_set(*opts, _name, v);                               \
                break;
        BCH_OPTS()
-#undef BCH_OPT
+#undef x
        default:
                BUG();
        }
@@ -125,11 +137,11 @@ struct bch_opts bch2_opts_from_sb(struct bch_sb *sb)
 {
        struct bch_opts opts = bch2_opts_empty();
 
-#define BCH_OPT(_name, _bits, _mode, _type, _sb_opt, _default)         \
+#define x(_name, _bits, _mode, _type, _sb_opt, ...)                    \
        if (_sb_opt != NO_SB_OPT)                                       \
                opt_set(opts, _name, _sb_opt(sb));
        BCH_OPTS()
-#undef BCH_OPT
+#undef x
 
        return opts;
 }
@@ -137,21 +149,27 @@ struct bch_opts bch2_opts_from_sb(struct bch_sb *sb)
 const struct bch_option bch2_opt_table[] = {
 #define OPT_BOOL()             .type = BCH_OPT_BOOL
 #define OPT_UINT(_min, _max)   .type = BCH_OPT_UINT, .min = _min, .max = _max
+#define OPT_SECTORS(_min, _max)        .type = BCH_OPT_SECTORS, .min = _min, .max = _max
 #define OPT_STR(_choices)      .type = BCH_OPT_STR, .choices = _choices
+#define OPT_FN(_fn)            .type = BCH_OPT_FN,                     \
+                               .parse = _fn##_parse,                   \
+                               .to_text = _fn##_to_text
 
-#define BCH_OPT(_name, _bits, _mode, _type, _sb_opt, _default)         \
+#define x(_name, _bits, _mode, _type, _sb_opt, _default, _hint, _help) \
        [Opt_##_name] = {                                               \
                .attr   = {                                             \
                        .name   = #_name,                               \
-                       .mode = _mode == OPT_RUNTIME ? 0644 : 0444,     \
+                       .mode = (_mode) & OPT_RUNTIME ? 0644 : 0444,    \
                },                                                      \
                .mode   = _mode,                                        \
+               .hint   = _hint,                                        \
+               .help   = _help,                                        \
                .set_sb = SET_##_sb_opt,                                \
                _type                                                   \
        },
 
        BCH_OPTS()
-#undef BCH_OPT
+#undef x
 };
 
 int bch2_opt_lookup(const char *name)
@@ -188,7 +206,8 @@ static int bch2_mount_opt_lookup(const char *name)
        return bch2_opt_lookup(name);
 }
 
-int bch2_opt_parse(const struct bch_option *opt, const char *val, u64 *res)
+int bch2_opt_parse(struct bch_fs *c, const struct bch_option *opt,
+                  const char *val, u64 *res)
 {
        ssize_t ret;
 
@@ -206,16 +225,104 @@ int bch2_opt_parse(const struct bch_option *opt, const char *val, u64 *res)
                if (ret < 0)
                        return ret;
 
+               if (*res < opt->min || *res >= opt->max)
+                       return -ERANGE;
+               break;
+       case BCH_OPT_SECTORS:
+               ret = bch2_strtou64_h(val, res);
+               if (ret < 0)
+                       return ret;
+
+               if (*res & 511)
+                       return -EINVAL;
+
+               *res >>= 9;
+
                if (*res < opt->min || *res >= opt->max)
                        return -ERANGE;
                break;
        case BCH_OPT_STR:
-               ret = bch2_read_string_list(val, opt->choices);
+               ret = match_string(opt->choices, -1, val);
                if (ret < 0)
                        return ret;
 
                *res = ret;
                break;
+       case BCH_OPT_FN:
+               if (!c)
+                       return -EINVAL;
+
+               return opt->parse(c, val, res);
+       }
+
+       return 0;
+}
+
+void bch2_opt_to_text(struct printbuf *out, struct bch_fs *c,
+                     const struct bch_option *opt, u64 v,
+                     unsigned flags)
+{
+       if (flags & OPT_SHOW_MOUNT_STYLE) {
+               if (opt->type == BCH_OPT_BOOL) {
+                       pr_buf(out, "%s%s",
+                              v ? "" : "no",
+                              opt->attr.name);
+                       return;
+               }
+
+               pr_buf(out, "%s=", opt->attr.name);
+       }
+
+       switch (opt->type) {
+       case BCH_OPT_BOOL:
+       case BCH_OPT_UINT:
+               pr_buf(out, "%lli", v);
+               break;
+       case BCH_OPT_SECTORS:
+               bch2_hprint(out, v);
+               break;
+       case BCH_OPT_STR:
+               if (flags & OPT_SHOW_FULL_LIST)
+                       bch2_string_opt_to_text(out, opt->choices, v);
+               else
+                       pr_buf(out, opt->choices[v]);
+               break;
+       case BCH_OPT_FN:
+               opt->to_text(out, c, v);
+               break;
+       default:
+               BUG();
+       }
+}
+
+int bch2_opt_check_may_set(struct bch_fs *c, int id, u64 v)
+{
+       int ret = 0;
+
+       switch (id) {
+       case Opt_compression:
+       case Opt_background_compression:
+               ret = bch2_check_set_has_compressed_data(c, v);
+               break;
+       case Opt_erasure_code:
+               if (v)
+                       bch2_check_set_feature(c, BCH_FEATURE_ec);
+               break;
+       }
+
+       return ret;
+}
+
+int bch2_opts_check_may_set(struct bch_fs *c)
+{
+       unsigned i;
+       int ret;
+
+       for (i = 0; i < bch2_opts_nr; i++) {
+               ret = bch2_opt_check_may_set(c, i,
+                               bch2_opt_get_by_id(&c->opts, i));
+               if (ret)
+                       return ret;
        }
 
        return 0;
@@ -236,7 +343,7 @@ int bch2_parse_mount_opts(struct bch_opts *opts, char *options)
                        if (id < 0)
                                goto bad_opt;
 
-                       ret = bch2_opt_parse(&bch2_opt_table[id], val, &v);
+                       ret = bch2_opt_parse(NULL, &bch2_opt_table[id], val, &v);
                        if (ret < 0)
                                goto bad_val;
                } else {
@@ -256,7 +363,7 @@ int bch2_parse_mount_opts(struct bch_opts *opts, char *options)
                                goto no_val;
                }
 
-               if (bch2_opt_table[id].mode < OPT_MOUNT)
+               if (!(bch2_opt_table[id].mode & OPT_MOUNT))
                        goto bad_opt;
 
                if (id == Opt_acl &&
@@ -288,40 +395,40 @@ no_val:
 struct bch_io_opts bch2_opts_to_inode_opts(struct bch_opts src)
 {
        struct bch_io_opts ret = { 0 };
-#define BCH_INODE_OPT(_name, _bits)                                    \
+#define x(_name, _bits)                                        \
        if (opt_defined(src, _name))                                    \
                opt_set(ret, _name, src._name);
        BCH_INODE_OPTS()
-#undef BCH_INODE_OPT
+#undef x
        return ret;
 }
 
 struct bch_opts bch2_inode_opts_to_opts(struct bch_io_opts src)
 {
        struct bch_opts ret = { 0 };
-#define BCH_INODE_OPT(_name, _bits)                                    \
+#define x(_name, _bits)                                        \
        if (opt_defined(src, _name))                                    \
                opt_set(ret, _name, src._name);
        BCH_INODE_OPTS()
-#undef BCH_INODE_OPT
+#undef x
        return ret;
 }
 
 void bch2_io_opts_apply(struct bch_io_opts *dst, struct bch_io_opts src)
 {
-#define BCH_INODE_OPT(_name, _bits)                                    \
+#define x(_name, _bits)                                        \
        if (opt_defined(src, _name))                                    \
                opt_set(*dst, _name, src._name);
        BCH_INODE_OPTS()
-#undef BCH_INODE_OPT
+#undef x
 }
 
 bool bch2_opt_is_inode_opt(enum bch_opt_id id)
 {
        static const enum bch_opt_id inode_opt_list[] = {
-#define BCH_INODE_OPT(_name, _bits)    Opt_##_name,
+#define x(_name, _bits)        Opt_##_name,
        BCH_INODE_OPTS()
-#undef BCH_INODE_OPT
+#undef x
        };
        unsigned i;