mirror of
https://github.com/koverstreet/bcachefs-tools.git
synced 2025-02-22 00:00:03 +03:00
Update bcachefs sources to e7015d0df31c bcachefs: Simplify bch2_xattr_emit() implementation
Signed-off-by: Kent Overstreet <kent.overstreet@linux.dev>
This commit is contained in:
parent
8b93af8747
commit
e2e1493111
@ -1 +1 @@
|
|||||||
070f7d6a382a0d67628756727751c24f70eb48ea
|
e7015d0df31c410789666b4c8ad0683aae87b4da
|
||||||
|
@ -47,6 +47,12 @@ struct xattr_handler {
|
|||||||
size_t size, int flags);
|
size_t size, int flags);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static inline bool xattr_handler_can_list(const struct xattr_handler *handler,
|
||||||
|
struct dentry *dentry)
|
||||||
|
{
|
||||||
|
return handler && (!handler->list || handler->list(dentry));
|
||||||
|
}
|
||||||
|
|
||||||
const char *xattr_full_name(const struct xattr_handler *, const char *);
|
const char *xattr_full_name(const struct xattr_handler *, const char *);
|
||||||
|
|
||||||
struct xattr {
|
struct xattr {
|
||||||
|
@ -196,75 +196,71 @@ static unsigned bch_alloc_v1_val_u64s(const struct bch_alloc *a)
|
|||||||
return DIV_ROUND_UP(bytes, sizeof(u64));
|
return DIV_ROUND_UP(bytes, sizeof(u64));
|
||||||
}
|
}
|
||||||
|
|
||||||
int bch2_alloc_v1_invalid(struct bch_fs *c, struct bkey_s_c k,
|
int bch2_alloc_v1_validate(struct bch_fs *c, struct bkey_s_c k,
|
||||||
enum bch_validate_flags flags,
|
enum bch_validate_flags flags)
|
||||||
struct printbuf *err)
|
|
||||||
{
|
{
|
||||||
struct bkey_s_c_alloc a = bkey_s_c_to_alloc(k);
|
struct bkey_s_c_alloc a = bkey_s_c_to_alloc(k);
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
|
|
||||||
/* allow for unknown fields */
|
/* allow for unknown fields */
|
||||||
bkey_fsck_err_on(bkey_val_u64s(a.k) < bch_alloc_v1_val_u64s(a.v), c, err,
|
bkey_fsck_err_on(bkey_val_u64s(a.k) < bch_alloc_v1_val_u64s(a.v),
|
||||||
alloc_v1_val_size_bad,
|
c, alloc_v1_val_size_bad,
|
||||||
"incorrect value size (%zu < %u)",
|
"incorrect value size (%zu < %u)",
|
||||||
bkey_val_u64s(a.k), bch_alloc_v1_val_u64s(a.v));
|
bkey_val_u64s(a.k), bch_alloc_v1_val_u64s(a.v));
|
||||||
fsck_err:
|
fsck_err:
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
int bch2_alloc_v2_invalid(struct bch_fs *c, struct bkey_s_c k,
|
int bch2_alloc_v2_validate(struct bch_fs *c, struct bkey_s_c k,
|
||||||
enum bch_validate_flags flags,
|
enum bch_validate_flags flags)
|
||||||
struct printbuf *err)
|
|
||||||
{
|
{
|
||||||
struct bkey_alloc_unpacked u;
|
struct bkey_alloc_unpacked u;
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
|
|
||||||
bkey_fsck_err_on(bch2_alloc_unpack_v2(&u, k), c, err,
|
bkey_fsck_err_on(bch2_alloc_unpack_v2(&u, k),
|
||||||
alloc_v2_unpack_error,
|
c, alloc_v2_unpack_error,
|
||||||
"unpack error");
|
"unpack error");
|
||||||
fsck_err:
|
fsck_err:
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
int bch2_alloc_v3_invalid(struct bch_fs *c, struct bkey_s_c k,
|
int bch2_alloc_v3_validate(struct bch_fs *c, struct bkey_s_c k,
|
||||||
enum bch_validate_flags flags,
|
enum bch_validate_flags flags)
|
||||||
struct printbuf *err)
|
|
||||||
{
|
{
|
||||||
struct bkey_alloc_unpacked u;
|
struct bkey_alloc_unpacked u;
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
|
|
||||||
bkey_fsck_err_on(bch2_alloc_unpack_v3(&u, k), c, err,
|
bkey_fsck_err_on(bch2_alloc_unpack_v3(&u, k),
|
||||||
alloc_v2_unpack_error,
|
c, alloc_v2_unpack_error,
|
||||||
"unpack error");
|
"unpack error");
|
||||||
fsck_err:
|
fsck_err:
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
int bch2_alloc_v4_invalid(struct bch_fs *c, struct bkey_s_c k,
|
int bch2_alloc_v4_validate(struct bch_fs *c, struct bkey_s_c k,
|
||||||
enum bch_validate_flags flags, struct printbuf *err)
|
enum bch_validate_flags flags)
|
||||||
{
|
{
|
||||||
struct bkey_s_c_alloc_v4 a = bkey_s_c_to_alloc_v4(k);
|
struct bkey_s_c_alloc_v4 a = bkey_s_c_to_alloc_v4(k);
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
|
|
||||||
bkey_fsck_err_on(alloc_v4_u64s_noerror(a.v) > bkey_val_u64s(k.k), c, err,
|
bkey_fsck_err_on(alloc_v4_u64s_noerror(a.v) > bkey_val_u64s(k.k),
|
||||||
alloc_v4_val_size_bad,
|
c, alloc_v4_val_size_bad,
|
||||||
"bad val size (%u > %zu)",
|
"bad val size (%u > %zu)",
|
||||||
alloc_v4_u64s_noerror(a.v), bkey_val_u64s(k.k));
|
alloc_v4_u64s_noerror(a.v), bkey_val_u64s(k.k));
|
||||||
|
|
||||||
bkey_fsck_err_on(!BCH_ALLOC_V4_BACKPOINTERS_START(a.v) &&
|
bkey_fsck_err_on(!BCH_ALLOC_V4_BACKPOINTERS_START(a.v) &&
|
||||||
BCH_ALLOC_V4_NR_BACKPOINTERS(a.v), c, err,
|
BCH_ALLOC_V4_NR_BACKPOINTERS(a.v),
|
||||||
alloc_v4_backpointers_start_bad,
|
c, alloc_v4_backpointers_start_bad,
|
||||||
"invalid backpointers_start");
|
"invalid backpointers_start");
|
||||||
|
|
||||||
bkey_fsck_err_on(alloc_data_type(*a.v, a.v->data_type) != a.v->data_type, c, err,
|
bkey_fsck_err_on(alloc_data_type(*a.v, a.v->data_type) != a.v->data_type,
|
||||||
alloc_key_data_type_bad,
|
c, alloc_key_data_type_bad,
|
||||||
"invalid data type (got %u should be %u)",
|
"invalid data type (got %u should be %u)",
|
||||||
a.v->data_type, alloc_data_type(*a.v, a.v->data_type));
|
a.v->data_type, alloc_data_type(*a.v, a.v->data_type));
|
||||||
|
|
||||||
for (unsigned i = 0; i < 2; i++)
|
for (unsigned i = 0; i < 2; i++)
|
||||||
bkey_fsck_err_on(a.v->io_time[i] > LRU_TIME_MAX,
|
bkey_fsck_err_on(a.v->io_time[i] > LRU_TIME_MAX,
|
||||||
c, err,
|
c, alloc_key_io_time_bad,
|
||||||
alloc_key_io_time_bad,
|
|
||||||
"invalid io_time[%s]: %llu, max %llu",
|
"invalid io_time[%s]: %llu, max %llu",
|
||||||
i == READ ? "read" : "write",
|
i == READ ? "read" : "write",
|
||||||
a.v->io_time[i], LRU_TIME_MAX);
|
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->dirty_sectors ||
|
||||||
a.v->cached_sectors ||
|
a.v->cached_sectors ||
|
||||||
a.v->stripe,
|
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",
|
"empty data type free but have data %u.%u.%u %u",
|
||||||
stripe_sectors,
|
stripe_sectors,
|
||||||
a.v->dirty_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:
|
case BCH_DATA_parity:
|
||||||
bkey_fsck_err_on(!a.v->dirty_sectors &&
|
bkey_fsck_err_on(!a.v->dirty_sectors &&
|
||||||
!stripe_sectors,
|
!stripe_sectors,
|
||||||
c, err, alloc_key_dirty_sectors_0,
|
c, alloc_key_dirty_sectors_0,
|
||||||
"data_type %s but dirty_sectors==0",
|
"data_type %s but dirty_sectors==0",
|
||||||
bch2_data_type_str(a.v->data_type));
|
bch2_data_type_str(a.v->data_type));
|
||||||
break;
|
break;
|
||||||
@ -305,12 +301,12 @@ int bch2_alloc_v4_invalid(struct bch_fs *c, struct bkey_s_c k,
|
|||||||
a.v->dirty_sectors ||
|
a.v->dirty_sectors ||
|
||||||
stripe_sectors ||
|
stripe_sectors ||
|
||||||
a.v->stripe,
|
a.v->stripe,
|
||||||
c, err, alloc_key_cached_inconsistency,
|
c, alloc_key_cached_inconsistency,
|
||||||
"data type inconsistency");
|
"data type inconsistency");
|
||||||
|
|
||||||
bkey_fsck_err_on(!a.v->io_time[READ] &&
|
bkey_fsck_err_on(!a.v->io_time[READ] &&
|
||||||
c->curr_recovery_pass > BCH_RECOVERY_PASS_check_alloc_to_lru_refs,
|
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");
|
"cached bucket with read_time == 0");
|
||||||
break;
|
break;
|
||||||
case BCH_DATA_stripe:
|
case BCH_DATA_stripe:
|
||||||
@ -513,14 +509,13 @@ static unsigned alloc_gen(struct bkey_s_c k, unsigned offset)
|
|||||||
: 0;
|
: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int bch2_bucket_gens_invalid(struct bch_fs *c, struct bkey_s_c k,
|
int bch2_bucket_gens_validate(struct bch_fs *c, struct bkey_s_c k,
|
||||||
enum bch_validate_flags flags,
|
enum bch_validate_flags flags)
|
||||||
struct printbuf *err)
|
|
||||||
{
|
{
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
|
|
||||||
bkey_fsck_err_on(bkey_val_bytes(k.k) != sizeof(struct bch_bucket_gens), c, err,
|
bkey_fsck_err_on(bkey_val_bytes(k.k) != sizeof(struct bch_bucket_gens),
|
||||||
bucket_gens_val_size_bad,
|
c, bucket_gens_val_size_bad,
|
||||||
"bad val size (%zu != %zu)",
|
"bad val size (%zu != %zu)",
|
||||||
bkey_val_bytes(k.k), sizeof(struct bch_bucket_gens));
|
bkey_val_bytes(k.k), sizeof(struct bch_bucket_gens));
|
||||||
fsck_err:
|
fsck_err:
|
||||||
@ -829,7 +824,19 @@ int bch2_trigger_alloc(struct btree_trans *trans,
|
|||||||
|
|
||||||
struct bch_alloc_v4 old_a_convert;
|
struct bch_alloc_v4 old_a_convert;
|
||||||
const struct bch_alloc_v4 *old_a = bch2_alloc_to_v4(old, &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) {
|
if (flags & BTREE_TRIGGER_transactional) {
|
||||||
alloc_data_type_set(new_a, new_a->data_type);
|
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)
|
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 \
|
#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_bucket_io_time_reset(struct btree_trans *, unsigned, size_t, int);
|
||||||
|
|
||||||
int bch2_alloc_v1_invalid(struct bch_fs *, struct bkey_s_c,
|
int bch2_alloc_v1_validate(struct bch_fs *, struct bkey_s_c, enum bch_validate_flags);
|
||||||
enum bch_validate_flags, struct printbuf *);
|
int bch2_alloc_v2_validate(struct bch_fs *, struct bkey_s_c, enum bch_validate_flags);
|
||||||
int bch2_alloc_v2_invalid(struct bch_fs *, struct bkey_s_c,
|
int bch2_alloc_v3_validate(struct bch_fs *, struct bkey_s_c, enum bch_validate_flags);
|
||||||
enum bch_validate_flags, struct printbuf *);
|
int bch2_alloc_v4_validate(struct bch_fs *, struct bkey_s_c, enum bch_validate_flags);
|
||||||
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 *);
|
|
||||||
void bch2_alloc_v4_swab(struct bkey_s);
|
void bch2_alloc_v4_swab(struct bkey_s);
|
||||||
void bch2_alloc_to_text(struct printbuf *, struct bch_fs *, struct bkey_s_c);
|
void bch2_alloc_to_text(struct printbuf *, struct bch_fs *, struct bkey_s_c);
|
||||||
|
|
||||||
#define bch2_bkey_ops_alloc ((struct bkey_ops) { \
|
#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, \
|
.val_to_text = bch2_alloc_to_text, \
|
||||||
.trigger = bch2_trigger_alloc, \
|
.trigger = bch2_trigger_alloc, \
|
||||||
.min_val_size = 8, \
|
.min_val_size = 8, \
|
||||||
})
|
})
|
||||||
|
|
||||||
#define bch2_bkey_ops_alloc_v2 ((struct bkey_ops) { \
|
#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, \
|
.val_to_text = bch2_alloc_to_text, \
|
||||||
.trigger = bch2_trigger_alloc, \
|
.trigger = bch2_trigger_alloc, \
|
||||||
.min_val_size = 8, \
|
.min_val_size = 8, \
|
||||||
})
|
})
|
||||||
|
|
||||||
#define bch2_bkey_ops_alloc_v3 ((struct bkey_ops) { \
|
#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, \
|
.val_to_text = bch2_alloc_to_text, \
|
||||||
.trigger = bch2_trigger_alloc, \
|
.trigger = bch2_trigger_alloc, \
|
||||||
.min_val_size = 16, \
|
.min_val_size = 16, \
|
||||||
})
|
})
|
||||||
|
|
||||||
#define bch2_bkey_ops_alloc_v4 ((struct bkey_ops) { \
|
#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, \
|
.val_to_text = bch2_alloc_to_text, \
|
||||||
.swab = bch2_alloc_v4_swab, \
|
.swab = bch2_alloc_v4_swab, \
|
||||||
.trigger = bch2_trigger_alloc, \
|
.trigger = bch2_trigger_alloc, \
|
||||||
.min_val_size = 48, \
|
.min_val_size = 48, \
|
||||||
})
|
})
|
||||||
|
|
||||||
int bch2_bucket_gens_invalid(struct bch_fs *, struct bkey_s_c,
|
int bch2_bucket_gens_validate(struct bch_fs *, struct bkey_s_c,
|
||||||
enum bch_validate_flags, struct printbuf *);
|
enum bch_validate_flags);
|
||||||
void bch2_bucket_gens_to_text(struct printbuf *, struct bch_fs *, struct bkey_s_c);
|
void bch2_bucket_gens_to_text(struct printbuf *, struct bch_fs *, struct bkey_s_c);
|
||||||
|
|
||||||
#define bch2_bkey_ops_bucket_gens ((struct bkey_ops) { \
|
#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, \
|
.val_to_text = bch2_bucket_gens_to_text, \
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@ -47,9 +47,8 @@ static bool extent_matches_bp(struct bch_fs *c,
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
int bch2_backpointer_invalid(struct bch_fs *c, struct bkey_s_c k,
|
int bch2_backpointer_validate(struct bch_fs *c, struct bkey_s_c k,
|
||||||
enum bch_validate_flags flags,
|
enum bch_validate_flags flags)
|
||||||
struct printbuf *err)
|
|
||||||
{
|
{
|
||||||
struct bkey_s_c_backpointer bp = bkey_s_c_to_backpointer(k);
|
struct bkey_s_c_backpointer bp = bkey_s_c_to_backpointer(k);
|
||||||
|
|
||||||
@ -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 ||
|
bkey_fsck_err_on((bp.v->bucket_offset >> MAX_EXTENT_COMPRESS_RATIO_SHIFT) >= ca->mi.bucket_size ||
|
||||||
!bpos_eq(bp.k->p, bp_pos),
|
!bpos_eq(bp.k->p, bp_pos),
|
||||||
c, err,
|
c, backpointer_bucket_offset_wrong,
|
||||||
backpointer_bucket_offset_wrong,
|
|
||||||
"backpointer bucket_offset wrong");
|
"backpointer bucket_offset wrong");
|
||||||
fsck_err:
|
fsck_err:
|
||||||
return ret;
|
return ret;
|
||||||
|
@ -18,14 +18,13 @@ static inline u64 swab40(u64 x)
|
|||||||
((x & 0xff00000000ULL) >> 32));
|
((x & 0xff00000000ULL) >> 32));
|
||||||
}
|
}
|
||||||
|
|
||||||
int bch2_backpointer_invalid(struct bch_fs *, struct bkey_s_c k,
|
int bch2_backpointer_validate(struct bch_fs *, struct bkey_s_c k, enum bch_validate_flags);
|
||||||
enum bch_validate_flags, struct printbuf *);
|
|
||||||
void bch2_backpointer_to_text(struct printbuf *, const struct bch_backpointer *);
|
void bch2_backpointer_to_text(struct printbuf *, const struct bch_backpointer *);
|
||||||
void bch2_backpointer_k_to_text(struct printbuf *, struct bch_fs *, struct bkey_s_c);
|
void bch2_backpointer_k_to_text(struct printbuf *, struct bch_fs *, struct bkey_s_c);
|
||||||
void bch2_backpointer_swab(struct bkey_s);
|
void bch2_backpointer_swab(struct bkey_s);
|
||||||
|
|
||||||
#define bch2_bkey_ops_backpointer ((struct bkey_ops) { \
|
#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, \
|
.val_to_text = bch2_backpointer_k_to_text, \
|
||||||
.swab = bch2_backpointer_swab, \
|
.swab = bch2_backpointer_swab, \
|
||||||
.min_val_size = 32, \
|
.min_val_size = 32, \
|
||||||
|
@ -447,6 +447,7 @@ BCH_DEBUG_PARAMS_DEBUG()
|
|||||||
x(blocked_journal_low_on_space) \
|
x(blocked_journal_low_on_space) \
|
||||||
x(blocked_journal_low_on_pin) \
|
x(blocked_journal_low_on_pin) \
|
||||||
x(blocked_journal_max_in_flight) \
|
x(blocked_journal_max_in_flight) \
|
||||||
|
x(blocked_key_cache_flush) \
|
||||||
x(blocked_allocate) \
|
x(blocked_allocate) \
|
||||||
x(blocked_allocate_open_bucket) \
|
x(blocked_allocate_open_bucket) \
|
||||||
x(blocked_write_buffer_full) \
|
x(blocked_write_buffer_full) \
|
||||||
|
@ -676,7 +676,8 @@ struct bch_sb_field_ext {
|
|||||||
x(mi_btree_bitmap, BCH_VERSION(1, 7)) \
|
x(mi_btree_bitmap, BCH_VERSION(1, 7)) \
|
||||||
x(bucket_stripe_sectors, BCH_VERSION(1, 8)) \
|
x(bucket_stripe_sectors, BCH_VERSION(1, 8)) \
|
||||||
x(disk_accounting_v2, BCH_VERSION(1, 9)) \
|
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 {
|
enum bcachefs_metadata_version {
|
||||||
bcachefs_metadata_version_min = 9,
|
bcachefs_metadata_version_min = 9,
|
||||||
|
@ -10,9 +10,10 @@
|
|||||||
#include "vstructs.h"
|
#include "vstructs.h"
|
||||||
|
|
||||||
enum bch_validate_flags {
|
enum bch_validate_flags {
|
||||||
BCH_VALIDATE_write = (1U << 0),
|
BCH_VALIDATE_write = BIT(0),
|
||||||
BCH_VALIDATE_commit = (1U << 1),
|
BCH_VALIDATE_commit = BIT(1),
|
||||||
BCH_VALIDATE_journal = (1U << 2),
|
BCH_VALIDATE_journal = BIT(2),
|
||||||
|
BCH_VALIDATE_silent = BIT(3),
|
||||||
};
|
};
|
||||||
|
|
||||||
#if 0
|
#if 0
|
||||||
|
@ -27,27 +27,27 @@ const char * const bch2_bkey_types[] = {
|
|||||||
NULL
|
NULL
|
||||||
};
|
};
|
||||||
|
|
||||||
static int deleted_key_invalid(struct bch_fs *c, struct bkey_s_c k,
|
static int deleted_key_validate(struct bch_fs *c, struct bkey_s_c k,
|
||||||
enum bch_validate_flags flags, struct printbuf *err)
|
enum bch_validate_flags flags)
|
||||||
{
|
{
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
#define bch2_bkey_ops_deleted ((struct bkey_ops) { \
|
#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) { \
|
#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,
|
static int empty_val_key_validate(struct bch_fs *c, struct bkey_s_c k,
|
||||||
enum bch_validate_flags flags, struct printbuf *err)
|
enum bch_validate_flags flags)
|
||||||
{
|
{
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
|
|
||||||
bkey_fsck_err_on(bkey_val_bytes(k.k), c, err,
|
bkey_fsck_err_on(bkey_val_bytes(k.k),
|
||||||
bkey_val_size_nonzero,
|
c, bkey_val_size_nonzero,
|
||||||
"incorrect value size (%zu != 0)",
|
"incorrect value size (%zu != 0)",
|
||||||
bkey_val_bytes(k.k));
|
bkey_val_bytes(k.k));
|
||||||
fsck_err:
|
fsck_err:
|
||||||
@ -55,11 +55,11 @@ fsck_err:
|
|||||||
}
|
}
|
||||||
|
|
||||||
#define bch2_bkey_ops_error ((struct bkey_ops) { \
|
#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,
|
static int key_type_cookie_validate(struct bch_fs *c, struct bkey_s_c k,
|
||||||
enum bch_validate_flags flags, struct printbuf *err)
|
enum bch_validate_flags flags)
|
||||||
{
|
{
|
||||||
return 0;
|
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) { \
|
#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, \
|
.val_to_text = key_type_cookie_to_text, \
|
||||||
.min_val_size = 8, \
|
.min_val_size = 8, \
|
||||||
})
|
})
|
||||||
|
|
||||||
#define bch2_bkey_ops_hash_whiteout ((struct bkey_ops) {\
|
#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,
|
static int key_type_inline_data_validate(struct bch_fs *c, struct bkey_s_c k,
|
||||||
enum bch_validate_flags flags, struct printbuf *err)
|
enum bch_validate_flags flags)
|
||||||
{
|
{
|
||||||
return 0;
|
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);
|
datalen, min(datalen, 32U), d.v->data);
|
||||||
}
|
}
|
||||||
|
|
||||||
#define bch2_bkey_ops_inline_data ((struct bkey_ops) { \
|
#define bch2_bkey_ops_inline_data ((struct bkey_ops) { \
|
||||||
.key_invalid = key_type_inline_data_invalid, \
|
.key_validate = key_type_inline_data_validate, \
|
||||||
.val_to_text = key_type_inline_data_to_text, \
|
.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)
|
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) { \
|
#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, \
|
.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 = {
|
const struct bkey_ops bch2_bkey_null_ops = {
|
||||||
};
|
};
|
||||||
|
|
||||||
int bch2_bkey_val_invalid(struct bch_fs *c, struct bkey_s_c k,
|
int bch2_bkey_val_validate(struct bch_fs *c, struct bkey_s_c k,
|
||||||
enum bch_validate_flags flags,
|
enum bch_validate_flags flags)
|
||||||
struct printbuf *err)
|
|
||||||
{
|
{
|
||||||
if (test_bit(BCH_FS_no_invalid_checks, &c->flags))
|
if (test_bit(BCH_FS_no_invalid_checks, &c->flags))
|
||||||
return 0;
|
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);
|
const struct bkey_ops *ops = bch2_bkey_type_ops(k.k->type);
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
|
|
||||||
bkey_fsck_err_on(bkey_val_bytes(k.k) < ops->min_val_size, c, err,
|
bkey_fsck_err_on(bkey_val_bytes(k.k) < ops->min_val_size,
|
||||||
bkey_val_size_too_small,
|
c, bkey_val_size_too_small,
|
||||||
"bad val size (%zu < %u)",
|
"bad val size (%zu < %u)",
|
||||||
bkey_val_bytes(k.k), ops->min_val_size);
|
bkey_val_bytes(k.k), ops->min_val_size);
|
||||||
|
|
||||||
if (!ops->key_invalid)
|
if (!ops->key_validate)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
ret = ops->key_invalid(c, k, flags, err);
|
ret = ops->key_validate(c, k, flags);
|
||||||
fsck_err:
|
fsck_err:
|
||||||
return ret;
|
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);
|
return type == BKEY_TYPE_btree ? "internal btree node" : bch2_btree_id_str(type - 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
int __bch2_bkey_invalid(struct bch_fs *c, struct bkey_s_c k,
|
int __bch2_bkey_validate(struct bch_fs *c, struct bkey_s_c k,
|
||||||
enum btree_node_type type,
|
enum btree_node_type type,
|
||||||
enum bch_validate_flags flags,
|
enum bch_validate_flags flags)
|
||||||
struct printbuf *err)
|
|
||||||
{
|
{
|
||||||
if (test_bit(BCH_FS_no_invalid_checks, &c->flags))
|
if (test_bit(BCH_FS_no_invalid_checks, &c->flags))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
|
|
||||||
bkey_fsck_err_on(k.k->u64s < BKEY_U64s, c, err,
|
bkey_fsck_err_on(k.k->u64s < BKEY_U64s,
|
||||||
bkey_u64s_too_small,
|
c, bkey_u64s_too_small,
|
||||||
"u64s too small (%u < %zu)", k.k->u64s, BKEY_U64s);
|
"u64s too small (%u < %zu)", k.k->u64s, BKEY_U64s);
|
||||||
|
|
||||||
if (type >= BKEY_TYPE_NR)
|
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 &&
|
bkey_fsck_err_on(k.k->type < KEY_TYPE_MAX &&
|
||||||
(type == BKEY_TYPE_btree || (flags & BCH_VALIDATE_commit)) &&
|
(type == BKEY_TYPE_btree || (flags & BCH_VALIDATE_commit)) &&
|
||||||
!(bch2_key_types_allowed[type] & BIT_ULL(k.k->type)), c, err,
|
!(bch2_key_types_allowed[type] & BIT_ULL(k.k->type)),
|
||||||
bkey_invalid_type_for_btree,
|
c, bkey_invalid_type_for_btree,
|
||||||
"invalid key type for btree %s (%s)",
|
"invalid key type for btree %s (%s)",
|
||||||
bch2_btree_node_type_str(type),
|
bch2_btree_node_type_str(type),
|
||||||
k.k->type < KEY_TYPE_MAX
|
k.k->type < KEY_TYPE_MAX
|
||||||
@ -189,17 +187,17 @@ int __bch2_bkey_invalid(struct bch_fs *c, struct bkey_s_c k,
|
|||||||
: "(unknown)");
|
: "(unknown)");
|
||||||
|
|
||||||
if (btree_node_type_is_extents(type) && !bkey_whiteout(k.k)) {
|
if (btree_node_type_is_extents(type) && !bkey_whiteout(k.k)) {
|
||||||
bkey_fsck_err_on(k.k->size == 0, c, err,
|
bkey_fsck_err_on(k.k->size == 0,
|
||||||
bkey_extent_size_zero,
|
c, bkey_extent_size_zero,
|
||||||
"size == 0");
|
"size == 0");
|
||||||
|
|
||||||
bkey_fsck_err_on(k.k->size > k.k->p.offset, c, err,
|
bkey_fsck_err_on(k.k->size > k.k->p.offset,
|
||||||
bkey_extent_size_greater_than_offset,
|
c, bkey_extent_size_greater_than_offset,
|
||||||
"size greater than offset (%u > %llu)",
|
"size greater than offset (%u > %llu)",
|
||||||
k.k->size, k.k->p.offset);
|
k.k->size, k.k->p.offset);
|
||||||
} else {
|
} else {
|
||||||
bkey_fsck_err_on(k.k->size, c, err,
|
bkey_fsck_err_on(k.k->size,
|
||||||
bkey_size_nonzero,
|
c, bkey_size_nonzero,
|
||||||
"size != 0");
|
"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;
|
enum btree_id btree = type - 1;
|
||||||
|
|
||||||
if (btree_type_has_snapshots(btree)) {
|
if (btree_type_has_snapshots(btree)) {
|
||||||
bkey_fsck_err_on(!k.k->p.snapshot, c, err,
|
bkey_fsck_err_on(!k.k->p.snapshot,
|
||||||
bkey_snapshot_zero,
|
c, bkey_snapshot_zero,
|
||||||
"snapshot == 0");
|
"snapshot == 0");
|
||||||
} else if (!btree_type_has_snapshot_field(btree)) {
|
} else if (!btree_type_has_snapshot_field(btree)) {
|
||||||
bkey_fsck_err_on(k.k->p.snapshot, c, err,
|
bkey_fsck_err_on(k.k->p.snapshot,
|
||||||
bkey_snapshot_nonzero,
|
c, bkey_snapshot_nonzero,
|
||||||
"nonzero snapshot");
|
"nonzero snapshot");
|
||||||
} else {
|
} 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_fsck_err_on(bkey_eq(k.k->p, POS_MAX),
|
||||||
bkey_at_pos_max,
|
c, bkey_at_pos_max,
|
||||||
"key at POS_MAX");
|
"key at POS_MAX");
|
||||||
}
|
}
|
||||||
fsck_err:
|
fsck_err:
|
||||||
return ret;
|
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 btree_node_type type,
|
||||||
enum bch_validate_flags flags,
|
enum bch_validate_flags flags)
|
||||||
struct printbuf *err)
|
|
||||||
{
|
{
|
||||||
return __bch2_bkey_invalid(c, k, type, flags, err) ?:
|
return __bch2_bkey_validate(c, k, type, flags) ?:
|
||||||
bch2_bkey_val_invalid(c, k, flags, err);
|
bch2_bkey_val_validate(c, k, flags);
|
||||||
}
|
}
|
||||||
|
|
||||||
int bch2_bkey_in_btree_node(struct bch_fs *c, struct btree *b,
|
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;
|
int ret = 0;
|
||||||
|
|
||||||
bkey_fsck_err_on(bpos_lt(k.k->p, b->data->min_key), c, err,
|
bkey_fsck_err_on(bpos_lt(k.k->p, b->data->min_key),
|
||||||
bkey_before_start_of_btree_node,
|
c, bkey_before_start_of_btree_node,
|
||||||
"key 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_fsck_err_on(bpos_gt(k.k->p, b->data->max_key),
|
||||||
bkey_after_end_of_btree_node,
|
c, bkey_after_end_of_btree_node,
|
||||||
"key past end of btree node");
|
"key past end of btree node");
|
||||||
fsck_err:
|
fsck_err:
|
||||||
return ret;
|
return ret;
|
||||||
|
@ -14,15 +14,15 @@ extern const char * const bch2_bkey_types[];
|
|||||||
extern const struct bkey_ops bch2_bkey_null_ops;
|
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.
|
* invalid, entire key will be deleted.
|
||||||
*
|
*
|
||||||
* When invalid, error string is returned via @err. @rw indicates whether key is
|
* 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.
|
* being read or written; more aggressive checks can be enabled when rw == WRITE.
|
||||||
*/
|
*/
|
||||||
struct bkey_ops {
|
struct bkey_ops {
|
||||||
int (*key_invalid)(struct bch_fs *c, struct bkey_s_c k,
|
int (*key_validate)(struct bch_fs *c, struct bkey_s_c k,
|
||||||
enum bch_validate_flags flags, struct printbuf *err);
|
enum bch_validate_flags flags);
|
||||||
void (*val_to_text)(struct printbuf *, struct bch_fs *,
|
void (*val_to_text)(struct printbuf *, struct bch_fs *,
|
||||||
struct bkey_s_c);
|
struct bkey_s_c);
|
||||||
void (*swab)(struct bkey_s);
|
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;
|
: &bch2_bkey_null_ops;
|
||||||
}
|
}
|
||||||
|
|
||||||
int bch2_bkey_val_invalid(struct bch_fs *, struct bkey_s_c,
|
int bch2_bkey_val_validate(struct bch_fs *, struct bkey_s_c, enum bch_validate_flags);
|
||||||
enum bch_validate_flags, struct printbuf *);
|
int __bch2_bkey_validate(struct bch_fs *, struct bkey_s_c, enum btree_node_type,
|
||||||
int __bch2_bkey_invalid(struct bch_fs *, struct bkey_s_c, enum btree_node_type,
|
enum bch_validate_flags);
|
||||||
enum bch_validate_flags, struct printbuf *);
|
int bch2_bkey_validate(struct bch_fs *, struct bkey_s_c, enum btree_node_type,
|
||||||
int bch2_bkey_invalid(struct bch_fs *, struct bkey_s_c, enum btree_node_type,
|
enum bch_validate_flags);
|
||||||
enum bch_validate_flags, struct printbuf *);
|
int bch2_bkey_in_btree_node(struct bch_fs *, struct btree *, struct bkey_s_c,
|
||||||
int bch2_bkey_in_btree_node(struct bch_fs *, struct btree *,
|
enum bch_validate_flags);
|
||||||
struct bkey_s_c, struct printbuf *);
|
|
||||||
|
|
||||||
void bch2_bpos_to_text(struct printbuf *, struct bpos);
|
void bch2_bpos_to_text(struct printbuf *, struct bpos);
|
||||||
void bch2_bkey_to_text(struct printbuf *, const struct bkey *);
|
void bch2_bkey_to_text(struct printbuf *, const struct bkey *);
|
||||||
|
@ -304,11 +304,6 @@ struct bkey_float {
|
|||||||
};
|
};
|
||||||
#define BKEY_MANTISSA_BITS 16
|
#define BKEY_MANTISSA_BITS 16
|
||||||
|
|
||||||
static unsigned bkey_float_byte_offset(unsigned idx)
|
|
||||||
{
|
|
||||||
return idx * sizeof(struct bkey_float);
|
|
||||||
}
|
|
||||||
|
|
||||||
struct ro_aux_tree {
|
struct ro_aux_tree {
|
||||||
u8 nothing[0];
|
u8 nothing[0];
|
||||||
struct bkey_float f[];
|
struct bkey_float f[];
|
||||||
@ -328,8 +323,7 @@ static unsigned bset_aux_tree_buf_end(const struct bset_tree *t)
|
|||||||
return t->aux_data_offset;
|
return t->aux_data_offset;
|
||||||
case BSET_RO_AUX_TREE:
|
case BSET_RO_AUX_TREE:
|
||||||
return t->aux_data_offset +
|
return t->aux_data_offset +
|
||||||
DIV_ROUND_UP(t->size * sizeof(struct bkey_float) +
|
DIV_ROUND_UP(t->size * sizeof(struct bkey_float), 8);
|
||||||
t->size * sizeof(u8), 8);
|
|
||||||
case BSET_RW_AUX_TREE:
|
case BSET_RW_AUX_TREE:
|
||||||
return t->aux_data_offset +
|
return t->aux_data_offset +
|
||||||
DIV_ROUND_UP(sizeof(struct rw_aux_tree) * t->size, 8);
|
DIV_ROUND_UP(sizeof(struct rw_aux_tree) * t->size, 8);
|
||||||
@ -360,14 +354,6 @@ static struct ro_aux_tree *ro_aux_tree_base(const struct btree *b,
|
|||||||
return __aux_tree_base(b, t);
|
return __aux_tree_base(b, t);
|
||||||
}
|
}
|
||||||
|
|
||||||
static u8 *ro_aux_tree_prev(const struct btree *b,
|
|
||||||
const struct bset_tree *t)
|
|
||||||
{
|
|
||||||
EBUG_ON(bset_aux_tree_type(t) != BSET_RO_AUX_TREE);
|
|
||||||
|
|
||||||
return __aux_tree_base(b, t) + bkey_float_byte_offset(t->size);
|
|
||||||
}
|
|
||||||
|
|
||||||
static struct bkey_float *bkey_float(const struct btree *b,
|
static struct bkey_float *bkey_float(const struct btree *b,
|
||||||
const struct bset_tree *t,
|
const struct bset_tree *t,
|
||||||
unsigned idx)
|
unsigned idx)
|
||||||
@ -479,15 +465,6 @@ static inline struct bkey_packed *tree_to_bkey(const struct btree *b,
|
|||||||
bkey_float(b, t, j)->key_offset);
|
bkey_float(b, t, j)->key_offset);
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct bkey_packed *tree_to_prev_bkey(const struct btree *b,
|
|
||||||
const struct bset_tree *t,
|
|
||||||
unsigned j)
|
|
||||||
{
|
|
||||||
unsigned prev_u64s = ro_aux_tree_prev(b, t)[j];
|
|
||||||
|
|
||||||
return (void *) ((u64 *) tree_to_bkey(b, t, j)->_data - prev_u64s);
|
|
||||||
}
|
|
||||||
|
|
||||||
static struct rw_aux_tree *rw_aux_tree(const struct btree *b,
|
static struct rw_aux_tree *rw_aux_tree(const struct btree *b,
|
||||||
const struct bset_tree *t)
|
const struct bset_tree *t)
|
||||||
{
|
{
|
||||||
@ -585,8 +562,7 @@ static unsigned rw_aux_tree_bsearch(struct btree *b,
|
|||||||
}
|
}
|
||||||
|
|
||||||
static inline unsigned bkey_mantissa(const struct bkey_packed *k,
|
static inline unsigned bkey_mantissa(const struct bkey_packed *k,
|
||||||
const struct bkey_float *f,
|
const struct bkey_float *f)
|
||||||
unsigned idx)
|
|
||||||
{
|
{
|
||||||
u64 v;
|
u64 v;
|
||||||
|
|
||||||
@ -617,7 +593,7 @@ static __always_inline void make_bfloat(struct btree *b, struct bset_tree *t,
|
|||||||
struct bkey_packed *m = tree_to_bkey(b, t, j);
|
struct bkey_packed *m = tree_to_bkey(b, t, j);
|
||||||
struct bkey_packed *l = is_power_of_2(j)
|
struct bkey_packed *l = is_power_of_2(j)
|
||||||
? min_key
|
? min_key
|
||||||
: tree_to_prev_bkey(b, t, j >> ffs(j));
|
: tree_to_bkey(b, t, j >> ffs(j));
|
||||||
struct bkey_packed *r = is_power_of_2(j + 1)
|
struct bkey_packed *r = is_power_of_2(j + 1)
|
||||||
? max_key
|
? max_key
|
||||||
: tree_to_bkey(b, t, j >> (ffz(j) + 1));
|
: tree_to_bkey(b, t, j >> (ffz(j) + 1));
|
||||||
@ -668,7 +644,7 @@ static __always_inline void make_bfloat(struct btree *b, struct bset_tree *t,
|
|||||||
EBUG_ON(shift < 0 || shift >= BFLOAT_FAILED);
|
EBUG_ON(shift < 0 || shift >= BFLOAT_FAILED);
|
||||||
|
|
||||||
f->exponent = shift;
|
f->exponent = shift;
|
||||||
mantissa = bkey_mantissa(m, f, j);
|
mantissa = bkey_mantissa(m, f);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If we've got garbage bits, set them to all 1s - it's legal for the
|
* If we've got garbage bits, set them to all 1s - it's legal for the
|
||||||
@ -690,8 +666,7 @@ static unsigned __bset_tree_capacity(struct btree *b, const struct bset_tree *t)
|
|||||||
|
|
||||||
static unsigned bset_ro_tree_capacity(struct btree *b, const struct bset_tree *t)
|
static unsigned bset_ro_tree_capacity(struct btree *b, const struct bset_tree *t)
|
||||||
{
|
{
|
||||||
return __bset_tree_capacity(b, t) /
|
return __bset_tree_capacity(b, t) / sizeof(struct bkey_float);
|
||||||
(sizeof(struct bkey_float) + sizeof(u8));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static unsigned bset_rw_tree_capacity(struct btree *b, const struct bset_tree *t)
|
static unsigned bset_rw_tree_capacity(struct btree *b, const struct bset_tree *t)
|
||||||
@ -720,7 +695,7 @@ static noinline void __build_rw_aux_tree(struct btree *b, struct bset_tree *t)
|
|||||||
|
|
||||||
static noinline void __build_ro_aux_tree(struct btree *b, struct bset_tree *t)
|
static noinline void __build_ro_aux_tree(struct btree *b, struct bset_tree *t)
|
||||||
{
|
{
|
||||||
struct bkey_packed *prev = NULL, *k = btree_bkey_first(b, t);
|
struct bkey_packed *k = btree_bkey_first(b, t);
|
||||||
struct bkey_i min_key, max_key;
|
struct bkey_i min_key, max_key;
|
||||||
unsigned cacheline = 1;
|
unsigned cacheline = 1;
|
||||||
|
|
||||||
@ -733,12 +708,12 @@ retry:
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
t->extra = (t->size - rounddown_pow_of_two(t->size - 1)) << 1;
|
t->extra = eytzinger1_extra(t->size - 1);
|
||||||
|
|
||||||
/* First we figure out where the first key in each cacheline is */
|
/* First we figure out where the first key in each cacheline is */
|
||||||
eytzinger1_for_each(j, t->size - 1) {
|
eytzinger1_for_each(j, t->size - 1) {
|
||||||
while (bkey_to_cacheline(b, t, k) < cacheline)
|
while (bkey_to_cacheline(b, t, k) < cacheline)
|
||||||
prev = k, k = bkey_p_next(k);
|
k = bkey_p_next(k);
|
||||||
|
|
||||||
if (k >= btree_bkey_last(b, t)) {
|
if (k >= btree_bkey_last(b, t)) {
|
||||||
/* XXX: this path sucks */
|
/* XXX: this path sucks */
|
||||||
@ -746,17 +721,12 @@ retry:
|
|||||||
goto retry;
|
goto retry;
|
||||||
}
|
}
|
||||||
|
|
||||||
ro_aux_tree_prev(b, t)[j] = prev->u64s;
|
|
||||||
bkey_float(b, t, j)->key_offset =
|
bkey_float(b, t, j)->key_offset =
|
||||||
bkey_to_cacheline_offset(b, t, cacheline++, k);
|
bkey_to_cacheline_offset(b, t, cacheline++, k);
|
||||||
|
|
||||||
EBUG_ON(tree_to_prev_bkey(b, t, j) != prev);
|
|
||||||
EBUG_ON(tree_to_bkey(b, t, j) != k);
|
EBUG_ON(tree_to_bkey(b, t, j) != k);
|
||||||
}
|
}
|
||||||
|
|
||||||
while (k != btree_bkey_last(b, t))
|
|
||||||
prev = k, k = bkey_p_next(k);
|
|
||||||
|
|
||||||
if (!bkey_pack_pos(bkey_to_packed(&min_key), b->data->min_key, b)) {
|
if (!bkey_pack_pos(bkey_to_packed(&min_key), b->data->min_key, b)) {
|
||||||
bkey_init(&min_key.k);
|
bkey_init(&min_key.k);
|
||||||
min_key.k.p = b->data->min_key;
|
min_key.k.p = b->data->min_key;
|
||||||
@ -999,7 +969,6 @@ static void bch2_bset_fix_lookup_table(struct btree *b,
|
|||||||
}
|
}
|
||||||
|
|
||||||
void bch2_bset_insert(struct btree *b,
|
void bch2_bset_insert(struct btree *b,
|
||||||
struct btree_node_iter *iter,
|
|
||||||
struct bkey_packed *where,
|
struct bkey_packed *where,
|
||||||
struct bkey_i *insert,
|
struct bkey_i *insert,
|
||||||
unsigned clobber_u64s)
|
unsigned clobber_u64s)
|
||||||
@ -1098,8 +1067,7 @@ static inline void prefetch_four_cachelines(void *p)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static inline bool bkey_mantissa_bits_dropped(const struct btree *b,
|
static inline bool bkey_mantissa_bits_dropped(const struct btree *b,
|
||||||
const struct bkey_float *f,
|
const struct bkey_float *f)
|
||||||
unsigned idx)
|
|
||||||
{
|
{
|
||||||
#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
|
#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
|
||||||
unsigned key_bits_start = b->format.key_u64s * 64 - b->nr_key_bits;
|
unsigned key_bits_start = b->format.key_u64s * 64 - b->nr_key_bits;
|
||||||
@ -1133,9 +1101,9 @@ static struct bkey_packed *bset_search_tree(const struct btree *b,
|
|||||||
goto slowpath;
|
goto slowpath;
|
||||||
|
|
||||||
l = f->mantissa;
|
l = f->mantissa;
|
||||||
r = bkey_mantissa(packed_search, f, n);
|
r = bkey_mantissa(packed_search, f);
|
||||||
|
|
||||||
if (unlikely(l == r) && bkey_mantissa_bits_dropped(b, f, n))
|
if (unlikely(l == r) && bkey_mantissa_bits_dropped(b, f))
|
||||||
goto slowpath;
|
goto slowpath;
|
||||||
|
|
||||||
n = n * 2 + (l < r);
|
n = n * 2 + (l < r);
|
||||||
|
@ -270,8 +270,8 @@ void bch2_bset_init_first(struct btree *, struct bset *);
|
|||||||
void bch2_bset_init_next(struct btree *, struct btree_node_entry *);
|
void bch2_bset_init_next(struct btree *, struct btree_node_entry *);
|
||||||
void bch2_bset_build_aux_tree(struct btree *, struct bset_tree *, bool);
|
void bch2_bset_build_aux_tree(struct btree *, struct bset_tree *, bool);
|
||||||
|
|
||||||
void bch2_bset_insert(struct btree *, struct btree_node_iter *,
|
void bch2_bset_insert(struct btree *, struct bkey_packed *, struct bkey_i *,
|
||||||
struct bkey_packed *, struct bkey_i *, unsigned);
|
unsigned);
|
||||||
void bch2_bset_delete(struct btree *, struct bkey_packed *, unsigned);
|
void bch2_bset_delete(struct btree *, struct bkey_packed *, unsigned);
|
||||||
|
|
||||||
/* Bkey utility code */
|
/* Bkey utility code */
|
||||||
|
@ -741,12 +741,9 @@ fsck_err:
|
|||||||
|
|
||||||
static int bch2_mark_superblocks(struct bch_fs *c)
|
static int bch2_mark_superblocks(struct bch_fs *c)
|
||||||
{
|
{
|
||||||
mutex_lock(&c->sb_lock);
|
|
||||||
gc_pos_set(c, gc_phase(GC_PHASE_sb));
|
gc_pos_set(c, gc_phase(GC_PHASE_sb));
|
||||||
|
|
||||||
int ret = bch2_trans_mark_dev_sbs_flags(c, BTREE_TRIGGER_gc);
|
return bch2_trans_mark_dev_sbs_flags(c, BTREE_TRIGGER_gc);
|
||||||
mutex_unlock(&c->sb_lock);
|
|
||||||
return ret;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void bch2_gc_free(struct bch_fs *c)
|
static void bch2_gc_free(struct bch_fs *c)
|
||||||
|
@ -836,14 +836,13 @@ fsck_err:
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int bset_key_invalid(struct bch_fs *c, struct btree *b,
|
static int bset_key_validate(struct bch_fs *c, struct btree *b,
|
||||||
struct bkey_s_c k,
|
struct bkey_s_c k,
|
||||||
bool updated_range, int rw,
|
bool updated_range, int rw)
|
||||||
struct printbuf *err)
|
|
||||||
{
|
{
|
||||||
return __bch2_bkey_invalid(c, k, btree_node_type(b), READ, err) ?:
|
return __bch2_bkey_validate(c, k, btree_node_type(b), 0) ?:
|
||||||
(!updated_range ? bch2_bkey_in_btree_node(c, b, k, err) : 0) ?:
|
(!updated_range ? bch2_bkey_in_btree_node(c, b, k, 0) : 0) ?:
|
||||||
(rw == WRITE ? bch2_bkey_val_invalid(c, k, READ, err) : 0);
|
(rw == WRITE ? bch2_bkey_val_validate(c, k, 0) : 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool bkey_packed_valid(struct bch_fs *c, struct btree *b,
|
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))
|
if (!bkeyp_u64s_valid(&b->format, k))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
struct printbuf buf = PRINTBUF;
|
|
||||||
struct bkey tmp;
|
struct bkey tmp;
|
||||||
struct bkey_s u = __bkey_disassemble(b, k, &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);
|
return !__bch2_bkey_validate(c, u.s_c, btree_node_type(b), BCH_VALIDATE_silent);
|
||||||
printbuf_exit(&buf);
|
|
||||||
return ret;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int validate_bset_keys(struct bch_fs *c, struct btree *b,
|
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);
|
u = __bkey_disassemble(b, k, &tmp);
|
||||||
|
|
||||||
printbuf_reset(&buf);
|
ret = bset_key_validate(c, b, u.s_c, updated_range, write);
|
||||||
if (bset_key_invalid(c, b, u.s_c, updated_range, write, &buf)) {
|
if (ret == -BCH_ERR_fsck_delete_bkey)
|
||||||
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);
|
|
||||||
goto drop_this_key;
|
goto drop_this_key;
|
||||||
}
|
if (ret)
|
||||||
|
goto fsck_err;
|
||||||
|
|
||||||
if (write)
|
if (write)
|
||||||
bch2_bkey_compat(b->c.level, b->c.btree_id, version,
|
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 tmp;
|
||||||
struct bkey_s u = __bkey_disassemble(b, k, &tmp);
|
struct bkey_s u = __bkey_disassemble(b, k, &tmp);
|
||||||
|
|
||||||
printbuf_reset(&buf);
|
ret = bch2_bkey_val_validate(c, u.s_c, READ);
|
||||||
|
if (ret == -BCH_ERR_fsck_delete_bkey ||
|
||||||
if (bch2_bkey_val_invalid(c, u.s_c, READ, &buf) ||
|
|
||||||
(bch2_inject_invalid_keys &&
|
(bch2_inject_invalid_keys &&
|
||||||
!bversion_cmp(u.k->version, MAX_VERSION))) {
|
!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);
|
btree_keys_account_key_drop(&b->nr, 0, k);
|
||||||
|
|
||||||
i->u64s = cpu_to_le16(le16_to_cpu(i->u64s) - k->u64s);
|
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);
|
set_btree_bset_end(b, b->set);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
if (ret)
|
||||||
|
goto fsck_err;
|
||||||
|
|
||||||
if (u.k->type == KEY_TYPE_btree_ptr_v2) {
|
if (u.k->type == KEY_TYPE_btree_ptr_v2) {
|
||||||
struct bkey_s_btree_ptr_v2 bp = bkey_s_to_btree_ptr_v2(u);
|
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);
|
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);
|
bch2_btree_node_read(trans, b, true);
|
||||||
|
|
||||||
if (btree_node_read_error(b)) {
|
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,
|
static int validate_bset_for_write(struct bch_fs *c, struct btree *b,
|
||||||
struct bset *i, unsigned sectors)
|
struct bset *i, unsigned sectors)
|
||||||
{
|
{
|
||||||
struct printbuf buf = PRINTBUF;
|
|
||||||
bool saw_error;
|
bool saw_error;
|
||||||
int ret;
|
|
||||||
|
|
||||||
ret = bch2_bkey_invalid(c, bkey_i_to_s_c(&b->key),
|
int ret = bch2_bkey_validate(c, bkey_i_to_s_c(&b->key),
|
||||||
BKEY_TYPE_btree, WRITE, &buf);
|
BKEY_TYPE_btree, WRITE);
|
||||||
|
if (ret) {
|
||||||
if (ret)
|
bch2_fs_inconsistent(c, "invalid btree node key before write");
|
||||||
bch2_fs_inconsistent(c, "invalid btree node key before write: %s", buf.buf);
|
|
||||||
printbuf_exit(&buf);
|
|
||||||
if (ret)
|
|
||||||
return ret;
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
ret = validate_bset_keys(c, b, i, WRITE, false, &saw_error) ?:
|
ret = validate_bset_keys(c, b, i, WRITE, false, &saw_error) ?:
|
||||||
validate_bset(c, NULL, b, i, b->written, sectors, WRITE, false, &saw_error);
|
validate_bset(c, NULL, b, i, b->written, sectors, WRITE, false, &saw_error);
|
||||||
|
@ -497,11 +497,6 @@ int bch2_btree_path_traverse_cached(struct btree_trans *trans, struct btree_path
|
|||||||
|
|
||||||
path->l[1].b = NULL;
|
path->l[1].b = NULL;
|
||||||
|
|
||||||
if (bch2_btree_node_relock_notrace(trans, path, 0)) {
|
|
||||||
path->uptodate = BTREE_ITER_UPTODATE;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int ret;
|
int ret;
|
||||||
do {
|
do {
|
||||||
ret = btree_path_traverse_cached_fast(trans, path);
|
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);
|
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_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 nr_keys = atomic_long_read(&c->btree_key_cache.nr_keys);
|
||||||
size_t max_dirty = 4096 + (nr_keys * 3) / 4;
|
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 *,
|
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);
|
bch_verbose(c, "%s(): recovering %s", __func__, buf.buf);
|
||||||
printbuf_exit(&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);
|
ret = bch2_journal_key_insert(c, btree, level + 1, &tmp.k);
|
||||||
if (ret)
|
if (ret)
|
||||||
|
@ -214,7 +214,7 @@ bool bch2_btree_bset_insert_key(struct btree_trans *trans,
|
|||||||
|
|
||||||
k = bch2_btree_node_iter_bset_pos(node_iter, b, bset_tree_last(b));
|
k = bch2_btree_node_iter_bset_pos(node_iter, b, bset_tree_last(b));
|
||||||
overwrite:
|
overwrite:
|
||||||
bch2_bset_insert(b, node_iter, k, insert, clobber_u64s);
|
bch2_bset_insert(b, k, insert, clobber_u64s);
|
||||||
new_u64s = k->u64s;
|
new_u64s = k->u64s;
|
||||||
fix_iter:
|
fix_iter:
|
||||||
if (clobber_u64s != new_u64s)
|
if (clobber_u64s != new_u64s)
|
||||||
@ -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,
|
a->k.version = journal_pos_to_bversion(&trans->journal_res,
|
||||||
(u64 *) entry - (u64 *) trans->journal_entries);
|
(u64 *) entry - (u64 *) trans->journal_entries);
|
||||||
BUG_ON(bversion_zero(a->k.version));
|
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)
|
if (ret)
|
||||||
goto revert_fs_usage;
|
goto revert_fs_usage;
|
||||||
}
|
}
|
||||||
@ -798,7 +798,7 @@ revert_fs_usage:
|
|||||||
struct bkey_s_accounting a = bkey_i_to_s_accounting(entry2->start);
|
struct bkey_s_accounting a = bkey_i_to_s_accounting(entry2->start);
|
||||||
|
|
||||||
bch2_accounting_neg(a);
|
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);
|
bch2_accounting_neg(a);
|
||||||
}
|
}
|
||||||
percpu_up_read(&c->mark_lock);
|
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);
|
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,
|
static int bch2_trans_commit_journal_pin_flush(struct journal *j,
|
||||||
struct journal_entry_pin *_pin, u64 seq)
|
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)
|
static int journal_reclaim_wait_done(struct bch_fs *c)
|
||||||
{
|
{
|
||||||
int ret = bch2_journal_error(&c->journal) ?:
|
int ret = bch2_journal_error(&c->journal) ?:
|
||||||
!bch2_btree_key_cache_must_wait(c);
|
bch2_btree_key_cache_wait_done(c);
|
||||||
|
|
||||||
if (!ret)
|
if (!ret)
|
||||||
journal_reclaim_kick(&c->journal);
|
journal_reclaim_kick(&c->journal);
|
||||||
@ -973,9 +929,13 @@ int bch2_trans_commit_error(struct btree_trans *trans, unsigned flags,
|
|||||||
bch2_trans_unlock(trans);
|
bch2_trans_unlock(trans);
|
||||||
|
|
||||||
trace_and_count(c, trans_blocked_journal_reclaim, trans, trace_ip);
|
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,
|
wait_event_freezable(c->journal.reclaim_wait,
|
||||||
(ret = journal_reclaim_wait_done(c)));
|
(ret = journal_reclaim_wait_done(c)));
|
||||||
|
|
||||||
|
track_event_change(&c->times[BCH_TIME_blocked_key_cache_flush], false);
|
||||||
|
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@ -1060,20 +1020,19 @@ int __bch2_trans_commit(struct btree_trans *trans, unsigned flags)
|
|||||||
goto out_reset;
|
goto out_reset;
|
||||||
|
|
||||||
trans_for_each_update(trans, i) {
|
trans_for_each_update(trans, i) {
|
||||||
struct printbuf buf = PRINTBUF;
|
|
||||||
enum bch_validate_flags invalid_flags = 0;
|
enum bch_validate_flags invalid_flags = 0;
|
||||||
|
|
||||||
if (!(flags & BCH_TRANS_COMMIT_no_journal_res))
|
if (!(flags & BCH_TRANS_COMMIT_no_journal_res))
|
||||||
invalid_flags |= BCH_VALIDATE_write|BCH_VALIDATE_commit;
|
invalid_flags |= BCH_VALIDATE_write|BCH_VALIDATE_commit;
|
||||||
|
|
||||||
if (unlikely(bch2_bkey_invalid(c, bkey_i_to_s_c(i->k),
|
ret = bch2_bkey_validate(c, bkey_i_to_s_c(i->k),
|
||||||
i->bkey_type, invalid_flags, &buf)))
|
i->bkey_type, invalid_flags);
|
||||||
ret = bch2_trans_commit_bkey_invalid(trans, invalid_flags, i, &buf);
|
if (unlikely(ret)){
|
||||||
btree_insert_entry_checks(trans, i);
|
bch2_trans_inconsistent(trans, "invalid bkey on insert from %s -> %ps\n",
|
||||||
printbuf_exit(&buf);
|
trans->fn, (void *) i->ip_allocated);
|
||||||
|
|
||||||
if (ret)
|
|
||||||
return ret;
|
return ret;
|
||||||
|
}
|
||||||
|
btree_insert_entry_checks(trans, i);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (struct jset_entry *i = trans->journal_entries;
|
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))
|
if (!(flags & BCH_TRANS_COMMIT_no_journal_res))
|
||||||
invalid_flags |= BCH_VALIDATE_write|BCH_VALIDATE_commit;
|
invalid_flags |= BCH_VALIDATE_write|BCH_VALIDATE_commit;
|
||||||
|
|
||||||
if (unlikely(bch2_journal_entry_validate(c, NULL, i,
|
ret = bch2_journal_entry_validate(c, NULL, i,
|
||||||
bcachefs_metadata_version_current,
|
bcachefs_metadata_version_current,
|
||||||
CPU_BIG_ENDIAN, invalid_flags)))
|
CPU_BIG_ENDIAN, invalid_flags);
|
||||||
ret = bch2_trans_commit_journal_entry_invalid(trans, i);
|
if (unlikely(ret)) {
|
||||||
|
bch2_trans_inconsistent(trans, "invalid journal entry on insert from %s\n",
|
||||||
if (ret)
|
trans->fn);
|
||||||
return ret;
|
return ret;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (unlikely(!test_bit(BCH_FS_may_go_rw, &c->flags))) {
|
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)))
|
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);
|
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),
|
if (bch2_bkey_validate(c, bkey_i_to_s_c(insert),
|
||||||
btree_node_type(b), WRITE, &buf) ?:
|
btree_node_type(b), BCH_VALIDATE_write) ?:
|
||||||
bch2_bkey_in_btree_node(c, b, bkey_i_to_s_c(insert), &buf)) {
|
bch2_bkey_in_btree_node(c, b, bkey_i_to_s_c(insert), BCH_VALIDATE_write)) {
|
||||||
printbuf_reset(&buf);
|
bch2_fs_inconsistent(c, "%s: inserting invalid bkey", __func__);
|
||||||
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);
|
|
||||||
dump_stack();
|
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);
|
ret = bch2_disk_accounting_mod(trans, &acc_btree_key, &replicas_sectors, 1, gc);
|
||||||
if (ret)
|
if (ret)
|
||||||
return 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)) {
|
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,
|
enum bch_data_type type,
|
||||||
unsigned sectors)
|
unsigned sectors)
|
||||||
{
|
{
|
||||||
struct bch_fs *c = trans->c;
|
|
||||||
struct btree_iter iter;
|
struct btree_iter iter;
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
|
|
||||||
@ -911,7 +924,7 @@ static int __bch2_trans_mark_metadata_bucket(struct btree_trans *trans,
|
|||||||
return PTR_ERR(a);
|
return PTR_ERR(a);
|
||||||
|
|
||||||
if (a->v.data_type && type && a->v.data_type != type) {
|
if (a->v.data_type && type && a->v.data_type != type) {
|
||||||
bch2_fsck_err(c, FSCK_CAN_IGNORE|FSCK_NEED_FSCK,
|
bch2_fsck_err(trans, FSCK_CAN_IGNORE|FSCK_NEED_FSCK,
|
||||||
bucket_metadata_type_mismatch,
|
bucket_metadata_type_mismatch,
|
||||||
"bucket %llu:%llu gen %u different types of data in same bucket: %s, %s\n"
|
"bucket %llu:%llu gen %u different types of data in same bucket: %s, %s\n"
|
||||||
"while marking %s",
|
"while marking %s",
|
||||||
@ -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,
|
static int __bch2_trans_mark_dev_sb(struct btree_trans *trans, struct bch_dev *ca,
|
||||||
enum btree_iter_update_trigger_flags flags)
|
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;
|
u64 bucket = 0;
|
||||||
unsigned i, bucket_sectors = 0;
|
unsigned i, bucket_sectors = 0;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
for (i = 0; i < layout->nr_superblocks; i++) {
|
for (i = 0; i < layout.nr_superblocks; i++) {
|
||||||
u64 offset = le64_to_cpu(layout->sb_offset[i]);
|
u64 offset = le64_to_cpu(layout.sb_offset[i]);
|
||||||
|
|
||||||
if (offset == BCH_SB_SECTOR) {
|
if (offset == BCH_SB_SECTOR) {
|
||||||
ret = bch2_trans_mark_metadata_sectors(trans, ca,
|
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,
|
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);
|
BCH_DATA_sb, &bucket, &bucket_sectors, flags);
|
||||||
if (ret)
|
if (ret)
|
||||||
return 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,
|
.dev_bucket = (u64) dev << 56 | bucket,
|
||||||
.journal_seq = journal_seq,
|
.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;
|
int ret = 0;
|
||||||
|
|
||||||
mutex_lock(&b->lock);
|
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++)
|
for (i = 0; i < size; i++)
|
||||||
nr_elements += t->d[i].journal_seq > flushed_seq;
|
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);
|
n = kvmalloc(sizeof(*n) + (sizeof(n->d[0]) << new_bits), GFP_KERNEL);
|
||||||
if (!n) {
|
if (!n) {
|
||||||
@ -115,7 +115,14 @@ int bch2_set_bucket_needs_journal_commit(struct buckets_waiting_for_journal *b,
|
|||||||
}
|
}
|
||||||
|
|
||||||
retry_rehash:
|
retry_rehash:
|
||||||
|
if (nr_rehashes_this_size == 3) {
|
||||||
|
new_bits++;
|
||||||
|
nr_rehashes_this_size = 0;
|
||||||
|
}
|
||||||
|
|
||||||
nr_rehashes++;
|
nr_rehashes++;
|
||||||
|
nr_rehashes_this_size++;
|
||||||
|
|
||||||
bucket_table_init(n, new_bits);
|
bucket_table_init(n, new_bits);
|
||||||
|
|
||||||
tmp = new;
|
tmp = new;
|
||||||
|
@ -250,10 +250,8 @@ restart_drop_extra_replicas:
|
|||||||
* it's been hard to reproduce, so this should give us some more
|
* it's been hard to reproduce, so this should give us some more
|
||||||
* information when it does occur:
|
* information when it does occur:
|
||||||
*/
|
*/
|
||||||
struct printbuf err = PRINTBUF;
|
int invalid = bch2_bkey_validate(c, bkey_i_to_s_c(insert), __btree_node_type(0, m->btree_id),
|
||||||
int invalid = bch2_bkey_invalid(c, bkey_i_to_s_c(insert), __btree_node_type(0, m->btree_id), 0, &err);
|
BCH_VALIDATE_commit);
|
||||||
printbuf_exit(&err);
|
|
||||||
|
|
||||||
if (invalid) {
|
if (invalid) {
|
||||||
struct printbuf buf = PRINTBUF;
|
struct printbuf buf = PRINTBUF;
|
||||||
|
|
||||||
|
@ -100,20 +100,19 @@ const struct bch_hash_desc bch2_dirent_hash_desc = {
|
|||||||
.is_visible = dirent_is_visible,
|
.is_visible = dirent_is_visible,
|
||||||
};
|
};
|
||||||
|
|
||||||
int bch2_dirent_invalid(struct bch_fs *c, struct bkey_s_c k,
|
int bch2_dirent_validate(struct bch_fs *c, struct bkey_s_c k,
|
||||||
enum bch_validate_flags flags,
|
enum bch_validate_flags flags)
|
||||||
struct printbuf *err)
|
|
||||||
{
|
{
|
||||||
struct bkey_s_c_dirent d = bkey_s_c_to_dirent(k);
|
struct bkey_s_c_dirent d = bkey_s_c_to_dirent(k);
|
||||||
struct qstr d_name = bch2_dirent_get_name(d);
|
struct qstr d_name = bch2_dirent_get_name(d);
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
|
|
||||||
bkey_fsck_err_on(!d_name.len, c, err,
|
bkey_fsck_err_on(!d_name.len,
|
||||||
dirent_empty_name,
|
c, dirent_empty_name,
|
||||||
"empty name");
|
"empty name");
|
||||||
|
|
||||||
bkey_fsck_err_on(bkey_val_u64s(k.k) > dirent_val_u64s(d_name.len), c, err,
|
bkey_fsck_err_on(bkey_val_u64s(k.k) > dirent_val_u64s(d_name.len),
|
||||||
dirent_val_too_big,
|
c, dirent_val_too_big,
|
||||||
"value too big (%zu > %u)",
|
"value too big (%zu > %u)",
|
||||||
bkey_val_u64s(k.k), dirent_val_u64s(d_name.len));
|
bkey_val_u64s(k.k), dirent_val_u64s(d_name.len));
|
||||||
|
|
||||||
@ -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
|
* Check new keys don't exceed the max length
|
||||||
* (older keys may be larger.)
|
* (older keys may be larger.)
|
||||||
*/
|
*/
|
||||||
bkey_fsck_err_on((flags & BCH_VALIDATE_commit) && d_name.len > BCH_NAME_MAX, c, err,
|
bkey_fsck_err_on((flags & BCH_VALIDATE_commit) && d_name.len > BCH_NAME_MAX,
|
||||||
dirent_name_too_long,
|
c, dirent_name_too_long,
|
||||||
"dirent name too big (%u > %u)",
|
"dirent name too big (%u > %u)",
|
||||||
d_name.len, BCH_NAME_MAX);
|
d_name.len, BCH_NAME_MAX);
|
||||||
|
|
||||||
bkey_fsck_err_on(d_name.len != strnlen(d_name.name, d_name.len), c, err,
|
bkey_fsck_err_on(d_name.len != strnlen(d_name.name, d_name.len),
|
||||||
dirent_name_embedded_nul,
|
c, dirent_name_embedded_nul,
|
||||||
"dirent has stray data after name's NUL");
|
"dirent has stray data after name's NUL");
|
||||||
|
|
||||||
bkey_fsck_err_on((d_name.len == 1 && !memcmp(d_name.name, ".", 1)) ||
|
bkey_fsck_err_on((d_name.len == 1 && !memcmp(d_name.name, ".", 1)) ||
|
||||||
(d_name.len == 2 && !memcmp(d_name.name, "..", 2)), c, err,
|
(d_name.len == 2 && !memcmp(d_name.name, "..", 2)),
|
||||||
dirent_name_dot_or_dotdot,
|
c, dirent_name_dot_or_dotdot,
|
||||||
"invalid name");
|
"invalid name");
|
||||||
|
|
||||||
bkey_fsck_err_on(memchr(d_name.name, '/', d_name.len), c, err,
|
bkey_fsck_err_on(memchr(d_name.name, '/', d_name.len),
|
||||||
dirent_name_has_slash,
|
c, dirent_name_has_slash,
|
||||||
"name with /");
|
"name with /");
|
||||||
|
|
||||||
bkey_fsck_err_on(d.v->d_type != DT_SUBVOL &&
|
bkey_fsck_err_on(d.v->d_type != DT_SUBVOL &&
|
||||||
le64_to_cpu(d.v->d_inum) == d.k->p.inode, c, err,
|
le64_to_cpu(d.v->d_inum) == d.k->p.inode,
|
||||||
dirent_to_itself,
|
c, dirent_to_itself,
|
||||||
"dirent points to own directory");
|
"dirent points to own directory");
|
||||||
fsck_err:
|
fsck_err:
|
||||||
return ret;
|
return ret;
|
||||||
|
@ -7,12 +7,11 @@
|
|||||||
enum bch_validate_flags;
|
enum bch_validate_flags;
|
||||||
extern const struct bch_hash_desc bch2_dirent_hash_desc;
|
extern const struct bch_hash_desc bch2_dirent_hash_desc;
|
||||||
|
|
||||||
int bch2_dirent_invalid(struct bch_fs *, struct bkey_s_c,
|
int bch2_dirent_validate(struct bch_fs *, struct bkey_s_c, enum bch_validate_flags);
|
||||||
enum bch_validate_flags, struct printbuf *);
|
|
||||||
void bch2_dirent_to_text(struct printbuf *, struct bch_fs *, struct bkey_s_c);
|
void bch2_dirent_to_text(struct printbuf *, struct bch_fs *, struct bkey_s_c);
|
||||||
|
|
||||||
#define bch2_bkey_ops_dirent ((struct bkey_ops) { \
|
#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, \
|
.val_to_text = bch2_dirent_to_text, \
|
||||||
.min_val_size = 16, \
|
.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))
|
#define field_end(p, member) (((void *) (&p.member)) + sizeof(p.member))
|
||||||
|
|
||||||
int bch2_accounting_invalid(struct bch_fs *c, struct bkey_s_c k,
|
int bch2_accounting_validate(struct bch_fs *c, struct bkey_s_c k,
|
||||||
enum bch_validate_flags flags,
|
enum bch_validate_flags flags)
|
||||||
struct printbuf *err)
|
|
||||||
{
|
{
|
||||||
struct disk_accounting_pos acc_k;
|
struct disk_accounting_pos acc_k;
|
||||||
bpos_to_disk_accounting_pos(&acc_k, k.k->p);
|
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;
|
break;
|
||||||
case BCH_DISK_ACCOUNTING_replicas:
|
case BCH_DISK_ACCOUNTING_replicas:
|
||||||
bkey_fsck_err_on(!acc_k.replicas.nr_devs,
|
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");
|
"accounting key replicas entry with nr_devs=0");
|
||||||
|
|
||||||
bkey_fsck_err_on(acc_k.replicas.nr_required > acc_k.replicas.nr_devs ||
|
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 > 1 &&
|
||||||
acc_k.replicas.nr_required == acc_k.replicas.nr_devs),
|
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");
|
"accounting key replicas entry with bad nr_required");
|
||||||
|
|
||||||
for (unsigned i = 0; i + 1 < acc_k.replicas.nr_devs; i++)
|
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],
|
bkey_fsck_err_on(acc_k.replicas.devs[i] >= acc_k.replicas.devs[i + 1],
|
||||||
c, err, accounting_key_replicas_devs_unsorted,
|
c, accounting_key_replicas_devs_unsorted,
|
||||||
"accounting key replicas entry with unsorted devs");
|
"accounting key replicas entry with unsorted devs");
|
||||||
|
|
||||||
end = (void *) &acc_k.replicas + replicas_entry_bytes(&acc_k.replicas);
|
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)),
|
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");
|
"junk at end of accounting key");
|
||||||
fsck_err:
|
fsck_err:
|
||||||
return ret;
|
return ret;
|
||||||
@ -528,6 +527,9 @@ int bch2_gc_accounting_done(struct bch_fs *c)
|
|||||||
struct disk_accounting_pos acc_k;
|
struct disk_accounting_pos acc_k;
|
||||||
bpos_to_disk_accounting_pos(&acc_k, e->pos);
|
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 src_v[BCH_ACCOUNTING_MAX_COUNTERS];
|
||||||
u64 dst_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;
|
struct { __BKEY_PADDED(k, BCH_ACCOUNTING_MAX_COUNTERS); } k_i;
|
||||||
|
|
||||||
accounting_key_init(&k_i.k, &acc_k, src_v, nr);
|
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();
|
preempt_disable();
|
||||||
struct bch_fs_usage_base *dst = this_cpu_ptr(c->usage);
|
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;
|
return 0;
|
||||||
|
|
||||||
percpu_down_read(&c->mark_lock);
|
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);
|
percpu_up_read(&c->mark_lock);
|
||||||
|
|
||||||
if (bch2_accounting_key_is_zero(bkey_s_c_to_accounting(k)) &&
|
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);
|
struct bkey_s_c_accounting a = bkey_s_c_to_accounting(k);
|
||||||
unsigned nr = bch2_accounting_counters(k.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);
|
bch2_accounting_mem_read(c, k.k->p, v, nr);
|
||||||
|
|
||||||
if (memcmp(a.v->d, v, nr * sizeof(u64))) {
|
if (memcmp(a.v->d, v, nr * sizeof(u64))) {
|
||||||
@ -775,9 +786,6 @@ void bch2_verify_accounting_clean(struct bch_fs *c)
|
|||||||
mismatch = true;
|
mismatch = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct disk_accounting_pos acc_k;
|
|
||||||
bpos_to_disk_accounting_pos(&acc_k, a.k->p);
|
|
||||||
|
|
||||||
switch (acc_k.type) {
|
switch (acc_k.type) {
|
||||||
case BCH_DISK_ACCOUNTING_persistent_reserved:
|
case BCH_DISK_ACCOUNTING_persistent_reserved:
|
||||||
base.reserved += acc_k.persistent_reserved.nr_replicas * a.v->d[0];
|
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);
|
s64 *, unsigned, bool);
|
||||||
int bch2_mod_dev_cached_sectors(struct btree_trans *, unsigned, s64, bool);
|
int bch2_mod_dev_cached_sectors(struct btree_trans *, unsigned, s64, bool);
|
||||||
|
|
||||||
int bch2_accounting_invalid(struct bch_fs *, struct bkey_s_c,
|
int bch2_accounting_validate(struct bch_fs *, struct bkey_s_c, enum bch_validate_flags);
|
||||||
enum bch_validate_flags, struct printbuf *);
|
|
||||||
void bch2_accounting_key_to_text(struct printbuf *, struct disk_accounting_pos *);
|
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_to_text(struct printbuf *, struct bch_fs *, struct bkey_s_c);
|
||||||
void bch2_accounting_swab(struct bkey_s);
|
void bch2_accounting_swab(struct bkey_s);
|
||||||
|
|
||||||
#define bch2_bkey_ops_accounting ((struct bkey_ops) { \
|
#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, \
|
.val_to_text = bch2_accounting_to_text, \
|
||||||
.swab = bch2_accounting_swab, \
|
.swab = bch2_accounting_swab, \
|
||||||
.min_val_size = 8, \
|
.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);
|
int bch2_accounting_mem_insert(struct bch_fs *, struct bkey_s_c_accounting, bool);
|
||||||
void bch2_accounting_mem_gc(struct bch_fs *);
|
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;
|
struct bch_accounting_mem *acc = &c->accounting;
|
||||||
unsigned idx;
|
unsigned idx;
|
||||||
|
|
||||||
@ -130,45 +161,10 @@ static inline int __bch2_accounting_mem_mod(struct bch_fs *c, struct bkey_s_c_ac
|
|||||||
return 0;
|
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)
|
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);
|
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);
|
percpu_up_read(&trans->c->mark_lock);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
@ -103,7 +103,8 @@ static inline bool data_type_is_hidden(enum bch_data_type type)
|
|||||||
x(compression, 4) \
|
x(compression, 4) \
|
||||||
x(snapshot, 5) \
|
x(snapshot, 5) \
|
||||||
x(btree, 6) \
|
x(btree, 6) \
|
||||||
x(rebalance_work, 7)
|
x(rebalance_work, 7) \
|
||||||
|
x(inum, 8)
|
||||||
|
|
||||||
enum disk_accounting_type {
|
enum disk_accounting_type {
|
||||||
#define x(f, nr) BCH_DISK_ACCOUNTING_##f = nr,
|
#define x(f, nr) BCH_DISK_ACCOUNTING_##f = nr,
|
||||||
@ -136,6 +137,10 @@ struct bch_acct_btree {
|
|||||||
__u32 id;
|
__u32 id;
|
||||||
} __packed;
|
} __packed;
|
||||||
|
|
||||||
|
struct bch_acct_inum {
|
||||||
|
__u64 inum;
|
||||||
|
} __packed;
|
||||||
|
|
||||||
struct bch_acct_rebalance_work {
|
struct bch_acct_rebalance_work {
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -152,6 +157,7 @@ struct disk_accounting_pos {
|
|||||||
struct bch_acct_snapshot snapshot;
|
struct bch_acct_snapshot snapshot;
|
||||||
struct bch_acct_btree btree;
|
struct bch_acct_btree btree;
|
||||||
struct bch_acct_rebalance_work rebalance_work;
|
struct bch_acct_rebalance_work rebalance_work;
|
||||||
|
struct bch_acct_inum inum;
|
||||||
} __packed;
|
} __packed;
|
||||||
} __packed;
|
} __packed;
|
||||||
struct bpos _pad;
|
struct bpos _pad;
|
||||||
|
@ -107,24 +107,23 @@ struct ec_bio {
|
|||||||
|
|
||||||
/* Stripes btree keys: */
|
/* Stripes btree keys: */
|
||||||
|
|
||||||
int bch2_stripe_invalid(struct bch_fs *c, struct bkey_s_c k,
|
int bch2_stripe_validate(struct bch_fs *c, struct bkey_s_c k,
|
||||||
enum bch_validate_flags flags,
|
enum bch_validate_flags flags)
|
||||||
struct printbuf *err)
|
|
||||||
{
|
{
|
||||||
const struct bch_stripe *s = bkey_s_c_to_stripe(k).v;
|
const struct bch_stripe *s = bkey_s_c_to_stripe(k).v;
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
|
|
||||||
bkey_fsck_err_on(bkey_eq(k.k->p, POS_MIN) ||
|
bkey_fsck_err_on(bkey_eq(k.k->p, POS_MIN) ||
|
||||||
bpos_gt(k.k->p, POS(0, U32_MAX)), c, err,
|
bpos_gt(k.k->p, POS(0, U32_MAX)),
|
||||||
stripe_pos_bad,
|
c, stripe_pos_bad,
|
||||||
"stripe at bad pos");
|
"stripe at bad pos");
|
||||||
|
|
||||||
bkey_fsck_err_on(bkey_val_u64s(k.k) < stripe_val_u64s(s), c, err,
|
bkey_fsck_err_on(bkey_val_u64s(k.k) < stripe_val_u64s(s),
|
||||||
stripe_val_size_bad,
|
c, stripe_val_size_bad,
|
||||||
"incorrect value size (%zu < %u)",
|
"incorrect value size (%zu < %u)",
|
||||||
bkey_val_u64s(k.k), stripe_val_u64s(s));
|
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:
|
fsck_err:
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
@ -8,8 +8,7 @@
|
|||||||
|
|
||||||
enum bch_validate_flags;
|
enum bch_validate_flags;
|
||||||
|
|
||||||
int bch2_stripe_invalid(struct bch_fs *, struct bkey_s_c,
|
int bch2_stripe_validate(struct bch_fs *, struct bkey_s_c, enum bch_validate_flags);
|
||||||
enum bch_validate_flags, struct printbuf *);
|
|
||||||
void bch2_stripe_to_text(struct printbuf *, struct bch_fs *,
|
void bch2_stripe_to_text(struct printbuf *, struct bch_fs *,
|
||||||
struct bkey_s_c);
|
struct bkey_s_c);
|
||||||
int bch2_trigger_stripe(struct btree_trans *, enum btree_id, unsigned,
|
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);
|
enum btree_iter_update_trigger_flags);
|
||||||
|
|
||||||
#define bch2_bkey_ops_stripe ((struct bkey_ops) { \
|
#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, \
|
.val_to_text = bch2_stripe_to_text, \
|
||||||
.swab = bch2_ptr_swab, \
|
.swab = bch2_ptr_swab, \
|
||||||
.trigger = bch2_trigger_stripe, \
|
.trigger = bch2_trigger_stripe, \
|
||||||
|
@ -145,6 +145,7 @@
|
|||||||
x(BCH_ERR_transaction_restart, transaction_restart_journal_preres_get) \
|
x(BCH_ERR_transaction_restart, transaction_restart_journal_preres_get) \
|
||||||
x(BCH_ERR_transaction_restart, transaction_restart_split_race) \
|
x(BCH_ERR_transaction_restart, transaction_restart_split_race) \
|
||||||
x(BCH_ERR_transaction_restart, transaction_restart_write_buffer_flush) \
|
x(BCH_ERR_transaction_restart, transaction_restart_write_buffer_flush) \
|
||||||
|
x(BCH_ERR_transaction_restart, transaction_restart_freeing_inode) \
|
||||||
x(BCH_ERR_transaction_restart, transaction_restart_nested) \
|
x(BCH_ERR_transaction_restart, transaction_restart_nested) \
|
||||||
x(0, no_btree_node) \
|
x(0, no_btree_node) \
|
||||||
x(BCH_ERR_no_btree_node, no_btree_node_relock) \
|
x(BCH_ERR_no_btree_node, no_btree_node_relock) \
|
||||||
@ -166,6 +167,7 @@
|
|||||||
x(0, journal_reclaim_would_deadlock) \
|
x(0, journal_reclaim_would_deadlock) \
|
||||||
x(EINVAL, fsck) \
|
x(EINVAL, fsck) \
|
||||||
x(BCH_ERR_fsck, fsck_fix) \
|
x(BCH_ERR_fsck, fsck_fix) \
|
||||||
|
x(BCH_ERR_fsck, fsck_delete_bkey) \
|
||||||
x(BCH_ERR_fsck, fsck_ignore) \
|
x(BCH_ERR_fsck, fsck_ignore) \
|
||||||
x(BCH_ERR_fsck, fsck_errors_not_fixed) \
|
x(BCH_ERR_fsck, fsck_errors_not_fixed) \
|
||||||
x(BCH_ERR_fsck, fsck_repair_unimplemented) \
|
x(BCH_ERR_fsck, fsck_repair_unimplemented) \
|
||||||
|
@ -416,6 +416,28 @@ err:
|
|||||||
return ret;
|
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)
|
void bch2_flush_fsck_errs(struct bch_fs *c)
|
||||||
{
|
{
|
||||||
struct fsck_err_state *s, *n;
|
struct fsck_err_state *s, *n;
|
||||||
|
@ -4,6 +4,7 @@
|
|||||||
|
|
||||||
#include <linux/list.h>
|
#include <linux/list.h>
|
||||||
#include <linux/printk.h>
|
#include <linux/printk.h>
|
||||||
|
#include "bkey_types.h"
|
||||||
#include "sb-errors.h"
|
#include "sb-errors.h"
|
||||||
|
|
||||||
struct bch_dev;
|
struct bch_dev;
|
||||||
@ -166,24 +167,30 @@ void bch2_flush_fsck_errs(struct bch_fs *);
|
|||||||
#define fsck_err_on(cond, c, _err_type, ...) \
|
#define fsck_err_on(cond, c, _err_type, ...) \
|
||||||
__fsck_err_on(cond, c, FSCK_CAN_FIX|FSCK_CAN_IGNORE, _err_type, __VA_ARGS__)
|
__fsck_err_on(cond, c, FSCK_CAN_FIX|FSCK_CAN_IGNORE, _err_type, __VA_ARGS__)
|
||||||
|
|
||||||
__printf(4, 0)
|
__printf(5, 6)
|
||||||
static inline void bch2_bkey_fsck_err(struct bch_fs *c,
|
int __bch2_bkey_fsck_err(struct bch_fs *,
|
||||||
struct printbuf *err_msg,
|
struct bkey_s_c,
|
||||||
enum bch_sb_error_id err_type,
|
enum bch_fsck_flags,
|
||||||
const char *fmt, ...)
|
enum bch_sb_error_id,
|
||||||
{
|
const char *, ...);
|
||||||
va_list args;
|
|
||||||
|
|
||||||
va_start(args, fmt);
|
/*
|
||||||
prt_vprintf(err_msg, fmt, args);
|
* for now, bkey fsck errors are always handled by deleting the entire key -
|
||||||
va_end(args);
|
* this will change at some point
|
||||||
}
|
*/
|
||||||
|
#define bkey_fsck_err(c, _err_type, _err_msg, ...) \
|
||||||
#define bkey_fsck_err(c, _err_msg, _err_type, ...) \
|
|
||||||
do { \
|
do { \
|
||||||
prt_printf(_err_msg, __VA_ARGS__); \
|
if ((flags & BCH_VALIDATE_silent)) { \
|
||||||
bch2_sb_error_count(c, BCH_FSCK_ERR_##_err_type); \
|
ret = -BCH_ERR_fsck_delete_bkey; \
|
||||||
ret = -BCH_ERR_invalid_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; \
|
goto fsck_err; \
|
||||||
} while (0)
|
} 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: */
|
/* KEY_TYPE_btree_ptr: */
|
||||||
|
|
||||||
int bch2_btree_ptr_invalid(struct bch_fs *c, struct bkey_s_c k,
|
int bch2_btree_ptr_validate(struct bch_fs *c, struct bkey_s_c k,
|
||||||
enum bch_validate_flags flags,
|
enum bch_validate_flags flags)
|
||||||
struct printbuf *err)
|
|
||||||
{
|
{
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
|
|
||||||
bkey_fsck_err_on(bkey_val_u64s(k.k) > BCH_REPLICAS_MAX, c, err,
|
bkey_fsck_err_on(bkey_val_u64s(k.k) > BCH_REPLICAS_MAX,
|
||||||
btree_ptr_val_too_big,
|
c, btree_ptr_val_too_big,
|
||||||
"value too big (%zu > %u)", bkey_val_u64s(k.k), BCH_REPLICAS_MAX);
|
"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:
|
fsck_err:
|
||||||
return ret;
|
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);
|
bch2_bkey_ptrs_to_text(out, c, k);
|
||||||
}
|
}
|
||||||
|
|
||||||
int bch2_btree_ptr_v2_invalid(struct bch_fs *c, struct bkey_s_c k,
|
int bch2_btree_ptr_v2_validate(struct bch_fs *c, struct bkey_s_c k,
|
||||||
enum bch_validate_flags flags,
|
enum bch_validate_flags flags)
|
||||||
struct printbuf *err)
|
|
||||||
{
|
{
|
||||||
struct bkey_s_c_btree_ptr_v2 bp = bkey_s_c_to_btree_ptr_v2(k);
|
struct bkey_s_c_btree_ptr_v2 bp = bkey_s_c_to_btree_ptr_v2(k);
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
|
|
||||||
bkey_fsck_err_on(bkey_val_u64s(k.k) > BKEY_BTREE_PTR_VAL_U64s_MAX,
|
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)",
|
"value too big (%zu > %zu)",
|
||||||
bkey_val_u64s(k.k), BKEY_BTREE_PTR_VAL_U64s_MAX);
|
bkey_val_u64s(k.k), BKEY_BTREE_PTR_VAL_U64s_MAX);
|
||||||
|
|
||||||
bkey_fsck_err_on(bpos_ge(bp.v->min_key, bp.k->p),
|
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");
|
"min_key > key");
|
||||||
|
|
||||||
if (flags & BCH_VALIDATE_write)
|
if (flags & BCH_VALIDATE_write)
|
||||||
bkey_fsck_err_on(!bp.v->sectors_written,
|
bkey_fsck_err_on(!bp.v->sectors_written,
|
||||||
c, err, btree_ptr_v2_written_0,
|
c, btree_ptr_v2_written_0,
|
||||||
"sectors_written == 0");
|
"sectors_written == 0");
|
||||||
|
|
||||||
ret = bch2_bkey_ptrs_invalid(c, k, flags, err);
|
ret = bch2_bkey_ptrs_validate(c, k, flags);
|
||||||
fsck_err:
|
fsck_err:
|
||||||
return ret;
|
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: */
|
/* KEY_TYPE_reservation: */
|
||||||
|
|
||||||
int bch2_reservation_invalid(struct bch_fs *c, struct bkey_s_c k,
|
int bch2_reservation_validate(struct bch_fs *c, struct bkey_s_c k,
|
||||||
enum bch_validate_flags flags,
|
enum bch_validate_flags flags)
|
||||||
struct printbuf *err)
|
|
||||||
{
|
{
|
||||||
struct bkey_s_c_reservation r = bkey_s_c_to_reservation(k);
|
struct bkey_s_c_reservation r = bkey_s_c_to_reservation(k);
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
|
|
||||||
bkey_fsck_err_on(!r.v->nr_replicas || r.v->nr_replicas > BCH_REPLICAS_MAX, c, err,
|
bkey_fsck_err_on(!r.v->nr_replicas || r.v->nr_replicas > BCH_REPLICAS_MAX,
|
||||||
reservation_key_nr_replicas_invalid,
|
c, reservation_key_nr_replicas_invalid,
|
||||||
"invalid nr_replicas (%u)", r.v->nr_replicas);
|
"invalid nr_replicas (%u)", r.v->nr_replicas);
|
||||||
fsck_err:
|
fsck_err:
|
||||||
return ret;
|
return ret;
|
||||||
@ -1102,14 +1099,12 @@ void bch2_bkey_ptrs_to_text(struct printbuf *out, struct bch_fs *c,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int extent_ptr_validate(struct bch_fs *c,
|
||||||
static int extent_ptr_invalid(struct bch_fs *c,
|
struct bkey_s_c k,
|
||||||
struct bkey_s_c k,
|
enum bch_validate_flags flags,
|
||||||
enum bch_validate_flags flags,
|
const struct bch_extent_ptr *ptr,
|
||||||
const struct bch_extent_ptr *ptr,
|
unsigned size_ondisk,
|
||||||
unsigned size_ondisk,
|
bool metadata)
|
||||||
bool metadata,
|
|
||||||
struct printbuf *err)
|
|
||||||
{
|
{
|
||||||
int ret = 0;
|
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);
|
struct bkey_ptrs_c ptrs = bch2_bkey_ptrs_c(k);
|
||||||
bkey_for_each_ptr(ptrs, ptr2)
|
bkey_for_each_ptr(ptrs, ptr2)
|
||||||
bkey_fsck_err_on(ptr != ptr2 && ptr->dev == ptr2->dev, c, err,
|
bkey_fsck_err_on(ptr != ptr2 && ptr->dev == ptr2->dev,
|
||||||
ptr_to_duplicate_device,
|
c, ptr_to_duplicate_device,
|
||||||
"multiple pointers to same device (%u)", ptr->dev);
|
"multiple pointers to same device (%u)", ptr->dev);
|
||||||
|
|
||||||
|
|
||||||
bkey_fsck_err_on(bucket >= nbuckets, c, err,
|
bkey_fsck_err_on(bucket >= nbuckets,
|
||||||
ptr_after_last_bucket,
|
c, ptr_after_last_bucket,
|
||||||
"pointer past last bucket (%llu > %llu)", bucket, nbuckets);
|
"pointer past last bucket (%llu > %llu)", bucket, nbuckets);
|
||||||
bkey_fsck_err_on(bucket < first_bucket, c, err,
|
bkey_fsck_err_on(bucket < first_bucket,
|
||||||
ptr_before_first_bucket,
|
c, ptr_before_first_bucket,
|
||||||
"pointer before first bucket (%llu < %u)", bucket, first_bucket);
|
"pointer before first bucket (%llu < %u)", bucket, first_bucket);
|
||||||
bkey_fsck_err_on(bucket_offset + size_ondisk > bucket_size, c, err,
|
bkey_fsck_err_on(bucket_offset + size_ondisk > bucket_size,
|
||||||
ptr_spans_multiple_buckets,
|
c, ptr_spans_multiple_buckets,
|
||||||
"pointer spans multiple buckets (%u + %u > %u)",
|
"pointer spans multiple buckets (%u + %u > %u)",
|
||||||
bucket_offset, size_ondisk, bucket_size);
|
bucket_offset, size_ondisk, bucket_size);
|
||||||
fsck_err:
|
fsck_err:
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
int bch2_bkey_ptrs_invalid(struct bch_fs *c, struct bkey_s_c k,
|
int bch2_bkey_ptrs_validate(struct bch_fs *c, struct bkey_s_c k,
|
||||||
enum bch_validate_flags flags,
|
enum bch_validate_flags flags)
|
||||||
struct printbuf *err)
|
|
||||||
{
|
{
|
||||||
struct bkey_ptrs_c ptrs = bch2_bkey_ptrs_c(k);
|
struct bkey_ptrs_c ptrs = bch2_bkey_ptrs_c(k);
|
||||||
const union bch_extent_entry *entry;
|
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);
|
size_ondisk = btree_sectors(c);
|
||||||
|
|
||||||
bkey_extent_entry_for_each(ptrs, entry) {
|
bkey_extent_entry_for_each(ptrs, entry) {
|
||||||
bkey_fsck_err_on(__extent_entry_type(entry) >= BCH_EXTENT_ENTRY_MAX, c, err,
|
bkey_fsck_err_on(__extent_entry_type(entry) >= BCH_EXTENT_ENTRY_MAX,
|
||||||
extent_ptrs_invalid_entry,
|
c, extent_ptrs_invalid_entry,
|
||||||
"invalid extent entry type (got %u, max %u)",
|
"invalid extent entry type (got %u, max %u)",
|
||||||
__extent_entry_type(entry), BCH_EXTENT_ENTRY_MAX);
|
__extent_entry_type(entry), BCH_EXTENT_ENTRY_MAX);
|
||||||
|
|
||||||
bkey_fsck_err_on(bkey_is_btree_ptr(k.k) &&
|
bkey_fsck_err_on(bkey_is_btree_ptr(k.k) &&
|
||||||
!extent_entry_is_ptr(entry), c, err,
|
!extent_entry_is_ptr(entry),
|
||||||
btree_ptr_has_non_ptr,
|
c, btree_ptr_has_non_ptr,
|
||||||
"has non ptr field");
|
"has non ptr field");
|
||||||
|
|
||||||
switch (extent_entry_type(entry)) {
|
switch (extent_entry_type(entry)) {
|
||||||
case BCH_EXTENT_ENTRY_ptr:
|
case BCH_EXTENT_ENTRY_ptr:
|
||||||
ret = extent_ptr_invalid(c, k, flags, &entry->ptr,
|
ret = extent_ptr_validate(c, k, flags, &entry->ptr, size_ondisk, false);
|
||||||
size_ondisk, false, err);
|
|
||||||
if (ret)
|
if (ret)
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
bkey_fsck_err_on(entry->ptr.cached && have_ec, c, err,
|
bkey_fsck_err_on(entry->ptr.cached && have_ec,
|
||||||
ptr_cached_and_erasure_coded,
|
c, ptr_cached_and_erasure_coded,
|
||||||
"cached, erasure coded ptr");
|
"cached, erasure coded ptr");
|
||||||
|
|
||||||
if (!entry->ptr.unwritten)
|
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:
|
case BCH_EXTENT_ENTRY_crc128:
|
||||||
crc = bch2_extent_crc_unpack(k.k, entry_to_crc(entry));
|
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,
|
bkey_fsck_err_on(crc.offset + crc.live_size > crc.uncompressed_size,
|
||||||
ptr_crc_uncompressed_size_too_small,
|
c, ptr_crc_uncompressed_size_too_small,
|
||||||
"checksum offset + key size > uncompressed size");
|
"checksum offset + key size > uncompressed size");
|
||||||
bkey_fsck_err_on(!bch2_checksum_type_valid(c, crc.csum_type), c, err,
|
bkey_fsck_err_on(!bch2_checksum_type_valid(c, crc.csum_type),
|
||||||
ptr_crc_csum_type_unknown,
|
c, ptr_crc_csum_type_unknown,
|
||||||
"invalid checksum type");
|
"invalid checksum type");
|
||||||
bkey_fsck_err_on(crc.compression_type >= BCH_COMPRESSION_TYPE_NR, c, err,
|
bkey_fsck_err_on(crc.compression_type >= BCH_COMPRESSION_TYPE_NR,
|
||||||
ptr_crc_compression_type_unknown,
|
c, ptr_crc_compression_type_unknown,
|
||||||
"invalid compression type");
|
"invalid compression type");
|
||||||
|
|
||||||
if (bch2_csum_type_is_encryption(crc.csum_type)) {
|
if (bch2_csum_type_is_encryption(crc.csum_type)) {
|
||||||
if (nonce == UINT_MAX)
|
if (nonce == UINT_MAX)
|
||||||
nonce = crc.offset + crc.nonce;
|
nonce = crc.offset + crc.nonce;
|
||||||
else if (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");
|
"incorrect nonce");
|
||||||
}
|
}
|
||||||
|
|
||||||
bkey_fsck_err_on(crc_since_last_ptr, c, err,
|
bkey_fsck_err_on(crc_since_last_ptr,
|
||||||
ptr_crc_redundant,
|
c, ptr_crc_redundant,
|
||||||
"redundant crc entry");
|
"redundant crc entry");
|
||||||
crc_since_last_ptr = true;
|
crc_since_last_ptr = true;
|
||||||
|
|
||||||
bkey_fsck_err_on(crc_is_encoded(crc) &&
|
bkey_fsck_err_on(crc_is_encoded(crc) &&
|
||||||
(crc.uncompressed_size > c->opts.encoded_extent_max >> 9) &&
|
(crc.uncompressed_size > c->opts.encoded_extent_max >> 9) &&
|
||||||
(flags & (BCH_VALIDATE_write|BCH_VALIDATE_commit)), c, err,
|
(flags & (BCH_VALIDATE_write|BCH_VALIDATE_commit)),
|
||||||
ptr_crc_uncompressed_size_too_big,
|
c, ptr_crc_uncompressed_size_too_big,
|
||||||
"too large encoded extent");
|
"too large encoded extent");
|
||||||
|
|
||||||
size_ondisk = crc.compressed_size;
|
size_ondisk = crc.compressed_size;
|
||||||
break;
|
break;
|
||||||
case BCH_EXTENT_ENTRY_stripe_ptr:
|
case BCH_EXTENT_ENTRY_stripe_ptr:
|
||||||
bkey_fsck_err_on(have_ec, c, err,
|
bkey_fsck_err_on(have_ec,
|
||||||
ptr_stripe_redundant,
|
c, ptr_stripe_redundant,
|
||||||
"redundant stripe entry");
|
"redundant stripe entry");
|
||||||
have_ec = true;
|
have_ec = true;
|
||||||
break;
|
break;
|
||||||
case BCH_EXTENT_ENTRY_rebalance: {
|
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;
|
const struct bch_extent_rebalance *r = &entry->rebalance;
|
||||||
|
|
||||||
if (!bch2_compression_opt_valid(r->compression)) {
|
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);
|
opt.type, opt.level);
|
||||||
return -BCH_ERR_invalid_bkey;
|
return -BCH_ERR_invalid_bkey;
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bkey_fsck_err_on(!nr_ptrs, c, err,
|
bkey_fsck_err_on(!nr_ptrs,
|
||||||
extent_ptrs_no_ptrs,
|
c, extent_ptrs_no_ptrs,
|
||||||
"no ptrs");
|
"no ptrs");
|
||||||
bkey_fsck_err_on(nr_ptrs > BCH_BKEY_PTRS_MAX, c, err,
|
bkey_fsck_err_on(nr_ptrs > BCH_BKEY_PTRS_MAX,
|
||||||
extent_ptrs_too_many_ptrs,
|
c, extent_ptrs_too_many_ptrs,
|
||||||
"too many ptrs: %u > %u", nr_ptrs, BCH_BKEY_PTRS_MAX);
|
"too many ptrs: %u > %u", nr_ptrs, BCH_BKEY_PTRS_MAX);
|
||||||
bkey_fsck_err_on(have_written && have_unwritten, c, err,
|
bkey_fsck_err_on(have_written && have_unwritten,
|
||||||
extent_ptrs_written_and_unwritten,
|
c, extent_ptrs_written_and_unwritten,
|
||||||
"extent with unwritten and written ptrs");
|
"extent with unwritten and written ptrs");
|
||||||
bkey_fsck_err_on(k.k->type != KEY_TYPE_extent && have_unwritten, c, err,
|
bkey_fsck_err_on(k.k->type != KEY_TYPE_extent && have_unwritten,
|
||||||
extent_ptrs_unwritten,
|
c, extent_ptrs_unwritten,
|
||||||
"has unwritten ptrs");
|
"has unwritten ptrs");
|
||||||
bkey_fsck_err_on(crc_since_last_ptr, c, err,
|
bkey_fsck_err_on(crc_since_last_ptr,
|
||||||
extent_ptrs_redundant_crc,
|
c, extent_ptrs_redundant_crc,
|
||||||
"redundant crc entry");
|
"redundant crc entry");
|
||||||
bkey_fsck_err_on(have_ec, c, err,
|
bkey_fsck_err_on(have_ec,
|
||||||
extent_ptrs_redundant_stripe,
|
c, extent_ptrs_redundant_stripe,
|
||||||
"redundant stripe entry");
|
"redundant stripe entry");
|
||||||
fsck_err:
|
fsck_err:
|
||||||
return ret;
|
return ret;
|
||||||
|
@ -409,26 +409,26 @@ int bch2_bkey_pick_read_device(struct bch_fs *, struct bkey_s_c,
|
|||||||
|
|
||||||
/* KEY_TYPE_btree_ptr: */
|
/* KEY_TYPE_btree_ptr: */
|
||||||
|
|
||||||
int bch2_btree_ptr_invalid(struct bch_fs *, struct bkey_s_c,
|
int bch2_btree_ptr_validate(struct bch_fs *, struct bkey_s_c,
|
||||||
enum bch_validate_flags, struct printbuf *);
|
enum bch_validate_flags);
|
||||||
void bch2_btree_ptr_to_text(struct printbuf *, struct bch_fs *,
|
void bch2_btree_ptr_to_text(struct printbuf *, struct bch_fs *,
|
||||||
struct bkey_s_c);
|
struct bkey_s_c);
|
||||||
|
|
||||||
int bch2_btree_ptr_v2_invalid(struct bch_fs *, struct bkey_s_c,
|
int bch2_btree_ptr_v2_validate(struct bch_fs *, struct bkey_s_c,
|
||||||
enum bch_validate_flags, struct printbuf *);
|
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_to_text(struct printbuf *, struct bch_fs *, struct bkey_s_c);
|
||||||
void bch2_btree_ptr_v2_compat(enum btree_id, unsigned, unsigned,
|
void bch2_btree_ptr_v2_compat(enum btree_id, unsigned, unsigned,
|
||||||
int, struct bkey_s);
|
int, struct bkey_s);
|
||||||
|
|
||||||
#define bch2_bkey_ops_btree_ptr ((struct bkey_ops) { \
|
#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, \
|
.val_to_text = bch2_btree_ptr_to_text, \
|
||||||
.swab = bch2_ptr_swab, \
|
.swab = bch2_ptr_swab, \
|
||||||
.trigger = bch2_trigger_extent, \
|
.trigger = bch2_trigger_extent, \
|
||||||
})
|
})
|
||||||
|
|
||||||
#define bch2_bkey_ops_btree_ptr_v2 ((struct bkey_ops) { \
|
#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, \
|
.val_to_text = bch2_btree_ptr_v2_to_text, \
|
||||||
.swab = bch2_ptr_swab, \
|
.swab = bch2_ptr_swab, \
|
||||||
.compat = bch2_btree_ptr_v2_compat, \
|
.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);
|
bool bch2_extent_merge(struct bch_fs *, struct bkey_s, struct bkey_s_c);
|
||||||
|
|
||||||
#define bch2_bkey_ops_extent ((struct bkey_ops) { \
|
#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, \
|
.val_to_text = bch2_bkey_ptrs_to_text, \
|
||||||
.swab = bch2_ptr_swab, \
|
.swab = bch2_ptr_swab, \
|
||||||
.key_normalize = bch2_extent_normalize, \
|
.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: */
|
/* KEY_TYPE_reservation: */
|
||||||
|
|
||||||
int bch2_reservation_invalid(struct bch_fs *, struct bkey_s_c,
|
int bch2_reservation_validate(struct bch_fs *, struct bkey_s_c,
|
||||||
enum bch_validate_flags, struct printbuf *);
|
enum bch_validate_flags);
|
||||||
void bch2_reservation_to_text(struct printbuf *, struct bch_fs *, struct bkey_s_c);
|
void bch2_reservation_to_text(struct printbuf *, struct bch_fs *, struct bkey_s_c);
|
||||||
bool bch2_reservation_merge(struct bch_fs *, struct bkey_s, struct bkey_s_c);
|
bool bch2_reservation_merge(struct bch_fs *, struct bkey_s, struct bkey_s_c);
|
||||||
|
|
||||||
#define bch2_bkey_ops_reservation ((struct bkey_ops) { \
|
#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, \
|
.val_to_text = bch2_reservation_to_text, \
|
||||||
.key_merge = bch2_reservation_merge, \
|
.key_merge = bch2_reservation_merge, \
|
||||||
.trigger = bch2_trigger_reservation, \
|
.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_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 *,
|
void bch2_bkey_ptrs_to_text(struct printbuf *, struct bch_fs *,
|
||||||
struct bkey_s_c);
|
struct bkey_s_c);
|
||||||
int bch2_bkey_ptrs_invalid(struct bch_fs *, struct bkey_s_c,
|
int bch2_bkey_ptrs_validate(struct bch_fs *, struct bkey_s_c,
|
||||||
enum bch_validate_flags, struct printbuf *);
|
enum bch_validate_flags);
|
||||||
|
|
||||||
void bch2_ptr_swab(struct bkey_s);
|
void bch2_ptr_swab(struct bkey_s);
|
||||||
|
|
||||||
|
@ -108,7 +108,7 @@ retry:
|
|||||||
goto retry;
|
goto retry;
|
||||||
|
|
||||||
bch2_fs_fatal_err_on(bch2_err_matches(ret, ENOENT), c,
|
bch2_fs_fatal_err_on(bch2_err_matches(ret, ENOENT), c,
|
||||||
"%s: inode %u:%llu not found when updating",
|
"%s: inode %llu:%llu not found when updating",
|
||||||
bch2_err_str(ret),
|
bch2_err_str(ret),
|
||||||
inode_inum(inode).subvol,
|
inode_inum(inode).subvol,
|
||||||
inode_inum(inode).inum);
|
inode_inum(inode).inum);
|
||||||
@ -185,16 +185,22 @@ static void __wait_on_freeing_inode(struct inode *inode)
|
|||||||
finish_wait(wq, &wait.wq_entry);
|
finish_wait(wq, &wait.wq_entry);
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct bch_inode_info *bch2_inode_hash_find(struct bch_fs *c, subvol_inum inum)
|
static struct bch_inode_info *bch2_inode_hash_find(struct bch_fs *c, struct btree_trans *trans,
|
||||||
|
subvol_inum inum)
|
||||||
{
|
{
|
||||||
struct bch_inode_info *inode;
|
struct bch_inode_info *inode;
|
||||||
repeat:
|
repeat:
|
||||||
inode = rhashtable_lookup_fast(&c->vfs_inodes_table, &inum,
|
inode = rhashtable_lookup_fast(&c->vfs_inodes_table, &inum, bch2_vfs_inodes_params);
|
||||||
bch2_vfs_inodes_params);
|
|
||||||
if (inode) {
|
if (inode) {
|
||||||
spin_lock(&inode->v.i_lock);
|
spin_lock(&inode->v.i_lock);
|
||||||
if ((inode->v.i_state & (I_FREEING|I_WILL_FREE))) {
|
if ((inode->v.i_state & (I_FREEING|I_WILL_FREE))) {
|
||||||
|
if (trans)
|
||||||
|
bch2_trans_unlock(trans);
|
||||||
__wait_on_freeing_inode(&inode->v);
|
__wait_on_freeing_inode(&inode->v);
|
||||||
|
if (trans) {
|
||||||
|
trace_and_count(c, trans_restart_freeing_inode, trans, _THIS_IP_);
|
||||||
|
return ERR_PTR(btree_trans_restart(trans, BCH_ERR_transaction_restart_freeing_inode));
|
||||||
|
}
|
||||||
goto repeat;
|
goto repeat;
|
||||||
}
|
}
|
||||||
__iget(&inode->v);
|
__iget(&inode->v);
|
||||||
@ -215,23 +221,27 @@ static void bch2_inode_hash_remove(struct bch_fs *c, struct bch_inode_info *inod
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct bch_inode_info *bch2_inode_hash_insert(struct bch_fs *c, struct bch_inode_info *inode)
|
static struct bch_inode_info *bch2_inode_hash_insert(struct bch_fs *c,
|
||||||
|
struct btree_trans *trans,
|
||||||
|
struct bch_inode_info *inode)
|
||||||
{
|
{
|
||||||
struct bch_inode_info *old = inode;
|
struct bch_inode_info *old = inode;
|
||||||
retry:
|
retry:
|
||||||
if (unlikely(rhashtable_lookup_insert_fast(&c->vfs_inodes_table,
|
if (unlikely(rhashtable_lookup_insert_fast(&c->vfs_inodes_table,
|
||||||
&inode->hash,
|
&inode->hash,
|
||||||
bch2_vfs_inodes_params))) {
|
bch2_vfs_inodes_params))) {
|
||||||
old = bch2_inode_hash_find(c, inode->ei_inum);
|
old = bch2_inode_hash_find(c, trans, inode->ei_inum);
|
||||||
if (!old)
|
if (!old)
|
||||||
goto retry;
|
goto retry;
|
||||||
|
if (IS_ERR(old))
|
||||||
|
return old;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* bcachefs doesn't use I_NEW; we have no use for it since we
|
* bcachefs doesn't use I_NEW; we have no use for it since we
|
||||||
* only insert fully created inodes in the inode hash table. But
|
* only insert fully created inodes in the inode hash table. But
|
||||||
* discard_new_inode() expects it to be set...
|
* 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 don't want bch2_evict_inode() to delete the inode on disk,
|
||||||
* we just raced and had another inode in cache. Normally new
|
* we just raced and had another inode in cache. Normally new
|
||||||
@ -312,9 +322,31 @@ static struct bch_inode_info *bch2_new_inode(struct btree_trans *trans)
|
|||||||
return inode;
|
return inode;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static struct bch_inode_info *bch2_inode_hash_init_insert(struct btree_trans *trans,
|
||||||
|
subvol_inum inum,
|
||||||
|
struct bch_inode_unpacked *bi,
|
||||||
|
struct bch_subvolume *subvol)
|
||||||
|
{
|
||||||
|
struct bch_inode_info *inode = bch2_new_inode(trans);
|
||||||
|
if (IS_ERR(inode))
|
||||||
|
return inode;
|
||||||
|
|
||||||
|
bch2_vfs_inode_init(trans, inum, inode, bi, subvol);
|
||||||
|
|
||||||
|
struct bch_inode_info *ret = bch2_inode_hash_insert(trans->c, trans, inode);
|
||||||
|
if (IS_ERR(ret)) {
|
||||||
|
inode->v.i_state |= I_NEW;
|
||||||
|
set_nlink(&inode->v, 1);
|
||||||
|
discard_new_inode(&inode->v);
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
struct inode *bch2_vfs_inode_get(struct bch_fs *c, subvol_inum inum)
|
struct inode *bch2_vfs_inode_get(struct bch_fs *c, subvol_inum inum)
|
||||||
{
|
{
|
||||||
struct bch_inode_info *inode = bch2_inode_hash_find(c, inum);
|
struct bch_inode_info *inode = bch2_inode_hash_find(c, NULL, inum);
|
||||||
if (inode)
|
if (inode)
|
||||||
return &inode->v;
|
return &inode->v;
|
||||||
|
|
||||||
@ -325,11 +357,7 @@ struct inode *bch2_vfs_inode_get(struct bch_fs *c, subvol_inum inum)
|
|||||||
int ret = lockrestart_do(trans,
|
int ret = lockrestart_do(trans,
|
||||||
bch2_subvolume_get(trans, inum.subvol, true, 0, &subvol) ?:
|
bch2_subvolume_get(trans, inum.subvol, true, 0, &subvol) ?:
|
||||||
bch2_inode_find_by_inum_trans(trans, inum, &inode_u)) ?:
|
bch2_inode_find_by_inum_trans(trans, inum, &inode_u)) ?:
|
||||||
PTR_ERR_OR_ZERO(inode = bch2_new_inode(trans));
|
PTR_ERR_OR_ZERO(inode = bch2_inode_hash_init_insert(trans, inum, &inode_u, &subvol));
|
||||||
if (!ret) {
|
|
||||||
bch2_vfs_inode_init(trans, inum, inode, &inode_u, &subvol);
|
|
||||||
inode = bch2_inode_hash_insert(c, inode);
|
|
||||||
}
|
|
||||||
bch2_trans_put(trans);
|
bch2_trans_put(trans);
|
||||||
|
|
||||||
return ret ? ERR_PTR(ret) : &inode->v;
|
return ret ? ERR_PTR(ret) : &inode->v;
|
||||||
@ -420,8 +448,16 @@ err_before_quota:
|
|||||||
* we must insert the new inode into the inode cache before calling
|
* we must insert the new inode into the inode cache before calling
|
||||||
* bch2_trans_exit() and dropping locks, else we could race with another
|
* bch2_trans_exit() and dropping locks, else we could race with another
|
||||||
* thread pulling the inode in and modifying it:
|
* thread pulling the inode in and modifying it:
|
||||||
|
*
|
||||||
|
* also, calling bch2_inode_hash_insert() without passing in the
|
||||||
|
* transaction object is sketchy - if we could ever end up in
|
||||||
|
* __wait_on_freeing_inode(), we'd risk deadlock.
|
||||||
|
*
|
||||||
|
* But that shouldn't be possible, since we still have the inode locked
|
||||||
|
* that we just created, and we _really_ can't take a transaction
|
||||||
|
* restart here.
|
||||||
*/
|
*/
|
||||||
inode = bch2_inode_hash_insert(c, inode);
|
inode = bch2_inode_hash_insert(c, NULL, inode);
|
||||||
bch2_trans_put(trans);
|
bch2_trans_put(trans);
|
||||||
err:
|
err:
|
||||||
posix_acl_release(default_acl);
|
posix_acl_release(default_acl);
|
||||||
@ -461,7 +497,7 @@ static struct bch_inode_info *bch2_lookup_trans(struct btree_trans *trans,
|
|||||||
if (ret)
|
if (ret)
|
||||||
goto err;
|
goto err;
|
||||||
|
|
||||||
struct bch_inode_info *inode = bch2_inode_hash_find(c, inum);
|
struct bch_inode_info *inode = bch2_inode_hash_find(c, trans, inum);
|
||||||
if (inode)
|
if (inode)
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
@ -469,7 +505,7 @@ static struct bch_inode_info *bch2_lookup_trans(struct btree_trans *trans,
|
|||||||
struct bch_inode_unpacked inode_u;
|
struct bch_inode_unpacked inode_u;
|
||||||
ret = bch2_subvolume_get(trans, inum.subvol, true, 0, &subvol) ?:
|
ret = bch2_subvolume_get(trans, inum.subvol, true, 0, &subvol) ?:
|
||||||
bch2_inode_find_by_inum_nowarn_trans(trans, inum, &inode_u) ?:
|
bch2_inode_find_by_inum_nowarn_trans(trans, inum, &inode_u) ?:
|
||||||
PTR_ERR_OR_ZERO(inode = bch2_new_inode(trans));
|
PTR_ERR_OR_ZERO(inode = bch2_inode_hash_init_insert(trans, inum, &inode_u, &subvol));
|
||||||
|
|
||||||
bch2_fs_inconsistent_on(bch2_err_matches(ret, ENOENT),
|
bch2_fs_inconsistent_on(bch2_err_matches(ret, ENOENT),
|
||||||
c, "dirent to missing inode:\n %s",
|
c, "dirent to missing inode:\n %s",
|
||||||
@ -489,9 +525,6 @@ static struct bch_inode_info *bch2_lookup_trans(struct btree_trans *trans,
|
|||||||
ret = -ENOENT;
|
ret = -ENOENT;
|
||||||
goto err;
|
goto err;
|
||||||
}
|
}
|
||||||
|
|
||||||
bch2_vfs_inode_init(trans, inum, inode, &inode_u, &subvol);
|
|
||||||
inode = bch2_inode_hash_insert(c, inode);
|
|
||||||
out:
|
out:
|
||||||
bch2_trans_iter_exit(trans, &dirent_iter);
|
bch2_trans_iter_exit(trans, &dirent_iter);
|
||||||
printbuf_exit(&buf);
|
printbuf_exit(&buf);
|
||||||
@ -1536,7 +1569,8 @@ static const struct export_operations bch_export_ops = {
|
|||||||
.get_name = bch2_get_name,
|
.get_name = bch2_get_name,
|
||||||
};
|
};
|
||||||
|
|
||||||
static void bch2_vfs_inode_init(struct btree_trans *trans, subvol_inum inum,
|
static void bch2_vfs_inode_init(struct btree_trans *trans,
|
||||||
|
subvol_inum inum,
|
||||||
struct bch_inode_info *inode,
|
struct bch_inode_info *inode,
|
||||||
struct bch_inode_unpacked *bi,
|
struct bch_inode_unpacked *bi,
|
||||||
struct bch_subvolume *subvol)
|
struct bch_subvolume *subvol)
|
||||||
|
@ -365,7 +365,7 @@ int bch2_inode_peek(struct btree_trans *trans,
|
|||||||
subvol_inum inum, unsigned flags)
|
subvol_inum inum, unsigned flags)
|
||||||
{
|
{
|
||||||
int ret = bch2_inode_peek_nowarn(trans, iter, inode, inum, flags);
|
int ret = bch2_inode_peek_nowarn(trans, iter, inode, inum, flags);
|
||||||
bch_err_msg(trans->c, ret, "looking up inum %u:%llu:", inum.subvol, inum.inum);
|
bch_err_msg(trans->c, ret, "looking up inum %llu:%llu:", inum.subvol, inum.inum);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -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;
|
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;
|
struct bch_inode_unpacked unpacked;
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
|
|
||||||
bkey_fsck_err_on(k.k->p.inode, c, err,
|
bkey_fsck_err_on(k.k->p.inode,
|
||||||
inode_pos_inode_nonzero,
|
c, inode_pos_inode_nonzero,
|
||||||
"nonzero k.p.inode");
|
"nonzero k.p.inode");
|
||||||
|
|
||||||
bkey_fsck_err_on(k.k->p.offset < BLOCKDEV_INODE_MAX, c, err,
|
bkey_fsck_err_on(k.k->p.offset < BLOCKDEV_INODE_MAX,
|
||||||
inode_pos_blockdev_range,
|
c, inode_pos_blockdev_range,
|
||||||
"fs inode in blockdev range");
|
"fs inode in blockdev range");
|
||||||
|
|
||||||
bkey_fsck_err_on(bch2_inode_unpack(k, &unpacked), c, err,
|
bkey_fsck_err_on(bch2_inode_unpack(k, &unpacked),
|
||||||
inode_unpack_error,
|
c, inode_unpack_error,
|
||||||
"invalid variable length fields");
|
"invalid variable length fields");
|
||||||
|
|
||||||
bkey_fsck_err_on(unpacked.bi_data_checksum >= BCH_CSUM_OPT_NR + 1, c, err,
|
bkey_fsck_err_on(unpacked.bi_data_checksum >= BCH_CSUM_OPT_NR + 1,
|
||||||
inode_checksum_type_invalid,
|
c, inode_checksum_type_invalid,
|
||||||
"invalid data checksum type (%u >= %u",
|
"invalid data checksum type (%u >= %u",
|
||||||
unpacked.bi_data_checksum, BCH_CSUM_OPT_NR + 1);
|
unpacked.bi_data_checksum, BCH_CSUM_OPT_NR + 1);
|
||||||
|
|
||||||
bkey_fsck_err_on(unpacked.bi_compression &&
|
bkey_fsck_err_on(unpacked.bi_compression &&
|
||||||
!bch2_compression_opt_valid(unpacked.bi_compression - 1), c, err,
|
!bch2_compression_opt_valid(unpacked.bi_compression - 1),
|
||||||
inode_compression_type_invalid,
|
c, inode_compression_type_invalid,
|
||||||
"invalid compression opt %u", unpacked.bi_compression - 1);
|
"invalid compression opt %u", unpacked.bi_compression - 1);
|
||||||
|
|
||||||
bkey_fsck_err_on((unpacked.bi_flags & BCH_INODE_unlinked) &&
|
bkey_fsck_err_on((unpacked.bi_flags & BCH_INODE_unlinked) &&
|
||||||
unpacked.bi_nlink != 0, c, err,
|
unpacked.bi_nlink != 0,
|
||||||
inode_unlinked_but_nlink_nonzero,
|
c, inode_unlinked_but_nlink_nonzero,
|
||||||
"flagged as unlinked but bi_nlink != 0");
|
"flagged as unlinked but bi_nlink != 0");
|
||||||
|
|
||||||
bkey_fsck_err_on(unpacked.bi_subvol && !S_ISDIR(unpacked.bi_mode), c, err,
|
bkey_fsck_err_on(unpacked.bi_subvol && !S_ISDIR(unpacked.bi_mode),
|
||||||
inode_subvol_root_but_not_dir,
|
c, inode_subvol_root_but_not_dir,
|
||||||
"subvolume root but not a directory");
|
"subvolume root but not a directory");
|
||||||
fsck_err:
|
fsck_err:
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
int bch2_inode_invalid(struct bch_fs *c, struct bkey_s_c k,
|
int bch2_inode_validate(struct bch_fs *c, struct bkey_s_c k,
|
||||||
enum bch_validate_flags flags,
|
enum bch_validate_flags flags)
|
||||||
struct printbuf *err)
|
|
||||||
{
|
{
|
||||||
struct bkey_s_c_inode inode = bkey_s_c_to_inode(k);
|
struct bkey_s_c_inode inode = bkey_s_c_to_inode(k);
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
|
|
||||||
bkey_fsck_err_on(INODE_STR_HASH(inode.v) >= BCH_STR_HASH_NR, c, err,
|
bkey_fsck_err_on(INODE_STR_HASH(inode.v) >= BCH_STR_HASH_NR,
|
||||||
inode_str_hash_invalid,
|
c, inode_str_hash_invalid,
|
||||||
"invalid str hash type (%llu >= %u)",
|
"invalid str hash type (%llu >= %u)",
|
||||||
INODE_STR_HASH(inode.v), BCH_STR_HASH_NR);
|
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:
|
fsck_err:
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
int bch2_inode_v2_invalid(struct bch_fs *c, struct bkey_s_c k,
|
int bch2_inode_v2_validate(struct bch_fs *c, struct bkey_s_c k,
|
||||||
enum bch_validate_flags flags,
|
enum bch_validate_flags flags)
|
||||||
struct printbuf *err)
|
|
||||||
{
|
{
|
||||||
struct bkey_s_c_inode_v2 inode = bkey_s_c_to_inode_v2(k);
|
struct bkey_s_c_inode_v2 inode = bkey_s_c_to_inode_v2(k);
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
|
|
||||||
bkey_fsck_err_on(INODEv2_STR_HASH(inode.v) >= BCH_STR_HASH_NR, c, err,
|
bkey_fsck_err_on(INODEv2_STR_HASH(inode.v) >= BCH_STR_HASH_NR,
|
||||||
inode_str_hash_invalid,
|
c, inode_str_hash_invalid,
|
||||||
"invalid str hash type (%llu >= %u)",
|
"invalid str hash type (%llu >= %u)",
|
||||||
INODEv2_STR_HASH(inode.v), BCH_STR_HASH_NR);
|
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:
|
fsck_err:
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
int bch2_inode_v3_invalid(struct bch_fs *c, struct bkey_s_c k,
|
int bch2_inode_v3_validate(struct bch_fs *c, struct bkey_s_c k,
|
||||||
enum bch_validate_flags flags,
|
enum bch_validate_flags flags)
|
||||||
struct printbuf *err)
|
|
||||||
{
|
{
|
||||||
struct bkey_s_c_inode_v3 inode = bkey_s_c_to_inode_v3(k);
|
struct bkey_s_c_inode_v3 inode = bkey_s_c_to_inode_v3(k);
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
|
|
||||||
bkey_fsck_err_on(INODEv3_FIELDS_START(inode.v) < INODEv3_FIELDS_START_INITIAL ||
|
bkey_fsck_err_on(INODEv3_FIELDS_START(inode.v) < INODEv3_FIELDS_START_INITIAL ||
|
||||||
INODEv3_FIELDS_START(inode.v) > bkey_val_u64s(inode.k), c, err,
|
INODEv3_FIELDS_START(inode.v) > bkey_val_u64s(inode.k),
|
||||||
inode_v3_fields_start_bad,
|
c, inode_v3_fields_start_bad,
|
||||||
"invalid fields_start (got %llu, min %u max %zu)",
|
"invalid fields_start (got %llu, min %u max %zu)",
|
||||||
INODEv3_FIELDS_START(inode.v),
|
INODEv3_FIELDS_START(inode.v),
|
||||||
INODEv3_FIELDS_START_INITIAL,
|
INODEv3_FIELDS_START_INITIAL,
|
||||||
bkey_val_u64s(inode.k));
|
bkey_val_u64s(inode.k));
|
||||||
|
|
||||||
bkey_fsck_err_on(INODEv3_STR_HASH(inode.v) >= BCH_STR_HASH_NR, c, err,
|
bkey_fsck_err_on(INODEv3_STR_HASH(inode.v) >= BCH_STR_HASH_NR,
|
||||||
inode_str_hash_invalid,
|
c, inode_str_hash_invalid,
|
||||||
"invalid str hash type (%llu >= %u)",
|
"invalid str hash type (%llu >= %u)",
|
||||||
INODEv3_STR_HASH(inode.v), BCH_STR_HASH_NR);
|
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:
|
fsck_err:
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
@ -625,14 +623,13 @@ int bch2_trigger_inode(struct btree_trans *trans,
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int bch2_inode_generation_invalid(struct bch_fs *c, struct bkey_s_c k,
|
int bch2_inode_generation_validate(struct bch_fs *c, struct bkey_s_c k,
|
||||||
enum bch_validate_flags flags,
|
enum bch_validate_flags flags)
|
||||||
struct printbuf *err)
|
|
||||||
{
|
{
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
|
|
||||||
bkey_fsck_err_on(k.k->p.inode, c, err,
|
bkey_fsck_err_on(k.k->p.inode,
|
||||||
inode_pos_inode_nonzero,
|
c, inode_pos_inode_nonzero,
|
||||||
"nonzero k.p.inode");
|
"nonzero k.p.inode");
|
||||||
fsck_err:
|
fsck_err:
|
||||||
return ret;
|
return ret;
|
||||||
|
@ -9,12 +9,12 @@
|
|||||||
enum bch_validate_flags;
|
enum bch_validate_flags;
|
||||||
extern const char * const bch2_inode_opts[];
|
extern const char * const bch2_inode_opts[];
|
||||||
|
|
||||||
int bch2_inode_invalid(struct bch_fs *, struct bkey_s_c,
|
int bch2_inode_validate(struct bch_fs *, struct bkey_s_c,
|
||||||
enum bch_validate_flags, struct printbuf *);
|
enum bch_validate_flags);
|
||||||
int bch2_inode_v2_invalid(struct bch_fs *, struct bkey_s_c,
|
int bch2_inode_v2_validate(struct bch_fs *, struct bkey_s_c,
|
||||||
enum bch_validate_flags, struct printbuf *);
|
enum bch_validate_flags);
|
||||||
int bch2_inode_v3_invalid(struct bch_fs *, struct bkey_s_c,
|
int bch2_inode_v3_validate(struct bch_fs *, struct bkey_s_c,
|
||||||
enum bch_validate_flags, struct printbuf *);
|
enum bch_validate_flags);
|
||||||
void bch2_inode_to_text(struct printbuf *, struct bch_fs *, struct bkey_s_c);
|
void bch2_inode_to_text(struct printbuf *, struct bch_fs *, struct bkey_s_c);
|
||||||
|
|
||||||
int bch2_trigger_inode(struct btree_trans *, enum btree_id, unsigned,
|
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);
|
enum btree_iter_update_trigger_flags);
|
||||||
|
|
||||||
#define bch2_bkey_ops_inode ((struct bkey_ops) { \
|
#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, \
|
.val_to_text = bch2_inode_to_text, \
|
||||||
.trigger = bch2_trigger_inode, \
|
.trigger = bch2_trigger_inode, \
|
||||||
.min_val_size = 16, \
|
.min_val_size = 16, \
|
||||||
})
|
})
|
||||||
|
|
||||||
#define bch2_bkey_ops_inode_v2 ((struct bkey_ops) { \
|
#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, \
|
.val_to_text = bch2_inode_to_text, \
|
||||||
.trigger = bch2_trigger_inode, \
|
.trigger = bch2_trigger_inode, \
|
||||||
.min_val_size = 32, \
|
.min_val_size = 32, \
|
||||||
})
|
})
|
||||||
|
|
||||||
#define bch2_bkey_ops_inode_v3 ((struct bkey_ops) { \
|
#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, \
|
.val_to_text = bch2_inode_to_text, \
|
||||||
.trigger = bch2_trigger_inode, \
|
.trigger = bch2_trigger_inode, \
|
||||||
.min_val_size = 48, \
|
.min_val_size = 48, \
|
||||||
@ -49,12 +49,12 @@ static inline bool bkey_is_inode(const struct bkey *k)
|
|||||||
k->type == KEY_TYPE_inode_v3;
|
k->type == KEY_TYPE_inode_v3;
|
||||||
}
|
}
|
||||||
|
|
||||||
int bch2_inode_generation_invalid(struct bch_fs *, struct bkey_s_c,
|
int bch2_inode_generation_validate(struct bch_fs *, struct bkey_s_c,
|
||||||
enum bch_validate_flags, struct printbuf *);
|
enum bch_validate_flags);
|
||||||
void bch2_inode_generation_to_text(struct printbuf *, struct bch_fs *, struct bkey_s_c);
|
void bch2_inode_generation_to_text(struct printbuf *, struct bch_fs *, struct bkey_s_c);
|
||||||
|
|
||||||
#define bch2_bkey_ops_inode_generation ((struct bkey_ops) { \
|
#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, \
|
.val_to_text = bch2_inode_generation_to_text, \
|
||||||
.min_val_size = 8, \
|
.min_val_size = 8, \
|
||||||
})
|
})
|
||||||
|
@ -332,7 +332,6 @@ static int journal_validate_key(struct bch_fs *c,
|
|||||||
{
|
{
|
||||||
int write = flags & BCH_VALIDATE_write;
|
int write = flags & BCH_VALIDATE_write;
|
||||||
void *next = vstruct_next(entry);
|
void *next = vstruct_next(entry);
|
||||||
struct printbuf buf = PRINTBUF;
|
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
|
|
||||||
if (journal_entry_err_on(!k->k.u64s,
|
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,
|
bch2_bkey_compat(level, btree_id, version, big_endian,
|
||||||
write, NULL, bkey_to_packed(k));
|
write, NULL, bkey_to_packed(k));
|
||||||
|
|
||||||
if (bch2_bkey_invalid(c, bkey_i_to_s_c(k),
|
ret = bch2_bkey_validate(c, bkey_i_to_s_c(k),
|
||||||
__btree_node_type(level, btree_id), write, &buf)) {
|
__btree_node_type(level, btree_id), write);
|
||||||
printbuf_reset(&buf);
|
if (ret == -BCH_ERR_fsck_delete_bkey) {
|
||||||
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);
|
|
||||||
|
|
||||||
le16_add_cpu(&entry->u64s, -((u16) k->k.u64s));
|
le16_add_cpu(&entry->u64s, -((u16) k->k.u64s));
|
||||||
memmove(k, bkey_next(k), next - (void *) bkey_next(k));
|
memmove(k, bkey_next(k), next - (void *) bkey_next(k));
|
||||||
journal_entry_null_range(vstruct_next(entry), next);
|
journal_entry_null_range(vstruct_next(entry), next);
|
||||||
|
|
||||||
printbuf_exit(&buf);
|
|
||||||
return FSCK_DELETED_KEY;
|
return FSCK_DELETED_KEY;
|
||||||
}
|
}
|
||||||
|
if (ret)
|
||||||
|
goto fsck_err;
|
||||||
|
|
||||||
if (write)
|
if (write)
|
||||||
bch2_bkey_compat(level, btree_id, version, big_endian,
|
bch2_bkey_compat(level, btree_id, version, big_endian,
|
||||||
write, NULL, bkey_to_packed(k));
|
write, NULL, bkey_to_packed(k));
|
||||||
fsck_err:
|
fsck_err:
|
||||||
printbuf_exit(&buf);
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -10,14 +10,13 @@
|
|||||||
#include "recovery.h"
|
#include "recovery.h"
|
||||||
|
|
||||||
/* KEY_TYPE_lru is obsolete: */
|
/* KEY_TYPE_lru is obsolete: */
|
||||||
int bch2_lru_invalid(struct bch_fs *c, struct bkey_s_c k,
|
int bch2_lru_validate(struct bch_fs *c, struct bkey_s_c k,
|
||||||
enum bch_validate_flags flags,
|
enum bch_validate_flags flags)
|
||||||
struct printbuf *err)
|
|
||||||
{
|
{
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
|
|
||||||
bkey_fsck_err_on(!lru_pos_time(k.k->p), c, err,
|
bkey_fsck_err_on(!lru_pos_time(k.k->p),
|
||||||
lru_entry_at_time_0,
|
c, lru_entry_at_time_0,
|
||||||
"lru entry at time=0");
|
"lru entry at time=0");
|
||||||
fsck_err:
|
fsck_err:
|
||||||
return ret;
|
return ret;
|
||||||
|
@ -33,14 +33,13 @@ static inline enum bch_lru_type lru_type(struct bkey_s_c l)
|
|||||||
return BCH_LRU_read;
|
return BCH_LRU_read;
|
||||||
}
|
}
|
||||||
|
|
||||||
int bch2_lru_invalid(struct bch_fs *, struct bkey_s_c,
|
int bch2_lru_validate(struct bch_fs *, struct bkey_s_c, enum bch_validate_flags);
|
||||||
enum bch_validate_flags, struct printbuf *);
|
|
||||||
void bch2_lru_to_text(struct printbuf *, struct bch_fs *, struct bkey_s_c);
|
void bch2_lru_to_text(struct printbuf *, struct bch_fs *, struct bkey_s_c);
|
||||||
|
|
||||||
void bch2_lru_pos_to_text(struct printbuf *, struct bpos);
|
void bch2_lru_pos_to_text(struct printbuf *, struct bpos);
|
||||||
|
|
||||||
#define bch2_bkey_ops_lru ((struct bkey_ops) { \
|
#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, \
|
.val_to_text = bch2_lru_to_text, \
|
||||||
.min_val_size = 8, \
|
.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,
|
.to_text = bch2_sb_quota_to_text,
|
||||||
};
|
};
|
||||||
|
|
||||||
int bch2_quota_invalid(struct bch_fs *c, struct bkey_s_c k,
|
int bch2_quota_validate(struct bch_fs *c, struct bkey_s_c k,
|
||||||
enum bch_validate_flags flags, struct printbuf *err)
|
enum bch_validate_flags flags)
|
||||||
{
|
{
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
|
|
||||||
bkey_fsck_err_on(k.k->p.inode >= QTYP_NR, c, err,
|
bkey_fsck_err_on(k.k->p.inode >= QTYP_NR,
|
||||||
quota_type_invalid,
|
c, quota_type_invalid,
|
||||||
"invalid quota type (%llu >= %u)",
|
"invalid quota type (%llu >= %u)",
|
||||||
k.k->p.inode, QTYP_NR);
|
k.k->p.inode, QTYP_NR);
|
||||||
fsck_err:
|
fsck_err:
|
||||||
|
@ -8,12 +8,11 @@
|
|||||||
enum bch_validate_flags;
|
enum bch_validate_flags;
|
||||||
extern const struct bch_sb_field_ops bch_sb_field_ops_quota;
|
extern const struct bch_sb_field_ops bch_sb_field_ops_quota;
|
||||||
|
|
||||||
int bch2_quota_invalid(struct bch_fs *, struct bkey_s_c,
|
int bch2_quota_validate(struct bch_fs *, struct bkey_s_c, enum bch_validate_flags);
|
||||||
enum bch_validate_flags, struct printbuf *);
|
|
||||||
void bch2_quota_to_text(struct printbuf *, struct bch_fs *, struct bkey_s_c);
|
void bch2_quota_to_text(struct printbuf *, struct bch_fs *, struct bkey_s_c);
|
||||||
|
|
||||||
#define bch2_bkey_ops_quota ((struct bkey_ops) { \
|
#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, \
|
.val_to_text = bch2_quota_to_text, \
|
||||||
.min_val_size = 32, \
|
.min_val_size = 32, \
|
||||||
})
|
})
|
||||||
|
@ -29,15 +29,14 @@ static inline unsigned bkey_type_to_indirect(const struct bkey *k)
|
|||||||
|
|
||||||
/* reflink pointers */
|
/* reflink pointers */
|
||||||
|
|
||||||
int bch2_reflink_p_invalid(struct bch_fs *c, struct bkey_s_c k,
|
int bch2_reflink_p_validate(struct bch_fs *c, struct bkey_s_c k,
|
||||||
enum bch_validate_flags flags,
|
enum bch_validate_flags flags)
|
||||||
struct printbuf *err)
|
|
||||||
{
|
{
|
||||||
struct bkey_s_c_reflink_p p = bkey_s_c_to_reflink_p(k);
|
struct bkey_s_c_reflink_p p = bkey_s_c_to_reflink_p(k);
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
|
|
||||||
bkey_fsck_err_on(le64_to_cpu(p.v->idx) < le32_to_cpu(p.v->front_pad),
|
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)",
|
"idx < front_pad (%llu < %u)",
|
||||||
le64_to_cpu(p.v->idx), le32_to_cpu(p.v->front_pad));
|
le64_to_cpu(p.v->idx), le32_to_cpu(p.v->front_pad));
|
||||||
fsck_err:
|
fsck_err:
|
||||||
@ -256,11 +255,10 @@ int bch2_trigger_reflink_p(struct btree_trans *trans,
|
|||||||
|
|
||||||
/* indirect extents */
|
/* indirect extents */
|
||||||
|
|
||||||
int bch2_reflink_v_invalid(struct bch_fs *c, struct bkey_s_c k,
|
int bch2_reflink_v_validate(struct bch_fs *c, struct bkey_s_c k,
|
||||||
enum bch_validate_flags flags,
|
enum bch_validate_flags flags)
|
||||||
struct printbuf *err)
|
|
||||||
{
|
{
|
||||||
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,
|
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 */
|
/* indirect inline data */
|
||||||
|
|
||||||
int bch2_indirect_inline_data_invalid(struct bch_fs *c, struct bkey_s_c k,
|
int bch2_indirect_inline_data_validate(struct bch_fs *c, struct bkey_s_c k,
|
||||||
enum bch_validate_flags flags,
|
enum bch_validate_flags flags)
|
||||||
struct printbuf *err)
|
|
||||||
{
|
{
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -4,41 +4,37 @@
|
|||||||
|
|
||||||
enum bch_validate_flags;
|
enum bch_validate_flags;
|
||||||
|
|
||||||
int bch2_reflink_p_invalid(struct bch_fs *, struct bkey_s_c,
|
int bch2_reflink_p_validate(struct bch_fs *, struct bkey_s_c, enum bch_validate_flags);
|
||||||
enum bch_validate_flags, struct printbuf *);
|
void bch2_reflink_p_to_text(struct printbuf *, struct bch_fs *, struct bkey_s_c);
|
||||||
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);
|
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,
|
int bch2_trigger_reflink_p(struct btree_trans *, enum btree_id, unsigned,
|
||||||
struct bkey_s_c, struct bkey_s,
|
struct bkey_s_c, struct bkey_s,
|
||||||
enum btree_iter_update_trigger_flags);
|
enum btree_iter_update_trigger_flags);
|
||||||
|
|
||||||
#define bch2_bkey_ops_reflink_p ((struct bkey_ops) { \
|
#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, \
|
.val_to_text = bch2_reflink_p_to_text, \
|
||||||
.key_merge = bch2_reflink_p_merge, \
|
.key_merge = bch2_reflink_p_merge, \
|
||||||
.trigger = bch2_trigger_reflink_p, \
|
.trigger = bch2_trigger_reflink_p, \
|
||||||
.min_val_size = 16, \
|
.min_val_size = 16, \
|
||||||
})
|
})
|
||||||
|
|
||||||
int bch2_reflink_v_invalid(struct bch_fs *, struct bkey_s_c,
|
int bch2_reflink_v_validate(struct bch_fs *, struct bkey_s_c, enum bch_validate_flags);
|
||||||
enum bch_validate_flags, struct printbuf *);
|
void bch2_reflink_v_to_text(struct printbuf *, struct bch_fs *, struct bkey_s_c);
|
||||||
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,
|
int bch2_trigger_reflink_v(struct btree_trans *, enum btree_id, unsigned,
|
||||||
struct bkey_s_c, struct bkey_s,
|
struct bkey_s_c, struct bkey_s,
|
||||||
enum btree_iter_update_trigger_flags);
|
enum btree_iter_update_trigger_flags);
|
||||||
|
|
||||||
#define bch2_bkey_ops_reflink_v ((struct bkey_ops) { \
|
#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, \
|
.val_to_text = bch2_reflink_v_to_text, \
|
||||||
.swab = bch2_ptr_swab, \
|
.swab = bch2_ptr_swab, \
|
||||||
.trigger = bch2_trigger_reflink_v, \
|
.trigger = bch2_trigger_reflink_v, \
|
||||||
.min_val_size = 8, \
|
.min_val_size = 8, \
|
||||||
})
|
})
|
||||||
|
|
||||||
int bch2_indirect_inline_data_invalid(struct bch_fs *, struct bkey_s_c,
|
int bch2_indirect_inline_data_validate(struct bch_fs *, struct bkey_s_c,
|
||||||
enum bch_validate_flags, struct printbuf *);
|
enum bch_validate_flags);
|
||||||
void bch2_indirect_inline_data_to_text(struct printbuf *,
|
void bch2_indirect_inline_data_to_text(struct printbuf *,
|
||||||
struct bch_fs *, struct bkey_s_c);
|
struct bch_fs *, struct bkey_s_c);
|
||||||
int bch2_trigger_indirect_inline_data(struct btree_trans *,
|
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);
|
enum btree_iter_update_trigger_flags);
|
||||||
|
|
||||||
#define bch2_bkey_ops_indirect_inline_data ((struct bkey_ops) { \
|
#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, \
|
.val_to_text = bch2_indirect_inline_data_to_text, \
|
||||||
.trigger = bch2_trigger_indirect_inline_data, \
|
.trigger = bch2_trigger_indirect_inline_data, \
|
||||||
.min_val_size = 8, \
|
.min_val_size = 8, \
|
||||||
|
@ -81,7 +81,8 @@
|
|||||||
x(trans_restart_write_buffer_flush, 75) \
|
x(trans_restart_write_buffer_flush, 75) \
|
||||||
x(trans_restart_split_race, 76) \
|
x(trans_restart_split_race, 76) \
|
||||||
x(write_buffer_flush_slowpath, 77) \
|
x(write_buffer_flush_slowpath, 77) \
|
||||||
x(write_buffer_flush_sync, 78)
|
x(write_buffer_flush_sync, 78) \
|
||||||
|
x(trans_restart_freeing_inode, 79)
|
||||||
|
|
||||||
enum bch_persistent_counters {
|
enum bch_persistent_counters {
|
||||||
#define x(t, n, ...) BCH_COUNTER_##t,
|
#define x(t, n, ...) BCH_COUNTER_##t,
|
||||||
|
@ -72,7 +72,10 @@
|
|||||||
BCH_FSCK_ERR_accounting_key_replicas_nr_devs_0, \
|
BCH_FSCK_ERR_accounting_key_replicas_nr_devs_0, \
|
||||||
BCH_FSCK_ERR_accounting_key_replicas_nr_required_bad, \
|
BCH_FSCK_ERR_accounting_key_replicas_nr_required_bad, \
|
||||||
BCH_FSCK_ERR_accounting_key_replicas_devs_unsorted, \
|
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() \
|
#define DOWNGRADE_TABLE() \
|
||||||
x(bucket_stripe_sectors, \
|
x(bucket_stripe_sectors, \
|
||||||
@ -104,6 +107,7 @@
|
|||||||
BCH_FSCK_ERR_fs_usage_nr_inodes_wrong, \
|
BCH_FSCK_ERR_fs_usage_nr_inodes_wrong, \
|
||||||
BCH_FSCK_ERR_fs_usage_persistent_reserved_wrong, \
|
BCH_FSCK_ERR_fs_usage_persistent_reserved_wrong, \
|
||||||
BCH_FSCK_ERR_fs_usage_replicas_wrong, \
|
BCH_FSCK_ERR_fs_usage_replicas_wrong, \
|
||||||
|
BCH_FSCK_ERR_accounting_replicas_not_marked, \
|
||||||
BCH_FSCK_ERR_bkey_version_in_future)
|
BCH_FSCK_ERR_bkey_version_in_future)
|
||||||
|
|
||||||
struct upgrade_downgrade_entry {
|
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));
|
le32_to_cpu(t.v->root_snapshot));
|
||||||
}
|
}
|
||||||
|
|
||||||
int bch2_snapshot_tree_invalid(struct bch_fs *c, struct bkey_s_c k,
|
int bch2_snapshot_tree_validate(struct bch_fs *c, struct bkey_s_c k,
|
||||||
enum bch_validate_flags flags,
|
enum bch_validate_flags flags)
|
||||||
struct printbuf *err)
|
|
||||||
{
|
{
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
|
|
||||||
bkey_fsck_err_on(bkey_gt(k.k->p, POS(0, U32_MAX)) ||
|
bkey_fsck_err_on(bkey_gt(k.k->p, POS(0, U32_MAX)) ||
|
||||||
bkey_lt(k.k->p, POS(0, 1)), c, err,
|
bkey_lt(k.k->p, POS(0, 1)),
|
||||||
snapshot_tree_pos_bad,
|
c, snapshot_tree_pos_bad,
|
||||||
"bad pos");
|
"bad pos");
|
||||||
fsck_err:
|
fsck_err:
|
||||||
return ret;
|
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]));
|
le32_to_cpu(s.v->skip[2]));
|
||||||
}
|
}
|
||||||
|
|
||||||
int bch2_snapshot_invalid(struct bch_fs *c, struct bkey_s_c k,
|
int bch2_snapshot_validate(struct bch_fs *c, struct bkey_s_c k,
|
||||||
enum bch_validate_flags flags,
|
enum bch_validate_flags flags)
|
||||||
struct printbuf *err)
|
|
||||||
{
|
{
|
||||||
struct bkey_s_c_snapshot s;
|
struct bkey_s_c_snapshot s;
|
||||||
u32 i, id;
|
u32 i, id;
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
|
|
||||||
bkey_fsck_err_on(bkey_gt(k.k->p, POS(0, U32_MAX)) ||
|
bkey_fsck_err_on(bkey_gt(k.k->p, POS(0, U32_MAX)) ||
|
||||||
bkey_lt(k.k->p, POS(0, 1)), c, err,
|
bkey_lt(k.k->p, POS(0, 1)),
|
||||||
snapshot_pos_bad,
|
c, snapshot_pos_bad,
|
||||||
"bad pos");
|
"bad pos");
|
||||||
|
|
||||||
s = bkey_s_c_to_snapshot(k);
|
s = bkey_s_c_to_snapshot(k);
|
||||||
|
|
||||||
id = le32_to_cpu(s.v->parent);
|
id = le32_to_cpu(s.v->parent);
|
||||||
bkey_fsck_err_on(id && id <= k.k->p.offset, c, err,
|
bkey_fsck_err_on(id && id <= k.k->p.offset,
|
||||||
snapshot_parent_bad,
|
c, snapshot_parent_bad,
|
||||||
"bad parent node (%u <= %llu)",
|
"bad parent node (%u <= %llu)",
|
||||||
id, k.k->p.offset);
|
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,
|
bkey_fsck_err_on(le32_to_cpu(s.v->children[0]) < le32_to_cpu(s.v->children[1]),
|
||||||
snapshot_children_not_normalized,
|
c, snapshot_children_not_normalized,
|
||||||
"children not normalized");
|
"children not normalized");
|
||||||
|
|
||||||
bkey_fsck_err_on(s.v->children[0] && s.v->children[0] == s.v->children[1], c, err,
|
bkey_fsck_err_on(s.v->children[0] && s.v->children[0] == s.v->children[1],
|
||||||
snapshot_child_duplicate,
|
c, snapshot_child_duplicate,
|
||||||
"duplicate child nodes");
|
"duplicate child nodes");
|
||||||
|
|
||||||
for (i = 0; i < 2; i++) {
|
for (i = 0; i < 2; i++) {
|
||||||
id = le32_to_cpu(s.v->children[i]);
|
id = le32_to_cpu(s.v->children[i]);
|
||||||
|
|
||||||
bkey_fsck_err_on(id >= k.k->p.offset, c, err,
|
bkey_fsck_err_on(id >= k.k->p.offset,
|
||||||
snapshot_child_bad,
|
c, snapshot_child_bad,
|
||||||
"bad child node (%u >= %llu)",
|
"bad child node (%u >= %llu)",
|
||||||
id, k.k->p.offset);
|
id, k.k->p.offset);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (bkey_val_bytes(k.k) > offsetof(struct bch_snapshot, skip)) {
|
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]) ||
|
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,
|
le32_to_cpu(s.v->skip[1]) > le32_to_cpu(s.v->skip[2]),
|
||||||
snapshot_skiplist_not_normalized,
|
c, snapshot_skiplist_not_normalized,
|
||||||
"skiplist not normalized");
|
"skiplist not normalized");
|
||||||
|
|
||||||
for (i = 0; i < ARRAY_SIZE(s.v->skip); i++) {
|
for (i = 0; i < ARRAY_SIZE(s.v->skip); i++) {
|
||||||
id = le32_to_cpu(s.v->skip[i]);
|
id = le32_to_cpu(s.v->skip[i]);
|
||||||
|
|
||||||
bkey_fsck_err_on(id && id < le32_to_cpu(s.v->parent), c, err,
|
bkey_fsck_err_on(id && id < le32_to_cpu(s.v->parent),
|
||||||
snapshot_skiplist_bad,
|
c, snapshot_skiplist_bad,
|
||||||
"bad skiplist node %u", id);
|
"bad skiplist node %u", id);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -5,11 +5,11 @@
|
|||||||
enum bch_validate_flags;
|
enum bch_validate_flags;
|
||||||
|
|
||||||
void bch2_snapshot_tree_to_text(struct printbuf *, struct bch_fs *, struct bkey_s_c);
|
void bch2_snapshot_tree_to_text(struct printbuf *, struct bch_fs *, struct bkey_s_c);
|
||||||
int bch2_snapshot_tree_invalid(struct bch_fs *, struct bkey_s_c,
|
int bch2_snapshot_tree_validate(struct bch_fs *, struct bkey_s_c,
|
||||||
enum bch_validate_flags, struct printbuf *);
|
enum bch_validate_flags);
|
||||||
|
|
||||||
#define bch2_bkey_ops_snapshot_tree ((struct bkey_ops) { \
|
#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, \
|
.val_to_text = bch2_snapshot_tree_to_text, \
|
||||||
.min_val_size = 8, \
|
.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 *);
|
int bch2_snapshot_tree_lookup(struct btree_trans *, u32, struct bch_snapshot_tree *);
|
||||||
|
|
||||||
void bch2_snapshot_to_text(struct printbuf *, struct bch_fs *, struct bkey_s_c);
|
void bch2_snapshot_to_text(struct printbuf *, struct bch_fs *, struct bkey_s_c);
|
||||||
int bch2_snapshot_invalid(struct bch_fs *, struct bkey_s_c,
|
int bch2_snapshot_validate(struct bch_fs *, struct bkey_s_c, enum bch_validate_flags);
|
||||||
enum bch_validate_flags, struct printbuf *);
|
|
||||||
int bch2_mark_snapshot(struct btree_trans *, enum btree_id, unsigned,
|
int bch2_mark_snapshot(struct btree_trans *, enum btree_id, unsigned,
|
||||||
struct bkey_s_c, struct bkey_s,
|
struct bkey_s_c, struct bkey_s,
|
||||||
enum btree_iter_update_trigger_flags);
|
enum btree_iter_update_trigger_flags);
|
||||||
|
|
||||||
#define bch2_bkey_ops_snapshot ((struct bkey_ops) { \
|
#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, \
|
.val_to_text = bch2_snapshot_to_text, \
|
||||||
.trigger = bch2_mark_snapshot, \
|
.trigger = bch2_mark_snapshot, \
|
||||||
.min_val_size = 24, \
|
.min_val_size = 24, \
|
||||||
|
@ -207,23 +207,23 @@ int bch2_check_subvol_children(struct bch_fs *c)
|
|||||||
|
|
||||||
/* Subvolumes: */
|
/* Subvolumes: */
|
||||||
|
|
||||||
int bch2_subvolume_invalid(struct bch_fs *c, struct bkey_s_c k,
|
int bch2_subvolume_validate(struct bch_fs *c, struct bkey_s_c k,
|
||||||
enum bch_validate_flags flags, struct printbuf *err)
|
enum bch_validate_flags flags)
|
||||||
{
|
{
|
||||||
struct bkey_s_c_subvolume subvol = bkey_s_c_to_subvolume(k);
|
struct bkey_s_c_subvolume subvol = bkey_s_c_to_subvolume(k);
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
|
|
||||||
bkey_fsck_err_on(bkey_lt(k.k->p, SUBVOL_POS_MIN) ||
|
bkey_fsck_err_on(bkey_lt(k.k->p, SUBVOL_POS_MIN) ||
|
||||||
bkey_gt(k.k->p, SUBVOL_POS_MAX), c, err,
|
bkey_gt(k.k->p, SUBVOL_POS_MAX),
|
||||||
subvol_pos_bad,
|
c, subvol_pos_bad,
|
||||||
"invalid pos");
|
"invalid pos");
|
||||||
|
|
||||||
bkey_fsck_err_on(!subvol.v->snapshot, c, err,
|
bkey_fsck_err_on(!subvol.v->snapshot,
|
||||||
subvol_snapshot_bad,
|
c, subvol_snapshot_bad,
|
||||||
"invalid snapshot");
|
"invalid snapshot");
|
||||||
|
|
||||||
bkey_fsck_err_on(!subvol.v->inode, c, err,
|
bkey_fsck_err_on(!subvol.v->inode,
|
||||||
subvol_inode_bad,
|
c, subvol_inode_bad,
|
||||||
"invalid inode");
|
"invalid inode");
|
||||||
fsck_err:
|
fsck_err:
|
||||||
return ret;
|
return ret;
|
||||||
|
@ -10,15 +10,14 @@ enum bch_validate_flags;
|
|||||||
int bch2_check_subvols(struct bch_fs *);
|
int bch2_check_subvols(struct bch_fs *);
|
||||||
int bch2_check_subvol_children(struct bch_fs *);
|
int bch2_check_subvol_children(struct bch_fs *);
|
||||||
|
|
||||||
int bch2_subvolume_invalid(struct bch_fs *, struct bkey_s_c,
|
int bch2_subvolume_validate(struct bch_fs *, struct bkey_s_c, enum bch_validate_flags);
|
||||||
enum bch_validate_flags, struct printbuf *);
|
|
||||||
void bch2_subvolume_to_text(struct printbuf *, struct bch_fs *, struct bkey_s_c);
|
void bch2_subvolume_to_text(struct printbuf *, struct bch_fs *, struct bkey_s_c);
|
||||||
int bch2_subvolume_trigger(struct btree_trans *, enum btree_id, unsigned,
|
int bch2_subvolume_trigger(struct btree_trans *, enum btree_id, unsigned,
|
||||||
struct bkey_s_c, struct bkey_s,
|
struct bkey_s_c, struct bkey_s,
|
||||||
enum btree_iter_update_trigger_flags);
|
enum btree_iter_update_trigger_flags);
|
||||||
|
|
||||||
#define bch2_bkey_ops_subvolume ((struct bkey_ops) { \
|
#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, \
|
.val_to_text = bch2_subvolume_to_text, \
|
||||||
.trigger = bch2_subvolume_trigger, \
|
.trigger = bch2_subvolume_trigger, \
|
||||||
.min_val_size = 16, \
|
.min_val_size = 16, \
|
||||||
|
@ -30,7 +30,8 @@ struct snapshot_table {
|
|||||||
};
|
};
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
u32 subvol;
|
/* we can't have padding in this struct: */
|
||||||
|
u64 subvol;
|
||||||
u64 inum;
|
u64 inum;
|
||||||
} subvol_inum;
|
} subvol_inum;
|
||||||
|
|
||||||
|
@ -4,6 +4,7 @@
|
|||||||
#include "buckets.h"
|
#include "buckets.h"
|
||||||
#include "btree_cache.h"
|
#include "btree_cache.h"
|
||||||
#include "btree_iter.h"
|
#include "btree_iter.h"
|
||||||
|
#include "btree_key_cache.h"
|
||||||
#include "btree_locking.h"
|
#include "btree_locking.h"
|
||||||
#include "btree_update_interior.h"
|
#include "btree_update_interior.h"
|
||||||
#include "keylist.h"
|
#include "keylist.h"
|
||||||
|
@ -993,10 +993,33 @@ TRACE_EVENT(trans_restart_split_race,
|
|||||||
__entry->u64s_remaining)
|
__entry->u64s_remaining)
|
||||||
);
|
);
|
||||||
|
|
||||||
DEFINE_EVENT(transaction_event, trans_blocked_journal_reclaim,
|
TRACE_EVENT(trans_blocked_journal_reclaim,
|
||||||
TP_PROTO(struct btree_trans *trans,
|
TP_PROTO(struct btree_trans *trans,
|
||||||
unsigned long caller_ip),
|
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,
|
TRACE_EVENT(trans_restart_journal_preres_get,
|
||||||
@ -1293,6 +1316,12 @@ TRACE_EVENT(trans_restart_key_cache_key_realloced,
|
|||||||
__entry->new_u64s)
|
__entry->new_u64s)
|
||||||
);
|
);
|
||||||
|
|
||||||
|
DEFINE_EVENT(transaction_event, trans_restart_freeing_inode,
|
||||||
|
TP_PROTO(struct btree_trans *trans,
|
||||||
|
unsigned long caller_ip),
|
||||||
|
TP_ARGS(trans, caller_ip)
|
||||||
|
);
|
||||||
|
|
||||||
TRACE_EVENT(path_downgrade,
|
TRACE_EVENT(path_downgrade,
|
||||||
TP_PROTO(struct btree_trans *trans,
|
TP_PROTO(struct btree_trans *trans,
|
||||||
unsigned long caller_ip,
|
unsigned long caller_ip,
|
||||||
|
@ -70,17 +70,16 @@ const struct bch_hash_desc bch2_xattr_hash_desc = {
|
|||||||
.cmp_bkey = xattr_cmp_bkey,
|
.cmp_bkey = xattr_cmp_bkey,
|
||||||
};
|
};
|
||||||
|
|
||||||
int bch2_xattr_invalid(struct bch_fs *c, struct bkey_s_c k,
|
int bch2_xattr_validate(struct bch_fs *c, struct bkey_s_c k,
|
||||||
enum bch_validate_flags flags,
|
enum bch_validate_flags flags)
|
||||||
struct printbuf *err)
|
|
||||||
{
|
{
|
||||||
struct bkey_s_c_xattr xattr = bkey_s_c_to_xattr(k);
|
struct bkey_s_c_xattr xattr = bkey_s_c_to_xattr(k);
|
||||||
unsigned val_u64s = xattr_val_u64s(xattr.v->x_name_len,
|
unsigned val_u64s = xattr_val_u64s(xattr.v->x_name_len,
|
||||||
le16_to_cpu(xattr.v->x_val_len));
|
le16_to_cpu(xattr.v->x_val_len));
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
|
|
||||||
bkey_fsck_err_on(bkey_val_u64s(k.k) < val_u64s, c, err,
|
bkey_fsck_err_on(bkey_val_u64s(k.k) < val_u64s,
|
||||||
xattr_val_size_too_small,
|
c, xattr_val_size_too_small,
|
||||||
"value too small (%zu < %u)",
|
"value too small (%zu < %u)",
|
||||||
bkey_val_u64s(k.k), val_u64s);
|
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,
|
val_u64s = xattr_val_u64s(xattr.v->x_name_len,
|
||||||
le16_to_cpu(xattr.v->x_val_len) + 4);
|
le16_to_cpu(xattr.v->x_val_len) + 4);
|
||||||
|
|
||||||
bkey_fsck_err_on(bkey_val_u64s(k.k) > val_u64s, c, err,
|
bkey_fsck_err_on(bkey_val_u64s(k.k) > val_u64s,
|
||||||
xattr_val_size_too_big,
|
c, xattr_val_size_too_big,
|
||||||
"value too big (%zu > %u)",
|
"value too big (%zu > %u)",
|
||||||
bkey_val_u64s(k.k), val_u64s);
|
bkey_val_u64s(k.k), val_u64s);
|
||||||
|
|
||||||
bkey_fsck_err_on(!bch2_xattr_type_to_handler(xattr.v->x_type), c, err,
|
bkey_fsck_err_on(!bch2_xattr_type_to_handler(xattr.v->x_type),
|
||||||
xattr_invalid_type,
|
c, xattr_invalid_type,
|
||||||
"invalid type (%u)", xattr.v->x_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,
|
bkey_fsck_err_on(memchr(xattr.v->x_name, '\0', xattr.v->x_name_len),
|
||||||
xattr_name_invalid_chars,
|
c, xattr_name_invalid_chars,
|
||||||
"xattr name has invalid characters");
|
"xattr name has invalid characters");
|
||||||
fsck_err:
|
fsck_err:
|
||||||
return ret;
|
return ret;
|
||||||
@ -251,17 +250,27 @@ static int __bch2_xattr_emit(const char *prefix,
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline const char *bch2_xattr_prefix(unsigned type, struct dentry *dentry)
|
||||||
|
{
|
||||||
|
const struct xattr_handler *handler = bch2_xattr_type_to_handler(type);
|
||||||
|
|
||||||
|
if (!xattr_handler_can_list(handler, dentry))
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
return xattr_prefix(handler);
|
||||||
|
}
|
||||||
|
|
||||||
static int bch2_xattr_emit(struct dentry *dentry,
|
static int bch2_xattr_emit(struct dentry *dentry,
|
||||||
const struct bch_xattr *xattr,
|
const struct bch_xattr *xattr,
|
||||||
struct xattr_buf *buf)
|
struct xattr_buf *buf)
|
||||||
{
|
{
|
||||||
const struct xattr_handler *handler =
|
const char *prefix;
|
||||||
bch2_xattr_type_to_handler(xattr->x_type);
|
|
||||||
|
|
||||||
return handler && (!handler->list || handler->list(dentry))
|
prefix = bch2_xattr_prefix(xattr->x_type, dentry);
|
||||||
? __bch2_xattr_emit(handler->prefix ?: handler->name,
|
if (!prefix)
|
||||||
xattr->x_name, xattr->x_name_len, buf)
|
return 0;
|
||||||
: 0;
|
|
||||||
|
return __bch2_xattr_emit(prefix, xattr->x_name, xattr->x_name_len, buf);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int bch2_xattr_list_bcachefs(struct bch_fs *c,
|
static int bch2_xattr_list_bcachefs(struct bch_fs *c,
|
||||||
@ -592,10 +601,6 @@ static const struct xattr_handler bch_xattr_bcachefs_effective_handler = {
|
|||||||
|
|
||||||
const struct xattr_handler *bch2_xattr_handlers[] = {
|
const struct xattr_handler *bch2_xattr_handlers[] = {
|
||||||
&bch_xattr_user_handler,
|
&bch_xattr_user_handler,
|
||||||
#ifdef CONFIG_BCACHEFS_POSIX_ACL
|
|
||||||
&nop_posix_acl_access,
|
|
||||||
&nop_posix_acl_default,
|
|
||||||
#endif
|
|
||||||
&bch_xattr_trusted_handler,
|
&bch_xattr_trusted_handler,
|
||||||
&bch_xattr_security_handler,
|
&bch_xattr_security_handler,
|
||||||
#ifndef NO_BCACHEFS_FS
|
#ifndef NO_BCACHEFS_FS
|
||||||
|
@ -6,12 +6,11 @@
|
|||||||
|
|
||||||
extern const struct bch_hash_desc bch2_xattr_hash_desc;
|
extern const struct bch_hash_desc bch2_xattr_hash_desc;
|
||||||
|
|
||||||
int bch2_xattr_invalid(struct bch_fs *, struct bkey_s_c,
|
int bch2_xattr_validate(struct bch_fs *, struct bkey_s_c, enum bch_validate_flags);
|
||||||
enum bch_validate_flags, struct printbuf *);
|
|
||||||
void bch2_xattr_to_text(struct printbuf *, struct bch_fs *, struct bkey_s_c);
|
void bch2_xattr_to_text(struct printbuf *, struct bch_fs *, struct bkey_s_c);
|
||||||
|
|
||||||
#define bch2_bkey_ops_xattr ((struct bkey_ops) { \
|
#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, \
|
.val_to_text = bch2_xattr_to_text, \
|
||||||
.min_val_size = 8, \
|
.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) {
|
if ((v = cmpxchg_release(&radix->root, r, new_root)) == r) {
|
||||||
v = new_root;
|
v = new_root;
|
||||||
new_node = NULL;
|
new_node = NULL;
|
||||||
|
} else {
|
||||||
|
new_node->children[0] = NULL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user