bcachefs: Ignore cached data when calculating fragmentation
authorKent Overstreet <kent.overstreet@gmail.com>
Tue, 11 Jan 2022 00:46:39 +0000 (19:46 -0500)
committerKent Overstreet <kent.overstreet@linux.dev>
Sun, 22 Oct 2023 21:09:22 +0000 (17:09 -0400)
Previously, bucket fragmentation was considered to be bucket size -
total amount of live data, both dirty and cached.

This meant that if a bucket was full but only a small amount of data in
it was dirty - the rest cached, we'd get stuck: copygc wouldn't move the
dirty data out of the bucket and the allocator wouldn't be able to
invalidate and drop the cached data.

This changes fragmentation to exclude cached data, so that copygc will
evacuate these buckets and copygc/the allocator will always be able to
make forward progress.

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

index 0cf71125c55f00dcad6808bc99350f6d44f219d1..1353e72bbfb0884bf852ead447fa1f283ee5bc2d 100644 (file)
@@ -544,7 +544,7 @@ static bool bch2_can_invalidate_bucket(struct bch_dev *ca, size_t b,
 static unsigned bucket_sort_key(struct bucket *g, struct bucket_mark m,
                                u64 now, u64 last_seq_ondisk)
 {
-       unsigned used = bucket_sectors_used(m);
+       unsigned used = m.cached_sectors;
 
        if (used) {
                /*
index fb833d82222bac8ba5404ff6b1265be362953d0f..acdc95d8d4c76b867253a37f55970dcb59b282f5 100644 (file)
@@ -291,8 +291,8 @@ static inline int is_unavailable_bucket(struct bucket_mark m)
 static inline int bucket_sectors_fragmented(struct bch_dev *ca,
                                            struct bucket_mark m)
 {
-       return bucket_sectors_used(m)
-               ? max(0, (int) ca->mi.bucket_size - (int) bucket_sectors_used(m))
+       return m.dirty_sectors
+               ? max(0, (int) ca->mi.bucket_size - (int) m.dirty_sectors)
                : 0;
 }
 
index 4b5376684d2c0c95b47160b0ebd9ed263b7f69a2..483c8b24293f913642a18e23b5f157eb4f459872 100644 (file)
@@ -149,11 +149,6 @@ static inline u8 ptr_stale(struct bch_dev *ca,
 
 /* bucket gc marks */
 
-static inline unsigned bucket_sectors_used(struct bucket_mark mark)
-{
-       return mark.dirty_sectors + mark.cached_sectors;
-}
-
 static inline bool is_available_bucket(struct bucket_mark mark)
 {
        return !mark.dirty_sectors && !mark.stripe;
index 4791e5099d93931b8a92079d6026ae6a9df12b2c..64cb10c3f3db09020db503d9ded46e92b0015c48 100644 (file)
@@ -69,10 +69,14 @@ static enum data_cmd copygc_pred(struct bch_fs *c, void *arg,
                        .dev    = p.ptr.dev,
                        .offset = p.ptr.offset,
                };
+               ssize_t i;
 
-               ssize_t i = eytzinger0_find_le(h->data, h->used,
-                                              sizeof(h->data[0]),
-                                              bucket_offset_cmp, &search);
+               if (p.ptr.cached)
+                       continue;
+
+               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;
@@ -185,8 +189,7 @@ static int bch2_copygc(struct bch_fs *c)
 
                        if (m.owned_by_allocator ||
                            m.data_type != BCH_DATA_user ||
-                           !bucket_sectors_used(m) ||
-                           bucket_sectors_used(m) >= ca->mi.bucket_size)
+                           m.dirty_sectors >= ca->mi.bucket_size)
                                continue;
 
                        WARN_ON(m.stripe && !g->stripe_redundancy);
@@ -195,9 +198,9 @@ static int bch2_copygc(struct bch_fs *c)
                                .dev            = dev_idx,
                                .gen            = m.gen,
                                .replicas       = 1 + g->stripe_redundancy,
-                               .fragmentation  = bucket_sectors_used(m) * (1U << 15)
+                               .fragmentation  = m.dirty_sectors * (1U << 15)
                                        / ca->mi.bucket_size,
-                               .sectors        = bucket_sectors_used(m),
+                               .sectors        = m.dirty_sectors,
                                .offset         = bucket_to_sector(ca, b),
                        };
                        heap_add_or_replace(h, e, -fragmentation_cmp, NULL);
@@ -263,8 +266,8 @@ static int bch2_copygc(struct bch_fs *c)
                        m = READ_ONCE(buckets->b[b].mark);
 
                        if (i->gen == m.gen &&
-                           bucket_sectors_used(m)) {
-                               sectors_not_moved += bucket_sectors_used(m);
+                           m.dirty_sectors) {
+                               sectors_not_moved += m.dirty_sectors;
                                buckets_not_moved++;
                        }
                }