Skip to content

Commit 8b16413

Browse files
author
Kent Overstreet
committed
bcachefs: bch_sb.recovery_passes_required
Add two new superblock fields. Since the main section of the superblock is now fully, we have to add a new variable length section for them - bch_sb_field_ext. - recovery_passes_requried: recovery passes that must be run on the next mount - errors_silent: errors that will be silently fixed These are to improve upgrading and dwongrading: these fields won't be cleared until after recovery successfully completes, so there won't be any issues with crashing partway through an upgrade or a downgrade. Signed-off-by: Kent Overstreet <kent.overstreet@linux.dev>
1 parent 808c680 commit 8b16413

File tree

9 files changed

+172
-30
lines changed

9 files changed

+172
-30
lines changed

fs/bcachefs/bcachefs.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -737,6 +737,7 @@ struct bch_fs {
737737
unsigned nsec_per_time_unit;
738738
u64 features;
739739
u64 compat;
740+
unsigned long errors_silent[BITS_TO_LONGS(BCH_SB_ERR_MAX)];
740741
} sb;
741742

742743

fs/bcachefs/bcachefs_format.h

Lines changed: 20 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1207,19 +1207,20 @@ struct bch_sb_field {
12071207
};
12081208

12091209
#define BCH_SB_FIELDS() \
1210-
x(journal, 0) \
1211-
x(members_v1, 1) \
1212-
x(crypt, 2) \
1213-
x(replicas_v0, 3) \
1214-
x(quota, 4) \
1215-
x(disk_groups, 5) \
1216-
x(clean, 6) \
1217-
x(replicas, 7) \
1218-
x(journal_seq_blacklist, 8) \
1219-
x(journal_v2, 9) \
1220-
x(counters, 10) \
1221-
x(members_v2, 11) \
1222-
x(errors, 12)
1210+
x(journal, 0) \
1211+
x(members_v1, 1) \
1212+
x(crypt, 2) \
1213+
x(replicas_v0, 3) \
1214+
x(quota, 4) \
1215+
x(disk_groups, 5) \
1216+
x(clean, 6) \
1217+
x(replicas, 7) \
1218+
x(journal_seq_blacklist, 8) \
1219+
x(journal_v2, 9) \
1220+
x(counters, 10) \
1221+
x(members_v2, 11) \
1222+
x(errors, 12) \
1223+
x(ext, 13)
12231224

12241225
enum bch_sb_field_type {
12251226
#define x(f, nr) BCH_SB_FIELD_##f = nr,
@@ -1631,6 +1632,12 @@ struct bch_sb_field_errors {
16311632
LE64_BITMASK(BCH_SB_ERROR_ENTRY_ID, struct bch_sb_field_error_entry, v, 0, 16);
16321633
LE64_BITMASK(BCH_SB_ERROR_ENTRY_NR, struct bch_sb_field_error_entry, v, 16, 64);
16331634

1635+
struct bch_sb_field_ext {
1636+
struct bch_sb_field field;
1637+
__le64 recovery_passes_required[2];
1638+
__le64 errors_silent[8];
1639+
};
1640+
16341641
/* Superblock: */
16351642

16361643
/*

fs/bcachefs/errcode.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -218,6 +218,7 @@
218218
x(BCH_ERR_invalid_sb, invalid_sb_quota) \
219219
x(BCH_ERR_invalid_sb, invalid_sb_errors) \
220220
x(BCH_ERR_invalid_sb, invalid_sb_opt_compression) \
221+
x(BCH_ERR_invalid_sb, invalid_sb_ext) \
221222
x(BCH_ERR_invalid, invalid_bkey) \
222223
x(BCH_ERR_operation_blocked, nocow_lock_blocked) \
223224
x(EIO, btree_node_read_err) \

fs/bcachefs/error.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -152,6 +152,9 @@ int bch2_fsck_err(struct bch_fs *c,
152152
struct printbuf buf = PRINTBUF, *out = &buf;
153153
int ret = -BCH_ERR_fsck_ignore;
154154

155+
if (test_bit(err, c->sb.errors_silent))
156+
return -BCH_ERR_fsck_fix;
157+
155158
bch2_sb_error_count(c, err);
156159

157160
va_start(args, fmt);

fs/bcachefs/recovery.c

Lines changed: 60 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -539,13 +539,12 @@ u64 bch2_recovery_passes_from_stable(u64 v)
539539
return ret;
540540
}
541541

542-
static void check_version_upgrade(struct bch_fs *c)
542+
static bool check_version_upgrade(struct bch_fs *c)
543543
{
544544
unsigned latest_compatible = bch2_latest_compatible_version(c->sb.version);
545545
unsigned latest_version = bcachefs_metadata_version_current;
546546
unsigned old_version = c->sb.version_upgrade_complete ?: c->sb.version;
547547
unsigned new_version = 0;
548-
u64 recovery_passes;
549548

550549
if (old_version < bcachefs_metadata_required_upgrade_below) {
551550
if (c->opts.version_upgrade == BCH_VERSION_UPGRADE_incompatible ||
@@ -589,7 +588,7 @@ static void check_version_upgrade(struct bch_fs *c)
589588
bch2_version_to_text(&buf, new_version);
590589
prt_newline(&buf);
591590

592-
recovery_passes = bch2_upgrade_recovery_passes(c, old_version, new_version);
591+
u64 recovery_passes = bch2_upgrade_recovery_passes(c, old_version, new_version);
593592
if (recovery_passes) {
594593
if ((recovery_passes & RECOVERY_PASS_ALL_FSCK) == RECOVERY_PASS_ALL_FSCK)
595594
prt_str(&buf, "fsck required");
@@ -604,12 +603,13 @@ static void check_version_upgrade(struct bch_fs *c)
604603

605604
bch_info(c, "%s", buf.buf);
606605

607-
mutex_lock(&c->sb_lock);
608606
bch2_sb_upgrade(c, new_version);
609-
mutex_unlock(&c->sb_lock);
610607

611608
printbuf_exit(&buf);
609+
return true;
612610
}
611+
612+
return false;
613613
}
614614

615615
u64 bch2_fsck_recovery_passes(void)
@@ -684,7 +684,6 @@ int bch2_fs_recovery(struct bch_fs *c)
684684
struct bch_sb_field_clean *clean = NULL;
685685
struct jset *last_journal_entry = NULL;
686686
u64 last_seq = 0, blacklist_seq, journal_seq;
687-
bool write_sb = false;
688687
int ret = 0;
689688

690689
if (c->sb.clean) {
@@ -712,15 +711,52 @@ int bch2_fs_recovery(struct bch_fs *c)
712711
goto err;
713712
}
714713

715-
if (c->opts.fsck || !(c->opts.nochanges && c->opts.norecovery))
716-
check_version_upgrade(c);
717-
718714
if (c->opts.fsck && c->opts.norecovery) {
719715
bch_err(c, "cannot select both norecovery and fsck");
720716
ret = -EINVAL;
721717
goto err;
722718
}
723719

720+
if (!(c->opts.nochanges && c->opts.norecovery)) {
721+
mutex_lock(&c->sb_lock);
722+
bool write_sb = false;
723+
724+
struct bch_sb_field_ext *ext =
725+
bch2_sb_field_get_minsize(&c->disk_sb, ext, sizeof(*ext) / sizeof(u64));
726+
if (!ext) {
727+
ret = -BCH_ERR_ENOSPC_sb;
728+
mutex_unlock(&c->sb_lock);
729+
goto err;
730+
}
731+
732+
if (BCH_SB_HAS_TOPOLOGY_ERRORS(c->disk_sb.sb)) {
733+
ext->recovery_passes_required[0] |=
734+
cpu_to_le64(bch2_recovery_passes_to_stable(BIT_ULL(BCH_RECOVERY_PASS_check_topology)));
735+
write_sb = true;
736+
}
737+
738+
u64 sb_passes = bch2_recovery_passes_from_stable(le64_to_cpu(ext->recovery_passes_required[0]));
739+
if (sb_passes) {
740+
struct printbuf buf = PRINTBUF;
741+
prt_str(&buf, "superblock requires following recovery passes to be run:\n ");
742+
prt_bitflags(&buf, bch2_recovery_passes, sb_passes);
743+
bch_info(c, "%s", buf.buf);
744+
printbuf_exit(&buf);
745+
}
746+
747+
if (check_version_upgrade(c))
748+
write_sb = true;
749+
750+
if (write_sb)
751+
bch2_write_super(c);
752+
753+
c->recovery_passes_explicit |= bch2_recovery_passes_from_stable(le64_to_cpu(ext->recovery_passes_required[0]));
754+
mutex_unlock(&c->sb_lock);
755+
}
756+
757+
if (c->opts.fsck && IS_ENABLED(CONFIG_BCACHEFS_DEBUG))
758+
c->recovery_passes_explicit |= BIT_ULL(BCH_RECOVERY_PASS_check_topology);
759+
724760
ret = bch2_blacklist_table_initialize(c);
725761
if (ret) {
726762
bch_err(c, "error initializing blacklist table");
@@ -857,11 +893,6 @@ int bch2_fs_recovery(struct bch_fs *c)
857893
if (ret)
858894
goto err;
859895

860-
if (c->opts.fsck &&
861-
(IS_ENABLED(CONFIG_BCACHEFS_DEBUG) ||
862-
BCH_SB_HAS_TOPOLOGY_ERRORS(c->disk_sb.sb)))
863-
c->recovery_passes_explicit |= BIT_ULL(BCH_RECOVERY_PASS_check_topology);
864-
865896
ret = bch2_run_recovery_passes(c);
866897
if (ret)
867898
goto err;
@@ -898,16 +929,30 @@ int bch2_fs_recovery(struct bch_fs *c)
898929
}
899930

900931
mutex_lock(&c->sb_lock);
932+
bool write_sb = false;
933+
901934
if (BCH_SB_VERSION_UPGRADE_COMPLETE(c->disk_sb.sb) != le16_to_cpu(c->disk_sb.sb->version)) {
902935
SET_BCH_SB_VERSION_UPGRADE_COMPLETE(c->disk_sb.sb, le16_to_cpu(c->disk_sb.sb->version));
903936
write_sb = true;
904937
}
905938

906-
if (!test_bit(BCH_FS_ERROR, &c->flags)) {
939+
if (!test_bit(BCH_FS_ERROR, &c->flags) &&
940+
!(c->disk_sb.sb->compat[0] & cpu_to_le64(1ULL << BCH_COMPAT_alloc_info))) {
907941
c->disk_sb.sb->compat[0] |= cpu_to_le64(1ULL << BCH_COMPAT_alloc_info);
908942
write_sb = true;
909943
}
910944

945+
if (!test_bit(BCH_FS_ERROR, &c->flags)) {
946+
struct bch_sb_field_ext *ext = bch2_sb_field_get(c->disk_sb.sb, ext);
947+
if (ext &&
948+
(!bch2_is_zero(ext->recovery_passes_required, sizeof(ext->recovery_passes_required)) ||
949+
!bch2_is_zero(ext->errors_silent, sizeof(ext->errors_silent)))) {
950+
memset(ext->recovery_passes_required, 0, sizeof(ext->recovery_passes_required));
951+
memset(ext->errors_silent, 0, sizeof(ext->errors_silent));
952+
write_sb = true;
953+
}
954+
}
955+
911956
if (c->opts.fsck &&
912957
!test_bit(BCH_FS_ERROR, &c->flags) &&
913958
!test_bit(BCH_FS_ERRORS_NOT_FIXED, &c->flags)) {

fs/bcachefs/sb-errors.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
#include "sb-errors.h"
55
#include "super-io.h"
66

7-
static const char * const bch2_sb_error_strs[] = {
7+
const char * const bch2_sb_error_strs[] = {
88
#define x(t, n, ...) [n] = #t,
99
BCH_SB_ERRS()
1010
NULL

fs/bcachefs/sb-errors.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@
44

55
#include "sb-errors_types.h"
66

7+
extern const char * const bch2_sb_error_strs[];
8+
79
extern const struct bch_sb_field_ops bch_sb_field_ops_errors;
810

911
void bch2_sb_error_count(struct bch_fs *, enum bch_sb_error_id);

fs/bcachefs/super-io.c

Lines changed: 74 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -264,6 +264,17 @@ struct bch_sb_field *bch2_sb_field_resize_id(struct bch_sb_handle *sb,
264264
return f;
265265
}
266266

267+
struct bch_sb_field *bch2_sb_field_get_minsize_id(struct bch_sb_handle *sb,
268+
enum bch_sb_field_type type,
269+
unsigned u64s)
270+
{
271+
struct bch_sb_field *f = bch2_sb_field_get_id(sb->sb, type);
272+
273+
if (!f || le32_to_cpu(f->u64s) < u64s)
274+
f = bch2_sb_field_resize_id(sb, type, u64s);
275+
return f;
276+
}
277+
267278
/* Superblock validate: */
268279

269280
static int validate_sb_layout(struct bch_sb_layout *layout, struct printbuf *out)
@@ -484,6 +495,21 @@ static int bch2_sb_validate(struct bch_sb_handle *disk_sb, struct printbuf *out,
484495

485496
/* device open: */
486497

498+
static unsigned long le_ulong_to_cpu(unsigned long v)
499+
{
500+
return sizeof(unsigned long) == 8
501+
? le64_to_cpu(v)
502+
: le32_to_cpu(v);
503+
}
504+
505+
static void le_bitvector_to_cpu(unsigned long *dst, unsigned long *src, unsigned nr)
506+
{
507+
BUG_ON(nr & (BITS_PER_TYPE(long) - 1));
508+
509+
for (unsigned i = 0; i < BITS_TO_LONGS(nr); i++)
510+
dst[i] = le_ulong_to_cpu(src[i]);
511+
}
512+
487513
static void bch2_sb_update(struct bch_fs *c)
488514
{
489515
struct bch_sb *src = c->disk_sb.sb;
@@ -512,8 +538,15 @@ static void bch2_sb_update(struct bch_fs *c)
512538
c->sb.features = le64_to_cpu(src->features[0]);
513539
c->sb.compat = le64_to_cpu(src->compat[0]);
514540

541+
memset(c->sb.errors_silent, 0, sizeof(c->sb.errors_silent));
542+
543+
struct bch_sb_field_ext *ext = bch2_sb_field_get(src, ext);
544+
if (ext)
545+
le_bitvector_to_cpu(c->sb.errors_silent, (void *) ext->errors_silent,
546+
sizeof(c->sb.errors_silent) * 8);
547+
515548
for_each_member_device(ca, c, i) {
516-
struct bch_member m = bch2_sb_member_get(src, i);
549+
struct bch_member m = bch2_sb_member_get(src, ca->dev_idx);
517550
ca->mi = bch2_mi_to_cpu(&m);
518551
}
519552
}
@@ -1054,6 +1087,46 @@ void bch2_sb_upgrade(struct bch_fs *c, unsigned new_version)
10541087
c->disk_sb.sb->features[0] |= cpu_to_le64(BCH_SB_FEATURES_ALL);
10551088
}
10561089

1090+
static int bch2_sb_ext_validate(struct bch_sb *sb, struct bch_sb_field *f,
1091+
struct printbuf *err)
1092+
{
1093+
if (vstruct_bytes(f) < 88) {
1094+
prt_printf(err, "field too small (%zu < %u)", vstruct_bytes(f), 88);
1095+
return -BCH_ERR_invalid_sb_ext;
1096+
}
1097+
1098+
return 0;
1099+
}
1100+
1101+
static void bch2_sb_ext_to_text(struct printbuf *out, struct bch_sb *sb,
1102+
struct bch_sb_field *f)
1103+
{
1104+
struct bch_sb_field_ext *e = field_to_type(f, ext);
1105+
1106+
prt_printf(out, "Recovery passes required:");
1107+
prt_tab(out);
1108+
prt_bitflags(out, bch2_recovery_passes,
1109+
bch2_recovery_passes_from_stable(le64_to_cpu(e->recovery_passes_required[0])));
1110+
prt_newline(out);
1111+
1112+
unsigned long *errors_silent = kmalloc(sizeof(e->errors_silent), GFP_KERNEL);
1113+
if (errors_silent) {
1114+
le_bitvector_to_cpu(errors_silent, (void *) e->errors_silent, sizeof(e->errors_silent) * 8);
1115+
1116+
prt_printf(out, "Errors to silently fix:");
1117+
prt_tab(out);
1118+
prt_bitflags_vector(out, bch2_sb_error_strs, errors_silent, sizeof(e->errors_silent) * 8);
1119+
prt_newline(out);
1120+
1121+
kfree(errors_silent);
1122+
}
1123+
}
1124+
1125+
static const struct bch_sb_field_ops bch_sb_field_ops_ext = {
1126+
.validate = bch2_sb_ext_validate,
1127+
.to_text = bch2_sb_ext_to_text,
1128+
};
1129+
10571130
static const struct bch_sb_field_ops *bch2_sb_field_ops[] = {
10581131
#define x(f, nr) \
10591132
[BCH_SB_FIELD_##f] = &bch_sb_field_ops_##f,

fs/bcachefs/super-io.h

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,16 @@ struct bch_sb_field *bch2_sb_field_resize_id(struct bch_sb_handle *,
4040
#define bch2_sb_field_resize(_sb, _name, _u64s) \
4141
field_to_type(bch2_sb_field_resize_id(_sb, BCH_SB_FIELD_##_name, _u64s), _name)
4242

43+
struct bch_sb_field *bch2_sb_field_get_minsize_id(struct bch_sb_handle *,
44+
enum bch_sb_field_type, unsigned);
45+
#define bch2_sb_field_get_minsize(_sb, _name, _u64s) \
46+
field_to_type(bch2_sb_field_get_minsize_id(_sb, BCH_SB_FIELD_##_name, _u64s), _name)
47+
48+
#define bch2_sb_field_nr_entries(_f) \
49+
(_f ? ((bch2_sb_field_bytes(&_f->field) - sizeof(*_f)) / \
50+
sizeof(_f->entries[0])) \
51+
: 0)
52+
4353
void bch2_sb_field_delete(struct bch_sb_handle *, enum bch_sb_field_type);
4454

4555
extern const char * const bch2_sb_fields[];

0 commit comments

Comments
 (0)