diff mbox series

[02/17] block: add a bdev_rw_virt helper

Message ID 20250422142628.1553523-3-hch@lst.de
State New
Headers show
Series [01/17] block: add a bio_add_virt_nofail helper | expand

Commit Message

Christoph Hellwig April 22, 2025, 2:26 p.m. UTC
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>
---
 block/bio.c         | 30 ++++++++++++++++++++++++++++++
 include/linux/bio.h |  5 ++++-
 2 files changed, 34 insertions(+), 1 deletion(-)

Comments

Hannes Reinecke April 23, 2025, 6:07 a.m. UTC | #1
On 4/22/25 16:26, Christoph Hellwig wrote:
> 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>
> ---
>   block/bio.c         | 30 ++++++++++++++++++++++++++++++
>   include/linux/bio.h |  5 ++++-
>   2 files changed, 34 insertions(+), 1 deletion(-)
> 
> diff --git a/block/bio.c b/block/bio.c
> index 4e6c85a33d74..a6a867a432cf 100644
> --- a/block/bio.c
> +++ b/block/bio.c
> @@ -1301,6 +1301,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 accasse
> + * @data:	data to read/write
> + * @len:	length 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);
> diff --git a/include/linux/bio.h b/include/linux/bio.h
> index 0678b67162ee..17a10220c57d 100644
> --- a/include/linux/bio.h
> +++ b/include/linux/bio.h
> @@ -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 *);
> @@ -434,6 +433,10 @@ static inline void bio_add_virt_nofail(struct bio *bio, void *vaddr,
>   	__bio_add_page(bio, virt_to_page(vaddr), len, offset_in_page(vaddr));
>   }
>   
> +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);

Any specific reason why the declaration of 'submit_bio_wait()' is moved?

Other than that:

Reviewed-by: Hannes Reinecke <hare@suse.de>

Cheers,

Hannes
Christoph Hellwig April 23, 2025, 9:36 a.m. UTC | #2
On Wed, Apr 23, 2025 at 08:07:19AM +0200, Hannes Reinecke wrote:
>>   +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);
>
> Any specific reason why the declaration of 'submit_bio_wait()' is moved?

To keep the related declarations together.
Johannes Thumshirn April 29, 2025, 11:03 a.m. UTC | #3
With the typo fixes addressed:
Reviewed-by: Johannes Thumshirn <johannes.thumshirn@wdc.com>
diff mbox series

Patch

diff --git a/block/bio.c b/block/bio.c
index 4e6c85a33d74..a6a867a432cf 100644
--- a/block/bio.c
+++ b/block/bio.c
@@ -1301,6 +1301,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 accasse
+ * @data:	data to read/write
+ * @len:	length 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);
diff --git a/include/linux/bio.h b/include/linux/bio.h
index 0678b67162ee..17a10220c57d 100644
--- a/include/linux/bio.h
+++ b/include/linux/bio.h
@@ -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 *);
@@ -434,6 +433,10 @@  static inline void bio_add_virt_nofail(struct bio *bio, void *vaddr,
 	__bio_add_page(bio, virt_to_page(vaddr), len, offset_in_page(vaddr));
 }
 
+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);