]> git.sesse.net Git - bcachefs-tools-debian/commitdiff
Update bcachefs sources to de3b30303e bcachefs: bucket_gens btree
authorKent Overstreet <kent.overstreet@linux.dev>
Sat, 3 Dec 2022 02:55:01 +0000 (21:55 -0500)
committerKent Overstreet <kent.overstreet@linux.dev>
Sat, 3 Dec 2022 02:55:01 +0000 (21:55 -0500)
.bcachefs_revision
libbcachefs/alloc_background.c
libbcachefs/alloc_background.h
libbcachefs/bcachefs.h
libbcachefs/bcachefs_format.h
libbcachefs/bkey_methods.c
libbcachefs/recovery.c

index 2aea1a7dbdbfe0b614f6906badec0be40619c935..0ba18448e1e1951b857fc06e2f8d3bb83aaf1cfd 100644 (file)
@@ -1 +1 @@
-be2d60d9484734b4c619ac0ddf54b3103210c9c0
+de3b30303e8a52dcbf738065efb4cf183fdbf1c1
index d9bc2d0f844aa589682d9abf70ae5dec07a6cb84..39d8d31722da0b47e6f8344316aad0df4d471bbf 100644 (file)
@@ -584,6 +584,159 @@ int bch2_alloc_read(struct bch_fs *c)
        return ret;
 }
 
+static struct bpos alloc_gens_pos(struct bpos pos, unsigned *offset)
+{
+       *offset = pos.offset & KEY_TYPE_BUCKET_GENS_MASK;
+
+       pos.offset >>= KEY_TYPE_BUCKET_GENS_BITS;
+       return pos;
+}
+
+static struct bpos bucket_gens_pos_to_alloc(struct bpos pos, unsigned offset)
+{
+       pos.offset <<= KEY_TYPE_BUCKET_GENS_BITS;
+       pos.offset += offset;
+       return pos;
+}
+
+static unsigned alloc_gen(struct bkey_s_c k, unsigned offset)
+{
+       return k.k->type == KEY_TYPE_bucket_gens
+               ? bkey_s_c_to_bucket_gens(k).v->gens[offset]
+               : 0;
+}
+
+int bch2_bucket_gens_invalid(const struct bch_fs *c, struct bkey_s_c k,
+                            int rw, struct printbuf *err)
+{
+       if (bkey_val_bytes(k.k) != sizeof(struct bch_bucket_gens)) {
+               prt_printf(err, "bad val size (%lu != %zu)",
+                      bkey_val_bytes(k.k), sizeof(struct bch_bucket_gens));
+               return -BCH_ERR_invalid_bkey;
+       }
+
+       return 0;
+}
+
+void bch2_bucket_gens_to_text(struct printbuf *out, struct bch_fs *c, struct bkey_s_c k)
+{
+       struct bkey_s_c_bucket_gens g = bkey_s_c_to_bucket_gens(k);
+       unsigned i;
+
+       for (i = 0; i < ARRAY_SIZE(g.v->gens); i++) {
+               if (i)
+                       prt_char(out, ' ');
+               prt_printf(out, "%u", g.v->gens[i]);
+       }
+}
+
+int bch2_bucket_gens_init(struct bch_fs *c)
+{
+       struct btree_trans trans;
+       struct btree_iter iter;
+       struct bkey_s_c k;
+       struct bch_alloc_v4 a;
+       struct bkey_i_bucket_gens g;
+       bool have_bucket_gens_key = false;
+       unsigned offset;
+       struct bpos pos;
+       u8 gen;
+       int ret;
+
+       bch2_trans_init(&trans, c, 0, 0);
+
+       for_each_btree_key(&trans, iter, BTREE_ID_alloc, POS_MIN,
+                          BTREE_ITER_PREFETCH, k, ret) {
+               /*
+                * Not a fsck error because this is checked/repaired by
+                * bch2_check_alloc_key() which runs later:
+                */
+               if (!bch2_dev_bucket_exists(c, k.k->p))
+                       continue;
+
+               gen = bch2_alloc_to_v4(k, &a)->gen;
+               pos = alloc_gens_pos(iter.pos, &offset);
+
+               if (have_bucket_gens_key && bkey_cmp(iter.pos, pos)) {
+                       ret = commit_do(&trans, NULL, NULL,
+                                       BTREE_INSERT_NOFAIL|
+                                       BTREE_INSERT_LAZY_RW,
+                               __bch2_btree_insert(&trans, BTREE_ID_bucket_gens, &g.k_i));
+                       if (ret)
+                               break;
+                       have_bucket_gens_key = false;
+               }
+
+               if (!have_bucket_gens_key) {
+                       bkey_bucket_gens_init(&g.k_i);
+                       g.k.p = pos;
+                       have_bucket_gens_key = true;
+               }
+
+               g.v.gens[offset] = gen;
+       }
+       bch2_trans_iter_exit(&trans, &iter);
+
+       if (have_bucket_gens_key && !ret)
+               ret = commit_do(&trans, NULL, NULL,
+                               BTREE_INSERT_NOFAIL|
+                               BTREE_INSERT_LAZY_RW,
+                       __bch2_btree_insert(&trans, BTREE_ID_bucket_gens, &g.k_i));
+
+       bch2_trans_exit(&trans);
+
+       if (ret)
+               bch_err(c, "%s: error %s", __func__, bch2_err_str(ret));
+
+       return ret;
+}
+
+int bch2_bucket_gens_read(struct bch_fs *c)
+{
+       struct btree_trans trans;
+       struct btree_iter iter;
+       struct bkey_s_c k;
+       const struct bch_bucket_gens *g;
+       struct bch_dev *ca;
+       u64 b;
+       int ret;
+
+       bch2_trans_init(&trans, c, 0, 0);
+
+       for_each_btree_key(&trans, iter, BTREE_ID_bucket_gens, POS_MIN,
+                          BTREE_ITER_PREFETCH, k, ret) {
+               u64 start = bucket_gens_pos_to_alloc(k.k->p, 0).offset;
+               u64 end = bucket_gens_pos_to_alloc(bpos_nosnap_successor(k.k->p), 0).offset;
+
+               if (k.k->type != KEY_TYPE_bucket_gens)
+                       continue;
+
+               g = bkey_s_c_to_bucket_gens(k).v;
+
+               /*
+                * Not a fsck error because this is checked/repaired by
+                * bch2_check_alloc_key() which runs later:
+                */
+               if (!bch2_dev_exists2(c, k.k->p.inode))
+                       continue;
+
+               ca = bch_dev_bkey_exists(c, k.k->p.inode);
+
+               for (b = max_t(u64, ca->mi.first_bucket, start);
+                    b < min_t(u64, ca->mi.nbuckets, end);
+                    b++)
+                       *bucket_gen(ca, b) = g->gens[b & KEY_TYPE_BUCKET_GENS_MASK];
+       }
+       bch2_trans_iter_exit(&trans, &iter);
+
+       bch2_trans_exit(&trans);
+
+       if (ret)
+               bch_err(c, "error reading alloc info: %s", bch2_err_str(ret));
+
+       return ret;
+}
+
 /* Free space/discard btree: */
 
 static int bch2_bucket_do_index(struct btree_trans *trans,
@@ -655,6 +808,44 @@ err:
        return ret;
 }
 
+static noinline int bch2_bucket_gen_update(struct btree_trans *trans,
+                                          struct bpos bucket, u8 gen)
+{
+       struct btree_iter iter;
+       unsigned offset;
+       struct bpos pos = alloc_gens_pos(bucket, &offset);
+       struct bkey_i_bucket_gens *g;
+       struct bkey_s_c k;
+       int ret;
+
+       g = bch2_trans_kmalloc(trans, sizeof(*g));
+       ret = PTR_ERR_OR_ZERO(g);
+       if (ret)
+               return ret;
+
+       bch2_trans_iter_init(trans, &iter, BTREE_ID_bucket_gens, pos,
+                            BTREE_ITER_INTENT|
+                            BTREE_ITER_WITH_UPDATES);
+       k = bch2_btree_iter_peek_slot(&iter);
+       ret = bkey_err(k);
+       if (ret)
+               goto err;
+
+       if (k.k->type != KEY_TYPE_bucket_gens) {
+               bkey_bucket_gens_init(&g->k_i);
+               g->k.p = iter.pos;
+       } else {
+               bkey_reassemble(&g->k_i, k);
+       }
+
+       g->v.gens[offset] = gen;
+
+       ret = bch2_trans_update(trans, &iter, &g->k_i, 0);
+err:
+       bch2_trans_iter_exit(trans, &iter);
+       return ret;
+}
+
 int bch2_trans_mark_alloc(struct btree_trans *trans,
                          enum btree_id btree_id, unsigned level,
                          struct bkey_s_c old, struct bkey_i *new,
@@ -718,6 +909,12 @@ int bch2_trans_mark_alloc(struct btree_trans *trans,
                        new_a->io_time[READ] = new_lru;
        }
 
+       if (old_a->gen != new_a->gen) {
+               ret = bch2_bucket_gen_update(trans, new->k.p, new_a->gen);
+               if (ret)
+                       return ret;
+       }
+
        return 0;
 }
 
@@ -823,13 +1020,15 @@ static int bch2_check_alloc_key(struct btree_trans *trans,
                                struct bkey_s_c alloc_k,
                                struct btree_iter *alloc_iter,
                                struct btree_iter *discard_iter,
-                               struct btree_iter *freespace_iter)
+                               struct btree_iter *freespace_iter,
+                               struct btree_iter *bucket_gens_iter)
 {
        struct bch_fs *c = trans->c;
        struct bch_dev *ca;
        struct bch_alloc_v4 a_convert;
        const struct bch_alloc_v4 *a;
        unsigned discard_key_type, freespace_key_type;
+       unsigned gens_offset;
        struct bkey_s_c k;
        struct printbuf buf = PRINTBUF;
        int ret;
@@ -845,14 +1044,8 @@ static int bch2_check_alloc_key(struct btree_trans *trans,
 
        a = bch2_alloc_to_v4(alloc_k, &a_convert);
 
-       discard_key_type = a->data_type == BCH_DATA_need_discard
-               ? KEY_TYPE_set : 0;
-       freespace_key_type = a->data_type == BCH_DATA_free
-               ? KEY_TYPE_set : 0;
-
+       discard_key_type = a->data_type == BCH_DATA_need_discard ? KEY_TYPE_set : 0;
        bch2_btree_iter_set_pos(discard_iter, alloc_k.k->p);
-       bch2_btree_iter_set_pos(freespace_iter, alloc_freespace_pos(alloc_k.k->p, *a));
-
        k = bch2_btree_iter_peek_slot(discard_iter);
        ret = bkey_err(k);
        if (ret)
@@ -881,6 +1074,8 @@ static int bch2_check_alloc_key(struct btree_trans *trans,
                        goto err;
        }
 
+       freespace_key_type = a->data_type == BCH_DATA_free ? KEY_TYPE_set : 0;
+       bch2_btree_iter_set_pos(freespace_iter, alloc_freespace_pos(alloc_k.k->p, *a));
        k = bch2_btree_iter_peek_slot(freespace_iter);
        ret = bkey_err(k);
        if (ret)
@@ -910,13 +1105,47 @@ static int bch2_check_alloc_key(struct btree_trans *trans,
                if (ret)
                        goto err;
        }
+
+       bch2_btree_iter_set_pos(bucket_gens_iter, alloc_gens_pos(alloc_k.k->p, &gens_offset));
+       k = bch2_btree_iter_peek_slot(bucket_gens_iter);
+       ret = bkey_err(k);
+       if (ret)
+               goto err;
+
+       if (a->gen != alloc_gen(k, gens_offset) &&
+           (c->opts.reconstruct_alloc ||
+            fsck_err(c, "incorrect gen in bucket_gens btree (got %u should be %u)\n"
+                     "  %s",
+                     alloc_gen(k, gens_offset), a->gen,
+                     (printbuf_reset(&buf),
+                      bch2_bkey_val_to_text(&buf, c, alloc_k), buf.buf)))) {
+               struct bkey_i_bucket_gens *g =
+                       bch2_trans_kmalloc(trans, sizeof(*g));
+
+               ret = PTR_ERR_OR_ZERO(g);
+               if (ret)
+                       goto err;
+
+               if (k.k->type == KEY_TYPE_bucket_gens) {
+                       bkey_reassemble(&g->k_i, k);
+               } else {
+                       bkey_bucket_gens_init(&g->k_i);
+                       g->k.p = alloc_gens_pos(alloc_k.k->p, &gens_offset);
+               }
+
+               g->v.gens[gens_offset] = a->gen;
+
+               ret = bch2_trans_update(trans, bucket_gens_iter, &g->k_i, 0);
+               if (ret)
+                       goto err;
+       }
 err:
 fsck_err:
        printbuf_exit(&buf);
        return ret;
 }
 
-static int bch2_check_alloc_hole(struct btree_trans *trans,
+static int bch2_check_alloc_hole_freespace(struct btree_trans *trans,
                                 struct bpos start,
                                 struct bpos *end,
                                 struct btree_iter *freespace_iter)
@@ -971,6 +1200,63 @@ fsck_err:
        return ret;
 }
 
+static int bch2_check_alloc_hole_bucket_gens(struct btree_trans *trans,
+                                struct bpos start,
+                                struct bpos *end,
+                                struct btree_iter *bucket_gens_iter)
+{
+       struct bch_fs *c = trans->c;
+       struct bkey_s_c k;
+       struct printbuf buf = PRINTBUF;
+       unsigned i, gens_offset, gens_end_offset;
+       int ret;
+
+       if (c->sb.version < bcachefs_metadata_version_bucket_gens &&
+           !c->opts.version_upgrade)
+               return 0;
+
+       bch2_btree_iter_set_pos(bucket_gens_iter, alloc_gens_pos(start, &gens_offset));
+
+       k = bch2_btree_iter_peek_slot(bucket_gens_iter);
+       ret = bkey_err(k);
+       if (ret)
+               goto err;
+
+       if (bkey_cmp(alloc_gens_pos(start, &gens_offset),
+                    alloc_gens_pos(*end,  &gens_end_offset)))
+               gens_end_offset = KEY_TYPE_BUCKET_GENS_NR;
+
+       if (k.k->type == KEY_TYPE_bucket_gens) {
+               struct bkey_i_bucket_gens g;
+               bool need_update = false;
+
+               bkey_reassemble(&g.k_i, k);
+
+               for (i = gens_offset; i < gens_end_offset; i++) {
+                       if (fsck_err_on(g.v.gens[i], c,
+                                       "hole in alloc btree at %llu:%llu with nonzero gen in bucket_gens btree (%u)",
+                                       bucket_gens_pos_to_alloc(k.k->p, i).inode,
+                                       bucket_gens_pos_to_alloc(k.k->p, i).offset,
+                                       g.v.gens[i])) {
+                               g.v.gens[i] = 0;
+                               need_update = true;
+                       }
+               }
+
+               if (need_update) {
+                       ret = bch2_trans_update(trans, bucket_gens_iter, &g.k_i, 0);
+                       if (ret)
+                               goto err;
+               }
+       }
+
+       *end = bkey_min(*end, bucket_gens_pos_to_alloc(bpos_nosnap_successor(k.k->p), 0));
+err:
+fsck_err:
+       printbuf_exit(&buf);
+       return ret;
+}
+
 static int bch2_check_discard_freespace_key(struct btree_trans *trans,
                                            struct btree_iter *iter)
 {
@@ -1026,10 +1312,79 @@ delete:
        goto out;
 }
 
+/*
+ * We've already checked that generation numbers in the bucket_gens btree are
+ * valid for buckets that exist; this just checks for keys for nonexistent
+ * buckets.
+ */
+static int bch2_check_bucket_gens_key(struct btree_trans *trans,
+                                     struct btree_iter *iter,
+                                     struct bkey_s_c k)
+{
+       struct bch_fs *c = trans->c;
+       struct bkey_i_bucket_gens g;
+       struct bch_dev *ca;
+       u64 start = bucket_gens_pos_to_alloc(k.k->p, 0).offset;
+       u64 end = bucket_gens_pos_to_alloc(bpos_nosnap_successor(k.k->p), 0).offset;
+       u64 b;
+       bool need_update = false;
+       struct printbuf buf = PRINTBUF;
+       int ret = 0;
+
+       BUG_ON(k.k->type != KEY_TYPE_bucket_gens);
+       bkey_reassemble(&g.k_i, k);
+
+       if (fsck_err_on(!bch2_dev_exists2(c, k.k->p.inode), c,
+                       "bucket_gens key for invalid device:\n  %s",
+                       (bch2_bkey_val_to_text(&buf, c, k), buf.buf))) {
+               ret = bch2_btree_delete_at(trans, iter, 0);
+               goto out;
+       }
+
+       ca = bch_dev_bkey_exists(c, k.k->p.inode);
+       if (fsck_err_on(end <= ca->mi.first_bucket ||
+                       start >= ca->mi.nbuckets, c,
+                       "bucket_gens key for invalid buckets:\n  %s",
+                       (bch2_bkey_val_to_text(&buf, c, k), buf.buf))) {
+               ret = bch2_btree_delete_at(trans, iter, 0);
+               goto out;
+       }
+
+       for (b = start; b < ca->mi.first_bucket; b++)
+               if (fsck_err_on(g.v.gens[b & KEY_TYPE_BUCKET_GENS_MASK], c,
+                               "bucket_gens key has nonzero gen for invalid bucket")) {
+                       g.v.gens[b & KEY_TYPE_BUCKET_GENS_MASK] = 0;
+                       need_update = true;
+               }
+
+       for (b = ca->mi.nbuckets; b < end; b++)
+               if (fsck_err_on(g.v.gens[b & KEY_TYPE_BUCKET_GENS_MASK], c,
+                               "bucket_gens key has nonzero gen for invalid bucket")) {
+                       g.v.gens[b & KEY_TYPE_BUCKET_GENS_MASK] = 0;
+                       need_update = true;
+               }
+
+       if (need_update) {
+               struct bkey_i *k;
+
+               k = bch2_trans_kmalloc(trans, sizeof(g));
+               ret = PTR_ERR_OR_ZERO(k);
+               if (ret)
+                       return ret;
+
+               memcpy(k, &g, sizeof(g));
+               ret = bch2_trans_update(trans, iter, k, 0);
+       }
+out:
+fsck_err:
+       printbuf_exit(&buf);
+       return ret;
+}
+
 int bch2_check_alloc_info(struct bch_fs *c)
 {
        struct btree_trans trans;
-       struct btree_iter iter, discard_iter, freespace_iter;
+       struct btree_iter iter, discard_iter, freespace_iter, bucket_gens_iter;
        struct bkey hole;
        struct bkey_s_c k;
        int ret = 0;
@@ -1042,6 +1397,8 @@ int bch2_check_alloc_info(struct bch_fs *c)
                             BTREE_ITER_PREFETCH);
        bch2_trans_iter_init(&trans, &freespace_iter, BTREE_ID_freespace, POS_MIN,
                             BTREE_ITER_PREFETCH);
+       bch2_trans_iter_init(&trans, &bucket_gens_iter, BTREE_ID_bucket_gens, POS_MIN,
+                            BTREE_ITER_PREFETCH);
 
        while (1) {
                struct bpos next;
@@ -1062,16 +1419,21 @@ int bch2_check_alloc_info(struct bch_fs *c)
                        ret = bch2_check_alloc_key(&trans,
                                                   k, &iter,
                                                   &discard_iter,
-                                                  &freespace_iter);
+                                                  &freespace_iter,
+                                                  &bucket_gens_iter);
                        if (ret)
                                break;
                } else {
                        next = k.k->p;
 
-                       ret = bch2_check_alloc_hole(&trans,
+                       ret = bch2_check_alloc_hole_freespace(&trans,
                                                    bkey_start_pos(k.k),
                                                    &next,
-                                                   &freespace_iter);
+                                                   &freespace_iter) ?:
+                               bch2_check_alloc_hole_bucket_gens(&trans,
+                                                   bkey_start_pos(k.k),
+                                                   &next,
+                                                   &bucket_gens_iter);
                        if (ret)
                                goto bkey_err;
                }
@@ -1089,6 +1451,7 @@ bkey_err:
                if (ret)
                        break;
        }
+       bch2_trans_iter_exit(&trans, &bucket_gens_iter);
        bch2_trans_iter_exit(&trans, &freespace_iter);
        bch2_trans_iter_exit(&trans, &discard_iter);
        bch2_trans_iter_exit(&trans, &iter);
@@ -1105,7 +1468,12 @@ bkey_err:
                        BTREE_ID_freespace, POS_MIN,
                        BTREE_ITER_PREFETCH, k,
                        NULL, NULL, BTREE_INSERT_NOFAIL|BTREE_INSERT_LAZY_RW,
-               bch2_check_discard_freespace_key(&trans, &iter));
+               bch2_check_discard_freespace_key(&trans, &iter)) ?:
+             for_each_btree_key_commit(&trans, iter,
+                       BTREE_ID_bucket_gens, POS_MIN,
+                       BTREE_ITER_PREFETCH, k,
+                       NULL, NULL, BTREE_INSERT_NOFAIL|BTREE_INSERT_LAZY_RW,
+               bch2_check_bucket_gens_key(&trans, &iter, k));
 err:
        bch2_trans_exit(&trans);
        return ret < 0 ? ret : 0;
index 7956d490a6e6afe112bab8b4061f077feb813edd..be48b7d88da56d91aadaf2629d0d3602aa54b565 100644 (file)
@@ -150,6 +150,16 @@ void bch2_alloc_to_text(struct printbuf *, struct bch_fs *, struct bkey_s_c);
        .atomic_trigger = bch2_mark_alloc,              \
 })
 
+int bch2_bucket_gens_invalid(const struct bch_fs *, struct bkey_s_c, int, struct printbuf *);
+void bch2_bucket_gens_to_text(struct printbuf *, struct bch_fs *, struct bkey_s_c);
+
+#define bch2_bkey_ops_bucket_gens ((struct bkey_ops) { \
+       .key_invalid    = bch2_bucket_gens_invalid,     \
+       .val_to_text    = bch2_bucket_gens_to_text,     \
+})
+
+int bch2_bucket_gens_init(struct bch_fs *);
+
 static inline bool bkey_is_alloc(const struct bkey *k)
 {
        return  k->type == KEY_TYPE_alloc ||
@@ -158,6 +168,7 @@ static inline bool bkey_is_alloc(const struct bkey *k)
 }
 
 int bch2_alloc_read(struct bch_fs *);
+int bch2_bucket_gens_read(struct bch_fs *);
 
 int bch2_trans_mark_alloc(struct btree_trans *, enum btree_id, unsigned,
                          struct bkey_s_c, struct bkey_i *, unsigned);
index 33341008016b7811c7a75d43200f91d414ae3671..7f479cdc7069f1409c1a87bbc668f70390ddbb12 100644 (file)
@@ -433,6 +433,7 @@ enum gc_phase {
        GC_PHASE_BTREE_freespace,
        GC_PHASE_BTREE_need_discard,
        GC_PHASE_BTREE_backpointers,
+       GC_PHASE_BTREE_bucket_gens,
 
        GC_PHASE_PENDING_DELETE,
 };
index f29e3e7e95258b2d1639491372f258edbfa3c204..91a6624e29abfb51b3c1ac7c7ab157d2defe7a40 100644 (file)
@@ -367,7 +367,8 @@ static inline void bkey_init(struct bkey *k)
        x(lru,                  26)                     \
        x(alloc_v4,             27)                     \
        x(backpointer,          28)                     \
-       x(inode_v3,             29)
+       x(inode_v3,             29)                     \
+       x(bucket_gens,          30)
 
 enum bch_bkey_type {
 #define x(name, nr) KEY_TYPE_##name    = nr,
@@ -1009,6 +1010,15 @@ struct bch_backpointer {
        struct bpos             pos;
 } __packed __aligned(8);
 
+#define KEY_TYPE_BUCKET_GENS_BITS      8
+#define KEY_TYPE_BUCKET_GENS_NR                (1U << KEY_TYPE_BUCKET_GENS_BITS)
+#define KEY_TYPE_BUCKET_GENS_MASK      (KEY_TYPE_BUCKET_GENS_NR - 1)
+
+struct bch_bucket_gens {
+       struct bch_val          v;
+       u8                      gens[KEY_TYPE_BUCKET_GENS_NR];
+} __packed __aligned(8);
+
 /* Quotas: */
 
 enum quota_types {
@@ -1546,7 +1556,8 @@ struct bch_sb_field_journal_seq_blacklist {
        x(new_data_types,               21)             \
        x(backpointers,                 22)             \
        x(inode_v3,                     23)             \
-       x(unwritten_extents,            24)
+       x(unwritten_extents,            24)             \
+       x(bucket_gens,                  25)
 
 enum bcachefs_metadata_version {
        bcachefs_metadata_version_min = 9,
@@ -2068,20 +2079,21 @@ LE32_BITMASK(JSET_NO_FLUSH,     struct jset, flags, 5, 6);
 /* Btree: */
 
 #define BCH_BTREE_IDS()                                \
-       x(extents,      0)                      \
-       x(inodes,       1)                      \
-       x(dirents,      2)                      \
-       x(xattrs,       3)                      \
-       x(alloc,        4)                      \
-       x(quotas,       5)                      \
-       x(stripes,      6)                      \
-       x(reflink,      7)                      \
-       x(subvolumes,   8)                      \
-       x(snapshots,    9)                      \
-       x(lru,          10)                     \
-       x(freespace,    11)                     \
-       x(need_discard, 12)                     \
-       x(backpointers, 13)
+       x(extents,              0)              \
+       x(inodes,               1)              \
+       x(dirents,              2)              \
+       x(xattrs,               3)              \
+       x(alloc,                4)              \
+       x(quotas,               5)              \
+       x(stripes,              6)              \
+       x(reflink,              7)              \
+       x(subvolumes,           8)              \
+       x(snapshots,            9)              \
+       x(lru,                  10)             \
+       x(freespace,            11)             \
+       x(need_discard,         12)             \
+       x(backpointers,         13)             \
+       x(bucket_gens,          14)
 
 enum btree_id {
 #define x(kwd, val) BTREE_ID_##kwd = val,
index 2d4db904afa3ba050f28ace57dfa33ae11448369..bb74e6f7d427299395fee739c399623ca7f8d960 100644 (file)
@@ -196,6 +196,9 @@ static unsigned bch2_key_types_allowed[] = {
        [BKEY_TYPE_backpointers] =
                (1U << KEY_TYPE_deleted)|
                (1U << KEY_TYPE_backpointer),
+       [BKEY_TYPE_bucket_gens] =
+               (1U << KEY_TYPE_deleted)|
+               (1U << KEY_TYPE_bucket_gens),
        [BKEY_TYPE_btree] =
                (1U << KEY_TYPE_deleted)|
                (1U << KEY_TYPE_btree_ptr)|
index af2628f43582ee3de736bc264916ba86bafc0eb7..4fd8ce55b30d749d32e573ec9f1f7fb6da0daa60 100644 (file)
@@ -1215,7 +1215,9 @@ use_clean:
        err = "error reading allocation information";
 
        down_read(&c->gc_lock);
-       ret = bch2_alloc_read(c);
+       ret = c->sb.version < bcachefs_metadata_version_bucket_gens
+               ? bch2_alloc_read(c)
+               : bch2_bucket_gens_read(c);
        up_read(&c->gc_lock);
 
        if (ret)
@@ -1351,6 +1353,16 @@ use_clean:
        if (ret)
                goto err;
 
+       if (c->sb.version < bcachefs_metadata_version_bucket_gens &&
+           c->opts.version_upgrade) {
+               bch_info(c, "initializing bucket_gens");
+               err = "error initializing bucket gens";
+               ret = bch2_bucket_gens_init(c);
+               if (ret)
+                       goto err;
+               bch_verbose(c, "bucket_gens init done");
+       }
+
        if (c->sb.version < bcachefs_metadata_version_snapshot_2) {
                /* set bi_subvol on root inode */
                err = "error upgrade root inode for subvolumes";