]> git.proxmox.com Git - mirror_ubuntu-kernels.git/commitdiff
bcachefs: Persist stripe blocks_used
authorKent Overstreet <kent.overstreet@gmail.com>
Mon, 26 Nov 2018 01:53:51 +0000 (20:53 -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/btree_gc.c
fs/bcachefs/buckets.c
fs/bcachefs/ec.c
fs/bcachefs/ec.h
fs/bcachefs/ec_types.h
fs/bcachefs/recovery.c
fs/bcachefs/super.c

index a725a106f6dc6b868538c4ba9bec0679dac43da0..b63dcbdb95c01760381f1536e26083d20bea9c31 100644 (file)
@@ -561,6 +561,7 @@ static void bch2_gc_done(struct bch_fs *c, bool initial)
                        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) {                   \
@@ -591,16 +592,18 @@ static void bch2_gc_done(struct bch_fs *c, bool initial)
 
                while ((dst = genradix_iter_peek(&dst_iter, &c->stripes[0])) &&
                       (src = genradix_iter_peek(&src_iter, &c->stripes[1]))) {
+                       BUG_ON(src_iter.pos != dst_iter.pos);
+
                        copy_stripe_field(alive,        "alive");
                        copy_stripe_field(sectors,      "sectors");
                        copy_stripe_field(algorithm,    "algorithm");
                        copy_stripe_field(nr_blocks,    "nr_blocks");
                        copy_stripe_field(nr_redundant, "nr_redundant");
-                       copy_stripe_field(blocks_nonempty.counter,
+                       copy_stripe_field(blocks_nonempty,
                                          "blocks_nonempty");
 
                        for (i = 0; i < ARRAY_SIZE(dst->block_sectors); i++)
-                               copy_stripe_field(block_sectors[i].counter,
+                               copy_stripe_field(block_sectors[i],
                                                  "block_sectors[%u]", i);
 
                        if (dst->alive)
index 3e92a1f6d7fc212f1d07b2fb0696a5921d12ad49..a1c243f622a87bec99eb70df1391788387c146a4 100644 (file)
@@ -605,9 +605,14 @@ static int bch2_mark_stripe_ptr(struct bch_fs *c,
        int blocks_nonempty_delta;
        s64 parity_sectors;
 
+       BUG_ON(!sectors);
+
        m = genradix_ptr(&c->stripes[gc], p.idx);
 
+       spin_lock(&c->ec_stripes_heap_lock);
+
        if (!m || !m->alive) {
+               spin_unlock(&c->ec_stripes_heap_lock);
                bch_err_ratelimited(c, "pointer to nonexistent stripe %llu",
                                    (u64) p.idx);
                return -1;
@@ -623,19 +628,21 @@ static int bch2_mark_stripe_ptr(struct bch_fs *c,
                parity_sectors = -parity_sectors;
        sectors += parity_sectors;
 
-       new = atomic_add_return(sectors, &m->block_sectors[p.block]);
-       old = new - sectors;
+       old = m->block_sectors[p.block];
+       m->block_sectors[p.block] += sectors;
+       new = m->block_sectors[p.block];
 
        blocks_nonempty_delta = (int) !!new - (int) !!old;
-       if (!blocks_nonempty_delta)
-               return 0;
+       if (blocks_nonempty_delta) {
+               m->blocks_nonempty += blocks_nonempty_delta;
 
-       atomic_add(blocks_nonempty_delta, &m->blocks_nonempty);
+               if (!gc)
+                       bch2_stripes_heap_update(c, m, p.idx);
+       }
 
-       BUG_ON(atomic_read(&m->blocks_nonempty) < 0);
+       m->dirty = true;
 
-       if (!gc)
-               bch2_stripes_heap_update(c, m, p.idx);
+       spin_unlock(&c->ec_stripes_heap_lock);
 
        update_replicas(c, fs_usage, &m->r.e, sectors);
 
@@ -721,8 +728,6 @@ static void bucket_set_stripe(struct bch_fs *c,
                                new.journal_seq         = journal_seq;
                        }
                }));
-
-               BUG_ON(old.stripe == enabled);
        }
 }
 
@@ -737,22 +742,19 @@ static int bch2_mark_stripe(struct bch_fs *c, struct bkey_s_c k,
        struct stripe *m = genradix_ptr(&c->stripes[gc], idx);
        unsigned i;
 
+       spin_lock(&c->ec_stripes_heap_lock);
+
        if (!m || (!inserting && !m->alive)) {
+               spin_unlock(&c->ec_stripes_heap_lock);
                bch_err_ratelimited(c, "error marking nonexistent stripe %zu",
                                    idx);
                return -1;
        }
 
-       if (inserting && m->alive) {
-               bch_err_ratelimited(c, "error marking stripe %zu: already exists",
-                                   idx);
-               return -1;
-       }
+       if (m->alive)
+               bch2_stripes_heap_del(c, m, idx);
 
-       BUG_ON(atomic_read(&m->blocks_nonempty));
-
-       for (i = 0; i < EC_STRIPE_MAX; i++)
-               BUG_ON(atomic_read(&m->block_sectors[i]));
+       memset(m, 0, sizeof(*m));
 
        if (inserting) {
                m->sectors      = le16_to_cpu(s.v->sectors);
@@ -768,7 +770,6 @@ static int bch2_mark_stripe(struct bch_fs *c, struct bkey_s_c k,
 
                for (i = 0; i < s.v->nr_blocks; i++)
                        m->r.e.devs[i] = s.v->ptrs[i].dev;
-       }
 
        /*
         * XXX: account for stripes somehow here
@@ -777,15 +778,23 @@ static int bch2_mark_stripe(struct bch_fs *c, struct bkey_s_c k,
        update_replicas(c, fs_usage, &m->r.e, stripe_sectors);
 #endif
 
-       if (!gc) {
-               if (inserting)
+               /* gc recalculates these fields: */
+               if (!(flags & BCH_BUCKET_MARK_GC)) {
+                       for (i = 0; i < s.v->nr_blocks; i++) {
+                               m->block_sectors[i] =
+                                       stripe_blockcount_get(s.v, i);
+                               m->blocks_nonempty += !!m->block_sectors[i];
+                       }
+               }
+
+               if (!gc)
                        bch2_stripes_heap_insert(c, m, idx);
                else
-                       bch2_stripes_heap_del(c, m, idx);
-       } else {
-               m->alive = inserting;
+                       m->alive = true;
        }
 
+       spin_unlock(&c->ec_stripes_heap_lock);
+
        bucket_set_stripe(c, s.v, inserting, fs_usage, 0, gc);
        return 0;
 }
index 5a5baba8d79be4f4af554da2d8386028c7a624a5..fc73823f6358ebfa1433d0b4b9422f285891edca 100644 (file)
@@ -12,6 +12,7 @@
 #include "ec.h"
 #include "error.h"
 #include "io.h"
+#include "journal_io.h"
 #include "keylist.h"
 #include "super-io.h"
 #include "util.h"
@@ -99,40 +100,6 @@ struct ec_bio {
 
 /* Stripes btree keys: */
 
-static unsigned stripe_csums_per_device(const struct bch_stripe *s)
-{
-       return DIV_ROUND_UP(le16_to_cpu(s->sectors),
-                           1 << s->csum_granularity_bits);
-}
-
-static unsigned stripe_csum_offset(const struct bch_stripe *s,
-                                  unsigned dev, unsigned csum_idx)
-{
-       unsigned csum_bytes = bch_crc_bytes[s->csum_type];
-
-       return sizeof(struct bch_stripe) +
-               sizeof(struct bch_extent_ptr) * s->nr_blocks +
-               (dev * stripe_csums_per_device(s) + csum_idx) * csum_bytes;
-}
-
-static unsigned stripe_blockcount_offset(const struct bch_stripe *s,
-                                        unsigned idx)
-{
-       return stripe_csum_offset(s, s->nr_blocks, 0) +
-               sizeof(16) * idx;
-}
-
-static unsigned stripe_val_u64s(const struct bch_stripe *s)
-{
-       return DIV_ROUND_UP(stripe_blockcount_offset(s, s->nr_blocks),
-                           sizeof(u64));
-}
-
-static void *stripe_csum(struct bch_stripe *s, unsigned dev, unsigned csum_idx)
-{
-       return (void *) s + stripe_csum_offset(s, dev, csum_idx);
-}
-
 const char *bch2_stripe_invalid(const struct bch_fs *c, struct bkey_s_c k)
 {
        const struct bch_stripe *s = bkey_s_c_to_stripe(k).v;
@@ -165,8 +132,9 @@ void bch2_stripe_to_text(struct printbuf *out, struct bch_fs *c,
               1U << s->csum_granularity_bits);
 
        for (i = 0; i < s->nr_blocks; i++)
-               pr_buf(out, " %u:%llu", s->ptrs[i].dev,
-                      (u64) s->ptrs[i].offset);
+               pr_buf(out, " %u:%llu:%u", s->ptrs[i].dev,
+                      (u64) s->ptrs[i].offset,
+                      stripe_blockcount_get(s, i));
 }
 
 static int ptr_matches_stripe(struct bch_fs *c,
@@ -610,29 +578,15 @@ static void heap_verify_backpointer(struct bch_fs *c, size_t idx)
        BUG_ON(h->data[m->heap_idx].idx != idx);
 }
 
-static inline unsigned stripe_entry_blocks(struct stripe *m)
-{
-       return atomic_read(&m->blocks_nonempty);
-}
-
 void bch2_stripes_heap_update(struct bch_fs *c,
                              struct stripe *m, size_t idx)
 {
        ec_stripes_heap *h = &c->ec_stripes_heap;
-       bool queue_delete;
        size_t i;
 
-       spin_lock(&c->ec_stripes_heap_lock);
-
-       if (!m->alive) {
-               spin_unlock(&c->ec_stripes_heap_lock);
-               return;
-       }
-
        heap_verify_backpointer(c, idx);
 
-       h->data[m->heap_idx].blocks_nonempty =
-               stripe_entry_blocks(m);
+       h->data[m->heap_idx].blocks_nonempty = m->blocks_nonempty;
 
        i = m->heap_idx;
        heap_sift_up(h,   i, ec_stripes_heap_cmp,
@@ -642,44 +596,35 @@ void bch2_stripes_heap_update(struct bch_fs *c,
 
        heap_verify_backpointer(c, idx);
 
-       queue_delete = stripe_idx_to_delete(c) >= 0;
-       spin_unlock(&c->ec_stripes_heap_lock);
-
-       if (queue_delete)
+       if (stripe_idx_to_delete(c) >= 0)
                schedule_work(&c->ec_stripe_delete_work);
 }
 
 void bch2_stripes_heap_del(struct bch_fs *c,
                           struct stripe *m, size_t idx)
 {
-       spin_lock(&c->ec_stripes_heap_lock);
        heap_verify_backpointer(c, idx);
 
        m->alive = false;
        heap_del(&c->ec_stripes_heap, m->heap_idx,
                 ec_stripes_heap_cmp,
                 ec_stripes_heap_set_backpointer);
-       spin_unlock(&c->ec_stripes_heap_lock);
 }
 
 void bch2_stripes_heap_insert(struct bch_fs *c,
                              struct stripe *m, size_t idx)
 {
-       spin_lock(&c->ec_stripes_heap_lock);
-
        BUG_ON(heap_full(&c->ec_stripes_heap));
 
        heap_add(&c->ec_stripes_heap, ((struct ec_stripe_heap_entry) {
                        .idx = idx,
-                       .blocks_nonempty = stripe_entry_blocks(m),
+                       .blocks_nonempty = m->blocks_nonempty,
                }),
                 ec_stripes_heap_cmp,
                 ec_stripes_heap_set_backpointer);
        m->alive = true;
 
        heap_verify_backpointer(c, idx);
-
-       spin_unlock(&c->ec_stripes_heap_lock);
 }
 
 /* stripe deletion */
@@ -1218,6 +1163,116 @@ unlock:
        mutex_unlock(&c->ec_new_stripe_lock);
 }
 
+static int __bch2_stripe_write_key(struct bch_fs *c,
+                                  struct btree_iter *iter,
+                                  struct stripe *m,
+                                  size_t idx,
+                                  struct bkey_i_stripe *new_key,
+                                  unsigned flags)
+{
+       struct bkey_s_c k;
+       unsigned i;
+       int ret;
+
+       bch2_btree_iter_set_pos(iter, POS(0, idx));
+
+       k = bch2_btree_iter_peek_slot(iter);
+       ret = btree_iter_err(k);
+       if (ret)
+               return ret;
+
+       if (k.k->type != KEY_TYPE_stripe)
+               return -EIO;
+
+       bkey_reassemble(&new_key->k_i, k);
+
+       spin_lock(&c->ec_stripes_heap_lock);
+
+       for (i = 0; i < new_key->v.nr_blocks; i++)
+               stripe_blockcount_set(&new_key->v, i,
+                                     m->block_sectors[i]);
+       m->dirty = false;
+
+       spin_unlock(&c->ec_stripes_heap_lock);
+
+       return bch2_btree_insert_at(c, NULL, NULL,
+                                  BTREE_INSERT_NOFAIL|flags,
+                                  BTREE_INSERT_ENTRY(iter, &new_key->k_i));
+}
+
+int bch2_stripes_write(struct bch_fs *c, bool *wrote)
+{
+       struct btree_iter iter;
+       struct genradix_iter giter;
+       struct bkey_i_stripe *new_key;
+       struct stripe *m;
+       int ret = 0;
+
+       new_key = kmalloc(255 * sizeof(u64), GFP_KERNEL);
+       BUG_ON(!new_key);
+
+       bch2_btree_iter_init(&iter, c, BTREE_ID_EC, POS_MIN,
+                            BTREE_ITER_SLOTS|BTREE_ITER_INTENT);
+
+       genradix_for_each(&c->stripes[0], giter, m) {
+               if (!m->dirty)
+                       continue;
+
+               ret = __bch2_stripe_write_key(c, &iter, m, giter.pos,
+                                       new_key, BTREE_INSERT_NOCHECK_RW);
+               if (ret)
+                       break;
+
+               *wrote = true;
+       }
+
+       bch2_btree_iter_unlock(&iter);
+
+       kfree(new_key);
+
+       return ret;
+}
+
+static void bch2_stripe_read_key(struct bch_fs *c, struct bkey_s_c k)
+{
+
+       struct gc_pos pos = { 0 };
+
+       bch2_mark_key(c, k, true, 0, pos, NULL, 0, 0);
+}
+
+int bch2_stripes_read(struct bch_fs *c, struct list_head *journal_replay_list)
+{
+       struct journal_replay *r;
+       struct btree_iter iter;
+       struct bkey_s_c k;
+       int ret;
+
+       ret = bch2_fs_ec_start(c);
+       if (ret)
+               return ret;
+
+       for_each_btree_key(&iter, c, BTREE_ID_EC, POS_MIN, 0, k) {
+               bch2_stripe_read_key(c, k);
+               bch2_btree_iter_cond_resched(&iter);
+       }
+
+       ret = bch2_btree_iter_unlock(&iter);
+       if (ret)
+               return ret;
+
+       list_for_each_entry(r, journal_replay_list, list) {
+               struct bkey_i *k, *n;
+               struct jset_entry *entry;
+
+               for_each_jset_key(k, n, entry, &r->j)
+                       if (entry->btree_id == BTREE_ID_EC)
+                               bch2_stripe_read_key(c, bkey_i_to_s_c(k));
+       }
+
+       return 0;
+}
+
 int bch2_ec_mem_alloc(struct bch_fs *c, bool gc)
 {
        struct btree_iter iter;
index 4a8cade37c7ac7fa4f3afa8ff53c3e9732b4a87a..7bcbb7e1137753ef9407d4917a289401c153e58f 100644 (file)
@@ -14,6 +14,55 @@ void bch2_stripe_to_text(struct printbuf *, struct bch_fs *,
        .val_to_text    = bch2_stripe_to_text,          \
 }
 
+static inline unsigned stripe_csums_per_device(const struct bch_stripe *s)
+{
+       return DIV_ROUND_UP(le16_to_cpu(s->sectors),
+                           1 << s->csum_granularity_bits);
+}
+
+static inline unsigned stripe_csum_offset(const struct bch_stripe *s,
+                                         unsigned dev, unsigned csum_idx)
+{
+       unsigned csum_bytes = bch_crc_bytes[s->csum_type];
+
+       return sizeof(struct bch_stripe) +
+               sizeof(struct bch_extent_ptr) * s->nr_blocks +
+               (dev * stripe_csums_per_device(s) + csum_idx) * csum_bytes;
+}
+
+static inline unsigned stripe_blockcount_offset(const struct bch_stripe *s,
+                                               unsigned idx)
+{
+       return stripe_csum_offset(s, s->nr_blocks, 0) +
+               sizeof(u16) * idx;
+}
+
+static inline unsigned stripe_blockcount_get(const struct bch_stripe *s,
+                                            unsigned idx)
+{
+       return le16_to_cpup((void *) s + stripe_blockcount_offset(s, idx));
+}
+
+static inline void stripe_blockcount_set(struct bch_stripe *s,
+                                        unsigned idx, unsigned v)
+{
+       __le16 *p = (void *) s + stripe_blockcount_offset(s, idx);
+
+       *p = cpu_to_le16(v);
+}
+
+static inline unsigned stripe_val_u64s(const struct bch_stripe *s)
+{
+       return DIV_ROUND_UP(stripe_blockcount_offset(s, s->nr_blocks),
+                           sizeof(u64));
+}
+
+static inline void *stripe_csum(struct bch_stripe *s,
+                               unsigned dev, unsigned csum_idx)
+{
+       return (void *) s + stripe_csum_offset(s, dev, csum_idx);
+}
+
 struct bch_read_bio;
 
 struct ec_stripe_buf {
@@ -101,6 +150,9 @@ void bch2_ec_stop_dev(struct bch_fs *, struct bch_dev *);
 
 void bch2_ec_flush_new_stripes(struct bch_fs *);
 
+int bch2_stripes_read(struct bch_fs *, struct list_head *);
+int bch2_stripes_write(struct bch_fs *, bool *);
+
 int bch2_ec_mem_alloc(struct bch_fs *, bool);
 
 int bch2_fs_ec_start(struct bch_fs *);
index e416dac7ee19a9370cf8f96d328a5e5b6aac8375..5c3f77c8aac71b9f269031f9deb2271e7e59c519 100644 (file)
@@ -20,9 +20,10 @@ struct stripe {
        u8                      nr_blocks;
        u8                      nr_redundant;
 
-       u8                      alive;
-       atomic_t                blocks_nonempty;
-       atomic_t                block_sectors[EC_STRIPE_MAX];
+       unsigned                alive:1;
+       unsigned                dirty:1;
+       u8                      blocks_nonempty;
+       u16                     block_sectors[EC_STRIPE_MAX];
 
        struct bch_replicas_padded r;
 };
index cfdf9b5636375c8e06f486d873674556a04064ac..2eaff9a6fee55ecc272f29a33248b296190399b3 100644 (file)
@@ -215,12 +215,12 @@ int bch2_fs_recovery(struct bch_fs *c)
        if (ret)
                goto err;
 
-       set_bit(BCH_FS_ALLOC_READ_DONE, &c->flags);
-
-       err = "cannot allocate memory";
-       ret = bch2_fs_ec_start(c);
+       ret = bch2_stripes_read(c, &journal);
        if (ret)
                goto err;
+       pr_info("stripes_read done");
+
+       set_bit(BCH_FS_ALLOC_READ_DONE, &c->flags);
 
        bch_verbose(c, "starting mark and sweep:");
        err = "error in recovery";
index 0ad62429405296ac0edb3236fc1f598ad3a17f63..f1e60c377fa2dfb9cf2c22d497c2ee860049b7d6 100644 (file)
@@ -198,6 +198,12 @@ static void __bch2_fs_read_only(struct bch_fs *c)
                        break;
                }
 
+               ret = bch2_stripes_write(c, &wrote);
+               if (ret) {
+                       bch2_fs_inconsistent(c, "error writing out stripes");
+                       break;
+               }
+
                for_each_member_device(ca, c, i)
                        bch2_dev_allocator_quiesce(c, ca);