]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
bcachefs: bch2_dev_remove_stripes() respects degraded flags
authorKent Overstreet <kent.overstreet@linux.dev>
Tue, 6 May 2025 04:51:39 +0000 (00:51 -0400)
committerKent Overstreet <kent.overstreet@linux.dev>
Thu, 22 May 2025 00:14:48 +0000 (20:14 -0400)
Signed-off-by: Kent Overstreet <kent.overstreet@linux.dev>
fs/bcachefs/alloc_background.c
fs/bcachefs/ec.c
fs/bcachefs/ec.h
fs/bcachefs/super.c

index 002e3853f8cf6a8d7d040783b35ce5cd822ca5ba..81e2ae4bb400bbd240ea267da36b44fe6335f478 100644 (file)
@@ -2442,8 +2442,7 @@ 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_dev_remove_stripes(c, ca->dev_idx) ?:
-               bch2_btree_delete_range(c, BTREE_ID_lru, start, end,
+       ret =   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) ?:
index dcd4e2266d344c9711d973ddef5ab1dfbdf58ec1..bf5f4f6283a436921fa4e1ce7854087d1629935f 100644 (file)
@@ -2106,23 +2106,17 @@ err:
 
 /* device removal */
 
-static int bch2_invalidate_stripe_to_dev(struct btree_trans *trans, struct bkey_s_c k_a)
+int bch2_invalidate_stripe_to_dev(struct btree_trans *trans,
+                                 struct btree_iter *iter,
+                                 struct bkey_s_c k,
+                                 unsigned dev_idx,
+                                 unsigned flags)
 {
-       struct bch_alloc_v4 a_convert;
-       const struct bch_alloc_v4 *a = bch2_alloc_to_v4(k_a, &a_convert);
-
-       if (!a->stripe)
+       if (k.k->type != KEY_TYPE_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);
+               bch2_bkey_make_mut_typed(trans, iter, &k, 0, stripe);
        int ret = PTR_ERR_OR_ZERO(s);
        if (ret)
                return ret;
@@ -2139,35 +2133,76 @@ static int bch2_invalidate_stripe_to_dev(struct btree_trans *trans, struct bkey_
        acc.replicas.data_type = BCH_DATA_user;
        ret = bch2_disk_accounting_mod(trans, &acc, &sectors, 1, false);
        if (ret)
-               goto err;
+               return ret;
 
        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)
+
+       /* XXX: how much redundancy do we still have? check degraded flags */
+
+       unsigned nr_good = 0;
+
+       rcu_read_lock();
+       bkey_for_each_ptr(ptrs, ptr) {
+               if (ptr->dev == dev_idx)
                        ptr->dev = BCH_SB_MEMBER_INVALID;
 
+               struct bch_dev *ca = bch2_dev_rcu(trans->c, ptr->dev);
+               nr_good += ca && ca->mi.state != BCH_MEMBER_STATE_failed;
+       }
+       rcu_read_unlock();
+
+       if (nr_good < s->v.nr_blocks && !(flags & BCH_FORCE_IF_DATA_DEGRADED))
+               return -BCH_ERR_remove_would_lose_data;
+
+       unsigned nr_data = s->v.nr_blocks - s->v.nr_redundant;
+
+       if (nr_good < nr_data && !(flags & BCH_FORCE_IF_DATA_LOST))
+               return -BCH_ERR_remove_would_lose_data;
+
        sectors = -sectors;
 
        memset(&acc, 0, sizeof(acc));
        acc.type = BCH_DISK_ACCOUNTING_replicas;
        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);
+       return bch2_disk_accounting_mod(trans, &acc, &sectors, 1, false);
+}
+
+static int bch2_invalidate_stripe_to_dev_from_alloc(struct btree_trans *trans, struct bkey_s_c k_a,
+                                                   unsigned flags)
+{
+       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_s_c_stripe s =
+               bch2_bkey_get_iter_typed(trans, &iter, BTREE_ID_stripes, POS(0, a->stripe),
+                                       BTREE_ITER_slots, stripe);
+       int ret = bkey_err(s);
        if (ret)
-               goto err;
-err:
+               return ret;
+
+       ret = bch2_invalidate_stripe_to_dev(trans, &iter, s.s_c, k_a.k->p.inode, flags);
        bch2_trans_iter_exit(trans, &iter);
        return ret;
 }
 
-int bch2_dev_remove_stripes(struct bch_fs *c, unsigned dev_idx)
+int bch2_dev_remove_stripes(struct bch_fs *c, unsigned dev_idx, unsigned flags)
 {
        return bch2_trans_run(c,
                for_each_btree_key_max_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);
+                       bch2_invalidate_stripe_to_dev_from_alloc(trans, k, flags);
        })));
 }
 
index 83d37bcb548a29e20e24a560da37e5e714ffd6a8..548048adf0d5737e82f9ab9ec40a54a7997374e3 100644 (file)
@@ -288,7 +288,9 @@ 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);
+int bch2_invalidate_stripe_to_dev(struct btree_trans *, struct btree_iter *,
+                                 struct bkey_s_c, unsigned, unsigned);
+int bch2_dev_remove_stripes(struct bch_fs *, unsigned, unsigned);
 
 void bch2_ec_stop_dev(struct bch_fs *, struct bch_dev *);
 void bch2_fs_ec_stop(struct bch_fs *);
index bd0565b7a9ba0cb5ee737c6f9a7cd2c89e2ab3dd..faa012107a97b70e113ce795eaa4f26c4c78d1cc 100644 (file)
@@ -1744,7 +1744,8 @@ int bch2_dev_remove(struct bch_fs *c, struct bch_dev *ca, int flags)
 
        __bch2_dev_read_only(c, ca);
 
-       ret = bch2_dev_data_drop(c, ca->dev_idx, flags);
+       ret = bch2_dev_data_drop(c, ca->dev_idx, flags) ?:
+               bch2_dev_remove_stripes(c, ca->dev_idx, flags);
        bch_err_msg(ca, ret, "bch2_dev_data_drop()");
        if (ret)
                goto err;