bcachefs: get_existing_stripe() uses new stripe lru

Convert to the new persistent stripe LRU.

Signed-off-by: Kent Overstreet <kent.overstreet@linux.dev>
This commit is contained in:
Kent Overstreet
2025-02-10 20:34:47 -05:00
parent 039790cfb5
commit 6c336144b9
2 changed files with 52 additions and 44 deletions

View File

@@ -1981,39 +1981,40 @@ static int new_stripe_alloc_buckets(struct btree_trans *trans,
return 0;
}
static s64 get_existing_stripe(struct bch_fs *c,
struct ec_stripe_head *head)
static int __get_existing_stripe(struct btree_trans *trans,
struct ec_stripe_head *head,
struct ec_stripe_buf *stripe,
u64 idx)
{
ec_stripes_heap *h = &c->ec_stripes_heap;
struct stripe *m;
size_t heap_idx;
u64 stripe_idx;
s64 ret = -1;
struct bch_fs *c = trans->c;
if (may_create_new_stripe(c))
return -1;
struct btree_iter iter;
struct bkey_s_c k = bch2_bkey_get_iter(trans, &iter,
BTREE_ID_stripes, POS(0, idx), 0);
int ret = bkey_err(k);
if (ret)
goto err;
mutex_lock(&c->ec_stripes_heap_lock);
for (heap_idx = 0; heap_idx < h->nr; heap_idx++) {
/* No blocks worth reusing, stripe will just be deleted: */
if (!h->data[heap_idx].blocks_nonempty)
continue;
/* We expect write buffer races here */
if (k.k->type != KEY_TYPE_stripe)
goto out;
stripe_idx = h->data[heap_idx].idx;
struct bkey_s_c_stripe s = bkey_s_c_to_stripe(k);
if (stripe_lru_pos(s.v) <= 1)
goto out;
m = genradix_ptr(&c->stripes, stripe_idx);
if (m->disk_label == head->disk_label &&
m->algorithm == head->algo &&
m->nr_redundant == head->redundancy &&
m->sectors == head->blocksize &&
m->blocks_nonempty < m->nr_blocks - m->nr_redundant &&
bch2_try_open_stripe(c, head->s, stripe_idx)) {
ret = stripe_idx;
break;
}
if (s.v->disk_label == head->disk_label &&
s.v->algorithm == head->algo &&
s.v->nr_redundant == head->redundancy &&
le16_to_cpu(s.v->sectors) == head->blocksize &&
bch2_try_open_stripe(c, head->s, idx)) {
bkey_reassemble(&stripe->key, k);
ret = 1;
}
mutex_unlock(&c->ec_stripes_heap_lock);
out:
bch2_set_btree_iter_dontneed(&iter);
err:
bch2_trans_iter_exit(trans, &iter);
return ret;
}
@@ -2065,24 +2066,33 @@ static int __bch2_ec_stripe_head_reuse(struct btree_trans *trans, struct ec_stri
struct ec_stripe_new *s)
{
struct bch_fs *c = trans->c;
s64 idx;
int ret;
/*
* If we can't allocate a new stripe, and there's no stripes with empty
* blocks for us to reuse, that means we have to wait on copygc:
*/
idx = get_existing_stripe(c, h);
if (idx < 0)
return -BCH_ERR_stripe_alloc_blocked;
if (may_create_new_stripe(c))
return -1;
ret = get_stripe_key_trans(trans, idx, &s->existing_stripe);
bch2_fs_fatal_err_on(ret && !bch2_err_matches(ret, BCH_ERR_transaction_restart), c,
"reading stripe key: %s", bch2_err_str(ret));
if (ret) {
bch2_stripe_close(c, s);
return ret;
struct btree_iter lru_iter;
struct bkey_s_c lru_k;
int ret = 0;
for_each_btree_key_max_norestart(trans, lru_iter, BTREE_ID_lru,
lru_pos(BCH_LRU_STRIPE_FRAGMENTATION, 2, 0),
lru_pos(BCH_LRU_STRIPE_FRAGMENTATION, 2, LRU_TIME_MAX),
0, lru_k, ret) {
ret = __get_existing_stripe(trans, h, &s->existing_stripe, lru_k.k->p.offset);
if (ret)
break;
}
bch2_trans_iter_exit(trans, &lru_iter);
if (!ret)
ret = -BCH_ERR_stripe_alloc_blocked;
if (ret == 1)
ret = 0;
if (ret)
return ret;
return init_new_stripe_from_existing(c, s);
}

View File

@@ -99,15 +99,13 @@ static inline u64 stripe_lru_pos(const struct bch_stripe *s)
if (!s)
return 0;
unsigned blocks_empty = 0, blocks_nonempty = 0;
unsigned nr_data = s->nr_blocks - s->nr_redundant, blocks_empty = 0;
for (unsigned i = 0; i < s->nr_blocks; i++) {
blocks_empty += !stripe_blockcount_get(s, i);
blocks_nonempty += !!stripe_blockcount_get(s, i);
}
for (unsigned i = 0; i < nr_data; i++)
blocks_empty += !stripe_blockcount_get(s, i);
/* Will be picked up by the stripe_delete worker */
if (!blocks_nonempty)
if (blocks_empty == nr_data)
return STRIPE_LRU_POS_EMPTY;
if (!blocks_empty)