* [PATCH 0/2] use blk_rq_nr_phys_segments() instead of iterating bvecs
@ 2025-11-08 23:00 Caleb Sander Mateos
2025-11-08 23:01 ` [PATCH 1/2] loop: " Caleb Sander Mateos
2025-11-08 23:01 ` [PATCH 2/2] zloop: " Caleb Sander Mateos
0 siblings, 2 replies; 10+ messages in thread
From: Caleb Sander Mateos @ 2025-11-08 23:00 UTC (permalink / raw)
To: Jens Axboe, Damien Le Moal, Christoph Hellwig
Cc: linux-block, linux-kernel, Caleb Sander Mateos
Minor simplification to loop and zloop to get the number of segments
from the request directly instead of iterating over all its bvecs.
Caleb Sander Mateos (2):
loop: use blk_rq_nr_phys_segments() instead of iterating bvecs
zloop: use blk_rq_nr_phys_segments() instead of iterating bvecs
drivers/block/loop.c | 5 +----
drivers/block/zloop.c | 5 +----
2 files changed, 2 insertions(+), 8 deletions(-)
--
2.45.2
^ permalink raw reply [flat|nested] 10+ messages in thread
* [PATCH 1/2] loop: use blk_rq_nr_phys_segments() instead of iterating bvecs
2025-11-08 23:00 [PATCH 0/2] use blk_rq_nr_phys_segments() instead of iterating bvecs Caleb Sander Mateos
@ 2025-11-08 23:01 ` Caleb Sander Mateos
2025-11-09 12:19 ` Ming Lei
2025-11-08 23:01 ` [PATCH 2/2] zloop: " Caleb Sander Mateos
1 sibling, 1 reply; 10+ messages in thread
From: Caleb Sander Mateos @ 2025-11-08 23:01 UTC (permalink / raw)
To: Jens Axboe, Damien Le Moal, Christoph Hellwig
Cc: linux-block, linux-kernel, Caleb Sander Mateos
The number of bvecs can be obtained directly from struct request's
nr_phys_segments field via blk_rq_nr_phys_segments(), so use that
instead of iterating over the bvecs an extra time.
Signed-off-by: Caleb Sander Mateos <csander@purestorage.com>
---
drivers/block/loop.c | 5 +----
1 file changed, 1 insertion(+), 4 deletions(-)
diff --git a/drivers/block/loop.c b/drivers/block/loop.c
index 13ce229d450c..8096478fad45 100644
--- a/drivers/block/loop.c
+++ b/drivers/block/loop.c
@@ -346,16 +346,13 @@ static int lo_rw_aio(struct loop_device *lo, struct loop_cmd *cmd,
struct request *rq = blk_mq_rq_from_pdu(cmd);
struct bio *bio = rq->bio;
struct file *file = lo->lo_backing_file;
struct bio_vec tmp;
unsigned int offset;
- int nr_bvec = 0;
+ unsigned short nr_bvec = blk_rq_nr_phys_segments(rq);
int ret;
- rq_for_each_bvec(tmp, rq, rq_iter)
- nr_bvec++;
-
if (rq->bio != rq->biotail) {
bvec = kmalloc_array(nr_bvec, sizeof(struct bio_vec),
GFP_NOIO);
if (!bvec)
--
2.45.2
^ permalink raw reply related [flat|nested] 10+ messages in thread
* [PATCH 2/2] zloop: use blk_rq_nr_phys_segments() instead of iterating bvecs
2025-11-08 23:00 [PATCH 0/2] use blk_rq_nr_phys_segments() instead of iterating bvecs Caleb Sander Mateos
2025-11-08 23:01 ` [PATCH 1/2] loop: " Caleb Sander Mateos
@ 2025-11-08 23:01 ` Caleb Sander Mateos
2025-11-11 9:07 ` Christoph Hellwig
1 sibling, 1 reply; 10+ messages in thread
From: Caleb Sander Mateos @ 2025-11-08 23:01 UTC (permalink / raw)
To: Jens Axboe, Damien Le Moal, Christoph Hellwig
Cc: linux-block, linux-kernel, Caleb Sander Mateos
The number of bvecs can be obtained directly from struct request's
nr_phys_segments field via blk_rq_nr_phys_segments(), so use that
instead of iterating over the bvecs an extra time.
Signed-off-by: Caleb Sander Mateos <csander@purestorage.com>
---
drivers/block/zloop.c | 5 +----
1 file changed, 1 insertion(+), 4 deletions(-)
diff --git a/drivers/block/zloop.c b/drivers/block/zloop.c
index 92be9f0af00a..7883e56ed12a 100644
--- a/drivers/block/zloop.c
+++ b/drivers/block/zloop.c
@@ -368,11 +368,11 @@ static void zloop_rw(struct zloop_cmd *cmd)
struct req_iterator rq_iter;
struct zloop_zone *zone;
struct iov_iter iter;
struct bio_vec tmp;
sector_t zone_end;
- int nr_bvec = 0;
+ unsigned short nr_bvec = blk_rq_nr_phys_segments(rq);
int ret;
atomic_set(&cmd->ref, 2);
cmd->sector = sector;
cmd->nr_sectors = nr_sectors;
@@ -435,13 +435,10 @@ static void zloop_rw(struct zloop_cmd *cmd)
zone->wp += nr_sectors;
if (zone->wp == zone_end)
zone->cond = BLK_ZONE_COND_FULL;
}
- rq_for_each_bvec(tmp, rq, rq_iter)
- nr_bvec++;
-
if (rq->bio != rq->biotail) {
struct bio_vec *bvec;
cmd->bvec = kmalloc_array(nr_bvec, sizeof(*cmd->bvec), GFP_NOIO);
if (!cmd->bvec) {
--
2.45.2
^ permalink raw reply related [flat|nested] 10+ messages in thread
* Re: [PATCH 1/2] loop: use blk_rq_nr_phys_segments() instead of iterating bvecs
2025-11-08 23:01 ` [PATCH 1/2] loop: " Caleb Sander Mateos
@ 2025-11-09 12:19 ` Ming Lei
2025-11-09 19:05 ` Chaitanya Kulkarni
2025-11-10 16:47 ` Caleb Sander Mateos
0 siblings, 2 replies; 10+ messages in thread
From: Ming Lei @ 2025-11-09 12:19 UTC (permalink / raw)
To: Caleb Sander Mateos
Cc: Jens Axboe, Damien Le Moal, Christoph Hellwig, linux-block,
linux-kernel
On Sat, Nov 08, 2025 at 04:01:00PM -0700, Caleb Sander Mateos wrote:
> The number of bvecs can be obtained directly from struct request's
> nr_phys_segments field via blk_rq_nr_phys_segments(), so use that
> instead of iterating over the bvecs an extra time.
>
> Signed-off-by: Caleb Sander Mateos <csander@purestorage.com>
> ---
> drivers/block/loop.c | 5 +----
> 1 file changed, 1 insertion(+), 4 deletions(-)
>
> diff --git a/drivers/block/loop.c b/drivers/block/loop.c
> index 13ce229d450c..8096478fad45 100644
> --- a/drivers/block/loop.c
> +++ b/drivers/block/loop.c
> @@ -346,16 +346,13 @@ static int lo_rw_aio(struct loop_device *lo, struct loop_cmd *cmd,
> struct request *rq = blk_mq_rq_from_pdu(cmd);
> struct bio *bio = rq->bio;
> struct file *file = lo->lo_backing_file;
> struct bio_vec tmp;
> unsigned int offset;
> - int nr_bvec = 0;
> + unsigned short nr_bvec = blk_rq_nr_phys_segments(rq);
> int ret;
>
> - rq_for_each_bvec(tmp, rq, rq_iter)
> - nr_bvec++;
> -
The two may not be same, since one bvec can be splitted into multiple segments.
Thanks,
Ming
^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [PATCH 1/2] loop: use blk_rq_nr_phys_segments() instead of iterating bvecs
2025-11-09 12:19 ` Ming Lei
@ 2025-11-09 19:05 ` Chaitanya Kulkarni
2025-11-10 16:47 ` Caleb Sander Mateos
1 sibling, 0 replies; 10+ messages in thread
From: Chaitanya Kulkarni @ 2025-11-09 19:05 UTC (permalink / raw)
To: Ming Lei, Caleb Sander Mateos
Cc: Jens Axboe, Damien Le Moal, Christoph Hellwig,
linux-block@vger.kernel.org, linux-kernel@vger.kernel.org
On 11/9/25 04:19, Ming Lei wrote:
> On Sat, Nov 08, 2025 at 04:01:00PM -0700, Caleb Sander Mateos wrote:
>> The number of bvecs can be obtained directly from struct request's
>> nr_phys_segments field via blk_rq_nr_phys_segments(), so use that
>> instead of iterating over the bvecs an extra time.
>>
>> Signed-off-by: Caleb Sander Mateos <csander@purestorage.com>
>> ---
>> drivers/block/loop.c | 5 +----
>> 1 file changed, 1 insertion(+), 4 deletions(-)
>>
>> diff --git a/drivers/block/loop.c b/drivers/block/loop.c
>> index 13ce229d450c..8096478fad45 100644
>> --- a/drivers/block/loop.c
>> +++ b/drivers/block/loop.c
>> @@ -346,16 +346,13 @@ static int lo_rw_aio(struct loop_device *lo, struct loop_cmd *cmd,
>> struct request *rq = blk_mq_rq_from_pdu(cmd);
>> struct bio *bio = rq->bio;
>> struct file *file = lo->lo_backing_file;
>> struct bio_vec tmp;
>> unsigned int offset;
>> - int nr_bvec = 0;
>> + unsigned short nr_bvec = blk_rq_nr_phys_segments(rq);
>> int ret;
>>
>> - rq_for_each_bvec(tmp, rq, rq_iter)
>> - nr_bvec++;
>> -
> The two may not be same, since one bvec can be splitted into multiple segments.
>
> Thanks,
> Ming
>
>
I had this patch only to realize this :-
bvec_split_segs():-
* When splitting a bio, it can happen that a bvec is encountered that is too
* big to fit in a single segment and hence that it has to be split in the
* middle. This function verifies whether or not that should happen. The
value
* %true is returned if and only if appending the entire @bv to a bio with
* *@nsegs segments and *@sectors sectors would make that bio
unacceptable for
* the block driver.
if following messup the indentation after I send plz ignore :-
submit_bio()
-> submit_bio_noacct()
-> __submit_bio_noacct()
-> __submit_bio()
-> blk_mq_submit_bio()
-> __bio_split_to_limits()
-> bio_split_rw()
-> bio_split_rw_at()
-> bio_split_io_at()
-- bio_for_each_bvec() (iterate all bvecs)
-- [Fast path]
nsegs++ (1 bvec = 1 segment)
bytes += bv.bv_len
-- [Slow path]
/* one bv is passed from bio bvec list */
-> bvec_split_segs(lim, &bv, &nsegs, &bytes,
lim->max_segments, max_bytes)
/* working on one bvec and associated
segments */
-- while (len && *nsegs < max_segs) {
...
get_max_segment_size()
-> min(len,
seg_boundary_mask - offset,
max_segment_size)
(*nsegs)++
total_len += seg_size
len -= seg_size
...
}
-- *bytes += total_len
-- return (len > 0)
-> blk_mq_bio_to_request()
rq->nr_phys_segments = nr_segs
-ck
^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [PATCH 1/2] loop: use blk_rq_nr_phys_segments() instead of iterating bvecs
2025-11-09 12:19 ` Ming Lei
2025-11-09 19:05 ` Chaitanya Kulkarni
@ 2025-11-10 16:47 ` Caleb Sander Mateos
2025-11-10 21:34 ` Chaitanya Kulkarni
2025-11-11 1:22 ` Ming Lei
1 sibling, 2 replies; 10+ messages in thread
From: Caleb Sander Mateos @ 2025-11-10 16:47 UTC (permalink / raw)
To: Ming Lei
Cc: Jens Axboe, Damien Le Moal, Christoph Hellwig, linux-block,
linux-kernel, Keith Busch
On Sun, Nov 9, 2025 at 4:20 AM Ming Lei <ming.lei@redhat.com> wrote:
>
> On Sat, Nov 08, 2025 at 04:01:00PM -0700, Caleb Sander Mateos wrote:
> > The number of bvecs can be obtained directly from struct request's
> > nr_phys_segments field via blk_rq_nr_phys_segments(), so use that
> > instead of iterating over the bvecs an extra time.
> >
> > Signed-off-by: Caleb Sander Mateos <csander@purestorage.com>
> > ---
> > drivers/block/loop.c | 5 +----
> > 1 file changed, 1 insertion(+), 4 deletions(-)
> >
> > diff --git a/drivers/block/loop.c b/drivers/block/loop.c
> > index 13ce229d450c..8096478fad45 100644
> > --- a/drivers/block/loop.c
> > +++ b/drivers/block/loop.c
> > @@ -346,16 +346,13 @@ static int lo_rw_aio(struct loop_device *lo, struct loop_cmd *cmd,
> > struct request *rq = blk_mq_rq_from_pdu(cmd);
> > struct bio *bio = rq->bio;
> > struct file *file = lo->lo_backing_file;
> > struct bio_vec tmp;
> > unsigned int offset;
> > - int nr_bvec = 0;
> > + unsigned short nr_bvec = blk_rq_nr_phys_segments(rq);
> > int ret;
> >
> > - rq_for_each_bvec(tmp, rq, rq_iter)
> > - nr_bvec++;
> > -
>
> The two may not be same, since one bvec can be splitted into multiple segments.
Hmm, io_buffer_register_bvec() already assumes
blk_rq_nr_phys_segments() returns the number of bvecs iterated by
rq_for_each_bvec(). I asked about this on the patch adding it, but
Keith assures me they match:
https://lore.kernel.org/io-uring/Z7TmrB4_aBnZdFbo@kbusch-mbp/.
Best,
Caleb
^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [PATCH 1/2] loop: use blk_rq_nr_phys_segments() instead of iterating bvecs
2025-11-10 16:47 ` Caleb Sander Mateos
@ 2025-11-10 21:34 ` Chaitanya Kulkarni
2025-11-11 1:22 ` Ming Lei
1 sibling, 0 replies; 10+ messages in thread
From: Chaitanya Kulkarni @ 2025-11-10 21:34 UTC (permalink / raw)
To: Caleb Sander Mateos
Cc: Jens Axboe, Damien Le Moal, Christoph Hellwig,
linux-block@vger.kernel.org, linux-kernel@vger.kernel.org,
Ming Lei, Keith Busch
On 11/10/25 08:47, Caleb Sander Mateos wrote:
> On Sun, Nov 9, 2025 at 4:20 AM Ming Lei <ming.lei@redhat.com> wrote:
>> On Sat, Nov 08, 2025 at 04:01:00PM -0700, Caleb Sander Mateos wrote:
>>> The number of bvecs can be obtained directly from struct request's
>>> nr_phys_segments field via blk_rq_nr_phys_segments(), so use that
>>> instead of iterating over the bvecs an extra time.
>>>
>>> Signed-off-by: Caleb Sander Mateos <csander@purestorage.com>
>>> ---
>>> drivers/block/loop.c | 5 +----
>>> 1 file changed, 1 insertion(+), 4 deletions(-)
>>>
>>> diff --git a/drivers/block/loop.c b/drivers/block/loop.c
>>> index 13ce229d450c..8096478fad45 100644
>>> --- a/drivers/block/loop.c
>>> +++ b/drivers/block/loop.c
>>> @@ -346,16 +346,13 @@ static int lo_rw_aio(struct loop_device *lo, struct loop_cmd *cmd,
>>> struct request *rq = blk_mq_rq_from_pdu(cmd);
>>> struct bio *bio = rq->bio;
>>> struct file *file = lo->lo_backing_file;
>>> struct bio_vec tmp;
>>> unsigned int offset;
>>> - int nr_bvec = 0;
>>> + unsigned short nr_bvec = blk_rq_nr_phys_segments(rq);
>>> int ret;
>>>
>>> - rq_for_each_bvec(tmp, rq, rq_iter)
>>> - nr_bvec++;
>>> -
>> The two may not be same, since one bvec can be splitted into multiple segments.
> Hmm, io_buffer_register_bvec() already assumes
> blk_rq_nr_phys_segments() returns the number of bvecs iterated by
> rq_for_each_bvec(). I asked about this on the patch adding it, but
> Keith assures me they match:
> https://lore.kernel.org/io-uring/Z7TmrB4_aBnZdFbo@kbusch-mbp/.
>
> Best,
> Caleb
>
Perhaps I don't understand how they will be same ? can share more details.
Segment Splitting :-
nr_bvec=1, blk_rq_nr_phys_segments=2 (see below)
- ONE large bvec split into MULTIPLE physical segments
- Patch above allocate array[2], but iterate and fill only array[0] ?
*[ 6155.673749] nullb_bio: 128K bio as ONE bvec: sector=0, size=131072, op=WRITE*
*[ 6155.673846] null_blk: #### null_handle_data_transfer:1375*
*[ 6155.673850] null_blk: nr_bvec=1 blk_rq_nr_phys_segments=2*
*[ 6155.674263] null_blk: #### null_handle_data_transfer:1375*
*[ 6155.674267] null_blk: nr_bvec=1 blk_rq_nr_phys_segments=1*
diff --git a/drivers/block/null_blk/main.c b/drivers/block/null_blk/main.c
index 1fe3373431ca..74ab0ba53f62 100644
--- a/drivers/block/null_blk/main.c
+++ b/drivers/block/null_blk/main.c
@@ -1364,7 +1364,18 @@ static blk_status_t null_handle_data_transfer(struct nullb_cmd *cmd,
unsigned int max_bytes = nr_sectors << SECTOR_SHIFT;
unsigned int transferred_bytes = 0;
struct req_iterator iter;
+ struct req_iterator rq_iter;
struct bio_vec bvec;
+ int nr_bvec = 0;
+
+ rq_for_each_bvec(bvec, rq, rq_iter)
+ nr_bvec++;
+
+ if (req_op(rq) == REQ_OP_WRITE) {
+ pr_info("#### %s:%d\n", __func__, __LINE__);
+ pr_info("nr_bvec=%d blk_rq_nr_phys_segments=%u\n",
+ nr_bvec, blk_rq_nr_phys_segments(rq));
+ }
spin_lock_irq(&nullb->lock);
rq_for_each_segment(bvec, rq, iter) {
-ck
^ permalink raw reply related [flat|nested] 10+ messages in thread
* Re: [PATCH 1/2] loop: use blk_rq_nr_phys_segments() instead of iterating bvecs
2025-11-10 16:47 ` Caleb Sander Mateos
2025-11-10 21:34 ` Chaitanya Kulkarni
@ 2025-11-11 1:22 ` Ming Lei
1 sibling, 0 replies; 10+ messages in thread
From: Ming Lei @ 2025-11-11 1:22 UTC (permalink / raw)
To: Caleb Sander Mateos
Cc: Jens Axboe, Damien Le Moal, Christoph Hellwig, linux-block,
linux-kernel, Keith Busch
On Mon, Nov 10, 2025 at 08:47:46AM -0800, Caleb Sander Mateos wrote:
> On Sun, Nov 9, 2025 at 4:20 AM Ming Lei <ming.lei@redhat.com> wrote:
> >
> > On Sat, Nov 08, 2025 at 04:01:00PM -0700, Caleb Sander Mateos wrote:
> > > The number of bvecs can be obtained directly from struct request's
> > > nr_phys_segments field via blk_rq_nr_phys_segments(), so use that
> > > instead of iterating over the bvecs an extra time.
> > >
> > > Signed-off-by: Caleb Sander Mateos <csander@purestorage.com>
> > > ---
> > > drivers/block/loop.c | 5 +----
> > > 1 file changed, 1 insertion(+), 4 deletions(-)
> > >
> > > diff --git a/drivers/block/loop.c b/drivers/block/loop.c
> > > index 13ce229d450c..8096478fad45 100644
> > > --- a/drivers/block/loop.c
> > > +++ b/drivers/block/loop.c
> > > @@ -346,16 +346,13 @@ static int lo_rw_aio(struct loop_device *lo, struct loop_cmd *cmd,
> > > struct request *rq = blk_mq_rq_from_pdu(cmd);
> > > struct bio *bio = rq->bio;
> > > struct file *file = lo->lo_backing_file;
> > > struct bio_vec tmp;
> > > unsigned int offset;
> > > - int nr_bvec = 0;
> > > + unsigned short nr_bvec = blk_rq_nr_phys_segments(rq);
> > > int ret;
> > >
> > > - rq_for_each_bvec(tmp, rq, rq_iter)
> > > - nr_bvec++;
> > > -
> >
> > The two may not be same, since one bvec can be splitted into multiple segments.
>
> Hmm, io_buffer_register_bvec() already assumes
> blk_rq_nr_phys_segments() returns the number of bvecs iterated by
> rq_for_each_bvec(). I asked about this on the patch adding it, but
> Keith assures me they match:
> https://lore.kernel.org/io-uring/Z7TmrB4_aBnZdFbo@kbusch-mbp/.
blk_rq_nr_phys_segments() >= nr_bvec, would you like to cook a fix?
Thanks,
Ming
^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [PATCH 2/2] zloop: use blk_rq_nr_phys_segments() instead of iterating bvecs
2025-11-08 23:01 ` [PATCH 2/2] zloop: " Caleb Sander Mateos
@ 2025-11-11 9:07 ` Christoph Hellwig
2025-11-11 18:19 ` Chaitanya Kulkarni
0 siblings, 1 reply; 10+ messages in thread
From: Christoph Hellwig @ 2025-11-11 9:07 UTC (permalink / raw)
To: Caleb Sander Mateos
Cc: Jens Axboe, Damien Le Moal, Christoph Hellwig, linux-block,
linux-kernel
On Sat, Nov 08, 2025 at 04:01:01PM -0700, Caleb Sander Mateos wrote:
> The number of bvecs can be obtained directly from struct request's
> nr_phys_segments field via blk_rq_nr_phys_segments(), so use that
> instead of iterating over the bvecs an extra time.
Same reason this doesn't work as Ming explained for ublk.
Maybe we should lift this code from loop/zloop into a well documented
common helper to make it more obvious?
^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [PATCH 2/2] zloop: use blk_rq_nr_phys_segments() instead of iterating bvecs
2025-11-11 9:07 ` Christoph Hellwig
@ 2025-11-11 18:19 ` Chaitanya Kulkarni
0 siblings, 0 replies; 10+ messages in thread
From: Chaitanya Kulkarni @ 2025-11-11 18:19 UTC (permalink / raw)
To: Christoph Hellwig
Cc: Jens Axboe, Damien Le Moal, linux-block@vger.kernel.org,
linux-kernel@vger.kernel.org, Caleb Sander Mateos
On 11/11/25 01:07, Christoph Hellwig wrote:
> On Sat, Nov 08, 2025 at 04:01:01PM -0700, Caleb Sander Mateos wrote:
>> The number of bvecs can be obtained directly from struct request's
>> nr_phys_segments field via blk_rq_nr_phys_segments(), so use that
>> instead of iterating over the bvecs an extra time.
> Same reason this doesn't work as Ming explained for ublk.
>
> Maybe we should lift this code from loop/zloop into a well documented
> common helper to make it more obvious?
>
>
Absolutely, patch sent with added quantitative data from my experiments,
to prove why above is wrong, please have a look.
-ck
^ permalink raw reply [flat|nested] 10+ messages in thread
end of thread, other threads:[~2025-11-11 18:19 UTC | newest]
Thread overview: 10+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2025-11-08 23:00 [PATCH 0/2] use blk_rq_nr_phys_segments() instead of iterating bvecs Caleb Sander Mateos
2025-11-08 23:01 ` [PATCH 1/2] loop: " Caleb Sander Mateos
2025-11-09 12:19 ` Ming Lei
2025-11-09 19:05 ` Chaitanya Kulkarni
2025-11-10 16:47 ` Caleb Sander Mateos
2025-11-10 21:34 ` Chaitanya Kulkarni
2025-11-11 1:22 ` Ming Lei
2025-11-08 23:01 ` [PATCH 2/2] zloop: " Caleb Sander Mateos
2025-11-11 9:07 ` Christoph Hellwig
2025-11-11 18:19 ` Chaitanya Kulkarni
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).