]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
bcachefs: Improve bucket_bitmap code
authorKent Overstreet <kent.overstreet@linux.dev>
Sat, 17 May 2025 19:05:26 +0000 (15:05 -0400)
committerKent Overstreet <kent.overstreet@linux.dev>
Thu, 22 May 2025 00:15:04 +0000 (20:15 -0400)
Add some more helpers, and mismatches is now a superset of the empty
bitmap - simplifies most checks.

Signed-off-by: Kent Overstreet <kent.overstreet@linux.dev>
fs/bcachefs/backpointers.c
fs/bcachefs/backpointers.h
fs/bcachefs/bcachefs.h
fs/bcachefs/buckets.c
fs/bcachefs/movinggc.c
fs/bcachefs/super.c

index d9ddfc4b5dcc763b68e85e96f4c6587bcae20269..6b98ce1ed6c929b78d6642605f68a4c02ccb0c7a 100644 (file)
@@ -15,6 +15,8 @@
 
 #include <linux/mm.h>
 
+static int bch2_bucket_bitmap_set(struct bch_dev *, struct bucket_bitmap *, u64);
+
 static inline struct bbpos bp_to_bbpos(struct bch_backpointer bp)
 {
        return (struct bbpos) {
@@ -685,31 +687,28 @@ static int check_extent_to_backpointers(struct btree_trans *trans,
                        continue;
                }
 
-               u64 b = PTR_BUCKET_NR(ca, &p.ptr);
-               bool set[2];
-
-               for (unsigned i = 0; i < ARRAY_SIZE(ca->bucket_backpointer_mismatches); i++) {
-                       unsigned long *bitmap =
-                               READ_ONCE(ca->bucket_backpointer_mismatches[i].buckets);
-                       set[i] = bitmap && test_bit(b, bitmap);
+               if (p.ptr.cached && dev_ptr_stale_rcu(ca, &p.ptr)) {
+                       rcu_read_unlock();
+                       continue;
                }
 
-               bool check = set[0];
-               bool empty = set[1];
+               u64 b = PTR_BUCKET_NR(ca, &p.ptr);
+               if (!bch2_bucket_bitmap_test(&ca->bucket_backpointer_mismatch, b)) {
+                       rcu_read_unlock();
+                       continue;
+               }
 
-               bool stale = p.ptr.cached && (!ca || dev_ptr_stale_rcu(ca, &p.ptr));
+               bool empty = bch2_bucket_bitmap_test(&ca->bucket_backpointer_empty, b);
                rcu_read_unlock();
 
-               if ((check || empty) && !stale) {
-                       struct bkey_i_backpointer bp;
-                       bch2_extent_ptr_to_bp(c, btree, level, k, p, entry, &bp);
+               struct bkey_i_backpointer bp;
+               bch2_extent_ptr_to_bp(c, btree, level, k, p, entry, &bp);
 
-                       int ret = check
-                               ? check_bp_exists(trans, s, &bp, k)
-                               : bch2_bucket_backpointer_mod(trans, k, &bp, true);
-                       if (ret)
-                               return ret;
-               }
+               int ret = !empty
+                       ? check_bp_exists(trans, s, &bp, k)
+                       : bch2_bucket_backpointer_mod(trans, k, &bp, true);
+               if (ret)
+                       return ret;
        }
 
        return 0;
@@ -952,21 +951,12 @@ static int check_bucket_backpointer_mismatch(struct btree_trans *trans, struct b
                              sectors[ALLOC_stripe] +
                              sectors[ALLOC_cached]) == 0;
 
-               struct bucket_bitmap *bitmap = &ca->bucket_backpointer_mismatches[empty];
-
-               mutex_lock(&bitmap->lock);
-               if (!bitmap->buckets) {
-                       bitmap->buckets = kvcalloc(BITS_TO_LONGS(ca->mi.nbuckets),
-                                                  sizeof(unsigned long), GFP_KERNEL);
-                       if (!bitmap->buckets) {
-                               mutex_unlock(&bitmap->lock);
-                               ret = -BCH_ERR_ENOMEM_backpointer_mismatches_bitmap;
-                               goto err;
-                       }
-               }
-
-               bitmap->nr += !__test_and_set_bit(alloc_k.k->p.offset, bitmap->buckets);
-               mutex_unlock(&bitmap->lock);
+               ret = bch2_bucket_bitmap_set(ca, &ca->bucket_backpointer_mismatch,
+                                            alloc_k.k->p.offset) ?:
+                       (empty
+                        ? bch2_bucket_bitmap_set(ca, &ca->bucket_backpointer_empty,
+                                                 alloc_k.k->p.offset)
+                        : 0);
        }
 err:
        bch2_dev_put(ca);
@@ -992,15 +982,10 @@ static bool backpointer_node_has_missing(struct bch_fs *c, struct bkey_s_c k)
                        struct bpos bucket = bp_pos_to_bucket(ca, pos);
                        u64 next = ca->mi.nbuckets;
 
-                       for (unsigned i = 0; i < ARRAY_SIZE(ca->bucket_backpointer_mismatches); i++) {
-                               unsigned long *bitmap =
-                                       READ_ONCE(ca->bucket_backpointer_mismatches[i].buckets);
-                               if (bitmap)
-                                       next = min_t(u64, next,
-                                                    find_next_bit(bitmap,
-                                                                  ca->mi.nbuckets,
-                                                                  bucket.offset));
-                       }
+                       unsigned long *bitmap = READ_ONCE(ca->bucket_backpointer_mismatch.buckets);
+                       if (bitmap)
+                               next = min_t(u64, next,
+                                            find_next_bit(bitmap, ca->mi.nbuckets, bucket.offset));
 
                        bucket.offset = next;
                        if (bucket.offset == ca->mi.nbuckets)
@@ -1124,18 +1109,17 @@ int bch2_check_extents_to_backpointers(struct bch_fs *c)
        if (ret)
                goto err;
 
-       u64 nr_buckets = 0, nr_mismatches = 0, nr_empty = 0;
+       u64 nr_buckets = 0, nr_mismatches = 0;
        for_each_member_device(c, ca) {
                nr_buckets      += ca->mi.nbuckets;
-               nr_mismatches   += ca->bucket_backpointer_mismatches[0].nr;
-               nr_empty        += ca->bucket_backpointer_mismatches[1].nr;
+               nr_mismatches   += ca->bucket_backpointer_mismatch.nr;
        }
 
-       if (!nr_mismatches && !nr_empty)
+       if (!nr_mismatches)
                goto err;
 
        bch_info(c, "scanning for missing backpointers in %llu/%llu buckets",
-                nr_mismatches + nr_empty, nr_buckets);
+                nr_mismatches, nr_buckets);
 
        while (1) {
                ret = bch2_pin_backpointer_nodes_with_missing(trans, s.bp_start, &s.bp_end);
@@ -1171,9 +1155,10 @@ err:
        bch2_bkey_buf_exit(&s.last_flushed, c);
        bch2_btree_cache_unpin(c);
 
-       for_each_member_device(c, ca)
-               for (unsigned i = 0; i < ARRAY_SIZE(ca->bucket_backpointer_mismatches); i++)
-                       bch2_bucket_bitmap_free(&ca->bucket_backpointer_mismatches[i]);
+       for_each_member_device(c, ca) {
+               bch2_bucket_bitmap_free(&ca->bucket_backpointer_mismatch);
+               bch2_bucket_bitmap_free(&ca->bucket_backpointer_empty);
+       }
 
        bch_err_fn(c, ret);
        return ret;
@@ -1297,6 +1282,42 @@ int bch2_check_backpointers_to_extents(struct bch_fs *c)
        return ret;
 }
 
+static int bch2_bucket_bitmap_set(struct bch_dev *ca, struct bucket_bitmap *b, u64 bit)
+{
+       scoped_guard(mutex, &b->lock) {
+               if (!b->buckets) {
+                       b->buckets = kvcalloc(BITS_TO_LONGS(ca->mi.nbuckets),
+                                             sizeof(unsigned long), GFP_KERNEL);
+                       if (!b->buckets)
+                               return -BCH_ERR_ENOMEM_backpointer_mismatches_bitmap;
+               }
+
+               b->nr += !__test_and_set_bit(bit, b->buckets);
+       }
+
+       return 0;
+}
+
+int bch2_bucket_bitmap_resize(struct bucket_bitmap *b, u64 old_size, u64 new_size)
+{
+       scoped_guard(mutex, &b->lock) {
+               if (!b->buckets)
+                       return 0;
+
+               unsigned long *n = kvcalloc(BITS_TO_LONGS(new_size),
+                                           sizeof(unsigned long), GFP_KERNEL);
+               if (!n)
+                       return -BCH_ERR_ENOMEM_backpointer_mismatches_bitmap;
+
+               memcpy(n, b->buckets,
+                      BITS_TO_LONGS(min(old_size, new_size)) * sizeof(unsigned long));
+               kvfree(b->buckets);
+               b->buckets = n;
+       }
+
+       return 0;
+}
+
 void bch2_bucket_bitmap_free(struct bucket_bitmap *b)
 {
        mutex_lock(&b->lock);
index f57098c3214361f9da4b7667de72c70a318d5048..fe7149a2fbf54227aaeb7c84d3bafd5af8c18f74 100644 (file)
@@ -188,6 +188,13 @@ int bch2_check_btree_backpointers(struct bch_fs *);
 int bch2_check_extents_to_backpointers(struct bch_fs *);
 int bch2_check_backpointers_to_extents(struct bch_fs *);
 
+static inline bool bch2_bucket_bitmap_test(struct bucket_bitmap *b, u64 i)
+{
+       unsigned long *bitmap = READ_ONCE(b->buckets);
+       return bitmap && test_bit(i, bitmap);
+}
+
+int bch2_bucket_bitmap_resize(struct bucket_bitmap *, u64, u64);
 void bch2_bucket_bitmap_free(struct bucket_bitmap *);
 
 #endif /* _BCACHEFS_BACKPOINTERS_BACKGROUND_H */
index e1680b635fe13158dc5dbd1ca43fc3d857983a16..b58fad743fc455266ed483299f57925d38ae3b43 100644 (file)
@@ -626,7 +626,8 @@ struct bch_dev {
        u8                      *oldest_gen;
        unsigned long           *buckets_nouse;
 
-       struct bucket_bitmap    bucket_backpointer_mismatches[2];
+       struct bucket_bitmap    bucket_backpointer_mismatch;
+       struct bucket_bitmap    bucket_backpointer_empty;
 
        struct bch_dev_usage_full __percpu
                                *usage;
index ca6e58d6fbc821373be08e64282e7f1c174bd230..8bb6384190c53318db0ee811d832ee9d31a8af60 100644 (file)
@@ -1324,27 +1324,10 @@ int bch2_dev_buckets_resize(struct bch_fs *c, struct bch_dev *ca, u64 nbuckets)
                       sizeof(bucket_gens->b[0]) * copy);
        }
 
-       for (unsigned i = 0; i < ARRAY_SIZE(ca->bucket_backpointer_mismatches); i++) {
-               struct bucket_bitmap *bitmap = &ca->bucket_backpointer_mismatches[i];
-
-               mutex_lock(&bitmap->lock);
-               if (bitmap->buckets) {
-                       unsigned long *n = kvcalloc(BITS_TO_LONGS(nbuckets),
-                                                   sizeof(unsigned long), GFP_KERNEL);
-                       if (!n) {
-                               mutex_unlock(&bitmap->lock);
-                               ret = -BCH_ERR_ENOMEM_backpointer_mismatches_bitmap;
-                               goto err;
-                       }
-
-                       memcpy(n, bitmap->buckets,
-                              BITS_TO_LONGS(ca->mi.nbuckets) * sizeof(unsigned long));
-                       kvfree(bitmap->buckets);
-                       bitmap->buckets = n;
-
-               }
-               mutex_unlock(&bitmap->lock);
-       }
+       ret =   bch2_bucket_bitmap_resize(&ca->bucket_backpointer_mismatch,
+                                         ca->mi.nbuckets, nbuckets) ?:
+               bch2_bucket_bitmap_resize(&ca->bucket_backpointer_empty,
+                                         ca->mi.nbuckets, nbuckets);
 
        rcu_assign_pointer(ca->bucket_gens, bucket_gens);
        bucket_gens     = old_bucket_gens;
index 4bfdb1befb9a4529e70938e4a712729bb9eb0052..0a751a65386f523e6d559a3214eb9c999c073d92 100644 (file)
@@ -8,6 +8,7 @@
 #include "bcachefs.h"
 #include "alloc_background.h"
 #include "alloc_foreground.h"
+#include "backpointers.h"
 #include "btree_iter.h"
 #include "btree_update.h"
 #include "btree_write_buffer.h"
@@ -76,7 +77,7 @@ static int bch2_bucket_is_movable(struct btree_trans *trans,
 
        if (ca->mi.state != BCH_MEMBER_STATE_rw ||
            !bch2_dev_is_online(ca))
-               goto out_put;
+               goto out;
 
        struct bch_alloc_v4 _a;
        const struct bch_alloc_v4 *a = bch2_alloc_to_v4(k, &_a);
@@ -85,9 +86,8 @@ static int bch2_bucket_is_movable(struct btree_trans *trans,
        u64 lru_idx     = alloc_lru_idx_fragmentation(*a, ca);
 
        ret = lru_idx && lru_idx <= time;
-out_put:
-       bch2_dev_put(ca);
 out:
+       bch2_dev_put(ca);
        bch2_trans_iter_exit(trans, &iter);
        return ret;
 }
index 170b0f26c018862cb260c8592241a0e85a22f1a6..24658bf450ab9df01fa517013d3b74faf4b81337 100644 (file)
@@ -1366,8 +1366,8 @@ static void bch2_dev_free(struct bch_dev *ca)
        if (ca->kobj.state_in_sysfs)
                kobject_del(&ca->kobj);
 
-       for (unsigned i = 0; i < ARRAY_SIZE(ca->bucket_backpointer_mismatches); i++)
-               bch2_bucket_bitmap_free(&ca->bucket_backpointer_mismatches[i]);
+       bch2_bucket_bitmap_free(&ca->bucket_backpointer_mismatch);
+       bch2_bucket_bitmap_free(&ca->bucket_backpointer_empty);
 
        bch2_free_super(&ca->disk_sb);
        bch2_dev_allocator_background_exit(ca);
@@ -1499,8 +1499,8 @@ static struct bch_dev *__bch2_dev_alloc(struct bch_fs *c,
        atomic_long_set(&ca->ref, 1);
 #endif
 
-       for (unsigned i = 0; i < ARRAY_SIZE(ca->bucket_backpointer_mismatches); i++)
-               mutex_init(&ca->bucket_backpointer_mismatches[i].lock);
+       mutex_init(&ca->bucket_backpointer_mismatch.lock);
+       mutex_init(&ca->bucket_backpointer_empty.lock);
 
        bch2_dev_allocator_background_init(ca);