bcachefs: Fix btree iter flags in data move (2)

Data move -> move_get_io_opts -> bch2_get_update_rebalance_opts

requires a not_extents iterator; this fixes the path where we're walking
the extents btree and chase a reflink pointer into the reflink btree.

bch2_lookup_indirect_extent() requires working with an extents iterator
(due to peek_slot() semantics), so we implement
bch2_lookup_indirect_extent_for_move().

This is simplified because there's no need to report
indirect_extent_missing_errors here, that can be deferred until fsck or
when a user reads that data.

Reported-by: Maël Kerbiriou <mael.kerbiriou@free.fr>
Signed-off-by: Kent Overstreet <kent.overstreet@linux.dev>
This commit is contained in:
Kent Overstreet
2025-03-17 15:07:06 -04:00
parent 19ff84b20d
commit 9314e2fb26

View File

@@ -528,6 +528,37 @@ int bch2_move_ratelimit(struct moving_context *ctxt)
return 0;
}
/*
* Move requires non extents iterators, and there's also no need for it to
* signal indirect_extent_missing_error:
*/
static struct bkey_s_c bch2_lookup_indirect_extent_for_move(struct btree_trans *trans,
struct btree_iter *iter,
struct bkey_s_c_reflink_p p)
{
if (unlikely(REFLINK_P_ERROR(p.v)))
return bkey_s_c_null;
struct bpos reflink_pos = POS(0, REFLINK_P_IDX(p.v));
bch2_trans_iter_init(trans, iter,
BTREE_ID_reflink, reflink_pos,
BTREE_ITER_not_extents);
struct bkey_s_c k = bch2_btree_iter_peek(iter);
if (!k.k || bkey_err(k)) {
bch2_trans_iter_exit(trans, iter);
return k;
}
if (bkey_lt(reflink_pos, bkey_start_pos(k.k))) {
bch2_trans_iter_exit(trans, iter);
return bkey_s_c_null;
}
return k;
}
static int bch2_move_data_btree(struct moving_context *ctxt,
struct bpos start,
struct bpos end,
@@ -592,17 +623,16 @@ static int bch2_move_data_btree(struct moving_context *ctxt,
k.k->type == KEY_TYPE_reflink_p &&
REFLINK_P_MAY_UPDATE_OPTIONS(bkey_s_c_to_reflink_p(k).v)) {
struct bkey_s_c_reflink_p p = bkey_s_c_to_reflink_p(k);
s64 offset_into_extent = 0;
bch2_trans_iter_exit(trans, &reflink_iter);
k = bch2_lookup_indirect_extent(trans, &reflink_iter, &offset_into_extent, p, true, 0);
k = bch2_lookup_indirect_extent_for_move(trans, &reflink_iter, p);
ret = bkey_err(k);
if (bch2_err_matches(ret, BCH_ERR_transaction_restart))
continue;
if (ret)
break;
if (bkey_deleted(k.k))
if (!k.k)
goto next_nondata;
/*
@@ -611,7 +641,6 @@ static int bch2_move_data_btree(struct moving_context *ctxt,
* pointer - need to fixup iter->k
*/
extent_iter = &reflink_iter;
offset_into_extent = 0;
}
if (!bkey_extent_is_direct_data(k.k))