Blame SOURCES/kvm-scsi-generic-prevent-guest-from-exceeding-SG_IO-limi.patch

7711c0
From ee5342df3b512da1ac1e85a7a65a50942d220019 Mon Sep 17 00:00:00 2001
7711c0
From: Stefan Hajnoczi <stefanha@redhat.com>
7711c0
Date: Wed, 24 Apr 2019 09:29:42 +0200
7711c0
Subject: [PATCH 02/12] scsi-generic: prevent guest from exceeding SG_IO limits
7711c0
7711c0
RH-Author: Stefan Hajnoczi <stefanha@redhat.com>
7711c0
Message-id: <20190424092942.29071-2-stefanha@redhat.com>
7711c0
Patchwork-id: 85876
7711c0
O-Subject: [RHEL-7.7 qemu-kvm-rhev PATCH 1/1] scsi-generic: prevent guest from exceeding SG_IO limits
7711c0
Bugzilla: 1693879
7711c0
RH-Acked-by: Sergio Lopez Pascual <slp@redhat.com>
7711c0
RH-Acked-by: Pankaj Gupta <pagupta@redhat.com>
7711c0
RH-Acked-by: Paolo Bonzini <pbonzini@redhat.com>
7711c0
RH-Acked-by: Stefano Garzarella <sgarzare@redhat.com>
7711c0
7711c0
From: Paolo Bonzini <pbonzini@redhat.com>
7711c0
7711c0
Bugzilla: 1693879
7711c0
Brew: https://brewweb.engineering.redhat.com/brew/taskinfo?taskID=21260328
7711c0
Upstream status: downstream only, see below
7711c0
7711c0
Until Linux 4.5, the kernel placed a limit of UIO_MAXIOV pages on
7711c0
SG_IO ioctls (and if the limit is exceeded, a confusing ENOMEM error is
7711c0
returned[1]).  The patches that removed the limitation are not easy to
7711c0
backport to RHEL7, so instead we work around it in QEMU: just prevent
7711c0
the guest from exceeding these limits by capping the maximum transfer
7711c0
length to that value in the block limits VPD page.
7711c0
7711c0
The customer has already tested the workaround of changing
7711c0
max_sectors_kb in the guest.  This fix has the same effect on the guest
7711c0
but does not require manually setting max_sectors_kb inside the guest.
7711c0
7711c0
RHEL8 does not have the problem; because this is for SCSI passthrough,
7711c0
live migration is not an issue.
7711c0
7711c0
[1] Oh well, at least it was easier to follow the kernel source knowing
7711c0
    it had to end as ENOMEM...
7711c0
7711c0
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
7711c0
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
7711c0
Signed-off-by: Miroslav Rezanina <mrezanin@redhat.com>
7711c0
---
7711c0
 hw/scsi/scsi-generic.c | 17 +++++++++++++----
7711c0
 1 file changed, 13 insertions(+), 4 deletions(-)
7711c0
7711c0
diff --git a/hw/scsi/scsi-generic.c b/hw/scsi/scsi-generic.c
7711c0
index e21adf9..b815b91 100644
7711c0
--- a/hw/scsi/scsi-generic.c
7711c0
+++ b/hw/scsi/scsi-generic.c
7711c0
@@ -144,6 +144,17 @@ static int execute_command(BlockBackend *blk,
7711c0
     return 0;
7711c0
 }
7711c0
 
7711c0
+/*
7711c0
+ * RHEL: Linux placed a hard limit on SG_IO transfers equal to UIO_MAXIOV
7711c0
+ * pages until 4.5, which we need to factor in the block limits we return.
7711c0
+ */
7711c0
+static uint32_t rhel_sg_max_transfer(SCSIDevice *s)
7711c0
+{
7711c0
+    uint32_t max_transfer = blk_get_max_transfer(s->conf.blk);
7711c0
+    max_transfer = MIN_NON_ZERO(max_transfer, UIO_MAXIOV * qemu_real_host_page_size);
7711c0
+    return max_transfer;
7711c0
+}
7711c0
+
7711c0
 static void scsi_handle_inquiry_reply(SCSIGenericReq *r, SCSIDevice *s)
7711c0
 {
7711c0
     uint8_t page, page_idx;
7711c0
@@ -175,10 +186,8 @@ static void scsi_handle_inquiry_reply(SCSIGenericReq *r, SCSIDevice *s)
7711c0
     if (s->type == TYPE_DISK && (r->req.cmd.buf[1] & 0x01)) {
7711c0
         page = r->req.cmd.buf[2];
7711c0
         if (page == 0xb0) {
7711c0
-            uint32_t max_transfer =
7711c0
-                blk_get_max_transfer(s->conf.blk) / s->blocksize;
7711c0
+            uint32_t max_transfer = rhel_sg_max_transfer(s) / s->blocksize;
7711c0
 
7711c0
-            assert(max_transfer);
7711c0
             stl_be_p(&r->buf[8], max_transfer);
7711c0
             /* Also take care of the opt xfer len. */
7711c0
             stl_be_p(&r->buf[12],
7711c0
@@ -219,7 +228,7 @@ static int scsi_generic_emulate_block_limits(SCSIGenericReq *r, SCSIDevice *s)
7711c0
     uint8_t buf[64];
7711c0
 
7711c0
     SCSIBlockLimits bl = {
7711c0
-        .max_io_sectors = blk_get_max_transfer(s->conf.blk) / s->blocksize
7711c0
+        .max_io_sectors = rhel_sg_max_transfer(s) / s->blocksize
7711c0
     };
7711c0
 
7711c0
     memset(r->buf, 0, r->buflen);
7711c0
-- 
7711c0
1.8.3.1
7711c0