ソースを参照

Merge remote-tracking branch 'remotes/bonzini-gitlab/tags/for-upstream' into staging

* fix tracing vs -daemonize (Daniel)
* detect invalid CFI configuration (Daniele)
* 32-bit PVH fix (David)
* forward SCSI passthrough host-status to the SCSI HBA (Hannes)
* detect ill-formed id in QMP object-add (Kevin)
* miscellaneous bugfixes and cleanups (Keqian, Kostiantyn, myself, Peng Liang)
* add nodelay option for chardev (myself)
* deprecate -M kernel-irqchip=off on x86 (myself)
* keep .d files (myself)
* Fix -trace file (myself)

# gpg: Signature made Sat 06 Mar 2021 10:43:12 GMT
# gpg:                using RSA key F13338574B662389866C7682BFFBD25F78C7AE83
# gpg:                issuer "pbonzini@redhat.com"
# gpg: Good signature from "Paolo Bonzini <bonzini@gnu.org>" [full]
# gpg:                 aka "Paolo Bonzini <pbonzini@redhat.com>" [full]
# Primary key fingerprint: 46F5 9FBD 57D6 12E7 BFD4  E2F7 7E15 100C CD36 69B1
#      Subkey fingerprint: F133 3857 4B66 2389 866C  7682 BFFB D25F 78C7 AE83

* remotes/bonzini-gitlab/tags/for-upstream: (23 commits)
  meson: Stop if cfi is enabled with system slirp
  trace: skip qemu_set_log_filename if no "-D" option was passed
  trace: fix "-trace file=..."
  meson: adjust timeouts for some slower tests
  build-sys: invoke ninja with -d keepdepfile
  qemu-option: do not suggest using the delay option
  scsi: move host_status handling into SCSI drivers
  scsi: inline sg_io_sense_from_errno() into the callers.
  scsi-generic: do not snoop the output of failed commands
  scsi: Add mapping for generic SCSI_HOST status to sense codes
  scsi: Rename linux-specific SG_ERR codes to generic SCSI_HOST error codes
  qemu-config: add error propagation to qemu_config_parse
  x86/pvh: extract only 4 bytes of start address for 32 bit kernels
  elf_ops: correct loading of 32 bit PVH kernel
  lsilogic: Use PCIDevice::exit instead of DeviceState::unrealize
  accel: kvm: Add aligment assert for kvm_log_clear_one_slot
  accel: kvm: Fix memory waste under mismatch page size
  vl.c: do not execute trace_init_backends() before daemonizing
  qom: Check for wellformed id in user_creatable_add_type()
  chardev: add nodelay option
  ...

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
Peter Maydell 4 年 前
コミット
0436c55edf

+ 1 - 1
Makefile

@@ -149,7 +149,7 @@ $(ninja-targets): run-ninja
 # --output-sync line.
 # --output-sync line.
 run-ninja: config-host.mak
 run-ninja: config-host.mak
 ifneq ($(filter $(ninja-targets), $(ninja-cmd-goals)),)
 ifneq ($(filter $(ninja-targets), $(ninja-cmd-goals)),)
-	+$(quiet-@)$(if $(MAKE.nq),@:, $(NINJA) \
+	+$(quiet-@)$(if $(MAKE.nq),@:, $(NINJA) -d keepdepfile \
 	   $(NINJAFLAGS) $(sort $(filter $(ninja-targets), $(ninja-cmd-goals))) | cat)
 	   $(NINJAFLAGS) $(sort $(filter $(ninja-targets), $(ninja-cmd-goals))) | cat)
 endif
 endif
 endif
 endif

+ 12 - 1
accel/kvm/kvm-all.c

@@ -598,8 +598,12 @@ static void kvm_memslot_init_dirty_bitmap(KVMSlot *mem)
      * too, in most cases).
      * too, in most cases).
      * So for now, let's align to 64 instead of HOST_LONG_BITS here, in
      * So for now, let's align to 64 instead of HOST_LONG_BITS here, in
      * a hope that sizeof(long) won't become >8 any time soon.
      * a hope that sizeof(long) won't become >8 any time soon.
+     *
+     * Note: the granule of kvm dirty log is qemu_real_host_page_size.
+     * And mem->memory_size is aligned to it (otherwise this mem can't
+     * be registered to KVM).
      */
      */
-    hwaddr bitmap_size = ALIGN(((mem->memory_size) >> TARGET_PAGE_BITS),
+    hwaddr bitmap_size = ALIGN(mem->memory_size / qemu_real_host_page_size,
                                         /*HOST_LONG_BITS*/ 64) / 8;
                                         /*HOST_LONG_BITS*/ 64) / 8;
     mem->dirty_bmap = g_malloc0(bitmap_size);
     mem->dirty_bmap = g_malloc0(bitmap_size);
 }
 }
@@ -669,6 +673,10 @@ out:
 #define KVM_CLEAR_LOG_ALIGN  (qemu_real_host_page_size << KVM_CLEAR_LOG_SHIFT)
 #define KVM_CLEAR_LOG_ALIGN  (qemu_real_host_page_size << KVM_CLEAR_LOG_SHIFT)
 #define KVM_CLEAR_LOG_MASK   (-KVM_CLEAR_LOG_ALIGN)
 #define KVM_CLEAR_LOG_MASK   (-KVM_CLEAR_LOG_ALIGN)
 
 
+/*
+ * As the granule of kvm dirty log is qemu_real_host_page_size,
+ * @start and @size are expected and restricted to align to it.
+ */
 static int kvm_log_clear_one_slot(KVMSlot *mem, int as_id, uint64_t start,
 static int kvm_log_clear_one_slot(KVMSlot *mem, int as_id, uint64_t start,
                                   uint64_t size)
                                   uint64_t size)
 {
 {
@@ -678,6 +686,9 @@ static int kvm_log_clear_one_slot(KVMSlot *mem, int as_id, uint64_t start,
     unsigned long *bmap_clear = NULL, psize = qemu_real_host_page_size;
     unsigned long *bmap_clear = NULL, psize = qemu_real_host_page_size;
     int ret;
     int ret;
 
 
+    /* Make sure start and size are qemu_real_host_page_size aligned */
+    assert(QEMU_IS_ALIGNED(start | size, psize));
+
     /*
     /*
      * We need to extend either the start or the size or both to
      * We need to extend either the start or the size or both to
      * satisfy the KVM interface requirement.  Firstly, do the start
      * satisfy the KVM interface requirement.  Firstly, do the start

+ 1 - 2
block/blkdebug.c

@@ -279,9 +279,8 @@ static int read_config(BDRVBlkdebugState *s, const char *filename,
             return -errno;
             return -errno;
         }
         }
 
 
-        ret = qemu_config_parse(f, config_groups, filename);
+        ret = qemu_config_parse(f, config_groups, filename, errp);
         if (ret < 0) {
         if (ret < 0) {
-            error_setg(errp, "Could not parse blkdebug config file");
             goto fail;
             goto fail;
         }
         }
     }
     }

+ 11 - 2
chardev/char-socket.c

@@ -1472,8 +1472,17 @@ static void qemu_chr_parse_socket(QemuOpts *opts, ChardevBackend *backend,
     sock = backend->u.socket.data = g_new0(ChardevSocket, 1);
     sock = backend->u.socket.data = g_new0(ChardevSocket, 1);
     qemu_chr_parse_common(opts, qapi_ChardevSocket_base(sock));
     qemu_chr_parse_common(opts, qapi_ChardevSocket_base(sock));
 
 
-    sock->has_nodelay = qemu_opt_get(opts, "delay");
-    sock->nodelay = !qemu_opt_get_bool(opts, "delay", true);
+    if (qemu_opt_get(opts, "delay") && qemu_opt_get(opts, "nodelay")) {
+        error_setg(errp, "'delay' and 'nodelay' are mutually exclusive");
+        return;
+    }
+    sock->has_nodelay =
+        qemu_opt_get(opts, "delay") ||
+        qemu_opt_get(opts, "nodelay");
+    sock->nodelay =
+        !qemu_opt_get_bool(opts, "delay", true) ||
+        qemu_opt_get_bool(opts, "nodelay", false);
+
     /*
     /*
      * We have different default to QMP for 'server', hence
      * We have different default to QMP for 'server', hence
      * we can't just check for existence of 'server'
      * we can't just check for existence of 'server'

+ 3 - 0
chardev/char.c

@@ -867,6 +867,9 @@ QemuOptsList qemu_chardev_opts = {
         },{
         },{
             .name = "delay",
             .name = "delay",
             .type = QEMU_OPT_BOOL,
             .type = QEMU_OPT_BOOL,
+        },{
+            .name = "nodelay",
+            .type = QEMU_OPT_BOOL,
         },{
         },{
             .name = "reconnect",
             .name = "reconnect",
             .type = QEMU_OPT_NUMBER,
             .type = QEMU_OPT_NUMBER,

+ 13 - 0
docs/system/deprecated.rst

@@ -134,6 +134,12 @@ Boolean options such as ``share=on``/``share=off`` could be written
 in short form as ``share`` and ``noshare``.  This is now deprecated
 in short form as ``share`` and ``noshare``.  This is now deprecated
 and will cause a warning.
 and will cause a warning.
 
 
+``delay`` option for socket character devices (since 6.0)
+'''''''''''''''''''''''''''''''''''''''''''''''''''''''''
+
+The replacement for the ``nodelay`` short-form boolean option is ``nodelay=on``
+rather than ``delay=off``.
+
 ``--enable-fips`` (since 6.0)
 ``--enable-fips`` (since 6.0)
 '''''''''''''''''''''''''''''
 '''''''''''''''''''''''''''''
 
 
@@ -153,6 +159,13 @@ The ``-writeconfig`` option is not able to serialize the entire contents
 of the QEMU command line.  It is thus considered a failed experiment
 of the QEMU command line.  It is thus considered a failed experiment
 and deprecated, with no current replacement.
 and deprecated, with no current replacement.
 
 
+Userspace local APIC with KVM (x86, since 6.0)
+''''''''''''''''''''''''''''''''''''''''''''''
+
+Using ``-M kernel-irqchip=off`` with x86 machine types that include a local
+APIC is deprecated.  The ``split`` setting is supported, as is using
+``-M kernel-irqchip=off`` with the ISA PC machine type.
+
 QEMU Machine Protocol (QMP) commands
 QEMU Machine Protocol (QMP) commands
 ------------------------------------
 ------------------------------------
 
 

+ 1 - 1
gdbstub.c

@@ -3505,7 +3505,7 @@ int gdbserver_start(const char *device)
         if (strstart(device, "tcp:", NULL)) {
         if (strstart(device, "tcp:", NULL)) {
             /* enforce required TCP attributes */
             /* enforce required TCP attributes */
             snprintf(gdbstub_device_name, sizeof(gdbstub_device_name),
             snprintf(gdbstub_device_name, sizeof(gdbstub_device_name),
-                     "%s,wait=off,delay=off,server=on", device);
+                     "%s,wait=off,nodelay=on,server=on", device);
             device = gdbstub_device_name;
             device = gdbstub_device_name;
         }
         }
 #ifndef _WIN32
 #ifndef _WIN32

+ 4 - 2
hw/i386/x86.c

@@ -690,6 +690,8 @@ static uint64_t read_pvh_start_addr(void *arg1, void *arg2, bool is64)
         elf_note_data_addr =
         elf_note_data_addr =
             ((void *)nhdr64) + nhdr_size64 +
             ((void *)nhdr64) + nhdr_size64 +
             QEMU_ALIGN_UP(nhdr_namesz, phdr_align);
             QEMU_ALIGN_UP(nhdr_namesz, phdr_align);
+
+        pvh_start_addr = *elf_note_data_addr;
     } else {
     } else {
         struct elf32_note *nhdr32 = (struct elf32_note *)arg1;
         struct elf32_note *nhdr32 = (struct elf32_note *)arg1;
         uint32_t nhdr_size32 = sizeof(struct elf32_note);
         uint32_t nhdr_size32 = sizeof(struct elf32_note);
@@ -699,9 +701,9 @@ static uint64_t read_pvh_start_addr(void *arg1, void *arg2, bool is64)
         elf_note_data_addr =
         elf_note_data_addr =
             ((void *)nhdr32) + nhdr_size32 +
             ((void *)nhdr32) + nhdr_size32 +
             QEMU_ALIGN_UP(nhdr_namesz, phdr_align);
             QEMU_ALIGN_UP(nhdr_namesz, phdr_align);
-    }
 
 
-    pvh_start_addr = *elf_note_data_addr;
+        pvh_start_addr = *(uint32_t *)elf_note_data_addr;
+    }
 
 
     return pvh_start_addr;
     return pvh_start_addr;
 }
 }

+ 6 - 0
hw/intc/apic.c

@@ -25,6 +25,7 @@
 #include "hw/intc/i8259.h"
 #include "hw/intc/i8259.h"
 #include "hw/pci/msi.h"
 #include "hw/pci/msi.h"
 #include "qemu/host-utils.h"
 #include "qemu/host-utils.h"
+#include "sysemu/kvm.h"
 #include "trace.h"
 #include "trace.h"
 #include "hw/i386/apic-msidef.h"
 #include "hw/i386/apic-msidef.h"
 #include "qapi/error.h"
 #include "qapi/error.h"
@@ -875,6 +876,11 @@ static void apic_realize(DeviceState *dev, Error **errp)
         return;
         return;
     }
     }
 
 
+    if (kvm_enabled()) {
+        warn_report("Userspace local APIC is deprecated for KVM.");
+        warn_report("Do not use kernel-irqchip except for the -M isapc machine type.");
+    }
+
     memory_region_init_io(&s->io_memory, OBJECT(s), &apic_io_ops, s, "apic-msi",
     memory_region_init_io(&s->io_memory, OBJECT(s), &apic_io_ops, s, "apic-msi",
                           APIC_SPACE_SIZE);
                           APIC_SPACE_SIZE);
 
 

+ 2 - 2
hw/scsi/lsi53c895a.c

@@ -2312,7 +2312,7 @@ static void lsi_scsi_realize(PCIDevice *dev, Error **errp)
     scsi_bus_new(&s->bus, sizeof(s->bus), d, &lsi_scsi_info, NULL);
     scsi_bus_new(&s->bus, sizeof(s->bus), d, &lsi_scsi_info, NULL);
 }
 }
 
 
-static void lsi_scsi_unrealize(DeviceState *dev)
+static void lsi_scsi_exit(PCIDevice *dev)
 {
 {
     LSIState *s = LSI53C895A(dev);
     LSIState *s = LSI53C895A(dev);
 
 
@@ -2325,11 +2325,11 @@ static void lsi_class_init(ObjectClass *klass, void *data)
     PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
     PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
 
 
     k->realize = lsi_scsi_realize;
     k->realize = lsi_scsi_realize;
+    k->exit = lsi_scsi_exit;
     k->vendor_id = PCI_VENDOR_ID_LSI_LOGIC;
     k->vendor_id = PCI_VENDOR_ID_LSI_LOGIC;
     k->device_id = PCI_DEVICE_ID_LSI_53C895A;
     k->device_id = PCI_DEVICE_ID_LSI_53C895A;
     k->class_id = PCI_CLASS_STORAGE_SCSI;
     k->class_id = PCI_CLASS_STORAGE_SCSI;
     k->subsystem_id = 0x1000;
     k->subsystem_id = 0x1000;
-    dc->unrealize = lsi_scsi_unrealize;
     dc->reset = lsi_scsi_reset;
     dc->reset = lsi_scsi_reset;
     dc->vmsd = &vmstate_lsi_scsi;
     dc->vmsd = &vmstate_lsi_scsi;
     set_bit(DEVICE_CATEGORY_STORAGE, dc->categories);
     set_bit(DEVICE_CATEGORY_STORAGE, dc->categories);

+ 31 - 2
hw/scsi/scsi-bus.c

@@ -692,6 +692,7 @@ SCSIRequest *scsi_req_alloc(const SCSIReqOps *reqops, SCSIDevice *d,
     req->lun = lun;
     req->lun = lun;
     req->hba_private = hba_private;
     req->hba_private = hba_private;
     req->status = -1;
     req->status = -1;
+    req->host_status = -1;
     req->ops = reqops;
     req->ops = reqops;
     object_ref(OBJECT(d));
     object_ref(OBJECT(d));
     object_ref(OBJECT(qbus->parent));
     object_ref(OBJECT(qbus->parent));
@@ -1455,10 +1456,38 @@ void scsi_req_print(SCSIRequest *req)
     }
     }
 }
 }
 
 
+void scsi_req_complete_failed(SCSIRequest *req, int host_status)
+{
+    SCSISense sense;
+    int status;
+
+    assert(req->status == -1 && req->host_status == -1);
+    assert(req->ops != &reqops_unit_attention);
+
+    if (!req->bus->info->fail) {
+        status = scsi_sense_from_host_status(req->host_status, &sense);
+        if (status == CHECK_CONDITION) {
+            scsi_req_build_sense(req, sense);
+        }
+        scsi_req_complete(req, status);
+        return;
+    }
+
+    req->host_status = host_status;
+    scsi_req_ref(req);
+    scsi_req_dequeue(req);
+    req->bus->info->fail(req);
+
+    /* Cancelled requests might end up being completed instead of cancelled */
+    notifier_list_notify(&req->cancel_notifiers, req);
+    scsi_req_unref(req);
+}
+
 void scsi_req_complete(SCSIRequest *req, int status)
 void scsi_req_complete(SCSIRequest *req, int status)
 {
 {
-    assert(req->status == -1);
+    assert(req->status == -1 && req->host_status == -1);
     req->status = status;
     req->status = status;
+    req->host_status = SCSI_HOST_OK;
 
 
     assert(req->sense_len <= sizeof(req->sense));
     assert(req->sense_len <= sizeof(req->sense));
     if (status == GOOD) {
     if (status == GOOD) {
@@ -1646,7 +1675,7 @@ static int put_scsi_requests(QEMUFile *f, void *pv, size_t size,
 
 
     QTAILQ_FOREACH(req, &s->requests, next) {
     QTAILQ_FOREACH(req, &s->requests, next) {
         assert(!req->io_canceled);
         assert(!req->io_canceled);
-        assert(req->status == -1);
+        assert(req->status == -1 && req->host_status == -1);
         assert(req->enqueued);
         assert(req->enqueued);
 
 
         qemu_put_sbyte(f, req->retry ? 1 : 2);
         qemu_put_sbyte(f, req->retry ? 1 : 2);

+ 42 - 5
hw/scsi/scsi-disk.c

@@ -77,7 +77,6 @@ typedef struct SCSIDiskReq {
     struct iovec iov;
     struct iovec iov;
     QEMUIOVector qiov;
     QEMUIOVector qiov;
     BlockAcctCookie acct;
     BlockAcctCookie acct;
-    unsigned char *status;
 } SCSIDiskReq;
 } SCSIDiskReq;
 
 
 #define SCSI_DISK_F_REMOVABLE             0
 #define SCSI_DISK_F_REMOVABLE             0
@@ -261,8 +260,6 @@ static bool scsi_disk_req_check_error(SCSIDiskReq *r, int ret, bool acct_failed)
 
 
     if (ret < 0) {
     if (ret < 0) {
         return scsi_handle_rw_error(r, ret, acct_failed);
         return scsi_handle_rw_error(r, ret, acct_failed);
-    } else if (r->status && *r->status) {
-        return scsi_handle_rw_error(r, *r->status, acct_failed);
     }
     }
 
 
     return false;
     return false;
@@ -2697,8 +2694,47 @@ typedef struct SCSIBlockReq {
 
 
     /* CDB passed to SG_IO.  */
     /* CDB passed to SG_IO.  */
     uint8_t cdb[16];
     uint8_t cdb[16];
+    BlockCompletionFunc *cb;
+    void *cb_opaque;
 } SCSIBlockReq;
 } SCSIBlockReq;
 
 
+static void scsi_block_sgio_complete(void *opaque, int ret)
+{
+    SCSIBlockReq *req = (SCSIBlockReq *)opaque;
+    SCSIDiskReq *r = &req->req;
+    SCSIDevice *s = r->req.dev;
+    sg_io_hdr_t *io_hdr = &req->io_header;
+
+    if (ret == 0) {
+        if (io_hdr->host_status != SCSI_HOST_OK) {
+            scsi_req_complete_failed(&r->req, io_hdr->host_status);
+            scsi_req_unref(&r->req);
+            return;
+        }
+
+        if (io_hdr->driver_status & SG_ERR_DRIVER_TIMEOUT) {
+            ret = BUSY;
+        } else {
+            ret = io_hdr->status;
+        }
+
+        if (ret > 0) {
+            aio_context_acquire(blk_get_aio_context(s->conf.blk));
+            if (scsi_handle_rw_error(r, ret, true)) {
+                aio_context_release(blk_get_aio_context(s->conf.blk));
+                scsi_req_unref(&r->req);
+                return;
+            }
+            aio_context_release(blk_get_aio_context(s->conf.blk));
+
+            /* Ignore error.  */
+            ret = 0;
+        }
+    }
+
+    req->cb(req->cb_opaque, ret);
+}
+
 static BlockAIOCB *scsi_block_do_sgio(SCSIBlockReq *req,
 static BlockAIOCB *scsi_block_do_sgio(SCSIBlockReq *req,
                                       int64_t offset, QEMUIOVector *iov,
                                       int64_t offset, QEMUIOVector *iov,
                                       int direction,
                                       int direction,
@@ -2777,9 +2813,11 @@ static BlockAIOCB *scsi_block_do_sgio(SCSIBlockReq *req,
     io_header->timeout = s->qdev.io_timeout * 1000;
     io_header->timeout = s->qdev.io_timeout * 1000;
     io_header->usr_ptr = r;
     io_header->usr_ptr = r;
     io_header->flags |= SG_FLAG_DIRECT_IO;
     io_header->flags |= SG_FLAG_DIRECT_IO;
+    req->cb = cb;
+    req->cb_opaque = opaque;
     trace_scsi_disk_aio_sgio_command(r->req.tag, req->cdb[0], lba,
     trace_scsi_disk_aio_sgio_command(r->req.tag, req->cdb[0], lba,
                                      nb_logical_blocks, io_header->timeout);
                                      nb_logical_blocks, io_header->timeout);
-    aiocb = blk_aio_ioctl(s->qdev.conf.blk, SG_IO, io_header, cb, opaque);
+    aiocb = blk_aio_ioctl(s->qdev.conf.blk, SG_IO, io_header, scsi_block_sgio_complete, req);
     assert(aiocb != NULL);
     assert(aiocb != NULL);
     return aiocb;
     return aiocb;
 }
 }
@@ -2893,7 +2931,6 @@ static int32_t scsi_block_dma_command(SCSIRequest *req, uint8_t *buf)
         return 0;
         return 0;
     }
     }
 
 
-    r->req.status = &r->io_header.status;
     return scsi_disk_dma_command(req, buf);
     return scsi_disk_dma_command(req, buf);
 }
 }
 
 

+ 18 - 7
hw/scsi/scsi-generic.c

@@ -75,6 +75,7 @@ static void scsi_command_complete_noio(SCSIGenericReq *r, int ret)
 {
 {
     int status;
     int status;
     SCSISense sense;
     SCSISense sense;
+    sg_io_hdr_t *io_hdr = &r->io_header;
 
 
     assert(r->req.aiocb == NULL);
     assert(r->req.aiocb == NULL);
 
 
@@ -82,15 +83,22 @@ static void scsi_command_complete_noio(SCSIGenericReq *r, int ret)
         scsi_req_cancel_complete(&r->req);
         scsi_req_cancel_complete(&r->req);
         goto done;
         goto done;
     }
     }
-    status = sg_io_sense_from_errno(-ret, &r->io_header, &sense);
-    if (status == CHECK_CONDITION) {
-        if (r->io_header.driver_status & SG_ERR_DRIVER_SENSE) {
-            r->req.sense_len = r->io_header.sb_len_wr;
-        } else {
+    if (ret < 0) {
+        status = scsi_sense_from_errno(-ret, &sense);
+        if (status == CHECK_CONDITION) {
             scsi_req_build_sense(&r->req, sense);
             scsi_req_build_sense(&r->req, sense);
         }
         }
+    } else if (io_hdr->host_status != SCSI_HOST_OK) {
+        scsi_req_complete_failed(&r->req, io_hdr->host_status);
+        goto done;
+    } else if (io_hdr->driver_status & SG_ERR_DRIVER_TIMEOUT) {
+        status = BUSY;
+    } else {
+        status = io_hdr->status;
+        if (io_hdr->driver_status & SG_ERR_DRIVER_SENSE) {
+            r->req.sense_len = io_hdr->sb_len_wr;
+        }
     }
     }
-
     trace_scsi_generic_command_complete_noio(r, r->req.tag, status);
     trace_scsi_generic_command_complete_noio(r, r->req.tag, status);
 
 
     scsi_req_complete(&r->req, status);
     scsi_req_complete(&r->req, status);
@@ -288,7 +296,10 @@ static void scsi_read_complete(void * opaque, int ret)
         }
         }
     }
     }
 
 
-    if (len == 0) {
+    if (r->io_header.host_status != SCSI_HOST_OK ||
+        (r->io_header.driver_status & SG_ERR_DRIVER_TIMEOUT) ||
+        r->io_header.status != GOOD ||
+        len == 0) {
         scsi_command_complete_noio(r, 0);
         scsi_command_complete_noio(r, 0);
         goto done;
         goto done;
     }
     }

+ 46 - 0
hw/scsi/virtio-scsi.c

@@ -500,6 +500,51 @@ static void virtio_scsi_complete_cmd_req(VirtIOSCSIReq *req)
     virtio_scsi_complete_req(req);
     virtio_scsi_complete_req(req);
 }
 }
 
 
+static void virtio_scsi_command_failed(SCSIRequest *r)
+{
+    VirtIOSCSIReq *req = r->hba_private;
+
+    if (r->io_canceled) {
+        return;
+    }
+
+    req->resp.cmd.status = GOOD;
+    switch (r->host_status) {
+    case SCSI_HOST_NO_LUN:
+        req->resp.cmd.response = VIRTIO_SCSI_S_INCORRECT_LUN;
+        break;
+    case SCSI_HOST_BUSY:
+        req->resp.cmd.response = VIRTIO_SCSI_S_BUSY;
+        break;
+    case SCSI_HOST_TIME_OUT:
+    case SCSI_HOST_ABORTED:
+        req->resp.cmd.response = VIRTIO_SCSI_S_ABORTED;
+        break;
+    case SCSI_HOST_BAD_RESPONSE:
+        req->resp.cmd.response = VIRTIO_SCSI_S_BAD_TARGET;
+        break;
+    case SCSI_HOST_RESET:
+        req->resp.cmd.response = VIRTIO_SCSI_S_RESET;
+        break;
+    case SCSI_HOST_TRANSPORT_DISRUPTED:
+        req->resp.cmd.response = VIRTIO_SCSI_S_TRANSPORT_FAILURE;
+        break;
+    case SCSI_HOST_TARGET_FAILURE:
+        req->resp.cmd.response = VIRTIO_SCSI_S_TARGET_FAILURE;
+        break;
+    case SCSI_HOST_RESERVATION_ERROR:
+        req->resp.cmd.response = VIRTIO_SCSI_S_NEXUS_FAILURE;
+        break;
+    case SCSI_HOST_ALLOCATION_FAILURE:
+    case SCSI_HOST_MEDIUM_ERROR:
+    case SCSI_HOST_ERROR:
+    default:
+        req->resp.cmd.response = VIRTIO_SCSI_S_FAILURE;
+        break;
+    }
+    virtio_scsi_complete_cmd_req(req);
+}
+
 static void virtio_scsi_command_complete(SCSIRequest *r, size_t resid)
 static void virtio_scsi_command_complete(SCSIRequest *r, size_t resid)
 {
 {
     VirtIOSCSIReq *req = r->hba_private;
     VirtIOSCSIReq *req = r->hba_private;
@@ -908,6 +953,7 @@ static struct SCSIBusInfo virtio_scsi_scsi_info = {
     .max_lun = VIRTIO_SCSI_MAX_LUN,
     .max_lun = VIRTIO_SCSI_MAX_LUN,
 
 
     .complete = virtio_scsi_command_complete,
     .complete = virtio_scsi_command_complete,
+    .fail = virtio_scsi_command_failed,
     .cancel = virtio_scsi_request_cancelled,
     .cancel = virtio_scsi_request_cancelled,
     .change = virtio_scsi_change,
     .change = virtio_scsi_change,
     .parse_cdb = virtio_scsi_parse_cdb,
     .parse_cdb = virtio_scsi_parse_cdb,

+ 39 - 0
hw/scsi/vmw_pvscsi.c

@@ -510,6 +510,44 @@ pvscsi_write_sense(PVSCSIRequest *r, uint8_t *sense, int len)
     cpu_physical_memory_write(r->req.senseAddr, sense, r->cmp.senseLen);
     cpu_physical_memory_write(r->req.senseAddr, sense, r->cmp.senseLen);
 }
 }
 
 
+static void
+pvscsi_command_failed(SCSIRequest *req)
+{
+    PVSCSIRequest *pvscsi_req = req->hba_private;
+    PVSCSIState *s;
+
+    if (!pvscsi_req) {
+        trace_pvscsi_command_complete_not_found(req->tag);
+        return;
+    }
+    s = pvscsi_req->dev;
+
+    switch (req->host_status) {
+    case SCSI_HOST_NO_LUN:
+        pvscsi_req->cmp.hostStatus = BTSTAT_LUNMISMATCH;
+        break;
+    case SCSI_HOST_BUSY:
+        pvscsi_req->cmp.hostStatus = BTSTAT_ABORTQUEUE;
+        break;
+    case SCSI_HOST_TIME_OUT:
+    case SCSI_HOST_ABORTED:
+        pvscsi_req->cmp.hostStatus = BTSTAT_SENTRST;
+        break;
+    case SCSI_HOST_BAD_RESPONSE:
+        pvscsi_req->cmp.hostStatus = BTSTAT_SELTIMEO;
+        break;
+    case SCSI_HOST_RESET:
+        pvscsi_req->cmp.hostStatus = BTSTAT_BUSRESET;
+        break;
+    default:
+        pvscsi_req->cmp.hostStatus = BTSTAT_HASOFTWARE;
+        break;
+    }
+    pvscsi_req->cmp.scsiStatus = GOOD;
+    qemu_sglist_destroy(&pvscsi_req->sgl);
+    pvscsi_complete_request(s, pvscsi_req);
+}
+
 static void
 static void
 pvscsi_command_complete(SCSIRequest *req, size_t resid)
 pvscsi_command_complete(SCSIRequest *req, size_t resid)
 {
 {
@@ -1103,6 +1141,7 @@ static const struct SCSIBusInfo pvscsi_scsi_info = {
         .get_sg_list = pvscsi_get_sg_list,
         .get_sg_list = pvscsi_get_sg_list,
         .complete = pvscsi_command_complete,
         .complete = pvscsi_command_complete,
         .cancel = pvscsi_request_cancelled,
         .cancel = pvscsi_request_cancelled,
+        .fail = pvscsi_command_failed,
 };
 };
 
 
 static void
 static void

+ 1 - 3
include/hw/elf_ops.h

@@ -598,9 +598,7 @@ static int glue(load_elf, SZ)(const char *name, int fd,
             nhdr = glue(get_elf_note_type, SZ)(nhdr, file_size, ph->p_align,
             nhdr = glue(get_elf_note_type, SZ)(nhdr, file_size, ph->p_align,
                                                *(uint64_t *)translate_opaque);
                                                *(uint64_t *)translate_opaque);
             if (nhdr != NULL) {
             if (nhdr != NULL) {
-                bool is64 =
-                    sizeof(struct elf_note) == sizeof(struct elf64_note);
-                elf_note_fn((void *)nhdr, (void *)&ph->p_align, is64);
+                elf_note_fn((void *)nhdr, (void *)&ph->p_align, SZ == 64);
             }
             }
             data = NULL;
             data = NULL;
         }
         }

+ 4 - 1
include/hw/scsi/scsi.h

@@ -27,7 +27,8 @@ struct SCSIRequest {
     uint32_t          refcount;
     uint32_t          refcount;
     uint32_t          tag;
     uint32_t          tag;
     uint32_t          lun;
     uint32_t          lun;
-    uint32_t          status;
+    int16_t           status;
+    int16_t           host_status;
     void              *hba_private;
     void              *hba_private;
     size_t            resid;
     size_t            resid;
     SCSICommand       cmd;
     SCSICommand       cmd;
@@ -123,6 +124,7 @@ struct SCSIBusInfo {
     int (*parse_cdb)(SCSIDevice *dev, SCSICommand *cmd, uint8_t *buf,
     int (*parse_cdb)(SCSIDevice *dev, SCSICommand *cmd, uint8_t *buf,
                      void *hba_private);
                      void *hba_private);
     void (*transfer_data)(SCSIRequest *req, uint32_t arg);
     void (*transfer_data)(SCSIRequest *req, uint32_t arg);
+    void (*fail)(SCSIRequest *req);
     void (*complete)(SCSIRequest *req, size_t resid);
     void (*complete)(SCSIRequest *req, size_t resid);
     void (*cancel)(SCSIRequest *req);
     void (*cancel)(SCSIRequest *req);
     void (*change)(SCSIBus *bus, SCSIDevice *dev, SCSISense sense);
     void (*change)(SCSIBus *bus, SCSIDevice *dev, SCSISense sense);
@@ -177,6 +179,7 @@ void scsi_req_print(SCSIRequest *req);
 void scsi_req_continue(SCSIRequest *req);
 void scsi_req_continue(SCSIRequest *req);
 void scsi_req_data(SCSIRequest *req, int len);
 void scsi_req_data(SCSIRequest *req, int len);
 void scsi_req_complete(SCSIRequest *req, int status);
 void scsi_req_complete(SCSIRequest *req, int status);
+void scsi_req_complete_failed(SCSIRequest *req, int host_status);
 uint8_t *scsi_req_get_buf(SCSIRequest *req);
 uint8_t *scsi_req_get_buf(SCSIRequest *req);
 int scsi_req_get_sense(SCSIRequest *req, uint8_t *buf, int len);
 int scsi_req_get_sense(SCSIRequest *req, uint8_t *buf, int len);
 void scsi_req_cancel_complete(SCSIRequest *req);
 void scsi_req_cancel_complete(SCSIRequest *req);

+ 3 - 2
include/qemu/config-file.h

@@ -11,9 +11,10 @@ void qemu_add_drive_opts(QemuOptsList *list);
 int qemu_global_option(const char *str);
 int qemu_global_option(const char *str);
 
 
 void qemu_config_write(FILE *fp);
 void qemu_config_write(FILE *fp);
-int qemu_config_parse(FILE *fp, QemuOptsList **lists, const char *fname);
+int qemu_config_parse(FILE *fp, QemuOptsList **lists, const char *fname,
+                      Error **errp);
 
 
-int qemu_read_config_file(const char *filename);
+int qemu_read_config_file(const char *filename, Error **errp);
 
 
 /* Parse QDict options as a replacement for a config file (allowing multiple
 /* Parse QDict options as a replacement for a config file (allowing multiple
    enumerated (0..(n-1)) configuration "sections") */
    enumerated (0..(n-1)) configuration "sections") */

+ 17 - 10
include/scsi/utils.h

@@ -16,6 +16,22 @@ enum SCSIXferMode {
     SCSI_XFER_TO_DEV,    /*  WRITE, MODE_SELECT, ...         */
     SCSI_XFER_TO_DEV,    /*  WRITE, MODE_SELECT, ...         */
 };
 };
 
 
+enum SCSIHostStatus {
+    SCSI_HOST_OK,
+    SCSI_HOST_NO_LUN,
+    SCSI_HOST_BUSY,
+    SCSI_HOST_TIME_OUT,
+    SCSI_HOST_BAD_RESPONSE,
+    SCSI_HOST_ABORTED,
+    SCSI_HOST_ERROR = 0x07,
+    SCSI_HOST_RESET = 0x08,
+    SCSI_HOST_TRANSPORT_DISRUPTED = 0xe,
+    SCSI_HOST_TARGET_FAILURE = 0x10,
+    SCSI_HOST_RESERVATION_ERROR = 0x11,
+    SCSI_HOST_ALLOCATION_FAILURE = 0x12,
+    SCSI_HOST_MEDIUM_ERROR = 0x13,
+};
+
 typedef struct SCSICommand {
 typedef struct SCSICommand {
     uint8_t buf[SCSI_CMD_BUF_SIZE];
     uint8_t buf[SCSI_CMD_BUF_SIZE];
     int len;
     int len;
@@ -123,18 +139,9 @@ int scsi_cdb_length(uint8_t *buf);
 #ifdef CONFIG_LINUX
 #ifdef CONFIG_LINUX
 #define SG_ERR_DRIVER_TIMEOUT  0x06
 #define SG_ERR_DRIVER_TIMEOUT  0x06
 #define SG_ERR_DRIVER_SENSE    0x08
 #define SG_ERR_DRIVER_SENSE    0x08
-
-#define SG_ERR_DID_OK          0x00
-#define SG_ERR_DID_NO_CONNECT  0x01
-#define SG_ERR_DID_BUS_BUSY    0x02
-#define SG_ERR_DID_TIME_OUT    0x03
-
-#define SG_ERR_DRIVER_SENSE    0x08
-
-int sg_io_sense_from_errno(int errno_value, struct sg_io_hdr *io_hdr,
-                           SCSISense *sense);
 #endif
 #endif
 
 
 int scsi_sense_from_errno(int errno_value, SCSISense *sense);
 int scsi_sense_from_errno(int errno_value, SCSISense *sense);
+int scsi_sense_from_host_status(uint8_t host_status, SCSISense *sense);
 
 
 #endif
 #endif

+ 12 - 0
meson.build

@@ -1574,6 +1574,18 @@ if have_system
   endif
   endif
 endif
 endif
 
 
+# For CFI, we need to compile slirp as a static library together with qemu.
+# This is because we register slirp functions as callbacks for QEMU Timers.
+# When using a system-wide shared libslirp, the type information for the
+# callback is missing and the timer call produces a false positive with CFI.
+#
+# Now that slirp_opt has been defined, check if the selected slirp is compatible
+# with control-flow integrity.
+if get_option('cfi') and slirp_opt == 'system'
+  error('Control-Flow Integrity is not compatible with system-wide slirp.' \
+         + ' Please configure with --enable-slirp=git')
+endif
+
 fdt = not_found
 fdt = not_found
 fdt_opt = get_option('fdt')
 fdt_opt = get_option('fdt')
 if have_system
 if have_system

+ 7 - 7
qemu-options.hx

@@ -3033,7 +3033,7 @@ DEFHEADING(Character device options:)
 DEF("chardev", HAS_ARG, QEMU_OPTION_chardev,
 DEF("chardev", HAS_ARG, QEMU_OPTION_chardev,
     "-chardev help\n"
     "-chardev help\n"
     "-chardev null,id=id[,mux=on|off][,logfile=PATH][,logappend=on|off]\n"
     "-chardev null,id=id[,mux=on|off][,logfile=PATH][,logappend=on|off]\n"
-    "-chardev socket,id=id[,host=host],port=port[,to=to][,ipv4=on|off][,ipv6=on|off][,delay=on|off][,reconnect=seconds]\n"
+    "-chardev socket,id=id[,host=host],port=port[,to=to][,ipv4=on|off][,ipv6=on|off][,nodelay=on|off][,reconnect=seconds]\n"
     "         [,server=on|off][,wait=on|off][,telnet=on|off][,websocket=on|off][,reconnect=seconds][,mux=on|off]\n"
     "         [,server=on|off][,wait=on|off][,telnet=on|off][,websocket=on|off][,reconnect=seconds][,mux=on|off]\n"
     "         [,logfile=PATH][,logappend=on|off][,tls-creds=ID][,tls-authz=ID] (tcp)\n"
     "         [,logfile=PATH][,logappend=on|off][,tls-creds=ID][,tls-authz=ID] (tcp)\n"
     "-chardev socket,id=id,path=path[,server=on|off][,wait=on|off][,telnet=on|off][,websocket=on|off][,reconnect=seconds]\n"
     "-chardev socket,id=id,path=path[,server=on|off][,wait=on|off][,telnet=on|off][,websocket=on|off][,reconnect=seconds]\n"
@@ -3184,7 +3184,7 @@ The available backends are:
 
 
     TCP and unix socket options are given below:
     TCP and unix socket options are given below:
 
 
-    ``TCP options: port=port[,host=host][,to=to][,ipv4=on|off][,ipv6=on|off][,delay=on|off]``
+    ``TCP options: port=port[,host=host][,to=to][,ipv4=on|off][,ipv6=on|off][,nodelay=on|off]``
         ``host`` for a listening socket specifies the local address to
         ``host`` for a listening socket specifies the local address to
         be bound. For a connecting socket species the remote host to
         be bound. For a connecting socket species the remote host to
         connect to. ``host`` is optional for listening sockets. If not
         connect to. ``host`` is optional for listening sockets. If not
@@ -3204,7 +3204,7 @@ The available backends are:
         or IPv6 must be used. If neither is specified the socket may
         or IPv6 must be used. If neither is specified the socket may
         use either protocol.
         use either protocol.
 
 
-        ``delay=on|off`` disables the Nagle algorithm.
+        ``nodelay=on|off`` disables the Nagle algorithm.
 
 
     ``unix options: path=path[,abstract=on|off][,tight=on|off]``
     ``unix options: path=path[,abstract=on|off][,tight=on|off]``
         ``path`` specifies the local path of the unix socket. ``path``
         ``path`` specifies the local path of the unix socket. ``path``
@@ -3593,13 +3593,13 @@ SRST
         ``telnet options:``
         ``telnet options:``
             localhost 5555
             localhost 5555
 
 
-    ``tcp:[host]:port[,server=on|off][,wait=on|off][,delay=on|off][,reconnect=seconds]``
+    ``tcp:[host]:port[,server=on|off][,wait=on|off][,nodelay=on|off][,reconnect=seconds]``
         The TCP Net Console has two modes of operation. It can send the
         The TCP Net Console has two modes of operation. It can send the
         serial I/O to a location or wait for a connection from a
         serial I/O to a location or wait for a connection from a
         location. By default the TCP Net Console is sent to host at the
         location. By default the TCP Net Console is sent to host at the
         port. If you use the ``server=on`` option QEMU will wait for a client
         port. If you use the ``server=on`` option QEMU will wait for a client
         socket application to connect to the port before continuing,
         socket application to connect to the port before continuing,
-        unless the ``wait=on|off`` option was specified. The ``delay=on|off``
+        unless the ``wait=on|off`` option was specified. The ``nodelay=on|off``
         option disables the Nagle buffering algorithm. The ``reconnect=on``
         option disables the Nagle buffering algorithm. The ``reconnect=on``
         option only applies if ``server=no`` is set, if the connection goes
         option only applies if ``server=no`` is set, if the connection goes
         down it will attempt to reconnect at the given interval. If host
         down it will attempt to reconnect at the given interval. If host
@@ -3616,7 +3616,7 @@ SRST
         ``Example to not wait and listen on ip 192.168.0.100 port 4444``
         ``Example to not wait and listen on ip 192.168.0.100 port 4444``
             -serial tcp:192.168.0.100:4444,server=on,wait=off
             -serial tcp:192.168.0.100:4444,server=on,wait=off
 
 
-    ``telnet:host:port[,server=on|off][,wait=on|off][,delay=on|off]``
+    ``telnet:host:port[,server=on|off][,wait=on|off][,nodelay=on|off]``
         The telnet protocol is used instead of raw tcp sockets. The
         The telnet protocol is used instead of raw tcp sockets. The
         options work the same as if you had specified ``-serial tcp``.
         options work the same as if you had specified ``-serial tcp``.
         The difference is that the port acts like a telnet server or
         The difference is that the port acts like a telnet server or
@@ -3626,7 +3626,7 @@ SRST
         you do it with Control-] and then type "send break" followed by
         you do it with Control-] and then type "send break" followed by
         pressing the enter key.
         pressing the enter key.
 
 
-    ``websocket:host:port,server=on[,wait=on|off][,delay=on|off]``
+    ``websocket:host:port,server=on[,wait=on|off][,nodelay=on|off]``
         The WebSocket protocol is used instead of raw tcp socket. The
         The WebSocket protocol is used instead of raw tcp socket. The
         port acts as a WebSocket server. Client mode is not supported.
         port acts as a WebSocket server. Client mode is not supported.
 
 

+ 2 - 2
qga/vss-win32/meson.build

@@ -1,5 +1,5 @@
 if add_languages('cpp', required: false)
 if add_languages('cpp', required: false)
-  glib_static = dependency('glib-2.0', static: true)
+  glib_dynamic = dependency('glib-2.0', static: false)
   link_args = cc.get_supported_link_arguments(['-fstack-protector-all', '-fstack-protector-strong',
   link_args = cc.get_supported_link_arguments(['-fstack-protector-all', '-fstack-protector-strong',
                                                '-Wl,--add-stdcall-alias', '-Wl,--enable-stdcall-fixup'])
                                                '-Wl,--add-stdcall-alias', '-Wl,--enable-stdcall-fixup'])
 
 
@@ -8,7 +8,7 @@ if add_languages('cpp', required: false)
                 cpp_args: ['-Wno-unknown-pragmas', '-Wno-delete-non-virtual-dtor', '-Wno-non-virtual-dtor'],
                 cpp_args: ['-Wno-unknown-pragmas', '-Wno-delete-non-virtual-dtor', '-Wno-non-virtual-dtor'],
                 link_args: link_args,
                 link_args: link_args,
                 vs_module_defs: 'qga-vss.def',
                 vs_module_defs: 'qga-vss.def',
-                dependencies: [glib_static, socket,
+                dependencies: [glib_dynamic, socket,
                                cc.find_library('ole32'),
                                cc.find_library('ole32'),
                                cc.find_library('oleaut32'),
                                cc.find_library('oleaut32'),
                                cc.find_library('shlwapi'),
                                cc.find_library('shlwapi'),

+ 9 - 0
qom/object_interfaces.c

@@ -8,6 +8,7 @@
 #include "qapi/qobject-input-visitor.h"
 #include "qapi/qobject-input-visitor.h"
 #include "qom/object_interfaces.h"
 #include "qom/object_interfaces.h"
 #include "qemu/help_option.h"
 #include "qemu/help_option.h"
+#include "qemu/id.h"
 #include "qemu/module.h"
 #include "qemu/module.h"
 #include "qemu/option.h"
 #include "qemu/option.h"
 #include "qapi/opts-visitor.h"
 #include "qapi/opts-visitor.h"
@@ -41,11 +42,19 @@ Object *user_creatable_add_type(const char *type, const char *id,
                                 const QDict *qdict,
                                 const QDict *qdict,
                                 Visitor *v, Error **errp)
                                 Visitor *v, Error **errp)
 {
 {
+    ERRP_GUARD();
     Object *obj;
     Object *obj;
     ObjectClass *klass;
     ObjectClass *klass;
     const QDictEntry *e;
     const QDictEntry *e;
     Error *local_err = NULL;
     Error *local_err = NULL;
 
 
+    if (id != NULL && !id_wellformed(id)) {
+        error_setg(errp, QERR_INVALID_PARAMETER_VALUE, "id", "an identifier");
+        error_append_hint(errp, "Identifiers consist of letters, digits, "
+                          "'-', '.', '_', starting with a letter.\n");
+        return NULL;
+    }
+
     klass = object_class_by_name(type);
     klass = object_class_by_name(type);
     if (!klass) {
     if (!klass) {
         error_setg(errp, "invalid object type: %s", type);
         error_setg(errp, "invalid object type: %s", type);

+ 17 - 7
scsi/qemu-pr-helper.c

@@ -149,19 +149,29 @@ static int do_sgio_worker(void *opaque)
     io_hdr.dxferp = (char *)data->buf;
     io_hdr.dxferp = (char *)data->buf;
     io_hdr.dxfer_len = data->sz;
     io_hdr.dxfer_len = data->sz;
     ret = ioctl(data->fd, SG_IO, &io_hdr);
     ret = ioctl(data->fd, SG_IO, &io_hdr);
-    status = sg_io_sense_from_errno(ret < 0 ? errno : 0, &io_hdr,
-                                    &sense_code);
+
+    if (ret < 0) {
+        status = scsi_sense_from_errno(errno, &sense_code);
+        if (status == CHECK_CONDITION) {
+            scsi_build_sense(data->sense, sense_code);
+        }
+    } else if (io_hdr.host_status != SCSI_HOST_OK) {
+        status = scsi_sense_from_host_status(io_hdr.host_status, &sense_code);
+        if (status == CHECK_CONDITION) {
+            scsi_build_sense(data->sense, sense_code);
+        }
+    } else if (io_hdr.driver_status & SG_ERR_DRIVER_TIMEOUT) {
+        status = BUSY;
+    } else {
+        status = io_hdr.status;
+    }
+
     if (status == GOOD) {
     if (status == GOOD) {
         data->sz -= io_hdr.resid;
         data->sz -= io_hdr.resid;
     } else {
     } else {
         data->sz = 0;
         data->sz = 0;
     }
     }
 
 
-    if (status == CHECK_CONDITION &&
-        !(io_hdr.driver_status & SG_ERR_DRIVER_SENSE)) {
-        scsi_build_sense(data->sense, sense_code);
-    }
-
     return status;
     return status;
 }
 }
 
 

+ 50 - 22
scsi/utils.c

@@ -257,6 +257,21 @@ const struct SCSISense sense_code_LUN_COMM_FAILURE = {
     .key = ABORTED_COMMAND, .asc = 0x08, .ascq = 0x00
     .key = ABORTED_COMMAND, .asc = 0x08, .ascq = 0x00
 };
 };
 
 
+/* Command aborted, LUN does not respond to selection */
+const struct SCSISense sense_code_LUN_NOT_RESPONDING = {
+    .key = ABORTED_COMMAND, .asc = 0x05, .ascq = 0x00
+};
+
+/* Command aborted, Command Timeout during processing */
+const struct SCSISense sense_code_COMMAND_TIMEOUT = {
+    .key = ABORTED_COMMAND, .asc = 0x2e, .ascq = 0x02
+};
+
+/* Command aborted, Commands cleared by device server */
+const struct SCSISense sense_code_COMMAND_ABORTED = {
+    .key = ABORTED_COMMAND, .asc = 0x2f, .ascq = 0x02
+};
+
 /* Medium Error, Unrecovered read error */
 /* Medium Error, Unrecovered read error */
 const struct SCSISense sense_code_READ_ERROR = {
 const struct SCSISense sense_code_READ_ERROR = {
     .key = MEDIUM_ERROR, .asc = 0x11, .ascq = 0x00
     .key = MEDIUM_ERROR, .asc = 0x11, .ascq = 0x00
@@ -605,28 +620,41 @@ int scsi_sense_from_errno(int errno_value, SCSISense *sense)
     }
     }
 }
 }
 
 
-#ifdef CONFIG_LINUX
-int sg_io_sense_from_errno(int errno_value, struct sg_io_hdr *io_hdr,
-                           SCSISense *sense)
+int scsi_sense_from_host_status(uint8_t host_status,
+                                SCSISense *sense)
 {
 {
-    if (errno_value != 0) {
-        return scsi_sense_from_errno(errno_value, sense);
-    } else {
-        if (io_hdr->host_status == SG_ERR_DID_NO_CONNECT ||
-            io_hdr->host_status == SG_ERR_DID_BUS_BUSY ||
-            io_hdr->host_status == SG_ERR_DID_TIME_OUT ||
-            (io_hdr->driver_status & SG_ERR_DRIVER_TIMEOUT)) {
-            return BUSY;
-        } else if (io_hdr->host_status) {
-            *sense = SENSE_CODE(I_T_NEXUS_LOSS);
-            return CHECK_CONDITION;
-        } else if (io_hdr->status) {
-            return io_hdr->status;
-        } else if (io_hdr->driver_status & SG_ERR_DRIVER_SENSE) {
-            return CHECK_CONDITION;
-        } else {
-            return GOOD;
-        }
+    switch (host_status) {
+    case SCSI_HOST_NO_LUN:
+        *sense = SENSE_CODE(LUN_NOT_RESPONDING);
+        return CHECK_CONDITION;
+    case SCSI_HOST_BUSY:
+        return BUSY;
+    case SCSI_HOST_TIME_OUT:
+        *sense = SENSE_CODE(COMMAND_TIMEOUT);
+        return CHECK_CONDITION;
+    case SCSI_HOST_BAD_RESPONSE:
+        *sense = SENSE_CODE(LUN_COMM_FAILURE);
+        return CHECK_CONDITION;
+    case SCSI_HOST_ABORTED:
+        *sense = SENSE_CODE(COMMAND_ABORTED);
+        return CHECK_CONDITION;
+    case SCSI_HOST_RESET:
+        *sense = SENSE_CODE(RESET);
+        return CHECK_CONDITION;
+    case SCSI_HOST_TRANSPORT_DISRUPTED:
+        *sense = SENSE_CODE(I_T_NEXUS_LOSS);
+        return CHECK_CONDITION;
+    case SCSI_HOST_TARGET_FAILURE:
+        *sense = SENSE_CODE(TARGET_FAILURE);
+        return CHECK_CONDITION;
+    case SCSI_HOST_RESERVATION_ERROR:
+        return RESERVATION_CONFLICT;
+    case SCSI_HOST_ALLOCATION_FAILURE:
+        *sense = SENSE_CODE(SPACE_ALLOC_FAILED);
+        return CHECK_CONDITION;
+    case SCSI_HOST_MEDIUM_ERROR:
+        *sense = SENSE_CODE(READ_ERROR);
+        return CHECK_CONDITION;
     }
     }
+    return GOOD;
 }
 }
-#endif

+ 27 - 24
softmmu/vl.c

@@ -2062,17 +2062,19 @@ static int global_init_func(void *opaque, QemuOpts *opts, Error **errp)
     return 0;
     return 0;
 }
 }
 
 
-static int qemu_read_default_config_file(void)
+static void qemu_read_default_config_file(Error **errp)
 {
 {
+    ERRP_GUARD();
     int ret;
     int ret;
     g_autofree char *file = get_relocated_path(CONFIG_QEMU_CONFDIR "/qemu.conf");
     g_autofree char *file = get_relocated_path(CONFIG_QEMU_CONFDIR "/qemu.conf");
 
 
-    ret = qemu_read_config_file(file);
-    if (ret < 0 && ret != -ENOENT) {
-        return ret;
+    ret = qemu_read_config_file(file, errp);
+    if (ret < 0) {
+        if (ret == -ENOENT) {
+            error_free(*errp);
+            *errp = NULL;
+        }
     }
     }
-
-    return 0;
 }
 }
 
 
 static int qemu_set_option(const char *str)
 static int qemu_set_option(const char *str)
@@ -2361,13 +2363,10 @@ static void qemu_process_early_options(void)
                       cleanup_add_fd, NULL, &error_fatal);
                       cleanup_add_fd, NULL, &error_fatal);
 #endif
 #endif
 
 
-    if (!trace_init_backends()) {
-        exit(1);
-    }
-    trace_init_file();
-
     /* Open the logfile at this point and set the log mask if necessary.  */
     /* Open the logfile at this point and set the log mask if necessary.  */
-    qemu_set_log_filename(log_file, &error_fatal);
+    if (log_file) {
+        qemu_set_log_filename(log_file, &error_fatal);
+    }
     if (log_mask) {
     if (log_mask) {
         int mask;
         int mask;
         mask = qemu_str_to_log_mask(log_mask);
         mask = qemu_str_to_log_mask(log_mask);
@@ -2638,9 +2637,7 @@ void qemu_init(int argc, char **argv, char **envp)
     }
     }
 
 
     if (userconfig) {
     if (userconfig) {
-        if (qemu_read_default_config_file() < 0) {
-            exit(1);
-        }
+        qemu_read_default_config_file(&error_fatal);
     }
     }
 
 
     /* second pass of option parsing */
     /* second pass of option parsing */
@@ -3328,15 +3325,8 @@ void qemu_init(int argc, char **argv, char **envp)
                 qemu_plugin_opt_parse(optarg, &plugin_list);
                 qemu_plugin_opt_parse(optarg, &plugin_list);
                 break;
                 break;
             case QEMU_OPTION_readconfig:
             case QEMU_OPTION_readconfig:
-                {
-                    int ret = qemu_read_config_file(optarg);
-                    if (ret < 0) {
-                        error_report("read config %s: %s", optarg,
-                                     strerror(-ret));
-                        exit(1);
-                    }
-                    break;
-                }
+                qemu_read_config_file(optarg, &error_fatal);
+                break;
             case QEMU_OPTION_spice:
             case QEMU_OPTION_spice:
                 olist = qemu_find_opts_err("spice", NULL);
                 olist = qemu_find_opts_err("spice", NULL);
                 if (!olist) {
                 if (!olist) {
@@ -3475,6 +3465,19 @@ void qemu_init(int argc, char **argv, char **envp)
     qemu_process_help_options();
     qemu_process_help_options();
     qemu_maybe_daemonize(pid_file);
     qemu_maybe_daemonize(pid_file);
 
 
+    /*
+     * The trace backend must be initialized after daemonizing.
+     * trace_init_backends() will call st_init(), which will create the
+     * trace thread in the parent, and also register st_flush_trace_buffer()
+     * in atexit(). This function will force the parent to wait for the
+     * writeout thread to finish, which will not occur, and the parent
+     * process will be left in the host.
+     */
+    if (!trace_init_backends()) {
+        exit(1);
+    }
+    trace_init_file();
+
     qemu_init_main_loop(&error_fatal);
     qemu_init_main_loop(&error_fatal);
     cpu_timers_init();
     cpu_timers_init();
 
 

+ 7 - 2
target/i386/kvm/kvm.c

@@ -4352,8 +4352,13 @@ int kvm_arch_remove_sw_breakpoint(CPUState *cs, struct kvm_sw_breakpoint *bp)
 {
 {
     uint8_t int3;
     uint8_t int3;
 
 
-    if (cpu_memory_rw_debug(cs, bp->pc, &int3, 1, 0) || int3 != 0xcc ||
-        cpu_memory_rw_debug(cs, bp->pc, (uint8_t *)&bp->saved_insn, 1, 1)) {
+    if (cpu_memory_rw_debug(cs, bp->pc, &int3, 1, 0)) {
+        return -EINVAL;
+    }
+    if (int3 != 0xcc) {
+        return 0;
+    }
+    if (cpu_memory_rw_debug(cs, bp->pc, (uint8_t *)&bp->saved_insn, 1, 1)) {
         return -EINVAL;
         return -EINVAL;
     }
     }
     return 0;
     return 0;

+ 1 - 1
tests/fp/meson.build

@@ -624,7 +624,7 @@ test('fp-test-mulAdd', fptest,
      # no fptest_rounding_args
      # no fptest_rounding_args
      args: fptest_args +
      args: fptest_args +
            ['f16_mulAdd', 'f32_mulAdd', 'f64_mulAdd', 'f128_mulAdd'],
            ['f16_mulAdd', 'f32_mulAdd', 'f64_mulAdd', 'f128_mulAdd'],
-     suite: ['softfloat-slow', 'softfloat-ops-slow'], timeout: 60)
+     suite: ['softfloat-slow', 'softfloat-ops-slow'], timeout: 90)
 
 
 fpbench = executable(
 fpbench = executable(
   'fp-bench',
   'fp-bench',

+ 8 - 0
tests/meson.build

@@ -237,6 +237,11 @@ test_env = environment()
 test_env.set('G_TEST_SRCDIR', meson.current_source_dir())
 test_env.set('G_TEST_SRCDIR', meson.current_source_dir())
 test_env.set('G_TEST_BUILDDIR', meson.current_build_dir())
 test_env.set('G_TEST_BUILDDIR', meson.current_build_dir())
 
 
+slow_tests = {
+  'test-crypto-tlscredsx509': 45,
+  'test-crypto-tlssession': 45
+}
+
 foreach test_name, extra: tests
 foreach test_name, extra: tests
   src = [test_name + '.c']
   src = [test_name + '.c']
   deps = [qemuutil]
   deps = [qemuutil]
@@ -254,6 +259,8 @@ foreach test_name, extra: tests
        env: test_env,
        env: test_env,
        args: ['--tap', '-k'],
        args: ['--tap', '-k'],
        protocol: 'tap',
        protocol: 'tap',
+       timeout: slow_tests.get(test_name, 30),
+       priority: slow_tests.get(test_name, 30),
        suite: ['unit'])
        suite: ['unit'])
 endforeach
 endforeach
 
 
@@ -263,6 +270,7 @@ foreach bench_name, deps: benchs
   benchmark(bench_name, exe,
   benchmark(bench_name, exe,
             args: ['--tap', '-k'],
             args: ['--tap', '-k'],
             protocol: 'tap',
             protocol: 'tap',
+            timeout: 0,
             suite: ['speed'])
             suite: ['speed'])
 endforeach
 endforeach
 
 

+ 15 - 0
tests/qtest/meson.build

@@ -4,6 +4,19 @@ if not config_host.has_key('CONFIG_POSIX')
   subdir_done()
   subdir_done()
 endif
 endif
 
 
+slow_qtests = {
+  'ahci-test' : 60,
+  'bios-tables-test' : 120,
+  'boot-serial-test' : 60,
+  'migration-test' : 150,
+  'npcm7xx_pwm-test': 150,
+  'prom-env-test' : 60,
+  'pxe-test' : 60,
+  'qos-test' : 60,
+  'qom-test' : 300,
+  'test-hmp' : 120,
+}
+
 qtests_generic = [
 qtests_generic = [
   'cdrom-test',
   'cdrom-test',
   'device-introspect-test',
   'device-introspect-test',
@@ -274,6 +287,8 @@ foreach dir : target_dirs
          env: qtest_env,
          env: qtest_env,
          args: ['--tap', '-k'],
          args: ['--tap', '-k'],
          protocol: 'tap',
          protocol: 'tap',
+         timeout: slow_qtests.get(test, 30),
+         priority: slow_qtests.get(test, 30),
          suite: ['qtest', 'qtest-' + target_base])
          suite: ['qtest', 'qtest-' + target_base])
   endforeach
   endforeach
 endforeach
 endforeach

+ 7 - 6
trace/control.c

@@ -40,6 +40,7 @@ static size_t nevent_groups;
 static uint32_t next_id;
 static uint32_t next_id;
 static uint32_t next_vcpu_id;
 static uint32_t next_vcpu_id;
 static bool init_trace_on_startup;
 static bool init_trace_on_startup;
+static char *trace_opts_file;
 
 
 QemuOptsList qemu_trace_opts = {
 QemuOptsList qemu_trace_opts = {
     .name = "trace",
     .name = "trace",
@@ -224,10 +225,8 @@ static void trace_init_events(const char *fname)
 
 
 void trace_init_file(void)
 void trace_init_file(void)
 {
 {
-    QemuOpts *opts = qemu_find_opts_singleton("trace");
-    const char *file = qemu_opt_get(opts, "file");
 #ifdef CONFIG_TRACE_SIMPLE
 #ifdef CONFIG_TRACE_SIMPLE
-    st_set_trace_file(file);
+    st_set_trace_file(trace_opts_file);
     if (init_trace_on_startup) {
     if (init_trace_on_startup) {
         st_set_trace_file_enabled(true);
         st_set_trace_file_enabled(true);
     }
     }
@@ -238,11 +237,11 @@ void trace_init_file(void)
      * backend. However we should only override -D if we actually have
      * backend. However we should only override -D if we actually have
      * something to override it with.
      * something to override it with.
      */
      */
-    if (file) {
-        qemu_set_log_filename(file, &error_fatal);
+    if (trace_opts_file) {
+        qemu_set_log_filename(trace_opts_file, &error_fatal);
     }
     }
 #else
 #else
-    if (file) {
+    if (trace_opts_file) {
         fprintf(stderr, "error: --trace file=...: "
         fprintf(stderr, "error: --trace file=...: "
                 "option not supported by the selected tracing backends\n");
                 "option not supported by the selected tracing backends\n");
         exit(1);
         exit(1);
@@ -303,6 +302,8 @@ void trace_opt_parse(const char *optarg)
     }
     }
     trace_init_events(qemu_opt_get(opts, "events"));
     trace_init_events(qemu_opt_get(opts, "events"));
     init_trace_on_startup = true;
     init_trace_on_startup = true;
+    g_free(trace_opts_file);
+    trace_opts_file = g_strdup(qemu_opt_get(opts, "file"));
     qemu_opts_del(opts);
     qemu_opts_del(opts);
 }
 }
 
 

+ 12 - 11
util/qemu-config.c

@@ -350,7 +350,7 @@ void qemu_config_write(FILE *fp)
 }
 }
 
 
 /* Returns number of config groups on success, -errno on error */
 /* Returns number of config groups on success, -errno on error */
-int qemu_config_parse(FILE *fp, QemuOptsList **lists, const char *fname)
+int qemu_config_parse(FILE *fp, QemuOptsList **lists, const char *fname, Error **errp)
 {
 {
     char line[1024], group[64], id[64], arg[64], value[1024];
     char line[1024], group[64], id[64], arg[64], value[1024];
     Location loc;
     Location loc;
@@ -375,7 +375,7 @@ int qemu_config_parse(FILE *fp, QemuOptsList **lists, const char *fname)
             /* group with id */
             /* group with id */
             list = find_list(lists, group, &local_err);
             list = find_list(lists, group, &local_err);
             if (local_err) {
             if (local_err) {
-                error_report_err(local_err);
+                error_propagate(errp, local_err);
                 goto out;
                 goto out;
             }
             }
             opts = qemu_opts_create(list, id, 1, NULL);
             opts = qemu_opts_create(list, id, 1, NULL);
@@ -386,7 +386,7 @@ int qemu_config_parse(FILE *fp, QemuOptsList **lists, const char *fname)
             /* group without id */
             /* group without id */
             list = find_list(lists, group, &local_err);
             list = find_list(lists, group, &local_err);
             if (local_err) {
             if (local_err) {
-                error_report_err(local_err);
+                error_propagate(errp, local_err);
                 goto out;
                 goto out;
             }
             }
             opts = qemu_opts_create(list, NULL, 0, &error_abort);
             opts = qemu_opts_create(list, NULL, 0, &error_abort);
@@ -398,21 +398,21 @@ int qemu_config_parse(FILE *fp, QemuOptsList **lists, const char *fname)
             sscanf(line, " %63s = \"\"", arg) == 1) {
             sscanf(line, " %63s = \"\"", arg) == 1) {
             /* arg = value */
             /* arg = value */
             if (opts == NULL) {
             if (opts == NULL) {
-                error_report("no group defined");
+                error_setg(errp, "no group defined");
                 goto out;
                 goto out;
             }
             }
-            if (!qemu_opt_set(opts, arg, value, &local_err)) {
-                error_report_err(local_err);
+            if (!qemu_opt_set(opts, arg, value, errp)) {
                 goto out;
                 goto out;
             }
             }
             continue;
             continue;
         }
         }
-        error_report("parse error");
+        error_setg(errp, "parse error");
         goto out;
         goto out;
     }
     }
     if (ferror(fp)) {
     if (ferror(fp)) {
-        error_report("error reading file");
-        goto out;
+        loc_pop(&loc);
+        error_setg_errno(errp, errno, "Cannot read config file");
+        return res;
     }
     }
     res = count;
     res = count;
 out:
 out:
@@ -420,16 +420,17 @@ out:
     return res;
     return res;
 }
 }
 
 
-int qemu_read_config_file(const char *filename)
+int qemu_read_config_file(const char *filename, Error **errp)
 {
 {
     FILE *f = fopen(filename, "r");
     FILE *f = fopen(filename, "r");
     int ret;
     int ret;
 
 
     if (f == NULL) {
     if (f == NULL) {
+        error_setg_file_open(errp, errno, filename);
         return -errno;
         return -errno;
     }
     }
 
 
-    ret = qemu_config_parse(f, vm_config_groups, filename);
+    ret = qemu_config_parse(f, vm_config_groups, filename, errp);
     fclose(f);
     fclose(f);
     return ret;
     return ret;
 }
 }

+ 5 - 1
util/qemu-option.c

@@ -785,7 +785,11 @@ static const char *get_opt_name_value(const char *params,
             }
             }
             if (!is_help && warn_on_flag) {
             if (!is_help && warn_on_flag) {
                 warn_report("short-form boolean option '%s%s' deprecated", prefix, *name);
                 warn_report("short-form boolean option '%s%s' deprecated", prefix, *name);
-                error_printf("Please use %s=%s instead\n", *name, *value);
+                if (g_str_equal(*name, "delay")) {
+                    error_printf("Please use nodelay=%s instead\n", prefix[0] ? "on" : "off");
+                } else {
+                    error_printf("Please use %s=%s instead\n", *name, *value);
+                }
             }
             }
         }
         }
     } else {
     } else {