diff options
Diffstat (limited to 'fs/bcachefs/ec.c')
-rw-r--r-- | fs/bcachefs/ec.c | 72 |
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); } |