All of lore.kernel.org
 help / color / mirror / Atom feed
* Re: Subject: [Bug] VPD Page 0xb0 Block Limits incorrectly emulated in scsi-generic causing guest mkfs.xfs failure
@ 2026-10-14  2:06 Wangyong
  0 siblings, 0 replies; 4+ messages in thread
From: Wangyong @ 2026-10-14  2:06 UTC (permalink / raw)
  To: Kevin Wolf; +Cc: pbonzini@redhat.com, hreitz@redhat.com, qemu-devel@nongnu.org

[-- Attachment #1: Type: text/plain, Size: 7626 bytes --]

Am 13.10.2026 um 10:32 hat Wangyong geschrieben:


Thank you for looking into this.



> Hi,

>

> I'm reporting a bug where VPD Page 0xb0 (Block Limits) is incorrectly

> emulated in QEMU's scsi-generic driver, causing guest VMs to fail

> operations like mkfs.xfs.

>

> Summary:

> When using QEMU stale-11.0 with scsi-block passthrough, the Optimal

> Transfer Length (and related fields) in VPD Page 0xb0 are incorrectly

> capped to a much smaller value than what the host device reports. This

> is caused by commit 3cb29058 which modified blk_get_max_transfer() to

> no longer check bs->bl.max_hw_transfer, and the scsi-generic code at

> line 194-198 uses this function to compute VPD fields(Optimal Transfer

> Length).



> My git repository doesn't contain a commit 3cb29058. Please specify where you got your copy of the QEMU code from.



The issue is related to the following patches:

01ef818 scsi-generic: pass max_segments via max_iov field in BlockLimits

1847346 file-posix: try BLKSECTGET on block devices too, do not round to power of 2

cc071629 block: introduce max_hw_iov for use in scsi-generic


We changed the code to use blk_get_max_hw_transfer() and blk_get_max_hw_iov for both offset 8 and offset 12:

stl_be_p(&buf[8], max_transfer);

stl_be_p(&buf[12], MIN_NON_ZERO(max_transfer, ldl_be_p(&buf[12])));



> Environment:

> Host: Linux with multipath + LUN

> Guest: Linux VM with QEMU 11.0 scsi-block passthrough Host kernel:

> 6.6.0

Supplement information:

[root@ ~]# lspci |grep Emu

02:00.0 Fibre Channel: Emulex Corporation LPe15000/LPe16000 Series 8Gb/16Gb Fibre Channel Adapter (rev 30)

02:00.1 Fibre Channel: Emulex Corporation LPe15000/LPe16000 Series 8Gb/16Gb Fibre Channel Adapter (rev 30)



[root@ ~]# cat /sys/block/dm-1/queue/max_segments

64

[root@ ~]# cat /sys/block/sdd/queue/max_segments

64

>

> Reproduction Steps:

> Set up a multipath environment with a LUN (physical disk with stripe

> geometry) Pass the LUN through to a QEMU VM using scsi-block:

> -device virtio-scsi-pci,id=scsi0,bus=pci.0,addr=0xa \ -drive

> file=/dev/disk/by-id/dm-name-36000d310057df8000000000000000969,format=

> raw,if=none,id=drive-scsi0-0-0-0,cache=none,aio=native \ -device

> scsi-block,bus=scsi0.0,channel=0,scsi-id=0,lun=0,drive=drive-scsi0-0-0

> -0,id=scsi0-0-0-0\

>

> Inside the VM, run mkfs.xfs /dev/sda

>

> Expected Behavior:

> mkfs.xfs should succeed

> VPD Page 0xb0 should report Optimal transfer length matching the

> host's RAID stripe size

>

> Actual Behavior:

> 1. mkfs.xfs fails inside VM

> SB stripe unit sanity check failed

> Metadata corruption detected at 0x...

> xfx_sb block 0x0/0x1000

> libxfs_bwrite: write verifier failed

> SB stripe unit sanity check failed

> AG 0x0 unlinked bucket sanity check failed

> mkfs.xfs: writing AG headers failed, err=117

>

> Note: No error in dmesg because XFS failed during in-memory superblock construction, never issuing actual I/O.

>

> mkfs.xfs -f -d su=0.sw=0 /dev/sda
Disabling striping in mkfs can be verified through testing.



> 2. VPD comparison between host and guest Host (sg_vpd -p 0xb0

> /dev/disk/by-id/dm-name-36000d310057df8000000000000000969)

> Block limits VPD page (SBC)

>   Write same non-zero (WSNZ): 0

>   Maximum compare and write length: 0x1

>   Optimal transfer length granularity: 0x1000

>   Maximum transfer length: 0 blocks [not reported]

>   Optimal transfer length: 0x1000

>   Maximum prefetch length: 0 blocks [not reported]

>   Maximum unmap LBA count: 0x200000

>   Maximum unmap block descriptor count: 0x1

>   Optimal unmap granularity: 0x1000

>   Unmap granularity alignment valid: true

>   Unmap granularity alignment: 0x0

>   Maximum write same length: 0 blocks [not reported]

>   Maximum atomic transfer length: 0 blocks [not reported]

>   Atomic alignment: 0 blocks [unaligned atomic writes permitted]

>   Atomic transfer length granularity: 0 blocks [no granularity requirement]

>   Maximum atomic transfer length with atomic boundary: 0 blocks [not reported]

>   Maximum atomic boundary size: 0 blocks [can only write atomic 1

> block]

> [root@cvknode151 ~]# ll

> /dev/disk/by-id/dm-name-36000d310057df8000000000000000969

> lrwxrwxrwx 1 root root 10 Oct 13 15:55

> /dev/disk/by-id/dm-name-36000d310057df8000000000000000969 ->

> ../../dm-1

> [root@cvknode151 ~]# cat /sys/block/dm-1/queue/max_segments

> 64

> Guest (sg_vpd -p 0xb0 /dev/sda):

> Block limits VPD page (SBC):

>   Write same non-zero (WSNZ): 0

>   Maximum compare and write length: 1 blocks

>   Optimal transfer length granularity: 4096 blocks

>   Maximum transfer length: 512 blocks

>   Optimal transfer length: 512 blocks     ← INCORRECT

>   Maximum prefetch transfer length: 0 blocks [ignored]

>   Maximum unmap LBA count: 2097152

>   Maximum unmap block descriptor count: 1

>   Optimal unmap granularity: 4096 blocks

>   Unmap granularity alignment valid: true

>   Unmap granularity alignment: 0

>   Maximum write same length: 0 blocks [not reported]

>   Maximum atomic transfer length: 0 blocks [not reported]

>   Atomic alignment: 0 [unaligned atomic writes permitted]

>   Atomic transfer length granularity: 0 [no granularity requirement

>   Maximum atomic transfer length with atomic boundary: 0 blocks [not reported]

>   Maximum atomic boundary size: 0 blocks [can only write atomic 1

> block]

>

> Restore "opt xfer len" to before modification, mkfs.xfs can pass the

> test

>

> @@ -169,15 +169,15 @@ static void scsi_handle_inquiry_reply(SCSIGenericReq *r, SCSIDevice *s)

>          if (page == 0xb0) {

> +            uint32_t max_transfer_opt =

> + blk_get_max_transfer(s->conf.blk) / s->blocksize;

>

>              assert(max_transfer);

>              max_transfer = MIN_NON_ZERO(max_transfer, max_iov * qemu_real_host_page_size)

>                  / s->blocksize;

>              stl_be_p(&r->buf[8], max_transfer);

>              /* Also take care of the opt xfer len. */

>              stl_be_p(&r->buf[12],

> -                    MIN_NON_ZERO(max_transfer, ldl_be_p(&r->buf[12])));

> +                    MIN_NON_ZERO(max_transfer_opt,

> + ldl_be_p(&r->buf[12])));

>          } else if (s->needs_vpd_bl_emulation && page == 0x00 && r->buflen >= 4) {

>              /*

>               * Now we're capable of supplying the VPD Block Limits



> Code that roughly looked like this existed in QEMU 7.0 and earlier. You said you're using QEMU 11.0, so it shouldn't exist in your code.

Sorry, update



+++ b/hw/scsi/scsi-generic.c

@@ -192,10 +192,11 @@ static int scsi_handle_inquiry_reply(SCSIGenericReq *r, SCSIDevice *s, int len)

             uint8_t buf[16] = {};

             uint8_t buf_used = MIN(r->buflen, 16);

             uint64_t max_transfer = calculate_max_transfer(s);

+            uint32_t max_transfer_opt = blk_get_max_transfer(s->conf.blk) / s->blocksize;



             memcpy(buf, r->buf, buf_used);

             stl_be_p(&buf[8], max_transfer);

-            stl_be_p(&buf[12], MIN_NON_ZERO(max_transfer, ldl_be_p(&buf[12])));

+            stl_be_p(&buf[12], MIN_NON_ZERO(max_transfer_opt, ldl_be_p(&buf[12])));

             memcpy(r->buf + 8, buf + 8, buf_used - 8);



         } else if (s->needs_vpd_bl_emulation && page == 0x00 && r->buflen >= 4) {



Kevin



[-- Attachment #2: Type: text/html, Size: 23167 bytes --]

^ permalink raw reply	[flat|nested] 4+ messages in thread
* Re: Subject: [Bug] VPD Page 0xb0 Block Limits incorrectly emulated in scsi-generic causing guest mkfs.xfs failure
@ 2026-10-14  2:21 Wangyong
  0 siblings, 0 replies; 4+ messages in thread
From: Wangyong @ 2026-10-14  2:21 UTC (permalink / raw)
  To: Kevin Wolf; +Cc: pbonzini@redhat.com, hreitz@redhat.com, qemu-devel@nongnu.org

Am 13.10.2026 um 10:32 hat Wangyong geschrieben:

> Hi,
>
> I'm reporting a bug where VPD Page 0xb0 (Block Limits) is incorrectly 
> emulated in QEMU's scsi-generic driver, causing guest VMs to fail 
> operations like mkfs.xfs.
>
> Summary:
> When using QEMU stale-11.0 with scsi-block passthrough, the Optimal 
> Transfer Length (and related fields) in VPD Page 0xb0 are incorrectly 
> capped to a much smaller value than what the host device reports. This 
> is caused by commit 3cb29058 which modified blk_get_max_transfer() to 
> no longer check bs->bl.max_hw_transfer, and the scsi-generic code at 
> line 194-198 uses this function to compute VPD fields(Optimal Transfer 
> Length).

> My git repository doesn't contain a commit 3cb29058. Please specify where you got your copy of the QEMU code from.

Thank you for looking into this.
The issue is related to the following patches:

01ef818 scsi-generic: pass max_segments via max_iov field in BlockLimits
1847346 file-posix: try BLKSECTGET on block devices too, do not round to power of 2
cc071629 block: introduce max_hw_iov for use in scsi-generic

> Environment:
> Host: Linux with multipath + LUN
> Guest: Linux VM with QEMU 11.0 scsi-block passthrough Host kernel: 
> 6.6.0
>
Supplement hardware information:

[root@ ~]# lspci |grep Emu
02:00.0 Fibre Channel: Emulex Corporation LPe15000/LPe16000 Series 8Gb/16Gb Fibre Channel Adapter (rev 30)
02:00.1 Fibre Channel: Emulex Corporation LPe15000/LPe16000 Series 8Gb/16Gb Fibre Channel Adapter (rev 30)

[root@ ~]# cat /sys/block/dm-1/queue/max_segments
64
[root@ ~]# cat /sys/block/sdd/queue/max_segments
64

> Reproduction Steps:
> Set up a multipath environment with a LUN (physical disk with stripe
> geometry) Pass the LUN through to a QEMU VM using scsi-block:
> -device virtio-scsi-pci,id=scsi0,bus=pci.0,addr=0xa \ -drive 
> file=/dev/disk/by-id/dm-name-36000d310057df8000000000000000969,format=
> raw,if=none,id=drive-scsi0-0-0-0,cache=none,aio=native \ -device
> scsi-block,bus=scsi0.0,channel=0,scsi-id=0,lun=0,drive=drive-scsi0-0-0
> -0,id=scsi0-0-0-0\
>
> Inside the VM, run mkfs.xfs /dev/sda
>
> Expected Behavior:
> mkfs.xfs should succeed
> VPD Page 0xb0 should report Optimal transfer length matching the 
> host's RAID stripe size
>
> Actual Behavior:
> 1. mkfs.xfs fails inside VM
> SB stripe unit sanity check failed
> Metadata corruption detected at 0x...
> xfx_sb block 0x0/0x1000
> libxfs_bwrite: write verifier failed
> SB stripe unit sanity check failed
> AG 0x0 unlinked bucket sanity check failed
> mkfs.xfs: writing AG headers failed, err=117
>
> Note: No error in dmesg because XFS failed during in-memory superblock construction, never issuing actual I/O.
>
> mkfs.xfs -f -d su=0.sw=0 /dev/sda
Disabling striping in mkfs can be verified through testing.

> 2. VPD comparison between host and guest Host (sg_vpd -p 0xb0
> /dev/disk/by-id/dm-name-36000d310057df8000000000000000969)
> Block limits VPD page (SBC)
>   Write same non-zero (WSNZ): 0
>   Maximum compare and write length: 0x1
>   Optimal transfer length granularity: 0x1000
>   Maximum transfer length: 0 blocks [not reported]
>   Optimal transfer length: 0x1000
>   Maximum prefetch length: 0 blocks [not reported]
>   Maximum unmap LBA count: 0x200000
>   Maximum unmap block descriptor count: 0x1
>   Optimal unmap granularity: 0x1000
>   Unmap granularity alignment valid: true
>   Unmap granularity alignment: 0x0
>   Maximum write same length: 0 blocks [not reported]
>   Maximum atomic transfer length: 0 blocks [not reported]
>   Atomic alignment: 0 blocks [unaligned atomic writes permitted]
>   Atomic transfer length granularity: 0 blocks [no granularity requirement]
>   Maximum atomic transfer length with atomic boundary: 0 blocks [not reported]
>   Maximum atomic boundary size: 0 blocks [can only write atomic 1 
> block]
> [root@cvknode151 ~]# ll
> /dev/disk/by-id/dm-name-36000d310057df8000000000000000969
> lrwxrwxrwx 1 root root 10 Oct 13 15:55
> /dev/disk/by-id/dm-name-36000d310057df8000000000000000969 ->
> ../../dm-1
> [root@cvknode151 ~]# cat /sys/block/dm-1/queue/max_segments
> 64
> Guest (sg_vpd -p 0xb0 /dev/sda):
> Block limits VPD page (SBC):
>   Write same non-zero (WSNZ): 0
>   Maximum compare and write length: 1 blocks
>   Optimal transfer length granularity: 4096 blocks
>   Maximum transfer length: 512 blocks
>   Optimal transfer length: 512 blocks     ← INCORRECT
>   Maximum prefetch transfer length: 0 blocks [ignored]
>   Maximum unmap LBA count: 2097152
>   Maximum unmap block descriptor count: 1
>   Optimal unmap granularity: 4096 blocks
>   Unmap granularity alignment valid: true
>   Unmap granularity alignment: 0
>   Maximum write same length: 0 blocks [not reported]
>   Maximum atomic transfer length: 0 blocks [not reported]
>   Atomic alignment: 0 [unaligned atomic writes permitted]
>   Atomic transfer length granularity: 0 [no granularity requirement
>   Maximum atomic transfer length with atomic boundary: 0 blocks [not reported]
>   Maximum atomic boundary size: 0 blocks [can only write atomic 1 
> block]
>
> Restore "opt xfer len" to before modification, mkfs.xfs can pass the 
> test
>
> @@ -169,15 +169,15 @@ static void scsi_handle_inquiry_reply(SCSIGenericReq *r, SCSIDevice *s)
>          if (page == 0xb0) {
> +            uint32_t max_transfer_opt =
> + blk_get_max_transfer(s->conf.blk) / s->blocksize;
>
>              assert(max_transfer);
>              max_transfer = MIN_NON_ZERO(max_transfer, max_iov * qemu_real_host_page_size)
>                  / s->blocksize;
>              stl_be_p(&r->buf[8], max_transfer);
>              /* Also take care of the opt xfer len. */
>              stl_be_p(&r->buf[12],
> -                    MIN_NON_ZERO(max_transfer, ldl_be_p(&r->buf[12])));
> +                    MIN_NON_ZERO(max_transfer_opt, 
> + ldl_be_p(&r->buf[12])));
>          } else if (s->needs_vpd_bl_emulation && page == 0x00 && r->buflen >= 4) {
>              /*
>               * Now we're capable of supplying the VPD Block Limits

> Code that roughly looked like this existed in QEMU 7.0 and earlier. You said you're using QEMU 11.0, so it shouldn't exist in your code.
Update

+++ b/hw/scsi/scsi-generic.c
@@ -192,10 +192,11 @@ static int scsi_handle_inquiry_reply(SCSIGenericReq *r, SCSIDevice *s, int len)
             uint8_t buf[16] = {};
             uint8_t buf_used = MIN(r->buflen, 16);
             uint64_t max_transfer = calculate_max_transfer(s);
+            uint32_t max_transfer_opt = blk_get_max_transfer(s->conf.blk) / s->blocksize;

             memcpy(buf, r->buf, buf_used);
             stl_be_p(&buf[8], max_transfer);
-            stl_be_p(&buf[12], MIN_NON_ZERO(max_transfer, ldl_be_p(&buf[12])));
+            stl_be_p(&buf[12], MIN_NON_ZERO(max_transfer_opt, ldl_be_p(&buf[12])));
             memcpy(r->buf + 8, buf + 8, buf_used - 8);

         } else if (s->needs_vpd_bl_emulation && page == 0x00 && r->buflen >= 4) {

wangyong



^ permalink raw reply	[flat|nested] 4+ messages in thread
* Subject: [Bug] VPD Page 0xb0 Block Limits incorrectly emulated in scsi-generic causing guest mkfs.xfs failure
@ 2026-10-13  8:32 Wangyong
  2026-10-13 13:51 ` Kevin Wolf
  0 siblings, 1 reply; 4+ messages in thread
From: Wangyong @ 2026-10-13  8:32 UTC (permalink / raw)
  To: pbonzini@redhat.com, kwolf@redhat.com, mreitz@redhat.com
  Cc: qemu-devel@nongnu.org

[-- Attachment #1: Type: text/plain, Size: 5061 bytes --]

Hi,

I'm reporting a bug where VPD Page 0xb0 (Block Limits) is incorrectly emulated in QEMU's scsi-generic driver, causing guest VMs to fail operations like mkfs.xfs.

Summary:
When using QEMU stale-11.0 with scsi-block passthrough, the Optimal Transfer Length (and related fields) in VPD Page 0xb0 are incorrectly capped to a much smaller value than what the host device reports. This is caused by commit 3cb29058 which modified blk_get_max_transfer() to no longer check bs->bl.max_hw_transfer, and the scsi-generic code at line 194-198 uses this function to compute VPD fields(Optimal Transfer Length).

Environment:
Host: Linux with multipath + LUN
Guest: Linux VM with QEMU 11.0 scsi-block passthrough
Host kernel: 6.6.0

Reproduction Steps:
Set up a multipath environment with a LUN (physical disk with stripe geometry)
Pass the LUN through to a QEMU VM using scsi-block:
-device virtio-scsi-pci,id=scsi0,bus=pci.0,addr=0xa \
-drive file=/dev/disk/by-id/dm-name-36000d310057df8000000000000000969,format=raw,if=none,id=drive-scsi0-0-0-0,cache=none,aio=native \
-device scsi-block,bus=scsi0.0,channel=0,scsi-id=0,lun=0,drive=drive-scsi0-0-0-0,id=scsi0-0-0-0\

Inside the VM, run mkfs.xfs /dev/sda

Expected Behavior:
mkfs.xfs should succeed
VPD Page 0xb0 should report Optimal transfer length matching the host's RAID stripe size

Actual Behavior:
1. mkfs.xfs fails inside VM
SB stripe unit sanity check failed
Metadata corruption detected at 0x...
xfx_sb block 0x0/0x1000
libxfs_bwrite: write verifier failed
SB stripe unit sanity check failed
AG 0x0 unlinked bucket sanity check failed
mkfs.xfs: writing AG headers failed, err=117

Note: No error in dmesg because XFS failed during in-memory superblock construction, never issuing actual I/O.

mkfs.xfs -f -d su=0.sw=0 /dev/sda
2. VPD comparison between host and guest
Host (sg_vpd -p 0xb0 /dev/disk/by-id/dm-name-36000d310057df8000000000000000969)
Block limits VPD page (SBC)
  Write same non-zero (WSNZ): 0
  Maximum compare and write length: 0x1
  Optimal transfer length granularity: 0x1000
  Maximum transfer length: 0 blocks [not reported]
  Optimal transfer length: 0x1000
  Maximum prefetch length: 0 blocks [not reported]
  Maximum unmap LBA count: 0x200000
  Maximum unmap block descriptor count: 0x1
  Optimal unmap granularity: 0x1000
  Unmap granularity alignment valid: true
  Unmap granularity alignment: 0x0
  Maximum write same length: 0 blocks [not reported]
  Maximum atomic transfer length: 0 blocks [not reported]
  Atomic alignment: 0 blocks [unaligned atomic writes permitted]
  Atomic transfer length granularity: 0 blocks [no granularity requirement]
  Maximum atomic transfer length with atomic boundary: 0 blocks [not reported]
  Maximum atomic boundary size: 0 blocks [can only write atomic 1 block]
[root@cvknode151 ~]# ll /dev/disk/by-id/dm-name-36000d310057df8000000000000000969
lrwxrwxrwx 1 root root 10 Oct 13 15:55 /dev/disk/by-id/dm-name-36000d310057df8000000000000000969 -> ../../dm-1
[root@cvknode151 ~]# cat /sys/block/dm-1/queue/max_segments
64
Guest (sg_vpd -p 0xb0 /dev/sda):
Block limits VPD page (SBC):
  Write same non-zero (WSNZ): 0
  Maximum compare and write length: 1 blocks
  Optimal transfer length granularity: 4096 blocks
  Maximum transfer length: 512 blocks
  Optimal transfer length: 512 blocks     ← INCORRECT
  Maximum prefetch transfer length: 0 blocks [ignored]
  Maximum unmap LBA count: 2097152
  Maximum unmap block descriptor count: 1
  Optimal unmap granularity: 4096 blocks
  Unmap granularity alignment valid: true
  Unmap granularity alignment: 0
  Maximum write same length: 0 blocks [not reported]
  Maximum atomic transfer length: 0 blocks [not reported]
  Atomic alignment: 0 [unaligned atomic writes permitted]
  Atomic transfer length granularity: 0 [no granularity requirement
  Maximum atomic transfer length with atomic boundary: 0 blocks [not reported]
  Maximum atomic boundary size: 0 blocks [can only write atomic 1 block]

Restore "opt xfer len" to before modification, mkfs.xfs can pass the test

@@ -169,15 +169,15 @@ static void scsi_handle_inquiry_reply(SCSIGenericReq *r, SCSIDevice *s)
         if (page == 0xb0) {
+            uint32_t max_transfer_opt = blk_get_max_transfer(s->conf.blk) / s->blocksize;

             assert(max_transfer);
             max_transfer = MIN_NON_ZERO(max_transfer, max_iov * qemu_real_host_page_size)
                 / s->blocksize;
             stl_be_p(&r->buf[8], max_transfer);
             /* Also take care of the opt xfer len. */
             stl_be_p(&r->buf[12],
-                    MIN_NON_ZERO(max_transfer, ldl_be_p(&r->buf[12])));
+                    MIN_NON_ZERO(max_transfer_opt, ldl_be_p(&r->buf[12])));
         } else if (s->needs_vpd_bl_emulation && page == 0x00 && r->buflen >= 4) {
             /*
              * Now we're capable of supplying the VPD Block Limits


Please let me know if you need any additional information.

Best regards,
wangyong




[-- Attachment #2: Type: text/html, Size: 16847 bytes --]

^ permalink raw reply	[flat|nested] 4+ messages in thread

end of thread, other threads:[~2026-10-14  2:22 UTC | newest]

Thread overview: 4+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-10-14  2:06 Subject: [Bug] VPD Page 0xb0 Block Limits incorrectly emulated in scsi-generic causing guest mkfs.xfs failure Wangyong
  -- strict thread matches above, loose matches on Subject: below --
2026-10-14  2:21 Wangyong
2026-10-13  8:32 Wangyong
2026-10-13 13:51 ` Kevin Wolf

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.