bcachefs: Stripe deletion now checks what it's deleting
authorKent Overstreet <kent.overstreet@linux.dev>
Sun, 19 Feb 2023 02:31:07 +0000 (21:31 -0500)
committerKent Overstreet <kent.overstreet@linux.dev>
Sun, 22 Oct 2023 21:09:54 +0000 (17:09 -0400)
Signed-off-by: Kent Overstreet <kent.overstreet@linux.dev>
fs/bcachefs/ec.c

index 44e7b6584713fc1da288d03b5456524a0ebabc8a..17284349ae2e544245869acf7a100e06a42d1b3c 100644 (file)
@@ -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);
 }