]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
block: factor out a bio_await helper
authorChristoph Hellwig <hch@lst.de>
Tue, 7 Apr 2026 14:05:26 +0000 (16:05 +0200)
committerJens Axboe <axboe@kernel.dk>
Tue, 7 Apr 2026 14:22:24 +0000 (08:22 -0600)
Add a new helper to wait for a bio and anything chained off it to
complete synchronously after submitting it.  This factors common code out
of submit_bio_wait and bio_await_chain and will also be useful for
file system code and thus is exported.

Note that this will now set REQ_SYNC also for the bio_await case for
consistency.  Nothing should look at the flag in the end_io handler,
but if something does having the flag set makes more sense.

Signed-off-by: Christoph Hellwig <hch@lst.de>
Reviewed-by: Damien Le Moal <dlemoal@kernel.org>
Link: https://patch.msgid.link/20260407140538.633364-4-hch@lst.de
Signed-off-by: Jens Axboe <axboe@kernel.dk>
block/bio.c
include/linux/bio.h

index 434e41182c050a0b0cc147cb4d3f76c8908d0d6c..61d65c544bcca16b46470088f8a7aefc3ef056c4 100644 (file)
@@ -1468,17 +1468,20 @@ static void bio_wait_end_io(struct bio *bio)
 }
 
 /**
- * submit_bio_wait - submit a bio, and wait until it completes
- * @bio: The &struct bio which describes the I/O
+ * bio_await - call a function on a bio, and wait until it completes
+ * @bio:       the bio which describes the I/O
+ * @submit:    function called to submit the bio
+ * @priv:      private data passed to @submit
  *
- * Simple wrapper around submit_bio(). Returns 0 on success, or the error from
- * bio_endio() on failure.
+ * Wait for the bio as well as any bio chained off it after executing the
+ * passed in callback @submit.  The wait for the bio is set up before calling
+ * @submit to ensure that the completion is captured.  If @submit is %NULL,
+ * submit_bio() is used instead to submit the bio.
  *
- * WARNING: Unlike to how submit_bio() is usually used, this function does not
- * result in bio reference to be consumed. The caller must drop the reference
- * on his own.
+ * Note: this overrides the bi_private and bi_end_io fields in the bio.
  */
-int submit_bio_wait(struct bio *bio)
+void bio_await(struct bio *bio, void *priv,
+              void (*submit)(struct bio *bio, void *priv))
 {
        DECLARE_COMPLETION_ONSTACK_MAP(done,
                        bio->bi_bdev->bd_disk->lockdep_map);
@@ -1486,13 +1489,37 @@ int submit_bio_wait(struct bio *bio)
        bio->bi_private = &done;
        bio->bi_end_io = bio_wait_end_io;
        bio->bi_opf |= REQ_SYNC;
-       submit_bio(bio);
+       if (submit)
+               submit(bio, priv);
+       else
+               submit_bio(bio);
        blk_wait_io(&done);
+}
+EXPORT_SYMBOL_GPL(bio_await);
 
+/**
+ * submit_bio_wait - submit a bio, and wait until it completes
+ * @bio: The &struct bio which describes the I/O
+ *
+ * Simple wrapper around submit_bio(). Returns 0 on success, or the error from
+ * bio_endio() on failure.
+ *
+ * WARNING: Unlike to how submit_bio() is usually used, this function does not
+ * result in bio reference to be consumed. The caller must drop the reference
+ * on his own.
+ */
+int submit_bio_wait(struct bio *bio)
+{
+       bio_await(bio, NULL, NULL);
        return blk_status_to_errno(bio->bi_status);
 }
 EXPORT_SYMBOL(submit_bio_wait);
 
+static void bio_endio_cb(struct bio *bio, void *priv)
+{
+       bio_endio(bio);
+}
+
 /**
  * bdev_rw_virt - synchronously read into / write from kernel mapping
  * @bdev:      block device to access
@@ -1528,13 +1555,7 @@ EXPORT_SYMBOL_GPL(bdev_rw_virt);
  */
 void bio_await_chain(struct bio *bio)
 {
-       DECLARE_COMPLETION_ONSTACK_MAP(done,
-                       bio->bi_bdev->bd_disk->lockdep_map);
-
-       bio->bi_private = &done;
-       bio->bi_end_io = bio_wait_end_io;
-       bio_endio(bio);
-       blk_wait_io(&done);
+       bio_await(bio, NULL, bio_endio_cb);
        bio_put(bio);
 }
 
index 984844d2870b740b022b6b95cea4896995e678a8..97d747320b35bc34197d026a53b611bf0c170530 100644 (file)
@@ -432,6 +432,8 @@ extern void bio_uninit(struct bio *);
 void bio_reset(struct bio *bio, struct block_device *bdev, blk_opf_t opf);
 void bio_reuse(struct bio *bio, blk_opf_t opf);
 void bio_chain(struct bio *, struct bio *);
+void bio_await(struct bio *bio, void *priv,
+              void (*submit)(struct bio *bio, void *priv));
 
 int __must_check bio_add_page(struct bio *bio, struct page *page, unsigned len,
                              unsigned off);