All of lore.kernel.org
 help / color / mirror / Atom feed
* [Qemu-devel] [PATCH] scsi-generic: prevent guest from exceeding SG_IO limits
@ 2019-04-17 11:53 ` Paolo Bonzini
  0 siblings, 0 replies; 14+ messages in thread
From: Paolo Bonzini @ 2019-04-17 11:53 UTC (permalink / raw)
  To: qemu-devel; +Cc: qemu-stable, qemu-block, Stefan Hajnoczi

Linux places a limit of UIO_MAXIOV pages on SG_IO ioctls (and if the limit
is exceeded, a confusing ENOMEM error is returned[1]).  Prevent the guest
from exceeding these limits, by capping the maximum transfer length to
that value in the block limits VPD page.

[1] Oh well, at least it was easier to follow the kernel source knowing
    it had to end as ENOMEM...

Cc: qemu-stable@nongnu.org
Cc: qemu-block@nongnu.org
Cc: Stefan Hajnoczi <stefanha@redhat.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
---
 hw/scsi/scsi-generic.c | 17 +++++++++++++----
 1 file changed, 13 insertions(+), 4 deletions(-)

diff --git a/hw/scsi/scsi-generic.c b/hw/scsi/scsi-generic.c
index d82b462be4..4134d8389b 100644
--- a/hw/scsi/scsi-generic.c
+++ b/hw/scsi/scsi-generic.c
@@ -131,6 +131,17 @@ static int execute_command(BlockBackend *blk,
     return 0;
 }
 
+/*
+ * Linux places a hard limit on SG_IO transfers equal to UIO_MAXIOV
+ * pages, which we need to factor in the block limits we return.
+ */
+static uint32_t sg_max_transfer(SCSIDevice *s)
+{
+    uint32_t max_transfer = blk_get_max_transfer(s->conf.blk);
+    max_transfer = MIN_NON_ZERO(max_transfer, UIO_MAXIOV * qemu_real_host_page_size);
+    return max_transfer / s->blocksize;
+}
+
 static void scsi_handle_inquiry_reply(SCSIGenericReq *r, SCSIDevice *s)
 {
     uint8_t page, page_idx;
@@ -162,10 +173,8 @@ static void scsi_handle_inquiry_reply(SCSIGenericReq *r, SCSIDevice *s)
     if (s->type == TYPE_DISK && (r->req.cmd.buf[1] & 0x01)) {
         page = r->req.cmd.buf[2];
         if (page == 0xb0) {
-            uint32_t max_transfer =
-                blk_get_max_transfer(s->conf.blk) / s->blocksize;
+            uint32_t max_transfer = sg_max_transfer(s);
 
-            assert(max_transfer);
             stl_be_p(&r->buf[8], max_transfer);
             /* Also take care of the opt xfer len. */
             stl_be_p(&r->buf[12],
@@ -206,7 +215,7 @@ static int scsi_generic_emulate_block_limits(SCSIGenericReq *r, SCSIDevice *s)
     uint8_t buf[64];
 
     SCSIBlockLimits bl = {
-        .max_io_sectors = blk_get_max_transfer(s->conf.blk) / s->blocksize
+        .max_io_sectors = sg_max_transfer(s)
     };
 
     memset(r->buf, 0, r->buflen);
-- 
2.21.0

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

end of thread, other threads:[~2019-04-18 11:42 UTC | newest]

Thread overview: 14+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2019-04-17 11:53 [Qemu-devel] [PATCH] scsi-generic: prevent guest from exceeding SG_IO limits Paolo Bonzini
2019-04-17 11:53 ` Paolo Bonzini
2019-04-17 12:30 ` [Qemu-devel] [Qemu-block] " Stefan Hajnoczi
2019-04-17 12:30   ` Stefan Hajnoczi
2019-04-18  9:48   ` Paolo Bonzini
2019-04-18  9:48     ` Paolo Bonzini
2019-04-18 10:47     ` Kevin Wolf
2019-04-18 10:47       ` Kevin Wolf
2019-04-18 11:01       ` Paolo Bonzini
2019-04-18 11:01         ` Paolo Bonzini
2019-04-18 11:23         ` Kevin Wolf
2019-04-18 11:23           ` Kevin Wolf
2019-04-18 11:32       ` Daniel P. Berrangé
2019-04-18 11:32         ` Daniel P. Berrangé

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.