* 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.
run-ninja: config-host.mak
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)
endif
endif

View File

@ -598,8 +598,12 @@ static void kvm_memslot_init_dirty_bitmap(KVMSlot *mem)
* too, in most cases).
* 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.
*
* 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;
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_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,
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;
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
* 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;
}
ret = qemu_config_parse(f, config_groups, filename);
ret = qemu_config_parse(f, config_groups, filename, errp);
if (ret < 0) {
error_setg(errp, "Could not parse blkdebug config file");
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);
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 can't just check for existence of 'server'

View File

@ -867,6 +867,9 @@ QemuOptsList qemu_chardev_opts = {
},{
.name = "delay",
.type = QEMU_OPT_BOOL,
},{
.name = "nodelay",
.type = QEMU_OPT_BOOL,
},{
.name = "reconnect",
.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
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)
'''''''''''''''''''''''''''''
@ -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
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
------------------------------------

View File

@ -3505,7 +3505,7 @@ int gdbserver_start(const char *device)
if (strstart(device, "tcp:", NULL)) {
/* enforce required TCP attributes */
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;
}
#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 =
((void *)nhdr64) + nhdr_size64 +
QEMU_ALIGN_UP(nhdr_namesz, phdr_align);
pvh_start_addr = *elf_note_data_addr;
} else {
struct elf32_note *nhdr32 = (struct elf32_note *)arg1;
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 =
((void *)nhdr32) + nhdr_size32 +
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;
}

View File

@ -25,6 +25,7 @@
#include "hw/intc/i8259.h"
#include "hw/pci/msi.h"
#include "qemu/host-utils.h"
#include "sysemu/kvm.h"
#include "trace.h"
#include "hw/i386/apic-msidef.h"
#include "qapi/error.h"
@ -875,6 +876,11 @@ static void apic_realize(DeviceState *dev, Error **errp)
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",
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);
}
static void lsi_scsi_unrealize(DeviceState *dev)
static void lsi_scsi_exit(PCIDevice *dev)
{
LSIState *s = LSI53C895A(dev);
@ -2325,11 +2325,11 @@ static void lsi_class_init(ObjectClass *klass, void *data)
PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
k->realize = lsi_scsi_realize;
k->exit = lsi_scsi_exit;
k->vendor_id = PCI_VENDOR_ID_LSI_LOGIC;
k->device_id = PCI_DEVICE_ID_LSI_53C895A;
k->class_id = PCI_CLASS_STORAGE_SCSI;
k->subsystem_id = 0x1000;
dc->unrealize = lsi_scsi_unrealize;
dc->reset = lsi_scsi_reset;
dc->vmsd = &vmstate_lsi_scsi;
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->hba_private = hba_private;
req->status = -1;
req->host_status = -1;
req->ops = reqops;
object_ref(OBJECT(d));
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)
{
assert(req->status == -1);
assert(req->status == -1 && req->host_status == -1);
req->status = status;
req->host_status = SCSI_HOST_OK;
assert(req->sense_len <= sizeof(req->sense));
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) {
assert(!req->io_canceled);
assert(req->status == -1);
assert(req->status == -1 && req->host_status == -1);
assert(req->enqueued);
qemu_put_sbyte(f, req->retry ? 1 : 2);

View File

@ -77,7 +77,6 @@ typedef struct SCSIDiskReq {
struct iovec iov;
QEMUIOVector qiov;
BlockAcctCookie acct;
unsigned char *status;
} SCSIDiskReq;
#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) {
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;
@ -2697,8 +2694,47 @@ typedef struct SCSIBlockReq {
/* CDB passed to SG_IO. */
uint8_t cdb[16];
BlockCompletionFunc *cb;
void *cb_opaque;
} 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,
int64_t offset, QEMUIOVector *iov,
int direction,
@ -2777,9 +2813,11 @@ static BlockAIOCB *scsi_block_do_sgio(SCSIBlockReq *req,
io_header->timeout = s->qdev.io_timeout * 1000;
io_header->usr_ptr = r;
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,
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);
return aiocb;
}
@ -2893,7 +2931,6 @@ static int32_t scsi_block_dma_command(SCSIRequest *req, uint8_t *buf)
return 0;
}
r->req.status = &r->io_header.status;
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;
SCSISense sense;
sg_io_hdr_t *io_hdr = &r->io_header;
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);
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);
}
} 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);
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);
goto done;
}

View File

@ -500,6 +500,51 @@ static void virtio_scsi_complete_cmd_req(VirtIOSCSIReq *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)
{
VirtIOSCSIReq *req = r->hba_private;
@ -908,6 +953,7 @@ static struct SCSIBusInfo virtio_scsi_scsi_info = {
.max_lun = VIRTIO_SCSI_MAX_LUN,
.complete = virtio_scsi_command_complete,
.fail = virtio_scsi_command_failed,
.cancel = virtio_scsi_request_cancelled,
.change = virtio_scsi_change,
.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);
}
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
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,
.complete = pvscsi_command_complete,
.cancel = pvscsi_request_cancelled,
.fail = pvscsi_command_failed,
};
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,
*(uint64_t *)translate_opaque);
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;
}

View File

@ -27,7 +27,8 @@ struct SCSIRequest {
uint32_t refcount;
uint32_t tag;
uint32_t lun;
uint32_t status;
int16_t status;
int16_t host_status;
void *hba_private;
size_t resid;
SCSICommand cmd;
@ -123,6 +124,7 @@ struct SCSIBusInfo {
int (*parse_cdb)(SCSIDevice *dev, SCSICommand *cmd, uint8_t *buf,
void *hba_private);
void (*transfer_data)(SCSIRequest *req, uint32_t arg);
void (*fail)(SCSIRequest *req);
void (*complete)(SCSIRequest *req, size_t resid);
void (*cancel)(SCSIRequest *req);
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_data(SCSIRequest *req, int len);
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);
int scsi_req_get_sense(SCSIRequest *req, uint8_t *buf, int len);
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);
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
enumerated (0..(n-1)) configuration "sections") */

View File

@ -16,6 +16,22 @@ enum SCSIXferMode {
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 {
uint8_t buf[SCSI_CMD_BUF_SIZE];
int len;
@ -123,18 +139,9 @@ int scsi_cdb_length(uint8_t *buf);
#ifdef CONFIG_LINUX
#define SG_ERR_DRIVER_TIMEOUT 0x06
#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
int scsi_sense_from_errno(int errno_value, SCSISense *sense);
int scsi_sense_from_host_status(uint8_t host_status, SCSISense *sense);
#endif

View File

@ -1574,6 +1574,18 @@ if have_system
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_opt = get_option('fdt')
if have_system

View File

@ -3033,7 +3033,7 @@ DEFHEADING(Character device options:)
DEF("chardev", HAS_ARG, QEMU_OPTION_chardev,
"-chardev help\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"
" [,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"
@ -3184,7 +3184,7 @@ The available backends are:
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
be bound. For a connecting socket species the remote host to
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
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]``
``path`` specifies the local path of the unix socket. ``path``
@ -3593,13 +3593,13 @@ SRST
``telnet options:``
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
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
port. If you use the ``server=on`` option QEMU will wait for a client
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 only applies if ``server=no`` is set, if the connection goes
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``
-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
options work the same as if you had specified ``-serial tcp``.
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
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
port acts as a WebSocket server. Client mode is not supported.

View File

@ -1,5 +1,5 @@
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',
'-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'],
link_args: link_args,
vs_module_defs: 'qga-vss.def',
dependencies: [glib_static, socket,
dependencies: [glib_dynamic, socket,
cc.find_library('ole32'),
cc.find_library('oleaut32'),
cc.find_library('shlwapi'),

View File

@ -8,6 +8,7 @@
#include "qapi/qobject-input-visitor.h"
#include "qom/object_interfaces.h"
#include "qemu/help_option.h"
#include "qemu/id.h"
#include "qemu/module.h"
#include "qemu/option.h"
#include "qapi/opts-visitor.h"
@ -41,11 +42,19 @@ Object *user_creatable_add_type(const char *type, const char *id,
const QDict *qdict,
Visitor *v, Error **errp)
{
ERRP_GUARD();
Object *obj;
ObjectClass *klass;
const QDictEntry *e;
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);
if (!klass) {
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.dxfer_len = data->sz;
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) {
data->sz -= io_hdr.resid;
} else {
data->sz = 0;
}
if (status == CHECK_CONDITION &&
!(io_hdr.driver_status & SG_ERR_DRIVER_SENSE)) {
scsi_build_sense(data->sense, sense_code);
}
return status;
}

View File

@ -257,6 +257,21 @@ const struct SCSISense sense_code_LUN_COMM_FAILURE = {
.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 */
const struct SCSISense sense_code_READ_ERROR = {
.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

View File

@ -2062,17 +2062,19 @@ static int global_init_func(void *opaque, QemuOpts *opts, Error **errp)
return 0;
}
static int qemu_read_default_config_file(void)
static void qemu_read_default_config_file(Error **errp)
{
ERRP_GUARD();
int ret;
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)
@ -2361,13 +2363,10 @@ static void qemu_process_early_options(void)
cleanup_add_fd, NULL, &error_fatal);
#endif
if (!trace_init_backends()) {
exit(1);
}
trace_init_file();
/* 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) {
int 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 (qemu_read_default_config_file() < 0) {
exit(1);
}
qemu_read_default_config_file(&error_fatal);
}
/* 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);
break;
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:
olist = qemu_find_opts_err("spice", NULL);
if (!olist) {
@ -3475,6 +3465,19 @@ void qemu_init(int argc, char **argv, char **envp)
qemu_process_help_options();
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);
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;
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 0;

View File

@ -624,7 +624,7 @@ test('fp-test-mulAdd', fptest,
# no fptest_rounding_args
args: fptest_args +
['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(
'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_BUILDDIR', meson.current_build_dir())
slow_tests = {
'test-crypto-tlscredsx509': 45,
'test-crypto-tlssession': 45
}
foreach test_name, extra: tests
src = [test_name + '.c']
deps = [qemuutil]
@ -254,6 +259,8 @@ foreach test_name, extra: tests
env: test_env,
args: ['--tap', '-k'],
protocol: 'tap',
timeout: slow_tests.get(test_name, 30),
priority: slow_tests.get(test_name, 30),
suite: ['unit'])
endforeach
@ -263,6 +270,7 @@ foreach bench_name, deps: benchs
benchmark(bench_name, exe,
args: ['--tap', '-k'],
protocol: 'tap',
timeout: 0,
suite: ['speed'])
endforeach

View File

@ -4,6 +4,19 @@ if not config_host.has_key('CONFIG_POSIX')
subdir_done()
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 = [
'cdrom-test',
'device-introspect-test',
@ -274,6 +287,8 @@ foreach dir : target_dirs
env: qtest_env,
args: ['--tap', '-k'],
protocol: 'tap',
timeout: slow_qtests.get(test, 30),
priority: slow_qtests.get(test, 30),
suite: ['qtest', 'qtest-' + target_base])
endforeach
endforeach

View File

@ -40,6 +40,7 @@ static size_t nevent_groups;
static uint32_t next_id;
static uint32_t next_vcpu_id;
static bool init_trace_on_startup;
static char *trace_opts_file;
QemuOptsList qemu_trace_opts = {
.name = "trace",
@ -224,10 +225,8 @@ static void trace_init_events(const char *fname)
void trace_init_file(void)
{
QemuOpts *opts = qemu_find_opts_singleton("trace");
const char *file = qemu_opt_get(opts, "file");
#ifdef CONFIG_TRACE_SIMPLE
st_set_trace_file(file);
st_set_trace_file(trace_opts_file);
if (init_trace_on_startup) {
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
* 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
if (file) {
if (trace_opts_file) {
fprintf(stderr, "error: --trace file=...: "
"option not supported by the selected tracing backends\n");
exit(1);
@ -303,6 +302,8 @@ void trace_opt_parse(const char *optarg)
}
trace_init_events(qemu_opt_get(opts, "events"));
init_trace_on_startup = true;
g_free(trace_opts_file);
trace_opts_file = g_strdup(qemu_opt_get(opts, "file"));
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 */
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];
Location loc;
@ -375,7 +375,7 @@ int qemu_config_parse(FILE *fp, QemuOptsList **lists, const char *fname)
/* group with id */
list = find_list(lists, group, &local_err);
if (local_err) {
error_report_err(local_err);
error_propagate(errp, local_err);
goto out;
}
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 */
list = find_list(lists, group, &local_err);
if (local_err) {
error_report_err(local_err);
error_propagate(errp, local_err);
goto out;
}
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) {
/* arg = value */
if (opts == NULL) {
error_report("no group defined");
error_setg(errp, "no group defined");
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;
}
continue;
}
error_report("parse error");
error_setg(errp, "parse error");
goto out;
}
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;
out:
@ -420,16 +420,17 @@ out:
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");
int ret;
if (f == NULL) {
error_setg_file_open(errp, errno, filename);
return -errno;
}
ret = qemu_config_parse(f, vm_config_groups, filename);
ret = qemu_config_parse(f, vm_config_groups, filename, errp);
fclose(f);
return ret;
}

View File

@ -785,7 +785,11 @@ static const char *get_opt_name_value(const char *params,
}
if (!is_help && warn_on_flag) {
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 {