* 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)
 -----BEGIN PGP SIGNATURE-----
 
 iQFIBAABCAAyFiEE8TM4V0tmI4mGbHaCv/vSX3jHroMFAmBDXMAUHHBib256aW5p
 QHJlZGhhdC5jb20ACgkQv/vSX3jHroPYPwf/YeM8TYqCFCt3Th4Ap2IuMqI/7HRq
 iNFlKWfM2S7Gk87RaNINL96MHadOteeYSQLuh4Y6FHL1OGpWX2ZByXR//z2DARLC
 AuV1IncevVyQiSDQzwZj6BU7G4b8xSU3Ey5yseYv+hjUhVbiscDvpioV2USkUvD5
 IJFXwL5+eRAOGma0SAcumgwu5xc5/GGh5D63vZ0R7q5eDCu69Q6/ZYvK93b6+TP7
 GWboGJFcbTvYku56S4ip8VdEzxiNhfQgGNa3nNDx4ejiTt4mYAft7wy+j/iQjPW9
 P0y4AYuvInCrUy1RBR1BqAE+ZXNxqby3AQ0ZTujG+YMiWLIvz5FZtGEvyg==
 =aCET
 -----END PGP SIGNATURE-----

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>
This commit is contained in:
Peter Maydell 2021-03-08 13:51:41 +00:00
commit 0436c55edf
33 changed files with 434 additions and 124 deletions

View File

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

View File

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

View File

@ -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;
} }
} }

View File

@ -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"); if (qemu_opt_get(opts, "delay") && qemu_opt_get(opts, "nodelay")) {
sock->nodelay = !qemu_opt_get_bool(opts, "delay", true); 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'

View File

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

View File

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

View File

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

View File

@ -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;
} }

View File

@ -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);

View File

@ -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);

View File

@ -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);

View File

@ -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);
} }

View File

@ -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 (ret < 0) {
if (status == CHECK_CONDITION) { status = scsi_sense_from_errno(-ret, &sense);
if (r->io_header.driver_status & SG_ERR_DRIVER_SENSE) { if (status == CHECK_CONDITION) {
r->req.sense_len = r->io_header.sb_len_wr;
} else {
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;
} }

View File

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

View File

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

View File

@ -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 = elf_note_fn((void *)nhdr, (void *)&ph->p_align, SZ == 64);
sizeof(struct elf_note) == sizeof(struct elf64_note);
elf_note_fn((void *)nhdr, (void *)&ph->p_align, is64);
} }
data = NULL; data = NULL;
} }

View File

@ -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);

View File

@ -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") */

View File

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

View File

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

View File

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

View File

@ -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'),

View File

@ -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);

View File

@ -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;
} }

View File

@ -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 scsi_sense_from_host_status(uint8_t host_status,
int sg_io_sense_from_errno(int errno_value, struct sg_io_hdr *io_hdr, SCSISense *sense)
SCSISense *sense)
{ {
if (errno_value != 0) { switch (host_status) {
return scsi_sense_from_errno(errno_value, sense); case SCSI_HOST_NO_LUN:
} else { *sense = SENSE_CODE(LUN_NOT_RESPONDING);
if (io_hdr->host_status == SG_ERR_DID_NO_CONNECT || return CHECK_CONDITION;
io_hdr->host_status == SG_ERR_DID_BUS_BUSY || case SCSI_HOST_BUSY:
io_hdr->host_status == SG_ERR_DID_TIME_OUT || return BUSY;
(io_hdr->driver_status & SG_ERR_DRIVER_TIMEOUT)) { case SCSI_HOST_TIME_OUT:
return BUSY; *sense = SENSE_CODE(COMMAND_TIMEOUT);
} else if (io_hdr->host_status) { return CHECK_CONDITION;
*sense = SENSE_CODE(I_T_NEXUS_LOSS); case SCSI_HOST_BAD_RESPONSE:
return CHECK_CONDITION; *sense = SENSE_CODE(LUN_COMM_FAILURE);
} else if (io_hdr->status) { return CHECK_CONDITION;
return io_hdr->status; case SCSI_HOST_ABORTED:
} else if (io_hdr->driver_status & SG_ERR_DRIVER_SENSE) { *sense = SENSE_CODE(COMMAND_ABORTED);
return CHECK_CONDITION; return CHECK_CONDITION;
} else { case SCSI_HOST_RESET:
return GOOD; *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

View File

@ -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); ret = qemu_read_config_file(file, errp);
if (ret < 0 && ret != -ENOENT) { if (ret < 0) {
return ret; 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) { qemu_read_default_config_file(&error_fatal);
exit(1);
}
} }
/* 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:
{ qemu_read_config_file(optarg, &error_fatal);
int ret = qemu_read_config_file(optarg); break;
if (ret < 0) {
error_report("read config %s: %s", optarg,
strerror(-ret));
exit(1);
}
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();

View File

@ -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 || if (cpu_memory_rw_debug(cs, bp->pc, &int3, 1, 0)) {
cpu_memory_rw_debug(cs, bp->pc, (uint8_t *)&bp->saved_insn, 1, 1)) { 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;

View File

@ -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',

View File

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

View File

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

View File

@ -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) { if (trace_opts_file) {
qemu_set_log_filename(file, &error_fatal); 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);
} }

View File

@ -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)) { if (!qemu_opt_set(opts, arg, value, errp)) {
error_report_err(local_err);
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"); loc_pop(&loc);
goto out; 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;
} }

View File

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