prt_str(out, ", continuing");
ret = -BCH_ERR_fsck_ignore;
}
- } else if (c->opts.fix_errors == FSCK_OPT_EXIT) {
+ } else if (c->opts.fix_errors == FSCK_FIX_exit) {
prt_str(out, ", exiting");
ret = -BCH_ERR_fsck_errors_not_fixed;
} else if (flags & FSCK_CAN_FIX) {
? s->fix
: c->opts.fix_errors;
- if (fix == FSCK_OPT_ASK) {
+ if (fix == FSCK_FIX_ask) {
int ask;
prt_str(out, ": fix?");
if (ask >= YN_ALLNO && s)
s->fix = ask == YN_ALLNO
- ? FSCK_OPT_NO
- : FSCK_OPT_YES;
+ ? FSCK_FIX_no
+ : FSCK_FIX_yes;
ret = ask & 1
? -BCH_ERR_fsck_fix
: -BCH_ERR_fsck_ignore;
- } else if (fix == FSCK_OPT_YES ||
+ } else if (fix == FSCK_FIX_yes ||
(c->opts.nochanges &&
!(flags & FSCK_CAN_IGNORE))) {
prt_str(out, ", fixing");
}
if (ret == -BCH_ERR_fsck_ignore &&
- (c->opts.fix_errors == FSCK_OPT_EXIT ||
+ (c->opts.fix_errors == FSCK_FIX_exit ||
!(flags & FSCK_CAN_IGNORE)))
ret = -BCH_ERR_fsck_errors_not_fixed;
#include "bcachefs.h"
#include "compress.h"
#include "disk_groups.h"
+#include "error.h"
#include "opts.h"
#include "super-io.h"
#include "util.h"
NULL
};
+const char * const bch2_fsck_fix_opts[] = {
+ BCH_FIX_ERRORS_OPTS()
+ NULL
+};
+
const char * const bch2_version_upgrade_opts[] = {
BCH_VERSION_UPGRADE_OPTS()
NULL
#undef x
+static int bch2_opt_fix_errors_parse(struct bch_fs *c, const char *val, u64 *res,
+ struct printbuf *err)
+{
+ if (!val) {
+ *res = FSCK_FIX_yes;
+ } else {
+ int ret = match_string(bch2_fsck_fix_opts, -1, val);
+
+ if (ret < 0 && err)
+ prt_str(err, "fix_errors: invalid selection");
+ if (ret < 0)
+ return ret;
+ *res = ret;
+ }
+
+ return 0;
+}
+
+static void bch2_opt_fix_errors_to_text(struct printbuf *out,
+ struct bch_fs *c,
+ struct bch_sb *sb,
+ u64 v)
+{
+ prt_str(out, bch2_fsck_fix_opts[v]);
+}
+
+static const struct bch_opt_fn bch2_opt_fix_errors = {
+ .parse = bch2_opt_fix_errors_parse,
+ .to_text = bch2_opt_fix_errors_to_text,
+};
+
const char * const bch2_d_types[BCH_DT_MAX] = {
[DT_UNKNOWN] = "unknown",
[DT_FIFO] = "fifo",
switch (opt->type) {
case BCH_OPT_BOOL:
- ret = kstrtou64(val, 10, res);
+ if (val) {
+ ret = kstrtou64(val, 10, res);
+ } else {
+ ret = 0;
+ *res = 1;
+ }
+
if (ret < 0 || (*res != 0 && *res != 1)) {
if (err)
- prt_printf(err, "%s: must be bool",
- opt->attr.name);
+ prt_printf(err, "%s: must be bool", opt->attr.name);
return ret;
}
break;
case BCH_OPT_UINT:
+ if (!val) {
+ prt_printf(err, "%s: required value",
+ opt->attr.name);
+ return -EINVAL;
+ }
+
ret = opt->flags & OPT_HUMAN_READABLE
? bch2_strtou64_h(val, res)
: kstrtou64(val, 10, res);
}
break;
case BCH_OPT_STR:
+ if (!val) {
+ prt_printf(err, "%s: required value",
+ opt->attr.name);
+ return -EINVAL;
+ }
+
ret = match_string(opt->choices, -1, val);
if (ret < 0) {
if (err)
if (flags & OPT_SHOW_FULL_LIST)
prt_string_option(out, opt->choices, v);
else
- prt_printf(out, "%s", opt->choices[v]);
+ prt_str(out, opt->choices[v]);
break;
case BCH_OPT_FN:
opt->fn.to_text(out, c, sb, v);
name = strsep(&opt, "=");
val = opt;
- if (val) {
- id = bch2_mount_opt_lookup(name);
- if (id < 0)
- goto bad_opt;
+ id = bch2_mount_opt_lookup(name);
- ret = bch2_opt_parse(c, &bch2_opt_table[id], val, &v, &err);
- if (ret < 0)
- goto bad_val;
- } else {
- id = bch2_mount_opt_lookup(name);
- v = 1;
-
- if (id < 0 &&
- !strncmp("no", name, 2)) {
- id = bch2_mount_opt_lookup(name + 2);
- v = 0;
- }
-
- if (id < 0)
- goto bad_opt;
-
- if (bch2_opt_table[id].type != BCH_OPT_BOOL)
- goto no_val;
+ /* Check for the form "noopt", negation of a boolean opt: */
+ if (id < 0 &&
+ !val &&
+ !strncmp("no", name, 2)) {
+ id = bch2_mount_opt_lookup(name + 2);
+ val = "0";
}
+ if (id < 0)
+ goto bad_opt;
+
if (!(bch2_opt_table[id].flags & OPT_MOUNT))
goto bad_opt;
!IS_ENABLED(CONFIG_BCACHEFS_QUOTA))
goto bad_opt;
+ ret = bch2_opt_parse(c, &bch2_opt_table[id], val, &v, &err);
+ if (ret < 0)
+ goto bad_val;
+
bch2_opt_set_by_id(opts, id, v);
}
pr_err("Invalid mount option %s", err.buf);
ret = -1;
goto out;
-no_val:
- pr_err("Mount option %s requires a value", name);
- ret = -1;
- goto out;
out:
kfree(copied_opts_start);
printbuf_exit(&err);
struct bch_fs;
extern const char * const bch2_error_actions[];
+extern const char * const bch2_fsck_fix_opts[];
extern const char * const bch2_version_upgrade_opts[];
extern const char * const bch2_sb_features[];
extern const char * const bch2_sb_compat[];
#define BCACHEFS_VERBOSE_DEFAULT false
#endif
+#define BCH_FIX_ERRORS_OPTS() \
+ x(exit, 0) \
+ x(yes, 1) \
+ x(no, 2) \
+ x(ask, 3)
+
+enum fsck_err_opts {
+#define x(t, n) FSCK_FIX_##t,
+ BCH_FIX_ERRORS_OPTS()
+#undef x
+};
+
#define BCH_OPTS() \
x(block_size, u16, \
OPT_FS|OPT_FORMAT| \
NULL, "Run fsck on mount") \
x(fix_errors, u8, \
OPT_FS|OPT_MOUNT, \
- OPT_BOOL(), \
- BCH2_NO_SB_OPT, false, \
+ OPT_FN(bch2_opt_fix_errors), \
+ BCH2_NO_SB_OPT, FSCK_FIX_exit, \
NULL, "Fix errors during fsck without asking") \
x(ratelimit_errors, u8, \
OPT_FS|OPT_MOUNT, \