summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKent Overstreet <kent.overstreet@linux.dev>2023-07-12 06:47:29 +0300
committerKent Overstreet <kent.overstreet@linux.dev>2023-10-23 00:10:07 +0300
commita0f8faea5f47d6e18253225e8f2f88cdc49d27d8 (patch)
treecf2b0b930c403173fc70e39313fd4d1348cf428c
parent9f343e24f541bef3d5f081925eae5734c2c39c28 (diff)
downloadlinux-a0f8faea5f47d6e18253225e8f2f88cdc49d27d8.tar.xz
bcachefs: fix_errors option is now a proper enum
Before, it was parsed as a bool but internally it was really an enum: this lets us pass in all the possible values. But we special case the option parsing: no supplied value is parsed as FSCK_FIX_yes, to match the previous behaviour. Signed-off-by: Kent Overstreet <kent.overstreet@linux.dev>
-rw-r--r--fs/bcachefs/btree_gc.c2
-rw-r--r--fs/bcachefs/error.c12
-rw-r--r--fs/bcachefs/error.h7
-rw-r--r--fs/bcachefs/opts.c102
-rw-r--r--fs/bcachefs/opts.h17
-rw-r--r--fs/bcachefs/recovery.c2
6 files changed, 95 insertions, 47 deletions
diff --git a/fs/bcachefs/btree_gc.c b/fs/bcachefs/btree_gc.c
index 6000b09dec26..edea6bb66253 100644
--- a/fs/bcachefs/btree_gc.c
+++ b/fs/bcachefs/btree_gc.c
@@ -1808,7 +1808,7 @@ again:
if (IS_ENABLED(CONFIG_BCACHEFS_DEBUG) ||
(BCH_SB_HAS_TOPOLOGY_ERRORS(c->disk_sb.sb) &&
c->curr_recovery_pass <= BCH_RECOVERY_PASS_check_allocations &&
- c->opts.fix_errors != FSCK_OPT_NO)) {
+ c->opts.fix_errors != FSCK_FIX_no)) {
bch_info(c, "Starting topology repair pass");
ret = bch2_repair_topology(c);
if (ret)
diff --git a/fs/bcachefs/error.c b/fs/bcachefs/error.c
index b08cd23dee00..685464b8cce3 100644
--- a/fs/bcachefs/error.c
+++ b/fs/bcachefs/error.c
@@ -204,7 +204,7 @@ int bch2_fsck_err(struct bch_fs *c, unsigned flags, const char *fmt, ...)
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) {
@@ -212,7 +212,7 @@ int bch2_fsck_err(struct bch_fs *c, unsigned flags, const char *fmt, ...)
? s->fix
: c->opts.fix_errors;
- if (fix == FSCK_OPT_ASK) {
+ if (fix == FSCK_FIX_ask) {
int ask;
prt_str(out, ": fix?");
@@ -223,13 +223,13 @@ int bch2_fsck_err(struct bch_fs *c, unsigned flags, const char *fmt, ...)
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");
@@ -244,7 +244,7 @@ int bch2_fsck_err(struct bch_fs *c, unsigned flags, const char *fmt, ...)
}
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;
diff --git a/fs/bcachefs/error.h b/fs/bcachefs/error.h
index edf12443822c..7ce9540052e5 100644
--- a/fs/bcachefs/error.h
+++ b/fs/bcachefs/error.h
@@ -91,13 +91,6 @@ do { \
* be able to repair:
*/
-enum fsck_err_opts {
- FSCK_OPT_EXIT,
- FSCK_OPT_YES,
- FSCK_OPT_NO,
- FSCK_OPT_ASK,
-};
-
struct fsck_err_state {
struct list_head list;
const char *fmt;
diff --git a/fs/bcachefs/opts.c b/fs/bcachefs/opts.c
index 96c2f3c2fbce..56f586f8d25b 100644
--- a/fs/bcachefs/opts.c
+++ b/fs/bcachefs/opts.c
@@ -5,6 +5,7 @@
#include "bcachefs.h"
#include "compress.h"
#include "disk_groups.h"
+#include "error.h"
#include "opts.h"
#include "super-io.h"
#include "util.h"
@@ -16,6 +17,11 @@ const char * const bch2_error_actions[] = {
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
@@ -89,6 +95,37 @@ const char * const bch2_fs_usage_types[] = {
#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",
@@ -265,15 +302,26 @@ int bch2_opt_parse(struct bch_fs *c,
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);
@@ -285,6 +333,12 @@ int bch2_opt_parse(struct bch_fs *c,
}
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)
@@ -336,7 +390,7 @@ void bch2_opt_to_text(struct printbuf *out,
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);
@@ -400,31 +454,19 @@ int bch2_parse_mount_opts(struct bch_fs *c, struct bch_opts *opts,
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;
@@ -437,6 +479,10 @@ int bch2_parse_mount_opts(struct bch_fs *c, struct bch_opts *opts,
!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);
}
@@ -451,10 +497,6 @@ bad_val:
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);
diff --git a/fs/bcachefs/opts.h b/fs/bcachefs/opts.h
index 3be5095aa472..92e2e5e759d9 100644
--- a/fs/bcachefs/opts.h
+++ b/fs/bcachefs/opts.h
@@ -11,6 +11,7 @@
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[];
@@ -105,6 +106,18 @@ struct bch_opt_fn {
#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| \
@@ -325,8 +338,8 @@ struct bch_opt_fn {
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, \
diff --git a/fs/bcachefs/recovery.c b/fs/bcachefs/recovery.c
index c46297bd1cf9..63b385d8886a 100644
--- a/fs/bcachefs/recovery.c
+++ b/fs/bcachefs/recovery.c
@@ -1175,7 +1175,7 @@ static void check_version_upgrade(struct bch_fs *c)
prt_str(&buf, "fsck required");
c->recovery_passes_explicit |= recovery_passes;
- c->opts.fix_errors = FSCK_OPT_YES;
+ c->opts.fix_errors = FSCK_FIX_yes;
}
bch_info(c, "%s", buf.buf);