bcachefs: Fix a race with b->write_type
authorKent Overstreet <kent.overstreet@linux.dev>
Thu, 17 Nov 2022 21:03:15 +0000 (16:03 -0500)
committerKent Overstreet <kent.overstreet@linux.dev>
Sun, 22 Oct 2023 21:09:46 +0000 (17:09 -0400)
b->write_type needs to be set atomically with setting the
btree_node_need_write flag, so move it into b->flags.

Signed-off-by: Kent Overstreet <kent.overstreet@linux.dev>
fs/bcachefs/bcachefs.h
fs/bcachefs/btree_cache.c
fs/bcachefs/btree_io.c
fs/bcachefs/btree_types.h
fs/bcachefs/btree_update_interior.c
fs/bcachefs/btree_update_leaf.c

index c8ab0e2029dfc838d913ddf70e581d3867a4c13a..e61dc1e6da06b04ad1282f6d7e62f8d62ae2353d 100644 (file)
@@ -627,23 +627,6 @@ typedef struct {
 #define BCACHEFS_ROOT_SUBVOL_INUM                                      \
        ((subvol_inum) { BCACHEFS_ROOT_SUBVOL,  BCACHEFS_ROOT_INO })
 
-#define BCH_BTREE_WRITE_TYPES()                                                \
-       x(initial,              0)                                      \
-       x(init_next_bset,       1)                                      \
-       x(cache_reclaim,        2)                                      \
-       x(journal_reclaim,      3)                                      \
-       x(interior,             4)
-
-enum btree_write_type {
-#define x(t, n) BTREE_WRITE_##t,
-       BCH_BTREE_WRITE_TYPES()
-#undef x
-       BTREE_WRITE_TYPE_NR,
-};
-
-#define BTREE_WRITE_TYPE_MASK  (roundup_pow_of_two(BTREE_WRITE_TYPE_NR) - 1)
-#define BTREE_WRITE_TYPE_BITS  ilog2(BTREE_WRITE_TYPE_MASK)
-
 struct bch_fs {
        struct closure          cl;
 
index 5adfdc5afbea846b6e609cf5bb75ee6e734bf866..c9d287f38d6307ee47a2b824da46853b9551ee3f 100644 (file)
@@ -631,7 +631,6 @@ out:
        b->flags                = 0;
        b->written              = 0;
        b->nsets                = 0;
-       b->write_type           = 0;
        b->sib_u64s[0]          = 0;
        b->sib_u64s[1]          = 0;
        b->whiteout_u64s        = 0;
index 5d750f4472416b6c70ec36ee74efe9ca8278ab61..8dbe930c1eb249d2e9717a1bcad390aedc135335 100644 (file)
@@ -1636,6 +1636,7 @@ static void __btree_node_write_done(struct bch_fs *c, struct btree *b)
 {
        struct btree_write *w = btree_prev_write(b);
        unsigned long old, new, v;
+       unsigned type = 0;
 
        bch2_btree_complete_write(c, b, w);
 
@@ -1654,6 +1655,9 @@ static void __btree_node_write_done(struct bch_fs *c, struct btree *b)
                        new |=  (1U << BTREE_NODE_write_in_flight_inner);
                        new |=  (1U << BTREE_NODE_just_written);
                        new ^=  (1U << BTREE_NODE_write_idx);
+
+                       type = new & BTREE_WRITE_TYPE_MASK;
+                       new &= ~BTREE_WRITE_TYPE_MASK;
                } else {
                        new &= ~(1U << BTREE_NODE_write_in_flight);
                        new &= ~(1U << BTREE_NODE_write_in_flight_inner);
@@ -1661,7 +1665,7 @@ static void __btree_node_write_done(struct bch_fs *c, struct btree *b)
        } while ((v = cmpxchg(&b->flags, old, new)) != old);
 
        if (new & (1U << BTREE_NODE_write_in_flight))
-               __bch2_btree_node_write(c, b, BTREE_WRITE_ALREADY_STARTED|b->write_type);
+               __bch2_btree_node_write(c, b, BTREE_WRITE_ALREADY_STARTED|type);
        else
                wake_up_bit(&b->flags, BTREE_NODE_write_in_flight);
 }
@@ -1846,6 +1850,10 @@ void __bch2_btree_node_write(struct bch_fs *c, struct btree *b, unsigned flags)
                if (old & (1 << BTREE_NODE_write_in_flight))
                        return;
 
+               if (flags & BTREE_WRITE_ONLY_IF_NEED)
+                       type = new & BTREE_WRITE_TYPE_MASK;
+               new &= ~BTREE_WRITE_TYPE_MASK;
+
                new &= ~(1 << BTREE_NODE_dirty);
                new &= ~(1 << BTREE_NODE_need_write);
                new |=  (1 << BTREE_NODE_write_in_flight);
@@ -1857,10 +1865,6 @@ void __bch2_btree_node_write(struct bch_fs *c, struct btree *b, unsigned flags)
        if (new & (1U << BTREE_NODE_need_write))
                return;
 do_write:
-       if ((flags & BTREE_WRITE_ONLY_IF_NEED))
-               type = b->write_type;
-       b->write_type = 0;
-
        BUG_ON((type == BTREE_WRITE_initial) != (b->written == 0));
 
        atomic_dec(&c->btree_cache.dirty);
index 38c4754dbd7e0a2d5dff6439790730016f13dd96..72e6a214b89a84a1352f8f06a47dc4ba90bec16b 100644 (file)
@@ -77,7 +77,6 @@ struct btree {
        u8                      nsets;
        u8                      nr_key_bits;
        u16                     version_ondisk;
-       u8                      write_type;
 
        struct bkey_format      format;
 
@@ -445,6 +444,23 @@ struct btree_trans {
        struct replicas_delta_list *fs_usage_deltas;
 };
 
+#define BCH_BTREE_WRITE_TYPES()                                                \
+       x(initial,              0)                                      \
+       x(init_next_bset,       1)                                      \
+       x(cache_reclaim,        2)                                      \
+       x(journal_reclaim,      3)                                      \
+       x(interior,             4)
+
+enum btree_write_type {
+#define x(t, n) BTREE_WRITE_##t,
+       BCH_BTREE_WRITE_TYPES()
+#undef x
+       BTREE_WRITE_TYPE_NR,
+};
+
+#define BTREE_WRITE_TYPE_MASK  (roundup_pow_of_two(BTREE_WRITE_TYPE_NR) - 1)
+#define BTREE_WRITE_TYPE_BITS  ilog2(roundup_pow_of_two(BTREE_WRITE_TYPE_NR))
+
 #define BTREE_FLAGS()                                                  \
        x(read_in_flight)                                               \
        x(read_error)                                                   \
@@ -464,6 +480,8 @@ struct btree_trans {
        x(never_write)
 
 enum btree_flags {
+       /* First bits for btree node write type */
+       BTREE_NODE_FLAGS_START = BTREE_WRITE_TYPE_BITS - 1,
 #define x(flag)        BTREE_NODE_##flag,
        BTREE_FLAGS()
 #undef x
index ac3a5ef1b1af2ada963464080cf9fa43fcb2c295..03e016758af3b2516ac4509af1f34b2e9ef9e83f 100644 (file)
@@ -1257,6 +1257,7 @@ static void bch2_insert_fixup_btree_ptr(struct btree_update *as,
        struct bch_fs *c = as->c;
        struct bkey_packed *k;
        struct printbuf buf = PRINTBUF;
+       unsigned long old, new, v;
 
        BUG_ON(insert->k.type == KEY_TYPE_btree_ptr_v2 &&
               !btree_ptr_sectors_written(insert));
@@ -1294,8 +1295,15 @@ static void bch2_insert_fixup_btree_ptr(struct btree_update *as,
 
        bch2_btree_bset_insert_key(trans, path, b, node_iter, insert);
        set_btree_node_dirty_acct(c, b);
-       set_btree_node_need_write(b);
-       b->write_type = BTREE_WRITE_interior;
+
+       v = READ_ONCE(b->flags);
+       do {
+               old = new = v;
+
+               new &= ~BTREE_WRITE_TYPE_MASK;
+               new |= BTREE_WRITE_interior;
+               new |= 1 << BTREE_NODE_need_write;
+       } while ((v = cmpxchg(&b->flags, old, new)) != old);
 
        printbuf_exit(&buf);
 }
index 1405ad4eda02acab914c007e1b395a22f4fd7cf1..445f8f57ef0ce0be856d339fe6e79a83847b9975 100644 (file)
@@ -178,11 +178,11 @@ static int __btree_node_flush(struct journal *j, struct journal_entry_pin *pin,
                    w->journal.seq != seq)
                        break;
 
+               new &= ~BTREE_WRITE_TYPE_MASK;
+               new |= BTREE_WRITE_journal_reclaim;
                new |= 1 << BTREE_NODE_need_write;
        } while ((v = cmpxchg(&b->flags, old, new)) != old);
 
-       b->write_type = BTREE_WRITE_journal_reclaim;
-
        btree_node_write_if_need(c, b, SIX_LOCK_read);
        six_unlock_read(&b->c.lock);