mirror of
https://github.com/torvalds/linux.git
synced 2024-11-21 19:41:42 +00:00
bcachefs: Make bkey_fsck_err() a wrapper around fsck_err()
bkey_fsck_err() was added as an interface that looks like fsck_err(), but previously all it did was ensure that the appropriate error counter was incremented in the superblock. This is a cleanup and bugfix patch that converts it to a wrapper around fsck_err(). This is needed to fix an issue with the upgrade path to disk_accounting_v3, where the "silent fix" error list now includes bkey_fsck errors; fsck_err() handles this in a unified way, and since we need to change printing of bkey fsck errors from the caller to the inner bkey_fsck_err() calls, this ends up being a pretty big change. Als,, rename .invalid() methods to .validate(), for clarity, while we're changing the function signature anyways (to drop the printbuf argument). Signed-off-by: Kent Overstreet <kent.overstreet@linux.dev>
This commit is contained in:
parent
c99471024f
commit
d97de0d017
@ -196,75 +196,71 @@ static unsigned bch_alloc_v1_val_u64s(const struct bch_alloc *a)
|
||||
return DIV_ROUND_UP(bytes, sizeof(u64));
|
||||
}
|
||||
|
||||
int bch2_alloc_v1_invalid(struct bch_fs *c, struct bkey_s_c k,
|
||||
enum bch_validate_flags flags,
|
||||
struct printbuf *err)
|
||||
int bch2_alloc_v1_validate(struct bch_fs *c, struct bkey_s_c k,
|
||||
enum bch_validate_flags flags)
|
||||
{
|
||||
struct bkey_s_c_alloc a = bkey_s_c_to_alloc(k);
|
||||
int ret = 0;
|
||||
|
||||
/* allow for unknown fields */
|
||||
bkey_fsck_err_on(bkey_val_u64s(a.k) < bch_alloc_v1_val_u64s(a.v), c, err,
|
||||
alloc_v1_val_size_bad,
|
||||
bkey_fsck_err_on(bkey_val_u64s(a.k) < bch_alloc_v1_val_u64s(a.v),
|
||||
c, alloc_v1_val_size_bad,
|
||||
"incorrect value size (%zu < %u)",
|
||||
bkey_val_u64s(a.k), bch_alloc_v1_val_u64s(a.v));
|
||||
fsck_err:
|
||||
return ret;
|
||||
}
|
||||
|
||||
int bch2_alloc_v2_invalid(struct bch_fs *c, struct bkey_s_c k,
|
||||
enum bch_validate_flags flags,
|
||||
struct printbuf *err)
|
||||
int bch2_alloc_v2_validate(struct bch_fs *c, struct bkey_s_c k,
|
||||
enum bch_validate_flags flags)
|
||||
{
|
||||
struct bkey_alloc_unpacked u;
|
||||
int ret = 0;
|
||||
|
||||
bkey_fsck_err_on(bch2_alloc_unpack_v2(&u, k), c, err,
|
||||
alloc_v2_unpack_error,
|
||||
bkey_fsck_err_on(bch2_alloc_unpack_v2(&u, k),
|
||||
c, alloc_v2_unpack_error,
|
||||
"unpack error");
|
||||
fsck_err:
|
||||
return ret;
|
||||
}
|
||||
|
||||
int bch2_alloc_v3_invalid(struct bch_fs *c, struct bkey_s_c k,
|
||||
enum bch_validate_flags flags,
|
||||
struct printbuf *err)
|
||||
int bch2_alloc_v3_validate(struct bch_fs *c, struct bkey_s_c k,
|
||||
enum bch_validate_flags flags)
|
||||
{
|
||||
struct bkey_alloc_unpacked u;
|
||||
int ret = 0;
|
||||
|
||||
bkey_fsck_err_on(bch2_alloc_unpack_v3(&u, k), c, err,
|
||||
alloc_v2_unpack_error,
|
||||
bkey_fsck_err_on(bch2_alloc_unpack_v3(&u, k),
|
||||
c, alloc_v2_unpack_error,
|
||||
"unpack error");
|
||||
fsck_err:
|
||||
return ret;
|
||||
}
|
||||
|
||||
int bch2_alloc_v4_invalid(struct bch_fs *c, struct bkey_s_c k,
|
||||
enum bch_validate_flags flags, struct printbuf *err)
|
||||
int bch2_alloc_v4_validate(struct bch_fs *c, struct bkey_s_c k,
|
||||
enum bch_validate_flags flags)
|
||||
{
|
||||
struct bkey_s_c_alloc_v4 a = bkey_s_c_to_alloc_v4(k);
|
||||
int ret = 0;
|
||||
|
||||
bkey_fsck_err_on(alloc_v4_u64s_noerror(a.v) > bkey_val_u64s(k.k), c, err,
|
||||
alloc_v4_val_size_bad,
|
||||
bkey_fsck_err_on(alloc_v4_u64s_noerror(a.v) > bkey_val_u64s(k.k),
|
||||
c, alloc_v4_val_size_bad,
|
||||
"bad val size (%u > %zu)",
|
||||
alloc_v4_u64s_noerror(a.v), bkey_val_u64s(k.k));
|
||||
|
||||
bkey_fsck_err_on(!BCH_ALLOC_V4_BACKPOINTERS_START(a.v) &&
|
||||
BCH_ALLOC_V4_NR_BACKPOINTERS(a.v), c, err,
|
||||
alloc_v4_backpointers_start_bad,
|
||||
BCH_ALLOC_V4_NR_BACKPOINTERS(a.v),
|
||||
c, alloc_v4_backpointers_start_bad,
|
||||
"invalid backpointers_start");
|
||||
|
||||
bkey_fsck_err_on(alloc_data_type(*a.v, a.v->data_type) != a.v->data_type, c, err,
|
||||
alloc_key_data_type_bad,
|
||||
bkey_fsck_err_on(alloc_data_type(*a.v, a.v->data_type) != a.v->data_type,
|
||||
c, alloc_key_data_type_bad,
|
||||
"invalid data type (got %u should be %u)",
|
||||
a.v->data_type, alloc_data_type(*a.v, a.v->data_type));
|
||||
|
||||
for (unsigned i = 0; i < 2; i++)
|
||||
bkey_fsck_err_on(a.v->io_time[i] > LRU_TIME_MAX,
|
||||
c, err,
|
||||
alloc_key_io_time_bad,
|
||||
c, alloc_key_io_time_bad,
|
||||
"invalid io_time[%s]: %llu, max %llu",
|
||||
i == READ ? "read" : "write",
|
||||
a.v->io_time[i], LRU_TIME_MAX);
|
||||
@ -282,7 +278,7 @@ int bch2_alloc_v4_invalid(struct bch_fs *c, struct bkey_s_c k,
|
||||
a.v->dirty_sectors ||
|
||||
a.v->cached_sectors ||
|
||||
a.v->stripe,
|
||||
c, err, alloc_key_empty_but_have_data,
|
||||
c, alloc_key_empty_but_have_data,
|
||||
"empty data type free but have data %u.%u.%u %u",
|
||||
stripe_sectors,
|
||||
a.v->dirty_sectors,
|
||||
@ -296,7 +292,7 @@ int bch2_alloc_v4_invalid(struct bch_fs *c, struct bkey_s_c k,
|
||||
case BCH_DATA_parity:
|
||||
bkey_fsck_err_on(!a.v->dirty_sectors &&
|
||||
!stripe_sectors,
|
||||
c, err, alloc_key_dirty_sectors_0,
|
||||
c, alloc_key_dirty_sectors_0,
|
||||
"data_type %s but dirty_sectors==0",
|
||||
bch2_data_type_str(a.v->data_type));
|
||||
break;
|
||||
@ -305,12 +301,12 @@ int bch2_alloc_v4_invalid(struct bch_fs *c, struct bkey_s_c k,
|
||||
a.v->dirty_sectors ||
|
||||
stripe_sectors ||
|
||||
a.v->stripe,
|
||||
c, err, alloc_key_cached_inconsistency,
|
||||
c, alloc_key_cached_inconsistency,
|
||||
"data type inconsistency");
|
||||
|
||||
bkey_fsck_err_on(!a.v->io_time[READ] &&
|
||||
c->curr_recovery_pass > BCH_RECOVERY_PASS_check_alloc_to_lru_refs,
|
||||
c, err, alloc_key_cached_but_read_time_zero,
|
||||
c, alloc_key_cached_but_read_time_zero,
|
||||
"cached bucket with read_time == 0");
|
||||
break;
|
||||
case BCH_DATA_stripe:
|
||||
@ -513,14 +509,13 @@ static unsigned alloc_gen(struct bkey_s_c k, unsigned offset)
|
||||
: 0;
|
||||
}
|
||||
|
||||
int bch2_bucket_gens_invalid(struct bch_fs *c, struct bkey_s_c k,
|
||||
enum bch_validate_flags flags,
|
||||
struct printbuf *err)
|
||||
int bch2_bucket_gens_validate(struct bch_fs *c, struct bkey_s_c k,
|
||||
enum bch_validate_flags flags)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
bkey_fsck_err_on(bkey_val_bytes(k.k) != sizeof(struct bch_bucket_gens), c, err,
|
||||
bucket_gens_val_size_bad,
|
||||
bkey_fsck_err_on(bkey_val_bytes(k.k) != sizeof(struct bch_bucket_gens),
|
||||
c, bucket_gens_val_size_bad,
|
||||
"bad val size (%zu != %zu)",
|
||||
bkey_val_bytes(k.k), sizeof(struct bch_bucket_gens));
|
||||
fsck_err:
|
||||
|
@ -240,52 +240,48 @@ 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_alloc_v1_invalid(struct bch_fs *, struct bkey_s_c,
|
||||
enum bch_validate_flags, struct printbuf *);
|
||||
int bch2_alloc_v2_invalid(struct bch_fs *, struct bkey_s_c,
|
||||
enum bch_validate_flags, struct printbuf *);
|
||||
int bch2_alloc_v3_invalid(struct bch_fs *, struct bkey_s_c,
|
||||
enum bch_validate_flags, struct printbuf *);
|
||||
int bch2_alloc_v4_invalid(struct bch_fs *, struct bkey_s_c,
|
||||
enum bch_validate_flags, struct printbuf *);
|
||||
int bch2_alloc_v1_validate(struct bch_fs *, struct bkey_s_c, enum bch_validate_flags);
|
||||
int bch2_alloc_v2_validate(struct bch_fs *, struct bkey_s_c, enum bch_validate_flags);
|
||||
int bch2_alloc_v3_validate(struct bch_fs *, struct bkey_s_c, enum bch_validate_flags);
|
||||
int bch2_alloc_v4_validate(struct bch_fs *, struct bkey_s_c, enum bch_validate_flags);
|
||||
void bch2_alloc_v4_swab(struct bkey_s);
|
||||
void bch2_alloc_to_text(struct printbuf *, struct bch_fs *, struct bkey_s_c);
|
||||
|
||||
#define bch2_bkey_ops_alloc ((struct bkey_ops) { \
|
||||
.key_invalid = bch2_alloc_v1_invalid, \
|
||||
.key_validate = bch2_alloc_v1_validate, \
|
||||
.val_to_text = bch2_alloc_to_text, \
|
||||
.trigger = bch2_trigger_alloc, \
|
||||
.min_val_size = 8, \
|
||||
})
|
||||
|
||||
#define bch2_bkey_ops_alloc_v2 ((struct bkey_ops) { \
|
||||
.key_invalid = bch2_alloc_v2_invalid, \
|
||||
.key_validate = bch2_alloc_v2_validate, \
|
||||
.val_to_text = bch2_alloc_to_text, \
|
||||
.trigger = bch2_trigger_alloc, \
|
||||
.min_val_size = 8, \
|
||||
})
|
||||
|
||||
#define bch2_bkey_ops_alloc_v3 ((struct bkey_ops) { \
|
||||
.key_invalid = bch2_alloc_v3_invalid, \
|
||||
.key_validate = bch2_alloc_v3_validate, \
|
||||
.val_to_text = bch2_alloc_to_text, \
|
||||
.trigger = bch2_trigger_alloc, \
|
||||
.min_val_size = 16, \
|
||||
})
|
||||
|
||||
#define bch2_bkey_ops_alloc_v4 ((struct bkey_ops) { \
|
||||
.key_invalid = bch2_alloc_v4_invalid, \
|
||||
.key_validate = bch2_alloc_v4_validate, \
|
||||
.val_to_text = bch2_alloc_to_text, \
|
||||
.swab = bch2_alloc_v4_swab, \
|
||||
.trigger = bch2_trigger_alloc, \
|
||||
.min_val_size = 48, \
|
||||
})
|
||||
|
||||
int bch2_bucket_gens_invalid(struct bch_fs *, struct bkey_s_c,
|
||||
enum bch_validate_flags, struct printbuf *);
|
||||
int bch2_bucket_gens_validate(struct bch_fs *, struct bkey_s_c,
|
||||
enum bch_validate_flags);
|
||||
void bch2_bucket_gens_to_text(struct printbuf *, struct bch_fs *, struct bkey_s_c);
|
||||
|
||||
#define bch2_bkey_ops_bucket_gens ((struct bkey_ops) { \
|
||||
.key_invalid = bch2_bucket_gens_invalid, \
|
||||
.key_validate = bch2_bucket_gens_validate, \
|
||||
.val_to_text = bch2_bucket_gens_to_text, \
|
||||
})
|
||||
|
||||
|
@ -47,9 +47,8 @@ static bool extent_matches_bp(struct bch_fs *c,
|
||||
return false;
|
||||
}
|
||||
|
||||
int bch2_backpointer_invalid(struct bch_fs *c, struct bkey_s_c k,
|
||||
enum bch_validate_flags flags,
|
||||
struct printbuf *err)
|
||||
int bch2_backpointer_validate(struct bch_fs *c, struct bkey_s_c k,
|
||||
enum bch_validate_flags flags)
|
||||
{
|
||||
struct bkey_s_c_backpointer bp = bkey_s_c_to_backpointer(k);
|
||||
|
||||
@ -68,8 +67,7 @@ int bch2_backpointer_invalid(struct bch_fs *c, struct bkey_s_c k,
|
||||
|
||||
bkey_fsck_err_on((bp.v->bucket_offset >> MAX_EXTENT_COMPRESS_RATIO_SHIFT) >= ca->mi.bucket_size ||
|
||||
!bpos_eq(bp.k->p, bp_pos),
|
||||
c, err,
|
||||
backpointer_bucket_offset_wrong,
|
||||
c, backpointer_bucket_offset_wrong,
|
||||
"backpointer bucket_offset wrong");
|
||||
fsck_err:
|
||||
return ret;
|
||||
|
@ -18,14 +18,13 @@ static inline u64 swab40(u64 x)
|
||||
((x & 0xff00000000ULL) >> 32));
|
||||
}
|
||||
|
||||
int bch2_backpointer_invalid(struct bch_fs *, struct bkey_s_c k,
|
||||
enum bch_validate_flags, struct printbuf *);
|
||||
int bch2_backpointer_validate(struct bch_fs *, struct bkey_s_c k, enum bch_validate_flags);
|
||||
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_swab(struct bkey_s);
|
||||
|
||||
#define bch2_bkey_ops_backpointer ((struct bkey_ops) { \
|
||||
.key_invalid = bch2_backpointer_invalid, \
|
||||
.key_validate = bch2_backpointer_validate, \
|
||||
.val_to_text = bch2_backpointer_k_to_text, \
|
||||
.swab = bch2_backpointer_swab, \
|
||||
.min_val_size = 32, \
|
||||
|
@ -10,9 +10,10 @@
|
||||
#include "vstructs.h"
|
||||
|
||||
enum bch_validate_flags {
|
||||
BCH_VALIDATE_write = (1U << 0),
|
||||
BCH_VALIDATE_commit = (1U << 1),
|
||||
BCH_VALIDATE_journal = (1U << 2),
|
||||
BCH_VALIDATE_write = BIT(0),
|
||||
BCH_VALIDATE_commit = BIT(1),
|
||||
BCH_VALIDATE_journal = BIT(2),
|
||||
BCH_VALIDATE_silent = BIT(3),
|
||||
};
|
||||
|
||||
#if 0
|
||||
|
@ -27,27 +27,27 @@ const char * const bch2_bkey_types[] = {
|
||||
NULL
|
||||
};
|
||||
|
||||
static int deleted_key_invalid(struct bch_fs *c, struct bkey_s_c k,
|
||||
enum bch_validate_flags flags, struct printbuf *err)
|
||||
static int deleted_key_validate(struct bch_fs *c, struct bkey_s_c k,
|
||||
enum bch_validate_flags flags)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
#define bch2_bkey_ops_deleted ((struct bkey_ops) { \
|
||||
.key_invalid = deleted_key_invalid, \
|
||||
.key_validate = deleted_key_validate, \
|
||||
})
|
||||
|
||||
#define bch2_bkey_ops_whiteout ((struct bkey_ops) { \
|
||||
.key_invalid = deleted_key_invalid, \
|
||||
.key_validate = deleted_key_validate, \
|
||||
})
|
||||
|
||||
static int empty_val_key_invalid(struct bch_fs *c, struct bkey_s_c k,
|
||||
enum bch_validate_flags flags, struct printbuf *err)
|
||||
static int empty_val_key_validate(struct bch_fs *c, struct bkey_s_c k,
|
||||
enum bch_validate_flags flags)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
bkey_fsck_err_on(bkey_val_bytes(k.k), c, err,
|
||||
bkey_val_size_nonzero,
|
||||
bkey_fsck_err_on(bkey_val_bytes(k.k),
|
||||
c, bkey_val_size_nonzero,
|
||||
"incorrect value size (%zu != 0)",
|
||||
bkey_val_bytes(k.k));
|
||||
fsck_err:
|
||||
@ -55,11 +55,11 @@ fsck_err:
|
||||
}
|
||||
|
||||
#define bch2_bkey_ops_error ((struct bkey_ops) { \
|
||||
.key_invalid = empty_val_key_invalid, \
|
||||
.key_validate = empty_val_key_validate, \
|
||||
})
|
||||
|
||||
static int key_type_cookie_invalid(struct bch_fs *c, struct bkey_s_c k,
|
||||
enum bch_validate_flags flags, struct printbuf *err)
|
||||
static int key_type_cookie_validate(struct bch_fs *c, struct bkey_s_c k,
|
||||
enum bch_validate_flags flags)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
@ -73,17 +73,17 @@ static void key_type_cookie_to_text(struct printbuf *out, struct bch_fs *c,
|
||||
}
|
||||
|
||||
#define bch2_bkey_ops_cookie ((struct bkey_ops) { \
|
||||
.key_invalid = key_type_cookie_invalid, \
|
||||
.key_validate = key_type_cookie_validate, \
|
||||
.val_to_text = key_type_cookie_to_text, \
|
||||
.min_val_size = 8, \
|
||||
})
|
||||
|
||||
#define bch2_bkey_ops_hash_whiteout ((struct bkey_ops) {\
|
||||
.key_invalid = empty_val_key_invalid, \
|
||||
.key_validate = empty_val_key_validate, \
|
||||
})
|
||||
|
||||
static int key_type_inline_data_invalid(struct bch_fs *c, struct bkey_s_c k,
|
||||
enum bch_validate_flags flags, struct printbuf *err)
|
||||
static int key_type_inline_data_validate(struct bch_fs *c, struct bkey_s_c k,
|
||||
enum bch_validate_flags flags)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
@ -99,7 +99,7 @@ static void key_type_inline_data_to_text(struct printbuf *out, struct bch_fs *c,
|
||||
}
|
||||
|
||||
#define bch2_bkey_ops_inline_data ((struct bkey_ops) { \
|
||||
.key_invalid = key_type_inline_data_invalid, \
|
||||
.key_validate = key_type_inline_data_validate, \
|
||||
.val_to_text = key_type_inline_data_to_text, \
|
||||
})
|
||||
|
||||
@ -110,7 +110,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) { \
|
||||
.key_invalid = empty_val_key_invalid, \
|
||||
.key_validate = empty_val_key_validate, \
|
||||
.key_merge = key_type_set_merge, \
|
||||
})
|
||||
|
||||
@ -123,9 +123,8 @@ const struct bkey_ops bch2_bkey_ops[] = {
|
||||
const struct bkey_ops bch2_bkey_null_ops = {
|
||||
};
|
||||
|
||||
int bch2_bkey_val_invalid(struct bch_fs *c, struct bkey_s_c k,
|
||||
enum bch_validate_flags flags,
|
||||
struct printbuf *err)
|
||||
int bch2_bkey_val_validate(struct bch_fs *c, struct bkey_s_c k,
|
||||
enum bch_validate_flags flags)
|
||||
{
|
||||
if (test_bit(BCH_FS_no_invalid_checks, &c->flags))
|
||||
return 0;
|
||||
@ -133,15 +132,15 @@ int bch2_bkey_val_invalid(struct bch_fs *c, struct bkey_s_c k,
|
||||
const struct bkey_ops *ops = bch2_bkey_type_ops(k.k->type);
|
||||
int ret = 0;
|
||||
|
||||
bkey_fsck_err_on(bkey_val_bytes(k.k) < ops->min_val_size, c, err,
|
||||
bkey_val_size_too_small,
|
||||
bkey_fsck_err_on(bkey_val_bytes(k.k) < ops->min_val_size,
|
||||
c, bkey_val_size_too_small,
|
||||
"bad val size (%zu < %u)",
|
||||
bkey_val_bytes(k.k), ops->min_val_size);
|
||||
|
||||
if (!ops->key_invalid)
|
||||
if (!ops->key_validate)
|
||||
return 0;
|
||||
|
||||
ret = ops->key_invalid(c, k, flags, err);
|
||||
ret = ops->key_validate(c, k, flags);
|
||||
fsck_err:
|
||||
return ret;
|
||||
}
|
||||
@ -161,18 +160,17 @@ const char *bch2_btree_node_type_str(enum btree_node_type type)
|
||||
return type == BKEY_TYPE_btree ? "internal btree node" : bch2_btree_id_str(type - 1);
|
||||
}
|
||||
|
||||
int __bch2_bkey_invalid(struct bch_fs *c, struct bkey_s_c k,
|
||||
int __bch2_bkey_validate(struct bch_fs *c, struct bkey_s_c k,
|
||||
enum btree_node_type type,
|
||||
enum bch_validate_flags flags,
|
||||
struct printbuf *err)
|
||||
enum bch_validate_flags flags)
|
||||
{
|
||||
if (test_bit(BCH_FS_no_invalid_checks, &c->flags))
|
||||
return 0;
|
||||
|
||||
int ret = 0;
|
||||
|
||||
bkey_fsck_err_on(k.k->u64s < BKEY_U64s, c, err,
|
||||
bkey_u64s_too_small,
|
||||
bkey_fsck_err_on(k.k->u64s < BKEY_U64s,
|
||||
c, bkey_u64s_too_small,
|
||||
"u64s too small (%u < %zu)", k.k->u64s, BKEY_U64s);
|
||||
|
||||
if (type >= BKEY_TYPE_NR)
|
||||
@ -180,8 +178,8 @@ int __bch2_bkey_invalid(struct bch_fs *c, struct bkey_s_c k,
|
||||
|
||||
bkey_fsck_err_on(k.k->type < KEY_TYPE_MAX &&
|
||||
(type == BKEY_TYPE_btree || (flags & BCH_VALIDATE_commit)) &&
|
||||
!(bch2_key_types_allowed[type] & BIT_ULL(k.k->type)), c, err,
|
||||
bkey_invalid_type_for_btree,
|
||||
!(bch2_key_types_allowed[type] & BIT_ULL(k.k->type)),
|
||||
c, bkey_invalid_type_for_btree,
|
||||
"invalid key type for btree %s (%s)",
|
||||
bch2_btree_node_type_str(type),
|
||||
k.k->type < KEY_TYPE_MAX
|
||||
@ -189,17 +187,17 @@ int __bch2_bkey_invalid(struct bch_fs *c, struct bkey_s_c k,
|
||||
: "(unknown)");
|
||||
|
||||
if (btree_node_type_is_extents(type) && !bkey_whiteout(k.k)) {
|
||||
bkey_fsck_err_on(k.k->size == 0, c, err,
|
||||
bkey_extent_size_zero,
|
||||
bkey_fsck_err_on(k.k->size == 0,
|
||||
c, bkey_extent_size_zero,
|
||||
"size == 0");
|
||||
|
||||
bkey_fsck_err_on(k.k->size > k.k->p.offset, c, err,
|
||||
bkey_extent_size_greater_than_offset,
|
||||
bkey_fsck_err_on(k.k->size > k.k->p.offset,
|
||||
c, bkey_extent_size_greater_than_offset,
|
||||
"size greater than offset (%u > %llu)",
|
||||
k.k->size, k.k->p.offset);
|
||||
} else {
|
||||
bkey_fsck_err_on(k.k->size, c, err,
|
||||
bkey_size_nonzero,
|
||||
bkey_fsck_err_on(k.k->size,
|
||||
c, bkey_size_nonzero,
|
||||
"size != 0");
|
||||
}
|
||||
|
||||
@ -207,12 +205,12 @@ int __bch2_bkey_invalid(struct bch_fs *c, struct bkey_s_c k,
|
||||
enum btree_id btree = type - 1;
|
||||
|
||||
if (btree_type_has_snapshots(btree)) {
|
||||
bkey_fsck_err_on(!k.k->p.snapshot, c, err,
|
||||
bkey_snapshot_zero,
|
||||
bkey_fsck_err_on(!k.k->p.snapshot,
|
||||
c, bkey_snapshot_zero,
|
||||
"snapshot == 0");
|
||||
} else if (!btree_type_has_snapshot_field(btree)) {
|
||||
bkey_fsck_err_on(k.k->p.snapshot, c, err,
|
||||
bkey_snapshot_nonzero,
|
||||
bkey_fsck_err_on(k.k->p.snapshot,
|
||||
c, bkey_snapshot_nonzero,
|
||||
"nonzero snapshot");
|
||||
} else {
|
||||
/*
|
||||
@ -221,34 +219,33 @@ int __bch2_bkey_invalid(struct bch_fs *c, struct bkey_s_c k,
|
||||
*/
|
||||
}
|
||||
|
||||
bkey_fsck_err_on(bkey_eq(k.k->p, POS_MAX), c, err,
|
||||
bkey_at_pos_max,
|
||||
bkey_fsck_err_on(bkey_eq(k.k->p, POS_MAX),
|
||||
c, bkey_at_pos_max,
|
||||
"key at POS_MAX");
|
||||
}
|
||||
fsck_err:
|
||||
return ret;
|
||||
}
|
||||
|
||||
int bch2_bkey_invalid(struct bch_fs *c, struct bkey_s_c k,
|
||||
int bch2_bkey_validate(struct bch_fs *c, struct bkey_s_c k,
|
||||
enum btree_node_type type,
|
||||
enum bch_validate_flags flags,
|
||||
struct printbuf *err)
|
||||
enum bch_validate_flags flags)
|
||||
{
|
||||
return __bch2_bkey_invalid(c, k, type, flags, err) ?:
|
||||
bch2_bkey_val_invalid(c, k, flags, err);
|
||||
return __bch2_bkey_validate(c, k, type, flags) ?:
|
||||
bch2_bkey_val_validate(c, k, flags);
|
||||
}
|
||||
|
||||
int bch2_bkey_in_btree_node(struct bch_fs *c, struct btree *b,
|
||||
struct bkey_s_c k, struct printbuf *err)
|
||||
struct bkey_s_c k, enum bch_validate_flags flags)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
bkey_fsck_err_on(bpos_lt(k.k->p, b->data->min_key), c, err,
|
||||
bkey_before_start_of_btree_node,
|
||||
bkey_fsck_err_on(bpos_lt(k.k->p, b->data->min_key),
|
||||
c, bkey_before_start_of_btree_node,
|
||||
"key before start of btree node");
|
||||
|
||||
bkey_fsck_err_on(bpos_gt(k.k->p, b->data->max_key), c, err,
|
||||
bkey_after_end_of_btree_node,
|
||||
bkey_fsck_err_on(bpos_gt(k.k->p, b->data->max_key),
|
||||
c, bkey_after_end_of_btree_node,
|
||||
"key past end of btree node");
|
||||
fsck_err:
|
||||
return ret;
|
||||
|
@ -14,15 +14,15 @@ extern const char * const bch2_bkey_types[];
|
||||
extern const struct bkey_ops bch2_bkey_null_ops;
|
||||
|
||||
/*
|
||||
* key_invalid: checks validity of @k, returns 0 if good or -EINVAL if bad. If
|
||||
* key_validate: checks validity of @k, returns 0 if good or -EINVAL if bad. If
|
||||
* invalid, entire key will be deleted.
|
||||
*
|
||||
* When invalid, error string is returned via @err. @rw indicates whether key is
|
||||
* being read or written; more aggressive checks can be enabled when rw == WRITE.
|
||||
*/
|
||||
struct bkey_ops {
|
||||
int (*key_invalid)(struct bch_fs *c, struct bkey_s_c k,
|
||||
enum bch_validate_flags flags, struct printbuf *err);
|
||||
int (*key_validate)(struct bch_fs *c, struct bkey_s_c k,
|
||||
enum bch_validate_flags flags);
|
||||
void (*val_to_text)(struct printbuf *, struct bch_fs *,
|
||||
struct bkey_s_c);
|
||||
void (*swab)(struct bkey_s);
|
||||
@ -48,14 +48,13 @@ static inline const struct bkey_ops *bch2_bkey_type_ops(enum bch_bkey_type type)
|
||||
: &bch2_bkey_null_ops;
|
||||
}
|
||||
|
||||
int bch2_bkey_val_invalid(struct bch_fs *, struct bkey_s_c,
|
||||
enum bch_validate_flags, struct printbuf *);
|
||||
int __bch2_bkey_invalid(struct bch_fs *, struct bkey_s_c, enum btree_node_type,
|
||||
enum bch_validate_flags, struct printbuf *);
|
||||
int bch2_bkey_invalid(struct bch_fs *, struct bkey_s_c, enum btree_node_type,
|
||||
enum bch_validate_flags, struct printbuf *);
|
||||
int bch2_bkey_in_btree_node(struct bch_fs *, struct btree *,
|
||||
struct bkey_s_c, struct printbuf *);
|
||||
int bch2_bkey_val_validate(struct bch_fs *, struct bkey_s_c, enum bch_validate_flags);
|
||||
int __bch2_bkey_validate(struct bch_fs *, struct bkey_s_c, enum btree_node_type,
|
||||
enum bch_validate_flags);
|
||||
int bch2_bkey_validate(struct bch_fs *, struct bkey_s_c, enum btree_node_type,
|
||||
enum bch_validate_flags);
|
||||
int bch2_bkey_in_btree_node(struct bch_fs *, struct btree *, struct bkey_s_c,
|
||||
enum bch_validate_flags);
|
||||
|
||||
void bch2_bpos_to_text(struct printbuf *, struct bpos);
|
||||
void bch2_bkey_to_text(struct printbuf *, const struct bkey *);
|
||||
|
@ -836,14 +836,13 @@ fsck_err:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int bset_key_invalid(struct bch_fs *c, struct btree *b,
|
||||
static int bset_key_validate(struct bch_fs *c, struct btree *b,
|
||||
struct bkey_s_c k,
|
||||
bool updated_range, int rw,
|
||||
struct printbuf *err)
|
||||
bool updated_range, int rw)
|
||||
{
|
||||
return __bch2_bkey_invalid(c, k, btree_node_type(b), READ, err) ?:
|
||||
(!updated_range ? bch2_bkey_in_btree_node(c, b, k, err) : 0) ?:
|
||||
(rw == WRITE ? bch2_bkey_val_invalid(c, k, READ, err) : 0);
|
||||
return __bch2_bkey_validate(c, k, btree_node_type(b), 0) ?:
|
||||
(!updated_range ? bch2_bkey_in_btree_node(c, b, k, 0) : 0) ?:
|
||||
(rw == WRITE ? bch2_bkey_val_validate(c, k, 0) : 0);
|
||||
}
|
||||
|
||||
static bool bkey_packed_valid(struct bch_fs *c, struct btree *b,
|
||||
@ -858,12 +857,9 @@ static bool bkey_packed_valid(struct bch_fs *c, struct btree *b,
|
||||
if (!bkeyp_u64s_valid(&b->format, k))
|
||||
return false;
|
||||
|
||||
struct printbuf buf = PRINTBUF;
|
||||
struct bkey tmp;
|
||||
struct bkey_s u = __bkey_disassemble(b, k, &tmp);
|
||||
bool ret = __bch2_bkey_invalid(c, u.s_c, btree_node_type(b), READ, &buf);
|
||||
printbuf_exit(&buf);
|
||||
return ret;
|
||||
return !__bch2_bkey_validate(c, u.s_c, btree_node_type(b), BCH_VALIDATE_silent);
|
||||
}
|
||||
|
||||
static int validate_bset_keys(struct bch_fs *c, struct btree *b,
|
||||
@ -915,19 +911,11 @@ static int validate_bset_keys(struct bch_fs *c, struct btree *b,
|
||||
|
||||
u = __bkey_disassemble(b, k, &tmp);
|
||||
|
||||
printbuf_reset(&buf);
|
||||
if (bset_key_invalid(c, b, u.s_c, updated_range, write, &buf)) {
|
||||
printbuf_reset(&buf);
|
||||
bset_key_invalid(c, b, u.s_c, updated_range, write, &buf);
|
||||
prt_printf(&buf, "\n ");
|
||||
bch2_bkey_val_to_text(&buf, c, u.s_c);
|
||||
|
||||
btree_err(-BCH_ERR_btree_node_read_err_fixable,
|
||||
c, NULL, b, i, k,
|
||||
btree_node_bad_bkey,
|
||||
"invalid bkey: %s", buf.buf);
|
||||
ret = bset_key_validate(c, b, u.s_c, updated_range, write);
|
||||
if (ret == -BCH_ERR_fsck_delete_bkey)
|
||||
goto drop_this_key;
|
||||
}
|
||||
if (ret)
|
||||
goto fsck_err;
|
||||
|
||||
if (write)
|
||||
bch2_bkey_compat(b->c.level, b->c.btree_id, version,
|
||||
@ -1228,23 +1216,10 @@ int bch2_btree_node_read_done(struct bch_fs *c, struct bch_dev *ca,
|
||||
struct bkey tmp;
|
||||
struct bkey_s u = __bkey_disassemble(b, k, &tmp);
|
||||
|
||||
printbuf_reset(&buf);
|
||||
|
||||
if (bch2_bkey_val_invalid(c, u.s_c, READ, &buf) ||
|
||||
ret = bch2_bkey_val_validate(c, u.s_c, READ);
|
||||
if (ret == -BCH_ERR_fsck_delete_bkey ||
|
||||
(bch2_inject_invalid_keys &&
|
||||
!bversion_cmp(u.k->version, MAX_VERSION))) {
|
||||
printbuf_reset(&buf);
|
||||
|
||||
prt_printf(&buf, "invalid bkey: ");
|
||||
bch2_bkey_val_invalid(c, u.s_c, READ, &buf);
|
||||
prt_printf(&buf, "\n ");
|
||||
bch2_bkey_val_to_text(&buf, c, u.s_c);
|
||||
|
||||
btree_err(-BCH_ERR_btree_node_read_err_fixable,
|
||||
c, NULL, b, i, k,
|
||||
btree_node_bad_bkey,
|
||||
"%s", buf.buf);
|
||||
|
||||
btree_keys_account_key_drop(&b->nr, 0, k);
|
||||
|
||||
i->u64s = cpu_to_le16(le16_to_cpu(i->u64s) - k->u64s);
|
||||
@ -1253,6 +1228,8 @@ int bch2_btree_node_read_done(struct bch_fs *c, struct bch_dev *ca,
|
||||
set_btree_bset_end(b, b->set);
|
||||
continue;
|
||||
}
|
||||
if (ret)
|
||||
goto fsck_err;
|
||||
|
||||
if (u.k->type == KEY_TYPE_btree_ptr_v2) {
|
||||
struct bkey_s_btree_ptr_v2 bp = bkey_s_to_btree_ptr_v2(u);
|
||||
@ -1954,18 +1931,14 @@ static void btree_node_write_endio(struct bio *bio)
|
||||
static int validate_bset_for_write(struct bch_fs *c, struct btree *b,
|
||||
struct bset *i, unsigned sectors)
|
||||
{
|
||||
struct printbuf buf = PRINTBUF;
|
||||
bool saw_error;
|
||||
int ret;
|
||||
|
||||
ret = bch2_bkey_invalid(c, bkey_i_to_s_c(&b->key),
|
||||
BKEY_TYPE_btree, WRITE, &buf);
|
||||
|
||||
if (ret)
|
||||
bch2_fs_inconsistent(c, "invalid btree node key before write: %s", buf.buf);
|
||||
printbuf_exit(&buf);
|
||||
if (ret)
|
||||
int ret = bch2_bkey_validate(c, bkey_i_to_s_c(&b->key),
|
||||
BKEY_TYPE_btree, WRITE);
|
||||
if (ret) {
|
||||
bch2_fs_inconsistent(c, "invalid btree node key before write");
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = validate_bset_keys(c, b, i, WRITE, false, &saw_error) ?:
|
||||
validate_bset(c, NULL, b, i, b->written, sectors, WRITE, false, &saw_error);
|
||||
|
@ -530,7 +530,7 @@ int bch2_get_scanned_nodes(struct bch_fs *c, enum btree_id btree,
|
||||
bch_verbose(c, "%s(): recovering %s", __func__, buf.buf);
|
||||
printbuf_exit(&buf);
|
||||
|
||||
BUG_ON(bch2_bkey_invalid(c, bkey_i_to_s_c(&tmp.k), BKEY_TYPE_btree, 0, NULL));
|
||||
BUG_ON(bch2_bkey_validate(c, bkey_i_to_s_c(&tmp.k), BKEY_TYPE_btree, 0));
|
||||
|
||||
ret = bch2_journal_key_insert(c, btree, level + 1, &tmp.k);
|
||||
if (ret)
|
||||
|
@ -818,50 +818,6 @@ static noinline void bch2_drop_overwrites_from_journal(struct btree_trans *trans
|
||||
bch2_journal_key_overwritten(trans->c, i->btree_id, i->level, i->k->k.p);
|
||||
}
|
||||
|
||||
static noinline int bch2_trans_commit_bkey_invalid(struct btree_trans *trans,
|
||||
enum bch_validate_flags flags,
|
||||
struct btree_insert_entry *i,
|
||||
struct printbuf *err)
|
||||
{
|
||||
struct bch_fs *c = trans->c;
|
||||
|
||||
printbuf_reset(err);
|
||||
prt_printf(err, "invalid bkey on insert from %s -> %ps\n",
|
||||
trans->fn, (void *) i->ip_allocated);
|
||||
printbuf_indent_add(err, 2);
|
||||
|
||||
bch2_bkey_val_to_text(err, c, bkey_i_to_s_c(i->k));
|
||||
prt_newline(err);
|
||||
|
||||
bch2_bkey_invalid(c, bkey_i_to_s_c(i->k), i->bkey_type, flags, err);
|
||||
bch2_print_string_as_lines(KERN_ERR, err->buf);
|
||||
|
||||
bch2_inconsistent_error(c);
|
||||
bch2_dump_trans_updates(trans);
|
||||
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static noinline int bch2_trans_commit_journal_entry_invalid(struct btree_trans *trans,
|
||||
struct jset_entry *i)
|
||||
{
|
||||
struct bch_fs *c = trans->c;
|
||||
struct printbuf buf = PRINTBUF;
|
||||
|
||||
prt_printf(&buf, "invalid bkey on insert from %s\n", trans->fn);
|
||||
printbuf_indent_add(&buf, 2);
|
||||
|
||||
bch2_journal_entry_to_text(&buf, c, i);
|
||||
prt_newline(&buf);
|
||||
|
||||
bch2_print_string_as_lines(KERN_ERR, buf.buf);
|
||||
|
||||
bch2_inconsistent_error(c);
|
||||
bch2_dump_trans_updates(trans);
|
||||
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static int bch2_trans_commit_journal_pin_flush(struct journal *j,
|
||||
struct journal_entry_pin *_pin, u64 seq)
|
||||
{
|
||||
@ -1064,21 +1020,20 @@ int __bch2_trans_commit(struct btree_trans *trans, unsigned flags)
|
||||
goto out_reset;
|
||||
|
||||
trans_for_each_update(trans, i) {
|
||||
struct printbuf buf = PRINTBUF;
|
||||
enum bch_validate_flags invalid_flags = 0;
|
||||
|
||||
if (!(flags & BCH_TRANS_COMMIT_no_journal_res))
|
||||
invalid_flags |= BCH_VALIDATE_write|BCH_VALIDATE_commit;
|
||||
|
||||
if (unlikely(bch2_bkey_invalid(c, bkey_i_to_s_c(i->k),
|
||||
i->bkey_type, invalid_flags, &buf)))
|
||||
ret = bch2_trans_commit_bkey_invalid(trans, invalid_flags, i, &buf);
|
||||
btree_insert_entry_checks(trans, i);
|
||||
printbuf_exit(&buf);
|
||||
|
||||
if (ret)
|
||||
ret = bch2_bkey_validate(c, bkey_i_to_s_c(i->k),
|
||||
i->bkey_type, invalid_flags);
|
||||
if (unlikely(ret)){
|
||||
bch2_trans_inconsistent(trans, "invalid bkey on insert from %s -> %ps\n",
|
||||
trans->fn, (void *) i->ip_allocated);
|
||||
return ret;
|
||||
}
|
||||
btree_insert_entry_checks(trans, i);
|
||||
}
|
||||
|
||||
for (struct jset_entry *i = trans->journal_entries;
|
||||
i != (void *) ((u64 *) trans->journal_entries + trans->journal_entries_u64s);
|
||||
@ -1088,14 +1043,15 @@ int __bch2_trans_commit(struct btree_trans *trans, unsigned flags)
|
||||
if (!(flags & BCH_TRANS_COMMIT_no_journal_res))
|
||||
invalid_flags |= BCH_VALIDATE_write|BCH_VALIDATE_commit;
|
||||
|
||||
if (unlikely(bch2_journal_entry_validate(c, NULL, i,
|
||||
ret = bch2_journal_entry_validate(c, NULL, i,
|
||||
bcachefs_metadata_version_current,
|
||||
CPU_BIG_ENDIAN, invalid_flags)))
|
||||
ret = bch2_trans_commit_journal_entry_invalid(trans, i);
|
||||
|
||||
if (ret)
|
||||
CPU_BIG_ENDIAN, invalid_flags);
|
||||
if (unlikely(ret)) {
|
||||
bch2_trans_inconsistent(trans, "invalid journal entry on insert from %s\n",
|
||||
trans->fn);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
if (unlikely(!test_bit(BCH_FS_may_go_rw, &c->flags))) {
|
||||
ret = do_bch2_trans_commit_to_journal_replay(trans);
|
||||
|
@ -1364,18 +1364,10 @@ static void bch2_insert_fixup_btree_ptr(struct btree_update *as,
|
||||
if (unlikely(!test_bit(JOURNAL_replay_done, &c->journal.flags)))
|
||||
bch2_journal_key_overwritten(c, b->c.btree_id, b->c.level, insert->k.p);
|
||||
|
||||
if (bch2_bkey_invalid(c, bkey_i_to_s_c(insert),
|
||||
btree_node_type(b), WRITE, &buf) ?:
|
||||
bch2_bkey_in_btree_node(c, b, bkey_i_to_s_c(insert), &buf)) {
|
||||
printbuf_reset(&buf);
|
||||
prt_printf(&buf, "inserting invalid bkey\n ");
|
||||
bch2_bkey_val_to_text(&buf, c, bkey_i_to_s_c(insert));
|
||||
prt_printf(&buf, "\n ");
|
||||
bch2_bkey_invalid(c, bkey_i_to_s_c(insert),
|
||||
btree_node_type(b), WRITE, &buf);
|
||||
bch2_bkey_in_btree_node(c, b, bkey_i_to_s_c(insert), &buf);
|
||||
|
||||
bch2_fs_inconsistent(c, "%s", buf.buf);
|
||||
if (bch2_bkey_validate(c, bkey_i_to_s_c(insert),
|
||||
btree_node_type(b), BCH_VALIDATE_write) ?:
|
||||
bch2_bkey_in_btree_node(c, b, bkey_i_to_s_c(insert), BCH_VALIDATE_write)) {
|
||||
bch2_fs_inconsistent(c, "%s: inserting invalid bkey", __func__);
|
||||
dump_stack();
|
||||
}
|
||||
|
||||
|
@ -250,10 +250,8 @@ restart_drop_extra_replicas:
|
||||
* it's been hard to reproduce, so this should give us some more
|
||||
* information when it does occur:
|
||||
*/
|
||||
struct printbuf err = PRINTBUF;
|
||||
int invalid = bch2_bkey_invalid(c, bkey_i_to_s_c(insert), __btree_node_type(0, m->btree_id), 0, &err);
|
||||
printbuf_exit(&err);
|
||||
|
||||
int invalid = bch2_bkey_validate(c, bkey_i_to_s_c(insert), __btree_node_type(0, m->btree_id),
|
||||
BCH_VALIDATE_commit);
|
||||
if (invalid) {
|
||||
struct printbuf buf = PRINTBUF;
|
||||
|
||||
|
@ -100,20 +100,19 @@ const struct bch_hash_desc bch2_dirent_hash_desc = {
|
||||
.is_visible = dirent_is_visible,
|
||||
};
|
||||
|
||||
int bch2_dirent_invalid(struct bch_fs *c, struct bkey_s_c k,
|
||||
enum bch_validate_flags flags,
|
||||
struct printbuf *err)
|
||||
int bch2_dirent_validate(struct bch_fs *c, struct bkey_s_c k,
|
||||
enum bch_validate_flags flags)
|
||||
{
|
||||
struct bkey_s_c_dirent d = bkey_s_c_to_dirent(k);
|
||||
struct qstr d_name = bch2_dirent_get_name(d);
|
||||
int ret = 0;
|
||||
|
||||
bkey_fsck_err_on(!d_name.len, c, err,
|
||||
dirent_empty_name,
|
||||
bkey_fsck_err_on(!d_name.len,
|
||||
c, dirent_empty_name,
|
||||
"empty name");
|
||||
|
||||
bkey_fsck_err_on(bkey_val_u64s(k.k) > dirent_val_u64s(d_name.len), c, err,
|
||||
dirent_val_too_big,
|
||||
bkey_fsck_err_on(bkey_val_u64s(k.k) > dirent_val_u64s(d_name.len),
|
||||
c, dirent_val_too_big,
|
||||
"value too big (%zu > %u)",
|
||||
bkey_val_u64s(k.k), dirent_val_u64s(d_name.len));
|
||||
|
||||
@ -121,27 +120,27 @@ int bch2_dirent_invalid(struct bch_fs *c, struct bkey_s_c k,
|
||||
* Check new keys don't exceed the max length
|
||||
* (older keys may be larger.)
|
||||
*/
|
||||
bkey_fsck_err_on((flags & BCH_VALIDATE_commit) && d_name.len > BCH_NAME_MAX, c, err,
|
||||
dirent_name_too_long,
|
||||
bkey_fsck_err_on((flags & BCH_VALIDATE_commit) && d_name.len > BCH_NAME_MAX,
|
||||
c, dirent_name_too_long,
|
||||
"dirent name too big (%u > %u)",
|
||||
d_name.len, BCH_NAME_MAX);
|
||||
|
||||
bkey_fsck_err_on(d_name.len != strnlen(d_name.name, d_name.len), c, err,
|
||||
dirent_name_embedded_nul,
|
||||
bkey_fsck_err_on(d_name.len != strnlen(d_name.name, d_name.len),
|
||||
c, dirent_name_embedded_nul,
|
||||
"dirent has stray data after name's NUL");
|
||||
|
||||
bkey_fsck_err_on((d_name.len == 1 && !memcmp(d_name.name, ".", 1)) ||
|
||||
(d_name.len == 2 && !memcmp(d_name.name, "..", 2)), c, err,
|
||||
dirent_name_dot_or_dotdot,
|
||||
(d_name.len == 2 && !memcmp(d_name.name, "..", 2)),
|
||||
c, dirent_name_dot_or_dotdot,
|
||||
"invalid name");
|
||||
|
||||
bkey_fsck_err_on(memchr(d_name.name, '/', d_name.len), c, err,
|
||||
dirent_name_has_slash,
|
||||
bkey_fsck_err_on(memchr(d_name.name, '/', d_name.len),
|
||||
c, dirent_name_has_slash,
|
||||
"name with /");
|
||||
|
||||
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,
|
||||
le64_to_cpu(d.v->d_inum) == d.k->p.inode,
|
||||
c, dirent_to_itself,
|
||||
"dirent points to own directory");
|
||||
fsck_err:
|
||||
return ret;
|
||||
|
@ -7,12 +7,11 @@
|
||||
enum bch_validate_flags;
|
||||
extern const struct bch_hash_desc bch2_dirent_hash_desc;
|
||||
|
||||
int bch2_dirent_invalid(struct bch_fs *, struct bkey_s_c,
|
||||
enum bch_validate_flags, struct printbuf *);
|
||||
int bch2_dirent_validate(struct bch_fs *, struct bkey_s_c, enum bch_validate_flags);
|
||||
void bch2_dirent_to_text(struct printbuf *, struct bch_fs *, struct bkey_s_c);
|
||||
|
||||
#define bch2_bkey_ops_dirent ((struct bkey_ops) { \
|
||||
.key_invalid = bch2_dirent_invalid, \
|
||||
.key_validate = bch2_dirent_validate, \
|
||||
.val_to_text = bch2_dirent_to_text, \
|
||||
.min_val_size = 16, \
|
||||
})
|
||||
|
@ -126,9 +126,8 @@ static inline bool is_zero(char *start, char *end)
|
||||
|
||||
#define field_end(p, member) (((void *) (&p.member)) + sizeof(p.member))
|
||||
|
||||
int bch2_accounting_invalid(struct bch_fs *c, struct bkey_s_c k,
|
||||
enum bch_validate_flags flags,
|
||||
struct printbuf *err)
|
||||
int bch2_accounting_validate(struct bch_fs *c, struct bkey_s_c k,
|
||||
enum bch_validate_flags flags)
|
||||
{
|
||||
struct disk_accounting_pos acc_k;
|
||||
bpos_to_disk_accounting_pos(&acc_k, k.k->p);
|
||||
@ -144,18 +143,18 @@ int bch2_accounting_invalid(struct bch_fs *c, struct bkey_s_c k,
|
||||
break;
|
||||
case BCH_DISK_ACCOUNTING_replicas:
|
||||
bkey_fsck_err_on(!acc_k.replicas.nr_devs,
|
||||
c, err, accounting_key_replicas_nr_devs_0,
|
||||
c, accounting_key_replicas_nr_devs_0,
|
||||
"accounting key replicas entry with nr_devs=0");
|
||||
|
||||
bkey_fsck_err_on(acc_k.replicas.nr_required > acc_k.replicas.nr_devs ||
|
||||
(acc_k.replicas.nr_required > 1 &&
|
||||
acc_k.replicas.nr_required == acc_k.replicas.nr_devs),
|
||||
c, err, accounting_key_replicas_nr_required_bad,
|
||||
c, accounting_key_replicas_nr_required_bad,
|
||||
"accounting key replicas entry with bad nr_required");
|
||||
|
||||
for (unsigned i = 0; i + 1 < acc_k.replicas.nr_devs; i++)
|
||||
bkey_fsck_err_on(acc_k.replicas.devs[i] >= acc_k.replicas.devs[i + 1],
|
||||
c, err, accounting_key_replicas_devs_unsorted,
|
||||
c, accounting_key_replicas_devs_unsorted,
|
||||
"accounting key replicas entry with unsorted devs");
|
||||
|
||||
end = (void *) &acc_k.replicas + replicas_entry_bytes(&acc_k.replicas);
|
||||
@ -178,7 +177,7 @@ int bch2_accounting_invalid(struct bch_fs *c, struct bkey_s_c k,
|
||||
}
|
||||
|
||||
bkey_fsck_err_on(!is_zero(end, (void *) (&acc_k + 1)),
|
||||
c, err, accounting_key_junk_at_end,
|
||||
c, accounting_key_junk_at_end,
|
||||
"junk at end of accounting key");
|
||||
fsck_err:
|
||||
return ret;
|
||||
|
@ -82,14 +82,13 @@ int bch2_disk_accounting_mod(struct btree_trans *, struct disk_accounting_pos *,
|
||||
s64 *, unsigned, bool);
|
||||
int bch2_mod_dev_cached_sectors(struct btree_trans *, unsigned, s64, bool);
|
||||
|
||||
int bch2_accounting_invalid(struct bch_fs *, struct bkey_s_c,
|
||||
enum bch_validate_flags, struct printbuf *);
|
||||
int bch2_accounting_validate(struct bch_fs *, struct bkey_s_c, enum bch_validate_flags);
|
||||
void bch2_accounting_key_to_text(struct printbuf *, struct disk_accounting_pos *);
|
||||
void bch2_accounting_to_text(struct printbuf *, struct bch_fs *, struct bkey_s_c);
|
||||
void bch2_accounting_swab(struct bkey_s);
|
||||
|
||||
#define bch2_bkey_ops_accounting ((struct bkey_ops) { \
|
||||
.key_invalid = bch2_accounting_invalid, \
|
||||
.key_validate = bch2_accounting_validate, \
|
||||
.val_to_text = bch2_accounting_to_text, \
|
||||
.swab = bch2_accounting_swab, \
|
||||
.min_val_size = 8, \
|
||||
|
@ -107,24 +107,23 @@ struct ec_bio {
|
||||
|
||||
/* Stripes btree keys: */
|
||||
|
||||
int bch2_stripe_invalid(struct bch_fs *c, struct bkey_s_c k,
|
||||
enum bch_validate_flags flags,
|
||||
struct printbuf *err)
|
||||
int bch2_stripe_validate(struct bch_fs *c, struct bkey_s_c k,
|
||||
enum bch_validate_flags flags)
|
||||
{
|
||||
const struct bch_stripe *s = bkey_s_c_to_stripe(k).v;
|
||||
int ret = 0;
|
||||
|
||||
bkey_fsck_err_on(bkey_eq(k.k->p, POS_MIN) ||
|
||||
bpos_gt(k.k->p, POS(0, U32_MAX)), c, err,
|
||||
stripe_pos_bad,
|
||||
bpos_gt(k.k->p, POS(0, U32_MAX)),
|
||||
c, stripe_pos_bad,
|
||||
"stripe at bad pos");
|
||||
|
||||
bkey_fsck_err_on(bkey_val_u64s(k.k) < stripe_val_u64s(s), c, err,
|
||||
stripe_val_size_bad,
|
||||
bkey_fsck_err_on(bkey_val_u64s(k.k) < stripe_val_u64s(s),
|
||||
c, stripe_val_size_bad,
|
||||
"incorrect value size (%zu < %u)",
|
||||
bkey_val_u64s(k.k), stripe_val_u64s(s));
|
||||
|
||||
ret = bch2_bkey_ptrs_invalid(c, k, flags, err);
|
||||
ret = bch2_bkey_ptrs_validate(c, k, flags);
|
||||
fsck_err:
|
||||
return ret;
|
||||
}
|
||||
|
@ -8,8 +8,7 @@
|
||||
|
||||
enum bch_validate_flags;
|
||||
|
||||
int bch2_stripe_invalid(struct bch_fs *, struct bkey_s_c,
|
||||
enum bch_validate_flags, struct printbuf *);
|
||||
int bch2_stripe_validate(struct bch_fs *, struct bkey_s_c, enum bch_validate_flags);
|
||||
void bch2_stripe_to_text(struct printbuf *, struct bch_fs *,
|
||||
struct bkey_s_c);
|
||||
int bch2_trigger_stripe(struct btree_trans *, enum btree_id, unsigned,
|
||||
@ -17,7 +16,7 @@ int bch2_trigger_stripe(struct btree_trans *, enum btree_id, unsigned,
|
||||
enum btree_iter_update_trigger_flags);
|
||||
|
||||
#define bch2_bkey_ops_stripe ((struct bkey_ops) { \
|
||||
.key_invalid = bch2_stripe_invalid, \
|
||||
.key_validate = bch2_stripe_validate, \
|
||||
.val_to_text = bch2_stripe_to_text, \
|
||||
.swab = bch2_ptr_swab, \
|
||||
.trigger = bch2_trigger_stripe, \
|
||||
|
@ -166,6 +166,7 @@
|
||||
x(0, journal_reclaim_would_deadlock) \
|
||||
x(EINVAL, fsck) \
|
||||
x(BCH_ERR_fsck, fsck_fix) \
|
||||
x(BCH_ERR_fsck, fsck_delete_bkey) \
|
||||
x(BCH_ERR_fsck, fsck_ignore) \
|
||||
x(BCH_ERR_fsck, fsck_errors_not_fixed) \
|
||||
x(BCH_ERR_fsck, fsck_repair_unimplemented) \
|
||||
|
@ -416,6 +416,28 @@ err:
|
||||
return ret;
|
||||
}
|
||||
|
||||
int __bch2_bkey_fsck_err(struct bch_fs *c,
|
||||
struct bkey_s_c k,
|
||||
enum bch_fsck_flags flags,
|
||||
enum bch_sb_error_id err,
|
||||
const char *fmt, ...)
|
||||
{
|
||||
struct printbuf buf = PRINTBUF;
|
||||
va_list args;
|
||||
|
||||
prt_str(&buf, "invalid bkey ");
|
||||
bch2_bkey_val_to_text(&buf, c, k);
|
||||
prt_str(&buf, "\n ");
|
||||
va_start(args, fmt);
|
||||
prt_vprintf(&buf, fmt, args);
|
||||
va_end(args);
|
||||
prt_str(&buf, ": delete?");
|
||||
|
||||
int ret = __bch2_fsck_err(c, NULL, flags, err, "%s", buf.buf);
|
||||
printbuf_exit(&buf);
|
||||
return ret;
|
||||
}
|
||||
|
||||
void bch2_flush_fsck_errs(struct bch_fs *c)
|
||||
{
|
||||
struct fsck_err_state *s, *n;
|
||||
|
@ -4,6 +4,7 @@
|
||||
|
||||
#include <linux/list.h>
|
||||
#include <linux/printk.h>
|
||||
#include "bkey_types.h"
|
||||
#include "sb-errors.h"
|
||||
|
||||
struct bch_dev;
|
||||
@ -166,24 +167,30 @@ void bch2_flush_fsck_errs(struct bch_fs *);
|
||||
#define fsck_err_on(cond, c, _err_type, ...) \
|
||||
__fsck_err_on(cond, c, FSCK_CAN_FIX|FSCK_CAN_IGNORE, _err_type, __VA_ARGS__)
|
||||
|
||||
__printf(4, 0)
|
||||
static inline void bch2_bkey_fsck_err(struct bch_fs *c,
|
||||
struct printbuf *err_msg,
|
||||
enum bch_sb_error_id err_type,
|
||||
const char *fmt, ...)
|
||||
{
|
||||
va_list args;
|
||||
__printf(5, 6)
|
||||
int __bch2_bkey_fsck_err(struct bch_fs *,
|
||||
struct bkey_s_c,
|
||||
enum bch_fsck_flags,
|
||||
enum bch_sb_error_id,
|
||||
const char *, ...);
|
||||
|
||||
va_start(args, fmt);
|
||||
prt_vprintf(err_msg, fmt, args);
|
||||
va_end(args);
|
||||
}
|
||||
|
||||
#define bkey_fsck_err(c, _err_msg, _err_type, ...) \
|
||||
/*
|
||||
* for now, bkey fsck errors are always handled by deleting the entire key -
|
||||
* this will change at some point
|
||||
*/
|
||||
#define bkey_fsck_err(c, _err_type, _err_msg, ...) \
|
||||
do { \
|
||||
prt_printf(_err_msg, __VA_ARGS__); \
|
||||
bch2_sb_error_count(c, BCH_FSCK_ERR_##_err_type); \
|
||||
ret = -BCH_ERR_invalid_bkey; \
|
||||
if ((flags & BCH_VALIDATE_silent)) { \
|
||||
ret = -BCH_ERR_fsck_delete_bkey; \
|
||||
goto fsck_err; \
|
||||
} \
|
||||
int _ret = __bch2_bkey_fsck_err(c, k, FSCK_CAN_FIX, \
|
||||
BCH_FSCK_ERR_##_err_type, \
|
||||
_err_msg, ##__VA_ARGS__); \
|
||||
if (_ret != -BCH_ERR_fsck_fix && \
|
||||
_ret != -BCH_ERR_fsck_ignore) \
|
||||
ret = _ret; \
|
||||
ret = -BCH_ERR_fsck_delete_bkey; \
|
||||
goto fsck_err; \
|
||||
} while (0)
|
||||
|
||||
|
@ -171,17 +171,16 @@ int bch2_bkey_pick_read_device(struct bch_fs *c, struct bkey_s_c k,
|
||||
|
||||
/* KEY_TYPE_btree_ptr: */
|
||||
|
||||
int bch2_btree_ptr_invalid(struct bch_fs *c, struct bkey_s_c k,
|
||||
enum bch_validate_flags flags,
|
||||
struct printbuf *err)
|
||||
int bch2_btree_ptr_validate(struct bch_fs *c, struct bkey_s_c k,
|
||||
enum bch_validate_flags flags)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
bkey_fsck_err_on(bkey_val_u64s(k.k) > BCH_REPLICAS_MAX, c, err,
|
||||
btree_ptr_val_too_big,
|
||||
bkey_fsck_err_on(bkey_val_u64s(k.k) > BCH_REPLICAS_MAX,
|
||||
c, btree_ptr_val_too_big,
|
||||
"value too big (%zu > %u)", bkey_val_u64s(k.k), BCH_REPLICAS_MAX);
|
||||
|
||||
ret = bch2_bkey_ptrs_invalid(c, k, flags, err);
|
||||
ret = bch2_bkey_ptrs_validate(c, k, flags);
|
||||
fsck_err:
|
||||
return ret;
|
||||
}
|
||||
@ -192,28 +191,27 @@ void bch2_btree_ptr_to_text(struct printbuf *out, struct bch_fs *c,
|
||||
bch2_bkey_ptrs_to_text(out, c, k);
|
||||
}
|
||||
|
||||
int bch2_btree_ptr_v2_invalid(struct bch_fs *c, struct bkey_s_c k,
|
||||
enum bch_validate_flags flags,
|
||||
struct printbuf *err)
|
||||
int bch2_btree_ptr_v2_validate(struct bch_fs *c, struct bkey_s_c k,
|
||||
enum bch_validate_flags flags)
|
||||
{
|
||||
struct bkey_s_c_btree_ptr_v2 bp = bkey_s_c_to_btree_ptr_v2(k);
|
||||
int ret = 0;
|
||||
|
||||
bkey_fsck_err_on(bkey_val_u64s(k.k) > BKEY_BTREE_PTR_VAL_U64s_MAX,
|
||||
c, err, btree_ptr_v2_val_too_big,
|
||||
c, btree_ptr_v2_val_too_big,
|
||||
"value too big (%zu > %zu)",
|
||||
bkey_val_u64s(k.k), BKEY_BTREE_PTR_VAL_U64s_MAX);
|
||||
|
||||
bkey_fsck_err_on(bpos_ge(bp.v->min_key, bp.k->p),
|
||||
c, err, btree_ptr_v2_min_key_bad,
|
||||
c, btree_ptr_v2_min_key_bad,
|
||||
"min_key > key");
|
||||
|
||||
if (flags & BCH_VALIDATE_write)
|
||||
bkey_fsck_err_on(!bp.v->sectors_written,
|
||||
c, err, btree_ptr_v2_written_0,
|
||||
c, btree_ptr_v2_written_0,
|
||||
"sectors_written == 0");
|
||||
|
||||
ret = bch2_bkey_ptrs_invalid(c, k, flags, err);
|
||||
ret = bch2_bkey_ptrs_validate(c, k, flags);
|
||||
fsck_err:
|
||||
return ret;
|
||||
}
|
||||
@ -399,15 +397,14 @@ bool bch2_extent_merge(struct bch_fs *c, struct bkey_s l, struct bkey_s_c r)
|
||||
|
||||
/* KEY_TYPE_reservation: */
|
||||
|
||||
int bch2_reservation_invalid(struct bch_fs *c, struct bkey_s_c k,
|
||||
enum bch_validate_flags flags,
|
||||
struct printbuf *err)
|
||||
int bch2_reservation_validate(struct bch_fs *c, struct bkey_s_c k,
|
||||
enum bch_validate_flags flags)
|
||||
{
|
||||
struct bkey_s_c_reservation r = bkey_s_c_to_reservation(k);
|
||||
int ret = 0;
|
||||
|
||||
bkey_fsck_err_on(!r.v->nr_replicas || r.v->nr_replicas > BCH_REPLICAS_MAX, c, err,
|
||||
reservation_key_nr_replicas_invalid,
|
||||
bkey_fsck_err_on(!r.v->nr_replicas || r.v->nr_replicas > BCH_REPLICAS_MAX,
|
||||
c, reservation_key_nr_replicas_invalid,
|
||||
"invalid nr_replicas (%u)", r.v->nr_replicas);
|
||||
fsck_err:
|
||||
return ret;
|
||||
@ -1102,14 +1099,12 @@ void bch2_bkey_ptrs_to_text(struct printbuf *out, struct bch_fs *c,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static int extent_ptr_invalid(struct bch_fs *c,
|
||||
static int extent_ptr_validate(struct bch_fs *c,
|
||||
struct bkey_s_c k,
|
||||
enum bch_validate_flags flags,
|
||||
const struct bch_extent_ptr *ptr,
|
||||
unsigned size_ondisk,
|
||||
bool metadata,
|
||||
struct printbuf *err)
|
||||
bool metadata)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
@ -1128,28 +1123,27 @@ static int extent_ptr_invalid(struct bch_fs *c,
|
||||
|
||||
struct bkey_ptrs_c ptrs = bch2_bkey_ptrs_c(k);
|
||||
bkey_for_each_ptr(ptrs, ptr2)
|
||||
bkey_fsck_err_on(ptr != ptr2 && ptr->dev == ptr2->dev, c, err,
|
||||
ptr_to_duplicate_device,
|
||||
bkey_fsck_err_on(ptr != ptr2 && ptr->dev == ptr2->dev,
|
||||
c, ptr_to_duplicate_device,
|
||||
"multiple pointers to same device (%u)", ptr->dev);
|
||||
|
||||
|
||||
bkey_fsck_err_on(bucket >= nbuckets, c, err,
|
||||
ptr_after_last_bucket,
|
||||
bkey_fsck_err_on(bucket >= nbuckets,
|
||||
c, ptr_after_last_bucket,
|
||||
"pointer past last bucket (%llu > %llu)", bucket, nbuckets);
|
||||
bkey_fsck_err_on(bucket < first_bucket, c, err,
|
||||
ptr_before_first_bucket,
|
||||
bkey_fsck_err_on(bucket < first_bucket,
|
||||
c, ptr_before_first_bucket,
|
||||
"pointer before first bucket (%llu < %u)", bucket, first_bucket);
|
||||
bkey_fsck_err_on(bucket_offset + size_ondisk > bucket_size, c, err,
|
||||
ptr_spans_multiple_buckets,
|
||||
bkey_fsck_err_on(bucket_offset + size_ondisk > bucket_size,
|
||||
c, ptr_spans_multiple_buckets,
|
||||
"pointer spans multiple buckets (%u + %u > %u)",
|
||||
bucket_offset, size_ondisk, bucket_size);
|
||||
fsck_err:
|
||||
return ret;
|
||||
}
|
||||
|
||||
int bch2_bkey_ptrs_invalid(struct bch_fs *c, struct bkey_s_c k,
|
||||
enum bch_validate_flags flags,
|
||||
struct printbuf *err)
|
||||
int bch2_bkey_ptrs_validate(struct bch_fs *c, struct bkey_s_c k,
|
||||
enum bch_validate_flags flags)
|
||||
{
|
||||
struct bkey_ptrs_c ptrs = bch2_bkey_ptrs_c(k);
|
||||
const union bch_extent_entry *entry;
|
||||
@ -1164,25 +1158,24 @@ int bch2_bkey_ptrs_invalid(struct bch_fs *c, struct bkey_s_c k,
|
||||
size_ondisk = btree_sectors(c);
|
||||
|
||||
bkey_extent_entry_for_each(ptrs, entry) {
|
||||
bkey_fsck_err_on(__extent_entry_type(entry) >= BCH_EXTENT_ENTRY_MAX, c, err,
|
||||
extent_ptrs_invalid_entry,
|
||||
bkey_fsck_err_on(__extent_entry_type(entry) >= BCH_EXTENT_ENTRY_MAX,
|
||||
c, extent_ptrs_invalid_entry,
|
||||
"invalid extent entry type (got %u, max %u)",
|
||||
__extent_entry_type(entry), BCH_EXTENT_ENTRY_MAX);
|
||||
|
||||
bkey_fsck_err_on(bkey_is_btree_ptr(k.k) &&
|
||||
!extent_entry_is_ptr(entry), c, err,
|
||||
btree_ptr_has_non_ptr,
|
||||
!extent_entry_is_ptr(entry),
|
||||
c, btree_ptr_has_non_ptr,
|
||||
"has non ptr field");
|
||||
|
||||
switch (extent_entry_type(entry)) {
|
||||
case BCH_EXTENT_ENTRY_ptr:
|
||||
ret = extent_ptr_invalid(c, k, flags, &entry->ptr,
|
||||
size_ondisk, false, err);
|
||||
ret = extent_ptr_validate(c, k, flags, &entry->ptr, size_ondisk, false);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
bkey_fsck_err_on(entry->ptr.cached && have_ec, c, err,
|
||||
ptr_cached_and_erasure_coded,
|
||||
bkey_fsck_err_on(entry->ptr.cached && have_ec,
|
||||
c, ptr_cached_and_erasure_coded,
|
||||
"cached, erasure coded ptr");
|
||||
|
||||
if (!entry->ptr.unwritten)
|
||||
@ -1199,44 +1192,50 @@ int bch2_bkey_ptrs_invalid(struct bch_fs *c, struct bkey_s_c k,
|
||||
case BCH_EXTENT_ENTRY_crc128:
|
||||
crc = bch2_extent_crc_unpack(k.k, entry_to_crc(entry));
|
||||
|
||||
bkey_fsck_err_on(crc.offset + crc.live_size > crc.uncompressed_size, c, err,
|
||||
ptr_crc_uncompressed_size_too_small,
|
||||
bkey_fsck_err_on(crc.offset + crc.live_size > crc.uncompressed_size,
|
||||
c, ptr_crc_uncompressed_size_too_small,
|
||||
"checksum offset + key size > uncompressed size");
|
||||
bkey_fsck_err_on(!bch2_checksum_type_valid(c, crc.csum_type), c, err,
|
||||
ptr_crc_csum_type_unknown,
|
||||
bkey_fsck_err_on(!bch2_checksum_type_valid(c, crc.csum_type),
|
||||
c, ptr_crc_csum_type_unknown,
|
||||
"invalid checksum type");
|
||||
bkey_fsck_err_on(crc.compression_type >= BCH_COMPRESSION_TYPE_NR, c, err,
|
||||
ptr_crc_compression_type_unknown,
|
||||
bkey_fsck_err_on(crc.compression_type >= BCH_COMPRESSION_TYPE_NR,
|
||||
c, ptr_crc_compression_type_unknown,
|
||||
"invalid compression type");
|
||||
|
||||
if (bch2_csum_type_is_encryption(crc.csum_type)) {
|
||||
if (nonce == UINT_MAX)
|
||||
nonce = crc.offset + crc.nonce;
|
||||
else if (nonce != crc.offset + crc.nonce)
|
||||
bkey_fsck_err(c, err, ptr_crc_nonce_mismatch,
|
||||
bkey_fsck_err(c, ptr_crc_nonce_mismatch,
|
||||
"incorrect nonce");
|
||||
}
|
||||
|
||||
bkey_fsck_err_on(crc_since_last_ptr, c, err,
|
||||
ptr_crc_redundant,
|
||||
bkey_fsck_err_on(crc_since_last_ptr,
|
||||
c, ptr_crc_redundant,
|
||||
"redundant crc entry");
|
||||
crc_since_last_ptr = true;
|
||||
|
||||
bkey_fsck_err_on(crc_is_encoded(crc) &&
|
||||
(crc.uncompressed_size > c->opts.encoded_extent_max >> 9) &&
|
||||
(flags & (BCH_VALIDATE_write|BCH_VALIDATE_commit)), c, err,
|
||||
ptr_crc_uncompressed_size_too_big,
|
||||
(flags & (BCH_VALIDATE_write|BCH_VALIDATE_commit)),
|
||||
c, ptr_crc_uncompressed_size_too_big,
|
||||
"too large encoded extent");
|
||||
|
||||
size_ondisk = crc.compressed_size;
|
||||
break;
|
||||
case BCH_EXTENT_ENTRY_stripe_ptr:
|
||||
bkey_fsck_err_on(have_ec, c, err,
|
||||
ptr_stripe_redundant,
|
||||
bkey_fsck_err_on(have_ec,
|
||||
c, ptr_stripe_redundant,
|
||||
"redundant stripe entry");
|
||||
have_ec = true;
|
||||
break;
|
||||
case BCH_EXTENT_ENTRY_rebalance: {
|
||||
/*
|
||||
* this shouldn't be a fsck error, for forward
|
||||
* compatibility; the rebalance code should just refetch
|
||||
* the compression opt if it's unknown
|
||||
*/
|
||||
#if 0
|
||||
const struct bch_extent_rebalance *r = &entry->rebalance;
|
||||
|
||||
if (!bch2_compression_opt_valid(r->compression)) {
|
||||
@ -1245,28 +1244,29 @@ int bch2_bkey_ptrs_invalid(struct bch_fs *c, struct bkey_s_c k,
|
||||
opt.type, opt.level);
|
||||
return -BCH_ERR_invalid_bkey;
|
||||
}
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bkey_fsck_err_on(!nr_ptrs, c, err,
|
||||
extent_ptrs_no_ptrs,
|
||||
bkey_fsck_err_on(!nr_ptrs,
|
||||
c, extent_ptrs_no_ptrs,
|
||||
"no ptrs");
|
||||
bkey_fsck_err_on(nr_ptrs > BCH_BKEY_PTRS_MAX, c, err,
|
||||
extent_ptrs_too_many_ptrs,
|
||||
bkey_fsck_err_on(nr_ptrs > BCH_BKEY_PTRS_MAX,
|
||||
c, extent_ptrs_too_many_ptrs,
|
||||
"too many ptrs: %u > %u", nr_ptrs, BCH_BKEY_PTRS_MAX);
|
||||
bkey_fsck_err_on(have_written && have_unwritten, c, err,
|
||||
extent_ptrs_written_and_unwritten,
|
||||
bkey_fsck_err_on(have_written && have_unwritten,
|
||||
c, extent_ptrs_written_and_unwritten,
|
||||
"extent with unwritten and written ptrs");
|
||||
bkey_fsck_err_on(k.k->type != KEY_TYPE_extent && have_unwritten, c, err,
|
||||
extent_ptrs_unwritten,
|
||||
bkey_fsck_err_on(k.k->type != KEY_TYPE_extent && have_unwritten,
|
||||
c, extent_ptrs_unwritten,
|
||||
"has unwritten ptrs");
|
||||
bkey_fsck_err_on(crc_since_last_ptr, c, err,
|
||||
extent_ptrs_redundant_crc,
|
||||
bkey_fsck_err_on(crc_since_last_ptr,
|
||||
c, extent_ptrs_redundant_crc,
|
||||
"redundant crc entry");
|
||||
bkey_fsck_err_on(have_ec, c, err,
|
||||
extent_ptrs_redundant_stripe,
|
||||
bkey_fsck_err_on(have_ec,
|
||||
c, extent_ptrs_redundant_stripe,
|
||||
"redundant stripe entry");
|
||||
fsck_err:
|
||||
return ret;
|
||||
|
@ -409,26 +409,26 @@ int bch2_bkey_pick_read_device(struct bch_fs *, struct bkey_s_c,
|
||||
|
||||
/* KEY_TYPE_btree_ptr: */
|
||||
|
||||
int bch2_btree_ptr_invalid(struct bch_fs *, struct bkey_s_c,
|
||||
enum bch_validate_flags, struct printbuf *);
|
||||
int bch2_btree_ptr_validate(struct bch_fs *, struct bkey_s_c,
|
||||
enum bch_validate_flags);
|
||||
void bch2_btree_ptr_to_text(struct printbuf *, struct bch_fs *,
|
||||
struct bkey_s_c);
|
||||
|
||||
int bch2_btree_ptr_v2_invalid(struct bch_fs *, struct bkey_s_c,
|
||||
enum bch_validate_flags, struct printbuf *);
|
||||
int bch2_btree_ptr_v2_validate(struct bch_fs *, struct bkey_s_c,
|
||||
enum bch_validate_flags);
|
||||
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,
|
||||
int, struct bkey_s);
|
||||
|
||||
#define bch2_bkey_ops_btree_ptr ((struct bkey_ops) { \
|
||||
.key_invalid = bch2_btree_ptr_invalid, \
|
||||
.key_validate = bch2_btree_ptr_validate, \
|
||||
.val_to_text = bch2_btree_ptr_to_text, \
|
||||
.swab = bch2_ptr_swab, \
|
||||
.trigger = bch2_trigger_extent, \
|
||||
})
|
||||
|
||||
#define bch2_bkey_ops_btree_ptr_v2 ((struct bkey_ops) { \
|
||||
.key_invalid = bch2_btree_ptr_v2_invalid, \
|
||||
.key_validate = bch2_btree_ptr_v2_validate, \
|
||||
.val_to_text = bch2_btree_ptr_v2_to_text, \
|
||||
.swab = bch2_ptr_swab, \
|
||||
.compat = bch2_btree_ptr_v2_compat, \
|
||||
@ -441,7 +441,7 @@ void bch2_btree_ptr_v2_compat(enum btree_id, unsigned, unsigned,
|
||||
bool bch2_extent_merge(struct bch_fs *, struct bkey_s, struct bkey_s_c);
|
||||
|
||||
#define bch2_bkey_ops_extent ((struct bkey_ops) { \
|
||||
.key_invalid = bch2_bkey_ptrs_invalid, \
|
||||
.key_validate = bch2_bkey_ptrs_validate, \
|
||||
.val_to_text = bch2_bkey_ptrs_to_text, \
|
||||
.swab = bch2_ptr_swab, \
|
||||
.key_normalize = bch2_extent_normalize, \
|
||||
@ -451,13 +451,13 @@ bool bch2_extent_merge(struct bch_fs *, struct bkey_s, struct bkey_s_c);
|
||||
|
||||
/* KEY_TYPE_reservation: */
|
||||
|
||||
int bch2_reservation_invalid(struct bch_fs *, struct bkey_s_c,
|
||||
enum bch_validate_flags, struct printbuf *);
|
||||
int bch2_reservation_validate(struct bch_fs *, struct bkey_s_c,
|
||||
enum bch_validate_flags);
|
||||
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);
|
||||
|
||||
#define bch2_bkey_ops_reservation ((struct bkey_ops) { \
|
||||
.key_invalid = bch2_reservation_invalid, \
|
||||
.key_validate = bch2_reservation_validate, \
|
||||
.val_to_text = bch2_reservation_to_text, \
|
||||
.key_merge = bch2_reservation_merge, \
|
||||
.trigger = bch2_trigger_reservation, \
|
||||
@ -683,8 +683,8 @@ bool bch2_extent_normalize(struct bch_fs *, struct bkey_s);
|
||||
void bch2_extent_ptr_to_text(struct printbuf *out, struct bch_fs *, const struct bch_extent_ptr *);
|
||||
void bch2_bkey_ptrs_to_text(struct printbuf *, struct bch_fs *,
|
||||
struct bkey_s_c);
|
||||
int bch2_bkey_ptrs_invalid(struct bch_fs *, struct bkey_s_c,
|
||||
enum bch_validate_flags, struct printbuf *);
|
||||
int bch2_bkey_ptrs_validate(struct bch_fs *, struct bkey_s_c,
|
||||
enum bch_validate_flags);
|
||||
|
||||
void bch2_ptr_swab(struct bkey_s);
|
||||
|
||||
|
@ -434,100 +434,98 @@ struct bkey_i *bch2_inode_to_v3(struct btree_trans *trans, struct bkey_i *k)
|
||||
return &inode_p->inode.k_i;
|
||||
}
|
||||
|
||||
static int __bch2_inode_invalid(struct bch_fs *c, struct bkey_s_c k, struct printbuf *err)
|
||||
static int __bch2_inode_validate(struct bch_fs *c, struct bkey_s_c k,
|
||||
enum bch_validate_flags flags)
|
||||
{
|
||||
struct bch_inode_unpacked unpacked;
|
||||
int ret = 0;
|
||||
|
||||
bkey_fsck_err_on(k.k->p.inode, c, err,
|
||||
inode_pos_inode_nonzero,
|
||||
bkey_fsck_err_on(k.k->p.inode,
|
||||
c, inode_pos_inode_nonzero,
|
||||
"nonzero k.p.inode");
|
||||
|
||||
bkey_fsck_err_on(k.k->p.offset < BLOCKDEV_INODE_MAX, c, err,
|
||||
inode_pos_blockdev_range,
|
||||
bkey_fsck_err_on(k.k->p.offset < BLOCKDEV_INODE_MAX,
|
||||
c, inode_pos_blockdev_range,
|
||||
"fs inode in blockdev range");
|
||||
|
||||
bkey_fsck_err_on(bch2_inode_unpack(k, &unpacked), c, err,
|
||||
inode_unpack_error,
|
||||
bkey_fsck_err_on(bch2_inode_unpack(k, &unpacked),
|
||||
c, inode_unpack_error,
|
||||
"invalid variable length fields");
|
||||
|
||||
bkey_fsck_err_on(unpacked.bi_data_checksum >= BCH_CSUM_OPT_NR + 1, c, err,
|
||||
inode_checksum_type_invalid,
|
||||
bkey_fsck_err_on(unpacked.bi_data_checksum >= BCH_CSUM_OPT_NR + 1,
|
||||
c, inode_checksum_type_invalid,
|
||||
"invalid data checksum type (%u >= %u",
|
||||
unpacked.bi_data_checksum, BCH_CSUM_OPT_NR + 1);
|
||||
|
||||
bkey_fsck_err_on(unpacked.bi_compression &&
|
||||
!bch2_compression_opt_valid(unpacked.bi_compression - 1), c, err,
|
||||
inode_compression_type_invalid,
|
||||
!bch2_compression_opt_valid(unpacked.bi_compression - 1),
|
||||
c, inode_compression_type_invalid,
|
||||
"invalid compression opt %u", unpacked.bi_compression - 1);
|
||||
|
||||
bkey_fsck_err_on((unpacked.bi_flags & BCH_INODE_unlinked) &&
|
||||
unpacked.bi_nlink != 0, c, err,
|
||||
inode_unlinked_but_nlink_nonzero,
|
||||
unpacked.bi_nlink != 0,
|
||||
c, inode_unlinked_but_nlink_nonzero,
|
||||
"flagged as unlinked but bi_nlink != 0");
|
||||
|
||||
bkey_fsck_err_on(unpacked.bi_subvol && !S_ISDIR(unpacked.bi_mode), c, err,
|
||||
inode_subvol_root_but_not_dir,
|
||||
bkey_fsck_err_on(unpacked.bi_subvol && !S_ISDIR(unpacked.bi_mode),
|
||||
c, inode_subvol_root_but_not_dir,
|
||||
"subvolume root but not a directory");
|
||||
fsck_err:
|
||||
return ret;
|
||||
}
|
||||
|
||||
int bch2_inode_invalid(struct bch_fs *c, struct bkey_s_c k,
|
||||
enum bch_validate_flags flags,
|
||||
struct printbuf *err)
|
||||
int bch2_inode_validate(struct bch_fs *c, struct bkey_s_c k,
|
||||
enum bch_validate_flags flags)
|
||||
{
|
||||
struct bkey_s_c_inode inode = bkey_s_c_to_inode(k);
|
||||
int ret = 0;
|
||||
|
||||
bkey_fsck_err_on(INODE_STR_HASH(inode.v) >= BCH_STR_HASH_NR, c, err,
|
||||
inode_str_hash_invalid,
|
||||
bkey_fsck_err_on(INODE_STR_HASH(inode.v) >= BCH_STR_HASH_NR,
|
||||
c, inode_str_hash_invalid,
|
||||
"invalid str hash type (%llu >= %u)",
|
||||
INODE_STR_HASH(inode.v), BCH_STR_HASH_NR);
|
||||
|
||||
ret = __bch2_inode_invalid(c, k, err);
|
||||
ret = __bch2_inode_validate(c, k, flags);
|
||||
fsck_err:
|
||||
return ret;
|
||||
}
|
||||
|
||||
int bch2_inode_v2_invalid(struct bch_fs *c, struct bkey_s_c k,
|
||||
enum bch_validate_flags flags,
|
||||
struct printbuf *err)
|
||||
int bch2_inode_v2_validate(struct bch_fs *c, struct bkey_s_c k,
|
||||
enum bch_validate_flags flags)
|
||||
{
|
||||
struct bkey_s_c_inode_v2 inode = bkey_s_c_to_inode_v2(k);
|
||||
int ret = 0;
|
||||
|
||||
bkey_fsck_err_on(INODEv2_STR_HASH(inode.v) >= BCH_STR_HASH_NR, c, err,
|
||||
inode_str_hash_invalid,
|
||||
bkey_fsck_err_on(INODEv2_STR_HASH(inode.v) >= BCH_STR_HASH_NR,
|
||||
c, inode_str_hash_invalid,
|
||||
"invalid str hash type (%llu >= %u)",
|
||||
INODEv2_STR_HASH(inode.v), BCH_STR_HASH_NR);
|
||||
|
||||
ret = __bch2_inode_invalid(c, k, err);
|
||||
ret = __bch2_inode_validate(c, k, flags);
|
||||
fsck_err:
|
||||
return ret;
|
||||
}
|
||||
|
||||
int bch2_inode_v3_invalid(struct bch_fs *c, struct bkey_s_c k,
|
||||
enum bch_validate_flags flags,
|
||||
struct printbuf *err)
|
||||
int bch2_inode_v3_validate(struct bch_fs *c, struct bkey_s_c k,
|
||||
enum bch_validate_flags flags)
|
||||
{
|
||||
struct bkey_s_c_inode_v3 inode = bkey_s_c_to_inode_v3(k);
|
||||
int ret = 0;
|
||||
|
||||
bkey_fsck_err_on(INODEv3_FIELDS_START(inode.v) < INODEv3_FIELDS_START_INITIAL ||
|
||||
INODEv3_FIELDS_START(inode.v) > bkey_val_u64s(inode.k), c, err,
|
||||
inode_v3_fields_start_bad,
|
||||
INODEv3_FIELDS_START(inode.v) > bkey_val_u64s(inode.k),
|
||||
c, inode_v3_fields_start_bad,
|
||||
"invalid fields_start (got %llu, min %u max %zu)",
|
||||
INODEv3_FIELDS_START(inode.v),
|
||||
INODEv3_FIELDS_START_INITIAL,
|
||||
bkey_val_u64s(inode.k));
|
||||
|
||||
bkey_fsck_err_on(INODEv3_STR_HASH(inode.v) >= BCH_STR_HASH_NR, c, err,
|
||||
inode_str_hash_invalid,
|
||||
bkey_fsck_err_on(INODEv3_STR_HASH(inode.v) >= BCH_STR_HASH_NR,
|
||||
c, inode_str_hash_invalid,
|
||||
"invalid str hash type (%llu >= %u)",
|
||||
INODEv3_STR_HASH(inode.v), BCH_STR_HASH_NR);
|
||||
|
||||
ret = __bch2_inode_invalid(c, k, err);
|
||||
ret = __bch2_inode_validate(c, k, flags);
|
||||
fsck_err:
|
||||
return ret;
|
||||
}
|
||||
@ -625,14 +623,13 @@ int bch2_trigger_inode(struct btree_trans *trans,
|
||||
return 0;
|
||||
}
|
||||
|
||||
int bch2_inode_generation_invalid(struct bch_fs *c, struct bkey_s_c k,
|
||||
enum bch_validate_flags flags,
|
||||
struct printbuf *err)
|
||||
int bch2_inode_generation_validate(struct bch_fs *c, struct bkey_s_c k,
|
||||
enum bch_validate_flags flags)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
bkey_fsck_err_on(k.k->p.inode, c, err,
|
||||
inode_pos_inode_nonzero,
|
||||
bkey_fsck_err_on(k.k->p.inode,
|
||||
c, inode_pos_inode_nonzero,
|
||||
"nonzero k.p.inode");
|
||||
fsck_err:
|
||||
return ret;
|
||||
|
@ -9,12 +9,12 @@
|
||||
enum bch_validate_flags;
|
||||
extern const char * const bch2_inode_opts[];
|
||||
|
||||
int bch2_inode_invalid(struct bch_fs *, struct bkey_s_c,
|
||||
enum bch_validate_flags, struct printbuf *);
|
||||
int bch2_inode_v2_invalid(struct bch_fs *, struct bkey_s_c,
|
||||
enum bch_validate_flags, struct printbuf *);
|
||||
int bch2_inode_v3_invalid(struct bch_fs *, struct bkey_s_c,
|
||||
enum bch_validate_flags, struct printbuf *);
|
||||
int bch2_inode_validate(struct bch_fs *, struct bkey_s_c,
|
||||
enum bch_validate_flags);
|
||||
int bch2_inode_v2_validate(struct bch_fs *, struct bkey_s_c,
|
||||
enum bch_validate_flags);
|
||||
int bch2_inode_v3_validate(struct bch_fs *, struct bkey_s_c,
|
||||
enum bch_validate_flags);
|
||||
void bch2_inode_to_text(struct printbuf *, struct bch_fs *, struct bkey_s_c);
|
||||
|
||||
int bch2_trigger_inode(struct btree_trans *, enum btree_id, unsigned,
|
||||
@ -22,21 +22,21 @@ int bch2_trigger_inode(struct btree_trans *, enum btree_id, unsigned,
|
||||
enum btree_iter_update_trigger_flags);
|
||||
|
||||
#define bch2_bkey_ops_inode ((struct bkey_ops) { \
|
||||
.key_invalid = bch2_inode_invalid, \
|
||||
.key_validate = bch2_inode_validate, \
|
||||
.val_to_text = bch2_inode_to_text, \
|
||||
.trigger = bch2_trigger_inode, \
|
||||
.min_val_size = 16, \
|
||||
})
|
||||
|
||||
#define bch2_bkey_ops_inode_v2 ((struct bkey_ops) { \
|
||||
.key_invalid = bch2_inode_v2_invalid, \
|
||||
.key_validate = bch2_inode_v2_validate, \
|
||||
.val_to_text = bch2_inode_to_text, \
|
||||
.trigger = bch2_trigger_inode, \
|
||||
.min_val_size = 32, \
|
||||
})
|
||||
|
||||
#define bch2_bkey_ops_inode_v3 ((struct bkey_ops) { \
|
||||
.key_invalid = bch2_inode_v3_invalid, \
|
||||
.key_validate = bch2_inode_v3_validate, \
|
||||
.val_to_text = bch2_inode_to_text, \
|
||||
.trigger = bch2_trigger_inode, \
|
||||
.min_val_size = 48, \
|
||||
@ -49,12 +49,12 @@ static inline bool bkey_is_inode(const struct bkey *k)
|
||||
k->type == KEY_TYPE_inode_v3;
|
||||
}
|
||||
|
||||
int bch2_inode_generation_invalid(struct bch_fs *, struct bkey_s_c,
|
||||
enum bch_validate_flags, struct printbuf *);
|
||||
int bch2_inode_generation_validate(struct bch_fs *, struct bkey_s_c,
|
||||
enum bch_validate_flags);
|
||||
void bch2_inode_generation_to_text(struct printbuf *, struct bch_fs *, struct bkey_s_c);
|
||||
|
||||
#define bch2_bkey_ops_inode_generation ((struct bkey_ops) { \
|
||||
.key_invalid = bch2_inode_generation_invalid, \
|
||||
.key_validate = bch2_inode_generation_validate, \
|
||||
.val_to_text = bch2_inode_generation_to_text, \
|
||||
.min_val_size = 8, \
|
||||
})
|
||||
|
@ -332,7 +332,6 @@ static int journal_validate_key(struct bch_fs *c,
|
||||
{
|
||||
int write = flags & BCH_VALIDATE_write;
|
||||
void *next = vstruct_next(entry);
|
||||
struct printbuf buf = PRINTBUF;
|
||||
int ret = 0;
|
||||
|
||||
if (journal_entry_err_on(!k->k.u64s,
|
||||
@ -368,34 +367,21 @@ static int journal_validate_key(struct bch_fs *c,
|
||||
bch2_bkey_compat(level, btree_id, version, big_endian,
|
||||
write, NULL, bkey_to_packed(k));
|
||||
|
||||
if (bch2_bkey_invalid(c, bkey_i_to_s_c(k),
|
||||
__btree_node_type(level, btree_id), write, &buf)) {
|
||||
printbuf_reset(&buf);
|
||||
journal_entry_err_msg(&buf, version, jset, entry);
|
||||
prt_newline(&buf);
|
||||
printbuf_indent_add(&buf, 2);
|
||||
|
||||
bch2_bkey_val_to_text(&buf, c, bkey_i_to_s_c(k));
|
||||
prt_newline(&buf);
|
||||
bch2_bkey_invalid(c, bkey_i_to_s_c(k),
|
||||
__btree_node_type(level, btree_id), write, &buf);
|
||||
|
||||
mustfix_fsck_err(c, journal_entry_bkey_invalid,
|
||||
"%s", buf.buf);
|
||||
|
||||
ret = bch2_bkey_validate(c, bkey_i_to_s_c(k),
|
||||
__btree_node_type(level, btree_id), write);
|
||||
if (ret == -BCH_ERR_fsck_delete_bkey) {
|
||||
le16_add_cpu(&entry->u64s, -((u16) k->k.u64s));
|
||||
memmove(k, bkey_next(k), next - (void *) bkey_next(k));
|
||||
journal_entry_null_range(vstruct_next(entry), next);
|
||||
|
||||
printbuf_exit(&buf);
|
||||
return FSCK_DELETED_KEY;
|
||||
}
|
||||
if (ret)
|
||||
goto fsck_err;
|
||||
|
||||
if (write)
|
||||
bch2_bkey_compat(level, btree_id, version, big_endian,
|
||||
write, NULL, bkey_to_packed(k));
|
||||
fsck_err:
|
||||
printbuf_exit(&buf);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -10,14 +10,13 @@
|
||||
#include "recovery.h"
|
||||
|
||||
/* KEY_TYPE_lru is obsolete: */
|
||||
int bch2_lru_invalid(struct bch_fs *c, struct bkey_s_c k,
|
||||
enum bch_validate_flags flags,
|
||||
struct printbuf *err)
|
||||
int bch2_lru_validate(struct bch_fs *c, struct bkey_s_c k,
|
||||
enum bch_validate_flags flags)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
bkey_fsck_err_on(!lru_pos_time(k.k->p), c, err,
|
||||
lru_entry_at_time_0,
|
||||
bkey_fsck_err_on(!lru_pos_time(k.k->p),
|
||||
c, lru_entry_at_time_0,
|
||||
"lru entry at time=0");
|
||||
fsck_err:
|
||||
return ret;
|
||||
|
@ -33,14 +33,13 @@ static inline enum bch_lru_type lru_type(struct bkey_s_c l)
|
||||
return BCH_LRU_read;
|
||||
}
|
||||
|
||||
int bch2_lru_invalid(struct bch_fs *, struct bkey_s_c,
|
||||
enum bch_validate_flags, struct printbuf *);
|
||||
int bch2_lru_validate(struct bch_fs *, struct bkey_s_c, enum bch_validate_flags);
|
||||
void bch2_lru_to_text(struct printbuf *, struct bch_fs *, struct bkey_s_c);
|
||||
|
||||
void bch2_lru_pos_to_text(struct printbuf *, struct bpos);
|
||||
|
||||
#define bch2_bkey_ops_lru ((struct bkey_ops) { \
|
||||
.key_invalid = bch2_lru_invalid, \
|
||||
.key_validate = bch2_lru_validate, \
|
||||
.val_to_text = bch2_lru_to_text, \
|
||||
.min_val_size = 8, \
|
||||
})
|
||||
|
@ -59,13 +59,13 @@ const struct bch_sb_field_ops bch_sb_field_ops_quota = {
|
||||
.to_text = bch2_sb_quota_to_text,
|
||||
};
|
||||
|
||||
int bch2_quota_invalid(struct bch_fs *c, struct bkey_s_c k,
|
||||
enum bch_validate_flags flags, struct printbuf *err)
|
||||
int bch2_quota_validate(struct bch_fs *c, struct bkey_s_c k,
|
||||
enum bch_validate_flags flags)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
bkey_fsck_err_on(k.k->p.inode >= QTYP_NR, c, err,
|
||||
quota_type_invalid,
|
||||
bkey_fsck_err_on(k.k->p.inode >= QTYP_NR,
|
||||
c, quota_type_invalid,
|
||||
"invalid quota type (%llu >= %u)",
|
||||
k.k->p.inode, QTYP_NR);
|
||||
fsck_err:
|
||||
|
@ -8,12 +8,11 @@
|
||||
enum bch_validate_flags;
|
||||
extern const struct bch_sb_field_ops bch_sb_field_ops_quota;
|
||||
|
||||
int bch2_quota_invalid(struct bch_fs *, struct bkey_s_c,
|
||||
enum bch_validate_flags, struct printbuf *);
|
||||
int bch2_quota_validate(struct bch_fs *, struct bkey_s_c, enum bch_validate_flags);
|
||||
void bch2_quota_to_text(struct printbuf *, struct bch_fs *, struct bkey_s_c);
|
||||
|
||||
#define bch2_bkey_ops_quota ((struct bkey_ops) { \
|
||||
.key_invalid = bch2_quota_invalid, \
|
||||
.key_validate = bch2_quota_validate, \
|
||||
.val_to_text = bch2_quota_to_text, \
|
||||
.min_val_size = 32, \
|
||||
})
|
||||
|
@ -29,15 +29,14 @@ static inline unsigned bkey_type_to_indirect(const struct bkey *k)
|
||||
|
||||
/* reflink pointers */
|
||||
|
||||
int bch2_reflink_p_invalid(struct bch_fs *c, struct bkey_s_c k,
|
||||
enum bch_validate_flags flags,
|
||||
struct printbuf *err)
|
||||
int bch2_reflink_p_validate(struct bch_fs *c, struct bkey_s_c k,
|
||||
enum bch_validate_flags flags)
|
||||
{
|
||||
struct bkey_s_c_reflink_p p = bkey_s_c_to_reflink_p(k);
|
||||
int ret = 0;
|
||||
|
||||
bkey_fsck_err_on(le64_to_cpu(p.v->idx) < le32_to_cpu(p.v->front_pad),
|
||||
c, err, reflink_p_front_pad_bad,
|
||||
c, reflink_p_front_pad_bad,
|
||||
"idx < front_pad (%llu < %u)",
|
||||
le64_to_cpu(p.v->idx), le32_to_cpu(p.v->front_pad));
|
||||
fsck_err:
|
||||
@ -256,11 +255,10 @@ int bch2_trigger_reflink_p(struct btree_trans *trans,
|
||||
|
||||
/* indirect extents */
|
||||
|
||||
int bch2_reflink_v_invalid(struct bch_fs *c, struct bkey_s_c k,
|
||||
enum bch_validate_flags flags,
|
||||
struct printbuf *err)
|
||||
int bch2_reflink_v_validate(struct bch_fs *c, struct bkey_s_c k,
|
||||
enum bch_validate_flags flags)
|
||||
{
|
||||
return bch2_bkey_ptrs_invalid(c, k, flags, err);
|
||||
return bch2_bkey_ptrs_validate(c, k, flags);
|
||||
}
|
||||
|
||||
void bch2_reflink_v_to_text(struct printbuf *out, struct bch_fs *c,
|
||||
@ -311,9 +309,8 @@ int bch2_trigger_reflink_v(struct btree_trans *trans,
|
||||
|
||||
/* indirect inline data */
|
||||
|
||||
int bch2_indirect_inline_data_invalid(struct bch_fs *c, struct bkey_s_c k,
|
||||
enum bch_validate_flags flags,
|
||||
struct printbuf *err)
|
||||
int bch2_indirect_inline_data_validate(struct bch_fs *c, struct bkey_s_c k,
|
||||
enum bch_validate_flags flags)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
@ -4,41 +4,37 @@
|
||||
|
||||
enum bch_validate_flags;
|
||||
|
||||
int bch2_reflink_p_invalid(struct bch_fs *, struct bkey_s_c,
|
||||
enum bch_validate_flags, struct printbuf *);
|
||||
void bch2_reflink_p_to_text(struct printbuf *, struct bch_fs *,
|
||||
struct bkey_s_c);
|
||||
int bch2_reflink_p_validate(struct bch_fs *, struct bkey_s_c, enum bch_validate_flags);
|
||||
void bch2_reflink_p_to_text(struct printbuf *, struct bch_fs *, struct bkey_s_c);
|
||||
bool bch2_reflink_p_merge(struct bch_fs *, struct bkey_s, struct bkey_s_c);
|
||||
int bch2_trigger_reflink_p(struct btree_trans *, enum btree_id, unsigned,
|
||||
struct bkey_s_c, struct bkey_s,
|
||||
enum btree_iter_update_trigger_flags);
|
||||
|
||||
#define bch2_bkey_ops_reflink_p ((struct bkey_ops) { \
|
||||
.key_invalid = bch2_reflink_p_invalid, \
|
||||
.key_validate = bch2_reflink_p_validate, \
|
||||
.val_to_text = bch2_reflink_p_to_text, \
|
||||
.key_merge = bch2_reflink_p_merge, \
|
||||
.trigger = bch2_trigger_reflink_p, \
|
||||
.min_val_size = 16, \
|
||||
})
|
||||
|
||||
int bch2_reflink_v_invalid(struct bch_fs *, struct bkey_s_c,
|
||||
enum bch_validate_flags, struct printbuf *);
|
||||
void bch2_reflink_v_to_text(struct printbuf *, struct bch_fs *,
|
||||
struct bkey_s_c);
|
||||
int bch2_reflink_v_validate(struct bch_fs *, struct bkey_s_c, enum bch_validate_flags);
|
||||
void bch2_reflink_v_to_text(struct printbuf *, struct bch_fs *, struct bkey_s_c);
|
||||
int bch2_trigger_reflink_v(struct btree_trans *, enum btree_id, unsigned,
|
||||
struct bkey_s_c, struct bkey_s,
|
||||
enum btree_iter_update_trigger_flags);
|
||||
|
||||
#define bch2_bkey_ops_reflink_v ((struct bkey_ops) { \
|
||||
.key_invalid = bch2_reflink_v_invalid, \
|
||||
.key_validate = bch2_reflink_v_validate, \
|
||||
.val_to_text = bch2_reflink_v_to_text, \
|
||||
.swab = bch2_ptr_swab, \
|
||||
.trigger = bch2_trigger_reflink_v, \
|
||||
.min_val_size = 8, \
|
||||
})
|
||||
|
||||
int bch2_indirect_inline_data_invalid(struct bch_fs *, struct bkey_s_c,
|
||||
enum bch_validate_flags, struct printbuf *);
|
||||
int bch2_indirect_inline_data_validate(struct bch_fs *, struct bkey_s_c,
|
||||
enum bch_validate_flags);
|
||||
void bch2_indirect_inline_data_to_text(struct printbuf *,
|
||||
struct bch_fs *, struct bkey_s_c);
|
||||
int bch2_trigger_indirect_inline_data(struct btree_trans *,
|
||||
@ -47,7 +43,7 @@ int bch2_trigger_indirect_inline_data(struct btree_trans *,
|
||||
enum btree_iter_update_trigger_flags);
|
||||
|
||||
#define bch2_bkey_ops_indirect_inline_data ((struct bkey_ops) { \
|
||||
.key_invalid = bch2_indirect_inline_data_invalid, \
|
||||
.key_validate = bch2_indirect_inline_data_validate, \
|
||||
.val_to_text = bch2_indirect_inline_data_to_text, \
|
||||
.trigger = bch2_trigger_indirect_inline_data, \
|
||||
.min_val_size = 8, \
|
||||
|
@ -31,15 +31,14 @@ void bch2_snapshot_tree_to_text(struct printbuf *out, struct bch_fs *c,
|
||||
le32_to_cpu(t.v->root_snapshot));
|
||||
}
|
||||
|
||||
int bch2_snapshot_tree_invalid(struct bch_fs *c, struct bkey_s_c k,
|
||||
enum bch_validate_flags flags,
|
||||
struct printbuf *err)
|
||||
int bch2_snapshot_tree_validate(struct bch_fs *c, struct bkey_s_c k,
|
||||
enum bch_validate_flags flags)
|
||||
{
|
||||
int ret = 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,
|
||||
bkey_lt(k.k->p, POS(0, 1)),
|
||||
c, snapshot_tree_pos_bad,
|
||||
"bad pos");
|
||||
fsck_err:
|
||||
return ret;
|
||||
@ -225,55 +224,54 @@ void bch2_snapshot_to_text(struct printbuf *out, struct bch_fs *c,
|
||||
le32_to_cpu(s.v->skip[2]));
|
||||
}
|
||||
|
||||
int bch2_snapshot_invalid(struct bch_fs *c, struct bkey_s_c k,
|
||||
enum bch_validate_flags flags,
|
||||
struct printbuf *err)
|
||||
int bch2_snapshot_validate(struct bch_fs *c, struct bkey_s_c k,
|
||||
enum bch_validate_flags flags)
|
||||
{
|
||||
struct bkey_s_c_snapshot s;
|
||||
u32 i, id;
|
||||
int ret = 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_pos_bad,
|
||||
bkey_lt(k.k->p, POS(0, 1)),
|
||||
c, snapshot_pos_bad,
|
||||
"bad pos");
|
||||
|
||||
s = bkey_s_c_to_snapshot(k);
|
||||
|
||||
id = le32_to_cpu(s.v->parent);
|
||||
bkey_fsck_err_on(id && id <= k.k->p.offset, c, err,
|
||||
snapshot_parent_bad,
|
||||
bkey_fsck_err_on(id && id <= k.k->p.offset,
|
||||
c, snapshot_parent_bad,
|
||||
"bad parent node (%u <= %llu)",
|
||||
id, k.k->p.offset);
|
||||
|
||||
bkey_fsck_err_on(le32_to_cpu(s.v->children[0]) < le32_to_cpu(s.v->children[1]), c, err,
|
||||
snapshot_children_not_normalized,
|
||||
bkey_fsck_err_on(le32_to_cpu(s.v->children[0]) < le32_to_cpu(s.v->children[1]),
|
||||
c, snapshot_children_not_normalized,
|
||||
"children not normalized");
|
||||
|
||||
bkey_fsck_err_on(s.v->children[0] && s.v->children[0] == s.v->children[1], c, err,
|
||||
snapshot_child_duplicate,
|
||||
bkey_fsck_err_on(s.v->children[0] && s.v->children[0] == s.v->children[1],
|
||||
c, snapshot_child_duplicate,
|
||||
"duplicate child nodes");
|
||||
|
||||
for (i = 0; i < 2; i++) {
|
||||
id = le32_to_cpu(s.v->children[i]);
|
||||
|
||||
bkey_fsck_err_on(id >= k.k->p.offset, c, err,
|
||||
snapshot_child_bad,
|
||||
bkey_fsck_err_on(id >= k.k->p.offset,
|
||||
c, snapshot_child_bad,
|
||||
"bad child node (%u >= %llu)",
|
||||
id, k.k->p.offset);
|
||||
}
|
||||
|
||||
if (bkey_val_bytes(k.k) > offsetof(struct bch_snapshot, skip)) {
|
||||
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]), c, err,
|
||||
snapshot_skiplist_not_normalized,
|
||||
le32_to_cpu(s.v->skip[1]) > le32_to_cpu(s.v->skip[2]),
|
||||
c, snapshot_skiplist_not_normalized,
|
||||
"skiplist not normalized");
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(s.v->skip); i++) {
|
||||
id = le32_to_cpu(s.v->skip[i]);
|
||||
|
||||
bkey_fsck_err_on(id && id < le32_to_cpu(s.v->parent), c, err,
|
||||
snapshot_skiplist_bad,
|
||||
bkey_fsck_err_on(id && id < le32_to_cpu(s.v->parent),
|
||||
c, snapshot_skiplist_bad,
|
||||
"bad skiplist node %u", id);
|
||||
}
|
||||
}
|
||||
|
@ -5,11 +5,11 @@
|
||||
enum bch_validate_flags;
|
||||
|
||||
void bch2_snapshot_tree_to_text(struct printbuf *, struct bch_fs *, struct bkey_s_c);
|
||||
int bch2_snapshot_tree_invalid(struct bch_fs *, struct bkey_s_c,
|
||||
enum bch_validate_flags, struct printbuf *);
|
||||
int bch2_snapshot_tree_validate(struct bch_fs *, struct bkey_s_c,
|
||||
enum bch_validate_flags);
|
||||
|
||||
#define bch2_bkey_ops_snapshot_tree ((struct bkey_ops) { \
|
||||
.key_invalid = bch2_snapshot_tree_invalid, \
|
||||
.key_validate = bch2_snapshot_tree_validate, \
|
||||
.val_to_text = bch2_snapshot_tree_to_text, \
|
||||
.min_val_size = 8, \
|
||||
})
|
||||
@ -19,14 +19,13 @@ 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 *);
|
||||
|
||||
void bch2_snapshot_to_text(struct printbuf *, struct bch_fs *, struct bkey_s_c);
|
||||
int bch2_snapshot_invalid(struct bch_fs *, struct bkey_s_c,
|
||||
enum bch_validate_flags, struct printbuf *);
|
||||
int bch2_snapshot_validate(struct bch_fs *, struct bkey_s_c, enum bch_validate_flags);
|
||||
int bch2_mark_snapshot(struct btree_trans *, enum btree_id, unsigned,
|
||||
struct bkey_s_c, struct bkey_s,
|
||||
enum btree_iter_update_trigger_flags);
|
||||
|
||||
#define bch2_bkey_ops_snapshot ((struct bkey_ops) { \
|
||||
.key_invalid = bch2_snapshot_invalid, \
|
||||
.key_validate = bch2_snapshot_validate, \
|
||||
.val_to_text = bch2_snapshot_to_text, \
|
||||
.trigger = bch2_mark_snapshot, \
|
||||
.min_val_size = 24, \
|
||||
|
@ -207,23 +207,23 @@ int bch2_check_subvol_children(struct bch_fs *c)
|
||||
|
||||
/* Subvolumes: */
|
||||
|
||||
int bch2_subvolume_invalid(struct bch_fs *c, struct bkey_s_c k,
|
||||
enum bch_validate_flags flags, struct printbuf *err)
|
||||
int bch2_subvolume_validate(struct bch_fs *c, struct bkey_s_c k,
|
||||
enum bch_validate_flags flags)
|
||||
{
|
||||
struct bkey_s_c_subvolume subvol = bkey_s_c_to_subvolume(k);
|
||||
int ret = 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,
|
||||
bkey_gt(k.k->p, SUBVOL_POS_MAX),
|
||||
c, subvol_pos_bad,
|
||||
"invalid pos");
|
||||
|
||||
bkey_fsck_err_on(!subvol.v->snapshot, c, err,
|
||||
subvol_snapshot_bad,
|
||||
bkey_fsck_err_on(!subvol.v->snapshot,
|
||||
c, subvol_snapshot_bad,
|
||||
"invalid snapshot");
|
||||
|
||||
bkey_fsck_err_on(!subvol.v->inode, c, err,
|
||||
subvol_inode_bad,
|
||||
bkey_fsck_err_on(!subvol.v->inode,
|
||||
c, subvol_inode_bad,
|
||||
"invalid inode");
|
||||
fsck_err:
|
||||
return ret;
|
||||
|
@ -10,15 +10,14 @@ enum bch_validate_flags;
|
||||
int bch2_check_subvols(struct bch_fs *);
|
||||
int bch2_check_subvol_children(struct bch_fs *);
|
||||
|
||||
int bch2_subvolume_invalid(struct bch_fs *, struct bkey_s_c,
|
||||
enum bch_validate_flags, struct printbuf *);
|
||||
int bch2_subvolume_validate(struct bch_fs *, struct bkey_s_c, enum bch_validate_flags);
|
||||
void bch2_subvolume_to_text(struct printbuf *, struct bch_fs *, struct bkey_s_c);
|
||||
int bch2_subvolume_trigger(struct btree_trans *, enum btree_id, unsigned,
|
||||
struct bkey_s_c, struct bkey_s,
|
||||
enum btree_iter_update_trigger_flags);
|
||||
|
||||
#define bch2_bkey_ops_subvolume ((struct bkey_ops) { \
|
||||
.key_invalid = bch2_subvolume_invalid, \
|
||||
.key_validate = bch2_subvolume_validate, \
|
||||
.val_to_text = bch2_subvolume_to_text, \
|
||||
.trigger = bch2_subvolume_trigger, \
|
||||
.min_val_size = 16, \
|
||||
|
@ -70,17 +70,16 @@ const struct bch_hash_desc bch2_xattr_hash_desc = {
|
||||
.cmp_bkey = xattr_cmp_bkey,
|
||||
};
|
||||
|
||||
int bch2_xattr_invalid(struct bch_fs *c, struct bkey_s_c k,
|
||||
enum bch_validate_flags flags,
|
||||
struct printbuf *err)
|
||||
int bch2_xattr_validate(struct bch_fs *c, struct bkey_s_c k,
|
||||
enum bch_validate_flags flags)
|
||||
{
|
||||
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;
|
||||
|
||||
bkey_fsck_err_on(bkey_val_u64s(k.k) < val_u64s, c, err,
|
||||
xattr_val_size_too_small,
|
||||
bkey_fsck_err_on(bkey_val_u64s(k.k) < val_u64s,
|
||||
c, xattr_val_size_too_small,
|
||||
"value too small (%zu < %u)",
|
||||
bkey_val_u64s(k.k), val_u64s);
|
||||
|
||||
@ -88,17 +87,17 @@ int bch2_xattr_invalid(struct bch_fs *c, struct bkey_s_c k,
|
||||
val_u64s = xattr_val_u64s(xattr.v->x_name_len,
|
||||
le16_to_cpu(xattr.v->x_val_len) + 4);
|
||||
|
||||
bkey_fsck_err_on(bkey_val_u64s(k.k) > val_u64s, c, err,
|
||||
xattr_val_size_too_big,
|
||||
bkey_fsck_err_on(bkey_val_u64s(k.k) > val_u64s,
|
||||
c, xattr_val_size_too_big,
|
||||
"value too big (%zu > %u)",
|
||||
bkey_val_u64s(k.k), val_u64s);
|
||||
|
||||
bkey_fsck_err_on(!bch2_xattr_type_to_handler(xattr.v->x_type), c, err,
|
||||
xattr_invalid_type,
|
||||
bkey_fsck_err_on(!bch2_xattr_type_to_handler(xattr.v->x_type),
|
||||
c, xattr_invalid_type,
|
||||
"invalid type (%u)", xattr.v->x_type);
|
||||
|
||||
bkey_fsck_err_on(memchr(xattr.v->x_name, '\0', xattr.v->x_name_len), c, err,
|
||||
xattr_name_invalid_chars,
|
||||
bkey_fsck_err_on(memchr(xattr.v->x_name, '\0', xattr.v->x_name_len),
|
||||
c, xattr_name_invalid_chars,
|
||||
"xattr name has invalid characters");
|
||||
fsck_err:
|
||||
return ret;
|
||||
|
@ -6,12 +6,11 @@
|
||||
|
||||
extern const struct bch_hash_desc bch2_xattr_hash_desc;
|
||||
|
||||
int bch2_xattr_invalid(struct bch_fs *, struct bkey_s_c,
|
||||
enum bch_validate_flags, struct printbuf *);
|
||||
int bch2_xattr_validate(struct bch_fs *, struct bkey_s_c, enum bch_validate_flags);
|
||||
void bch2_xattr_to_text(struct printbuf *, struct bch_fs *, struct bkey_s_c);
|
||||
|
||||
#define bch2_bkey_ops_xattr ((struct bkey_ops) { \
|
||||
.key_invalid = bch2_xattr_invalid, \
|
||||
.key_validate = bch2_xattr_validate, \
|
||||
.val_to_text = bch2_xattr_to_text, \
|
||||
.min_val_size = 8, \
|
||||
})
|
||||
|
Loading…
Reference in New Issue
Block a user