summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--fs/bcachefs/errcode.h5
-rw-r--r--fs/bcachefs/movinggc.c44
2 files changed, 36 insertions, 13 deletions
diff --git a/fs/bcachefs/errcode.h b/fs/bcachefs/errcode.h
index c4344a1d6976..cbf1eedddad7 100644
--- a/fs/bcachefs/errcode.h
+++ b/fs/bcachefs/errcode.h
@@ -188,6 +188,11 @@
x(BCH_ERR_recovery_will_run, recovery_pass_will_run) \
x(0, data_update_done) \
x(0, bkey_was_deleted) \
+ x(0, bucket_not_moveable) \
+ x(BCH_ERR_bucket_not_moveable, bucket_not_moveable_dev_not_rw) \
+ x(BCH_ERR_bucket_not_moveable, bucket_not_moveable_bucket_open) \
+ x(BCH_ERR_bucket_not_moveable, bucket_not_moveable_bp_mismatch) \
+ x(BCH_ERR_bucket_not_moveable, bucket_not_moveable_lru_race) \
x(BCH_ERR_data_update_done, data_update_done_would_block) \
x(BCH_ERR_data_update_done, data_update_done_unwritten) \
x(BCH_ERR_data_update_done, data_update_done_no_writes_needed) \
diff --git a/fs/bcachefs/movinggc.c b/fs/bcachefs/movinggc.c
index f36d60b8fb07..0f7e35684bc8 100644
--- a/fs/bcachefs/movinggc.c
+++ b/fs/bcachefs/movinggc.c
@@ -62,25 +62,38 @@ static int bch2_bucket_is_movable(struct btree_trans *trans,
{
struct bch_fs *c = trans->c;
- if (bch2_bucket_is_open(c, b->k.bucket.inode, b->k.bucket.offset))
+ /*
+ * Valid bucket?
+ *
+ * XXX: we should kill the LRU entry here if it's not
+ */
+ CLASS(bch2_dev_bucket_tryget, ca)(c, b->k.bucket);
+ if (!ca)
return 0;
- CLASS(btree_iter, iter)(trans, BTREE_ID_alloc, b->k.bucket, BTREE_ITER_cached);
- struct bkey_s_c k = bch2_btree_iter_peek_slot(&iter);
- int ret = bkey_err(k);
- if (ret)
- return ret;
-
- CLASS(bch2_dev_bucket_tryget, ca)(c, k.k->p);
- if (!ca)
+ if (ca->mi.state != BCH_MEMBER_STATE_rw ||
+ !bch2_dev_is_online(ca)) {
+ bch_err_throw(c, bucket_not_moveable_dev_not_rw);
return 0;
+ }
- if (bch2_bucket_bitmap_test(&ca->bucket_backpointer_mismatch, b->k.bucket.offset))
+ /* Bucket still being written? */
+ if (bch2_bucket_is_open(c, b->k.bucket.inode, b->k.bucket.offset)) {
+ bch_err_throw(c, bucket_not_moveable_bucket_open);
return 0;
+ }
- if (ca->mi.state != BCH_MEMBER_STATE_rw ||
- !bch2_dev_is_online(ca))
+ /* We won't be able to evacuate it if there's missing backpointers */
+ if (bch2_bucket_bitmap_test(&ca->bucket_backpointer_mismatch, b->k.bucket.offset)) {
+ bch_err_throw(c, bucket_not_moveable_bp_mismatch);
return 0;
+ }
+
+ CLASS(btree_iter, iter)(trans, BTREE_ID_alloc, b->k.bucket, BTREE_ITER_cached);
+ struct bkey_s_c k = bch2_btree_iter_peek_slot(&iter);
+ int ret = bkey_err(k);
+ if (ret)
+ return ret;
struct bch_alloc_v4 _a;
const struct bch_alloc_v4 *a = bch2_alloc_to_v4(k, &_a);
@@ -88,7 +101,12 @@ static int bch2_bucket_is_movable(struct btree_trans *trans,
b->sectors = bch2_bucket_sectors_dirty(*a);
u64 lru_idx = alloc_lru_idx_fragmentation(*a, ca);
- return lru_idx && lru_idx <= time;
+ if (!lru_idx || lru_idx > time) {
+ bch_err_throw(c, bucket_not_moveable_lru_race);
+ return 0;
+ }
+
+ return true;
}
static void move_bucket_free(struct buckets_in_flight *list,