bcachefs: Improve opts.degraded

Kill 'opts.very_degraded', and make 'opts.degraded' a persistent option,
stored in the superblock.

It's now an enum, with available choices ask/yes/very/no.

"ask" mode will be handled by the mount helper, for prompting the user
(on a machine used interactively) for whether to do a degraded mount.

Signed-off-by: Kent Overstreet <kent.overstreet@linux.dev>
This commit is contained in:
Kent Overstreet 2025-04-06 13:50:20 -04:00
parent 2758c28aca
commit ef8dd631f7
5 changed files with 77 additions and 34 deletions

View File

@ -867,6 +867,7 @@ LE64_BITMASK(BCH_SB_VERSION_INCOMPAT_ALLOWED,
LE64_BITMASK(BCH_SB_SHARD_INUMS_NBITS, struct bch_sb, flags[6], 0, 4);
LE64_BITMASK(BCH_SB_WRITE_ERROR_TIMEOUT,struct bch_sb, flags[6], 4, 14);
LE64_BITMASK(BCH_SB_CSUM_ERR_RETRY_NR, struct bch_sb, flags[6], 14, 20);
LE64_BITMASK(BCH_SB_DEGRADED_ACTION, struct bch_sb, flags[6], 20, 22);
LE64_BITMASK(BCH_SB_CASEFOLD, struct bch_sb, flags[6], 22, 23);
static inline __u64 BCH_SB_COMPRESSION_TYPE(const struct bch_sb *sb)
@ -989,6 +990,19 @@ enum bch_error_actions {
BCH_ON_ERROR_NR
};
#define BCH_DEGRADED_ACTIONS() \
x(ask, 0) \
x(yes, 1) \
x(very, 2) \
x(no, 3)
enum bch_degraded_actions {
#define x(t, n) BCH_DEGRADED_##t = n,
BCH_DEGRADED_ACTIONS()
#undef x
BCH_DEGRADED_ACTIONS_NR
};
#define BCH_STR_HASH_TYPES() \
x(crc32c, 0) \
x(crc64, 1) \

View File

@ -19,6 +19,11 @@ const char * const bch2_error_actions[] = {
NULL
};
const char * const bch2_degraded_actions[] = {
BCH_DEGRADED_ACTIONS()
NULL
};
const char * const bch2_fsck_fix_opts[] = {
BCH_FIX_ERRORS_OPTS()
NULL
@ -273,20 +278,20 @@ int bch2_opt_lookup(const char *name)
return -1;
}
struct synonym {
struct opt_synonym {
const char *s1, *s2;
};
static const struct synonym bch_opt_synonyms[] = {
static const struct opt_synonym bch2_opt_synonyms[] = {
{ "quota", "usrquota" },
};
static int bch2_mount_opt_lookup(const char *name)
{
const struct synonym *i;
const struct opt_synonym *i;
for (i = bch_opt_synonyms;
i < bch_opt_synonyms + ARRAY_SIZE(bch_opt_synonyms);
for (i = bch2_opt_synonyms;
i < bch2_opt_synonyms + ARRAY_SIZE(bch2_opt_synonyms);
i++)
if (!strcmp(name, i->s1))
name = i->s2;
@ -294,6 +299,30 @@ static int bch2_mount_opt_lookup(const char *name)
return bch2_opt_lookup(name);
}
struct opt_val_synonym {
const char *opt, *v1, *v2;
};
static const struct opt_val_synonym bch2_opt_val_synonyms[] = {
{ "degraded", "true", "yes" },
{ "degraded", "false", "no" },
{ "degraded", "1", "yes" },
{ "degraded", "0", "no" },
};
static const char *bch2_opt_val_synonym_lookup(const char *opt, const char *val)
{
const struct opt_val_synonym *i;
for (i = bch2_opt_val_synonyms;
i < bch2_opt_val_synonyms + ARRAY_SIZE(bch2_opt_val_synonyms);
i++)
if (!strcmp(opt, i->opt) && !strcmp(val, i->v1))
return i->v2;
return val;
}
int bch2_opt_validate(const struct bch_option *opt, u64 v, struct printbuf *err)
{
if (v < opt->min) {
@ -342,19 +371,17 @@ int bch2_opt_parse(struct bch_fs *c,
switch (opt->type) {
case BCH_OPT_BOOL:
if (val) {
ret = lookup_constant(bool_names, val, -BCH_ERR_option_not_bool);
if (ret != -BCH_ERR_option_not_bool) {
*res = ret;
} else {
if (err)
prt_printf(err, "%s: must be bool", opt->attr.name);
return ret;
}
} else {
*res = 1;
}
if (!val)
val = "1";
ret = lookup_constant(bool_names, val, -BCH_ERR_option_not_bool);
if (ret != -BCH_ERR_option_not_bool) {
*res = ret;
} else {
if (err)
prt_printf(err, "%s: must be bool", opt->attr.name);
return ret;
}
break;
case BCH_OPT_UINT:
if (!val) {
@ -545,6 +572,12 @@ int bch2_parse_one_mount_opt(struct bch_fs *c, struct bch_opts *opts,
if (id < 0)
return 0;
/* must have a value for synonym lookup - but OPT_FN is weird */
if (!val && bch2_opt_table[id].type != BCH_OPT_FN)
val = "1";
val = bch2_opt_val_synonym_lookup(name, val);
if (!(bch2_opt_table[id].flags & OPT_MOUNT))
goto bad_opt;

View File

@ -11,6 +11,7 @@
struct bch_fs;
extern const char * const bch2_error_actions[];
extern const char * const bch2_degraded_actions[];
extern const char * const bch2_fsck_fix_opts[];
extern const char * const bch2_version_upgrade_opts[];
extern const char * const bch2_sb_features[];
@ -307,14 +308,9 @@ enum fsck_err_opts {
NULL, "Enable project quotas") \
x(degraded, u8, \
OPT_FS|OPT_MOUNT, \
OPT_BOOL(), \
BCH2_NO_SB_OPT, false, \
OPT_STR(bch2_degraded_actions), \
BCH_SB_DEGRADED_ACTION, BCH_DEGRADED_ask, \
NULL, "Allow mounting in degraded mode") \
x(very_degraded, u8, \
OPT_FS|OPT_MOUNT, \
OPT_BOOL(), \
BCH2_NO_SB_OPT, false, \
NULL, "Allow mounting in when data will be missing") \
x(no_splitbrain_check, u8, \
OPT_FS|OPT_MOUNT, \
OPT_BOOL(), \

View File

@ -1022,7 +1022,7 @@ int bch2_write_super(struct bch_fs *c)
trace_and_count(c, write_super, c, _RET_IP_);
if (c->opts.very_degraded)
if (c->opts.degraded == BCH_DEGRADED_very)
degraded_flags |= BCH_FORCE_IF_LOST;
lockdep_assert_held(&c->sb_lock);

View File

@ -1040,19 +1040,18 @@ static void print_mount_opts(struct bch_fs *c)
static bool bch2_fs_may_start(struct bch_fs *c)
{
struct bch_dev *ca;
unsigned i, flags = 0;
unsigned flags = 0;
if (c->opts.very_degraded)
switch (c->opts.degraded) {
case BCH_DEGRADED_very:
flags |= BCH_FORCE_IF_DEGRADED|BCH_FORCE_IF_LOST;
if (c->opts.degraded)
break;
case BCH_DEGRADED_yes:
flags |= BCH_FORCE_IF_DEGRADED;
if (!c->opts.degraded &&
!c->opts.very_degraded) {
break;
default:
mutex_lock(&c->sb_lock);
for (i = 0; i < c->disk_sb.sb->nr_devices; i++) {
for (unsigned i = 0; i < c->disk_sb.sb->nr_devices; i++) {
if (!bch2_member_exists(c->disk_sb.sb, i))
continue;
@ -1066,6 +1065,7 @@ static bool bch2_fs_may_start(struct bch_fs *c)
}
}
mutex_unlock(&c->sb_lock);
break;
}
return bch2_have_enough_devs(c, bch2_online_devs(c), flags, true);