|
|
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 |
|