summaryrefslogtreecommitdiffstats
path: root/fs/bcachefs/ec.c
diff options
context:
space:
mode:
authorKent Overstreet <kent.overstreet@linux.dev>2023-02-18 21:31:07 -0500
committerKent Overstreet <kent.overstreet@linux.dev>2023-10-22 17:09:54 -0400
commitba7c37d330816bcc10c55c8eaab268afca2447e8 (patch)
tree9fd19430a430018f70665194b5f420bdb14e31ef /fs/bcachefs/ec.c
parentebe8bd75a073c303e695589c11f298fcc3a1fb1c (diff)
downloadlinux-stable-ba7c37d330816bcc10c55c8eaab268afca2447e8.tar.gz
linux-stable-ba7c37d330816bcc10c55c8eaab268afca2447e8.tar.bz2
linux-stable-ba7c37d330816bcc10c55c8eaab268afca2447e8.zip
bcachefs: Stripe deletion now checks what it's deleting
Signed-off-by: Kent Overstreet <kent.overstreet@linux.dev>
Diffstat (limited to 'fs/bcachefs/ec.c')
-rw-r--r--fs/bcachefs/ec.c72
1 files changed, 56 insertions, 16 deletions
diff --git a/fs/bcachefs/ec.c b/fs/bcachefs/ec.c
index 44e7b6584713..17284349ae2e 100644
--- a/fs/bcachefs/ec.c
+++ b/fs/bcachefs/ec.c
@@ -584,12 +584,12 @@ static int ec_stripe_mem_alloc(struct btree_trans *trans,
bch2_trans_relock(trans);
}
-static ssize_t stripe_idx_to_delete(struct bch_fs *c)
+static u64 stripe_idx_to_delete(struct bch_fs *c)
{
ec_stripes_heap *h = &c->ec_stripes_heap;
return h->used && h->data[0].blocks_nonempty == 0
- ? h->data[0].idx : -1;
+ ? h->data[0].idx : 0;
}
static inline int ec_stripes_heap_cmp(ec_stripes_heap *h,
@@ -674,41 +674,81 @@ void bch2_stripes_heap_update(struct bch_fs *c,
heap_verify_backpointer(c, idx);
- if (stripe_idx_to_delete(c) >= 0)
+ if (stripe_idx_to_delete(c))
bch2_do_stripe_deletes(c);
}
/* stripe deletion */
-static int ec_stripe_delete(struct bch_fs *c, size_t idx)
+static int ec_stripe_delete(struct btree_trans *trans, u64 idx)
{
- return bch2_btree_delete_range(c, BTREE_ID_stripes,
- POS(0, idx),
- POS(0, idx),
- 0, NULL);
+ struct bch_fs *c = trans->c;
+ struct btree_iter iter;
+ struct bkey_s_c k;
+ struct bkey_s_c_stripe s;
+ int ret;
+
+ bch2_trans_iter_init(trans, &iter, BTREE_ID_stripes, POS(0, idx),
+ BTREE_ITER_INTENT);
+ k = bch2_btree_iter_peek_slot(&iter);
+ ret = bkey_err(k);
+ if (ret)
+ goto err;
+
+ if (k.k->type != KEY_TYPE_stripe) {
+ bch2_fs_inconsistent(c, "attempting to delete nonexistent stripe %llu", idx);
+ ret = -EINVAL;
+ goto err;
+ }
+
+ s = bkey_s_c_to_stripe(k);
+ for (unsigned i = 0; i < s.v->nr_blocks; i++)
+ if (stripe_blockcount_get(s.v, i)) {
+ struct printbuf buf = PRINTBUF;
+
+ bch2_bkey_val_to_text(&buf, c, k);
+ bch2_fs_inconsistent(c, "attempting to delete nonempty stripe %s", buf.buf);
+ printbuf_exit(&buf);
+ ret = -EINVAL;
+ goto err;
+ }
+
+ ret = bch2_btree_delete_at(trans, &iter, 0);
+err:
+ bch2_trans_iter_exit(trans, &iter);
+ return ret;
}
static void ec_stripe_delete_work(struct work_struct *work)
{
struct bch_fs *c =
container_of(work, struct bch_fs, ec_stripe_delete_work);
- ssize_t idx;
+ struct btree_trans trans;
+ int ret;
+ u64 idx;
+
+ bch2_trans_init(&trans, c, 0, 0);
while (1) {
mutex_lock(&c->ec_stripes_heap_lock);
idx = stripe_idx_to_delete(c);
- if (idx < 0) {
- mutex_unlock(&c->ec_stripes_heap_lock);
- break;
- }
-
- bch2_stripes_heap_del(c, genradix_ptr(&c->stripes, idx), idx);
+ if (idx)
+ bch2_stripes_heap_del(c, genradix_ptr(&c->stripes, idx), idx);
mutex_unlock(&c->ec_stripes_heap_lock);
- if (ec_stripe_delete(c, idx))
+ if (!idx)
+ break;
+
+ ret = commit_do(&trans, NULL, NULL, BTREE_INSERT_NOFAIL,
+ ec_stripe_delete(&trans, idx));
+ if (ret) {
+ bch_err(c, "%s: err %s", __func__, bch2_err_str(ret));
break;
+ }
}
+ bch2_trans_exit(&trans);
+
bch2_write_ref_put(c, BCH_WRITE_REF_stripe_delete);
}