bcachefs: Repair code for multiple types of data in same bucket
authorKent Overstreet <kent.overstreet@gmail.com>
Sat, 15 May 2021 01:28:37 +0000 (21:28 -0400)
committerKent Overstreet <kent.overstreet@linux.dev>
Sun, 22 Oct 2023 21:09:03 +0000 (17:09 -0400)
bch2_check_fix_ptrs() is awkward, we need to find a way to improve it.

Signed-off-by: Kent Overstreet <kent.overstreet@gmail.com>
Signed-off-by: Kent Overstreet <kent.overstreet@linux.dev>
fs/bcachefs/btree_gc.c
fs/bcachefs/extents.h

index bd4dd1d67a1d84b23ffdf8d4af64357ccddbef5d..5b839cca8a9d6f7a27dec89caf76585892b82ce2 100644 (file)
@@ -427,18 +427,38 @@ static int bch2_check_fix_ptrs(struct bch_fs *c, enum btree_id btree_id,
        const union bch_extent_entry *entry;
        struct extent_ptr_decoded p = { 0 };
        bool do_update = false;
+       char buf[200];
        int ret = 0;
 
        bkey_for_each_ptr_decode(k->k, ptrs, p, entry) {
                struct bch_dev *ca = bch_dev_bkey_exists(c, p.ptr.dev);
                struct bucket *g = PTR_BUCKET(ca, &p.ptr, true);
                struct bucket *g2 = PTR_BUCKET(ca, &p.ptr, false);
+               enum bch_data_type data_type = bch2_bkey_ptr_data_type(*k, &entry->ptr);
+
+               if (fsck_err_on(g->mark.data_type &&
+                               g->mark.data_type != data_type, c,
+                               "bucket %u:%zu different types of data in same bucket: %s, %s\n"
+                               "while marking %s",
+                               p.ptr.dev, PTR_BUCKET_NR(ca, &p.ptr),
+                               bch2_data_types[g->mark.data_type],
+                               bch2_data_types[data_type],
+                               (bch2_bkey_val_to_text(&PBUF(buf), c, *k), buf))) {
+                       if (data_type == BCH_DATA_btree) {
+                               g2->_mark.data_type = g->_mark.data_type = data_type;
+                               set_bit(BCH_FS_NEED_ALLOC_WRITE, &c->flags);
+                       } else {
+                               do_update = true;
+                       }
+               }
 
                if (fsck_err_on(!g->gen_valid, c,
-                               "bucket %u:%zu data type %s ptr gen %u missing in alloc btree",
+                               "bucket %u:%zu data type %s ptr gen %u missing in alloc btree\n"
+                               "while marking %s",
                                p.ptr.dev, PTR_BUCKET_NR(ca, &p.ptr),
                                bch2_data_types[ptr_data_type(k->k, &p.ptr)],
-                               p.ptr.gen)) {
+                               p.ptr.gen,
+                               (bch2_bkey_val_to_text(&PBUF(buf), c, *k), buf))) {
                        if (!p.ptr.cached) {
                                g2->_mark.gen   = g->_mark.gen          = p.ptr.gen;
                                g2->gen_valid   = g->gen_valid          = true;
@@ -449,10 +469,12 @@ static int bch2_check_fix_ptrs(struct bch_fs *c, enum btree_id btree_id,
                }
 
                if (fsck_err_on(gen_cmp(p.ptr.gen, g->mark.gen) > 0, c,
-                               "bucket %u:%zu data type %s ptr gen in the future: %u > %u",
+                               "bucket %u:%zu data type %s ptr gen in the future: %u > %u\n"
+                               "while marking %s",
                                p.ptr.dev, PTR_BUCKET_NR(ca, &p.ptr),
                                bch2_data_types[ptr_data_type(k->k, &p.ptr)],
-                               p.ptr.gen, g->mark.gen)) {
+                               p.ptr.gen, g->mark.gen,
+                               (bch2_bkey_val_to_text(&PBUF(buf), c, *k), buf))) {
                        if (!p.ptr.cached) {
                                g2->_mark.gen   = g->_mark.gen  = p.ptr.gen;
                                g2->gen_valid   = g->gen_valid  = true;
@@ -468,23 +490,29 @@ static int bch2_check_fix_ptrs(struct bch_fs *c, enum btree_id btree_id,
 
                if (fsck_err_on(!p.ptr.cached &&
                                gen_cmp(p.ptr.gen, g->mark.gen) < 0, c,
-                               "bucket %u:%zu data type %s stale dirty ptr: %u < %u",
+                               "bucket %u:%zu data type %s stale dirty ptr: %u < %u\n"
+                               "while marking %s",
                                p.ptr.dev, PTR_BUCKET_NR(ca, &p.ptr),
                                bch2_data_types[ptr_data_type(k->k, &p.ptr)],
-                               p.ptr.gen, g->mark.gen))
+                               p.ptr.gen, g->mark.gen,
+                               (bch2_bkey_val_to_text(&PBUF(buf), c, *k), buf)))
                        do_update = true;
 
                if (p.has_ec) {
                        struct stripe *m = genradix_ptr(&c->stripes[true], p.ec.idx);
 
                        if (fsck_err_on(!m || !m->alive, c,
-                                       "pointer to nonexistent stripe %llu",
-                                       (u64) p.ec.idx))
+                                       "pointer to nonexistent stripe %llu\n"
+                                       "while marking %s",
+                                       (u64) p.ec.idx,
+                                       (bch2_bkey_val_to_text(&PBUF(buf), c, *k), buf)))
                                do_update = true;
 
                        if (fsck_err_on(!bch2_ptr_matches_stripe_m(m, p), c,
-                                       "pointer does not match stripe %llu",
-                                       (u64) p.ec.idx))
+                                       "pointer does not match stripe %llu\n"
+                                       "while marking %s",
+                                       (u64) p.ec.idx,
+                                       (bch2_bkey_val_to_text(&PBUF(buf), c, *k), buf)))
                                do_update = true;
                }
        }
@@ -525,11 +553,14 @@ static int bch2_check_fix_ptrs(struct bch_fs *c, enum btree_id btree_id,
                        bch2_bkey_drop_ptrs(bkey_i_to_s(new), ptr, ({
                                struct bch_dev *ca = bch_dev_bkey_exists(c, ptr->dev);
                                struct bucket *g = PTR_BUCKET(ca, ptr, true);
+                               enum bch_data_type data_type = bch2_bkey_ptr_data_type(*k, ptr);
 
                                (ptr->cached &&
                                 (!g->gen_valid || gen_cmp(ptr->gen, g->mark.gen) > 0)) ||
                                (!ptr->cached &&
-                                gen_cmp(ptr->gen, g->mark.gen) < 0);
+                                gen_cmp(ptr->gen, g->mark.gen) < 0) ||
+                               (g->mark.data_type &&
+                                g->mark.data_type != data_type);
                        }));
 again:
                        ptrs = bch2_bkey_ptrs(bkey_i_to_s(new));
index ccee43a2019da10ca572faf6c6cf4463bc7930e5..9999805f955ebfff87cf066aff9457c976d9c3db 100644 (file)
@@ -529,6 +529,30 @@ static inline struct bch_devs_list bch2_bkey_cached_devs(struct bkey_s_c k)
        return ret;
 }
 
+static inline unsigned bch2_bkey_ptr_data_type(struct bkey_s_c k, const struct bch_extent_ptr *ptr)
+{
+       switch (k.k->type) {
+       case KEY_TYPE_btree_ptr:
+       case KEY_TYPE_btree_ptr_v2:
+               return BCH_DATA_btree;
+       case KEY_TYPE_extent:
+       case KEY_TYPE_reflink_v:
+               return BCH_DATA_user;
+       case KEY_TYPE_stripe: {
+               struct bkey_s_c_stripe s = bkey_s_c_to_stripe(k);
+
+               BUG_ON(ptr < s.v->ptrs ||
+                      ptr >= s.v->ptrs + s.v->nr_blocks);
+
+               return ptr >= s.v->ptrs + s.v->nr_blocks - s.v->nr_redundant
+                       ? BCH_DATA_parity
+                       : BCH_DATA_user;
+       }
+       default:
+               BUG();
+       }
+}
+
 unsigned bch2_bkey_nr_ptrs(struct bkey_s_c);
 unsigned bch2_bkey_nr_ptrs_allocated(struct bkey_s_c);
 unsigned bch2_bkey_nr_ptrs_fully_allocated(struct bkey_s_c);