]> git.sesse.net Git - bcachefs-tools-debian/blobdiff - libbcachefs/movinggc.c
Update bcachefs sources to 4837f82ee1 bcachefs: Use cached iterators for alloc btree
[bcachefs-tools-debian] / libbcachefs / movinggc.c
index abdeef20fde9fe0a34e78eee0c545e836989b008..0a87cd7405dd4b454663ee704cc169c2581e76ce 100644 (file)
@@ -78,7 +78,17 @@ static bool __copygc_pred(struct bch_dev *ca,
                ssize_t i = eytzinger0_find_le(h->data, h->used,
                                               sizeof(h->data[0]),
                                               bucket_offset_cmp, &search);
+#if 0
+               /* eytzinger search verify code: */
+               ssize_t j = -1, k;
 
+               for (k = 0; k < h->used; k++)
+                       if (h->data[k].offset <= ptr->offset &&
+                           (j < 0 || h->data[k].offset > h->data[j].offset))
+                               j = k;
+
+               BUG_ON(i != j);
+#endif
                return (i >= 0 &&
                        ptr->offset < h->data[i].offset + ca->mi.bucket_size &&
                        ptr->gen == h->data[i].gen);
@@ -203,23 +213,48 @@ static void bch2_copygc(struct bch_fs *c, struct bch_dev *ca)
 
        if (sectors_not_moved && !ret)
                bch_warn_ratelimited(c,
-                       "copygc finished but %llu/%llu sectors, %llu/%llu buckets not moved",
+                       "copygc finished but %llu/%llu sectors, %llu/%llu buckets not moved (move stats: moved %llu sectors, raced %llu keys, %llu sectors)",
                         sectors_not_moved, sectors_to_move,
-                        buckets_not_moved, buckets_to_move);
+                        buckets_not_moved, buckets_to_move,
+                        atomic64_read(&move_stats.sectors_moved),
+                        atomic64_read(&move_stats.keys_raced),
+                        atomic64_read(&move_stats.sectors_raced));
 
        trace_copygc(ca,
                     atomic64_read(&move_stats.sectors_moved), sectors_not_moved,
                     buckets_to_move, buckets_not_moved);
 }
 
+/*
+ * Copygc runs when the amount of fragmented data is above some arbitrary
+ * threshold:
+ *
+ * The threshold at the limit - when the device is full - is the amount of space
+ * we reserved in bch2_recalc_capacity; we can't have more than that amount of
+ * disk space stranded due to fragmentation and store everything we have
+ * promised to store.
+ *
+ * But we don't want to be running copygc unnecessarily when the device still
+ * has plenty of free space - rather, we want copygc to smoothly run every so
+ * often and continually reduce the amount of fragmented space as the device
+ * fills up. So, we increase the threshold by half the current free space.
+ */
+unsigned long bch2_copygc_wait_amount(struct bch_dev *ca)
+{
+       struct bch_fs *c = ca->fs;
+       struct bch_dev_usage usage = bch2_dev_usage_read(c, ca);
+       u64 fragmented_allowed = ca->copygc_threshold +
+               ((__dev_buckets_available(ca, usage) * ca->mi.bucket_size) >> 1);
+
+       return max_t(s64, 0, fragmented_allowed - usage.sectors_fragmented);
+}
+
 static int bch2_copygc_thread(void *arg)
 {
        struct bch_dev *ca = arg;
        struct bch_fs *c = ca->fs;
        struct io_clock *clock = &c->io_clock[WRITE];
-       struct bch_dev_usage usage;
-       unsigned long last;
-       u64 available, fragmented, reserve, next;
+       unsigned long last, wait;
 
        set_freezable();
 
@@ -228,28 +263,10 @@ static int bch2_copygc_thread(void *arg)
                        break;
 
                last = atomic_long_read(&clock->now);
+               wait = bch2_copygc_wait_amount(ca);
 
-               reserve = ca->copygc_threshold;
-
-               usage = bch2_dev_usage_read(c, ca);
-
-               available = __dev_buckets_available(ca, usage) *
-                       ca->mi.bucket_size;
-               if (available > reserve) {
-                       next = last + available - reserve;
-                       bch2_kthread_io_clock_wait(clock, next,
-                                       MAX_SCHEDULE_TIMEOUT);
-                       continue;
-               }
-
-               /*
-                * don't start copygc until there's more than half the copygc
-                * reserve of fragmented space:
-                */
-               fragmented = usage.sectors_fragmented;
-               if (fragmented < reserve) {
-                       next = last + reserve - fragmented;
-                       bch2_kthread_io_clock_wait(clock, next,
+               if (wait > clock->max_slop) {
+                       bch2_kthread_io_clock_wait(clock, last + wait,
                                        MAX_SCHEDULE_TIMEOUT);
                        continue;
                }