block: add a bdev_rw_virt helper
authorChristoph Hellwig <hch@lst.de>
Wed, 7 May 2025 12:04:26 +0000 (14:04 +0200)
committerJens Axboe <axboe@kernel.dk>
Wed, 7 May 2025 13:31:07 +0000 (07:31 -0600)
Add a helper to perform synchronous I/O on a kernel direct map range.
Currently this is implemented in various places in usually not very
efficient ways, so provide a generic helper instead.

Signed-off-by: Christoph Hellwig <hch@lst.de>
Reviewed-by: Damien Le Moal <dlemoal@kernel.org>
Reviewed-by: Hannes Reinecke <hare@suse.de>
Reviewed-by: Johannes Thumshirn <johannes.thumshirn@wdc.com>
Link: https://lore.kernel.org/r/20250507120451.4000627-3-hch@lst.de
Signed-off-by: Jens Axboe <axboe@kernel.dk>
block/bio.c
include/linux/bio.h

index bd3d048d0a728683e4c1c29385f07a4c48d9be5b..26782ff85dbf61a660a5b6ddd2841c26e1e7dc71 100644 (file)
@@ -1319,6 +1319,36 @@ int submit_bio_wait(struct bio *bio)
 }
 EXPORT_SYMBOL(submit_bio_wait);
 
+/**
+ * bdev_rw_virt - synchronously read into / write from kernel mapping
+ * @bdev:      block device to access
+ * @sector:    sector to access
+ * @data:      data to read/write
+ * @len:       length in byte to read/write
+ * @op:                operation (e.g. REQ_OP_READ/REQ_OP_WRITE)
+ *
+ * Performs synchronous I/O to @bdev for @data/@len.  @data must be in
+ * the kernel direct mapping and not a vmalloc address.
+ */
+int bdev_rw_virt(struct block_device *bdev, sector_t sector, void *data,
+               size_t len, enum req_op op)
+{
+       struct bio_vec bv;
+       struct bio bio;
+       int error;
+
+       if (WARN_ON_ONCE(is_vmalloc_addr(data)))
+               return -EIO;
+
+       bio_init(&bio, bdev, &bv, 1, op);
+       bio.bi_iter.bi_sector = sector;
+       bio_add_virt_nofail(&bio, data, len);
+       error = submit_bio_wait(&bio);
+       bio_uninit(&bio);
+       return error;
+}
+EXPORT_SYMBOL_GPL(bdev_rw_virt);
+
 static void bio_wait_end_io(struct bio *bio)
 {
        complete(bio->bi_private);
index acca7464080c215a80e75b355ceedf89c461ae16..ad54e6af20dcf7336ca91a2b0e40a877444de5d6 100644 (file)
@@ -402,7 +402,6 @@ static inline int bio_iov_vecs_to_alloc(struct iov_iter *iter, int max_segs)
 
 struct request_queue;
 
-extern int submit_bio_wait(struct bio *bio);
 void bio_init(struct bio *bio, struct block_device *bdev, struct bio_vec *table,
              unsigned short max_vecs, blk_opf_t opf);
 extern void bio_uninit(struct bio *);
@@ -419,6 +418,10 @@ void bio_add_folio_nofail(struct bio *bio, struct folio *folio, size_t len,
                          size_t off);
 void bio_add_virt_nofail(struct bio *bio, void *vaddr, unsigned len);
 
+int submit_bio_wait(struct bio *bio);
+int bdev_rw_virt(struct block_device *bdev, sector_t sector, void *data,
+               size_t len, enum req_op op);
+
 int bio_iov_iter_get_pages(struct bio *bio, struct iov_iter *iter);
 void bio_iov_bvec_set(struct bio *bio, const struct iov_iter *iter);
 void __bio_release_pages(struct bio *bio, bool mark_dirty);