bcachefs: Fix another iterator leak
authorKent Overstreet <kent.overstreet@gmail.com>
Mon, 16 Mar 2020 19:48:58 +0000 (15:48 -0400)
committerKent Overstreet <kent.overstreet@linux.dev>
Sun, 22 Oct 2023 21:08:36 +0000 (17:08 -0400)
This updates bch2_rbio_narrow_crcs() to the current style for
transactional btree code, and fixes a rare panic on iterator overflow.

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

index 717332072d875138a48f539877f86cfe3e017b85..2ec7203e582487d1ea9291878cee6773267dd6d6 100644 (file)
@@ -1701,33 +1701,39 @@ static void bch2_rbio_error(struct bch_read_bio *rbio, int retry,
        }
 }
 
-static void bch2_rbio_narrow_crcs(struct bch_read_bio *rbio)
+static int __bch2_rbio_narrow_crcs(struct btree_trans *trans,
+                                  struct bch_read_bio *rbio)
 {
        struct bch_fs *c = rbio->c;
-       struct btree_trans trans;
-       struct btree_iter *iter;
-       struct bkey_s_c k;
-       struct bkey_on_stack new;
-       struct bch_extent_crc_unpacked new_crc;
        u64 data_offset = rbio->pos.offset - rbio->pick.crc.offset;
-       int ret;
+       struct bch_extent_crc_unpacked new_crc;
+       struct btree_iter *iter = NULL;
+       struct bkey_i *new;
+       struct bkey_s_c k;
+       int ret = 0;
 
        if (crc_is_compressed(rbio->pick.crc))
-               return;
-
-       bkey_on_stack_init(&new);
-       bch2_trans_init(&trans, c, 0, 0);
-retry:
-       bch2_trans_begin(&trans);
+               return 0;
 
-       iter = bch2_trans_get_iter(&trans, BTREE_ID_EXTENTS, rbio->pos,
+       iter = bch2_trans_get_iter(trans, BTREE_ID_EXTENTS, rbio->pos,
                                   BTREE_ITER_SLOTS|BTREE_ITER_INTENT);
+       if ((ret = PTR_ERR_OR_ZERO(iter)))
+               goto out;
+
        k = bch2_btree_iter_peek_slot(iter);
-       if (IS_ERR_OR_NULL(k.k))
+       if ((ret = bkey_err(k)))
+               goto out;
+
+       /*
+        * going to be temporarily appending another checksum entry:
+        */
+       new = bch2_trans_kmalloc(trans, bkey_bytes(k.k) +
+                                BKEY_EXTENT_U64s_MAX * 8);
+       if ((ret = PTR_ERR_OR_ZERO(new)))
                goto out;
 
-       bkey_on_stack_reassemble(&new, c, k);
-       k = bkey_i_to_s_c(new.k);
+       bkey_reassemble(new, k);
+       k = bkey_i_to_s_c(new);
 
        if (bversion_cmp(k.k->version, rbio->version) ||
            !bch2_bkey_matches_ptr(c, k, rbio->pick.ptr, data_offset))
@@ -1743,21 +1749,23 @@ retry:
                        bkey_start_offset(k.k) - data_offset, k.k->size,
                        rbio->pick.crc.csum_type)) {
                bch_err(c, "error verifying existing checksum while narrowing checksum (memory corruption?)");
+               ret = 0;
                goto out;
        }
 
-       if (!bch2_bkey_narrow_crcs(new.k, new_crc))
+       if (!bch2_bkey_narrow_crcs(new, new_crc))
                goto out;
 
-       bch2_trans_update(&trans, iter, new.k, 0);
-       ret = bch2_trans_commit(&trans, NULL, NULL,
-                               BTREE_INSERT_NOFAIL|
-                               BTREE_INSERT_NOWAIT);
-       if (ret == -EINTR)
-               goto retry;
+       bch2_trans_update(trans, iter, new, 0);
 out:
-       bch2_trans_exit(&trans);
-       bkey_on_stack_exit(&new, c);
+       bch2_trans_iter_put(trans, iter);
+       return ret;
+}
+
+static noinline void bch2_rbio_narrow_crcs(struct bch_read_bio *rbio)
+{
+       bch2_trans_do(rbio->c, NULL, NULL, BTREE_INSERT_NOFAIL,
+                     __bch2_rbio_narrow_crcs(&trans, rbio));
 }
 
 /* Inner part that may run in process context */