diff options
author | Kent Overstreet <kent.overstreet@linux.dev> | 2024-04-20 02:03:58 +0300 |
---|---|---|
committer | Kent Overstreet <kent.overstreet@linux.dev> | 2024-05-09 00:29:20 +0300 |
commit | 70e3e039cf65f67fa3c41b51cb00a58f6cd48886 (patch) | |
tree | ceb664bcda1e3abf653a0e2f489aa6c04a3e4f9b | |
parent | 9cc455d1bcd3bd44d1f103bf3f2e58293976a006 (diff) | |
download | linux-70e3e039cf65f67fa3c41b51cb00a58f6cd48886.tar.xz |
bcachefs: bch2_bucket_ref_update()
If we hit an inconsistency when updating allocation information, we
don't want to fail the update if it's for a deletion - only if it's for
a new key.
Rename check_bucket_ref() -> bucket_ref_update() so we can centralize
the logic to do this.
Signed-off-by: Kent Overstreet <kent.overstreet@linux.dev>
-rw-r--r-- | fs/bcachefs/buckets.c | 55 | ||||
-rw-r--r-- | fs/bcachefs/buckets.h | 6 | ||||
-rw-r--r-- | fs/bcachefs/ec.c | 14 |
3 files changed, 42 insertions, 33 deletions
diff --git a/fs/bcachefs/buckets.c b/fs/bcachefs/buckets.c index 36d13819a27d..adaa66f7764a 100644 --- a/fs/bcachefs/buckets.c +++ b/fs/bcachefs/buckets.c @@ -485,19 +485,22 @@ int bch2_update_cached_sectors_list(struct btree_trans *trans, unsigned dev, s64 return bch2_update_replicas_list(trans, &r.e, sectors); } -int bch2_check_bucket_ref(struct btree_trans *trans, +int bch2_bucket_ref_update(struct btree_trans *trans, struct bkey_s_c k, const struct bch_extent_ptr *ptr, s64 sectors, enum bch_data_type ptr_data_type, u8 b_gen, u8 bucket_data_type, - u32 bucket_sectors) + u32 *bucket_sectors) { struct bch_fs *c = trans->c; struct bch_dev *ca = bch2_dev_bkey_exists(c, ptr->dev); size_t bucket_nr = PTR_BUCKET_NR(ca, ptr); struct printbuf buf = PRINTBUF; + bool inserting = sectors > 0; int ret = 0; + BUG_ON(!sectors); + if (gen_after(ptr->gen, b_gen)) { bch2_fsck_err(c, FSCK_CAN_IGNORE|FSCK_NEED_FSCK, BCH_FSCK_ERR_ptr_gen_newer_than_bucket_gen, @@ -507,8 +510,9 @@ int bch2_check_bucket_ref(struct btree_trans *trans, bch2_data_type_str(bucket_data_type ?: ptr_data_type), ptr->gen, (bch2_bkey_val_to_text(&buf, c, k), buf.buf)); - ret = -EIO; - goto err; + if (inserting) + goto err; + goto out; } if (gen_cmp(b_gen, ptr->gen) > BUCKET_GC_GEN_MAX) { @@ -521,11 +525,17 @@ int bch2_check_bucket_ref(struct btree_trans *trans, ptr->gen, (printbuf_reset(&buf), bch2_bkey_val_to_text(&buf, c, k), buf.buf)); - ret = -EIO; - goto err; + if (inserting) + goto err; + goto out; } - if (b_gen != ptr->gen && !ptr->cached) { + if (b_gen != ptr->gen && ptr->cached) { + ret = 1; + goto out; + } + + if (b_gen != ptr->gen) { bch2_fsck_err(c, FSCK_CAN_IGNORE|FSCK_NEED_FSCK, BCH_FSCK_ERR_stale_dirty_ptr, "bucket %u:%zu gen %u (mem gen %u) data type %s: stale dirty ptr (gen %u)\n" @@ -536,12 +546,8 @@ int bch2_check_bucket_ref(struct btree_trans *trans, ptr->gen, (printbuf_reset(&buf), bch2_bkey_val_to_text(&buf, c, k), buf.buf)); - ret = -EIO; - goto err; - } - - if (b_gen != ptr->gen) { - ret = 1; + if (inserting) + goto err; goto out; } @@ -555,28 +561,33 @@ int bch2_check_bucket_ref(struct btree_trans *trans, bch2_data_type_str(ptr_data_type), (printbuf_reset(&buf), bch2_bkey_val_to_text(&buf, c, k), buf.buf)); - ret = -EIO; - goto err; + if (inserting) + goto err; + goto out; } - if ((u64) bucket_sectors + sectors > U32_MAX) { + if ((u64) *bucket_sectors + sectors > U32_MAX) { bch2_fsck_err(c, FSCK_CAN_IGNORE|FSCK_NEED_FSCK, BCH_FSCK_ERR_bucket_sector_count_overflow, "bucket %u:%zu gen %u data type %s sector count overflow: %u + %lli > U32_MAX\n" "while marking %s", ptr->dev, bucket_nr, b_gen, bch2_data_type_str(bucket_data_type ?: ptr_data_type), - bucket_sectors, sectors, + *bucket_sectors, sectors, (printbuf_reset(&buf), bch2_bkey_val_to_text(&buf, c, k), buf.buf)); - ret = -EIO; - goto err; + if (inserting) + goto err; + sectors = -*bucket_sectors; } + + *bucket_sectors += sectors; out: printbuf_exit(&buf); return ret; err: bch2_dump_trans_updates(trans); + ret = -EIO; goto out; } @@ -723,14 +734,12 @@ static int __mark_pointer(struct btree_trans *trans, u32 *dst_sectors = !ptr->cached ? dirty_sectors : cached_sectors; - int ret = bch2_check_bucket_ref(trans, k, ptr, sectors, ptr_data_type, - bucket_gen, *bucket_data_type, *dst_sectors); + int ret = bch2_bucket_ref_update(trans, k, ptr, sectors, ptr_data_type, + bucket_gen, *bucket_data_type, dst_sectors); if (ret) return ret; - *dst_sectors += sectors; - if (!*dirty_sectors && !*cached_sectors) *bucket_data_type = 0; else if (*bucket_data_type != BCH_DATA_stripe) diff --git a/fs/bcachefs/buckets.h b/fs/bcachefs/buckets.h index a88b9033349f..c2c2ac36bee5 100644 --- a/fs/bcachefs/buckets.h +++ b/fs/bcachefs/buckets.h @@ -337,9 +337,9 @@ int bch2_replicas_deltas_realloc(struct btree_trans *, unsigned); void bch2_fs_usage_initialize(struct bch_fs *); -int bch2_check_bucket_ref(struct btree_trans *, struct bkey_s_c, - const struct bch_extent_ptr *, - s64, enum bch_data_type, u8, u8, u32); +int bch2_bucket_ref_update(struct btree_trans *, struct bkey_s_c, + const struct bch_extent_ptr *, + s64, enum bch_data_type, u8, u8, u32 *); int bch2_trigger_extent(struct btree_trans *, enum btree_id, unsigned, struct bkey_s_c, struct bkey_s, diff --git a/fs/bcachefs/ec.c b/fs/bcachefs/ec.c index 2d1b20856841..31db3c8fce50 100644 --- a/fs/bcachefs/ec.c +++ b/fs/bcachefs/ec.c @@ -243,13 +243,13 @@ static int __mark_stripe_bucket(struct btree_trans *trans, } } - ret = bch2_check_bucket_ref(trans, s.s_c, ptr, sectors, data_type, - bucket_gen, *bucket_data_type, - *bucket_dirty_sectors); - if (ret) - goto err; - - *bucket_dirty_sectors += sectors; + if (sectors) { + ret = bch2_bucket_ref_update(trans, s.s_c, ptr, sectors, data_type, + bucket_gen, *bucket_data_type, + bucket_dirty_sectors); + if (ret) + goto err; + } if (!deleting) { *bucket_stripe = s.k->p.offset; |