bcachefs: Don't corrupt journal keys gap buffer when dropping alloc info
authorKent Overstreet <kent.overstreet@linux.dev>
Sun, 17 Mar 2024 01:22:47 +0000 (21:22 -0400)
committerKent Overstreet <kent.overstreet@linux.dev>
Mon, 18 Mar 2024 01:17:38 +0000 (21:17 -0400)
Signed-off-by: Kent Overstreet <kent.overstreet@linux.dev>
fs/bcachefs/btree_io.c
fs/bcachefs/recovery.c
fs/bcachefs/util.h

index 624c8287deb43191d39b130c842875f7aa1a9ff1..44856f018adf6394e041c840d860645c22921993 100644 (file)
@@ -1338,7 +1338,7 @@ start:
        if (saw_error && !btree_node_read_error(b)) {
                printbuf_reset(&buf);
                bch2_bpos_to_text(&buf, b->key.k.p);
-               bch_info(c, "%s: rewriting btree node at btree=%s level=%u %s due to error",
+               bch_err_ratelimited(c, "%s: rewriting btree node at btree=%s level=%u %s due to error",
                         __func__, bch2_btree_id_str(b->c.btree_id), b->c.level, buf.buf);
 
                bch2_btree_node_rewrite_async(c, b);
index 2af219aedfdbefb36d37fe19423d8e26cabf0cdd..03f9d6afe467889b02a483561277b0d539a836f5 100644 (file)
@@ -90,10 +90,12 @@ static void do_reconstruct_alloc(struct bch_fs *c)
        struct journal_keys *keys = &c->journal_keys;
        size_t src, dst;
 
+       move_gap(keys, keys->nr);
+
        for (src = 0, dst = 0; src < keys->nr; src++)
                if (!btree_id_is_alloc(keys->data[src].btree_id))
                        keys->data[dst++] = keys->data[src];
-       keys->nr = dst;
+       keys->nr = keys->gap = dst;
 }
 
 /*
@@ -203,6 +205,8 @@ static int bch2_journal_replay(struct bch_fs *c)
 
        BUG_ON(!atomic_read(&keys->ref));
 
+       move_gap(keys, keys->nr);
+
        /*
         * First, attempt to replay keys in sorted order. This is more
         * efficient - better locality of btree access -  but some might fail if
index 7ffbddb80400d7aed4bc1479c79cae32427e2595..175aee3074c7d539d40e7ec3ffc072a0e3d2d388 100644 (file)
@@ -683,6 +683,9 @@ static inline void __move_gap(void *array, size_t element_size,
 /* Move the gap in a gap buffer: */
 #define move_gap(_d, _new_gap)                                         \
 do {                                                                   \
+       BUG_ON(_new_gap > (_d)->nr);                                    \
+       BUG_ON((_d)->gap > (_d)->nr);                                   \
+                                                                       \
        __move_gap((_d)->data, sizeof((_d)->data[0]),                   \
                   (_d)->nr, (_d)->size, (_d)->gap, _new_gap);          \
        (_d)->gap = _new_gap;                                           \