diff mbox series

[01/17] block: export bio_split_rw

Message ID 20220901074216.1849941-2-hch@lst.de (mailing list archive)
State New, archived
Headers show
Series [01/17] block: export bio_split_rw | expand

Commit Message

Christoph Hellwig Sept. 1, 2022, 7:42 a.m. UTC
bio_split_rw can be used by file systems to split and incoming write
bio into multiple bios fitting the hardware limit for use as ZONE_APPEND
bios.  Export it for initial use in btrfs.

Signed-off-by: Christoph Hellwig <hch@lst.de>
---
 block/blk-merge.c   | 3 ++-
 include/linux/bio.h | 4 ++++
 2 files changed, 6 insertions(+), 1 deletion(-)

Comments

Johannes Thumshirn Sept. 1, 2022, 8:02 a.m. UTC | #1
Looks good,
Reviewed-by: Johannes Thumshirn <johannes.thumshirn@wdc.com>
Qu Wenruo Sept. 1, 2022, 8:54 a.m. UTC | #2
On 2022/9/1 15:42, Christoph Hellwig wrote:
> bio_split_rw can be used by file systems to split and incoming write
> bio into multiple bios fitting the hardware limit for use as ZONE_APPEND
> bios.  Export it for initial use in btrfs.
>
> Signed-off-by: Christoph Hellwig <hch@lst.de>
> ---
>   block/blk-merge.c   | 3 ++-
>   include/linux/bio.h | 4 ++++
>   2 files changed, 6 insertions(+), 1 deletion(-)
>
> diff --git a/block/blk-merge.c b/block/blk-merge.c
> index ff04e9290715a..e68295462977b 100644
> --- a/block/blk-merge.c
> +++ b/block/blk-merge.c
> @@ -267,7 +267,7 @@ static bool bvec_split_segs(struct queue_limits *lim, const struct bio_vec *bv,
>    * responsible for ensuring that @bs is only destroyed after processing of the
>    * split bio has finished.
>    */
> -static struct bio *bio_split_rw(struct bio *bio, struct queue_limits *lim,
> +struct bio *bio_split_rw(struct bio *bio, struct queue_limits *lim,

I found the queue_limits structure pretty scary, while we only have very
limited members used in this case:

- lim->virt_boundary_mask
   Used in bvec_gap_to_prev()

- lim->max_segments

- lim->seg_boundary_mask
- lim->max_segment_size
   Used in bvec_split_segs()

- lim->logical_block_size

Not familiar with block layer, thus I'm wondering do btrfs really need a
full queue_limits structure to call bio_split_rw().

Or can we have a simplified wrapper?

IIRC inside btrfs we only need two cases for bio split:

- Split for stripe boundary

- Split for OE/zoned boundary

Thanks,
Qu

>   		unsigned *segs, struct bio_set *bs, unsigned max_bytes)
>   {
>   	struct bio_vec bv, bvprv, *bvprvp = NULL;
> @@ -317,6 +317,7 @@ static struct bio *bio_split_rw(struct bio *bio, struct queue_limits *lim,
>   	bio_clear_polled(bio);
>   	return bio_split(bio, bytes >> SECTOR_SHIFT, GFP_NOIO, bs);
>   }
> +EXPORT_SYMBOL_GPL(bio_split_rw);
>
>   /**
>    * __bio_split_to_limits - split a bio to fit the queue limits
> diff --git a/include/linux/bio.h b/include/linux/bio.h
> index ca22b06700a94..46890f8235401 100644
> --- a/include/linux/bio.h
> +++ b/include/linux/bio.h
> @@ -12,6 +12,8 @@
>
>   #define BIO_MAX_VECS		256U
>
> +struct queue_limits;
> +
>   static inline unsigned int bio_max_segs(unsigned int nr_segs)
>   {
>   	return min(nr_segs, BIO_MAX_VECS);
> @@ -375,6 +377,8 @@ static inline void bip_set_seed(struct bio_integrity_payload *bip,
>   void bio_trim(struct bio *bio, sector_t offset, sector_t size);
>   extern struct bio *bio_split(struct bio *bio, int sectors,
>   			     gfp_t gfp, struct bio_set *bs);
> +struct bio *bio_split_rw(struct bio *bio, struct queue_limits *lim,
> +		unsigned *segs, struct bio_set *bs, unsigned max_bytes);
>
>   /**
>    * bio_next_split - get next @sectors from a bio, splitting if necessary
Christoph Hellwig Sept. 5, 2022, 6:44 a.m. UTC | #3
On Thu, Sep 01, 2022 at 04:54:32PM +0800, Qu Wenruo wrote:
> I found the queue_limits structure pretty scary, while we only have very
> limited members used in this case:
>
> - lim->virt_boundary_mask
>   Used in bvec_gap_to_prev()
>
> - lim->max_segments
>
> - lim->seg_boundary_mask
> - lim->max_segment_size
>   Used in bvec_split_segs()
>
> - lim->logical_block_size
>
> Not familiar with block layer, thus I'm wondering do btrfs really need a
> full queue_limits structure to call bio_split_rw().

Well, the queue limits is what the block layer uses for communicating
the I/O size limitations, and thus both bio_split_rw and the stacking
layer helpers operate on it. 

> Or can we have a simplified wrapper?

I don't think we can simplify anything here.  The alternative would
be to open code the I/O path logic, which means a lot more code that
needs to be maintained and has a high probability to get out of sync
with the block layer logic.  So I'd much rather share this code
between everything that stacks block devices, be that to represent
another block device on the top like dm/md or for a 'direct' stacking
in the file system like btrfs does.

> IIRC inside btrfs we only need two cases for bio split:
>
> - Split for stripe boundary
>
> - Split for OE/zoned boundary

No.  For zoned devices we all limitations for bio, basically all that
you mentioned above.
Qu Wenruo Sept. 5, 2022, 6:51 a.m. UTC | #4
On 2022/9/5 14:44, Christoph Hellwig wrote:
> On Thu, Sep 01, 2022 at 04:54:32PM +0800, Qu Wenruo wrote:
>> I found the queue_limits structure pretty scary, while we only have very
>> limited members used in this case:
>>
>> - lim->virt_boundary_mask
>>    Used in bvec_gap_to_prev()
>>
>> - lim->max_segments
>>
>> - lim->seg_boundary_mask
>> - lim->max_segment_size
>>    Used in bvec_split_segs()
>>
>> - lim->logical_block_size
>>
>> Not familiar with block layer, thus I'm wondering do btrfs really need a
>> full queue_limits structure to call bio_split_rw().
>
> Well, the queue limits is what the block layer uses for communicating
> the I/O size limitations, and thus both bio_split_rw and the stacking
> layer helpers operate on it.
>
>> Or can we have a simplified wrapper?
>
> I don't think we can simplify anything here.  The alternative would
> be to open code the I/O path logic, which means a lot more code that
> needs to be maintained and has a high probability to get out of sync
> with the block layer logic.  So I'd much rather share this code
> between everything that stacks block devices, be that to represent
> another block device on the top like dm/md or for a 'direct' stacking
> in the file system like btrfs does.
>
>> IIRC inside btrfs we only need two cases for bio split:
>>
>> - Split for stripe boundary
>>
>> - Split for OE/zoned boundary
>
> No.  For zoned devices we all limitations for bio, basically all that
> you mentioned above.

OK, that explains the reason for the full queue_limits exported.

Then it makes sense to me now.

Thanks,
Qu
Josef Bacik Sept. 7, 2022, 5:51 p.m. UTC | #5
On Thu, Sep 01, 2022 at 10:42:00AM +0300, Christoph Hellwig wrote:
> bio_split_rw can be used by file systems to split and incoming write
> bio into multiple bios fitting the hardware limit for use as ZONE_APPEND
> bios.  Export it for initial use in btrfs.
> 
> Signed-off-by: Christoph Hellwig <hch@lst.de>

Reviewed-by: Josef Bacik <josef@toxicpanda.com>

Thanks,

Josef
diff mbox series

Patch

diff --git a/block/blk-merge.c b/block/blk-merge.c
index ff04e9290715a..e68295462977b 100644
--- a/block/blk-merge.c
+++ b/block/blk-merge.c
@@ -267,7 +267,7 @@  static bool bvec_split_segs(struct queue_limits *lim, const struct bio_vec *bv,
  * responsible for ensuring that @bs is only destroyed after processing of the
  * split bio has finished.
  */
-static struct bio *bio_split_rw(struct bio *bio, struct queue_limits *lim,
+struct bio *bio_split_rw(struct bio *bio, struct queue_limits *lim,
 		unsigned *segs, struct bio_set *bs, unsigned max_bytes)
 {
 	struct bio_vec bv, bvprv, *bvprvp = NULL;
@@ -317,6 +317,7 @@  static struct bio *bio_split_rw(struct bio *bio, struct queue_limits *lim,
 	bio_clear_polled(bio);
 	return bio_split(bio, bytes >> SECTOR_SHIFT, GFP_NOIO, bs);
 }
+EXPORT_SYMBOL_GPL(bio_split_rw);
 
 /**
  * __bio_split_to_limits - split a bio to fit the queue limits
diff --git a/include/linux/bio.h b/include/linux/bio.h
index ca22b06700a94..46890f8235401 100644
--- a/include/linux/bio.h
+++ b/include/linux/bio.h
@@ -12,6 +12,8 @@ 
 
 #define BIO_MAX_VECS		256U
 
+struct queue_limits;
+
 static inline unsigned int bio_max_segs(unsigned int nr_segs)
 {
 	return min(nr_segs, BIO_MAX_VECS);
@@ -375,6 +377,8 @@  static inline void bip_set_seed(struct bio_integrity_payload *bip,
 void bio_trim(struct bio *bio, sector_t offset, sector_t size);
 extern struct bio *bio_split(struct bio *bio, int sectors,
 			     gfp_t gfp, struct bio_set *bs);
+struct bio *bio_split_rw(struct bio *bio, struct queue_limits *lim,
+		unsigned *segs, struct bio_set *bs, unsigned max_bytes);
 
 /**
  * bio_next_split - get next @sectors from a bio, splitting if necessary