diff mbox series

scsi: storvsc: set max_segment_size as UINT_MAX explicitly

Message ID 20250616160509.52491-1-ming.lei@redhat.com
State New
Headers show
Series scsi: storvsc: set max_segment_size as UINT_MAX explicitly | expand

Commit Message

Ming Lei June 16, 2025, 4:05 p.m. UTC
Set max_segment_size as UINT_MAX explicitly:

- storvrc uses virt_boundary to define `segment`

- strovrc does not define max_segment_size

So define max_segment_size as UINT_MAX, otherwise __blk_rq_map_sg() takes
default 64K max segment size and splits one virtual segment into two parts,
then breaks virt_boundary limit.

Before commit ec84ca4025c0 ("scsi: block: Remove now unused queue limits helpers"),
max segment size is set as UINT_MAX in case that virt_boundary is
defined.

Cc: "K. Y. Srinivasan" <kys@microsoft.com>
Cc: Haiyang Zhang <haiyangz@microsoft.com>
Cc: Wei Liu <wei.liu@kernel.org>
Cc: Christoph Hellwig <hch@lst.de>
Cc: Ewan D. Milne <emilne@redhat.com>
Cc: Laurence Oberman <loberman@redhat.com>
Fixes: ec84ca4025c0 ("scsi: block: Remove now unused queue limits helpers")
Signed-off-by: Ming Lei <ming.lei@redhat.com>
---
 drivers/scsi/storvsc_drv.c | 1 +
 1 file changed, 1 insertion(+)

Comments

Bart Van Assche June 16, 2025, 4:18 p.m. UTC | #1
On 6/16/25 9:05 AM, Ming Lei wrote:
> - storvrc uses virt_boundary to define `segment`
     ^^^^^^^
storvsc?

> - strovrc does not define max_segment_size
     ^^^^^^^
storvsc?

Otherwise this patch looks good to me.

Thanks,

Bart.
Wei Liu June 16, 2025, 6:51 p.m. UTC | #2
+Long for reviewing this patch.

On Tue, Jun 17, 2025 at 12:05:09AM +0800, Ming Lei wrote:
> Set max_segment_size as UINT_MAX explicitly:
> 
> - storvrc uses virt_boundary to define `segment`
> 
> - strovrc does not define max_segment_size
> 

Typo here. It should be storvsc, not storvrc.

> So define max_segment_size as UINT_MAX, otherwise __blk_rq_map_sg() takes
> default 64K max segment size and splits one virtual segment into two parts,
> then breaks virt_boundary limit.
> 
> Before commit ec84ca4025c0 ("scsi: block: Remove now unused queue limits helpers"),
> max segment size is set as UINT_MAX in case that virt_boundary is
> defined.
> 
> Cc: "K. Y. Srinivasan" <kys@microsoft.com>
> Cc: Haiyang Zhang <haiyangz@microsoft.com>
> Cc: Wei Liu <wei.liu@kernel.org>
> Cc: Christoph Hellwig <hch@lst.de>
> Cc: Ewan D. Milne <emilne@redhat.com>
> Cc: Laurence Oberman <loberman@redhat.com>
> Fixes: ec84ca4025c0 ("scsi: block: Remove now unused queue limits helpers")
> Signed-off-by: Ming Lei <ming.lei@redhat.com>
> ---
>  drivers/scsi/storvsc_drv.c | 1 +
>  1 file changed, 1 insertion(+)
> 
> diff --git a/drivers/scsi/storvsc_drv.c b/drivers/scsi/storvsc_drv.c
> index 2e6b2412d2c9..1e7ad85f4ba3 100644
> --- a/drivers/scsi/storvsc_drv.c
> +++ b/drivers/scsi/storvsc_drv.c
> @@ -1897,6 +1897,7 @@ static struct scsi_host_template scsi_driver = {
>  	.no_write_same =	1,
>  	.track_queue_depth =	1,
>  	.change_queue_depth =	storvsc_change_queue_depth,
> +	.max_segment_size   = 0xffffffff,
>  };
>  
>  enum {
> -- 
> 2.47.0
>
Martin K. Petersen June 16, 2025, 9:56 p.m. UTC | #3
On Tue, 17 Jun 2025 00:05:09 +0800, Ming Lei wrote:

> Set max_segment_size as UINT_MAX explicitly:
> 
> - storvrc uses virt_boundary to define `segment`
> 
> - strovrc does not define max_segment_size
> 
> So define max_segment_size as UINT_MAX, otherwise __blk_rq_map_sg() takes
> default 64K max segment size and splits one virtual segment into two parts,
> then breaks virt_boundary limit.
> 
> [...]

Applied to 6.16/scsi-fixes, thanks!

[1/1] scsi: storvsc: set max_segment_size as UINT_MAX explicitly
      https://git.kernel.org/mkp/scsi/c/19ec970841ca
Christoph Hellwig June 17, 2025, 4:43 a.m. UTC | #4
On Tue, Jun 17, 2025 at 12:05:09AM +0800, Ming Lei wrote:
> Set max_segment_size as UINT_MAX explicitly:
> 
> - storvrc uses virt_boundary to define `segment`
> 
> - strovrc does not define max_segment_size
> 
> So define max_segment_size as UINT_MAX, otherwise __blk_rq_map_sg() takes
> default 64K max segment size and splits one virtual segment into two parts,
> then breaks virt_boundary limit.
> 
> Before commit ec84ca4025c0 ("scsi: block: Remove now unused queue limits helpers"),
> max segment size is set as UINT_MAX in case that virt_boundary is
> defined.

Drivers should not have done this.  If you need this someone (probably
me) broke the block layer code ensuring it's not needed, and that
affects all drivers using virt_boundary.
Christoph Hellwig June 17, 2025, 5:02 a.m. UTC | #5
Please try this proper fix instead:

diff --git a/drivers/scsi/hosts.c b/drivers/scsi/hosts.c
index e021f1106bea..09f5fb5b2fb1 100644
--- a/drivers/scsi/hosts.c
+++ b/drivers/scsi/hosts.c
@@ -473,7 +473,9 @@ struct Scsi_Host *scsi_host_alloc(const struct scsi_host_template *sht, int priv
 	else
 		shost->max_sectors = SCSI_DEFAULT_MAX_SECTORS;
 
-	if (sht->max_segment_size)
+	if (sht->virt_boundary_mask)
+		shost->virt_boundary_mask = sht->virt_boundary_mask;
+	else if (sht->max_segment_size)
 		shost->max_segment_size = sht->max_segment_size;
 	else
 		shost->max_segment_size = BLK_MAX_SEGMENT_SIZE;
@@ -492,9 +494,6 @@ struct Scsi_Host *scsi_host_alloc(const struct scsi_host_template *sht, int priv
 	else
 		shost->dma_boundary = 0xffffffff;
 
-	if (sht->virt_boundary_mask)
-		shost->virt_boundary_mask = sht->virt_boundary_mask;
-
 	device_initialize(&shost->shost_gendev);
 	dev_set_name(&shost->shost_gendev, "host%d", shost->host_no);
 	shost->shost_gendev.bus = &scsi_bus_type;
Ming Lei June 17, 2025, 7:25 a.m. UTC | #6
On Tue, Jun 17, 2025 at 07:02:40AM +0200, Christoph Hellwig wrote:
> Please try this proper fix instead:
> 
> diff --git a/drivers/scsi/hosts.c b/drivers/scsi/hosts.c
> index e021f1106bea..09f5fb5b2fb1 100644
> --- a/drivers/scsi/hosts.c
> +++ b/drivers/scsi/hosts.c
> @@ -473,7 +473,9 @@ struct Scsi_Host *scsi_host_alloc(const struct scsi_host_template *sht, int priv
>  	else
>  		shost->max_sectors = SCSI_DEFAULT_MAX_SECTORS;
>  
> -	if (sht->max_segment_size)
> +	if (sht->virt_boundary_mask)
> +		shost->virt_boundary_mask = sht->virt_boundary_mask;
> +	else if (sht->max_segment_size)
>  		shost->max_segment_size = sht->max_segment_size;
>  	else
>  		shost->max_segment_size = BLK_MAX_SEGMENT_SIZE;

This way works, but I prefer to set it explicitly in driver, instead of
making block layer more fragile to deal with def ->max_segment_size
if ->virt_boundary_mask is defined

- for low level driver, if ->virt_boundary_mask is defined, ->max_segment_size
should be UINT_MAX obviously since it implies single `virt segment`.
Setting UINT_MAX in driver has document benefit too.

- for logical block device(md, dm, ...), both ->virt_boundary_mask and
->max_segment_size may be set, and it is fine since logical block device
driver needn't to deal with sg


Thanks,
Ming
Laurence Oberman June 17, 2025, 1:58 p.m. UTC | #7
On Tue, 2025-06-17 at 00:05 +0800, Ming Lei wrote:
> Set max_segment_size as UINT_MAX explicitly:
> 
> - storvrc uses virt_boundary to define `segment`
> 
> - strovrc does not define max_segment_size
> 
> So define max_segment_size as UINT_MAX, otherwise __blk_rq_map_sg()
> takes
> default 64K max segment size and splits one virtual segment into two
> parts,
> then breaks virt_boundary limit.
> 
> Before commit ec84ca4025c0 ("scsi: block: Remove now unused queue
> limits helpers"),
> max segment size is set as UINT_MAX in case that virt_boundary is
> defined.
> 
> Cc: "K. Y. Srinivasan" <kys@microsoft.com>
> Cc: Haiyang Zhang <haiyangz@microsoft.com>
> Cc: Wei Liu <wei.liu@kernel.org>
> Cc: Christoph Hellwig <hch@lst.de>
> Cc: Ewan D. Milne <emilne@redhat.com>
> Cc: Laurence Oberman <loberman@redhat.com>
> Fixes: ec84ca4025c0 ("scsi: block: Remove now unused queue limits
> helpers")
> Signed-off-by: Ming Lei <ming.lei@redhat.com>
> ---
>  drivers/scsi/storvsc_drv.c | 1 +
>  1 file changed, 1 insertion(+)
> 
> diff --git a/drivers/scsi/storvsc_drv.c b/drivers/scsi/storvsc_drv.c
> index 2e6b2412d2c9..1e7ad85f4ba3 100644
> --- a/drivers/scsi/storvsc_drv.c
> +++ b/drivers/scsi/storvsc_drv.c
> @@ -1897,6 +1897,7 @@ static struct scsi_host_template scsi_driver =
> {
>         .no_write_same =        1,
>         .track_queue_depth =    1,
>         .change_queue_depth =   storvsc_change_queue_depth,
> +       .max_segment_size   = 0xffffffff,
>  };
>  
>  enum {

Hello 
For what it is worth, I tested Ming's patch in our lab and at our
customers and it fixed a very serious corruption in Oracle REDO logs.

Tested-by: Laurence Oberman  <loberman@redhat.com>

I will test what Christoph share dbut our initial way to deal with this
in RHEL will be the point fix in storvsc as its a critical issue
needing an urgent fix.

Thanks
Laurence
Christoph Hellwig June 18, 2025, 5:44 a.m. UTC | #8
On Tue, Jun 17, 2025 at 03:25:21PM +0800, Ming Lei wrote:
> > @@ -473,7 +473,9 @@ struct Scsi_Host *scsi_host_alloc(const struct scsi_host_template *sht, int priv
> >  	else
> >  		shost->max_sectors = SCSI_DEFAULT_MAX_SECTORS;
> >  
> > -	if (sht->max_segment_size)
> > +	if (sht->virt_boundary_mask)
> > +		shost->virt_boundary_mask = sht->virt_boundary_mask;
> > +	else if (sht->max_segment_size)
> >  		shost->max_segment_size = sht->max_segment_size;
> >  	else
> >  		shost->max_segment_size = BLK_MAX_SEGMENT_SIZE;
> 
> This way works, but I prefer to set it explicitly in driver, instead of
> making block layer more fragile to deal with def ->max_segment_size
> if ->virt_boundary_mask is defined

The block layer already enforces this as it is a requirement.  It is
just the SCSI wrapper that broke it.  Without this proper fix iser
is still broken, and srp might or might not.

> - for low level driver, if ->virt_boundary_mask is defined, ->max_segment_size
> should be UINT_MAX obviously since it implies single `virt segment`.
> Setting UINT_MAX in driver has document benefit too.

No, it doesn't.  It means you need to cargo cult copy and paste code
instead of solving the problem in the proper place.

> - for logical block device(md, dm, ...), both ->virt_boundary_mask and
> ->max_segment_size may be set, and it is fine since logical block device
> driver needn't to deal with sg

Stacked devices should not inherit the hardware limits at all because
we split below them, but that's a separate story.  Either way this is
not relevant here as we don't have stacking drivers that use the
SCSI layer.
diff mbox series

Patch

diff --git a/drivers/scsi/storvsc_drv.c b/drivers/scsi/storvsc_drv.c
index 2e6b2412d2c9..1e7ad85f4ba3 100644
--- a/drivers/scsi/storvsc_drv.c
+++ b/drivers/scsi/storvsc_drv.c
@@ -1897,6 +1897,7 @@  static struct scsi_host_template scsi_driver = {
 	.no_write_same =	1,
 	.track_queue_depth =	1,
 	.change_queue_depth =	storvsc_change_queue_depth,
+	.max_segment_size   = 0xffffffff,
 };
 
 enum {