diff --git a/contrib/libvhost-user/libvhost-user.c b/contrib/libvhost-user/libvhost-user.c index cb5f5770e4c6ba73df06ea8c7d72794bde1ca796..164e6d1df897acf586dbfc95614673c60e4ef0cc 100644 --- a/contrib/libvhost-user/libvhost-user.c +++ b/contrib/libvhost-user/libvhost-user.c @@ -387,26 +387,37 @@ vu_send_reply(VuDev *dev, int conn_fd, VhostUserMsg *vmsg) return vu_message_write(dev, conn_fd, vmsg); } +/* + * Processes a reply on the slave channel. + * Entered with slave_mutex held and releases it before exit. + * Returns true on success. + */ static bool vu_process_message_reply(VuDev *dev, const VhostUserMsg *vmsg) { VhostUserMsg msg_reply; + bool result = false; if ((vmsg->flags & VHOST_USER_NEED_REPLY_MASK) == 0) { - return true; + result = true; + goto out; } if (!vu_message_read(dev, dev->slave_fd, &msg_reply)) { - return false; + goto out; } if (msg_reply.request != vmsg->request) { DPRINT("Received unexpected msg type. Expected %d received %d", vmsg->request, msg_reply.request); - return false; + goto out; } - return msg_reply.payload.u64 == 0; + result = msg_reply.payload.u64 == 0; + +out: + pthread_mutex_unlock(&dev->slave_mutex); + return result; } /* Kick the log_call_fd if required. */ @@ -548,6 +559,21 @@ vu_reset_device_exec(VuDev *dev, VhostUserMsg *vmsg) return false; } +static bool +map_ring(VuDev *dev, VuVirtq *vq) +{ + vq->vring.desc = qva_to_va(dev, vq->vra.desc_user_addr); + vq->vring.used = qva_to_va(dev, vq->vra.used_user_addr); + vq->vring.avail = qva_to_va(dev, vq->vra.avail_user_addr); + + DPRINT("Setting virtq addresses:\n"); + DPRINT(" vring_desc at %p\n", vq->vring.desc); + DPRINT(" vring_used at %p\n", vq->vring.used); + DPRINT(" vring_avail at %p\n", vq->vring.avail); + + return !(vq->vring.desc && vq->vring.used && vq->vring.avail); +} + static bool vu_set_mem_table_exec_postcopy(VuDev *dev, VhostUserMsg *vmsg) { @@ -751,6 +777,14 @@ vu_set_mem_table_exec(VuDev *dev, VhostUserMsg *vmsg) close(vmsg->fds[i]); } + for (i = 0; i < dev->max_queues; i++) { + if (dev->vq[i].vring.desc) { + if (map_ring(dev, &dev->vq[i])) { + vu_panic(dev, "remaping queue %d during setmemtable", i); + } + } + } + return false; } @@ -837,18 +871,12 @@ vu_set_vring_addr_exec(VuDev *dev, VhostUserMsg *vmsg) DPRINT(" avail_user_addr: 0x%016" PRIx64 "\n", vra->avail_user_addr); DPRINT(" log_guest_addr: 0x%016" PRIx64 "\n", vra->log_guest_addr); + vq->vra = *vra; vq->vring.flags = vra->flags; - vq->vring.desc = qva_to_va(dev, vra->desc_user_addr); - vq->vring.used = qva_to_va(dev, vra->used_user_addr); - vq->vring.avail = qva_to_va(dev, vra->avail_user_addr); vq->vring.log_guest_addr = vra->log_guest_addr; - DPRINT("Setting virtq addresses:\n"); - DPRINT(" vring_desc at %p\n", vq->vring.desc); - DPRINT(" vring_used at %p\n", vq->vring.used); - DPRINT(" vring_avail at %p\n", vq->vring.avail); - if (!(vq->vring.desc && vq->vring.used && vq->vring.avail)) { + if (map_ring(dev, vq)) { vu_panic(dev, "Invalid vring_addr message"); return false; } @@ -1102,10 +1130,13 @@ bool vu_set_queue_host_notifier(VuDev *dev, VuVirtq *vq, int fd, return false; } + pthread_mutex_lock(&dev->slave_mutex); if (!vu_message_write(dev, dev->slave_fd, &vmsg)) { + pthread_mutex_unlock(&dev->slave_mutex); return false; } + /* Also unlocks the slave_mutex */ return vu_process_message_reply(dev, &vmsg); } @@ -1625,6 +1656,7 @@ vu_deinit(VuDev *dev) close(dev->slave_fd); dev->slave_fd = -1; } + pthread_mutex_destroy(&dev->slave_mutex); if (dev->sock != -1) { close(dev->sock); @@ -1660,6 +1692,7 @@ vu_init(VuDev *dev, dev->remove_watch = remove_watch; dev->iface = iface; dev->log_call_fd = -1; + pthread_mutex_init(&dev->slave_mutex, NULL); dev->slave_fd = -1; dev->max_queues = max_queues; diff --git a/contrib/libvhost-user/libvhost-user.h b/contrib/libvhost-user/libvhost-user.h index 46b600799b2ef48b61ec8140fd5e66c1700d756c..5cb7708559a82e398dd38cffe8a72a929ac77001 100644 --- a/contrib/libvhost-user/libvhost-user.h +++ b/contrib/libvhost-user/libvhost-user.h @@ -19,6 +19,7 @@ #include #include #include +#include #include "standard-headers/linux/virtio_ring.h" /* Based on qemu/hw/virtio/vhost-user.c */ @@ -326,6 +327,9 @@ typedef struct VuVirtq { int err_fd; unsigned int enable; bool started; + + /* Guest addresses of our ring */ + struct vhost_vring_addr vra; } VuVirtq; enum VuWatchCondtion { @@ -355,6 +359,8 @@ struct VuDev { VuVirtq *vq; VuDevInflightInfo inflight_info; int log_call_fd; + /* Must be held while using slave_fd */ + pthread_mutex_t slave_mutex; int slave_fd; uint64_t log_size; uint8_t *log_table; diff --git a/hw/block/virtio-blk.c b/hw/block/virtio-blk.c index 2db9804cfef19d82e72ff36baa30e1afcec18ac4..fbe2ed677916d60e550d9af507495bfba5105d8c 100644 --- a/hw/block/virtio-blk.c +++ b/hw/block/virtio-blk.c @@ -766,13 +766,16 @@ bool virtio_blk_handle_vq(VirtIOBlock *s, VirtQueue *vq) { VirtIOBlockReq *req; MultiReqBuffer mrb = {}; + bool suppress_notifications = virtio_queue_get_notification(vq); bool progress = false; aio_context_acquire(blk_get_aio_context(s->blk)); blk_io_plug(s->blk); do { - virtio_queue_set_notification(vq, 0); + if (suppress_notifications) { + virtio_queue_set_notification(vq, 0); + } while ((req = virtio_blk_get_request(s, vq))) { progress = true; @@ -783,7 +786,9 @@ bool virtio_blk_handle_vq(VirtIOBlock *s, VirtQueue *vq) } } - virtio_queue_set_notification(vq, 1); + if (suppress_notifications) { + virtio_queue_set_notification(vq, 1); + } } while (!virtio_queue_empty(vq)); if (mrb.num_reqs) { diff --git a/hw/intc/xics.c b/hw/intc/xics.c index faa976e2f8a8272c0e9a561ed34922deb6e40a36..d2d377fc85fd9ba8672f4d12ab754a03267ac0aa 100644 --- a/hw/intc/xics.c +++ b/hw/intc/xics.c @@ -303,9 +303,6 @@ static void icp_reset_handler(void *dev) icp->pending_priority = 0xff; icp->mfrr = 0xff; - /* Make all outputs are deasserted */ - qemu_set_irq(icp->output, 0); - if (kvm_irqchip_in_kernel()) { Error *local_err = NULL; diff --git a/hw/scsi/virtio-scsi.c b/hw/scsi/virtio-scsi.c index 8b9e5e2b49d7596dd8f03fe3f17eabe8cc149f23..eddb13e7c6d1472b3c13cd76d284c3190800e2db 100644 --- a/hw/scsi/virtio-scsi.c +++ b/hw/scsi/virtio-scsi.c @@ -594,12 +594,15 @@ bool virtio_scsi_handle_cmd_vq(VirtIOSCSI *s, VirtQueue *vq) { VirtIOSCSIReq *req, *next; int ret = 0; + bool suppress_notifications = virtio_queue_get_notification(vq); bool progress = false; QTAILQ_HEAD(, VirtIOSCSIReq) reqs = QTAILQ_HEAD_INITIALIZER(reqs); do { - virtio_queue_set_notification(vq, 0); + if (suppress_notifications) { + virtio_queue_set_notification(vq, 0); + } while ((req = virtio_scsi_pop_req(s, vq))) { progress = true; @@ -619,7 +622,9 @@ bool virtio_scsi_handle_cmd_vq(VirtIOSCSI *s, VirtQueue *vq) } } - virtio_queue_set_notification(vq, 1); + if (suppress_notifications) { + virtio_queue_set_notification(vq, 1); + } } while (ret != -EINVAL && !virtio_queue_empty(vq)); QTAILQ_FOREACH_SAFE(req, &reqs, next, next) { diff --git a/hw/usb/hcd-xhci.c b/hw/usb/hcd-xhci.c index 24565de1d171e11ef12c229dc82131e28ae7db2b..4b42f53b9c9cb1491b18e3ae004bf881a1d4a948 100644 --- a/hw/usb/hcd-xhci.c +++ b/hw/usb/hcd-xhci.c @@ -1860,6 +1860,13 @@ static void xhci_kick_ep(XHCIState *xhci, unsigned int slotid, xhci_kick_epctx(epctx, streamid); } +static bool xhci_slot_ok(XHCIState *xhci, int slotid) +{ + return (xhci->slots[slotid - 1].uport && + xhci->slots[slotid - 1].uport->dev && + xhci->slots[slotid - 1].uport->dev->attached); +} + static void xhci_kick_epctx(XHCIEPContext *epctx, unsigned int streamid) { XHCIState *xhci = epctx->xhci; @@ -1877,9 +1884,7 @@ static void xhci_kick_epctx(XHCIEPContext *epctx, unsigned int streamid) /* If the device has been detached, but the guest has not noticed this yet the 2 above checks will succeed, but we must NOT continue */ - if (!xhci->slots[epctx->slotid - 1].uport || - !xhci->slots[epctx->slotid - 1].uport->dev || - !xhci->slots[epctx->slotid - 1].uport->dev->attached) { + if (!xhci_slot_ok(xhci, epctx->slotid)) { return; } @@ -1986,6 +1991,10 @@ static void xhci_kick_epctx(XHCIEPContext *epctx, unsigned int streamid) } else { xhci_fire_transfer(xhci, xfer, epctx); } + if (!xhci_slot_ok(xhci, epctx->slotid)) { + /* surprise removal -> stop processing */ + break; + } if (xfer->complete) { /* update ring dequeue ptr */ xhci_set_ep_state(xhci, epctx, stctx, epctx->state); diff --git a/hw/usb/redirect.c b/hw/usb/redirect.c index 9764a579877ce69a2099fd1d7b6e2508cce3e1eb..3cf82589ede2644666ec15e612955425af7c3dc6 100644 --- a/hw/usb/redirect.c +++ b/hw/usb/redirect.c @@ -109,6 +109,7 @@ struct USBRedirDevice { /* Properties */ CharBackend cs; bool enable_streams; + bool in_write; uint8_t debug; int32_t bootindex; char *filter_str; @@ -286,6 +287,13 @@ static int usbredir_write(void *priv, uint8_t *data, int count) return 0; } + /* Recursion check */ + if (dev->in_write) { + DPRINTF("usbredir_write recursion\n"); + return 0; + } + dev->in_write = true; + r = qemu_chr_fe_write(&dev->cs, data, count); if (r < count) { if (!dev->watch) { @@ -296,6 +304,7 @@ static int usbredir_write(void *priv, uint8_t *data, int count) r = 0; } } + dev->in_write = false; return r; } diff --git a/hw/virtio/vhost-user.c b/hw/virtio/vhost-user.c index 4ca5b2551e1288c3b5c193d287881f8a832917a3..f0127742101fb428d7cf4e9f69eef0299a5d115b 100644 --- a/hw/virtio/vhost-user.c +++ b/hw/virtio/vhost-user.c @@ -1054,7 +1054,7 @@ static void slave_read(void *opaque) fd[0]); break; default: - error_report("Received unexpected msg type."); + error_report("Received unexpected msg type: %d.", hdr.request); ret = -EINVAL; } diff --git a/hw/virtio/vhost.c b/hw/virtio/vhost.c index 9c16f0d107d5e513fdc8d01d8bd3c5bc03387a7c..ae61c33c15a747c6b5ca90a6515c6b0303d87793 100644 --- a/hw/virtio/vhost.c +++ b/hw/virtio/vhost.c @@ -591,9 +591,10 @@ static void vhost_region_add_section(struct vhost_dev *dev, * match up in the same RAMBlock if they do. */ if (mrs_gpa < prev_gpa_start) { - error_report("%s:Section rounded to %"PRIx64 - " prior to previous %"PRIx64, - __func__, mrs_gpa, prev_gpa_start); + error_report("%s:Section '%s' rounded to %"PRIx64 + " prior to previous '%s' %"PRIx64, + __func__, section->mr->name, mrs_gpa, + prev_sec->mr->name, prev_gpa_start); /* A way to cleanly fail here would be better */ return; } diff --git a/hw/virtio/virtio.c b/hw/virtio/virtio.c index 90971f4afab0134850e43010a3677ab380a7d8b5..daa82503329154085e8c352de29d8e001c4a8426 100644 --- a/hw/virtio/virtio.c +++ b/hw/virtio/virtio.c @@ -390,6 +390,11 @@ void virtio_queue_set_notification(VirtQueue *vq, int enable) rcu_read_unlock(); } +bool virtio_queue_get_notification(VirtQueue *vq) +{ + return vq->notification; +} + int virtio_queue_ready(VirtQueue *vq) { return vq->vring.avail != 0; @@ -2572,17 +2577,12 @@ static bool virtio_queue_host_notifier_aio_poll(void *opaque) { EventNotifier *n = opaque; VirtQueue *vq = container_of(n, VirtQueue, host_notifier); - bool progress; if (!vq->vring.desc || virtio_queue_empty(vq)) { return false; } - progress = virtio_queue_notify_aio_vq(vq); - - /* In case the handler function re-enabled notifications */ - virtio_queue_set_notification(vq, 0); - return progress; + return virtio_queue_notify_aio_vq(vq); } static void virtio_queue_host_notifier_aio_poll_end(EventNotifier *n) diff --git a/include/hw/virtio/virtio.h b/include/hw/virtio/virtio.h index ca2fbaeb351bc2d8a59baefc1ccf189ba5f40dbd..7394715407cee6ac66a87f52ec37205f52b5e830 100644 --- a/include/hw/virtio/virtio.h +++ b/include/hw/virtio/virtio.h @@ -229,6 +229,7 @@ int virtio_load(VirtIODevice *vdev, QEMUFile *f, int version_id); void virtio_notify_config(VirtIODevice *vdev); +bool virtio_queue_get_notification(VirtQueue *vq); void virtio_queue_set_notification(VirtQueue *vq, int enable); int virtio_queue_ready(VirtQueue *vq); diff --git a/qemu-deprecated.texi b/qemu-deprecated.texi index fff07bb2a3199970ce398dd097d083ebb8d0c3e1..719ac23d72f9ce791d15618d6709f4d1abce1350 100644 --- a/qemu-deprecated.texi +++ b/qemu-deprecated.texi @@ -331,3 +331,11 @@ existing CPU models. Management software that needs runnability guarantees must resolve the CPU model aliases using te ``alias-of'' field returned by the ``query-cpu-definitions'' QMP command. + +While those guarantees are kept, the return value of +``query-cpu-definitions'' will have existing CPU model aliases +point to a version that doesn't break runnability guarantees +(specifically, version 1 of those CPU models). In future QEMU +versions, aliases will point to newer CPU model versions +depending on the machine type, so management software must +resolve CPU model aliases before starting a virtual machine. diff --git a/target/i386/cpu.c b/target/i386/cpu.c index e0f3a2dd991eec7deb8e1c9831fd8e70cda3492f..22e0e89718b2052aebf77806011f59c75666adf9 100644 --- a/target/i386/cpu.c +++ b/target/i386/cpu.c @@ -3933,7 +3933,13 @@ static PropValue tcg_default_props[] = { }; -X86CPUVersion default_cpu_version = CPU_VERSION_LATEST; +/* + * We resolve CPU model aliases using -v1 when using "-machine + * none", but this is just for compatibility while libvirt isn't + * adapted to resolve CPU model versions before creating VMs. + * See "Runnability guarantee of CPU models" at * qemu-deprecated.texi. + */ +X86CPUVersion default_cpu_version = 1; void x86_cpu_set_default_version(X86CPUVersion version) {