]> git.proxmox.com Git - mirror_ubuntu-kernels.git/commitdiff
bcachefs: Don't modify existing key in place in sort_repack_merge()
authorKent Overstreet <kent.overstreet@gmail.com>
Thu, 16 Jan 2020 21:14:56 +0000 (16:14 -0500)
committerKent Overstreet <kent.overstreet@linux.dev>
Sun, 22 Oct 2023 21:08:34 +0000 (17:08 -0400)
This fixes a nasty memory corruption with other threads that are still
reading the btree node being compacted.

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

index 1c8e5a80e32a215321d70bfe446c70e0e90c8635..7cbb57042af10de4cf8fc0241e77d1bcdda4b06b 100644 (file)
@@ -210,28 +210,38 @@ bch2_sort_repack_merge(struct bch_fs *c,
                       bool filter_whiteouts)
 {
        struct bkey_packed *prev = NULL, *k_packed;
-       struct bkey_s k;
+       struct bkey_on_stack k;
        struct btree_nr_keys nr;
-       struct bkey unpacked;
 
        memset(&nr, 0, sizeof(nr));
+       bkey_on_stack_init(&k);
 
        while ((k_packed = bch2_btree_node_iter_next_all(iter, src))) {
                if (filter_whiteouts && bkey_whiteout(k_packed))
                        continue;
 
-               k = __bkey_disassemble(src, k_packed, &unpacked);
+               /*
+                * NOTE:
+                * bch2_bkey_normalize may modify the key we pass it (dropping
+                * stale pointers) and we don't have a write lock on the src
+                * node; we have to make a copy of the entire key before calling
+                * normalize
+                */
+               bkey_on_stack_realloc(&k, c, k_packed->u64s + BKEY_U64s);
+               bch2_bkey_unpack(src, k.k, k_packed);
 
                if (filter_whiteouts &&
-                   bch2_bkey_normalize(c, k))
+                   bch2_bkey_normalize(c, bkey_i_to_s(k.k)))
                        continue;
 
-               extent_sort_append(c, out_f, &nr, vstruct_last(dst), &prev, k);
+               extent_sort_append(c, out_f, &nr, vstruct_last(dst),
+                                  &prev, bkey_i_to_s(k.k));
        }
 
        extent_sort_advance_prev(out_f, &nr, vstruct_last(dst), &prev);
 
        dst->u64s = cpu_to_le16((u64 *) prev - dst->_data);
+       bkey_on_stack_exit(&k, c);
        return nr;
 }