bcachefs: Fix oldest_gen handling
authorKent Overstreet <kent.overstreet@gmail.com>
Tue, 12 Feb 2019 00:27:33 +0000 (19:27 -0500)
committerKent Overstreet <kent.overstreet@linux.dev>
Sun, 22 Oct 2023 21:08:15 +0000 (17:08 -0400)
Signed-off-by: Kent Overstreet <kent.overstreet@linux.dev>
fs/bcachefs/alloc_background.c
fs/bcachefs/bcachefs.h
fs/bcachefs/bcachefs_format.h
fs/bcachefs/btree_gc.c
fs/bcachefs/buckets.c
fs/bcachefs/buckets.h
fs/bcachefs/buckets_types.h

index 34c1de63e43b837bac9c3b47f15caaa49ec43e4a..9d2e21d99e6e7ae17f2c759f8699b0005f297b51 100644 (file)
@@ -183,6 +183,7 @@ static void __alloc_read_key(struct bucket *g, const struct bch_alloc *a)
        g->_mark.data_type      = get_alloc_field(a, &d, idx++);
        g->_mark.dirty_sectors  = get_alloc_field(a, &d, idx++);
        g->_mark.cached_sectors = get_alloc_field(a, &d, idx++);
+       g->oldest_gen           = get_alloc_field(a, &d, idx++);
 }
 
 static void __alloc_write_key(struct bkey_i_alloc *a, struct bucket *g,
@@ -200,6 +201,7 @@ static void __alloc_write_key(struct bkey_i_alloc *a, struct bucket *g,
        put_alloc_field(a, &d, idx++, m.data_type);
        put_alloc_field(a, &d, idx++, m.dirty_sectors);
        put_alloc_field(a, &d, idx++, m.cached_sectors);
+       put_alloc_field(a, &d, idx++, g->oldest_gen);
 
        set_bkey_val_bytes(&a->k, (void *) d - (void *) &a->v);
 }
index 81597383dc200069bd16b0f66f1a72e5617c7fc5..0b495dd32f6750c8200de66d63b2c460138d107d 100644 (file)
@@ -399,8 +399,6 @@ struct bch_dev {
        struct bucket_array __rcu *buckets[2];
        unsigned long           *buckets_nouse;
        unsigned long           *buckets_written;
-       /* most out of date gen in the btree */
-       u8                      *oldest_gens;
        struct rw_semaphore     bucket_lock;
 
        struct bch_dev_usage __percpu *usage[2];
index a663f9d3fb5150214f95fbae414f2da960d49fcb..c7971e5c7c3639f2d591497f08d019e0fce2def6 100644 (file)
@@ -830,7 +830,8 @@ struct bch_alloc {
        x(write_time, 2)                        \
        x(data_type, 1)                         \
        x(dirty_sectors, 2)                     \
-       x(cached_sectors, 2)
+       x(cached_sectors, 2)                    \
+       x(oldest_gen, 1)
 
 enum {
 #define x(name, bytes) BCH_ALLOC_FIELD_##name,
index 899bdfa4d6d33fe1434c28837a919face4d9eaa8..391389d431c8053cac8007e45566371c36c94dd6 100644 (file)
@@ -167,9 +167,10 @@ static int bch2_gc_mark_key(struct bch_fs *c, struct bkey_s_c k,
        bkey_for_each_ptr(ptrs, ptr) {
                struct bch_dev *ca = bch_dev_bkey_exists(c, ptr->dev);
                size_t b = PTR_BUCKET_NR(ca, ptr);
+               struct bucket *g = __bucket(ca, b, true);
 
-               if (gen_after(ca->oldest_gens[b], ptr->gen))
-                       ca->oldest_gens[b] = ptr->gen;
+               if (gen_after(g->oldest_gen, ptr->gen))
+                       g->oldest_gen = ptr->gen;
 
                *max_stale = max(*max_stale, ptr_stale(ca, ptr));
        }
@@ -486,89 +487,38 @@ static void bch2_gc_free(struct bch_fs *c)
        percpu_up_write(&c->mark_lock);
 }
 
-static void bch2_gc_done_nocheck(struct bch_fs *c)
-{
-       struct bch_dev *ca;
-       unsigned i;
-
-       {
-               struct genradix_iter dst_iter = genradix_iter_init(&c->stripes[0], 0);
-               struct genradix_iter src_iter = genradix_iter_init(&c->stripes[1], 0);
-               struct stripe *dst, *src;
-
-               c->ec_stripes_heap.used = 0;
-
-               while ((dst = genradix_iter_peek(&dst_iter, &c->stripes[0])) &&
-                      (src = genradix_iter_peek(&src_iter, &c->stripes[1]))) {
-                       *dst = *src;
-
-                       if (dst->alive)
-                               bch2_stripes_heap_insert(c, dst, dst_iter.pos);
-
-                       genradix_iter_advance(&dst_iter, &c->stripes[0]);
-                       genradix_iter_advance(&src_iter, &c->stripes[1]);
-               }
-       }
-
-       for_each_member_device(ca, c, i) {
-               struct bucket_array *src = __bucket_array(ca, 1);
-
-               memcpy(__bucket_array(ca, 0), src,
-                      sizeof(struct bucket_array) +
-                      sizeof(struct bucket) * src->nbuckets);
-       };
-
-       for_each_member_device(ca, c, i) {
-               unsigned nr = sizeof(struct bch_dev_usage) / sizeof(u64);
-               struct bch_dev_usage *dst = (void *)
-                       bch2_acc_percpu_u64s((void *) ca->usage[0], nr);
-               struct bch_dev_usage *src = (void *)
-                       bch2_acc_percpu_u64s((void *) ca->usage[1], nr);
-
-               *dst = *src;
-       }
-
-       {
-               unsigned nr = sizeof(struct bch_fs_usage) / sizeof(u64) +
-                       c->replicas.nr;
-               struct bch_fs_usage *dst = (void *)
-                       bch2_acc_percpu_u64s((void *) c->usage[0], nr);
-               struct bch_fs_usage *src = (void *)
-                       bch2_acc_percpu_u64s((void *) c->usage[1], nr);
-               unsigned offset = offsetof(typeof(*dst), s.gc_start);
-
-               memcpy((void *) dst + offset,
-                      (void *) src + offset,
-                      nr * sizeof(u64) - offset);
-       }
-}
-
 static void bch2_gc_done(struct bch_fs *c, bool initial)
 {
        struct bch_dev *ca;
+       bool verify = !initial ||
+               (c->sb.compat & (1ULL << BCH_COMPAT_FEAT_ALLOC_INFO));
        unsigned i;
 
 #define copy_field(_f, _msg, ...)                                      \
        if (dst->_f != src->_f) {                                       \
-               bch_err(c, _msg ": got %llu, should be %llu, fixing"    \
-                       , ##__VA_ARGS__, dst->_f, src->_f);             \
+               if (verify)                                             \
+                       bch_err(c, _msg ": got %llu, should be %llu, fixing"\
+                               , ##__VA_ARGS__, dst->_f, src->_f);     \
                dst->_f = src->_f;                                      \
        }
 #define copy_stripe_field(_f, _msg, ...)                               \
        if (dst->_f != src->_f) {                                       \
-               bch_err_ratelimited(c, "stripe %zu has wrong "_msg      \
-                       ": got %u, should be %u, fixing",               \
-                       dst_iter.pos, ##__VA_ARGS__,                    \
-                       dst->_f, src->_f);                              \
+               if (verify)                                             \
+                       bch_err_ratelimited(c, "stripe %zu has wrong "_msg\
+                               ": got %u, should be %u, fixing",       \
+                               dst_iter.pos, ##__VA_ARGS__,            \
+                               dst->_f, src->_f);                      \
                dst->_f = src->_f;                                      \
                dst->dirty = true;                                      \
        }
 #define copy_bucket_field(_f)                                          \
        if (dst->b[b].mark._f != src->b[b].mark._f) {                   \
-               bch_err_ratelimited(c, "dev %u bucket %zu has wrong " #_f\
-                       ": got %u, should be %u, fixing",               \
-                       i, b, dst->b[b].mark._f, src->b[b].mark._f);    \
+               if (verify)                                             \
+                       bch_err_ratelimited(c, "dev %u bucket %zu has wrong " #_f\
+                               ": got %u, should be %u, fixing", i, b, \
+                               dst->b[b].mark._f, src->b[b].mark._f);  \
                dst->b[b]._mark._f = src->b[b].mark._f;                 \
+               dst->b[b]._mark.dirty = true;                           \
        }
 #define copy_dev_field(_f, _msg, ...)                                  \
        copy_field(_f, "dev %u has wrong " _msg, i, ##__VA_ARGS__)
@@ -577,12 +527,6 @@ static void bch2_gc_done(struct bch_fs *c, bool initial)
 
        percpu_down_write(&c->mark_lock);
 
-       if (initial &&
-           !(c->sb.compat & (1ULL << BCH_COMPAT_FEAT_ALLOC_INFO))) {
-               bch2_gc_done_nocheck(c);
-               goto out;
-       }
-
        {
                struct genradix_iter dst_iter = genradix_iter_init(&c->stripes[0], 0);
                struct genradix_iter src_iter = genradix_iter_init(&c->stripes[1], 0);
@@ -633,6 +577,11 @@ static void bch2_gc_done(struct bch_fs *c, bool initial)
                        copy_bucket_field(stripe);
                        copy_bucket_field(dirty_sectors);
                        copy_bucket_field(cached_sectors);
+
+                       if (dst->b[b].oldest_gen != src->b[b].oldest_gen) {
+                               dst->b[b].oldest_gen = src->b[b].oldest_gen;
+                               dst->b[b]._mark.dirty = true;
+                       }
                }
        };
 
@@ -645,16 +594,16 @@ static void bch2_gc_done(struct bch_fs *c, bool initial)
                unsigned b;
 
                for (b = 0; b < BCH_DATA_NR; b++)
-                       copy_dev_field(buckets[b],
-                                      "buckets[%s]", bch2_data_types[b]);
-               copy_dev_field(buckets_alloc, "buckets_alloc");
-               copy_dev_field(buckets_ec, "buckets_ec");
+                       copy_dev_field(buckets[b],      "buckets[%s]",
+                                      bch2_data_types[b]);
+               copy_dev_field(buckets_alloc,           "buckets_alloc");
+               copy_dev_field(buckets_ec,              "buckets_ec");
+               copy_dev_field(buckets_unavailable,     "buckets_unavailable");
 
                for (b = 0; b < BCH_DATA_NR; b++)
-                       copy_dev_field(sectors[b],
-                                      "sectors[%s]", bch2_data_types[b]);
-               copy_dev_field(sectors_fragmented,
-                              "sectors_fragmented");
+                       copy_dev_field(sectors[b],      "sectors[%s]",
+                                      bch2_data_types[b]);
+               copy_dev_field(sectors_fragmented,      "sectors_fragmented");
        }
 
        {
@@ -682,7 +631,7 @@ static void bch2_gc_done(struct bch_fs *c, bool initial)
                        copy_fs_field(data[i], "data[%i]", i);
                }
        }
-out:
+
        percpu_up_write(&c->mark_lock);
 
 #undef copy_fs_field
@@ -745,7 +694,9 @@ static int bch2_gc_start(struct bch_fs *c)
                dst->nbuckets           = src->nbuckets;
 
                for (b = 0; b < src->nbuckets; b++)
-                       dst->b[b]._mark.gen = src->b[b].mark.gen;
+                       dst->b[b]._mark.gen =
+                               dst->b[b].oldest_gen =
+                               src->b[b].mark.gen;
        };
 
        percpu_up_write(&c->mark_lock);
index d2e047ee29cf6874411b88d0c986a67a311cbc5e..5a3ecbcd5ad4df4cf9c644ca9981a2953d9aabbd 100644 (file)
@@ -1148,7 +1148,6 @@ int bch2_dev_buckets_resize(struct bch_fs *c, struct bch_dev *ca, u64 nbuckets)
        struct bucket_array *buckets = NULL, *old_buckets = NULL;
        unsigned long *buckets_nouse = NULL;
        unsigned long *buckets_written = NULL;
-       u8 *oldest_gens = NULL;
        alloc_fifo      free[RESERVE_NR];
        alloc_fifo      free_inc;
        alloc_heap      alloc_heap;
@@ -1174,8 +1173,6 @@ int bch2_dev_buckets_resize(struct bch_fs *c, struct bch_dev *ca, u64 nbuckets)
        if (!(buckets           = kvpmalloc(sizeof(struct bucket_array) +
                                            nbuckets * sizeof(struct bucket),
                                            GFP_KERNEL|__GFP_ZERO)) ||
-           !(oldest_gens       = kvpmalloc(nbuckets * sizeof(u8),
-                                           GFP_KERNEL|__GFP_ZERO)) ||
            !(buckets_nouse     = kvpmalloc(BITS_TO_LONGS(nbuckets) *
                                            sizeof(unsigned long),
                                            GFP_KERNEL|__GFP_ZERO)) ||
@@ -1210,9 +1207,6 @@ int bch2_dev_buckets_resize(struct bch_fs *c, struct bch_dev *ca, u64 nbuckets)
                memcpy(buckets->b,
                       old_buckets->b,
                       n * sizeof(struct bucket));
-               memcpy(oldest_gens,
-                      ca->oldest_gens,
-                      n * sizeof(u8));
                memcpy(buckets_nouse,
                       ca->buckets_nouse,
                       BITS_TO_LONGS(n) * sizeof(unsigned long));
@@ -1224,7 +1218,6 @@ int bch2_dev_buckets_resize(struct bch_fs *c, struct bch_dev *ca, u64 nbuckets)
        rcu_assign_pointer(ca->buckets[0], buckets);
        buckets = old_buckets;
 
-       swap(ca->oldest_gens, oldest_gens);
        swap(ca->buckets_nouse, buckets_nouse);
        swap(ca->buckets_written, buckets_written);
 
@@ -1268,8 +1261,6 @@ err:
                BITS_TO_LONGS(nbuckets) * sizeof(unsigned long));
        kvpfree(buckets_written,
                BITS_TO_LONGS(nbuckets) * sizeof(unsigned long));
-       kvpfree(oldest_gens,
-               nbuckets * sizeof(u8));
        if (buckets)
                call_rcu(&old_buckets->rcu, buckets_free_rcu);
 
@@ -1289,7 +1280,6 @@ void bch2_dev_buckets_free(struct bch_dev *ca)
                BITS_TO_LONGS(ca->mi.nbuckets) * sizeof(unsigned long));
        kvpfree(ca->buckets_nouse,
                BITS_TO_LONGS(ca->mi.nbuckets) * sizeof(unsigned long));
-       kvpfree(ca->oldest_gens, ca->mi.nbuckets * sizeof(u8));
        kvpfree(rcu_dereference_protected(ca->buckets[0], 1),
                sizeof(struct bucket_array) +
                ca->mi.nbuckets * sizeof(struct bucket));
index e5b9d5cb1215decc2512f94aa6d32920cf096cb4..885280899dc64da558983013c9b1e8003daeaa25 100644 (file)
@@ -87,7 +87,9 @@ static inline u16 bucket_last_io(struct bch_fs *c, struct bucket *g, int rw)
 
 static inline u8 bucket_gc_gen(struct bch_dev *ca, size_t b)
 {
-       return bucket(ca, b)->mark.gen - ca->oldest_gens[b];
+       struct bucket *g = bucket(ca, b);
+
+       return g->mark.gen - g->oldest_gen;
 }
 
 static inline size_t PTR_BUCKET_NR(const struct bch_dev *ca,
index 65b4bb39f88e029937a043a71d5a684416901279..6eaee889f1e1acd9750b29e275cc8fe72ea7d370 100644 (file)
@@ -39,6 +39,7 @@ struct bucket {
        };
 
        u16                             io_time[2];
+       u8                              oldest_gen;
        unsigned                        gen_valid:1;
 };