bcachefs fixes for 6.11-rc4
- New on disk format version, bcachefs_metadata_version_disk_accounting_inum This adds one more disk accounting counter, which counts disk usage and number of extents per inode number. This lets us track fragmentation, for implementing defragmentation later, and it also counts disk usage per inode in all snapshots, which will be a useful thing to expose to users. - One performance issue we've observed is threads spinning when they should be waiting for dirty keys in the key cache to be flushed by journal reclaim, so we now have hysteresis for the waiting thread, as well as improving the tracepoint and a new time_stat, for tracking time blocked waiting on key cache flushing. And, various assorted smaller fixes. -----BEGIN PGP SIGNATURE----- iQIzBAABCgAdFiEEKnAFLkS8Qha+jvQrE6szbY3KbnYFAma/9QkACgkQE6szbY3K bnYcBw/+LBSZ415gWSjPktdecf5rc6K4KxETxAxV0f0KesYzxqAtQzN0SCDvKt65 3aALU03wM8vWITiLS38/ckT+j6S2BpXcOxdu/OC0nRYQEUg9ZLvqEG5lQ3a/LliV Q64N33qsSr6QaKszFllLYcN4tGduKg8HoMlHn6+vJ7HNPjdfv0HHERSUsc7K84/w jkRtDE2NxsRJZKMEvIFp8hd5KXUR5zyBz/kc4P0WliLXpSyJLITzhKw1JV7ikKVD 0mO2bJ/0i7wPIabAD2HJahvbC7fl+2fkYFxUJ2XnvMTgU/+QyeGHEufbcbVrVSp0 BpzBTmSMFbGXBkbQBruFX5rJetzXeBqdYf0Yfavd4KDhGvYlSfDZQUapXT1QKC2q aHSB/s+2r7Crr/MBJyjbeFgXFTNGvI5yerlbdp2yj1kxjYJHHaKrp6h7n6XXk21W /mGF5tkIMkFTv98rQnIaky4neJzOPsLTTgxeR8zEudCgMaVUqEcaMdIFvARDjY/3 n52VR0zl3olV3vu7LgHaHfgH6lfaMV0sHPaGNYGL0YL+bCJD+lYM8a6l9aaks8vk md7+mFcOS4FUdDdS8MEKIN/k/gkEOC/EpmI864i9rIl0SiNXNy7FPTDKON8b+Ury 5omBMUQMEe9Q/pgKGXfpJWFynhSPEVf4y1DIOsrXk/jeBqenFyo= =BPGT -----END PGP SIGNATURE----- Merge tag 'bcachefs-2024-08-16' of git://evilpiepirate.org/bcachefs Pull bcachefs fixes from Kent OverstreetL - New on disk format version, bcachefs_metadata_version_disk_accounting_inum This adds one more disk accounting counter, which counts disk usage and number of extents per inode number. This lets us track fragmentation, for implementing defragmentation later, and it also counts disk usage per inode in all snapshots, which will be a useful thing to expose to users. - One performance issue we've observed is threads spinning when they should be waiting for dirty keys in the key cache to be flushed by journal reclaim, so we now have hysteresis for the waiting thread, as well as improving the tracepoint and a new time_stat, for tracking time blocked waiting on key cache flushing. ... and various assorted smaller fixes. * tag 'bcachefs-2024-08-16' of git://evilpiepirate.org/bcachefs: bcachefs: Fix locking in __bch2_trans_mark_dev_sb() bcachefs: fix incorrect i_state usage bcachefs: avoid overflowing LRU_TIME_BITS for cached data lru bcachefs: Fix forgetting to pass trans to fsck_err() bcachefs: Increase size of cuckoo hash table on too many rehashes bcachefs: bcachefs_metadata_version_disk_accounting_inum bcachefs: Kill __bch2_accounting_mem_mod() bcachefs: Make bkey_fsck_err() a wrapper around fsck_err() bcachefs: Fix warning in __bch2_fsck_err() for trans not passed in bcachefs: Add a time_stat for blocked on key cache flush bcachefs: Improve trans_blocked_journal_reclaim tracepoint bcachefs: Add hysteresis to waiting on btree key cache flush lib/generic-radix-tree.c: Fix rare race in __genradix_ptr_alloc() bcachefs: Convert for_each_btree_node() to lockrestart_do() bcachefs: Add missing downgrade table entry bcachefs: disk accounting: ignore unknown types bcachefs: bch2_accounting_invalid() fixup bcachefs: Fix bch2_trigger_alloc when upgrading from old versions bcachefs: delete faulty fastpath in bch2_btree_path_traverse_cached()
This commit is contained in:
commit
b718175853
@ -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:
|
||||
@ -829,7 +824,19 @@ int bch2_trigger_alloc(struct btree_trans *trans,
|
||||
|
||||
struct bch_alloc_v4 old_a_convert;
|
||||
const struct bch_alloc_v4 *old_a = bch2_alloc_to_v4(old, &old_a_convert);
|
||||
struct bch_alloc_v4 *new_a = bkey_s_to_alloc_v4(new).v;
|
||||
|
||||
struct bch_alloc_v4 *new_a;
|
||||
if (likely(new.k->type == KEY_TYPE_alloc_v4)) {
|
||||
new_a = bkey_s_to_alloc_v4(new).v;
|
||||
} else {
|
||||
BUG_ON(!(flags & BTREE_TRIGGER_gc));
|
||||
|
||||
struct bkey_i_alloc_v4 *new_ka = bch2_alloc_to_v4_mut_inlined(trans, new.s_c);
|
||||
ret = PTR_ERR_OR_ZERO(new_ka);
|
||||
if (unlikely(ret))
|
||||
goto err;
|
||||
new_a = &new_ka->v;
|
||||
}
|
||||
|
||||
if (flags & BTREE_TRIGGER_transactional) {
|
||||
alloc_data_type_set(new_a, new_a->data_type);
|
||||
|
@ -150,7 +150,9 @@ static inline void alloc_data_type_set(struct bch_alloc_v4 *a, enum bch_data_typ
|
||||
|
||||
static inline u64 alloc_lru_idx_read(struct bch_alloc_v4 a)
|
||||
{
|
||||
return a.data_type == BCH_DATA_cached ? a.io_time[READ] : 0;
|
||||
return a.data_type == BCH_DATA_cached
|
||||
? a.io_time[READ] & LRU_TIME_MAX
|
||||
: 0;
|
||||
}
|
||||
|
||||
#define DATA_TYPES_MOVABLE \
|
||||
@ -240,52 +242,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;
|
||||
@ -763,27 +761,22 @@ static int bch2_get_btree_in_memory_pos(struct btree_trans *trans,
|
||||
btree < BTREE_ID_NR && !ret;
|
||||
btree++) {
|
||||
unsigned depth = (BIT_ULL(btree) & btree_leaf_mask) ? 0 : 1;
|
||||
struct btree_iter iter;
|
||||
struct btree *b;
|
||||
|
||||
if (!(BIT_ULL(btree) & btree_leaf_mask) &&
|
||||
!(BIT_ULL(btree) & btree_interior_mask))
|
||||
continue;
|
||||
|
||||
bch2_trans_begin(trans);
|
||||
|
||||
__for_each_btree_node(trans, iter, btree,
|
||||
ret = __for_each_btree_node(trans, iter, btree,
|
||||
btree == start.btree ? start.pos : POS_MIN,
|
||||
0, depth, BTREE_ITER_prefetch, b, ret) {
|
||||
0, depth, BTREE_ITER_prefetch, b, ({
|
||||
mem_may_pin -= btree_buf_bytes(b);
|
||||
if (mem_may_pin <= 0) {
|
||||
c->btree_cache.pinned_nodes_end = *end =
|
||||
BBPOS(btree, b->key.k.p);
|
||||
bch2_trans_iter_exit(trans, &iter);
|
||||
return 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
bch2_trans_iter_exit(trans, &iter);
|
||||
0;
|
||||
}));
|
||||
}
|
||||
|
||||
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, \
|
||||
|
@ -447,6 +447,7 @@ BCH_DEBUG_PARAMS_DEBUG()
|
||||
x(blocked_journal_low_on_space) \
|
||||
x(blocked_journal_low_on_pin) \
|
||||
x(blocked_journal_max_in_flight) \
|
||||
x(blocked_key_cache_flush) \
|
||||
x(blocked_allocate) \
|
||||
x(blocked_allocate_open_bucket) \
|
||||
x(blocked_write_buffer_full) \
|
||||
|
@ -676,7 +676,8 @@ struct bch_sb_field_ext {
|
||||
x(mi_btree_bitmap, BCH_VERSION(1, 7)) \
|
||||
x(bucket_stripe_sectors, BCH_VERSION(1, 8)) \
|
||||
x(disk_accounting_v2, BCH_VERSION(1, 9)) \
|
||||
x(disk_accounting_v3, BCH_VERSION(1, 10))
|
||||
x(disk_accounting_v3, BCH_VERSION(1, 10)) \
|
||||
x(disk_accounting_inum, BCH_VERSION(1, 11))
|
||||
|
||||
enum bcachefs_metadata_version {
|
||||
bcachefs_metadata_version_min = 9,
|
||||
|
@ -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;
|
||||
}
|
||||
@ -98,9 +98,9 @@ static void key_type_inline_data_to_text(struct printbuf *out, struct bch_fs *c,
|
||||
datalen, min(datalen, 32U), d.v->data);
|
||||
}
|
||||
|
||||
#define bch2_bkey_ops_inline_data ((struct bkey_ops) { \
|
||||
.key_invalid = key_type_inline_data_invalid, \
|
||||
.val_to_text = key_type_inline_data_to_text, \
|
||||
#define bch2_bkey_ops_inline_data ((struct bkey_ops) { \
|
||||
.key_validate = key_type_inline_data_validate, \
|
||||
.val_to_text = key_type_inline_data_to_text, \
|
||||
})
|
||||
|
||||
static bool key_type_set_merge(struct bch_fs *c, struct bkey_s l, struct bkey_s_c r)
|
||||
@ -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,
|
||||
enum btree_node_type type,
|
||||
enum bch_validate_flags flags,
|
||||
struct printbuf *err)
|
||||
int __bch2_bkey_validate(struct bch_fs *c, struct bkey_s_c k,
|
||||
enum btree_node_type type,
|
||||
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 *);
|
||||
|
@ -741,12 +741,9 @@ fsck_err:
|
||||
|
||||
static int bch2_mark_superblocks(struct bch_fs *c)
|
||||
{
|
||||
mutex_lock(&c->sb_lock);
|
||||
gc_pos_set(c, gc_phase(GC_PHASE_sb));
|
||||
|
||||
int ret = bch2_trans_mark_dev_sbs_flags(c, BTREE_TRIGGER_gc);
|
||||
mutex_unlock(&c->sb_lock);
|
||||
return ret;
|
||||
return bch2_trans_mark_dev_sbs_flags(c, BTREE_TRIGGER_gc);
|
||||
}
|
||||
|
||||
static void bch2_gc_free(struct bch_fs *c)
|
||||
|
@ -836,14 +836,13 @@ fsck_err:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int bset_key_invalid(struct bch_fs *c, struct btree *b,
|
||||
struct bkey_s_c k,
|
||||
bool updated_range, int rw,
|
||||
struct printbuf *err)
|
||||
static int bset_key_validate(struct bch_fs *c, struct btree *b,
|
||||
struct bkey_s_c k,
|
||||
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);
|
||||
@ -1767,6 +1744,8 @@ static int __bch2_btree_root_read(struct btree_trans *trans, enum btree_id id,
|
||||
|
||||
set_btree_node_read_in_flight(b);
|
||||
|
||||
/* we can't pass the trans to read_done() for fsck errors, so it must be unlocked */
|
||||
bch2_trans_unlock(trans);
|
||||
bch2_btree_node_read(trans, b, true);
|
||||
|
||||
if (btree_node_read_error(b)) {
|
||||
@ -1952,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);
|
||||
|
@ -1900,6 +1900,7 @@ err:
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* Only kept for -tools */
|
||||
struct btree *bch2_btree_iter_peek_node_and_restart(struct btree_iter *iter)
|
||||
{
|
||||
struct btree *b;
|
||||
|
@ -600,23 +600,35 @@ void bch2_trans_srcu_unlock(struct btree_trans *);
|
||||
|
||||
u32 bch2_trans_begin(struct btree_trans *);
|
||||
|
||||
/*
|
||||
* XXX
|
||||
* this does not handle transaction restarts from bch2_btree_iter_next_node()
|
||||
* correctly
|
||||
*/
|
||||
#define __for_each_btree_node(_trans, _iter, _btree_id, _start, \
|
||||
_locks_want, _depth, _flags, _b, _ret) \
|
||||
for (bch2_trans_node_iter_init((_trans), &(_iter), (_btree_id), \
|
||||
_start, _locks_want, _depth, _flags); \
|
||||
(_b) = bch2_btree_iter_peek_node_and_restart(&(_iter)), \
|
||||
!((_ret) = PTR_ERR_OR_ZERO(_b)) && (_b); \
|
||||
(_b) = bch2_btree_iter_next_node(&(_iter)))
|
||||
#define __for_each_btree_node(_trans, _iter, _btree_id, _start, \
|
||||
_locks_want, _depth, _flags, _b, _do) \
|
||||
({ \
|
||||
bch2_trans_begin((_trans)); \
|
||||
\
|
||||
struct btree_iter _iter; \
|
||||
bch2_trans_node_iter_init((_trans), &_iter, (_btree_id), \
|
||||
_start, _locks_want, _depth, _flags); \
|
||||
int _ret3 = 0; \
|
||||
do { \
|
||||
_ret3 = lockrestart_do((_trans), ({ \
|
||||
struct btree *_b = bch2_btree_iter_peek_node(&_iter); \
|
||||
if (!_b) \
|
||||
break; \
|
||||
\
|
||||
PTR_ERR_OR_ZERO(_b) ?: (_do); \
|
||||
})) ?: \
|
||||
lockrestart_do((_trans), \
|
||||
PTR_ERR_OR_ZERO(bch2_btree_iter_next_node(&_iter))); \
|
||||
} while (!_ret3); \
|
||||
\
|
||||
bch2_trans_iter_exit((_trans), &(_iter)); \
|
||||
_ret3; \
|
||||
})
|
||||
|
||||
#define for_each_btree_node(_trans, _iter, _btree_id, _start, \
|
||||
_flags, _b, _ret) \
|
||||
__for_each_btree_node(_trans, _iter, _btree_id, _start, \
|
||||
0, 0, _flags, _b, _ret)
|
||||
_flags, _b, _do) \
|
||||
__for_each_btree_node(_trans, _iter, _btree_id, _start, \
|
||||
0, 0, _flags, _b, _do)
|
||||
|
||||
static inline struct bkey_s_c bch2_btree_iter_peek_prev_type(struct btree_iter *iter,
|
||||
unsigned flags)
|
||||
|
@ -497,11 +497,6 @@ int bch2_btree_path_traverse_cached(struct btree_trans *trans, struct btree_path
|
||||
|
||||
path->l[1].b = NULL;
|
||||
|
||||
if (bch2_btree_node_relock_notrace(trans, path, 0)) {
|
||||
path->uptodate = BTREE_ITER_UPTODATE;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ret;
|
||||
do {
|
||||
ret = btree_path_traverse_cached_fast(trans, path);
|
||||
|
@ -11,13 +11,27 @@ static inline size_t bch2_nr_btree_keys_need_flush(struct bch_fs *c)
|
||||
return max_t(ssize_t, 0, nr_dirty - max_dirty);
|
||||
}
|
||||
|
||||
static inline bool bch2_btree_key_cache_must_wait(struct bch_fs *c)
|
||||
static inline ssize_t __bch2_btree_key_cache_must_wait(struct bch_fs *c)
|
||||
{
|
||||
size_t nr_dirty = atomic_long_read(&c->btree_key_cache.nr_dirty);
|
||||
size_t nr_keys = atomic_long_read(&c->btree_key_cache.nr_keys);
|
||||
size_t max_dirty = 4096 + (nr_keys * 3) / 4;
|
||||
|
||||
return nr_dirty > max_dirty;
|
||||
return nr_dirty - max_dirty;
|
||||
}
|
||||
|
||||
static inline bool bch2_btree_key_cache_must_wait(struct bch_fs *c)
|
||||
{
|
||||
return __bch2_btree_key_cache_must_wait(c) > 0;
|
||||
}
|
||||
|
||||
static inline bool bch2_btree_key_cache_wait_done(struct bch_fs *c)
|
||||
{
|
||||
size_t nr_dirty = atomic_long_read(&c->btree_key_cache.nr_dirty);
|
||||
size_t nr_keys = atomic_long_read(&c->btree_key_cache.nr_keys);
|
||||
size_t max_dirty = 2048 + (nr_keys * 5) / 8;
|
||||
|
||||
return nr_dirty <= max_dirty;
|
||||
}
|
||||
|
||||
int bch2_btree_key_cache_journal_flush(struct journal *,
|
||||
|
@ -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)
|
||||
|
@ -712,7 +712,7 @@ bch2_trans_commit_write_locked(struct btree_trans *trans, unsigned flags,
|
||||
a->k.version = journal_pos_to_bversion(&trans->journal_res,
|
||||
(u64 *) entry - (u64 *) trans->journal_entries);
|
||||
BUG_ON(bversion_zero(a->k.version));
|
||||
ret = bch2_accounting_mem_mod_locked(trans, accounting_i_to_s_c(a), false);
|
||||
ret = bch2_accounting_mem_mod_locked(trans, accounting_i_to_s_c(a), false, false);
|
||||
if (ret)
|
||||
goto revert_fs_usage;
|
||||
}
|
||||
@ -798,7 +798,7 @@ revert_fs_usage:
|
||||
struct bkey_s_accounting a = bkey_i_to_s_accounting(entry2->start);
|
||||
|
||||
bch2_accounting_neg(a);
|
||||
bch2_accounting_mem_mod_locked(trans, a.c, false);
|
||||
bch2_accounting_mem_mod_locked(trans, a.c, false, false);
|
||||
bch2_accounting_neg(a);
|
||||
}
|
||||
percpu_up_read(&c->mark_lock);
|
||||
@ -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)
|
||||
{
|
||||
@ -927,7 +883,7 @@ static inline int do_bch2_trans_commit(struct btree_trans *trans, unsigned flags
|
||||
static int journal_reclaim_wait_done(struct bch_fs *c)
|
||||
{
|
||||
int ret = bch2_journal_error(&c->journal) ?:
|
||||
!bch2_btree_key_cache_must_wait(c);
|
||||
bch2_btree_key_cache_wait_done(c);
|
||||
|
||||
if (!ret)
|
||||
journal_reclaim_kick(&c->journal);
|
||||
@ -973,9 +929,13 @@ int bch2_trans_commit_error(struct btree_trans *trans, unsigned flags,
|
||||
bch2_trans_unlock(trans);
|
||||
|
||||
trace_and_count(c, trans_blocked_journal_reclaim, trans, trace_ip);
|
||||
track_event_change(&c->times[BCH_TIME_blocked_key_cache_flush], true);
|
||||
|
||||
wait_event_freezable(c->journal.reclaim_wait,
|
||||
(ret = journal_reclaim_wait_done(c)));
|
||||
|
||||
track_event_change(&c->times[BCH_TIME_blocked_key_cache_flush], false);
|
||||
|
||||
if (ret < 0)
|
||||
break;
|
||||
|
||||
@ -1060,20 +1020,19 @@ 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;
|
||||
@ -1084,13 +1043,14 @@ 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,
|
||||
bcachefs_metadata_version_current,
|
||||
CPU_BIG_ENDIAN, invalid_flags)))
|
||||
ret = bch2_trans_commit_journal_entry_invalid(trans, i);
|
||||
|
||||
if (ret)
|
||||
ret = bch2_journal_entry_validate(c, NULL, i,
|
||||
bcachefs_metadata_version_current,
|
||||
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))) {
|
||||
|
@ -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();
|
||||
}
|
||||
|
||||
|
@ -810,6 +810,20 @@ static int __trigger_extent(struct btree_trans *trans,
|
||||
ret = bch2_disk_accounting_mod(trans, &acc_btree_key, &replicas_sectors, 1, gc);
|
||||
if (ret)
|
||||
return ret;
|
||||
} else {
|
||||
bool insert = !(flags & BTREE_TRIGGER_overwrite);
|
||||
struct disk_accounting_pos acc_inum_key = {
|
||||
.type = BCH_DISK_ACCOUNTING_inum,
|
||||
.inum.inum = k.k->p.inode,
|
||||
};
|
||||
s64 v[3] = {
|
||||
insert ? 1 : -1,
|
||||
insert ? k.k->size : -((s64) k.k->size),
|
||||
replicas_sectors,
|
||||
};
|
||||
ret = bch2_disk_accounting_mod(trans, &acc_inum_key, v, ARRAY_SIZE(v), gc);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (bch2_bkey_rebalance_opts(k)) {
|
||||
@ -901,7 +915,6 @@ static int __bch2_trans_mark_metadata_bucket(struct btree_trans *trans,
|
||||
enum bch_data_type type,
|
||||
unsigned sectors)
|
||||
{
|
||||
struct bch_fs *c = trans->c;
|
||||
struct btree_iter iter;
|
||||
int ret = 0;
|
||||
|
||||
@ -911,7 +924,7 @@ static int __bch2_trans_mark_metadata_bucket(struct btree_trans *trans,
|
||||
return PTR_ERR(a);
|
||||
|
||||
if (a->v.data_type && type && a->v.data_type != type) {
|
||||
bch2_fsck_err(c, FSCK_CAN_IGNORE|FSCK_NEED_FSCK,
|
||||
bch2_fsck_err(trans, FSCK_CAN_IGNORE|FSCK_NEED_FSCK,
|
||||
bucket_metadata_type_mismatch,
|
||||
"bucket %llu:%llu gen %u different types of data in same bucket: %s, %s\n"
|
||||
"while marking %s",
|
||||
@ -1032,13 +1045,18 @@ static int bch2_trans_mark_metadata_sectors(struct btree_trans *trans,
|
||||
static int __bch2_trans_mark_dev_sb(struct btree_trans *trans, struct bch_dev *ca,
|
||||
enum btree_iter_update_trigger_flags flags)
|
||||
{
|
||||
struct bch_sb_layout *layout = &ca->disk_sb.sb->layout;
|
||||
struct bch_fs *c = trans->c;
|
||||
|
||||
mutex_lock(&c->sb_lock);
|
||||
struct bch_sb_layout layout = ca->disk_sb.sb->layout;
|
||||
mutex_unlock(&c->sb_lock);
|
||||
|
||||
u64 bucket = 0;
|
||||
unsigned i, bucket_sectors = 0;
|
||||
int ret;
|
||||
|
||||
for (i = 0; i < layout->nr_superblocks; i++) {
|
||||
u64 offset = le64_to_cpu(layout->sb_offset[i]);
|
||||
for (i = 0; i < layout.nr_superblocks; i++) {
|
||||
u64 offset = le64_to_cpu(layout.sb_offset[i]);
|
||||
|
||||
if (offset == BCH_SB_SECTOR) {
|
||||
ret = bch2_trans_mark_metadata_sectors(trans, ca,
|
||||
@ -1049,7 +1067,7 @@ static int __bch2_trans_mark_dev_sb(struct btree_trans *trans, struct bch_dev *c
|
||||
}
|
||||
|
||||
ret = bch2_trans_mark_metadata_sectors(trans, ca, offset,
|
||||
offset + (1 << layout->sb_max_size_bits),
|
||||
offset + (1 << layout.sb_max_size_bits),
|
||||
BCH_DATA_sb, &bucket, &bucket_sectors, flags);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
@ -93,7 +93,7 @@ int bch2_set_bucket_needs_journal_commit(struct buckets_waiting_for_journal *b,
|
||||
.dev_bucket = (u64) dev << 56 | bucket,
|
||||
.journal_seq = journal_seq,
|
||||
};
|
||||
size_t i, size, new_bits, nr_elements = 1, nr_rehashes = 0;
|
||||
size_t i, size, new_bits, nr_elements = 1, nr_rehashes = 0, nr_rehashes_this_size = 0;
|
||||
int ret = 0;
|
||||
|
||||
mutex_lock(&b->lock);
|
||||
@ -106,7 +106,7 @@ int bch2_set_bucket_needs_journal_commit(struct buckets_waiting_for_journal *b,
|
||||
for (i = 0; i < size; i++)
|
||||
nr_elements += t->d[i].journal_seq > flushed_seq;
|
||||
|
||||
new_bits = t->bits + (nr_elements * 3 > size);
|
||||
new_bits = ilog2(roundup_pow_of_two(nr_elements * 3));
|
||||
|
||||
n = kvmalloc(sizeof(*n) + (sizeof(n->d[0]) << new_bits), GFP_KERNEL);
|
||||
if (!n) {
|
||||
@ -115,7 +115,14 @@ int bch2_set_bucket_needs_journal_commit(struct buckets_waiting_for_journal *b,
|
||||
}
|
||||
|
||||
retry_rehash:
|
||||
if (nr_rehashes_this_size == 3) {
|
||||
new_bits++;
|
||||
nr_rehashes_this_size = 0;
|
||||
}
|
||||
|
||||
nr_rehashes++;
|
||||
nr_rehashes_this_size++;
|
||||
|
||||
bucket_table_init(n, new_bits);
|
||||
|
||||
tmp = new;
|
||||
|
@ -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;
|
||||
|
||||
|
@ -397,47 +397,27 @@ static ssize_t bch2_read_btree_formats(struct file *file, char __user *buf,
|
||||
size_t size, loff_t *ppos)
|
||||
{
|
||||
struct dump_iter *i = file->private_data;
|
||||
struct btree_trans *trans;
|
||||
struct btree_iter iter;
|
||||
struct btree *b;
|
||||
ssize_t ret;
|
||||
|
||||
i->ubuf = buf;
|
||||
i->size = size;
|
||||
i->ret = 0;
|
||||
|
||||
ret = flush_buf(i);
|
||||
ssize_t ret = flush_buf(i);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (bpos_eq(SPOS_MAX, i->from))
|
||||
return i->ret;
|
||||
|
||||
trans = bch2_trans_get(i->c);
|
||||
retry:
|
||||
bch2_trans_begin(trans);
|
||||
return bch2_trans_run(i->c,
|
||||
for_each_btree_node(trans, iter, i->id, i->from, 0, b, ({
|
||||
bch2_btree_node_to_text(&i->buf, i->c, b);
|
||||
i->from = !bpos_eq(SPOS_MAX, b->key.k.p)
|
||||
? bpos_successor(b->key.k.p)
|
||||
: b->key.k.p;
|
||||
|
||||
for_each_btree_node(trans, iter, i->id, i->from, 0, b, ret) {
|
||||
bch2_btree_node_to_text(&i->buf, i->c, b);
|
||||
i->from = !bpos_eq(SPOS_MAX, b->key.k.p)
|
||||
? bpos_successor(b->key.k.p)
|
||||
: b->key.k.p;
|
||||
|
||||
ret = drop_locks_do(trans, flush_buf(i));
|
||||
if (ret)
|
||||
break;
|
||||
}
|
||||
bch2_trans_iter_exit(trans, &iter);
|
||||
|
||||
if (bch2_err_matches(ret, BCH_ERR_transaction_restart))
|
||||
goto retry;
|
||||
|
||||
bch2_trans_put(trans);
|
||||
|
||||
if (!ret)
|
||||
ret = flush_buf(i);
|
||||
|
||||
return ret ?: i->ret;
|
||||
drop_locks_do(trans, flush_buf(i));
|
||||
}))) ?: i->ret;
|
||||
}
|
||||
|
||||
static const struct file_operations btree_format_debug_ops = {
|
||||
|
@ -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,
|
||||
bkey_fsck_err_on(acc_k.replicas.devs[i] >= acc_k.replicas.devs[i + 1],
|
||||
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;
|
||||
@ -528,6 +527,9 @@ int bch2_gc_accounting_done(struct bch_fs *c)
|
||||
struct disk_accounting_pos acc_k;
|
||||
bpos_to_disk_accounting_pos(&acc_k, e->pos);
|
||||
|
||||
if (acc_k.type >= BCH_DISK_ACCOUNTING_TYPE_NR)
|
||||
continue;
|
||||
|
||||
u64 src_v[BCH_ACCOUNTING_MAX_COUNTERS];
|
||||
u64 dst_v[BCH_ACCOUNTING_MAX_COUNTERS];
|
||||
|
||||
@ -564,7 +566,7 @@ int bch2_gc_accounting_done(struct bch_fs *c)
|
||||
struct { __BKEY_PADDED(k, BCH_ACCOUNTING_MAX_COUNTERS); } k_i;
|
||||
|
||||
accounting_key_init(&k_i.k, &acc_k, src_v, nr);
|
||||
bch2_accounting_mem_mod_locked(trans, bkey_i_to_s_c_accounting(&k_i.k), false);
|
||||
bch2_accounting_mem_mod_locked(trans, bkey_i_to_s_c_accounting(&k_i.k), false, false);
|
||||
|
||||
preempt_disable();
|
||||
struct bch_fs_usage_base *dst = this_cpu_ptr(c->usage);
|
||||
@ -593,7 +595,7 @@ static int accounting_read_key(struct btree_trans *trans, struct bkey_s_c k)
|
||||
return 0;
|
||||
|
||||
percpu_down_read(&c->mark_lock);
|
||||
int ret = __bch2_accounting_mem_mod(c, bkey_s_c_to_accounting(k), false);
|
||||
int ret = bch2_accounting_mem_mod_locked(trans, bkey_s_c_to_accounting(k), false, true);
|
||||
percpu_up_read(&c->mark_lock);
|
||||
|
||||
if (bch2_accounting_key_is_zero(bkey_s_c_to_accounting(k)) &&
|
||||
@ -760,6 +762,15 @@ void bch2_verify_accounting_clean(struct bch_fs *c)
|
||||
struct bkey_s_c_accounting a = bkey_s_c_to_accounting(k);
|
||||
unsigned nr = bch2_accounting_counters(k.k);
|
||||
|
||||
struct disk_accounting_pos acc_k;
|
||||
bpos_to_disk_accounting_pos(&acc_k, k.k->p);
|
||||
|
||||
if (acc_k.type >= BCH_DISK_ACCOUNTING_TYPE_NR)
|
||||
continue;
|
||||
|
||||
if (acc_k.type == BCH_DISK_ACCOUNTING_inum)
|
||||
continue;
|
||||
|
||||
bch2_accounting_mem_read(c, k.k->p, v, nr);
|
||||
|
||||
if (memcmp(a.v->d, v, nr * sizeof(u64))) {
|
||||
@ -775,9 +786,6 @@ void bch2_verify_accounting_clean(struct bch_fs *c)
|
||||
mismatch = true;
|
||||
}
|
||||
|
||||
struct disk_accounting_pos acc_k;
|
||||
bpos_to_disk_accounting_pos(&acc_k, a.k->p);
|
||||
|
||||
switch (acc_k.type) {
|
||||
case BCH_DISK_ACCOUNTING_persistent_reserved:
|
||||
base.reserved += acc_k.persistent_reserved.nr_replicas * a.v->d[0];
|
||||
|
@ -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,8 +106,40 @@ static inline int accounting_pos_cmp(const void *_l, const void *_r)
|
||||
int bch2_accounting_mem_insert(struct bch_fs *, struct bkey_s_c_accounting, bool);
|
||||
void bch2_accounting_mem_gc(struct bch_fs *);
|
||||
|
||||
static inline int __bch2_accounting_mem_mod(struct bch_fs *c, struct bkey_s_c_accounting a, bool gc)
|
||||
/*
|
||||
* Update in memory counters so they match the btree update we're doing; called
|
||||
* from transaction commit path
|
||||
*/
|
||||
static inline int bch2_accounting_mem_mod_locked(struct btree_trans *trans, struct bkey_s_c_accounting a, bool gc, bool read)
|
||||
{
|
||||
struct bch_fs *c = trans->c;
|
||||
struct disk_accounting_pos acc_k;
|
||||
bpos_to_disk_accounting_pos(&acc_k, a.k->p);
|
||||
|
||||
if (acc_k.type == BCH_DISK_ACCOUNTING_inum)
|
||||
return 0;
|
||||
|
||||
if (!gc && !read) {
|
||||
switch (acc_k.type) {
|
||||
case BCH_DISK_ACCOUNTING_persistent_reserved:
|
||||
trans->fs_usage_delta.reserved += acc_k.persistent_reserved.nr_replicas * a.v->d[0];
|
||||
break;
|
||||
case BCH_DISK_ACCOUNTING_replicas:
|
||||
fs_usage_data_type_to_base(&trans->fs_usage_delta, acc_k.replicas.data_type, a.v->d[0]);
|
||||
break;
|
||||
case BCH_DISK_ACCOUNTING_dev_data_type:
|
||||
rcu_read_lock();
|
||||
struct bch_dev *ca = bch2_dev_rcu(c, acc_k.dev_data_type.dev);
|
||||
if (ca) {
|
||||
this_cpu_add(ca->usage->d[acc_k.dev_data_type.data_type].buckets, a.v->d[0]);
|
||||
this_cpu_add(ca->usage->d[acc_k.dev_data_type.data_type].sectors, a.v->d[1]);
|
||||
this_cpu_add(ca->usage->d[acc_k.dev_data_type.data_type].fragmented, a.v->d[2]);
|
||||
}
|
||||
rcu_read_unlock();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
struct bch_accounting_mem *acc = &c->accounting;
|
||||
unsigned idx;
|
||||
|
||||
@ -130,45 +161,10 @@ static inline int __bch2_accounting_mem_mod(struct bch_fs *c, struct bkey_s_c_ac
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Update in memory counters so they match the btree update we're doing; called
|
||||
* from transaction commit path
|
||||
*/
|
||||
static inline int bch2_accounting_mem_mod_locked(struct btree_trans *trans, struct bkey_s_c_accounting a, bool gc)
|
||||
{
|
||||
struct bch_fs *c = trans->c;
|
||||
|
||||
if (!gc) {
|
||||
struct disk_accounting_pos acc_k;
|
||||
bpos_to_disk_accounting_pos(&acc_k, a.k->p);
|
||||
|
||||
switch (acc_k.type) {
|
||||
case BCH_DISK_ACCOUNTING_persistent_reserved:
|
||||
trans->fs_usage_delta.reserved += acc_k.persistent_reserved.nr_replicas * a.v->d[0];
|
||||
break;
|
||||
case BCH_DISK_ACCOUNTING_replicas:
|
||||
fs_usage_data_type_to_base(&trans->fs_usage_delta, acc_k.replicas.data_type, a.v->d[0]);
|
||||
break;
|
||||
case BCH_DISK_ACCOUNTING_dev_data_type:
|
||||
rcu_read_lock();
|
||||
struct bch_dev *ca = bch2_dev_rcu(c, acc_k.dev_data_type.dev);
|
||||
if (ca) {
|
||||
this_cpu_add(ca->usage->d[acc_k.dev_data_type.data_type].buckets, a.v->d[0]);
|
||||
this_cpu_add(ca->usage->d[acc_k.dev_data_type.data_type].sectors, a.v->d[1]);
|
||||
this_cpu_add(ca->usage->d[acc_k.dev_data_type.data_type].fragmented, a.v->d[2]);
|
||||
}
|
||||
rcu_read_unlock();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return __bch2_accounting_mem_mod(c, a, gc);
|
||||
}
|
||||
|
||||
static inline int bch2_accounting_mem_add(struct btree_trans *trans, struct bkey_s_c_accounting a, bool gc)
|
||||
{
|
||||
percpu_down_read(&trans->c->mark_lock);
|
||||
int ret = bch2_accounting_mem_mod_locked(trans, a, gc);
|
||||
int ret = bch2_accounting_mem_mod_locked(trans, a, gc, false);
|
||||
percpu_up_read(&trans->c->mark_lock);
|
||||
return ret;
|
||||
}
|
||||
|
@ -103,7 +103,8 @@ static inline bool data_type_is_hidden(enum bch_data_type type)
|
||||
x(compression, 4) \
|
||||
x(snapshot, 5) \
|
||||
x(btree, 6) \
|
||||
x(rebalance_work, 7)
|
||||
x(rebalance_work, 7) \
|
||||
x(inum, 8)
|
||||
|
||||
enum disk_accounting_type {
|
||||
#define x(f, nr) BCH_DISK_ACCOUNTING_##f = nr,
|
||||
@ -136,6 +137,10 @@ struct bch_acct_btree {
|
||||
__u32 id;
|
||||
} __packed;
|
||||
|
||||
struct bch_acct_inum {
|
||||
__u64 inum;
|
||||
} __packed;
|
||||
|
||||
struct bch_acct_rebalance_work {
|
||||
};
|
||||
|
||||
@ -152,6 +157,7 @@ struct disk_accounting_pos {
|
||||
struct bch_acct_snapshot snapshot;
|
||||
struct bch_acct_btree btree;
|
||||
struct bch_acct_rebalance_work rebalance_work;
|
||||
struct bch_acct_inum inum;
|
||||
} __packed;
|
||||
} __packed;
|
||||
struct bpos _pad;
|
||||
|
@ -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,
|
||||
struct bkey_s_c k,
|
||||
enum bch_validate_flags flags,
|
||||
const struct bch_extent_ptr *ptr,
|
||||
unsigned size_ondisk,
|
||||
bool metadata,
|
||||
struct printbuf *err)
|
||||
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)
|
||||
{
|
||||
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,
|
||||
"invalid extent entry type (got %u, max %u)",
|
||||
__extent_entry_type(entry), BCH_EXTENT_ENTRY_MAX);
|
||||
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);
|
||||
|
||||
|
@ -193,7 +193,7 @@ static struct bch_inode_info *bch2_inode_insert(struct bch_fs *c, struct bch_ino
|
||||
* only insert fully created inodes in the inode hash table. But
|
||||
* discard_new_inode() expects it to be set...
|
||||
*/
|
||||
inode->v.i_flags |= I_NEW;
|
||||
inode->v.i_state |= I_NEW;
|
||||
/*
|
||||
* We don't want bch2_evict_inode() to delete the inode on disk,
|
||||
* we just raced and had another inode in cache. Normally new
|
||||
|
@ -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, \
|
||||
|
@ -72,7 +72,10 @@
|
||||
BCH_FSCK_ERR_accounting_key_replicas_nr_devs_0, \
|
||||
BCH_FSCK_ERR_accounting_key_replicas_nr_required_bad, \
|
||||
BCH_FSCK_ERR_accounting_key_replicas_devs_unsorted, \
|
||||
BCH_FSCK_ERR_accounting_key_junk_at_end)
|
||||
BCH_FSCK_ERR_accounting_key_junk_at_end) \
|
||||
x(disk_accounting_inum, \
|
||||
BIT_ULL(BCH_RECOVERY_PASS_check_allocations), \
|
||||
BCH_FSCK_ERR_accounting_mismatch)
|
||||
|
||||
#define DOWNGRADE_TABLE() \
|
||||
x(bucket_stripe_sectors, \
|
||||
@ -104,6 +107,7 @@
|
||||
BCH_FSCK_ERR_fs_usage_nr_inodes_wrong, \
|
||||
BCH_FSCK_ERR_fs_usage_persistent_reserved_wrong, \
|
||||
BCH_FSCK_ERR_fs_usage_replicas_wrong, \
|
||||
BCH_FSCK_ERR_accounting_replicas_not_marked, \
|
||||
BCH_FSCK_ERR_bkey_version_in_future)
|
||||
|
||||
struct upgrade_downgrade_entry {
|
||||
|
@ -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, \
|
||||
|
@ -4,6 +4,7 @@
|
||||
#include "buckets.h"
|
||||
#include "btree_cache.h"
|
||||
#include "btree_iter.h"
|
||||
#include "btree_key_cache.h"
|
||||
#include "btree_locking.h"
|
||||
#include "btree_update_interior.h"
|
||||
#include "keylist.h"
|
||||
|
@ -988,10 +988,33 @@ TRACE_EVENT(trans_restart_split_race,
|
||||
__entry->u64s_remaining)
|
||||
);
|
||||
|
||||
DEFINE_EVENT(transaction_event, trans_blocked_journal_reclaim,
|
||||
TRACE_EVENT(trans_blocked_journal_reclaim,
|
||||
TP_PROTO(struct btree_trans *trans,
|
||||
unsigned long caller_ip),
|
||||
TP_ARGS(trans, caller_ip)
|
||||
TP_ARGS(trans, caller_ip),
|
||||
|
||||
TP_STRUCT__entry(
|
||||
__array(char, trans_fn, 32 )
|
||||
__field(unsigned long, caller_ip )
|
||||
|
||||
__field(unsigned long, key_cache_nr_keys )
|
||||
__field(unsigned long, key_cache_nr_dirty )
|
||||
__field(long, must_wait )
|
||||
),
|
||||
|
||||
TP_fast_assign(
|
||||
strscpy(__entry->trans_fn, trans->fn, sizeof(__entry->trans_fn));
|
||||
__entry->caller_ip = caller_ip;
|
||||
__entry->key_cache_nr_keys = atomic_long_read(&trans->c->btree_key_cache.nr_keys);
|
||||
__entry->key_cache_nr_dirty = atomic_long_read(&trans->c->btree_key_cache.nr_dirty);
|
||||
__entry->must_wait = __bch2_btree_key_cache_must_wait(trans->c);
|
||||
),
|
||||
|
||||
TP_printk("%s %pS key cache keys %lu dirty %lu must_wait %li",
|
||||
__entry->trans_fn, (void *) __entry->caller_ip,
|
||||
__entry->key_cache_nr_keys,
|
||||
__entry->key_cache_nr_dirty,
|
||||
__entry->must_wait)
|
||||
);
|
||||
|
||||
TRACE_EVENT(trans_restart_journal_preres_get,
|
||||
|
@ -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, \
|
||||
})
|
||||
|
@ -121,6 +121,8 @@ void *__genradix_ptr_alloc(struct __genradix *radix, size_t offset,
|
||||
if ((v = cmpxchg_release(&radix->root, r, new_root)) == r) {
|
||||
v = new_root;
|
||||
new_node = NULL;
|
||||
} else {
|
||||
new_node->children[0] = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user