block/bio.c | 2 +- drivers/scsi/sd_zbc.c | 3 +++ include/linux/bio.h | 2 ++ 3 files changed, 6 insertions(+), 1 deletion(-)
The report zones buffer size is currently limited by the HBA's
maximum segment count to ensure the buffer can be mapped. However,
the block layer further limits the number of iovec entries to
1024 when allocating a bio.
To avoid allocation of buffers too large to be mapped, further
restrict the maximum buffer size to BIO_MAX_INLINE_VECS.
Replace the UIO_MAXIOV symbolic name with the more contextually
appropriate BIO_MAX_INLINE_VECS.
Signed-off-by: Steve Siwinski <ssiwinski@atto.com>
---
block/bio.c | 2 +-
drivers/scsi/sd_zbc.c | 3 +++
include/linux/bio.h | 2 ++
3 files changed, 6 insertions(+), 1 deletion(-)
diff --git a/block/bio.c b/block/bio.c
index 4e6c85a33d74..4be592d37fb6 100644
--- a/block/bio.c
+++ b/block/bio.c
@@ -611,7 +611,7 @@ struct bio *bio_kmalloc(unsigned short nr_vecs, gfp_t gfp_mask)
{
struct bio *bio;
- if (nr_vecs > UIO_MAXIOV)
+ if (nr_vecs > BIO_MAX_INLINE_VECS)
return NULL;
return kmalloc(struct_size(bio, bi_inline_vecs, nr_vecs), gfp_mask);
}
diff --git a/drivers/scsi/sd_zbc.c b/drivers/scsi/sd_zbc.c
index 7a447ff600d2..a5364fdc2824 100644
--- a/drivers/scsi/sd_zbc.c
+++ b/drivers/scsi/sd_zbc.c
@@ -180,12 +180,15 @@ static void *sd_zbc_alloc_report_buffer(struct scsi_disk *sdkp,
* Furthermore, since the report zone command cannot be split, make
* sure that the allocated buffer can always be mapped by limiting the
* number of pages allocated to the HBA max segments limit.
+ * Since max segments can be larger than the max inline bio vectors,
+ * further limit the allocated buffer to BIO_MAX_INLINE_VECS.
*/
nr_zones = min(nr_zones, sdkp->zone_info.nr_zones);
bufsize = roundup((nr_zones + 1) * 64, SECTOR_SIZE);
bufsize = min_t(size_t, bufsize,
queue_max_hw_sectors(q) << SECTOR_SHIFT);
bufsize = min_t(size_t, bufsize, queue_max_segments(q) << PAGE_SHIFT);
+ bufsize = min_t(size_t, bufsize, BIO_MAX_INLINE_VECS << PAGE_SHIFT);
while (bufsize >= SECTOR_SIZE) {
buf = kvzalloc(bufsize, GFP_KERNEL | __GFP_NORETRY);
diff --git a/include/linux/bio.h b/include/linux/bio.h
index cafc7c215de8..7cf9506a6c36 100644
--- a/include/linux/bio.h
+++ b/include/linux/bio.h
@@ -11,6 +11,8 @@
#include <linux/uio.h>
#define BIO_MAX_VECS 256U
+/* BIO_MAX_INLINE_VECS must be at most the size of UIO_MAXIOV */
+#define BIO_MAX_INLINE_VECS 1024
struct queue_limits;
--
2.43.5
On 5/3/25 04:35, Steve Siwinski wrote:
> The report zones buffer size is currently limited by the HBA's
> maximum segment count to ensure the buffer can be mapped. However,
> the block layer further limits the number of iovec entries to
> 1024 when allocating a bio.
>
> To avoid allocation of buffers too large to be mapped, further
> restrict the maximum buffer size to BIO_MAX_INLINE_VECS.
>
> Replace the UIO_MAXIOV symbolic name with the more contextually
> appropriate BIO_MAX_INLINE_VECS.
>
> Signed-off-by: Steve Siwinski <ssiwinski@atto.com>
This needs a "Fixes" tag:
Fixes: b091ac616846 ("sd_zbc: Fix report zones buffer allocation")
Cc: stable@vger.kernel.org
> diff --git a/drivers/scsi/sd_zbc.c b/drivers/scsi/sd_zbc.c
> index 7a447ff600d2..a5364fdc2824 100644
> --- a/drivers/scsi/sd_zbc.c
> +++ b/drivers/scsi/sd_zbc.c
> @@ -180,12 +180,15 @@ static void *sd_zbc_alloc_report_buffer(struct scsi_disk *sdkp,
> * Furthermore, since the report zone command cannot be split, make
> * sure that the allocated buffer can always be mapped by limiting the
> * number of pages allocated to the HBA max segments limit.
> + * Since max segments can be larger than the max inline bio vectors,
> + * further limit the allocated buffer to BIO_MAX_INLINE_VECS.
> */
> nr_zones = min(nr_zones, sdkp->zone_info.nr_zones);
> bufsize = roundup((nr_zones + 1) * 64, SECTOR_SIZE);
> bufsize = min_t(size_t, bufsize,
> queue_max_hw_sectors(q) << SECTOR_SHIFT);
> bufsize = min_t(size_t, bufsize, queue_max_segments(q) << PAGE_SHIFT);
> + bufsize = min_t(size_t, bufsize, BIO_MAX_INLINE_VECS << PAGE_SHIFT);
I would prefer something like:
unsigned int max_segments;
...
max_segments = min(BIO_MAX_INLINE_VECS, queue_max_segments(q));
bufsize = min_t(size_t, bufsize, max_segments << PAGE_SHIFT);
>
> while (bufsize >= SECTOR_SIZE) {
> buf = kvzalloc(bufsize, GFP_KERNEL | __GFP_NORETRY);
> diff --git a/include/linux/bio.h b/include/linux/bio.h
> index cafc7c215de8..7cf9506a6c36 100644
> --- a/include/linux/bio.h
> +++ b/include/linux/bio.h
> @@ -11,6 +11,8 @@
> #include <linux/uio.h>
>
> #define BIO_MAX_VECS 256U
> +/* BIO_MAX_INLINE_VECS must be at most the size of UIO_MAXIOV */
> +#define BIO_MAX_INLINE_VECS 1024
This should be:
#define BIO_MAX_INLINE_VECS UIO_MAXIOV
so that we do not end up with inconsistencies with what user space sees as the
maximum value.
>
> struct queue_limits;
>
--
Damien Le Moal
Western Digital Research
The report zones buffer size is currently limited by the HBA's
maximum segment count to ensure the buffer can be mapped. However,
the block layer further limits the number of iovec entries to
1024 when allocating a bio.
To avoid allocation of buffers too large to be mapped, further
restrict the maximum buffer size to BIO_MAX_INLINE_VECS.
Replace the UIO_MAXIOV symbolic name with the more contextually
appropriate BIO_MAX_INLINE_VECS.
Fixes: b091ac616846 ("sd_zbc: Fix report zones buffer allocation")
Cc: stable@vger.kernel.org
Signed-off-by: Steve Siwinski <ssiwinski@atto.com>
---
block/bio.c | 2 +-
drivers/scsi/sd_zbc.c | 6 +++++-
include/linux/bio.h | 1 +
3 files changed, 7 insertions(+), 2 deletions(-)
diff --git a/block/bio.c b/block/bio.c
index 4e6c85a33d74..4be592d37fb6 100644
--- a/block/bio.c
+++ b/block/bio.c
@@ -611,7 +611,7 @@ struct bio *bio_kmalloc(unsigned short nr_vecs, gfp_t gfp_mask)
{
struct bio *bio;
- if (nr_vecs > UIO_MAXIOV)
+ if (nr_vecs > BIO_MAX_INLINE_VECS)
return NULL;
return kmalloc(struct_size(bio, bi_inline_vecs, nr_vecs), gfp_mask);
}
diff --git a/drivers/scsi/sd_zbc.c b/drivers/scsi/sd_zbc.c
index 7a447ff600d2..a8db66428f80 100644
--- a/drivers/scsi/sd_zbc.c
+++ b/drivers/scsi/sd_zbc.c
@@ -169,6 +169,7 @@ static void *sd_zbc_alloc_report_buffer(struct scsi_disk *sdkp,
unsigned int nr_zones, size_t *buflen)
{
struct request_queue *q = sdkp->disk->queue;
+ unsigned int max_segments;
size_t bufsize;
void *buf;
@@ -180,12 +181,15 @@ static void *sd_zbc_alloc_report_buffer(struct scsi_disk *sdkp,
* Furthermore, since the report zone command cannot be split, make
* sure that the allocated buffer can always be mapped by limiting the
* number of pages allocated to the HBA max segments limit.
+ * Since max segments can be larger than the max inline bio vectors,
+ * further limit the allocated buffer to BIO_MAX_INLINE_VECS.
*/
nr_zones = min(nr_zones, sdkp->zone_info.nr_zones);
bufsize = roundup((nr_zones + 1) * 64, SECTOR_SIZE);
bufsize = min_t(size_t, bufsize,
queue_max_hw_sectors(q) << SECTOR_SHIFT);
- bufsize = min_t(size_t, bufsize, queue_max_segments(q) << PAGE_SHIFT);
+ max_segments = min(BIO_MAX_INLINE_VECS, queue_max_segments(q));
+ bufsize = min_t(size_t, bufsize, max_segments << PAGE_SHIFT);
while (bufsize >= SECTOR_SIZE) {
buf = kvzalloc(bufsize, GFP_KERNEL | __GFP_NORETRY);
diff --git a/include/linux/bio.h b/include/linux/bio.h
index cafc7c215de8..b786ec5bcc81 100644
--- a/include/linux/bio.h
+++ b/include/linux/bio.h
@@ -11,6 +11,7 @@
#include <linux/uio.h>
#define BIO_MAX_VECS 256U
+#define BIO_MAX_INLINE_VECS UIO_MAXIOV
struct queue_limits;
--
2.43.5
On 5/9/25 5:01 AM, Steve Siwinski wrote:
> The report zones buffer size is currently limited by the HBA's
> maximum segment count to ensure the buffer can be mapped. However,
> the block layer further limits the number of iovec entries to
> 1024 when allocating a bio.
>
> To avoid allocation of buffers too large to be mapped, further
> restrict the maximum buffer size to BIO_MAX_INLINE_VECS.
>
> Replace the UIO_MAXIOV symbolic name with the more contextually
> appropriate BIO_MAX_INLINE_VECS.
>
> Fixes: b091ac616846 ("sd_zbc: Fix report zones buffer allocation")
> Cc: stable@vger.kernel.org
> Signed-off-by: Steve Siwinski <ssiwinski@atto.com>
Looks good to me.
Reviewed-by: Damien Le Moal <dlemoal@kernel.org>
--
Damien Le Moal
Western Digital Research
© 2016 - 2026 Red Hat, Inc.