Commit b65db750 authored by Kent Overstreet's avatar Kent Overstreet

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: default avatarKent Overstreet <kent.overstreet@linux.dev>
parent f5d26fa3
This diff is collapsed.
...@@ -149,13 +149,13 @@ struct bkey_i_alloc_v4 *bch2_alloc_to_v4_mut(struct btree_trans *, struct bkey_s ...@@ -149,13 +149,13 @@ struct bkey_i_alloc_v4 *bch2_alloc_to_v4_mut(struct btree_trans *, struct bkey_s
int bch2_bucket_io_time_reset(struct btree_trans *, unsigned, size_t, int); int bch2_bucket_io_time_reset(struct btree_trans *, unsigned, size_t, int);
int bch2_alloc_v1_invalid(const struct bch_fs *, struct bkey_s_c, int bch2_alloc_v1_invalid(struct bch_fs *, struct bkey_s_c,
enum bkey_invalid_flags, struct printbuf *); enum bkey_invalid_flags, struct printbuf *);
int bch2_alloc_v2_invalid(const struct bch_fs *, struct bkey_s_c, int bch2_alloc_v2_invalid(struct bch_fs *, struct bkey_s_c,
enum bkey_invalid_flags, struct printbuf *); enum bkey_invalid_flags, struct printbuf *);
int bch2_alloc_v3_invalid(const struct bch_fs *, struct bkey_s_c, int bch2_alloc_v3_invalid(struct bch_fs *, struct bkey_s_c,
enum bkey_invalid_flags, struct printbuf *); enum bkey_invalid_flags, struct printbuf *);
int bch2_alloc_v4_invalid(const struct bch_fs *, struct bkey_s_c, int bch2_alloc_v4_invalid(struct bch_fs *, struct bkey_s_c,
enum bkey_invalid_flags, struct printbuf *); enum bkey_invalid_flags, struct printbuf *);
void bch2_alloc_v4_swab(struct bkey_s); void bch2_alloc_v4_swab(struct bkey_s);
void bch2_alloc_to_text(struct printbuf *, struct bch_fs *, struct bkey_s_c); 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); ...@@ -193,7 +193,7 @@ void bch2_alloc_to_text(struct printbuf *, struct bch_fs *, struct bkey_s_c);
.min_val_size = 48, \ .min_val_size = 48, \
}) })
int bch2_bucket_gens_invalid(const struct bch_fs *, struct bkey_s_c, int bch2_bucket_gens_invalid(struct bch_fs *, struct bkey_s_c,
enum bkey_invalid_flags, struct printbuf *); enum bkey_invalid_flags, struct printbuf *);
void bch2_bucket_gens_to_text(struct printbuf *, struct bch_fs *, struct bkey_s_c); void bch2_bucket_gens_to_text(struct printbuf *, struct bch_fs *, struct bkey_s_c);
......
...@@ -37,19 +37,20 @@ static bool extent_matches_bp(struct bch_fs *c, ...@@ -37,19 +37,20 @@ static bool extent_matches_bp(struct bch_fs *c,
return false; return false;
} }
int bch2_backpointer_invalid(const struct bch_fs *c, struct bkey_s_c k, int bch2_backpointer_invalid(struct bch_fs *c, struct bkey_s_c k,
enum bkey_invalid_flags flags, enum bkey_invalid_flags flags,
struct printbuf *err) struct printbuf *err)
{ {
struct bkey_s_c_backpointer bp = bkey_s_c_to_backpointer(k); struct bkey_s_c_backpointer bp = bkey_s_c_to_backpointer(k);
struct bpos bucket = bp_pos_to_bucket(c, bp.k->p); struct bpos bucket = bp_pos_to_bucket(c, bp.k->p);
int ret = 0;
if (!bpos_eq(bp.k->p, bucket_pos_to_bp(c, bucket, bp.v->bucket_offset))) { bkey_fsck_err_on(!bpos_eq(bp.k->p, bucket_pos_to_bp(c, bucket, bp.v->bucket_offset)),
prt_str(err, "backpointer at wrong pos"); c, err,
return -BCH_ERR_invalid_bkey; backpointer_pos_wrong,
} "backpointer at wrong pos");
fsck_err:
return 0; return ret;
} }
void bch2_backpointer_to_text(struct printbuf *out, const struct bch_backpointer *bp) void bch2_backpointer_to_text(struct printbuf *out, const struct bch_backpointer *bp)
...@@ -356,6 +357,7 @@ static int bch2_check_btree_backpointer(struct btree_trans *trans, struct btree_ ...@@ -356,6 +357,7 @@ static int bch2_check_btree_backpointer(struct btree_trans *trans, struct btree_
int ret = 0; int ret = 0;
if (fsck_err_on(!bch2_dev_exists2(c, k.k->p.inode), c, if (fsck_err_on(!bch2_dev_exists2(c, k.k->p.inode), c,
backpointer_to_missing_device,
"backpointer for missing device:\n%s", "backpointer for missing device:\n%s",
(bch2_bkey_val_to_text(&buf, c, k), buf.buf))) { (bch2_bkey_val_to_text(&buf, c, k), buf.buf))) {
ret = bch2_btree_delete_at(trans, bp_iter, 0); ret = bch2_btree_delete_at(trans, bp_iter, 0);
...@@ -369,6 +371,7 @@ static int bch2_check_btree_backpointer(struct btree_trans *trans, struct btree_ ...@@ -369,6 +371,7 @@ static int bch2_check_btree_backpointer(struct btree_trans *trans, struct btree_
goto out; goto out;
if (fsck_err_on(alloc_k.k->type != KEY_TYPE_alloc_v4, c, if (fsck_err_on(alloc_k.k->type != KEY_TYPE_alloc_v4, c,
backpointer_to_missing_alloc,
"backpointer for nonexistent alloc key: %llu:%llu:0\n%s", "backpointer for nonexistent alloc key: %llu:%llu:0\n%s",
alloc_iter.pos.inode, alloc_iter.pos.offset, alloc_iter.pos.inode, alloc_iter.pos.offset,
(bch2_bkey_val_to_text(&buf, c, alloc_k), buf.buf))) { (bch2_bkey_val_to_text(&buf, c, alloc_k), buf.buf))) {
...@@ -460,7 +463,7 @@ static int check_bp_exists(struct btree_trans *trans, ...@@ -460,7 +463,7 @@ static int check_bp_exists(struct btree_trans *trans,
if (c->sb.version_upgrade_complete < bcachefs_metadata_version_backpointers || if (c->sb.version_upgrade_complete < bcachefs_metadata_version_backpointers ||
c->opts.reconstruct_alloc || c->opts.reconstruct_alloc ||
fsck_err(c, "%s", buf.buf)) fsck_err(c, ptr_to_missing_backpointer, "%s", buf.buf))
ret = bch2_bucket_backpointer_mod(trans, bucket, bp, orig_k, true); ret = bch2_bucket_backpointer_mod(trans, bucket, bp, orig_k, true);
goto out; goto out;
...@@ -793,6 +796,7 @@ static int check_one_backpointer(struct btree_trans *trans, ...@@ -793,6 +796,7 @@ static int check_one_backpointer(struct btree_trans *trans,
} }
if (fsck_err_on(!k.k, c, if (fsck_err_on(!k.k, c,
backpointer_to_missing_ptr,
"backpointer for missing extent\n %s", "backpointer for missing extent\n %s",
(bch2_bkey_val_to_text(&buf, c, bp.s_c), buf.buf))) { (bch2_bkey_val_to_text(&buf, c, bp.s_c), buf.buf))) {
ret = bch2_btree_delete_at_buffered(trans, BTREE_ID_backpointers, bp.k->p); ret = bch2_btree_delete_at_buffered(trans, BTREE_ID_backpointers, bp.k->p);
......
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
#include "buckets.h" #include "buckets.h"
#include "super.h" #include "super.h"
int bch2_backpointer_invalid(const struct bch_fs *, struct bkey_s_c k, int bch2_backpointer_invalid(struct bch_fs *, struct bkey_s_c k,
enum bkey_invalid_flags, struct printbuf *); enum bkey_invalid_flags, struct printbuf *);
void bch2_backpointer_to_text(struct printbuf *, const struct bch_backpointer *); void bch2_backpointer_to_text(struct printbuf *, const struct bch_backpointer *);
void bch2_backpointer_k_to_text(struct printbuf *, struct bch_fs *, struct bkey_s_c); void bch2_backpointer_k_to_text(struct printbuf *, struct bch_fs *, struct bkey_s_c);
......
...@@ -26,7 +26,7 @@ const char * const bch2_bkey_types[] = { ...@@ -26,7 +26,7 @@ const char * const bch2_bkey_types[] = {
NULL NULL
}; };
static int deleted_key_invalid(const struct bch_fs *c, struct bkey_s_c k, static int deleted_key_invalid(struct bch_fs *c, struct bkey_s_c k,
enum bkey_invalid_flags flags, struct printbuf *err) enum bkey_invalid_flags flags, struct printbuf *err)
{ {
return 0; return 0;
...@@ -40,23 +40,24 @@ static int deleted_key_invalid(const struct bch_fs *c, struct bkey_s_c k, ...@@ -40,23 +40,24 @@ static int deleted_key_invalid(const struct bch_fs *c, struct bkey_s_c k,
.key_invalid = deleted_key_invalid, \ .key_invalid = deleted_key_invalid, \
}) })
static int empty_val_key_invalid(const struct bch_fs *c, struct bkey_s_c k, static int empty_val_key_invalid(struct bch_fs *c, struct bkey_s_c k,
enum bkey_invalid_flags flags, struct printbuf *err) enum bkey_invalid_flags flags, struct printbuf *err)
{ {
if (bkey_val_bytes(k.k)) { int ret = 0;
prt_printf(err, "incorrect value size (%zu != 0)",
bkey_val_bytes(k.k));
return -BCH_ERR_invalid_bkey;
}
return 0; bkey_fsck_err_on(bkey_val_bytes(k.k), c, err,
bkey_val_size_nonzero,
"incorrect value size (%zu != 0)",
bkey_val_bytes(k.k));
fsck_err:
return ret;
} }
#define bch2_bkey_ops_error ((struct bkey_ops) { \ #define bch2_bkey_ops_error ((struct bkey_ops) { \
.key_invalid = empty_val_key_invalid, \ .key_invalid = empty_val_key_invalid, \
}) })
static int key_type_cookie_invalid(const struct bch_fs *c, struct bkey_s_c k, static int key_type_cookie_invalid(struct bch_fs *c, struct bkey_s_c k,
enum bkey_invalid_flags flags, struct printbuf *err) enum bkey_invalid_flags flags, struct printbuf *err)
{ {
return 0; return 0;
...@@ -71,7 +72,7 @@ static int key_type_cookie_invalid(const struct bch_fs *c, struct bkey_s_c k, ...@@ -71,7 +72,7 @@ static int key_type_cookie_invalid(const struct bch_fs *c, struct bkey_s_c k,
.key_invalid = empty_val_key_invalid, \ .key_invalid = empty_val_key_invalid, \
}) })
static int key_type_inline_data_invalid(const struct bch_fs *c, struct bkey_s_c k, static int key_type_inline_data_invalid(struct bch_fs *c, struct bkey_s_c k,
enum bkey_invalid_flags flags, struct printbuf *err) enum bkey_invalid_flags flags, struct printbuf *err)
{ {
return 0; return 0;
...@@ -92,18 +93,6 @@ static void key_type_inline_data_to_text(struct printbuf *out, struct bch_fs *c, ...@@ -92,18 +93,6 @@ static void key_type_inline_data_to_text(struct printbuf *out, struct bch_fs *c,
.val_to_text = key_type_inline_data_to_text, \ .val_to_text = key_type_inline_data_to_text, \
}) })
static int key_type_set_invalid(const struct bch_fs *c, struct bkey_s_c k,
enum bkey_invalid_flags flags, struct printbuf *err)
{
if (bkey_val_bytes(k.k)) {
prt_printf(err, "incorrect value size (%zu != %zu)",
bkey_val_bytes(k.k), sizeof(struct bch_cookie));
return -BCH_ERR_invalid_bkey;
}
return 0;
}
static bool key_type_set_merge(struct bch_fs *c, struct bkey_s l, struct bkey_s_c r) static bool key_type_set_merge(struct bch_fs *c, struct bkey_s l, struct bkey_s_c r)
{ {
bch2_key_resize(l.k, l.k->size + r.k->size); bch2_key_resize(l.k, l.k->size + r.k->size);
...@@ -111,7 +100,7 @@ static bool key_type_set_merge(struct bch_fs *c, struct bkey_s l, struct bkey_s_ ...@@ -111,7 +100,7 @@ static bool key_type_set_merge(struct bch_fs *c, struct bkey_s l, struct bkey_s_
} }
#define bch2_bkey_ops_set ((struct bkey_ops) { \ #define bch2_bkey_ops_set ((struct bkey_ops) { \
.key_invalid = key_type_set_invalid, \ .key_invalid = empty_val_key_invalid, \
.key_merge = key_type_set_merge, \ .key_merge = key_type_set_merge, \
}) })
...@@ -129,17 +118,19 @@ int bch2_bkey_val_invalid(struct bch_fs *c, struct bkey_s_c k, ...@@ -129,17 +118,19 @@ int bch2_bkey_val_invalid(struct bch_fs *c, struct bkey_s_c k,
struct printbuf *err) struct printbuf *err)
{ {
const struct bkey_ops *ops = bch2_bkey_type_ops(k.k->type); const struct bkey_ops *ops = bch2_bkey_type_ops(k.k->type);
int ret = 0;
if (bkey_val_bytes(k.k) < ops->min_val_size) { bkey_fsck_err_on(bkey_val_bytes(k.k) < ops->min_val_size, c, err,
prt_printf(err, "bad val size (%zu < %u)", bkey_val_size_too_small,
"bad val size (%zu < %u)",
bkey_val_bytes(k.k), ops->min_val_size); bkey_val_bytes(k.k), ops->min_val_size);
return -BCH_ERR_invalid_bkey;
}
if (!ops->key_invalid) if (!ops->key_invalid)
return 0; return 0;
return ops->key_invalid(c, k, flags, err); ret = ops->key_invalid(c, k, flags, err);
fsck_err:
return ret;
} }
static u64 bch2_key_types_allowed[] = { static u64 bch2_key_types_allowed[] = {
...@@ -162,61 +153,55 @@ int __bch2_bkey_invalid(struct bch_fs *c, struct bkey_s_c k, ...@@ -162,61 +153,55 @@ int __bch2_bkey_invalid(struct bch_fs *c, struct bkey_s_c k,
enum bkey_invalid_flags flags, enum bkey_invalid_flags flags,
struct printbuf *err) struct printbuf *err)
{ {
if (k.k->u64s < BKEY_U64s) { int ret = 0;
prt_printf(err, "u64s too small (%u < %zu)", k.k->u64s, BKEY_U64s);
return -BCH_ERR_invalid_bkey; bkey_fsck_err_on(k.k->u64s < BKEY_U64s, c, err,
} bkey_u64s_too_small,
"u64s too small (%u < %zu)", k.k->u64s, BKEY_U64s);
if (type >= BKEY_TYPE_NR) if (type >= BKEY_TYPE_NR)
return 0; return 0;
if (flags & BKEY_INVALID_COMMIT && bkey_fsck_err_on((flags & BKEY_INVALID_COMMIT) &&
!(bch2_key_types_allowed[type] & BIT_ULL(k.k->type))) { !(bch2_key_types_allowed[type] & BIT_ULL(k.k->type)), c, err,
prt_printf(err, "invalid key type for btree %s (%s)", bkey_invalid_type_for_btree,
"invalid key type for btree %s (%s)",
bch2_btree_node_type_str(type), bch2_bkey_types[k.k->type]); bch2_btree_node_type_str(type), bch2_bkey_types[k.k->type]);
return -BCH_ERR_invalid_bkey;
}
if (btree_node_type_is_extents(type) && !bkey_whiteout(k.k)) { if (btree_node_type_is_extents(type) && !bkey_whiteout(k.k)) {
if (k.k->size == 0) { bkey_fsck_err_on(k.k->size == 0, c, err,
prt_printf(err, "size == 0"); bkey_extent_size_zero,
return -BCH_ERR_invalid_bkey; "size == 0");
}
if (k.k->size > k.k->p.offset) { bkey_fsck_err_on(k.k->size > k.k->p.offset, c, err,
prt_printf(err, "size greater than offset (%u > %llu)", bkey_extent_size_greater_than_offset,
"size greater than offset (%u > %llu)",
k.k->size, k.k->p.offset); k.k->size, k.k->p.offset);
return -BCH_ERR_invalid_bkey;
}
} else { } else {
if (k.k->size) { bkey_fsck_err_on(k.k->size, c, err,
prt_printf(err, "size != 0"); bkey_size_nonzero,
return -BCH_ERR_invalid_bkey; "size != 0");
}
} }
if (type != BKEY_TYPE_btree) { if (type != BKEY_TYPE_btree) {
enum btree_id btree = type - 1; enum btree_id btree = type - 1;
if (!btree_type_has_snapshots(btree) && bkey_fsck_err_on(!btree_type_has_snapshots(btree) &&
k.k->p.snapshot) { k.k->p.snapshot, c, err,
prt_printf(err, "nonzero snapshot"); bkey_snapshot_nonzero,
return -BCH_ERR_invalid_bkey; "nonzero snapshot");
}
if (btree_type_has_snapshots(btree) && bkey_fsck_err_on(btree_type_has_snapshots(btree) &&
!k.k->p.snapshot) { !k.k->p.snapshot, c, err,
prt_printf(err, "snapshot == 0"); bkey_snapshot_zero,
return -BCH_ERR_invalid_bkey; "snapshot == 0");
}
if (bkey_eq(k.k->p, POS_MAX)) { bkey_fsck_err_on(bkey_eq(k.k->p, POS_MAX), c, err,
prt_printf(err, "key at POS_MAX"); bkey_at_pos_max,
return -BCH_ERR_invalid_bkey; "key at POS_MAX");
} }
} fsck_err:
return ret;
return 0;
} }
int bch2_bkey_invalid(struct bch_fs *c, struct bkey_s_c k, int bch2_bkey_invalid(struct bch_fs *c, struct bkey_s_c k,
...@@ -228,20 +213,20 @@ int bch2_bkey_invalid(struct bch_fs *c, struct bkey_s_c k, ...@@ -228,20 +213,20 @@ int bch2_bkey_invalid(struct bch_fs *c, struct bkey_s_c k,
bch2_bkey_val_invalid(c, k, flags, err); bch2_bkey_val_invalid(c, k, flags, err);
} }
int bch2_bkey_in_btree_node(struct btree *b, struct bkey_s_c k, int bch2_bkey_in_btree_node(struct bch_fs *c, struct btree *b,
struct printbuf *err) struct bkey_s_c k, struct printbuf *err)
{ {
if (bpos_lt(k.k->p, b->data->min_key)) { int ret = 0;
prt_printf(err, "key before start of btree node");
return -BCH_ERR_invalid_bkey;
}
if (bpos_gt(k.k->p, b->data->max_key)) { bkey_fsck_err_on(bpos_lt(k.k->p, b->data->min_key), c, err,
prt_printf(err, "key past end of btree node"); bkey_before_start_of_btree_node,
return -BCH_ERR_invalid_bkey; "key before start of btree node");
}
return 0; bkey_fsck_err_on(bpos_gt(k.k->p, b->data->max_key), c, err,
bkey_after_end_of_btree_node,
"key past end of btree node");
fsck_err:
return ret;
} }
void bch2_bpos_to_text(struct printbuf *out, struct bpos pos) void bch2_bpos_to_text(struct printbuf *out, struct bpos pos)
......
...@@ -21,7 +21,7 @@ extern const struct bkey_ops bch2_bkey_null_ops; ...@@ -21,7 +21,7 @@ extern const struct bkey_ops bch2_bkey_null_ops;
* being read or written; more aggressive checks can be enabled when rw == WRITE. * being read or written; more aggressive checks can be enabled when rw == WRITE.
*/ */
struct bkey_ops { struct bkey_ops {
int (*key_invalid)(const struct bch_fs *c, struct bkey_s_c k, int (*key_invalid)(struct bch_fs *c, struct bkey_s_c k,
enum bkey_invalid_flags flags, struct printbuf *err); enum bkey_invalid_flags flags, struct printbuf *err);
void (*val_to_text)(struct printbuf *, struct bch_fs *, void (*val_to_text)(struct printbuf *, struct bch_fs *,
struct bkey_s_c); struct bkey_s_c);
...@@ -55,7 +55,8 @@ int __bch2_bkey_invalid(struct bch_fs *, struct bkey_s_c, enum btree_node_type, ...@@ -55,7 +55,8 @@ int __bch2_bkey_invalid(struct bch_fs *, struct bkey_s_c, enum btree_node_type,
enum bkey_invalid_flags, struct printbuf *); enum bkey_invalid_flags, struct printbuf *);
int bch2_bkey_invalid(struct bch_fs *, struct bkey_s_c, enum btree_node_type, int bch2_bkey_invalid(struct bch_fs *, struct bkey_s_c, enum btree_node_type,
enum bkey_invalid_flags, struct printbuf *); enum bkey_invalid_flags, struct printbuf *);
int bch2_bkey_in_btree_node(struct btree *, struct bkey_s_c, struct printbuf *); int bch2_bkey_in_btree_node(struct bch_fs *, struct btree *,
struct bkey_s_c, struct printbuf *);
void bch2_bpos_to_text(struct printbuf *, struct bpos); void bch2_bpos_to_text(struct printbuf *, struct bpos);
void bch2_bkey_to_text(struct printbuf *, const struct bkey *); void bch2_bkey_to_text(struct printbuf *, const struct bkey *);
......
This diff is collapsed.
This diff is collapsed.
...@@ -1274,14 +1274,14 @@ static void bch2_insert_fixup_btree_ptr(struct btree_update *as, ...@@ -1274,14 +1274,14 @@ static void bch2_insert_fixup_btree_ptr(struct btree_update *as,
if (bch2_bkey_invalid(c, bkey_i_to_s_c(insert), if (bch2_bkey_invalid(c, bkey_i_to_s_c(insert),
btree_node_type(b), WRITE, &buf) ?: btree_node_type(b), WRITE, &buf) ?:
bch2_bkey_in_btree_node(b, bkey_i_to_s_c(insert), &buf)) { bch2_bkey_in_btree_node(c, b, bkey_i_to_s_c(insert), &buf)) {
printbuf_reset(&buf); printbuf_reset(&buf);
prt_printf(&buf, "inserting invalid bkey\n "); prt_printf(&buf, "inserting invalid bkey\n ");
bch2_bkey_val_to_text(&buf, c, bkey_i_to_s_c(insert)); bch2_bkey_val_to_text(&buf, c, bkey_i_to_s_c(insert));
prt_printf(&buf, "\n "); prt_printf(&buf, "\n ");
bch2_bkey_invalid(c, bkey_i_to_s_c(insert), bch2_bkey_invalid(c, bkey_i_to_s_c(insert),
btree_node_type(b), WRITE, &buf); btree_node_type(b), WRITE, &buf);
bch2_bkey_in_btree_node(b, bkey_i_to_s_c(insert), &buf); bch2_bkey_in_btree_node(c, b, bkey_i_to_s_c(insert), &buf);
bch2_fs_inconsistent(c, "%s", buf.buf); bch2_fs_inconsistent(c, "%s", buf.buf);
dump_stack(); dump_stack();
......
...@@ -370,8 +370,8 @@ static inline int update_replicas(struct bch_fs *c, struct bkey_s_c k, ...@@ -370,8 +370,8 @@ static inline int update_replicas(struct bch_fs *c, struct bkey_s_c k,
idx = bch2_replicas_entry_idx(c, r); idx = bch2_replicas_entry_idx(c, r);
if (idx < 0 && if (idx < 0 &&
fsck_err(c, "no replicas entry\n" fsck_err(c, ptr_to_missing_replicas_entry,
" while marking %s", "no replicas entry\n while marking %s",
(bch2_bkey_val_to_text(&buf, c, k), buf.buf))) { (bch2_bkey_val_to_text(&buf, c, k), buf.buf))) {
percpu_up_read(&c->mark_lock); percpu_up_read(&c->mark_lock);
ret = bch2_mark_replicas(c, r); ret = bch2_mark_replicas(c, r);
...@@ -695,6 +695,7 @@ static int check_bucket_ref(struct btree_trans *trans, ...@@ -695,6 +695,7 @@ static int check_bucket_ref(struct btree_trans *trans,
if (gen_after(ptr->gen, b_gen)) { if (gen_after(ptr->gen, b_gen)) {
bch2_fsck_err(c, FSCK_CAN_IGNORE|FSCK_NEED_FSCK, bch2_fsck_err(c, FSCK_CAN_IGNORE|FSCK_NEED_FSCK,
BCH_FSCK_ERR_ptr_gen_newer_than_bucket_gen,
"bucket %u:%zu gen %u data type %s: ptr gen %u newer than bucket gen\n" "bucket %u:%zu gen %u data type %s: ptr gen %u newer than bucket gen\n"
"while marking %s", "while marking %s",
ptr->dev, bucket_nr, b_gen, ptr->dev, bucket_nr, b_gen,
...@@ -707,6 +708,7 @@ static int check_bucket_ref(struct btree_trans *trans, ...@@ -707,6 +708,7 @@ static int check_bucket_ref(struct btree_trans *trans,
if (gen_cmp(b_gen, ptr->gen) > BUCKET_GC_GEN_MAX) { if (gen_cmp(b_gen, ptr->gen) > BUCKET_GC_GEN_MAX) {
bch2_fsck_err(c, FSCK_CAN_IGNORE|FSCK_NEED_FSCK, bch2_fsck_err(c, FSCK_CAN_IGNORE|FSCK_NEED_FSCK,
BCH_FSCK_ERR_ptr_too_stale,
"bucket %u:%zu gen %u data type %s: ptr gen %u too stale\n" "bucket %u:%zu gen %u data type %s: ptr gen %u too stale\n"
"while marking %s", "while marking %s",
ptr->dev, bucket_nr, b_gen, ptr->dev, bucket_nr, b_gen,
...@@ -720,6 +722,7 @@ static int check_bucket_ref(struct btree_trans *trans, ...@@ -720,6 +722,7 @@ static int check_bucket_ref(struct btree_trans *trans,
if (b_gen != ptr->gen && !ptr->cached) { if (b_gen != ptr->gen && !ptr->cached) {
bch2_fsck_err(c, FSCK_CAN_IGNORE|FSCK_NEED_FSCK, bch2_fsck_err(c, FSCK_CAN_IGNORE|FSCK_NEED_FSCK,
BCH_FSCK_ERR_stale_dirty_ptr,
"bucket %u:%zu gen %u (mem gen %u) data type %s: stale dirty ptr (gen %u)\n" "bucket %u:%zu gen %u (mem gen %u) data type %s: stale dirty ptr (gen %u)\n"
"while marking %s", "while marking %s",
ptr->dev, bucket_nr, b_gen, ptr->dev, bucket_nr, b_gen,
...@@ -741,6 +744,7 @@ static int check_bucket_ref(struct btree_trans *trans, ...@@ -741,6 +744,7 @@ static int check_bucket_ref(struct btree_trans *trans,
ptr_data_type && ptr_data_type &&
bucket_data_type != ptr_data_type) { bucket_data_type != ptr_data_type) {
bch2_fsck_err(c, FSCK_CAN_IGNORE|FSCK_NEED_FSCK, bch2_fsck_err(c, FSCK_CAN_IGNORE|FSCK_NEED_FSCK,
BCH_FSCK_ERR_ptr_bucket_data_type_mismatch,
"bucket %u:%zu gen %u different types of data in same bucket: %s, %s\n" "bucket %u:%zu gen %u different types of data in same bucket: %s, %s\n"
"while marking %s", "while marking %s",
ptr->dev, bucket_nr, b_gen, ptr->dev, bucket_nr, b_gen,
...@@ -754,6 +758,7 @@ static int check_bucket_ref(struct btree_trans *trans, ...@@ -754,6 +758,7 @@ static int check_bucket_ref(struct btree_trans *trans,
if ((u64) bucket_sectors + sectors > U32_MAX) { if ((u64) bucket_sectors + sectors > U32_MAX) {
bch2_fsck_err(c, FSCK_CAN_IGNORE|FSCK_NEED_FSCK, bch2_fsck_err(c, FSCK_CAN_IGNORE|FSCK_NEED_FSCK,
BCH_FSCK_ERR_bucket_sector_count_overflow,
"bucket %u:%zu gen %u data type %s sector count overflow: %u + %lli > U32_MAX\n" "bucket %u:%zu gen %u data type %s sector count overflow: %u + %lli > U32_MAX\n"
"while marking %s", "while marking %s",
ptr->dev, bucket_nr, b_gen, ptr->dev, bucket_nr, b_gen,
...@@ -1195,7 +1200,8 @@ static s64 __bch2_mark_reflink_p(struct btree_trans *trans, ...@@ -1195,7 +1200,8 @@ static s64 __bch2_mark_reflink_p(struct btree_trans *trans,
*idx = r->offset; *idx = r->offset;
return 0; return 0;
not_found: not_found:
if (fsck_err(c, "pointer to missing indirect extent\n" if (fsck_err(c, reflink_p_to_missing_reflink_v,
"pointer to missing indirect extent\n"
" %s\n" " %s\n"
" missing range %llu-%llu", " missing range %llu-%llu",
(bch2_bkey_val_to_text(&buf, c, p.s_c), buf.buf), (bch2_bkey_val_to_text(&buf, c, p.s_c), buf.buf),
...@@ -1857,6 +1863,7 @@ static int __bch2_trans_mark_metadata_bucket(struct btree_trans *trans, ...@@ -1857,6 +1863,7 @@ static int __bch2_trans_mark_metadata_bucket(struct btree_trans *trans,
if (a->v.data_type && type && a->v.data_type != type) { if (a->v.data_type && type && a->v.data_type != type) {
bch2_fsck_err(c, FSCK_CAN_IGNORE|FSCK_NEED_FSCK, bch2_fsck_err(c, FSCK_CAN_IGNORE|FSCK_NEED_FSCK,
BCH_FSCK_ERR_bucket_metadata_type_mismatch,
"bucket %llu:%llu gen %u different types of data in same bucket: %s, %s\n" "bucket %llu:%llu gen %u different types of data in same bucket: %s, %s\n"
"while marking %s", "while marking %s",
iter.pos.inode, iter.pos.offset, a->v.gen, iter.pos.inode, iter.pos.offset, a->v.gen,
......
...@@ -97,61 +97,51 @@ const struct bch_hash_desc bch2_dirent_hash_desc = { ...@@ -97,61 +97,51 @@ const struct bch_hash_desc bch2_dirent_hash_desc = {
.is_visible = dirent_is_visible, .is_visible = dirent_is_visible,
}; };
int bch2_dirent_invalid(const struct bch_fs *c, struct bkey_s_c k, int bch2_dirent_invalid(struct bch_fs *c, struct bkey_s_c k,
enum bkey_invalid_flags flags, enum bkey_invalid_flags flags,
struct printbuf *err) struct printbuf *err)
{ {
struct bkey_s_c_dirent d = bkey_s_c_to_dirent(k); struct bkey_s_c_dirent d = bkey_s_c_to_dirent(k);
struct qstr d_name = bch2_dirent_get_name(d); struct qstr d_name = bch2_dirent_get_name(d);
int ret = 0;
if (!d_name.len) { bkey_fsck_err_on(!d_name.len, c, err,
prt_printf(err, "empty name"); dirent_empty_name,
return -BCH_ERR_invalid_bkey; "empty name");
}
if (bkey_val_u64s(k.k) > dirent_val_u64s(d_name.len)) { bkey_fsck_err_on(bkey_val_u64s(k.k) > dirent_val_u64s(d_name.len), c, err,
prt_printf(err, "value too big (%zu > %u)", dirent_val_too_big,
"value too big (%zu > %u)",
bkey_val_u64s(k.k), dirent_val_u64s(d_name.len)); bkey_val_u64s(k.k), dirent_val_u64s(d_name.len));
return -BCH_ERR_invalid_bkey;
}
/* /*
* Check new keys don't exceed the max length * Check new keys don't exceed the max length
* (older keys may be larger.) * (older keys may be larger.)
*/ */
if ((flags & BKEY_INVALID_COMMIT) && d_name.len > BCH_NAME_MAX) { bkey_fsck_err_on((flags & BKEY_INVALID_COMMIT) && d_name.len > BCH_NAME_MAX, c, err,
prt_printf(err, "dirent name too big (%u > %u)", dirent_name_too_long,
"dirent name too big (%u > %u)",
d_name.len, BCH_NAME_MAX); d_name.len, BCH_NAME_MAX);
return -BCH_ERR_invalid_bkey;
}
if (d_name.len != strnlen(d_name.name, d_name.len)) {
prt_printf(err, "dirent has stray data after name's NUL");
return -BCH_ERR_invalid_bkey;
}
if (d_name.len == 1 && !memcmp(d_name.name, ".", 1)) { bkey_fsck_err_on(d_name.len != strnlen(d_name.name, d_name.len), c, err,
prt_printf(err, "invalid name"); dirent_name_embedded_nul,
return -BCH_ERR_invalid_bkey; "dirent has stray data after name's NUL");
}
if (d_name.len == 2 && !memcmp(d_name.name, "..", 2)) {
prt_printf(err, "invalid name");
return -BCH_ERR_invalid_bkey;
}
if (memchr(d_name.name, '/', d_name.len)) { bkey_fsck_err_on((d_name.len == 1 && !memcmp(d_name.name, ".", 1)) ||
prt_printf(err, "invalid name"); (d_name.len == 2 && !memcmp(d_name.name, "..", 2)), c, err,
return -BCH_ERR_invalid_bkey; dirent_name_dot_or_dotdot,
} "invalid name");
if (d.v->d_type != DT_SUBVOL && bkey_fsck_err_on(memchr(d_name.name, '/', d_name.len), c, err,
le64_to_cpu(d.v->d_inum) == d.k->p.inode) { dirent_name_has_slash,
prt_printf(err, "dirent points to own directory"); "name with /");
return -BCH_ERR_invalid_bkey;
}
return 0; bkey_fsck_err_on(d.v->d_type != DT_SUBVOL &&
le64_to_cpu(d.v->d_inum) == d.k->p.inode, c, err,
dirent_to_itself,
"dirent points to own directory");
fsck_err:
return ret;
} }
void bch2_dirent_to_text(struct printbuf *out, struct bch_fs *c, void bch2_dirent_to_text(struct printbuf *out, struct bch_fs *c,
......
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
enum bkey_invalid_flags; enum bkey_invalid_flags;
extern const struct bch_hash_desc bch2_dirent_hash_desc; extern const struct bch_hash_desc bch2_dirent_hash_desc;
int bch2_dirent_invalid(const struct bch_fs *, struct bkey_s_c, int bch2_dirent_invalid(struct bch_fs *, struct bkey_s_c,
enum bkey_invalid_flags, struct printbuf *); enum bkey_invalid_flags, struct printbuf *);
void bch2_dirent_to_text(struct printbuf *, struct bch_fs *, struct bkey_s_c); void bch2_dirent_to_text(struct printbuf *, struct bch_fs *, struct bkey_s_c);
......
...@@ -105,29 +105,26 @@ struct ec_bio { ...@@ -105,29 +105,26 @@ struct ec_bio {
/* Stripes btree keys: */ /* Stripes btree keys: */
int bch2_stripe_invalid(const struct bch_fs *c, struct bkey_s_c k, int bch2_stripe_invalid(struct bch_fs *c, struct bkey_s_c k,
enum bkey_invalid_flags flags, enum bkey_invalid_flags flags,
struct printbuf *err) struct printbuf *err)
{ {
const struct bch_stripe *s = bkey_s_c_to_stripe(k).v; const struct bch_stripe *s = bkey_s_c_to_stripe(k).v;
int ret = 0;
if (bkey_eq(k.k->p, POS_MIN)) { bkey_fsck_err_on(bkey_eq(k.k->p, POS_MIN) ||
prt_printf(err, "stripe at POS_MIN"); bpos_gt(k.k->p, POS(0, U32_MAX)), c, err,
return -BCH_ERR_invalid_bkey; stripe_pos_bad,
} "stripe at bad pos");
if (k.k->p.inode) {
prt_printf(err, "nonzero inode field");
return -BCH_ERR_invalid_bkey;
}
if (bkey_val_u64s(k.k) < stripe_val_u64s(s)) { bkey_fsck_err_on(bkey_val_u64s(k.k) < stripe_val_u64s(s), c, err,
prt_printf(err, "incorrect value size (%zu < %u)", stripe_val_size_bad,
"incorrect value size (%zu < %u)",
bkey_val_u64s(k.k), stripe_val_u64s(s)); bkey_val_u64s(k.k), stripe_val_u64s(s));
return -BCH_ERR_invalid_bkey;
}
return bch2_bkey_ptrs_invalid(c, k, flags, err); ret = bch2_bkey_ptrs_invalid(c, k, flags, err);
fsck_err:
return ret;
} }
void bch2_stripe_to_text(struct printbuf *out, struct bch_fs *c, void bch2_stripe_to_text(struct printbuf *out, struct bch_fs *c,
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
enum bkey_invalid_flags; enum bkey_invalid_flags;
int bch2_stripe_invalid(const struct bch_fs *, struct bkey_s_c, int bch2_stripe_invalid(struct bch_fs *, struct bkey_s_c,
enum bkey_invalid_flags, struct printbuf *); enum bkey_invalid_flags, struct printbuf *);
void bch2_stripe_to_text(struct printbuf *, struct bch_fs *, void bch2_stripe_to_text(struct printbuf *, struct bch_fs *,
struct bkey_s_c); struct bkey_s_c);
......
...@@ -141,7 +141,10 @@ static struct fsck_err_state *fsck_err_get(struct bch_fs *c, const char *fmt) ...@@ -141,7 +141,10 @@ static struct fsck_err_state *fsck_err_get(struct bch_fs *c, const char *fmt)
return s; return s;
} }
int bch2_fsck_err(struct bch_fs *c, unsigned flags, const char *fmt, ...) int bch2_fsck_err(struct bch_fs *c,
enum bch_fsck_flags flags,
enum bch_sb_error_id err,
const char *fmt, ...)
{ {
struct fsck_err_state *s = NULL; struct fsck_err_state *s = NULL;
va_list args; va_list args;
...@@ -149,6 +152,8 @@ int bch2_fsck_err(struct bch_fs *c, unsigned flags, const char *fmt, ...) ...@@ -149,6 +152,8 @@ int bch2_fsck_err(struct bch_fs *c, unsigned flags, const char *fmt, ...)
struct printbuf buf = PRINTBUF, *out = &buf; struct printbuf buf = PRINTBUF, *out = &buf;
int ret = -BCH_ERR_fsck_ignore; int ret = -BCH_ERR_fsck_ignore;
bch2_sb_error_count(c, err);
va_start(args, fmt); va_start(args, fmt);
prt_vprintf(out, fmt, args); prt_vprintf(out, fmt, args);
va_end(args); va_end(args);
......
...@@ -4,6 +4,7 @@ ...@@ -4,6 +4,7 @@
#include <linux/list.h> #include <linux/list.h>
#include <linux/printk.h> #include <linux/printk.h>
#include "sb-errors.h"
struct bch_dev; struct bch_dev;
struct bch_fs; struct bch_fs;
...@@ -101,18 +102,26 @@ struct fsck_err_state { ...@@ -101,18 +102,26 @@ struct fsck_err_state {
char *last_msg; char *last_msg;
}; };
#define FSCK_CAN_FIX (1 << 0) enum bch_fsck_flags {
#define FSCK_CAN_IGNORE (1 << 1) FSCK_CAN_FIX = 1 << 0,
#define FSCK_NEED_FSCK (1 << 2) FSCK_CAN_IGNORE = 1 << 1,
#define FSCK_NO_RATELIMIT (1 << 3) FSCK_NEED_FSCK = 1 << 2,
FSCK_NO_RATELIMIT = 1 << 3,
};
#define fsck_err_count(_c, _err) bch2_sb_err_count(_c, BCH_FSCK_ERR_##_err)
__printf(3, 4) __cold __printf(4, 5) __cold
int bch2_fsck_err(struct bch_fs *, unsigned, const char *, ...); int bch2_fsck_err(struct bch_fs *,
enum bch_fsck_flags,
enum bch_sb_error_id,
const char *, ...);
void bch2_flush_fsck_errs(struct bch_fs *); void bch2_flush_fsck_errs(struct bch_fs *);
#define __fsck_err(c, _flags, msg, ...) \ #define __fsck_err(c, _flags, _err_type, ...) \
({ \ ({ \
int _ret = bch2_fsck_err(c, _flags, msg, ##__VA_ARGS__); \ int _ret = bch2_fsck_err(c, _flags, BCH_FSCK_ERR_##_err_type, \
__VA_ARGS__); \
\ \
if (_ret != -BCH_ERR_fsck_fix && \ if (_ret != -BCH_ERR_fsck_fix && \
_ret != -BCH_ERR_fsck_ignore) { \ _ret != -BCH_ERR_fsck_ignore) { \
...@@ -127,26 +136,53 @@ void bch2_flush_fsck_errs(struct bch_fs *); ...@@ -127,26 +136,53 @@ void bch2_flush_fsck_errs(struct bch_fs *);
/* XXX: mark in superblock that filesystem contains errors, if we ignore: */ /* XXX: mark in superblock that filesystem contains errors, if we ignore: */
#define __fsck_err_on(cond, c, _flags, ...) \ #define __fsck_err_on(cond, c, _flags, _err_type, ...) \
(unlikely(cond) ? __fsck_err(c, _flags, ##__VA_ARGS__) : false) (unlikely(cond) ? __fsck_err(c, _flags, _err_type, __VA_ARGS__) : false)
#define need_fsck_err_on(cond, c, _err_type, ...) \
__fsck_err_on(cond, c, FSCK_CAN_IGNORE|FSCK_NEED_FSCK, _err_type, __VA_ARGS__)
#define need_fsck_err(c, _err_type, ...) \
__fsck_err(c, FSCK_CAN_IGNORE|FSCK_NEED_FSCK, _err_type, __VA_ARGS__)
#define mustfix_fsck_err(c, _err_type, ...) \
__fsck_err(c, FSCK_CAN_FIX, _err_type, __VA_ARGS__)
#define mustfix_fsck_err_on(cond, c, _err_type, ...) \
__fsck_err_on(cond, c, FSCK_CAN_FIX, _err_type, __VA_ARGS__)
#define need_fsck_err_on(cond, c, ...) \ #define fsck_err(c, _err_type, ...) \
__fsck_err_on(cond, c, FSCK_CAN_IGNORE|FSCK_NEED_FSCK, ##__VA_ARGS__) __fsck_err(c, FSCK_CAN_FIX|FSCK_CAN_IGNORE, _err_type, __VA_ARGS__)
#define need_fsck_err(c, ...) \ #define fsck_err_on(cond, c, _err_type, ...) \
__fsck_err(c, FSCK_CAN_IGNORE|FSCK_NEED_FSCK, ##__VA_ARGS__) __fsck_err_on(cond, c, FSCK_CAN_FIX|FSCK_CAN_IGNORE, _err_type, __VA_ARGS__)
#define mustfix_fsck_err(c, ...) \ static inline void bch2_bkey_fsck_err(struct bch_fs *c,
__fsck_err(c, FSCK_CAN_FIX, ##__VA_ARGS__) struct printbuf *err_msg,
enum bch_sb_error_id err_type,
const char *fmt, ...)
{
va_list args;
#define mustfix_fsck_err_on(cond, c, ...) \ va_start(args, fmt);
__fsck_err_on(cond, c, FSCK_CAN_FIX, ##__VA_ARGS__) prt_vprintf(err_msg, fmt, args);
va_end(args);
#define fsck_err(c, ...) \ }
__fsck_err(c, FSCK_CAN_FIX|FSCK_CAN_IGNORE, ##__VA_ARGS__)
#define fsck_err_on(cond, c, ...) \ #define bkey_fsck_err(c, _err_msg, _err_type, ...) \
__fsck_err_on(cond, c, FSCK_CAN_FIX|FSCK_CAN_IGNORE, ##__VA_ARGS__) do { \
prt_printf(_err_msg, __VA_ARGS__); \
bch2_sb_error_count(c, BCH_FSCK_ERR_##_err_type); \
ret = -BCH_ERR_invalid_bkey; \
goto fsck_err; \
} while (0)
#define bkey_fsck_err_on(cond, ...) \
do { \
if (unlikely(cond)) \
bkey_fsck_err(__VA_ARGS__); \
} while (0)
/* /*
* Fatal errors: these don't indicate a bug, but we can't continue running in RW * Fatal errors: these don't indicate a bug, but we can't continue running in RW
......
This diff is collapsed.
...@@ -400,12 +400,12 @@ int bch2_bkey_pick_read_device(struct bch_fs *, struct bkey_s_c, ...@@ -400,12 +400,12 @@ int bch2_bkey_pick_read_device(struct bch_fs *, struct bkey_s_c,
/* KEY_TYPE_btree_ptr: */ /* KEY_TYPE_btree_ptr: */
int bch2_btree_ptr_invalid(const struct bch_fs *, struct bkey_s_c, int bch2_btree_ptr_invalid(struct bch_fs *, struct bkey_s_c,
enum bkey_invalid_flags, struct printbuf *); enum bkey_invalid_flags, struct printbuf *);
void bch2_btree_ptr_to_text(struct printbuf *, struct bch_fs *, void bch2_btree_ptr_to_text(struct printbuf *, struct bch_fs *,
struct bkey_s_c); struct bkey_s_c);
int bch2_btree_ptr_v2_invalid(const struct bch_fs *, struct bkey_s_c, int bch2_btree_ptr_v2_invalid(struct bch_fs *, struct bkey_s_c,
enum bkey_invalid_flags, struct printbuf *); enum bkey_invalid_flags, struct printbuf *);
void bch2_btree_ptr_v2_to_text(struct printbuf *, struct bch_fs *, struct bkey_s_c); void bch2_btree_ptr_v2_to_text(struct printbuf *, struct bch_fs *, struct bkey_s_c);
void bch2_btree_ptr_v2_compat(enum btree_id, unsigned, unsigned, void bch2_btree_ptr_v2_compat(enum btree_id, unsigned, unsigned,
...@@ -445,7 +445,7 @@ bool bch2_extent_merge(struct bch_fs *, struct bkey_s, struct bkey_s_c); ...@@ -445,7 +445,7 @@ bool bch2_extent_merge(struct bch_fs *, struct bkey_s, struct bkey_s_c);
/* KEY_TYPE_reservation: */ /* KEY_TYPE_reservation: */
int bch2_reservation_invalid(const struct bch_fs *, struct bkey_s_c, int bch2_reservation_invalid(struct bch_fs *, struct bkey_s_c,
enum bkey_invalid_flags, struct printbuf *); enum bkey_invalid_flags, struct printbuf *);
void bch2_reservation_to_text(struct printbuf *, struct bch_fs *, struct bkey_s_c); void bch2_reservation_to_text(struct printbuf *, struct bch_fs *, struct bkey_s_c);
bool bch2_reservation_merge(struct bch_fs *, struct bkey_s, struct bkey_s_c); bool bch2_reservation_merge(struct bch_fs *, struct bkey_s, struct bkey_s_c);
...@@ -705,7 +705,7 @@ void bch2_extent_ptr_set_cached(struct bkey_s, struct bch_extent_ptr *); ...@@ -705,7 +705,7 @@ void bch2_extent_ptr_set_cached(struct bkey_s, struct bch_extent_ptr *);
bool bch2_extent_normalize(struct bch_fs *, struct bkey_s); bool bch2_extent_normalize(struct bch_fs *, struct bkey_s);
void bch2_bkey_ptrs_to_text(struct printbuf *, struct bch_fs *, void bch2_bkey_ptrs_to_text(struct printbuf *, struct bch_fs *,
struct bkey_s_c); struct bkey_s_c);
int bch2_bkey_ptrs_invalid(const struct bch_fs *, struct bkey_s_c, int bch2_bkey_ptrs_invalid(struct bch_fs *, struct bkey_s_c,
enum bkey_invalid_flags, struct printbuf *); enum bkey_invalid_flags, struct printbuf *);
void bch2_ptr_swab(struct bkey_s); void bch2_ptr_swab(struct bkey_s);
......
This diff is collapsed.
...@@ -398,104 +398,102 @@ struct bkey_i *bch2_inode_to_v3(struct btree_trans *trans, struct bkey_i *k) ...@@ -398,104 +398,102 @@ struct bkey_i *bch2_inode_to_v3(struct btree_trans *trans, struct bkey_i *k)
return &inode_p->inode.k_i; return &inode_p->inode.k_i;
} }
static int __bch2_inode_invalid(struct bkey_s_c k, struct printbuf *err) static int __bch2_inode_invalid(struct bch_fs *c, struct bkey_s_c k, struct printbuf *err)
{ {
struct bch_inode_unpacked unpacked; struct bch_inode_unpacked unpacked;
int ret = 0;
if (k.k->p.inode) { bkey_fsck_err_on(k.k->p.inode, c, err,
prt_printf(err, "nonzero k.p.inode"); inode_pos_inode_nonzero,
return -BCH_ERR_invalid_bkey; "nonzero k.p.inode");
}
if (k.k->p.offset < BLOCKDEV_INODE_MAX) { bkey_fsck_err_on(k.k->p.offset < BLOCKDEV_INODE_MAX, c, err,
prt_printf(err, "fs inode in blockdev range"); inode_pos_blockdev_range,
return -BCH_ERR_invalid_bkey; "fs inode in blockdev range");
}
if (bch2_inode_unpack(k, &unpacked)) { bkey_fsck_err_on(bch2_inode_unpack(k, &unpacked), c, err,
prt_printf(err, "invalid variable length fields"); inode_unpack_error,
return -BCH_ERR_invalid_bkey; "invalid variable length fields");
}
if (unpacked.bi_data_checksum >= BCH_CSUM_OPT_NR + 1) { bkey_fsck_err_on(unpacked.bi_data_checksum >= BCH_CSUM_OPT_NR + 1, c, err,
prt_printf(err, "invalid data checksum type (%u >= %u", inode_checksum_type_invalid,
"invalid data checksum type (%u >= %u",
unpacked.bi_data_checksum, BCH_CSUM_OPT_NR + 1); unpacked.bi_data_checksum, BCH_CSUM_OPT_NR + 1);
return -BCH_ERR_invalid_bkey;
}
if (unpacked.bi_compression && bkey_fsck_err_on(unpacked.bi_compression &&
!bch2_compression_opt_valid(unpacked.bi_compression - 1)) { !bch2_compression_opt_valid(unpacked.bi_compression - 1), c, err,
prt_printf(err, "invalid compression opt %u", inode_compression_type_invalid,
unpacked.bi_compression - 1); "invalid compression opt %u", unpacked.bi_compression - 1);
return -BCH_ERR_invalid_bkey;
}
if ((unpacked.bi_flags & BCH_INODE_UNLINKED) && bkey_fsck_err_on((unpacked.bi_flags & BCH_INODE_UNLINKED) &&
unpacked.bi_nlink != 0) { unpacked.bi_nlink != 0, c, err,
prt_printf(err, "flagged as unlinked but bi_nlink != 0"); inode_unlinked_but_nlink_nonzero,
return -BCH_ERR_invalid_bkey; "flagged as unlinked but bi_nlink != 0");
}
if (unpacked.bi_subvol && !S_ISDIR(unpacked.bi_mode)) { bkey_fsck_err_on(unpacked.bi_subvol && !S_ISDIR(unpacked.bi_mode), c, err,
prt_printf(err, "subvolume root but not a directory"); inode_subvol_root_but_not_dir,
return -BCH_ERR_invalid_bkey; "subvolume root but not a directory");
} fsck_err:
return ret;
return 0;
} }
int bch2_inode_invalid(const struct bch_fs *c, struct bkey_s_c k, int bch2_inode_invalid(struct bch_fs *c, struct bkey_s_c k,
enum bkey_invalid_flags flags, enum bkey_invalid_flags flags,
struct printbuf *err) struct printbuf *err)
{ {
struct bkey_s_c_inode inode = bkey_s_c_to_inode(k); struct bkey_s_c_inode inode = bkey_s_c_to_inode(k);
int ret = 0;
if (INODE_STR_HASH(inode.v) >= BCH_STR_HASH_NR) { bkey_fsck_err_on(INODE_STR_HASH(inode.v) >= BCH_STR_HASH_NR, c, err,
prt_printf(err, "invalid str hash type (%llu >= %u)", inode_str_hash_invalid,
"invalid str hash type (%llu >= %u)",
INODE_STR_HASH(inode.v), BCH_STR_HASH_NR); INODE_STR_HASH(inode.v), BCH_STR_HASH_NR);
return -BCH_ERR_invalid_bkey;
}
return __bch2_inode_invalid(k, err); ret = __bch2_inode_invalid(c, k, err);
fsck_err:
return ret;
} }
int bch2_inode_v2_invalid(const struct bch_fs *c, struct bkey_s_c k, int bch2_inode_v2_invalid(struct bch_fs *c, struct bkey_s_c k,
enum bkey_invalid_flags flags, enum bkey_invalid_flags flags,
struct printbuf *err) struct printbuf *err)
{ {
struct bkey_s_c_inode_v2 inode = bkey_s_c_to_inode_v2(k); struct bkey_s_c_inode_v2 inode = bkey_s_c_to_inode_v2(k);
int ret = 0;
if (INODEv2_STR_HASH(inode.v) >= BCH_STR_HASH_NR) { bkey_fsck_err_on(INODEv2_STR_HASH(inode.v) >= BCH_STR_HASH_NR, c, err,
prt_printf(err, "invalid str hash type (%llu >= %u)", inode_str_hash_invalid,
"invalid str hash type (%llu >= %u)",
INODEv2_STR_HASH(inode.v), BCH_STR_HASH_NR); INODEv2_STR_HASH(inode.v), BCH_STR_HASH_NR);
return -BCH_ERR_invalid_bkey;
}
return __bch2_inode_invalid(k, err); ret = __bch2_inode_invalid(c, k, err);
fsck_err:
return ret;
} }
int bch2_inode_v3_invalid(const struct bch_fs *c, struct bkey_s_c k, int bch2_inode_v3_invalid(struct bch_fs *c, struct bkey_s_c k,
enum bkey_invalid_flags flags, enum bkey_invalid_flags flags,
struct printbuf *err) struct printbuf *err)
{ {
struct bkey_s_c_inode_v3 inode = bkey_s_c_to_inode_v3(k); struct bkey_s_c_inode_v3 inode = bkey_s_c_to_inode_v3(k);
int ret = 0;
if (INODEv3_FIELDS_START(inode.v) < INODEv3_FIELDS_START_INITIAL || bkey_fsck_err_on(INODEv3_FIELDS_START(inode.v) < INODEv3_FIELDS_START_INITIAL ||
INODEv3_FIELDS_START(inode.v) > bkey_val_u64s(inode.k)) { INODEv3_FIELDS_START(inode.v) > bkey_val_u64s(inode.k), c, err,
prt_printf(err, "invalid fields_start (got %llu, min %u max %zu)", inode_v3_fields_start_bad,
"invalid fields_start (got %llu, min %u max %zu)",
INODEv3_FIELDS_START(inode.v), INODEv3_FIELDS_START(inode.v),
INODEv3_FIELDS_START_INITIAL, INODEv3_FIELDS_START_INITIAL,
bkey_val_u64s(inode.k)); bkey_val_u64s(inode.k));
return -BCH_ERR_invalid_bkey;
}
if (INODEv3_STR_HASH(inode.v) >= BCH_STR_HASH_NR) { bkey_fsck_err_on(INODEv3_STR_HASH(inode.v) >= BCH_STR_HASH_NR, c, err,
prt_printf(err, "invalid str hash type (%llu >= %u)", inode_str_hash_invalid,
"invalid str hash type (%llu >= %u)",
INODEv3_STR_HASH(inode.v), BCH_STR_HASH_NR); INODEv3_STR_HASH(inode.v), BCH_STR_HASH_NR);
return -BCH_ERR_invalid_bkey;
}
return __bch2_inode_invalid(k, err); ret = __bch2_inode_invalid(c, k, err);
fsck_err:
return ret;
} }
static void __bch2_inode_unpacked_to_text(struct printbuf *out, static void __bch2_inode_unpacked_to_text(struct printbuf *out,
...@@ -612,16 +610,17 @@ int bch2_mark_inode(struct btree_trans *trans, ...@@ -612,16 +610,17 @@ int bch2_mark_inode(struct btree_trans *trans,
return 0; return 0;
} }
int bch2_inode_generation_invalid(const struct bch_fs *c, struct bkey_s_c k, int bch2_inode_generation_invalid(struct bch_fs *c, struct bkey_s_c k,
enum bkey_invalid_flags flags, enum bkey_invalid_flags flags,
struct printbuf *err) struct printbuf *err)
{ {
if (k.k->p.inode) { int ret = 0;
prt_printf(err, "nonzero k.p.inode");
return -BCH_ERR_invalid_bkey;
}
return 0; bkey_fsck_err_on(k.k->p.inode, c, err,
inode_pos_inode_nonzero,
"nonzero k.p.inode");
fsck_err:
return ret;
} }
void bch2_inode_generation_to_text(struct printbuf *out, struct bch_fs *c, void bch2_inode_generation_to_text(struct printbuf *out, struct bch_fs *c,
...@@ -1068,6 +1067,7 @@ static int may_delete_deleted_inode(struct btree_trans *trans, struct bpos pos) ...@@ -1068,6 +1067,7 @@ static int may_delete_deleted_inode(struct btree_trans *trans, struct bpos pos)
return 0; return 0;
if (!fsck_err_on(c->sb.clean, c, if (!fsck_err_on(c->sb.clean, c,
deleted_inode_but_clean,
"filesystem marked as clean but have deleted inode %llu:%u", "filesystem marked as clean but have deleted inode %llu:%u",
pos.offset, pos.snapshot)) pos.offset, pos.snapshot))
return 0; return 0;
...@@ -1079,6 +1079,7 @@ static int may_delete_deleted_inode(struct btree_trans *trans, struct bpos pos) ...@@ -1079,6 +1079,7 @@ static int may_delete_deleted_inode(struct btree_trans *trans, struct bpos pos)
ret = bkey_is_inode(k.k) ? 0 : -BCH_ERR_ENOENT_inode; ret = bkey_is_inode(k.k) ? 0 : -BCH_ERR_ENOENT_inode;
if (fsck_err_on(!bkey_is_inode(k.k), c, if (fsck_err_on(!bkey_is_inode(k.k), c,
deleted_inode_missing,
"nonexistent inode %llu:%u in deleted_inodes btree", "nonexistent inode %llu:%u in deleted_inodes btree",
pos.offset, pos.snapshot)) pos.offset, pos.snapshot))
goto delete; goto delete;
...@@ -1088,11 +1089,13 @@ static int may_delete_deleted_inode(struct btree_trans *trans, struct bpos pos) ...@@ -1088,11 +1089,13 @@ static int may_delete_deleted_inode(struct btree_trans *trans, struct bpos pos)
goto err; goto err;
if (fsck_err_on(S_ISDIR(inode.bi_mode), c, if (fsck_err_on(S_ISDIR(inode.bi_mode), c,
deleted_inode_is_dir,
"directory %llu:%u in deleted_inodes btree", "directory %llu:%u in deleted_inodes btree",
pos.offset, pos.snapshot)) pos.offset, pos.snapshot))
goto delete; goto delete;
if (fsck_err_on(!(inode.bi_flags & BCH_INODE_UNLINKED), c, if (fsck_err_on(!(inode.bi_flags & BCH_INODE_UNLINKED), c,
deleted_inode_not_unlinked,
"non-deleted inode %llu:%u in deleted_inodes btree", "non-deleted inode %llu:%u in deleted_inodes btree",
pos.offset, pos.snapshot)) pos.offset, pos.snapshot))
goto delete; goto delete;
......
...@@ -8,11 +8,11 @@ ...@@ -8,11 +8,11 @@
enum bkey_invalid_flags; enum bkey_invalid_flags;
extern const char * const bch2_inode_opts[]; extern const char * const bch2_inode_opts[];
int bch2_inode_invalid(const struct bch_fs *, struct bkey_s_c, int bch2_inode_invalid(struct bch_fs *, struct bkey_s_c,
enum bkey_invalid_flags, struct printbuf *); enum bkey_invalid_flags, struct printbuf *);
int bch2_inode_v2_invalid(const struct bch_fs *, struct bkey_s_c, int bch2_inode_v2_invalid(struct bch_fs *, struct bkey_s_c,
enum bkey_invalid_flags, struct printbuf *); enum bkey_invalid_flags, struct printbuf *);
int bch2_inode_v3_invalid(const struct bch_fs *, struct bkey_s_c, int bch2_inode_v3_invalid(struct bch_fs *, struct bkey_s_c,
enum bkey_invalid_flags, struct printbuf *); enum bkey_invalid_flags, struct printbuf *);
void bch2_inode_to_text(struct printbuf *, struct bch_fs *, struct bkey_s_c); void bch2_inode_to_text(struct printbuf *, struct bch_fs *, struct bkey_s_c);
...@@ -52,7 +52,7 @@ static inline bool bkey_is_inode(const struct bkey *k) ...@@ -52,7 +52,7 @@ static inline bool bkey_is_inode(const struct bkey *k)
k->type == KEY_TYPE_inode_v3; k->type == KEY_TYPE_inode_v3;
} }
int bch2_inode_generation_invalid(const struct bch_fs *, struct bkey_s_c, int bch2_inode_generation_invalid(struct bch_fs *, struct bkey_s_c,
enum bkey_invalid_flags, struct printbuf *); enum bkey_invalid_flags, struct printbuf *);
void bch2_inode_generation_to_text(struct printbuf *, struct bch_fs *, struct bkey_s_c); void bch2_inode_generation_to_text(struct printbuf *, struct bch_fs *, struct bkey_s_c);
......
This diff is collapsed.
...@@ -10,17 +10,17 @@ ...@@ -10,17 +10,17 @@
#include "recovery.h" #include "recovery.h"
/* KEY_TYPE_lru is obsolete: */ /* KEY_TYPE_lru is obsolete: */
int bch2_lru_invalid(const struct bch_fs *c, struct bkey_s_c k, int bch2_lru_invalid(struct bch_fs *c, struct bkey_s_c k,
enum bkey_invalid_flags flags, enum bkey_invalid_flags flags,
struct printbuf *err) struct printbuf *err)
{ {
if (!lru_pos_time(k.k->p)) { int ret = 0;
prt_printf(err, "lru entry at time=0");
return -BCH_ERR_invalid_bkey;
}
return 0; bkey_fsck_err_on(!lru_pos_time(k.k->p), c, err,
lru_entry_at_time_0,
"lru entry at time=0");
fsck_err:
return ret;
} }
void bch2_lru_to_text(struct printbuf *out, struct bch_fs *c, void bch2_lru_to_text(struct printbuf *out, struct bch_fs *c,
...@@ -95,6 +95,7 @@ static int bch2_check_lru_key(struct btree_trans *trans, ...@@ -95,6 +95,7 @@ static int bch2_check_lru_key(struct btree_trans *trans,
int ret; int ret;
if (fsck_err_on(!bch2_dev_bucket_exists(c, alloc_pos), c, if (fsck_err_on(!bch2_dev_bucket_exists(c, alloc_pos), c,
lru_entry_to_invalid_bucket,
"lru key points to nonexistent device:bucket %llu:%llu", "lru key points to nonexistent device:bucket %llu:%llu",
alloc_pos.inode, alloc_pos.offset)) alloc_pos.inode, alloc_pos.offset))
return bch2_btree_delete_at(trans, lru_iter, 0); return bch2_btree_delete_at(trans, lru_iter, 0);
...@@ -125,7 +126,8 @@ static int bch2_check_lru_key(struct btree_trans *trans, ...@@ -125,7 +126,8 @@ static int bch2_check_lru_key(struct btree_trans *trans,
} }
if (c->opts.reconstruct_alloc || if (c->opts.reconstruct_alloc ||
fsck_err(c, "incorrect lru entry: lru %s time %llu\n" fsck_err(c, lru_entry_bad,
"incorrect lru entry: lru %s time %llu\n"
" %s\n" " %s\n"
" for %s", " for %s",
bch2_lru_types[type], bch2_lru_types[type],
......
...@@ -48,7 +48,7 @@ static inline enum bch_lru_type lru_type(struct bkey_s_c l) ...@@ -48,7 +48,7 @@ static inline enum bch_lru_type lru_type(struct bkey_s_c l)
return BCH_LRU_read; return BCH_LRU_read;
} }
int bch2_lru_invalid(const struct bch_fs *, struct bkey_s_c, int bch2_lru_invalid(struct bch_fs *, struct bkey_s_c,
enum bkey_invalid_flags, struct printbuf *); enum bkey_invalid_flags, struct printbuf *);
void bch2_lru_to_text(struct printbuf *, struct bch_fs *, struct bkey_s_c); void bch2_lru_to_text(struct printbuf *, struct bch_fs *, struct bkey_s_c);
......
...@@ -59,17 +59,18 @@ const struct bch_sb_field_ops bch_sb_field_ops_quota = { ...@@ -59,17 +59,18 @@ const struct bch_sb_field_ops bch_sb_field_ops_quota = {
.to_text = bch2_sb_quota_to_text, .to_text = bch2_sb_quota_to_text,
}; };
int bch2_quota_invalid(const struct bch_fs *c, struct bkey_s_c k, int bch2_quota_invalid(struct bch_fs *c, struct bkey_s_c k,
enum bkey_invalid_flags flags, enum bkey_invalid_flags flags,
struct printbuf *err) struct printbuf *err)
{ {
if (k.k->p.inode >= QTYP_NR) { int ret = 0;
prt_printf(err, "invalid quota type (%llu >= %u)",
k.k->p.inode, QTYP_NR);
return -BCH_ERR_invalid_bkey;
}
return 0; bkey_fsck_err_on(k.k->p.inode >= QTYP_NR, c, err,
quota_type_invalid,
"invalid quota type (%llu >= %u)",
k.k->p.inode, QTYP_NR);
fsck_err:
return ret;
} }
void bch2_quota_to_text(struct printbuf *out, struct bch_fs *c, void bch2_quota_to_text(struct printbuf *out, struct bch_fs *c,
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
enum bkey_invalid_flags; enum bkey_invalid_flags;
extern const struct bch_sb_field_ops bch_sb_field_ops_quota; extern const struct bch_sb_field_ops bch_sb_field_ops_quota;
int bch2_quota_invalid(const struct bch_fs *, struct bkey_s_c, int bch2_quota_invalid(struct bch_fs *, struct bkey_s_c,
enum bkey_invalid_flags, struct printbuf *); enum bkey_invalid_flags, struct printbuf *);
void bch2_quota_to_text(struct printbuf *, struct bch_fs *, struct bkey_s_c); void bch2_quota_to_text(struct printbuf *, struct bch_fs *, struct bkey_s_c);
......
...@@ -365,8 +365,10 @@ static int read_btree_roots(struct bch_fs *c) ...@@ -365,8 +365,10 @@ static int read_btree_roots(struct bch_fs *c)
} }
if (r->error) { if (r->error) {
__fsck_err(c, btree_id_is_alloc(i) __fsck_err(c,
btree_id_is_alloc(i)
? FSCK_CAN_IGNORE : 0, ? FSCK_CAN_IGNORE : 0,
btree_root_bkey_invalid,
"invalid btree root %s", "invalid btree root %s",
bch2_btree_id_str(i)); bch2_btree_id_str(i));
if (i == BTREE_ID_alloc) if (i == BTREE_ID_alloc)
...@@ -376,6 +378,7 @@ static int read_btree_roots(struct bch_fs *c) ...@@ -376,6 +378,7 @@ static int read_btree_roots(struct bch_fs *c)
ret = bch2_btree_root_read(c, i, &r->key, r->level); ret = bch2_btree_root_read(c, i, &r->key, r->level);
if (ret) { if (ret) {
fsck_err(c, fsck_err(c,
btree_root_read_error,
"error reading btree root %s", "error reading btree root %s",
bch2_btree_id_str(i)); bch2_btree_id_str(i));
if (btree_id_is_alloc(i)) if (btree_id_is_alloc(i))
...@@ -714,6 +717,7 @@ int bch2_fs_recovery(struct bch_fs *c) ...@@ -714,6 +717,7 @@ int bch2_fs_recovery(struct bch_fs *c)
if (mustfix_fsck_err_on(c->sb.clean && if (mustfix_fsck_err_on(c->sb.clean &&
last_journal_entry && last_journal_entry &&
!journal_entry_empty(last_journal_entry), c, !journal_entry_empty(last_journal_entry), c,
clean_but_journal_not_empty,
"filesystem marked clean but journal not empty")) { "filesystem marked clean but journal not empty")) {
c->sb.compat &= ~(1ULL << BCH_COMPAT_alloc_info); c->sb.compat &= ~(1ULL << BCH_COMPAT_alloc_info);
SET_BCH_SB_CLEAN(c->disk_sb.sb, false); SET_BCH_SB_CLEAN(c->disk_sb.sb, false);
...@@ -721,7 +725,9 @@ int bch2_fs_recovery(struct bch_fs *c) ...@@ -721,7 +725,9 @@ int bch2_fs_recovery(struct bch_fs *c)
} }
if (!last_journal_entry) { if (!last_journal_entry) {
fsck_err_on(!c->sb.clean, c, "no journal entries found"); fsck_err_on(!c->sb.clean, c,
dirty_but_no_journal_entries,
"no journal entries found");
if (clean) if (clean)
goto use_clean; goto use_clean;
......
...@@ -28,7 +28,7 @@ static inline unsigned bkey_type_to_indirect(const struct bkey *k) ...@@ -28,7 +28,7 @@ static inline unsigned bkey_type_to_indirect(const struct bkey *k)
/* reflink pointers */ /* reflink pointers */
int bch2_reflink_p_invalid(const struct bch_fs *c, struct bkey_s_c k, int bch2_reflink_p_invalid(struct bch_fs *c, struct bkey_s_c k,
enum bkey_invalid_flags flags, enum bkey_invalid_flags flags,
struct printbuf *err) struct printbuf *err)
{ {
...@@ -75,7 +75,7 @@ bool bch2_reflink_p_merge(struct bch_fs *c, struct bkey_s _l, struct bkey_s_c _r ...@@ -75,7 +75,7 @@ bool bch2_reflink_p_merge(struct bch_fs *c, struct bkey_s _l, struct bkey_s_c _r
/* indirect extents */ /* indirect extents */
int bch2_reflink_v_invalid(const struct bch_fs *c, struct bkey_s_c k, int bch2_reflink_v_invalid(struct bch_fs *c, struct bkey_s_c k,
enum bkey_invalid_flags flags, enum bkey_invalid_flags flags,
struct printbuf *err) struct printbuf *err)
{ {
...@@ -126,7 +126,7 @@ int bch2_trans_mark_reflink_v(struct btree_trans *trans, ...@@ -126,7 +126,7 @@ int bch2_trans_mark_reflink_v(struct btree_trans *trans,
/* indirect inline data */ /* indirect inline data */
int bch2_indirect_inline_data_invalid(const struct bch_fs *c, struct bkey_s_c k, int bch2_indirect_inline_data_invalid(struct bch_fs *c, struct bkey_s_c k,
enum bkey_invalid_flags flags, enum bkey_invalid_flags flags,
struct printbuf *err) struct printbuf *err)
{ {
......
...@@ -4,7 +4,7 @@ ...@@ -4,7 +4,7 @@
enum bkey_invalid_flags; enum bkey_invalid_flags;
int bch2_reflink_p_invalid(const struct bch_fs *, struct bkey_s_c, int bch2_reflink_p_invalid(struct bch_fs *, struct bkey_s_c,
enum bkey_invalid_flags, struct printbuf *); enum bkey_invalid_flags, struct printbuf *);
void bch2_reflink_p_to_text(struct printbuf *, struct bch_fs *, void bch2_reflink_p_to_text(struct printbuf *, struct bch_fs *,
struct bkey_s_c); struct bkey_s_c);
...@@ -19,7 +19,7 @@ bool bch2_reflink_p_merge(struct bch_fs *, struct bkey_s, struct bkey_s_c); ...@@ -19,7 +19,7 @@ bool bch2_reflink_p_merge(struct bch_fs *, struct bkey_s, struct bkey_s_c);
.min_val_size = 16, \ .min_val_size = 16, \
}) })
int bch2_reflink_v_invalid(const struct bch_fs *, struct bkey_s_c, int bch2_reflink_v_invalid(struct bch_fs *, struct bkey_s_c,
enum bkey_invalid_flags, struct printbuf *); enum bkey_invalid_flags, struct printbuf *);
void bch2_reflink_v_to_text(struct printbuf *, struct bch_fs *, void bch2_reflink_v_to_text(struct printbuf *, struct bch_fs *,
struct bkey_s_c); struct bkey_s_c);
...@@ -35,7 +35,7 @@ int bch2_trans_mark_reflink_v(struct btree_trans *, enum btree_id, unsigned, ...@@ -35,7 +35,7 @@ int bch2_trans_mark_reflink_v(struct btree_trans *, enum btree_id, unsigned,
.min_val_size = 8, \ .min_val_size = 8, \
}) })
int bch2_indirect_inline_data_invalid(const struct bch_fs *, struct bkey_s_c, int bch2_indirect_inline_data_invalid(struct bch_fs *, struct bkey_s_c,
enum bkey_invalid_flags, struct printbuf *); enum bkey_invalid_flags, struct printbuf *);
void bch2_indirect_inline_data_to_text(struct printbuf *, void bch2_indirect_inline_data_to_text(struct printbuf *,
struct bch_fs *, struct bkey_s_c); struct bch_fs *, struct bkey_s_c);
......
...@@ -82,6 +82,7 @@ int bch2_verify_superblock_clean(struct bch_fs *c, ...@@ -82,6 +82,7 @@ int bch2_verify_superblock_clean(struct bch_fs *c,
int ret = 0; int ret = 0;
if (mustfix_fsck_err_on(j->seq != clean->journal_seq, c, if (mustfix_fsck_err_on(j->seq != clean->journal_seq, c,
sb_clean_journal_seq_mismatch,
"superblock journal seq (%llu) doesn't match journal (%llu) after clean shutdown", "superblock journal seq (%llu) doesn't match journal (%llu) after clean shutdown",
le64_to_cpu(clean->journal_seq), le64_to_cpu(clean->journal_seq),
le64_to_cpu(j->seq))) { le64_to_cpu(j->seq))) {
...@@ -119,6 +120,7 @@ int bch2_verify_superblock_clean(struct bch_fs *c, ...@@ -119,6 +120,7 @@ int bch2_verify_superblock_clean(struct bch_fs *c,
k1->k.u64s != k2->k.u64s || k1->k.u64s != k2->k.u64s ||
memcmp(k1, k2, bkey_bytes(&k1->k)) || memcmp(k1, k2, bkey_bytes(&k1->k)) ||
l1 != l2, c, l1 != l2, c,
sb_clean_btree_root_mismatch,
"superblock btree root %u doesn't match journal after clean shutdown\n" "superblock btree root %u doesn't match journal after clean shutdown\n"
"sb: l=%u %s\n" "sb: l=%u %s\n"
"journal: l=%u %s\n", i, "journal: l=%u %s\n", i,
...@@ -140,6 +142,7 @@ struct bch_sb_field_clean *bch2_read_superblock_clean(struct bch_fs *c) ...@@ -140,6 +142,7 @@ struct bch_sb_field_clean *bch2_read_superblock_clean(struct bch_fs *c)
sb_clean = bch2_sb_field_get(c->disk_sb.sb, clean); sb_clean = bch2_sb_field_get(c->disk_sb.sb, clean);
if (fsck_err_on(!sb_clean, c, if (fsck_err_on(!sb_clean, c,
sb_clean_missing,
"superblock marked clean but clean section not present")) { "superblock marked clean but clean section not present")) {
SET_BCH_SB_CLEAN(c->disk_sb.sb, false); SET_BCH_SB_CLEAN(c->disk_sb.sb, false);
c->sb.clean = false; c->sb.clean = false;
......
...@@ -4,7 +4,251 @@ ...@@ -4,7 +4,251 @@
#include "sb-errors_types.h" #include "sb-errors_types.h"
#define BCH_SB_ERRS() #define BCH_SB_ERRS() \
x(clean_but_journal_not_empty, 0) \
x(dirty_but_no_journal_entries, 1) \
x(dirty_but_no_journal_entries_post_drop_nonflushes, 2) \
x(sb_clean_journal_seq_mismatch, 3) \
x(sb_clean_btree_root_mismatch, 4) \
x(sb_clean_missing, 5) \
x(jset_unsupported_version, 6) \
x(jset_unknown_csum, 7) \
x(jset_last_seq_newer_than_seq, 8) \
x(jset_past_bucket_end, 9) \
x(jset_seq_blacklisted, 10) \
x(journal_entries_missing, 11) \
x(journal_entry_replicas_not_marked, 12) \
x(journal_entry_past_jset_end, 13) \
x(journal_entry_replicas_data_mismatch, 14) \
x(journal_entry_bkey_u64s_0, 15) \
x(journal_entry_bkey_past_end, 16) \
x(journal_entry_bkey_bad_format, 17) \
x(journal_entry_bkey_invalid, 18) \
x(journal_entry_btree_root_bad_size, 19) \
x(journal_entry_blacklist_bad_size, 20) \
x(journal_entry_blacklist_v2_bad_size, 21) \
x(journal_entry_blacklist_v2_start_past_end, 22) \
x(journal_entry_usage_bad_size, 23) \
x(journal_entry_data_usage_bad_size, 24) \
x(journal_entry_clock_bad_size, 25) \
x(journal_entry_clock_bad_rw, 26) \
x(journal_entry_dev_usage_bad_size, 27) \
x(journal_entry_dev_usage_bad_dev, 28) \
x(journal_entry_dev_usage_bad_pad, 29) \
x(btree_node_unreadable, 30) \
x(btree_node_fault_injected, 31) \
x(btree_node_bad_magic, 32) \
x(btree_node_bad_seq, 33) \
x(btree_node_unsupported_version, 34) \
x(btree_node_bset_older_than_sb_min, 35) \
x(btree_node_bset_newer_than_sb, 36) \
x(btree_node_data_missing, 37) \
x(btree_node_bset_after_end, 38) \
x(btree_node_replicas_sectors_written_mismatch, 39) \
x(btree_node_replicas_data_mismatch, 40) \
x(bset_unknown_csum, 41) \
x(bset_bad_csum, 42) \
x(bset_past_end_of_btree_node, 43) \
x(bset_wrong_sector_offset, 44) \
x(bset_empty, 45) \
x(bset_bad_seq, 46) \
x(bset_blacklisted_journal_seq, 47) \
x(first_bset_blacklisted_journal_seq, 48) \
x(btree_node_bad_btree, 49) \
x(btree_node_bad_level, 50) \
x(btree_node_bad_min_key, 51) \
x(btree_node_bad_max_key, 52) \
x(btree_node_bad_format, 53) \
x(btree_node_bkey_past_bset_end, 54) \
x(btree_node_bkey_bad_format, 55) \
x(btree_node_bad_bkey, 56) \
x(btree_node_bkey_out_of_order, 57) \
x(btree_root_bkey_invalid, 58) \
x(btree_root_read_error, 59) \
x(btree_root_bad_min_key, 50) \
x(btree_root_bad_max_key, 61) \
x(btree_node_read_error, 62) \
x(btree_node_topology_bad_min_key, 63) \
x(btree_node_topology_bad_max_key, 64) \
x(btree_node_topology_overwritten_by_prev_node, 65) \
x(btree_node_topology_overwritten_by_next_node, 66) \
x(btree_node_topology_interior_node_empty, 67) \
x(fs_usage_hidden_wrong, 68) \
x(fs_usage_btree_wrong, 69) \
x(fs_usage_data_wrong, 70) \
x(fs_usage_cached_wrong, 71) \
x(fs_usage_reserved_wrong, 72) \
x(fs_usage_persistent_reserved_wrong, 73) \
x(fs_usage_nr_inodes_wrong, 74) \
x(fs_usage_replicas_wrong, 75) \
x(dev_usage_buckets_wrong, 76) \
x(dev_usage_sectors_wrong, 77) \
x(dev_usage_fragmented_wrong, 78) \
x(dev_usage_buckets_ec_wrong, 79) \
x(bkey_version_in_future, 80) \
x(bkey_u64s_too_small, 81) \
x(bkey_invalid_type_for_btree, 82) \
x(bkey_extent_size_zero, 83) \
x(bkey_extent_size_greater_than_offset, 84) \
x(bkey_size_nonzero, 85) \
x(bkey_snapshot_nonzero, 86) \
x(bkey_snapshot_zero, 87) \
x(bkey_at_pos_max, 88) \
x(bkey_before_start_of_btree_node, 89) \
x(bkey_after_end_of_btree_node, 90) \
x(bkey_val_size_nonzero, 91) \
x(bkey_val_size_too_small, 92) \
x(alloc_v1_val_size_bad, 93) \
x(alloc_v2_unpack_error, 94) \
x(alloc_v3_unpack_error, 95) \
x(alloc_v4_val_size_bad, 96) \
x(alloc_v4_backpointers_start_bad, 97) \
x(alloc_key_data_type_bad, 98) \
x(alloc_key_empty_but_have_data, 99) \
x(alloc_key_dirty_sectors_0, 100) \
x(alloc_key_data_type_inconsistency, 101) \
x(alloc_key_to_missing_dev_bucket, 102) \
x(alloc_key_cached_inconsistency, 103) \
x(alloc_key_cached_but_read_time_zero, 104) \
x(alloc_key_to_missing_lru_entry, 105) \
x(alloc_key_data_type_wrong, 106) \
x(alloc_key_gen_wrong, 107) \
x(alloc_key_dirty_sectors_wrong, 108) \
x(alloc_key_cached_sectors_wrong, 109) \
x(alloc_key_stripe_wrong, 110) \
x(alloc_key_stripe_redundancy_wrong, 111) \
x(bucket_sector_count_overflow, 112) \
x(bucket_metadata_type_mismatch, 113) \
x(need_discard_key_wrong, 114) \
x(freespace_key_wrong, 115) \
x(freespace_hole_missing, 116) \
x(bucket_gens_val_size_bad, 117) \
x(bucket_gens_key_wrong, 118) \
x(bucket_gens_hole_wrong, 119) \
x(bucket_gens_to_invalid_dev, 120) \
x(bucket_gens_to_invalid_buckets, 121) \
x(bucket_gens_nonzero_for_invalid_buckets, 122) \
x(need_discard_freespace_key_to_invalid_dev_bucket, 123) \
x(need_discard_freespace_key_bad, 124) \
x(backpointer_pos_wrong, 125) \
x(backpointer_to_missing_device, 126) \
x(backpointer_to_missing_alloc, 127) \
x(backpointer_to_missing_ptr, 128) \
x(lru_entry_at_time_0, 129) \
x(lru_entry_to_invalid_bucket, 130) \
x(lru_entry_bad, 131) \
x(btree_ptr_val_too_big, 132) \
x(btree_ptr_v2_val_too_big, 133) \
x(btree_ptr_has_non_ptr, 134) \
x(extent_ptrs_invalid_entry, 135) \
x(extent_ptrs_no_ptrs, 136) \
x(extent_ptrs_too_many_ptrs, 137) \
x(extent_ptrs_redundant_crc, 138) \
x(extent_ptrs_redundant_stripe, 139) \
x(extent_ptrs_unwritten, 140) \
x(extent_ptrs_written_and_unwritten, 141) \
x(ptr_to_invalid_device, 142) \
x(ptr_to_duplicate_device, 143) \
x(ptr_after_last_bucket, 144) \
x(ptr_before_first_bucket, 145) \
x(ptr_spans_multiple_buckets, 146) \
x(ptr_to_missing_backpointer, 147) \
x(ptr_to_missing_alloc_key, 148) \
x(ptr_to_missing_replicas_entry, 149) \
x(ptr_to_missing_stripe, 150) \
x(ptr_to_incorrect_stripe, 151) \
x(ptr_gen_newer_than_bucket_gen, 152) \
x(ptr_too_stale, 153) \
x(stale_dirty_ptr, 154) \
x(ptr_bucket_data_type_mismatch, 155) \
x(ptr_cached_and_erasure_coded, 156) \
x(ptr_crc_uncompressed_size_too_small, 157) \
x(ptr_crc_csum_type_unknown, 158) \
x(ptr_crc_compression_type_unknown, 159) \
x(ptr_crc_redundant, 160) \
x(ptr_crc_uncompressed_size_too_big, 161) \
x(ptr_crc_nonce_mismatch, 162) \
x(ptr_stripe_redundant, 163) \
x(reservation_key_nr_replicas_invalid, 164) \
x(reflink_v_refcount_wrong, 165) \
x(reflink_p_to_missing_reflink_v, 166) \
x(stripe_pos_bad, 167) \
x(stripe_val_size_bad, 168) \
x(stripe_sector_count_wrong, 169) \
x(snapshot_tree_pos_bad, 170) \
x(snapshot_tree_to_missing_snapshot, 171) \
x(snapshot_tree_to_missing_subvol, 172) \
x(snapshot_tree_to_wrong_subvol, 173) \
x(snapshot_tree_to_snapshot_subvol, 174) \
x(snapshot_pos_bad, 175) \
x(snapshot_parent_bad, 176) \
x(snapshot_children_not_normalized, 177) \
x(snapshot_child_duplicate, 178) \
x(snapshot_child_bad, 179) \
x(snapshot_skiplist_not_normalized, 180) \
x(snapshot_skiplist_bad, 181) \
x(snapshot_should_not_have_subvol, 182) \
x(snapshot_to_bad_snapshot_tree, 183) \
x(snapshot_bad_depth, 184) \
x(snapshot_bad_skiplist, 185) \
x(subvol_pos_bad, 186) \
x(subvol_not_master_and_not_snapshot, 187) \
x(subvol_to_missing_root, 188) \
x(subvol_root_wrong_bi_subvol, 189) \
x(bkey_in_missing_snapshot, 190) \
x(inode_pos_inode_nonzero, 191) \
x(inode_pos_blockdev_range, 192) \
x(inode_unpack_error, 193) \
x(inode_str_hash_invalid, 194) \
x(inode_v3_fields_start_bad, 195) \
x(inode_snapshot_mismatch, 196) \
x(inode_unlinked_but_clean, 197) \
x(inode_unlinked_but_nlink_nonzero, 198) \
x(inode_checksum_type_invalid, 199) \
x(inode_compression_type_invalid, 200) \
x(inode_subvol_root_but_not_dir, 201) \
x(inode_i_size_dirty_but_clean, 202) \
x(inode_i_sectors_dirty_but_clean, 203) \
x(inode_i_sectors_wrong, 204) \
x(inode_dir_wrong_nlink, 205) \
x(inode_dir_multiple_links, 206) \
x(inode_multiple_links_but_nlink_0, 207) \
x(inode_wrong_backpointer, 208) \
x(inode_wrong_nlink, 209) \
x(inode_unreachable, 210) \
x(deleted_inode_but_clean, 211) \
x(deleted_inode_missing, 212) \
x(deleted_inode_is_dir, 213) \
x(deleted_inode_not_unlinked, 214) \
x(extent_overlapping, 215) \
x(extent_in_missing_inode, 216) \
x(extent_in_non_reg_inode, 217) \
x(extent_past_end_of_inode, 218) \
x(dirent_empty_name, 219) \
x(dirent_val_too_big, 220) \
x(dirent_name_too_long, 221) \
x(dirent_name_embedded_nul, 222) \
x(dirent_name_dot_or_dotdot, 223) \
x(dirent_name_has_slash, 224) \
x(dirent_d_type_wrong, 225) \
x(dirent_d_parent_subvol_wrong, 226) \
x(dirent_in_missing_dir_inode, 227) \
x(dirent_in_non_dir_inode, 228) \
x(dirent_to_missing_inode, 229) \
x(dirent_to_missing_subvol, 230) \
x(dirent_to_itself, 231) \
x(quota_type_invalid, 232) \
x(xattr_val_size_too_small, 233) \
x(xattr_val_size_too_big, 234) \
x(xattr_invalid_type, 235) \
x(xattr_name_invalid_chars, 236) \
x(xattr_in_missing_inode, 237) \
x(root_subvol_missing, 238) \
x(root_dir_missing, 239) \
x(root_inode_not_dir, 240) \
x(dir_loop, 241) \
x(hash_table_key_duplicate, 242) \
x(hash_table_key_wrong_offset, 243)
enum bch_sb_error_id { enum bch_sb_error_id {
#define x(t, n) BCH_FSCK_ERR_##t = n, #define x(t, n) BCH_FSCK_ERR_##t = n,
......
...@@ -30,17 +30,18 @@ void bch2_snapshot_tree_to_text(struct printbuf *out, struct bch_fs *c, ...@@ -30,17 +30,18 @@ void bch2_snapshot_tree_to_text(struct printbuf *out, struct bch_fs *c,
le32_to_cpu(t.v->root_snapshot)); le32_to_cpu(t.v->root_snapshot));
} }
int bch2_snapshot_tree_invalid(const struct bch_fs *c, struct bkey_s_c k, int bch2_snapshot_tree_invalid(struct bch_fs *c, struct bkey_s_c k,
enum bkey_invalid_flags flags, enum bkey_invalid_flags flags,
struct printbuf *err) struct printbuf *err)
{ {
if (bkey_gt(k.k->p, POS(0, U32_MAX)) || int ret = 0;
bkey_lt(k.k->p, POS(0, 1))) {
prt_printf(err, "bad pos");
return -BCH_ERR_invalid_bkey;
}
return 0; bkey_fsck_err_on(bkey_gt(k.k->p, POS(0, U32_MAX)) ||
bkey_lt(k.k->p, POS(0, 1)), c, err,
snapshot_tree_pos_bad,
"bad pos");
fsck_err:
return ret;
} }
int bch2_snapshot_tree_lookup(struct btree_trans *trans, u32 id, int bch2_snapshot_tree_lookup(struct btree_trans *trans, u32 id,
...@@ -202,67 +203,60 @@ void bch2_snapshot_to_text(struct printbuf *out, struct bch_fs *c, ...@@ -202,67 +203,60 @@ void bch2_snapshot_to_text(struct printbuf *out, struct bch_fs *c,
le32_to_cpu(s.v->skip[2])); le32_to_cpu(s.v->skip[2]));
} }
int bch2_snapshot_invalid(const struct bch_fs *c, struct bkey_s_c k, int bch2_snapshot_invalid(struct bch_fs *c, struct bkey_s_c k,
enum bkey_invalid_flags flags, enum bkey_invalid_flags flags,
struct printbuf *err) struct printbuf *err)
{ {
struct bkey_s_c_snapshot s; struct bkey_s_c_snapshot s;
u32 i, id; u32 i, id;
int ret = 0;
if (bkey_gt(k.k->p, POS(0, U32_MAX)) || bkey_fsck_err_on(bkey_gt(k.k->p, POS(0, U32_MAX)) ||
bkey_lt(k.k->p, POS(0, 1))) { bkey_lt(k.k->p, POS(0, 1)), c, err,
prt_printf(err, "bad pos"); snapshot_pos_bad,
return -BCH_ERR_invalid_bkey; "bad pos");
}
s = bkey_s_c_to_snapshot(k); s = bkey_s_c_to_snapshot(k);
id = le32_to_cpu(s.v->parent); id = le32_to_cpu(s.v->parent);
if (id && id <= k.k->p.offset) { bkey_fsck_err_on(id && id <= k.k->p.offset, c, err,
prt_printf(err, "bad parent node (%u <= %llu)", snapshot_parent_bad,
"bad parent node (%u <= %llu)",
id, k.k->p.offset); id, k.k->p.offset);
return -BCH_ERR_invalid_bkey;
}
if (le32_to_cpu(s.v->children[0]) < le32_to_cpu(s.v->children[1])) { bkey_fsck_err_on(le32_to_cpu(s.v->children[0]) < le32_to_cpu(s.v->children[1]), c, err,
prt_printf(err, "children not normalized"); snapshot_children_not_normalized,
return -BCH_ERR_invalid_bkey; "children not normalized");
}
if (s.v->children[0] && bkey_fsck_err_on(s.v->children[0] && s.v->children[0] == s.v->children[1], c, err,
s.v->children[0] == s.v->children[1]) { snapshot_child_duplicate,
prt_printf(err, "duplicate child nodes"); "duplicate child nodes");
return -BCH_ERR_invalid_bkey;
}
for (i = 0; i < 2; i++) { for (i = 0; i < 2; i++) {
id = le32_to_cpu(s.v->children[i]); id = le32_to_cpu(s.v->children[i]);
if (id >= k.k->p.offset) { bkey_fsck_err_on(id >= k.k->p.offset, c, err,
prt_printf(err, "bad child node (%u >= %llu)", snapshot_child_bad,
"bad child node (%u >= %llu)",
id, k.k->p.offset); id, k.k->p.offset);
return -BCH_ERR_invalid_bkey;
}
} }
if (bkey_val_bytes(k.k) > offsetof(struct bch_snapshot, skip)) { if (bkey_val_bytes(k.k) > offsetof(struct bch_snapshot, skip)) {
if (le32_to_cpu(s.v->skip[0]) > le32_to_cpu(s.v->skip[1]) || bkey_fsck_err_on(le32_to_cpu(s.v->skip[0]) > le32_to_cpu(s.v->skip[1]) ||
le32_to_cpu(s.v->skip[1]) > le32_to_cpu(s.v->skip[2])) { le32_to_cpu(s.v->skip[1]) > le32_to_cpu(s.v->skip[2]), c, err,
prt_printf(err, "skiplist not normalized"); snapshot_skiplist_not_normalized,
return -BCH_ERR_invalid_bkey; "skiplist not normalized");
}
for (i = 0; i < ARRAY_SIZE(s.v->skip); i++) { for (i = 0; i < ARRAY_SIZE(s.v->skip); i++) {
id = le32_to_cpu(s.v->skip[i]); id = le32_to_cpu(s.v->skip[i]);
if (id && id < le32_to_cpu(s.v->parent)) { bkey_fsck_err_on(id && id < le32_to_cpu(s.v->parent), c, err,
prt_printf(err, "bad skiplist node %u", id); snapshot_skiplist_bad,
return -BCH_ERR_invalid_bkey; "bad skiplist node %u", id);
}
} }
} }
fsck_err:
return 0; return ret;
} }
static void __set_is_ancestor_bitmap(struct bch_fs *c, u32 id) static void __set_is_ancestor_bitmap(struct bch_fs *c, u32 id)
...@@ -529,7 +523,7 @@ static int check_snapshot_tree(struct btree_trans *trans, ...@@ -529,7 +523,7 @@ static int check_snapshot_tree(struct btree_trans *trans,
if (fsck_err_on(ret || if (fsck_err_on(ret ||
root_id != bch2_snapshot_root(c, root_id) || root_id != bch2_snapshot_root(c, root_id) ||
st.k->p.offset != le32_to_cpu(s.tree), st.k->p.offset != le32_to_cpu(s.tree),
c, c, snapshot_tree_to_missing_snapshot,
"snapshot tree points to missing/incorrect snapshot:\n %s", "snapshot tree points to missing/incorrect snapshot:\n %s",
(bch2_bkey_val_to_text(&buf, c, st.s_c), buf.buf))) { (bch2_bkey_val_to_text(&buf, c, st.s_c), buf.buf))) {
ret = bch2_btree_delete_at(trans, iter, 0); ret = bch2_btree_delete_at(trans, iter, 0);
...@@ -541,17 +535,20 @@ static int check_snapshot_tree(struct btree_trans *trans, ...@@ -541,17 +535,20 @@ static int check_snapshot_tree(struct btree_trans *trans,
if (ret && !bch2_err_matches(ret, ENOENT)) if (ret && !bch2_err_matches(ret, ENOENT))
goto err; goto err;
if (fsck_err_on(ret, c, if (fsck_err_on(ret,
c, snapshot_tree_to_missing_subvol,
"snapshot tree points to missing subvolume:\n %s", "snapshot tree points to missing subvolume:\n %s",
(printbuf_reset(&buf), (printbuf_reset(&buf),
bch2_bkey_val_to_text(&buf, c, st.s_c), buf.buf)) || bch2_bkey_val_to_text(&buf, c, st.s_c), buf.buf)) ||
fsck_err_on(!bch2_snapshot_is_ancestor_early(c, fsck_err_on(!bch2_snapshot_is_ancestor_early(c,
le32_to_cpu(subvol.snapshot), le32_to_cpu(subvol.snapshot),
root_id), c, root_id),
c, snapshot_tree_to_wrong_subvol,
"snapshot tree points to subvolume that does not point to snapshot in this tree:\n %s", "snapshot tree points to subvolume that does not point to snapshot in this tree:\n %s",
(printbuf_reset(&buf), (printbuf_reset(&buf),
bch2_bkey_val_to_text(&buf, c, st.s_c), buf.buf)) || bch2_bkey_val_to_text(&buf, c, st.s_c), buf.buf)) ||
fsck_err_on(BCH_SUBVOLUME_SNAP(&subvol), c, fsck_err_on(BCH_SUBVOLUME_SNAP(&subvol),
c, snapshot_tree_to_snapshot_subvol,
"snapshot tree points to snapshot subvolume:\n %s", "snapshot tree points to snapshot subvolume:\n %s",
(printbuf_reset(&buf), (printbuf_reset(&buf),
bch2_bkey_val_to_text(&buf, c, st.s_c), buf.buf))) { bch2_bkey_val_to_text(&buf, c, st.s_c), buf.buf))) {
...@@ -787,7 +784,9 @@ static int check_snapshot(struct btree_trans *trans, ...@@ -787,7 +784,9 @@ static int check_snapshot(struct btree_trans *trans,
goto err; goto err;
} }
} else { } else {
if (fsck_err_on(s.subvol, c, "snapshot should not point to subvol:\n %s", if (fsck_err_on(s.subvol,
c, snapshot_should_not_have_subvol,
"snapshot should not point to subvol:\n %s",
(bch2_bkey_val_to_text(&buf, c, k), buf.buf))) { (bch2_bkey_val_to_text(&buf, c, k), buf.buf))) {
u = bch2_bkey_make_mut_typed(trans, iter, &k, 0, snapshot); u = bch2_bkey_make_mut_typed(trans, iter, &k, 0, snapshot);
ret = PTR_ERR_OR_ZERO(u); ret = PTR_ERR_OR_ZERO(u);
...@@ -803,7 +802,8 @@ static int check_snapshot(struct btree_trans *trans, ...@@ -803,7 +802,8 @@ static int check_snapshot(struct btree_trans *trans,
if (ret < 0) if (ret < 0)
goto err; goto err;
if (fsck_err_on(!ret, c, "snapshot points to missing/incorrect tree:\n %s", if (fsck_err_on(!ret, c, snapshot_to_bad_snapshot_tree,
"snapshot points to missing/incorrect tree:\n %s",
(bch2_bkey_val_to_text(&buf, c, k), buf.buf))) { (bch2_bkey_val_to_text(&buf, c, k), buf.buf))) {
ret = snapshot_tree_ptr_repair(trans, iter, k, &s); ret = snapshot_tree_ptr_repair(trans, iter, k, &s);
if (ret) if (ret)
...@@ -815,7 +815,8 @@ static int check_snapshot(struct btree_trans *trans, ...@@ -815,7 +815,8 @@ static int check_snapshot(struct btree_trans *trans,
if (le32_to_cpu(s.depth) != real_depth && if (le32_to_cpu(s.depth) != real_depth &&
(c->sb.version_upgrade_complete < bcachefs_metadata_version_snapshot_skiplists || (c->sb.version_upgrade_complete < bcachefs_metadata_version_snapshot_skiplists ||
fsck_err(c, "snapshot with incorrect depth field, should be %u:\n %s", fsck_err(c, snapshot_bad_depth,
"snapshot with incorrect depth field, should be %u:\n %s",
real_depth, (bch2_bkey_val_to_text(&buf, c, k), buf.buf)))) { real_depth, (bch2_bkey_val_to_text(&buf, c, k), buf.buf)))) {
u = bch2_bkey_make_mut_typed(trans, iter, &k, 0, snapshot); u = bch2_bkey_make_mut_typed(trans, iter, &k, 0, snapshot);
ret = PTR_ERR_OR_ZERO(u); ret = PTR_ERR_OR_ZERO(u);
...@@ -832,7 +833,8 @@ static int check_snapshot(struct btree_trans *trans, ...@@ -832,7 +833,8 @@ static int check_snapshot(struct btree_trans *trans,
if (!ret && if (!ret &&
(c->sb.version_upgrade_complete < bcachefs_metadata_version_snapshot_skiplists || (c->sb.version_upgrade_complete < bcachefs_metadata_version_snapshot_skiplists ||
fsck_err(c, "snapshot with bad skiplist field:\n %s", fsck_err(c, snapshot_bad_skiplist,
"snapshot with bad skiplist field:\n %s",
(bch2_bkey_val_to_text(&buf, c, k), buf.buf)))) { (bch2_bkey_val_to_text(&buf, c, k), buf.buf)))) {
u = bch2_bkey_make_mut_typed(trans, iter, &k, 0, snapshot); u = bch2_bkey_make_mut_typed(trans, iter, &k, 0, snapshot);
ret = PTR_ERR_OR_ZERO(u); ret = PTR_ERR_OR_ZERO(u);
......
...@@ -5,7 +5,7 @@ ...@@ -5,7 +5,7 @@
enum bkey_invalid_flags; enum bkey_invalid_flags;
void bch2_snapshot_tree_to_text(struct printbuf *, struct bch_fs *, struct bkey_s_c); void bch2_snapshot_tree_to_text(struct printbuf *, struct bch_fs *, struct bkey_s_c);
int bch2_snapshot_tree_invalid(const struct bch_fs *, struct bkey_s_c, int bch2_snapshot_tree_invalid(struct bch_fs *, struct bkey_s_c,
enum bkey_invalid_flags, struct printbuf *); enum bkey_invalid_flags, struct printbuf *);
#define bch2_bkey_ops_snapshot_tree ((struct bkey_ops) { \ #define bch2_bkey_ops_snapshot_tree ((struct bkey_ops) { \
...@@ -19,7 +19,7 @@ struct bkey_i_snapshot_tree *__bch2_snapshot_tree_create(struct btree_trans *); ...@@ -19,7 +19,7 @@ struct bkey_i_snapshot_tree *__bch2_snapshot_tree_create(struct btree_trans *);
int bch2_snapshot_tree_lookup(struct btree_trans *, u32, struct bch_snapshot_tree *); int bch2_snapshot_tree_lookup(struct btree_trans *, u32, struct bch_snapshot_tree *);
void bch2_snapshot_to_text(struct printbuf *, struct bch_fs *, struct bkey_s_c); void bch2_snapshot_to_text(struct printbuf *, struct bch_fs *, struct bkey_s_c);
int bch2_snapshot_invalid(const struct bch_fs *, struct bkey_s_c, int bch2_snapshot_invalid(struct bch_fs *, struct bkey_s_c,
enum bkey_invalid_flags, struct printbuf *); enum bkey_invalid_flags, struct printbuf *);
int bch2_mark_snapshot(struct btree_trans *, enum btree_id, unsigned, int bch2_mark_snapshot(struct btree_trans *, enum btree_id, unsigned,
struct bkey_s_c, struct bkey_s_c, unsigned); struct bkey_s_c, struct bkey_s_c, unsigned);
......
...@@ -62,7 +62,8 @@ static int check_subvol(struct btree_trans *trans, ...@@ -62,7 +62,8 @@ static int check_subvol(struct btree_trans *trans,
if (ret) if (ret)
return ret; return ret;
if (fsck_err_on(le32_to_cpu(st.master_subvol) != subvol.k->p.offset, c, if (fsck_err_on(le32_to_cpu(st.master_subvol) != subvol.k->p.offset,
c, subvol_not_master_and_not_snapshot,
"subvolume %llu is not set as snapshot but is not master subvolume", "subvolume %llu is not set as snapshot but is not master subvolume",
k.k->p.offset)) { k.k->p.offset)) {
struct bkey_i_subvolume *s = struct bkey_i_subvolume *s =
...@@ -97,16 +98,17 @@ int bch2_check_subvols(struct bch_fs *c) ...@@ -97,16 +98,17 @@ int bch2_check_subvols(struct bch_fs *c)
/* Subvolumes: */ /* Subvolumes: */
int bch2_subvolume_invalid(const struct bch_fs *c, struct bkey_s_c k, int bch2_subvolume_invalid(struct bch_fs *c, struct bkey_s_c k,
enum bkey_invalid_flags flags, struct printbuf *err) enum bkey_invalid_flags flags, struct printbuf *err)
{ {
if (bkey_lt(k.k->p, SUBVOL_POS_MIN) || int ret = 0;
bkey_gt(k.k->p, SUBVOL_POS_MAX)) {
prt_printf(err, "invalid pos");
return -BCH_ERR_invalid_bkey;
}
return 0; bkey_fsck_err_on(bkey_lt(k.k->p, SUBVOL_POS_MIN) ||
bkey_gt(k.k->p, SUBVOL_POS_MAX), c, err,
subvol_pos_bad,
"invalid pos");
fsck_err:
return ret;
} }
void bch2_subvolume_to_text(struct printbuf *out, struct bch_fs *c, void bch2_subvolume_to_text(struct printbuf *out, struct bch_fs *c,
......
...@@ -9,7 +9,7 @@ enum bkey_invalid_flags; ...@@ -9,7 +9,7 @@ enum bkey_invalid_flags;
int bch2_check_subvols(struct bch_fs *); int bch2_check_subvols(struct bch_fs *);
int bch2_subvolume_invalid(const struct bch_fs *, struct bkey_s_c, int bch2_subvolume_invalid(struct bch_fs *, struct bkey_s_c,
enum bkey_invalid_flags, struct printbuf *); enum bkey_invalid_flags, struct printbuf *);
void bch2_subvolume_to_text(struct printbuf *, struct bch_fs *, struct bkey_s_c); void bch2_subvolume_to_text(struct printbuf *, struct bch_fs *, struct bkey_s_c);
......
...@@ -70,46 +70,38 @@ const struct bch_hash_desc bch2_xattr_hash_desc = { ...@@ -70,46 +70,38 @@ const struct bch_hash_desc bch2_xattr_hash_desc = {
.cmp_bkey = xattr_cmp_bkey, .cmp_bkey = xattr_cmp_bkey,
}; };
int bch2_xattr_invalid(const struct bch_fs *c, struct bkey_s_c k, int bch2_xattr_invalid(struct bch_fs *c, struct bkey_s_c k,
enum bkey_invalid_flags flags, enum bkey_invalid_flags flags,
struct printbuf *err) struct printbuf *err)
{ {
const struct xattr_handler *handler;
struct bkey_s_c_xattr xattr = bkey_s_c_to_xattr(k); struct bkey_s_c_xattr xattr = bkey_s_c_to_xattr(k);
unsigned val_u64s = xattr_val_u64s(xattr.v->x_name_len,
le16_to_cpu(xattr.v->x_val_len));
int ret = 0;
if (bkey_val_u64s(k.k) < bkey_fsck_err_on(bkey_val_u64s(k.k) < val_u64s, c, err,
xattr_val_u64s(xattr.v->x_name_len, xattr_val_size_too_small,
le16_to_cpu(xattr.v->x_val_len))) { "value too small (%zu < %u)",
prt_printf(err, "value too small (%zu < %u)", bkey_val_u64s(k.k), val_u64s);
bkey_val_u64s(k.k),
xattr_val_u64s(xattr.v->x_name_len,
le16_to_cpu(xattr.v->x_val_len)));
return -BCH_ERR_invalid_bkey;
}
/* XXX why +4 ? */ /* XXX why +4 ? */
if (bkey_val_u64s(k.k) > val_u64s = xattr_val_u64s(xattr.v->x_name_len,
xattr_val_u64s(xattr.v->x_name_len, le16_to_cpu(xattr.v->x_val_len) + 4);
le16_to_cpu(xattr.v->x_val_len) + 4)) {
prt_printf(err, "value too big (%zu > %u)", bkey_fsck_err_on(bkey_val_u64s(k.k) > val_u64s, c, err,
bkey_val_u64s(k.k), xattr_val_size_too_big,
xattr_val_u64s(xattr.v->x_name_len, "value too big (%zu > %u)",
le16_to_cpu(xattr.v->x_val_len) + 4)); bkey_val_u64s(k.k), val_u64s);
return -BCH_ERR_invalid_bkey;
} bkey_fsck_err_on(!bch2_xattr_type_to_handler(xattr.v->x_type), c, err,
xattr_invalid_type,
handler = bch2_xattr_type_to_handler(xattr.v->x_type); "invalid type (%u)", xattr.v->x_type);
if (!handler) {
prt_printf(err, "invalid type (%u)", xattr.v->x_type); bkey_fsck_err_on(memchr(xattr.v->x_name, '\0', xattr.v->x_name_len), c, err,
return -BCH_ERR_invalid_bkey; xattr_name_invalid_chars,
} "xattr name has invalid characters");
fsck_err:
if (memchr(xattr.v->x_name, '\0', xattr.v->x_name_len)) { return ret;
prt_printf(err, "xattr name has invalid characters");
return -BCH_ERR_invalid_bkey;
}
return 0;
} }
void bch2_xattr_to_text(struct printbuf *out, struct bch_fs *c, void bch2_xattr_to_text(struct printbuf *out, struct bch_fs *c,
......
...@@ -6,7 +6,7 @@ ...@@ -6,7 +6,7 @@
extern const struct bch_hash_desc bch2_xattr_hash_desc; extern const struct bch_hash_desc bch2_xattr_hash_desc;
int bch2_xattr_invalid(const struct bch_fs *, struct bkey_s_c, int bch2_xattr_invalid(struct bch_fs *, struct bkey_s_c,
enum bkey_invalid_flags, struct printbuf *); enum bkey_invalid_flags, struct printbuf *);
void bch2_xattr_to_text(struct printbuf *, struct bch_fs *, struct bkey_s_c); void bch2_xattr_to_text(struct printbuf *, struct bch_fs *, struct bkey_s_c);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment