bcachefs: Fix copygc threshold
authorKent Overstreet <kent.overstreet@gmail.com>
Tue, 13 Apr 2021 13:49:23 +0000 (09:49 -0400)
committerKent Overstreet <kent.overstreet@linux.dev>
Sun, 22 Oct 2023 21:08:54 +0000 (17:08 -0400)
Awhile back the meaning of is_available_bucket() and thus also
bch_dev_usage->buckets_unavailable changed to include buckets that are
owned by the allocator - this was so that the stat could be persisted
like other allocation information, and wouldn't have to be regenerated
by walking each bucket at mount time.

This broke copygc, which needs to consider buckets that are reclaimable
and haven't yet been grabbed by the allocator thread and moved onta
freelist. This patch fixes that by adding dev_buckets_reclaimable() for
copygc and the allocator thread, and cleans up some of the callers a bit.

Signed-off-by: Kent Overstreet <kent.overstreet@gmail.com>
Signed-off-by: Kent Overstreet <kent.overstreet@linux.dev>
fs/bcachefs/alloc_background.c
fs/bcachefs/alloc_foreground.c
fs/bcachefs/bcachefs.h
fs/bcachefs/buckets.h
fs/bcachefs/movinggc.c
fs/bcachefs/sysfs.c

index f2117084f2fed91d8954f1f67ec6f9272d9be23f..f603fd347d582a98c09e6965be8975232dfb2c17 100644 (file)
@@ -46,7 +46,7 @@ static void pd_controllers_update(struct work_struct *work)
                struct bch_dev_usage stats = bch2_dev_usage_read(ca);
 
                free += bucket_to_sector(ca,
-                               __dev_buckets_free(ca, stats)) << 9;
+                               __dev_buckets_available(ca, stats)) << 9;
                /*
                 * Bytes of internal fragmentation, which can be
                 * reclaimed by copy GC
@@ -499,7 +499,6 @@ static int wait_buckets_available(struct bch_fs *c, struct bch_dev *ca)
 {
        unsigned long gc_count = c->gc_count;
        s64 available;
-       unsigned i;
        int ret = 0;
 
        ca->allocator_state = ALLOCATOR_BLOCKED;
@@ -515,19 +514,12 @@ static int wait_buckets_available(struct bch_fs *c, struct bch_dev *ca)
                if (gc_count != c->gc_count)
                        ca->inc_gen_really_needs_gc = 0;
 
-               available  = dev_buckets_available(ca);
+               available  = dev_buckets_reclaimable(ca);
                available -= ca->inc_gen_really_needs_gc;
 
-               spin_lock(&c->freelist_lock);
-               for (i = 0; i < RESERVE_NR; i++)
-                       available -= fifo_used(&ca->free[i]);
-               spin_unlock(&c->freelist_lock);
-
                available = max(available, 0LL);
 
-               if (available > fifo_free(&ca->free_inc) ||
-                   (available &&
-                    !fifo_full(&ca->free[RESERVE_MOVINGGC])))
+               if (available)
                        break;
 
                up_read(&c->gc_lock);
@@ -1189,7 +1181,7 @@ stop:
 void bch2_recalc_capacity(struct bch_fs *c)
 {
        struct bch_dev *ca;
-       u64 capacity = 0, reserved_sectors = 0, gc_reserve, copygc_threshold = 0;
+       u64 capacity = 0, reserved_sectors = 0, gc_reserve;
        unsigned bucket_size_max = 0;
        unsigned long ra_pages = 0;
        unsigned i, j;
@@ -1232,8 +1224,6 @@ void bch2_recalc_capacity(struct bch_fs *c)
 
                dev_reserve *= ca->mi.bucket_size;
 
-               copygc_threshold += dev_reserve;
-
                capacity += bucket_to_sector(ca, ca->mi.nbuckets -
                                             ca->mi.first_bucket);
 
@@ -1251,7 +1241,6 @@ void bch2_recalc_capacity(struct bch_fs *c)
 
        reserved_sectors = min(reserved_sectors, capacity);
 
-       c->copygc_threshold = copygc_threshold;
        c->capacity = capacity - reserved_sectors;
 
        c->bucket_size_max = bucket_size_max;
index 97b692bcfe463748bd3ae2a5025f31162fcc601f..4834ac798b9e9fc236f69426d4553d15faa1e119 100644 (file)
@@ -109,7 +109,9 @@ void __bch2_open_bucket_put(struct bch_fs *c, struct open_bucket *ob)
        spin_lock(&c->freelist_lock);
        ob->freelist = c->open_buckets_freelist;
        c->open_buckets_freelist = ob - c->open_buckets;
+
        c->open_buckets_nr_free++;
+       ca->nr_open_buckets--;
        spin_unlock(&c->freelist_lock);
 
        closure_wake_up(&c->open_buckets_wait);
@@ -316,6 +318,7 @@ out:
                c->blocked_allocate = 0;
        }
 
+       ca->nr_open_buckets++;
        spin_unlock(&c->freelist_lock);
 
        bch2_wake_allocator(ca);
@@ -351,7 +354,7 @@ void bch2_dev_stripe_increment(struct bch_dev *ca,
                               struct dev_stripe_state *stripe)
 {
        u64 *v = stripe->next_alloc + ca->dev_idx;
-       u64 free_space = dev_buckets_free(ca);
+       u64 free_space = dev_buckets_available(ca);
        u64 free_space_inv = free_space
                ? div64_u64(1ULL << 48, free_space)
                : 1ULL << 48;
index cec5c3ddce342a1bc9b1250adaac266f91331a15..76b72ed693a8f70b48a7b0071a5c4949912be74d 100644 (file)
@@ -447,6 +447,7 @@ struct bch_dev {
         */
        alloc_fifo              free[RESERVE_NR];
        alloc_fifo              free_inc;
+       unsigned                nr_open_buckets;
 
        open_bucket_idx_t       open_buckets_partial[OPEN_BUCKETS_COUNT];
        open_bucket_idx_t       open_buckets_partial_nr;
@@ -772,7 +773,6 @@ mempool_t           bio_bounce_pages;
        copygc_heap             copygc_heap;
        struct bch_pd_controller copygc_pd;
        struct write_point      copygc_write_point;
-       u64                     copygc_threshold;
 
        /* STRIPES: */
        GENRADIX(struct stripe) stripes[2];
index c965c4d48218e686c2aedafd544f5ef2131a10ca..e53cee27a720423979c180f2c8420ae62a1f9a20 100644 (file)
@@ -175,25 +175,31 @@ static inline u64 __dev_buckets_available(struct bch_dev *ca,
        return total - stats.buckets_unavailable;
 }
 
-/*
- * Number of reclaimable buckets - only for use by the allocator thread:
- */
 static inline u64 dev_buckets_available(struct bch_dev *ca)
 {
        return __dev_buckets_available(ca, bch2_dev_usage_read(ca));
 }
 
-static inline u64 __dev_buckets_free(struct bch_dev *ca,
-                                    struct bch_dev_usage stats)
+static inline u64 __dev_buckets_reclaimable(struct bch_dev *ca,
+                                           struct bch_dev_usage stats)
 {
-       return __dev_buckets_available(ca, stats) +
-               fifo_used(&ca->free[RESERVE_NONE]) +
-               fifo_used(&ca->free_inc);
+       struct bch_fs *c = ca->fs;
+       s64 available = __dev_buckets_available(ca, stats);
+       unsigned i;
+
+       spin_lock(&c->freelist_lock);
+       for (i = 0; i < RESERVE_NR; i++)
+               available -= fifo_used(&ca->free[i]);
+       available -= fifo_used(&ca->free_inc);
+       available -= ca->nr_open_buckets;
+       spin_unlock(&c->freelist_lock);
+
+       return max(available, 0LL);
 }
 
-static inline u64 dev_buckets_free(struct bch_dev *ca)
+static inline u64 dev_buckets_reclaimable(struct bch_dev *ca)
 {
-       return __dev_buckets_free(ca, bch2_dev_usage_read(ca));
+       return __dev_buckets_reclaimable(ca, bch2_dev_usage_read(ca));
 }
 
 /* Filesystem usage: */
index 65a8cd14ee75dd5d4a7c0495af379af550fb53c8..b8da600cdc530e377923b3f93550cd72d5201fad 100644 (file)
@@ -282,13 +282,12 @@ unsigned long bch2_copygc_wait_amount(struct bch_fs *c)
 {
        struct bch_dev *ca;
        unsigned dev_idx;
-       u64 fragmented_allowed = c->copygc_threshold;
-       u64 fragmented = 0;
+       u64 fragmented_allowed = 0, fragmented = 0;
 
        for_each_rw_member(ca, c, dev_idx) {
                struct bch_dev_usage usage = bch2_dev_usage_read(ca);
 
-               fragmented_allowed += ((__dev_buckets_available(ca, usage) *
+               fragmented_allowed += ((__dev_buckets_reclaimable(ca, usage) *
                                        ca->mi.bucket_size) >> 1);
                fragmented += usage.d[BCH_DATA_user].fragmented;
        }
index 49c19873ad6f0529196940a34318bdf0c81d49a1..9f75f72f7b12f46784e8bb7868b64a0ce68c071d 100644 (file)
@@ -805,7 +805,9 @@ static void dev_alloc_debug_to_text(struct printbuf *out, struct bch_dev *ca)
               "free[RESERVE_MOVINGGC]\t%zu/%zu\n"
               "free[RESERVE_NONE]\t%zu/%zu\n"
               "freelist_wait\t\t%s\n"
-              "open buckets\t\t%u/%u (reserved %u)\n"
+              "open buckets allocated\t%u\n"
+              "open buckets this dev\t%u\n"
+              "open buckets total\t%u\n"
               "open_buckets_wait\t%s\n"
               "open_buckets_btree\t%u\n"
               "open_buckets_user\t%u\n"
@@ -816,8 +818,9 @@ static void dev_alloc_debug_to_text(struct printbuf *out, struct bch_dev *ca)
               fifo_used(&ca->free[RESERVE_MOVINGGC]),  ca->free[RESERVE_MOVINGGC].size,
               fifo_used(&ca->free[RESERVE_NONE]),      ca->free[RESERVE_NONE].size,
               c->freelist_wait.list.first              ? "waiting" : "empty",
-              c->open_buckets_nr_free, OPEN_BUCKETS_COUNT,
-              BTREE_NODE_OPEN_BUCKET_RESERVE,
+              OPEN_BUCKETS_COUNT - c->open_buckets_nr_free,
+              ca->nr_open_buckets,
+              OPEN_BUCKETS_COUNT,
               c->open_buckets_wait.list.first          ? "waiting" : "empty",
               nr[BCH_DATA_btree],
               nr[BCH_DATA_user],