bcachefs: Ensure copygc does not spin
authorKent Overstreet <kent.overstreet@linux.dev>
Mon, 30 Oct 2023 17:15:36 +0000 (13:15 -0400)
committerKent Overstreet <kent.overstreet@linux.dev>
Sat, 4 Nov 2023 18:17:11 +0000 (14:17 -0400)
If copygc does no work - finds no fragmented buckets - wait for a bit of
IO to happen.

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

index c342ec3..bcfae91 100644 (file)
@@ -2085,6 +2085,17 @@ void bch2_recalc_capacity(struct bch_fs *c)
        closure_wake_up(&c->freelist_wait);
 }
 
+u64 bch2_min_rw_member_capacity(struct bch_fs *c)
+{
+       struct bch_dev *ca;
+       unsigned i;
+       u64 ret = U64_MAX;
+
+       for_each_rw_member(ca, c, i)
+               ret = min(ret, ca->mi.nbuckets * ca->mi.bucket_size);
+       return ret;
+}
+
 static bool bch2_dev_has_open_write_point(struct bch_fs *c, struct bch_dev *ca)
 {
        struct open_bucket *ob;
index e1ce38e..73faf99 100644 (file)
@@ -249,6 +249,7 @@ int bch2_dev_freespace_init(struct bch_fs *, struct bch_dev *, u64, u64);
 int bch2_fs_freespace_init(struct bch_fs *);
 
 void bch2_recalc_capacity(struct bch_fs *);
+u64 bch2_min_rw_member_capacity(struct bch_fs *);
 
 void bch2_dev_allocator_remove(struct bch_fs *, struct bch_dev *);
 void bch2_dev_allocator_add(struct bch_fs *, struct bch_dev *);
index f73b9b7..e0efa52 100644 (file)
@@ -188,7 +188,8 @@ static int bch2_copygc_get_buckets(struct moving_context *ctxt,
 
 noinline
 static int bch2_copygc(struct moving_context *ctxt,
-                      struct buckets_in_flight *buckets_in_flight)
+                      struct buckets_in_flight *buckets_in_flight,
+                      bool *did_work)
 {
        struct btree_trans *trans = ctxt->trans;
        struct bch_fs *c = trans->c;
@@ -224,6 +225,8 @@ static int bch2_copygc(struct moving_context *ctxt,
                                             f->bucket.k.gen, data_opts);
                if (ret)
                        goto err;
+
+               *did_work = true;
        }
 err:
        darray_exit(&buckets);
@@ -322,6 +325,8 @@ static int bch2_copygc_thread(void *arg)
                              false);
 
        while (!ret && !kthread_should_stop()) {
+               bool did_work = false;
+
                bch2_trans_unlock(ctxt.trans);
                cond_resched();
 
@@ -352,10 +357,21 @@ static int bch2_copygc_thread(void *arg)
                c->copygc_wait = 0;
 
                c->copygc_running = true;
-               ret = bch2_copygc(&ctxt, &buckets);
+               ret = bch2_copygc(&ctxt, &buckets, &did_work);
                c->copygc_running = false;
 
                wake_up(&c->copygc_running_wq);
+
+               if (!wait && !did_work) {
+                       u64 min_member_capacity = bch2_min_rw_member_capacity(c);
+
+                       if (min_member_capacity == U64_MAX)
+                               min_member_capacity = 128 * 2048;
+
+                       bch2_trans_unlock_long(ctxt.trans);
+                       bch2_kthread_io_clock_wait(clock, last + (min_member_capacity >> 6),
+                                       MAX_SCHEDULE_TIMEOUT);
+               }
        }
 
        move_buckets_wait(&ctxt, &buckets, true);
index 6ee4d2e..82014cc 100644 (file)
@@ -1,6 +1,7 @@
 // SPDX-License-Identifier: GPL-2.0
 
 #include "bcachefs.h"
+#include "alloc_background.h"
 #include "alloc_foreground.h"
 #include "btree_iter.h"
 #include "btree_update.h"
@@ -282,15 +283,12 @@ static int do_rebalance_scan(struct moving_context *ctxt, u64 inum, u64 cookie)
 static void rebalance_wait(struct bch_fs *c)
 {
        struct bch_fs_rebalance *r = &c->rebalance;
-       struct bch_dev *ca;
        struct io_clock *clock = &c->io_clock[WRITE];
        u64 now = atomic64_read(&clock->now);
-       u64 min_member_capacity = 128 * 2048;
-       unsigned i;
+       u64 min_member_capacity = bch2_min_rw_member_capacity(c);
 
-       for_each_rw_member(ca, c, i)
-               min_member_capacity = min(min_member_capacity,
-                                         ca->mi.nbuckets * ca->mi.bucket_size);
+       if (min_member_capacity == U64_MAX)
+               min_member_capacity = 128 * 2048;
 
        r->wait_iotime_end              = now + (min_member_capacity >> 6);