thebeanogamer / rpms / qemu-kvm

Forked from rpms/qemu-kvm 5 months ago
Clone
1be5c7
From a9a4dfdd6312e192e9134d46edfac4c1b1bfa63d Mon Sep 17 00:00:00 2001
1be5c7
From: Kevin Wolf <kwolf@redhat.com>
1be5c7
Date: Mon, 22 Aug 2022 14:53:20 +0200
1be5c7
Subject: [PATCH] scsi-generic: Fix emulated block limits VPD page
1be5c7
1be5c7
RH-Author: Kevin Wolf <kwolf@redhat.com>
1be5c7
RH-MergeRequest: 212: scsi-generic: Fix emulated block limits VPD page
1be5c7
RH-Commit: [1/1] d3ba6b2e03039043716ddc6b7d4a424d92249081
1be5c7
RH-Bugzilla: 2120279
1be5c7
RH-Acked-by: Emanuele Giuseppe Esposito <eesposit@redhat.com>
1be5c7
RH-Acked-by: Hanna Reitz <hreitz@redhat.com>
1be5c7
RH-Acked-by: Paolo Bonzini <pbonzini@redhat.com>
1be5c7
RH-Acked-by: Stefan Hajnoczi <stefanha@redhat.com>
1be5c7
1be5c7
Commits 01ef8185b80 amd 24b36e9813e updated the way that the maximum
1be5c7
transfer length is calculated for patching block limits VPD page in an
1be5c7
INQUIRY response.
1be5c7
1be5c7
The same updates also need to be made for the case where the host device
1be5c7
does not support the block limits VPD page at all and we emulate the
1be5c7
whole page.
1be5c7
1be5c7
Without this fix, on host block devices a maximum transfer length of
1be5c7
(INT_MAX - sector_size) bytes is advertised to the guest, resulting in
1be5c7
I/O errors when a request that exceeds the host limits is made by the
1be5c7
guest. (Prior to commit 24b36e9813e, this code path would use the
1be5c7
max_transfer value from the host instead of INT_MAX, but still miss the
1be5c7
fix from 01ef8185b80 where max_transfer is also capped to max_iov
1be5c7
host pages, so it would be less wrong, but still wrong.)
1be5c7
1be5c7
Cc: qemu-stable@nongnu.org
1be5c7
Buglink: https://bugzilla.redhat.com/show_bug.cgi?id=2096251
1be5c7
Fixes: 01ef8185b809af9d287e1a03a3f9d8ea8231118a
1be5c7
Fixes: 24b36e9813ec15da7db62e3b3621730710c5f020
1be5c7
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
1be5c7
Message-Id: <20220822125320.48257-1-kwolf@redhat.com>
1be5c7
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
1be5c7
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
1be5c7
(cherry picked from commit 51e15194b0a091e5c40aab2eb234a1d36c5c58ee)
1be5c7
1be5c7
Resolved conflict: qemu_real_host_page_size() is a getter function in
1be5c7
current upstream, but still just a public global variable downstream.
1be5c7
1be5c7
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
1be5c7
---
1be5c7
 hw/scsi/scsi-generic.c | 21 ++++++++++++++-------
1be5c7
 1 file changed, 14 insertions(+), 7 deletions(-)
1be5c7
1be5c7
diff --git a/hw/scsi/scsi-generic.c b/hw/scsi/scsi-generic.c
1be5c7
index 0306ccc7b1..3742899839 100644
1be5c7
--- a/hw/scsi/scsi-generic.c
1be5c7
+++ b/hw/scsi/scsi-generic.c
1be5c7
@@ -147,6 +147,18 @@ static int execute_command(BlockBackend *blk,
1be5c7
     return 0;
1be5c7
 }
1be5c7
 
1be5c7
+static uint64_t calculate_max_transfer(SCSIDevice *s)
1be5c7
+{
1be5c7
+    uint64_t max_transfer = blk_get_max_hw_transfer(s->conf.blk);
1be5c7
+    uint32_t max_iov = blk_get_max_hw_iov(s->conf.blk);
1be5c7
+
1be5c7
+    assert(max_transfer);
1be5c7
+    max_transfer = MIN_NON_ZERO(max_transfer,
1be5c7
+                                max_iov * qemu_real_host_page_size);
1be5c7
+
1be5c7
+    return max_transfer / s->blocksize;
1be5c7
+}
1be5c7
+
1be5c7
 static int scsi_handle_inquiry_reply(SCSIGenericReq *r, SCSIDevice *s, int len)
1be5c7
 {
1be5c7
     uint8_t page, page_idx;
1be5c7
@@ -179,12 +191,7 @@ static int scsi_handle_inquiry_reply(SCSIGenericReq *r, SCSIDevice *s, int len)
1be5c7
         (r->req.cmd.buf[1] & 0x01)) {
1be5c7
         page = r->req.cmd.buf[2];
1be5c7
         if (page == 0xb0) {
1be5c7
-            uint64_t max_transfer = blk_get_max_hw_transfer(s->conf.blk);
1be5c7
-            uint32_t max_iov = blk_get_max_hw_iov(s->conf.blk);
1be5c7
-
1be5c7
-            assert(max_transfer);
1be5c7
-            max_transfer = MIN_NON_ZERO(max_transfer, max_iov * qemu_real_host_page_size)
1be5c7
-                / s->blocksize;
1be5c7
+            uint64_t max_transfer = calculate_max_transfer(s);
1be5c7
             stl_be_p(&r->buf[8], max_transfer);
1be5c7
             /* Also take care of the opt xfer len. */
1be5c7
             stl_be_p(&r->buf[12],
1be5c7
@@ -230,7 +237,7 @@ static int scsi_generic_emulate_block_limits(SCSIGenericReq *r, SCSIDevice *s)
1be5c7
     uint8_t buf[64];
1be5c7
 
1be5c7
     SCSIBlockLimits bl = {
1be5c7
-        .max_io_sectors = blk_get_max_transfer(s->conf.blk) / s->blocksize
1be5c7
+        .max_io_sectors = calculate_max_transfer(s),
1be5c7
     };
1be5c7
 
1be5c7
     memset(r->buf, 0, r->buflen);
1be5c7
-- 
1be5c7
2.35.3
1be5c7