Skip to content

Commit b65db75

Browse files
author
Kent Overstreet
committed
bcachefs: Enumerate fsck errors
This patch adds a superblock error counter for every distinct fsck error; this means that when analyzing filesystems out in the wild we'll be able to see what sorts of inconsistencies are being found and repair, and hence what bugs to look for. Errors validating bkeys are not yet considered distinct fsck errors, but this patch adds a new helper, bkey_fsck_err(), in order to add distinct error types for them as well. Signed-off-by: Kent Overstreet <kent.overstreet@linux.dev>
1 parent f5d26fa commit b65db75

37 files changed

Lines changed: 1175 additions & 738 deletions

fs/bcachefs/alloc_background.c

Lines changed: 84 additions & 74 deletions
Original file line numberDiff line numberDiff line change
@@ -192,114 +192,109 @@ static unsigned bch_alloc_v1_val_u64s(const struct bch_alloc *a)
192192
return DIV_ROUND_UP(bytes, sizeof(u64));
193193
}
194194

195-
int bch2_alloc_v1_invalid(const struct bch_fs *c, struct bkey_s_c k,
195+
int bch2_alloc_v1_invalid(struct bch_fs *c, struct bkey_s_c k,
196196
enum bkey_invalid_flags flags,
197197
struct printbuf *err)
198198
{
199199
struct bkey_s_c_alloc a = bkey_s_c_to_alloc(k);
200+
int ret = 0;
200201

201202
/* allow for unknown fields */
202-
if (bkey_val_u64s(a.k) < bch_alloc_v1_val_u64s(a.v)) {
203-
prt_printf(err, "incorrect value size (%zu < %u)",
204-
bkey_val_u64s(a.k), bch_alloc_v1_val_u64s(a.v));
205-
return -BCH_ERR_invalid_bkey;
206-
}
207-
208-
return 0;
203+
bkey_fsck_err_on(bkey_val_u64s(a.k) < bch_alloc_v1_val_u64s(a.v), c, err,
204+
alloc_v1_val_size_bad,
205+
"incorrect value size (%zu < %u)",
206+
bkey_val_u64s(a.k), bch_alloc_v1_val_u64s(a.v));
207+
fsck_err:
208+
return ret;
209209
}
210210

211-
int bch2_alloc_v2_invalid(const struct bch_fs *c, struct bkey_s_c k,
211+
int bch2_alloc_v2_invalid(struct bch_fs *c, struct bkey_s_c k,
212212
enum bkey_invalid_flags flags,
213213
struct printbuf *err)
214214
{
215215
struct bkey_alloc_unpacked u;
216+
int ret = 0;
216217

217-
if (bch2_alloc_unpack_v2(&u, k)) {
218-
prt_printf(err, "unpack error");
219-
return -BCH_ERR_invalid_bkey;
220-
}
221-
222-
return 0;
218+
bkey_fsck_err_on(bch2_alloc_unpack_v2(&u, k), c, err,
219+
alloc_v2_unpack_error,
220+
"unpack error");
221+
fsck_err:
222+
return ret;
223223
}
224224

225-
int bch2_alloc_v3_invalid(const struct bch_fs *c, struct bkey_s_c k,
225+
int bch2_alloc_v3_invalid(struct bch_fs *c, struct bkey_s_c k,
226226
enum bkey_invalid_flags flags,
227227
struct printbuf *err)
228228
{
229229
struct bkey_alloc_unpacked u;
230+
int ret = 0;
230231

231-
if (bch2_alloc_unpack_v3(&u, k)) {
232-
prt_printf(err, "unpack error");
233-
return -BCH_ERR_invalid_bkey;
234-
}
235-
236-
return 0;
232+
bkey_fsck_err_on(bch2_alloc_unpack_v3(&u, k), c, err,
233+
alloc_v2_unpack_error,
234+
"unpack error");
235+
fsck_err:
236+
return ret;
237237
}
238238

239-
int bch2_alloc_v4_invalid(const struct bch_fs *c, struct bkey_s_c k,
239+
int bch2_alloc_v4_invalid(struct bch_fs *c, struct bkey_s_c k,
240240
enum bkey_invalid_flags flags, struct printbuf *err)
241241
{
242242
struct bkey_s_c_alloc_v4 a = bkey_s_c_to_alloc_v4(k);
243+
int ret = 0;
243244

244-
if (alloc_v4_u64s(a.v) > bkey_val_u64s(k.k)) {
245-
prt_printf(err, "bad val size (%u > %zu)",
246-
alloc_v4_u64s(a.v), bkey_val_u64s(k.k));
247-
return -BCH_ERR_invalid_bkey;
248-
}
245+
bkey_fsck_err_on(alloc_v4_u64s(a.v) > bkey_val_u64s(k.k), c, err,
246+
alloc_v4_val_size_bad,
247+
"bad val size (%u > %zu)",
248+
alloc_v4_u64s(a.v), bkey_val_u64s(k.k));
249249

250-
if (!BCH_ALLOC_V4_BACKPOINTERS_START(a.v) &&
251-
BCH_ALLOC_V4_NR_BACKPOINTERS(a.v)) {
252-
prt_printf(err, "invalid backpointers_start");
253-
return -BCH_ERR_invalid_bkey;
254-
}
250+
bkey_fsck_err_on(!BCH_ALLOC_V4_BACKPOINTERS_START(a.v) &&
251+
BCH_ALLOC_V4_NR_BACKPOINTERS(a.v), c, err,
252+
alloc_v4_backpointers_start_bad,
253+
"invalid backpointers_start");
255254

256-
if (alloc_data_type(*a.v, a.v->data_type) != a.v->data_type) {
257-
prt_printf(err, "invalid data type (got %u should be %u)",
258-
a.v->data_type, alloc_data_type(*a.v, a.v->data_type));
259-
return -BCH_ERR_invalid_bkey;
260-
}
255+
bkey_fsck_err_on(alloc_data_type(*a.v, a.v->data_type) != a.v->data_type, c, err,
256+
alloc_key_data_type_bad,
257+
"invalid data type (got %u should be %u)",
258+
a.v->data_type, alloc_data_type(*a.v, a.v->data_type));
261259

262260
switch (a.v->data_type) {
263261
case BCH_DATA_free:
264262
case BCH_DATA_need_gc_gens:
265263
case BCH_DATA_need_discard:
266-
if (a.v->dirty_sectors ||
267-
a.v->cached_sectors ||
268-
a.v->stripe) {
269-
prt_printf(err, "empty data type free but have data");
270-
return -BCH_ERR_invalid_bkey;
271-
}
264+
bkey_fsck_err_on(a.v->dirty_sectors ||
265+
a.v->cached_sectors ||
266+
a.v->stripe, c, err,
267+
alloc_key_empty_but_have_data,
268+
"empty data type free but have data");
272269
break;
273270
case BCH_DATA_sb:
274271
case BCH_DATA_journal:
275272
case BCH_DATA_btree:
276273
case BCH_DATA_user:
277274
case BCH_DATA_parity:
278-
if (!a.v->dirty_sectors) {
279-
prt_printf(err, "data_type %s but dirty_sectors==0",
280-
bch2_data_types[a.v->data_type]);
281-
return -BCH_ERR_invalid_bkey;
282-
}
275+
bkey_fsck_err_on(!a.v->dirty_sectors, c, err,
276+
alloc_key_dirty_sectors_0,
277+
"data_type %s but dirty_sectors==0",
278+
bch2_data_types[a.v->data_type]);
283279
break;
284280
case BCH_DATA_cached:
285-
if (!a.v->cached_sectors ||
286-
a.v->dirty_sectors ||
287-
a.v->stripe) {
288-
prt_printf(err, "data type inconsistency");
289-
return -BCH_ERR_invalid_bkey;
290-
}
291-
292-
if (!a.v->io_time[READ] &&
293-
c->curr_recovery_pass > BCH_RECOVERY_PASS_check_alloc_to_lru_refs) {
294-
prt_printf(err, "cached bucket with read_time == 0");
295-
return -BCH_ERR_invalid_bkey;
296-
}
281+
bkey_fsck_err_on(!a.v->cached_sectors ||
282+
a.v->dirty_sectors ||
283+
a.v->stripe, c, err,
284+
alloc_key_cached_inconsistency,
285+
"data type inconsistency");
286+
287+
bkey_fsck_err_on(!a.v->io_time[READ] &&
288+
c->curr_recovery_pass > BCH_RECOVERY_PASS_check_alloc_to_lru_refs,
289+
c, err,
290+
alloc_key_cached_but_read_time_zero,
291+
"cached bucket with read_time == 0");
297292
break;
298293
case BCH_DATA_stripe:
299294
break;
300295
}
301-
302-
return 0;
296+
fsck_err:
297+
return ret;
303298
}
304299

305300
static inline u64 swab40(u64 x)
@@ -521,17 +516,18 @@ static unsigned alloc_gen(struct bkey_s_c k, unsigned offset)
521516
: 0;
522517
}
523518

524-
int bch2_bucket_gens_invalid(const struct bch_fs *c, struct bkey_s_c k,
519+
int bch2_bucket_gens_invalid(struct bch_fs *c, struct bkey_s_c k,
525520
enum bkey_invalid_flags flags,
526521
struct printbuf *err)
527522
{
528-
if (bkey_val_bytes(k.k) != sizeof(struct bch_bucket_gens)) {
529-
prt_printf(err, "bad val size (%zu != %zu)",
530-
bkey_val_bytes(k.k), sizeof(struct bch_bucket_gens));
531-
return -BCH_ERR_invalid_bkey;
532-
}
523+
int ret = 0;
533524

534-
return 0;
525+
bkey_fsck_err_on(bkey_val_bytes(k.k) != sizeof(struct bch_bucket_gens), c, err,
526+
bucket_gens_val_size_bad,
527+
"bad val size (%zu != %zu)",
528+
bkey_val_bytes(k.k), sizeof(struct bch_bucket_gens));
529+
fsck_err:
530+
return ret;
535531
}
536532

537533
void bch2_bucket_gens_to_text(struct printbuf *out, struct bch_fs *c, struct bkey_s_c k)
@@ -986,6 +982,7 @@ int bch2_check_alloc_key(struct btree_trans *trans,
986982
int ret;
987983

988984
if (fsck_err_on(!bch2_dev_bucket_exists(c, alloc_k.k->p), c,
985+
alloc_key_to_missing_dev_bucket,
989986
"alloc key for invalid device:bucket %llu:%llu",
990987
alloc_k.k->p.inode, alloc_k.k->p.offset))
991988
return bch2_btree_delete_at(trans, alloc_iter, 0);
@@ -1005,7 +1002,8 @@ int bch2_check_alloc_key(struct btree_trans *trans,
10051002

10061003
if (k.k->type != discard_key_type &&
10071004
(c->opts.reconstruct_alloc ||
1008-
fsck_err(c, "incorrect key in need_discard btree (got %s should be %s)\n"
1005+
fsck_err(c, need_discard_key_wrong,
1006+
"incorrect key in need_discard btree (got %s should be %s)\n"
10091007
" %s",
10101008
bch2_bkey_types[k.k->type],
10111009
bch2_bkey_types[discard_key_type],
@@ -1035,7 +1033,8 @@ int bch2_check_alloc_key(struct btree_trans *trans,
10351033

10361034
if (k.k->type != freespace_key_type &&
10371035
(c->opts.reconstruct_alloc ||
1038-
fsck_err(c, "incorrect key in freespace btree (got %s should be %s)\n"
1036+
fsck_err(c, freespace_key_wrong,
1037+
"incorrect key in freespace btree (got %s should be %s)\n"
10391038
" %s",
10401039
bch2_bkey_types[k.k->type],
10411040
bch2_bkey_types[freespace_key_type],
@@ -1066,7 +1065,8 @@ int bch2_check_alloc_key(struct btree_trans *trans,
10661065

10671066
if (a->gen != alloc_gen(k, gens_offset) &&
10681067
(c->opts.reconstruct_alloc ||
1069-
fsck_err(c, "incorrect gen in bucket_gens btree (got %u should be %u)\n"
1068+
fsck_err(c, bucket_gens_key_wrong,
1069+
"incorrect gen in bucket_gens btree (got %u should be %u)\n"
10701070
" %s",
10711071
alloc_gen(k, gens_offset), a->gen,
10721072
(printbuf_reset(&buf),
@@ -1124,7 +1124,8 @@ int bch2_check_alloc_hole_freespace(struct btree_trans *trans,
11241124

11251125
if (k.k->type != KEY_TYPE_set &&
11261126
(c->opts.reconstruct_alloc ||
1127-
fsck_err(c, "hole in alloc btree missing in freespace btree\n"
1127+
fsck_err(c, freespace_hole_missing,
1128+
"hole in alloc btree missing in freespace btree\n"
11281129
" device %llu buckets %llu-%llu",
11291130
freespace_iter->pos.inode,
11301131
freespace_iter->pos.offset,
@@ -1187,6 +1188,7 @@ int bch2_check_alloc_hole_bucket_gens(struct btree_trans *trans,
11871188

11881189
for (i = gens_offset; i < gens_end_offset; i++) {
11891190
if (fsck_err_on(g.v.gens[i], c,
1191+
bucket_gens_hole_wrong,
11901192
"hole in alloc btree at %llu:%llu with nonzero gen in bucket_gens btree (%u)",
11911193
bucket_gens_pos_to_alloc(k.k->p, i).inode,
11921194
bucket_gens_pos_to_alloc(k.k->p, i).offset,
@@ -1244,6 +1246,7 @@ static noinline_for_stack int __bch2_check_discard_freespace_key(struct btree_tr
12441246
return ret;
12451247

12461248
if (fsck_err_on(!bch2_dev_bucket_exists(c, pos), c,
1249+
need_discard_freespace_key_to_invalid_dev_bucket,
12471250
"entry in %s btree for nonexistant dev:bucket %llu:%llu",
12481251
bch2_btree_id_str(iter->btree_id), pos.inode, pos.offset))
12491252
goto delete;
@@ -1253,6 +1256,7 @@ static noinline_for_stack int __bch2_check_discard_freespace_key(struct btree_tr
12531256
if (fsck_err_on(a->data_type != state ||
12541257
(state == BCH_DATA_free &&
12551258
genbits != alloc_freespace_genbits(*a)), c,
1259+
need_discard_freespace_key_bad,
12561260
"%s\n incorrectly set at %s:%llu:%llu:0 (free %u, genbits %llu should be %llu)",
12571261
(bch2_bkey_val_to_text(&buf, c, alloc_k), buf.buf),
12581262
bch2_btree_id_str(iter->btree_id),
@@ -1320,6 +1324,7 @@ int bch2_check_bucket_gens_key(struct btree_trans *trans,
13201324
dev_exists = bch2_dev_exists2(c, k.k->p.inode);
13211325
if (!dev_exists) {
13221326
if (fsck_err_on(!dev_exists, c,
1327+
bucket_gens_to_invalid_dev,
13231328
"bucket_gens key for invalid device:\n %s",
13241329
(bch2_bkey_val_to_text(&buf, c, k), buf.buf))) {
13251330
ret = bch2_btree_delete_at(trans, iter, 0);
@@ -1330,6 +1335,7 @@ int bch2_check_bucket_gens_key(struct btree_trans *trans,
13301335
ca = bch_dev_bkey_exists(c, k.k->p.inode);
13311336
if (fsck_err_on(end <= ca->mi.first_bucket ||
13321337
start >= ca->mi.nbuckets, c,
1338+
bucket_gens_to_invalid_buckets,
13331339
"bucket_gens key for invalid buckets:\n %s",
13341340
(bch2_bkey_val_to_text(&buf, c, k), buf.buf))) {
13351341
ret = bch2_btree_delete_at(trans, iter, 0);
@@ -1338,13 +1344,15 @@ int bch2_check_bucket_gens_key(struct btree_trans *trans,
13381344

13391345
for (b = start; b < ca->mi.first_bucket; b++)
13401346
if (fsck_err_on(g.v.gens[b & KEY_TYPE_BUCKET_GENS_MASK], c,
1347+
bucket_gens_nonzero_for_invalid_buckets,
13411348
"bucket_gens key has nonzero gen for invalid bucket")) {
13421349
g.v.gens[b & KEY_TYPE_BUCKET_GENS_MASK] = 0;
13431350
need_update = true;
13441351
}
13451352

13461353
for (b = ca->mi.nbuckets; b < end; b++)
13471354
if (fsck_err_on(g.v.gens[b & KEY_TYPE_BUCKET_GENS_MASK], c,
1355+
bucket_gens_nonzero_for_invalid_buckets,
13481356
"bucket_gens key has nonzero gen for invalid bucket")) {
13491357
g.v.gens[b & KEY_TYPE_BUCKET_GENS_MASK] = 0;
13501358
need_update = true;
@@ -1495,11 +1503,13 @@ static int bch2_check_alloc_to_lru_ref(struct btree_trans *trans,
14951503
return ret;
14961504

14971505
if (fsck_err_on(!a->io_time[READ], c,
1506+
alloc_key_cached_but_read_time_zero,
14981507
"cached bucket with read_time 0\n"
14991508
" %s",
15001509
(printbuf_reset(&buf),
15011510
bch2_bkey_val_to_text(&buf, c, alloc_k), buf.buf)) ||
15021511
fsck_err_on(lru_k.k->type != KEY_TYPE_set, c,
1512+
alloc_key_to_missing_lru_entry,
15031513
"missing lru entry\n"
15041514
" %s",
15051515
(printbuf_reset(&buf),

fs/bcachefs/alloc_background.h

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -149,13 +149,13 @@ struct bkey_i_alloc_v4 *bch2_alloc_to_v4_mut(struct btree_trans *, struct bkey_s
149149

150150
int bch2_bucket_io_time_reset(struct btree_trans *, unsigned, size_t, int);
151151

152-
int bch2_alloc_v1_invalid(const struct bch_fs *, struct bkey_s_c,
152+
int bch2_alloc_v1_invalid(struct bch_fs *, struct bkey_s_c,
153153
enum bkey_invalid_flags, struct printbuf *);
154-
int bch2_alloc_v2_invalid(const struct bch_fs *, struct bkey_s_c,
154+
int bch2_alloc_v2_invalid(struct bch_fs *, struct bkey_s_c,
155155
enum bkey_invalid_flags, struct printbuf *);
156-
int bch2_alloc_v3_invalid(const struct bch_fs *, struct bkey_s_c,
156+
int bch2_alloc_v3_invalid(struct bch_fs *, struct bkey_s_c,
157157
enum bkey_invalid_flags, struct printbuf *);
158-
int bch2_alloc_v4_invalid(const struct bch_fs *, struct bkey_s_c,
158+
int bch2_alloc_v4_invalid(struct bch_fs *, struct bkey_s_c,
159159
enum bkey_invalid_flags, struct printbuf *);
160160
void bch2_alloc_v4_swab(struct bkey_s);
161161
void bch2_alloc_to_text(struct printbuf *, struct bch_fs *, struct bkey_s_c);
@@ -193,7 +193,7 @@ void bch2_alloc_to_text(struct printbuf *, struct bch_fs *, struct bkey_s_c);
193193
.min_val_size = 48, \
194194
})
195195

196-
int bch2_bucket_gens_invalid(const struct bch_fs *, struct bkey_s_c,
196+
int bch2_bucket_gens_invalid(struct bch_fs *, struct bkey_s_c,
197197
enum bkey_invalid_flags, struct printbuf *);
198198
void bch2_bucket_gens_to_text(struct printbuf *, struct bch_fs *, struct bkey_s_c);
199199

0 commit comments

Comments
 (0)