Loading fs/bcachefs/alloc_background.c +20 −2 Original line number Diff line number Diff line Loading @@ -741,6 +741,7 @@ int bch2_trigger_alloc(struct btree_trans *trans, enum btree_iter_update_trigger_flags flags) { struct bch_fs *c = trans->c; struct printbuf buf = PRINTBUF; int ret = 0; struct bch_dev *ca = bch2_dev_bucket_tryget(c, new.k->p); Loading Loading @@ -860,8 +861,14 @@ int bch2_trigger_alloc(struct btree_trans *trans, } percpu_down_read(&c->mark_lock); if (new_a->gen != old_a->gen) *bucket_gen(ca, new.k->p.offset) = new_a->gen; if (new_a->gen != old_a->gen) { u8 *gen = bucket_gen(ca, new.k->p.offset); if (unlikely(!gen)) { percpu_up_read(&c->mark_lock); goto invalid_bucket; } *gen = new_a->gen; } bch2_dev_usage_update(c, ca, old_a, new_a, journal_seq, false); percpu_up_read(&c->mark_lock); Loading Loading @@ -895,6 +902,11 @@ int bch2_trigger_alloc(struct btree_trans *trans, percpu_down_read(&c->mark_lock); struct bucket *g = gc_bucket(ca, new.k->p.offset); if (unlikely(!g)) { percpu_up_read(&c->mark_lock); goto invalid_bucket; } g->gen_valid = 1; bucket_lock(g); Loading @@ -910,8 +922,14 @@ int bch2_trigger_alloc(struct btree_trans *trans, percpu_up_read(&c->mark_lock); } err: printbuf_exit(&buf); bch2_dev_put(ca); return ret; invalid_bucket: bch2_fs_inconsistent(c, "reference to invalid bucket\n %s", (bch2_bkey_val_to_text(&buf, c, new.s_c), buf.buf)); ret = -EIO; goto err; } /* Loading fs/bcachefs/btree_gc.c +10 −5 Original line number Diff line number Diff line Loading @@ -874,6 +874,9 @@ static int bch2_alloc_write_key(struct btree_trans *trans, const struct bch_alloc_v4 *old; int ret; if (!bucket_valid(ca, k.k->p.offset)) return 0; old = bch2_alloc_to_v4(k, &old_convert); gc = new = *old; Loading Loading @@ -1005,12 +1008,14 @@ static int bch2_gc_alloc_start(struct bch_fs *c) continue; } if (bucket_valid(ca, k.k->p.offset)) { struct bch_alloc_v4 a_convert; const struct bch_alloc_v4 *a = bch2_alloc_to_v4(k, &a_convert); struct bucket *g = gc_bucket(ca, k.k->p.offset); g->gen_valid = 1; g->gen = a->gen; } 0; }))); bch2_dev_put(ca); Loading fs/bcachefs/buckets.c +35 −15 Original line number Diff line number Diff line Loading @@ -488,6 +488,17 @@ static int bch2_check_fix_ptr(struct btree_trans *trans, } struct bucket *g = PTR_GC_BUCKET(ca, &p.ptr); if (!g) { if (fsck_err(c, ptr_to_invalid_device, "pointer to invalid bucket on device %u\n" "while marking %s", p.ptr.dev, (printbuf_reset(&buf), bch2_bkey_val_to_text(&buf, c, k), buf.buf))) *do_update = true; goto out; } enum bch_data_type data_type = bch2_bkey_ptr_data_type(k, p, entry); if (fsck_err_on(!g->gen_valid, Loading Loading @@ -577,8 +588,8 @@ static int bch2_check_fix_ptr(struct btree_trans *trans, if (p.has_ec) { struct gc_stripe *m = genradix_ptr(&c->gc_stripes, p.ec.idx); if (fsck_err_on(!m || !m->alive, c, ptr_to_missing_stripe, if (fsck_err_on(!m || !m->alive, c, ptr_to_missing_stripe, "pointer to nonexistent stripe %llu\n" "while marking %s", (u64) p.ec.idx, Loading @@ -586,8 +597,8 @@ static int bch2_check_fix_ptr(struct btree_trans *trans, bch2_bkey_val_to_text(&buf, c, k), buf.buf))) *do_update = true; if (fsck_err_on(m && m->alive && !bch2_ptr_matches_stripe_m(m, p), c, ptr_to_incorrect_stripe, if (fsck_err_on(m && m->alive && !bch2_ptr_matches_stripe_m(m, p), c, ptr_to_incorrect_stripe, "pointer does not match stripe %llu\n" "while marking %s", (u64) p.ec.idx, Loading Loading @@ -1004,6 +1015,7 @@ static int bch2_trigger_pointer(struct btree_trans *trans, enum btree_iter_update_trigger_flags flags) { bool insert = !(flags & BTREE_TRIGGER_overwrite); struct printbuf buf = PRINTBUF; int ret = 0; struct bch_fs *c = trans->c; Loading Loading @@ -1036,6 +1048,13 @@ static int bch2_trigger_pointer(struct btree_trans *trans, if (flags & BTREE_TRIGGER_gc) { percpu_down_read(&c->mark_lock); struct bucket *g = gc_bucket(ca, bucket.offset); if (bch2_fs_inconsistent_on(!g, c, "reference to invalid bucket on device %u\n %s", p.ptr.dev, (bch2_bkey_val_to_text(&buf, c, k), buf.buf))) { ret = -EIO; goto err_unlock; } bucket_lock(g); struct bch_alloc_v4 old = bucket_m_to_alloc(*g), new = old; ret = __mark_pointer(trans, ca, k, &p.ptr, *sectors, bp.data_type, &new); Loading @@ -1044,10 +1063,12 @@ static int bch2_trigger_pointer(struct btree_trans *trans, bch2_dev_usage_update(c, ca, &old, &new, 0, true); } bucket_unlock(g); err_unlock: percpu_up_read(&c->mark_lock); } err: bch2_dev_put(ca); printbuf_exit(&buf); return ret; } Loading Loading @@ -1335,10 +1356,11 @@ static int bch2_mark_metadata_bucket(struct bch_fs *c, struct bch_dev *ca, u64 b, enum bch_data_type data_type, unsigned sectors, enum btree_iter_update_trigger_flags flags) { int ret = 0; percpu_down_read(&c->mark_lock); struct bucket *g = gc_bucket(ca, b); if (bch2_fs_inconsistent_on(!g, c, "reference to invalid bucket on device %u when marking metadata type %s", ca->dev_idx, bch2_data_type_str(data_type))) goto err_unlock; bucket_lock(g); struct bch_alloc_v4 old = bucket_m_to_alloc(*g); Loading @@ -1347,29 +1369,27 @@ static int bch2_mark_metadata_bucket(struct bch_fs *c, struct bch_dev *ca, g->data_type != data_type, c, "different types of data in same bucket: %s, %s", bch2_data_type_str(g->data_type), bch2_data_type_str(data_type))) { ret = -EIO; bch2_data_type_str(data_type))) goto err; } if (bch2_fs_inconsistent_on((u64) g->dirty_sectors + sectors > ca->mi.bucket_size, c, "bucket %u:%llu gen %u data type %s sector count overflow: %u + %u > bucket size", ca->dev_idx, b, g->gen, bch2_data_type_str(g->data_type ?: data_type), g->dirty_sectors, sectors)) { ret = -EIO; g->dirty_sectors, sectors)) goto err; } g->data_type = data_type; g->dirty_sectors += sectors; struct bch_alloc_v4 new = bucket_m_to_alloc(*g); bch2_dev_usage_update(c, ca, &old, &new, 0, true); percpu_up_read(&c->mark_lock); return 0; err: bucket_unlock(g); if (!ret) bch2_dev_usage_update(c, ca, &old, &new, 0, true); err_unlock: percpu_up_read(&c->mark_lock); return ret; return -EIO; } int bch2_trans_mark_metadata_bucket(struct btree_trans *trans, Loading fs/bcachefs/buckets.h +7 −4 Original line number Diff line number Diff line Loading @@ -172,19 +172,22 @@ static inline int gen_after(u8 a, u8 b) return r > 0 ? r : 0; } static inline u8 dev_ptr_stale_rcu(struct bch_dev *ca, const struct bch_extent_ptr *ptr) static inline int dev_ptr_stale_rcu(struct bch_dev *ca, const struct bch_extent_ptr *ptr) { return gen_after(*bucket_gen(ca, PTR_BUCKET_NR(ca, ptr)), ptr->gen); u8 *gen = bucket_gen(ca, PTR_BUCKET_NR(ca, ptr)); if (!gen) return -1; return gen_after(*gen, ptr->gen); } /** * dev_ptr_stale() - check if a pointer points into a bucket that has been * invalidated. */ static inline u8 dev_ptr_stale(struct bch_dev *ca, const struct bch_extent_ptr *ptr) static inline int dev_ptr_stale(struct bch_dev *ca, const struct bch_extent_ptr *ptr) { rcu_read_lock(); u8 ret = dev_ptr_stale_rcu(ca, ptr); int ret = dev_ptr_stale_rcu(ca, ptr); rcu_read_unlock(); return ret; Loading fs/bcachefs/ec.c +20 −6 Original line number Diff line number Diff line Loading @@ -268,6 +268,7 @@ static int mark_stripe_bucket(struct btree_trans *trans, { struct bch_fs *c = trans->c; const struct bch_extent_ptr *ptr = s.v->ptrs + ptr_idx; struct printbuf buf = PRINTBUF; int ret = 0; struct bch_dev *ca = bch2_dev_tryget(c, ptr->dev); Loading @@ -289,6 +290,13 @@ static int mark_stripe_bucket(struct btree_trans *trans, if (flags & BTREE_TRIGGER_gc) { percpu_down_read(&c->mark_lock); struct bucket *g = gc_bucket(ca, bucket.offset); if (bch2_fs_inconsistent_on(!g, c, "reference to invalid bucket on device %u\n %s", ptr->dev, (bch2_bkey_val_to_text(&buf, c, s.s_c), buf.buf))) { ret = -EIO; goto err_unlock; } bucket_lock(g); struct bch_alloc_v4 old = bucket_m_to_alloc(*g), new = old; ret = __mark_stripe_bucket(trans, ca, s, ptr_idx, deleting, bucket, &new, flags); Loading @@ -297,10 +305,12 @@ static int mark_stripe_bucket(struct btree_trans *trans, bch2_dev_usage_update(c, ca, &old, &new, 0, true); } bucket_unlock(g); err_unlock: percpu_up_read(&c->mark_lock); } err: bch2_dev_put(ca); printbuf_exit(&buf); return ret; } Loading Loading @@ -714,10 +724,12 @@ static void ec_block_endio(struct bio *bio) bch2_blk_status_to_str(bio->bi_status))) clear_bit(ec_bio->idx, ec_bio->buf->valid); if (dev_ptr_stale(ca, ptr)) { int stale = dev_ptr_stale(ca, ptr); if (stale) { bch_err_ratelimited(ca->fs, "error %s stripe: stale pointer after io", bio_data_dir(bio) == READ ? "reading from" : "writing to"); "error %s stripe: stale/invalid pointer (%i) after io", bio_data_dir(bio) == READ ? "reading from" : "writing to", stale); clear_bit(ec_bio->idx, ec_bio->buf->valid); } Loading @@ -743,10 +755,12 @@ static void ec_block_io(struct bch_fs *c, struct ec_stripe_buf *buf, return; } if (dev_ptr_stale(ca, ptr)) { int stale = dev_ptr_stale(ca, ptr); if (stale) { bch_err_ratelimited(c, "error %s stripe: stale pointer", rw == READ ? "reading from" : "writing to"); "error %s stripe: stale pointer (%i)", rw == READ ? "reading from" : "writing to", stale); clear_bit(idx, buf->valid); return; } Loading Loading
fs/bcachefs/alloc_background.c +20 −2 Original line number Diff line number Diff line Loading @@ -741,6 +741,7 @@ int bch2_trigger_alloc(struct btree_trans *trans, enum btree_iter_update_trigger_flags flags) { struct bch_fs *c = trans->c; struct printbuf buf = PRINTBUF; int ret = 0; struct bch_dev *ca = bch2_dev_bucket_tryget(c, new.k->p); Loading Loading @@ -860,8 +861,14 @@ int bch2_trigger_alloc(struct btree_trans *trans, } percpu_down_read(&c->mark_lock); if (new_a->gen != old_a->gen) *bucket_gen(ca, new.k->p.offset) = new_a->gen; if (new_a->gen != old_a->gen) { u8 *gen = bucket_gen(ca, new.k->p.offset); if (unlikely(!gen)) { percpu_up_read(&c->mark_lock); goto invalid_bucket; } *gen = new_a->gen; } bch2_dev_usage_update(c, ca, old_a, new_a, journal_seq, false); percpu_up_read(&c->mark_lock); Loading Loading @@ -895,6 +902,11 @@ int bch2_trigger_alloc(struct btree_trans *trans, percpu_down_read(&c->mark_lock); struct bucket *g = gc_bucket(ca, new.k->p.offset); if (unlikely(!g)) { percpu_up_read(&c->mark_lock); goto invalid_bucket; } g->gen_valid = 1; bucket_lock(g); Loading @@ -910,8 +922,14 @@ int bch2_trigger_alloc(struct btree_trans *trans, percpu_up_read(&c->mark_lock); } err: printbuf_exit(&buf); bch2_dev_put(ca); return ret; invalid_bucket: bch2_fs_inconsistent(c, "reference to invalid bucket\n %s", (bch2_bkey_val_to_text(&buf, c, new.s_c), buf.buf)); ret = -EIO; goto err; } /* Loading
fs/bcachefs/btree_gc.c +10 −5 Original line number Diff line number Diff line Loading @@ -874,6 +874,9 @@ static int bch2_alloc_write_key(struct btree_trans *trans, const struct bch_alloc_v4 *old; int ret; if (!bucket_valid(ca, k.k->p.offset)) return 0; old = bch2_alloc_to_v4(k, &old_convert); gc = new = *old; Loading Loading @@ -1005,12 +1008,14 @@ static int bch2_gc_alloc_start(struct bch_fs *c) continue; } if (bucket_valid(ca, k.k->p.offset)) { struct bch_alloc_v4 a_convert; const struct bch_alloc_v4 *a = bch2_alloc_to_v4(k, &a_convert); struct bucket *g = gc_bucket(ca, k.k->p.offset); g->gen_valid = 1; g->gen = a->gen; } 0; }))); bch2_dev_put(ca); Loading
fs/bcachefs/buckets.c +35 −15 Original line number Diff line number Diff line Loading @@ -488,6 +488,17 @@ static int bch2_check_fix_ptr(struct btree_trans *trans, } struct bucket *g = PTR_GC_BUCKET(ca, &p.ptr); if (!g) { if (fsck_err(c, ptr_to_invalid_device, "pointer to invalid bucket on device %u\n" "while marking %s", p.ptr.dev, (printbuf_reset(&buf), bch2_bkey_val_to_text(&buf, c, k), buf.buf))) *do_update = true; goto out; } enum bch_data_type data_type = bch2_bkey_ptr_data_type(k, p, entry); if (fsck_err_on(!g->gen_valid, Loading Loading @@ -577,8 +588,8 @@ static int bch2_check_fix_ptr(struct btree_trans *trans, if (p.has_ec) { struct gc_stripe *m = genradix_ptr(&c->gc_stripes, p.ec.idx); if (fsck_err_on(!m || !m->alive, c, ptr_to_missing_stripe, if (fsck_err_on(!m || !m->alive, c, ptr_to_missing_stripe, "pointer to nonexistent stripe %llu\n" "while marking %s", (u64) p.ec.idx, Loading @@ -586,8 +597,8 @@ static int bch2_check_fix_ptr(struct btree_trans *trans, bch2_bkey_val_to_text(&buf, c, k), buf.buf))) *do_update = true; if (fsck_err_on(m && m->alive && !bch2_ptr_matches_stripe_m(m, p), c, ptr_to_incorrect_stripe, if (fsck_err_on(m && m->alive && !bch2_ptr_matches_stripe_m(m, p), c, ptr_to_incorrect_stripe, "pointer does not match stripe %llu\n" "while marking %s", (u64) p.ec.idx, Loading Loading @@ -1004,6 +1015,7 @@ static int bch2_trigger_pointer(struct btree_trans *trans, enum btree_iter_update_trigger_flags flags) { bool insert = !(flags & BTREE_TRIGGER_overwrite); struct printbuf buf = PRINTBUF; int ret = 0; struct bch_fs *c = trans->c; Loading Loading @@ -1036,6 +1048,13 @@ static int bch2_trigger_pointer(struct btree_trans *trans, if (flags & BTREE_TRIGGER_gc) { percpu_down_read(&c->mark_lock); struct bucket *g = gc_bucket(ca, bucket.offset); if (bch2_fs_inconsistent_on(!g, c, "reference to invalid bucket on device %u\n %s", p.ptr.dev, (bch2_bkey_val_to_text(&buf, c, k), buf.buf))) { ret = -EIO; goto err_unlock; } bucket_lock(g); struct bch_alloc_v4 old = bucket_m_to_alloc(*g), new = old; ret = __mark_pointer(trans, ca, k, &p.ptr, *sectors, bp.data_type, &new); Loading @@ -1044,10 +1063,12 @@ static int bch2_trigger_pointer(struct btree_trans *trans, bch2_dev_usage_update(c, ca, &old, &new, 0, true); } bucket_unlock(g); err_unlock: percpu_up_read(&c->mark_lock); } err: bch2_dev_put(ca); printbuf_exit(&buf); return ret; } Loading Loading @@ -1335,10 +1356,11 @@ static int bch2_mark_metadata_bucket(struct bch_fs *c, struct bch_dev *ca, u64 b, enum bch_data_type data_type, unsigned sectors, enum btree_iter_update_trigger_flags flags) { int ret = 0; percpu_down_read(&c->mark_lock); struct bucket *g = gc_bucket(ca, b); if (bch2_fs_inconsistent_on(!g, c, "reference to invalid bucket on device %u when marking metadata type %s", ca->dev_idx, bch2_data_type_str(data_type))) goto err_unlock; bucket_lock(g); struct bch_alloc_v4 old = bucket_m_to_alloc(*g); Loading @@ -1347,29 +1369,27 @@ static int bch2_mark_metadata_bucket(struct bch_fs *c, struct bch_dev *ca, g->data_type != data_type, c, "different types of data in same bucket: %s, %s", bch2_data_type_str(g->data_type), bch2_data_type_str(data_type))) { ret = -EIO; bch2_data_type_str(data_type))) goto err; } if (bch2_fs_inconsistent_on((u64) g->dirty_sectors + sectors > ca->mi.bucket_size, c, "bucket %u:%llu gen %u data type %s sector count overflow: %u + %u > bucket size", ca->dev_idx, b, g->gen, bch2_data_type_str(g->data_type ?: data_type), g->dirty_sectors, sectors)) { ret = -EIO; g->dirty_sectors, sectors)) goto err; } g->data_type = data_type; g->dirty_sectors += sectors; struct bch_alloc_v4 new = bucket_m_to_alloc(*g); bch2_dev_usage_update(c, ca, &old, &new, 0, true); percpu_up_read(&c->mark_lock); return 0; err: bucket_unlock(g); if (!ret) bch2_dev_usage_update(c, ca, &old, &new, 0, true); err_unlock: percpu_up_read(&c->mark_lock); return ret; return -EIO; } int bch2_trans_mark_metadata_bucket(struct btree_trans *trans, Loading
fs/bcachefs/buckets.h +7 −4 Original line number Diff line number Diff line Loading @@ -172,19 +172,22 @@ static inline int gen_after(u8 a, u8 b) return r > 0 ? r : 0; } static inline u8 dev_ptr_stale_rcu(struct bch_dev *ca, const struct bch_extent_ptr *ptr) static inline int dev_ptr_stale_rcu(struct bch_dev *ca, const struct bch_extent_ptr *ptr) { return gen_after(*bucket_gen(ca, PTR_BUCKET_NR(ca, ptr)), ptr->gen); u8 *gen = bucket_gen(ca, PTR_BUCKET_NR(ca, ptr)); if (!gen) return -1; return gen_after(*gen, ptr->gen); } /** * dev_ptr_stale() - check if a pointer points into a bucket that has been * invalidated. */ static inline u8 dev_ptr_stale(struct bch_dev *ca, const struct bch_extent_ptr *ptr) static inline int dev_ptr_stale(struct bch_dev *ca, const struct bch_extent_ptr *ptr) { rcu_read_lock(); u8 ret = dev_ptr_stale_rcu(ca, ptr); int ret = dev_ptr_stale_rcu(ca, ptr); rcu_read_unlock(); return ret; Loading
fs/bcachefs/ec.c +20 −6 Original line number Diff line number Diff line Loading @@ -268,6 +268,7 @@ static int mark_stripe_bucket(struct btree_trans *trans, { struct bch_fs *c = trans->c; const struct bch_extent_ptr *ptr = s.v->ptrs + ptr_idx; struct printbuf buf = PRINTBUF; int ret = 0; struct bch_dev *ca = bch2_dev_tryget(c, ptr->dev); Loading @@ -289,6 +290,13 @@ static int mark_stripe_bucket(struct btree_trans *trans, if (flags & BTREE_TRIGGER_gc) { percpu_down_read(&c->mark_lock); struct bucket *g = gc_bucket(ca, bucket.offset); if (bch2_fs_inconsistent_on(!g, c, "reference to invalid bucket on device %u\n %s", ptr->dev, (bch2_bkey_val_to_text(&buf, c, s.s_c), buf.buf))) { ret = -EIO; goto err_unlock; } bucket_lock(g); struct bch_alloc_v4 old = bucket_m_to_alloc(*g), new = old; ret = __mark_stripe_bucket(trans, ca, s, ptr_idx, deleting, bucket, &new, flags); Loading @@ -297,10 +305,12 @@ static int mark_stripe_bucket(struct btree_trans *trans, bch2_dev_usage_update(c, ca, &old, &new, 0, true); } bucket_unlock(g); err_unlock: percpu_up_read(&c->mark_lock); } err: bch2_dev_put(ca); printbuf_exit(&buf); return ret; } Loading Loading @@ -714,10 +724,12 @@ static void ec_block_endio(struct bio *bio) bch2_blk_status_to_str(bio->bi_status))) clear_bit(ec_bio->idx, ec_bio->buf->valid); if (dev_ptr_stale(ca, ptr)) { int stale = dev_ptr_stale(ca, ptr); if (stale) { bch_err_ratelimited(ca->fs, "error %s stripe: stale pointer after io", bio_data_dir(bio) == READ ? "reading from" : "writing to"); "error %s stripe: stale/invalid pointer (%i) after io", bio_data_dir(bio) == READ ? "reading from" : "writing to", stale); clear_bit(ec_bio->idx, ec_bio->buf->valid); } Loading @@ -743,10 +755,12 @@ static void ec_block_io(struct bch_fs *c, struct ec_stripe_buf *buf, return; } if (dev_ptr_stale(ca, ptr)) { int stale = dev_ptr_stale(ca, ptr); if (stale) { bch_err_ratelimited(c, "error %s stripe: stale pointer", rw == READ ? "reading from" : "writing to"); "error %s stripe: stale pointer (%i)", rw == READ ? "reading from" : "writing to", stale); clear_bit(idx, buf->valid); return; } Loading