Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

scsi: core: Enforce unlimited max_segment_size when virt_boundary_mask is set

The virt_boundary_mask limit requires an unlimited max_segment_size for
bio splitting to not corrupt data. Historically, the block layer tried
to validate this, although the check was half-hearted until the addition
of the atomic queue limits API. The full blown check then triggered
issues with stacked devices incorrectly inheriting limits such as the
virt boundary and got disabled in commit b561ea56a264 ("block: allow
device to have both virt_boundary_mask and max segment size") instead of
fixing the issue properly.

Ensure that the SCSI mid layer doesn't set the default low
max_segment_size limit for this case, and check for invalid
max_segment_size values in the host template, similar to the original
block layer check given that SCSI devices can't be stacked.

This fixes reported data corruption on storvsc, although as far as I can
tell storvsc always failed to properly set the max_segment_size limit as
the SCSI APIs historically applied that when setting up the host, while
storvsc only set the virt_boundary_mask when configuring the scsi_device.

Fixes: 81988a0e6b03 ("storvsc: get rid of bounce buffer")
Fixes: b561ea56a264 ("block: allow device to have both virt_boundary_mask and max segment size")
Reported-by: Ming Lei <ming.lei@redhat.com>
Signed-off-by: Christoph Hellwig <hch@lst.de>
Link: https://lore.kernel.org/r/20250624125233.219635-3-hch@lst.de
Reviewed-by: John Garry <john.g.garry@oracle.com>
Reviewed-by: Ming Lei <ming.lei@redhat.com>
Reviewed-by: Hannes Reinecke <hare@suse.de>
Reviewed-by: Bart Van Assche <bvanassche@acm.org>
Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>

authored by

Christoph Hellwig and committed by
Martin K. Petersen
4937e604 844c6a16

+11 -7
+11 -7
drivers/scsi/hosts.c
··· 473 473 else 474 474 shost->max_sectors = SCSI_DEFAULT_MAX_SECTORS; 475 475 476 - if (sht->max_segment_size) 477 - shost->max_segment_size = sht->max_segment_size; 478 - else 479 - shost->max_segment_size = BLK_MAX_SEGMENT_SIZE; 476 + shost->virt_boundary_mask = sht->virt_boundary_mask; 477 + if (shost->virt_boundary_mask) { 478 + WARN_ON_ONCE(sht->max_segment_size && 479 + sht->max_segment_size != UINT_MAX); 480 + shost->max_segment_size = UINT_MAX; 481 + } else { 482 + if (sht->max_segment_size) 483 + shost->max_segment_size = sht->max_segment_size; 484 + else 485 + shost->max_segment_size = BLK_MAX_SEGMENT_SIZE; 486 + } 480 487 481 488 /* 32-byte (dword) is a common minimum for HBAs. */ 482 489 if (sht->dma_alignment) ··· 498 491 shost->dma_boundary = sht->dma_boundary; 499 492 else 500 493 shost->dma_boundary = 0xffffffff; 501 - 502 - if (sht->virt_boundary_mask) 503 - shost->virt_boundary_mask = sht->virt_boundary_mask; 504 494 505 495 device_initialize(&shost->shost_gendev); 506 496 dev_set_name(&shost->shost_gendev, "host%d", shost->host_no);