bcachefs: Nocow write error path fix
authorKent Overstreet <kent.overstreet@linux.dev>
Sun, 19 Mar 2023 16:50:05 +0000 (12:50 -0400)
committerKent Overstreet <kent.overstreet@linux.dev>
Sun, 22 Oct 2023 21:09:58 +0000 (17:09 -0400)
The nocow write error path was iterating over pointers in an extent,
aftre we'd dropped btree locks - oops.

Fortunately we'd already stashed what we need in nocow_lock_bucket, so
use that instead.

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

index 0c2d42eaba56edb80517c7a77fda24cdf006b919..ad22557197a666b3f648d7e4c3e6f532855a0111 100644 (file)
@@ -1481,7 +1481,7 @@ static void bch2_nocow_write(struct bch_write_op *op)
        struct btree_iter iter;
        struct bkey_s_c k;
        struct bkey_ptrs_c ptrs;
-       const struct bch_extent_ptr *ptr, *ptr2;
+       const struct bch_extent_ptr *ptr;
        struct {
                struct bpos     b;
                unsigned        gen;
@@ -1536,11 +1536,12 @@ retry:
                                                  bucket_to_u64(buckets[nr_buckets].b));
 
                        prefetch(buckets[nr_buckets].l);
-                       nr_buckets++;
 
                        if (unlikely(!bch2_dev_get_ioref(bch_dev_bkey_exists(c, ptr->dev), WRITE)))
                                goto err_get_ioref;
 
+                       nr_buckets++;
+
                        if (ptr->unwritten)
                                op->flags |= BCH_WRITE_CONVERT_UNWRITTEN;
                }
@@ -1631,12 +1632,8 @@ err:
        }
        return;
 err_get_ioref:
-       bkey_for_each_ptr(ptrs, ptr2) {
-               if (ptr2 == ptr)
-                       break;
-
-               percpu_ref_put(&bch_dev_bkey_exists(c, ptr2->dev)->io_ref);
-       }
+       for (i = 0; i < nr_buckets; i++)
+               percpu_ref_put(&bch_dev_bkey_exists(c, buckets[i].b.inode)->io_ref);
 
        /* Fall back to COW path: */
        goto out;
@@ -1645,9 +1642,8 @@ err_bucket_stale:
                bch2_bucket_nocow_unlock(&c->nocow_locks,
                                         buckets[i].b,
                                         BUCKET_NOCOW_LOCK_UPDATE);
-
-       bkey_for_each_ptr(ptrs, ptr2)
-               percpu_ref_put(&bch_dev_bkey_exists(c, ptr2->dev)->io_ref);
+       for (i = 0; i < nr_buckets; i++)
+               percpu_ref_put(&bch_dev_bkey_exists(c, buckets[i].b.inode)->io_ref);
 
        /* We can retry this: */
        ret = BCH_ERR_transaction_restart;