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

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