]> git.dujemihanovic.xyz Git - linux.git/commitdiff
bcachefs: bch2_dev_remove_stripes()
authorKent Overstreet <kent.overstreet@linux.dev>
Sun, 1 Sep 2024 22:35:52 +0000 (18:35 -0400)
committerKent Overstreet <kent.overstreet@linux.dev>
Sat, 21 Sep 2024 15:39:49 +0000 (11:39 -0400)
We can now correctly force-remove a device that has stripes on it; this
uses the new BCH_SB_MEMBER_INVALID sentinal value.

Signed-off-by: Kent Overstreet <kent.overstreet@linux.dev>
fs/bcachefs/alloc_background.c
fs/bcachefs/ec.c
fs/bcachefs/ec.h
fs/bcachefs/errcode.h

index d4f0b62e31384cb8077554f76d1066d39754e6dc..87ce65e4630417e0145409a4225c5db8d791dcb1 100644 (file)
@@ -2310,7 +2310,8 @@ int bch2_dev_remove_alloc(struct bch_fs *c, struct bch_dev *ca)
         * We clear the LRU and need_discard btrees first so that we don't race
         * with bch2_do_invalidates() and bch2_do_discards()
         */
-       ret =   bch2_btree_delete_range(c, BTREE_ID_lru, start, end,
+       ret =   bch2_dev_remove_stripes(c, ca->dev_idx) ?:
+               bch2_btree_delete_range(c, BTREE_ID_lru, start, end,
                                        BTREE_TRIGGER_norun, NULL) ?:
                bch2_btree_delete_range(c, BTREE_ID_need_discard, start, end,
                                        BTREE_TRIGGER_norun, NULL) ?:
@@ -2318,10 +2319,10 @@ int bch2_dev_remove_alloc(struct bch_fs *c, struct bch_dev *ca)
                                        BTREE_TRIGGER_norun, NULL) ?:
                bch2_btree_delete_range(c, BTREE_ID_backpointers, start, end,
                                        BTREE_TRIGGER_norun, NULL) ?:
-               bch2_btree_delete_range(c, BTREE_ID_alloc, start, end,
-                                       BTREE_TRIGGER_norun, NULL) ?:
                bch2_btree_delete_range(c, BTREE_ID_bucket_gens, start, end,
                                        BTREE_TRIGGER_norun, NULL) ?:
+               bch2_btree_delete_range(c, BTREE_ID_alloc, start, end,
+                                       BTREE_TRIGGER_norun, NULL) ?:
                bch2_dev_usage_remove(c, ca->dev_idx);
        bch_err_msg(ca, ret, "removing dev alloc info");
        return ret;
index 8af623b15ecf470529d4dcff63bf61e733987741..f58c3e78ea45b1befedf972f7493bd867782c922 100644 (file)
@@ -2169,6 +2169,73 @@ err:
        return ERR_PTR(ret);
 }
 
+/* device removal */
+
+static int bch2_invalidate_stripe_to_dev(struct btree_trans *trans, struct bkey_s_c k_a)
+{
+       struct bch_alloc_v4 a_convert;
+       const struct bch_alloc_v4 *a = bch2_alloc_to_v4(k_a, &a_convert);
+
+       if (!a->stripe)
+               return 0;
+
+       if (a->stripe_sectors) {
+               bch_err(trans->c, "trying to invalidate device in stripe when bucket has stripe data");
+               return -BCH_ERR_invalidate_stripe_to_dev;
+       }
+
+       struct btree_iter iter;
+       struct bkey_i_stripe *s =
+               bch2_bkey_get_mut_typed(trans, &iter, BTREE_ID_stripes, POS(0, a->stripe),
+                                       BTREE_ITER_slots, stripe);
+       int ret = PTR_ERR_OR_ZERO(s);
+       if (ret)
+               return ret;
+
+       struct disk_accounting_pos acc = {
+               .type = BCH_DISK_ACCOUNTING_replicas,
+       };
+
+       s64 sectors = 0;
+       for (unsigned i = 0; i < s->v.nr_blocks; i++)
+               sectors -= stripe_blockcount_get(&s->v, i);
+
+       bch2_bkey_to_replicas(&acc.replicas, bkey_i_to_s_c(&s->k_i));
+       acc.replicas.data_type = BCH_DATA_user;
+       ret = bch2_disk_accounting_mod(trans, &acc, &sectors, 1, false);
+       if (ret)
+               goto err;
+
+       struct bkey_ptrs ptrs = bch2_bkey_ptrs(bkey_i_to_s(&s->k_i));
+       bkey_for_each_ptr(ptrs, ptr)
+               if (ptr->dev == k_a.k->p.inode)
+                       ptr->dev = BCH_SB_MEMBER_INVALID;
+
+       sectors = -sectors;
+
+       bch2_bkey_to_replicas(&acc.replicas, bkey_i_to_s_c(&s->k_i));
+       acc.replicas.data_type = BCH_DATA_user;
+       ret = bch2_disk_accounting_mod(trans, &acc, &sectors, 1, false);
+       if (ret)
+               goto err;
+err:
+       bch2_trans_iter_exit(trans, &iter);
+       return ret;
+}
+
+int bch2_dev_remove_stripes(struct bch_fs *c, unsigned dev_idx)
+{
+       return bch2_trans_run(c,
+               for_each_btree_key_upto_commit(trans, iter,
+                                 BTREE_ID_alloc, POS(dev_idx, 0), POS(dev_idx, U64_MAX),
+                                 BTREE_ITER_intent, k,
+                                 NULL, NULL, 0, ({
+                       bch2_invalidate_stripe_to_dev(trans, k);
+       })));
+}
+
+/* startup/shutdown */
+
 static void __bch2_ec_stop(struct bch_fs *c, struct bch_dev *ca)
 {
        struct ec_stripe_head *h;
index 179a8674dac4359e27a83b4299d7215090d38266..c432040238cdb356346d25c4808542f10c6bdd94 100644 (file)
@@ -251,6 +251,8 @@ static inline void ec_stripe_new_put(struct bch_fs *c, struct ec_stripe_new *s,
                }
 }
 
+int bch2_dev_remove_stripes(struct bch_fs *, unsigned);
+
 void bch2_ec_stop_dev(struct bch_fs *, struct bch_dev *);
 void bch2_fs_ec_stop(struct bch_fs *);
 void bch2_fs_ec_flush(struct bch_fs *);
index 5241910c1cb029c637a81aa86a1714a0c71a0f91..60b7875adada357d029b8b33e207e553ea77303c 100644 (file)
        x(EIO,                          key_type_error)                         \
        x(EIO,                          no_device_to_read_from)                 \
        x(EIO,                          missing_indirect_extent)                \
+       x(EIO,                          invalidate_stripe_to_dev)               \
        x(BCH_ERR_btree_node_read_err,  btree_node_read_err_fixable)            \
        x(BCH_ERR_btree_node_read_err,  btree_node_read_err_want_retry)         \
        x(BCH_ERR_btree_node_read_err,  btree_node_read_err_must_retry)         \