summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKent Overstreet <kent.overstreet@linux.dev>2025-07-07 20:07:37 -0400
committerKent Overstreet <kent.overstreet@linux.dev>2025-07-24 12:05:04 -0400
commitce3d3f9c7bb6ba216f28b259de26b5f536ea6ee5 (patch)
treeb7126a91614fb1f24ec8fdebd961876a54197051
parent8fc559990887645a0d372ed186f58646bd788a8b (diff)
bcachefs: __bch2_btree_node_alloc() now respects target
cmd_image in bcachefs-tools now requires that btree node allocation strictly respects target when specified; allocating from the cache wasn't obeying this. Signed-off-by: Kent Overstreet <kent.overstreet@linux.dev>
-rw-r--r--fs/bcachefs/btree_update_interior.c19
-rw-r--r--fs/bcachefs/extents.c12
-rw-r--r--fs/bcachefs/extents.h1
3 files changed, 25 insertions, 7 deletions
diff --git a/fs/bcachefs/btree_update_interior.c b/fs/bcachefs/btree_update_interior.c
index 8084ca2dde3c..ebdb4d2f1be9 100644
--- a/fs/bcachefs/btree_update_interior.c
+++ b/fs/bcachefs/btree_update_interior.c
@@ -305,13 +305,18 @@ static struct btree *__bch2_btree_node_alloc(struct btree_trans *trans,
mutex_lock(&c->btree_reserve_cache_lock);
if (c->btree_reserve_cache_nr > nr_reserve) {
- struct btree_alloc *a =
- &c->btree_reserve_cache[--c->btree_reserve_cache_nr];
-
- bkey_copy(&b->key, &a->k);
- b->ob = a->ob;
- mutex_unlock(&c->btree_reserve_cache_lock);
- goto out;
+ for (struct btree_alloc *a = c->btree_reserve_cache;
+ a < c->btree_reserve_cache + c->btree_reserve_cache_nr;
+ a++) {
+ if (target && !bch2_bkey_in_target(c, bkey_i_to_s_c(&a->k), target))
+ continue;
+
+ bkey_copy(&b->key, &a->k);
+ b->ob = a->ob;
+ *a = c->btree_reserve_cache[--c->btree_reserve_cache_nr];
+ mutex_unlock(&c->btree_reserve_cache_lock);
+ goto out;
+ }
}
mutex_unlock(&c->btree_reserve_cache_lock);
retry:
diff --git a/fs/bcachefs/extents.c b/fs/bcachefs/extents.c
index 83cbd77dcb9c..ec0951fbddea 100644
--- a/fs/bcachefs/extents.c
+++ b/fs/bcachefs/extents.c
@@ -1023,6 +1023,18 @@ bool bch2_bkey_has_target(struct bch_fs *c, struct bkey_s_c k, unsigned target)
return false;
}
+bool bch2_bkey_in_target(struct bch_fs *c, struct bkey_s_c k, unsigned target)
+{
+ struct bkey_ptrs_c ptrs = bch2_bkey_ptrs_c(k);
+
+ guard(rcu)();
+ bkey_for_each_ptr(ptrs, ptr)
+ if (!bch2_dev_in_target(c, ptr->dev, target))
+ return false;
+
+ return true;
+}
+
bool bch2_bkey_matches_ptr(struct bch_fs *c, struct bkey_s_c k,
struct bch_extent_ptr m, u64 offset)
{
diff --git a/fs/bcachefs/extents.h b/fs/bcachefs/extents.h
index b8590e51b76e..f212f91c278d 100644
--- a/fs/bcachefs/extents.h
+++ b/fs/bcachefs/extents.h
@@ -615,6 +615,7 @@ static inline struct bch_extent_ptr *bch2_bkey_has_device(struct bkey_s k, unsig
}
bool bch2_bkey_has_target(struct bch_fs *, struct bkey_s_c, unsigned);
+bool bch2_bkey_in_target(struct bch_fs *, struct bkey_s_c, unsigned);
void bch2_bkey_extent_entry_drop(struct bkey_i *, union bch_extent_entry *);