From f41d912023e777d95e782a1ade6338c5fed8b842 Mon Sep 17 00:00:00 2001 From: "Michael S. Tsirkin" Date: Thu, 8 Feb 2018 19:26:51 +0200 Subject: Revert "vhost: add traces for memory listeners" This reverts commit 0750b060216de69ed1f14bc08181bf4ad27fc622. Follow up patches are reworking the memory listeners, the new mechanism will add its own set of traces. Signed-off-by: Michael S. Tsirkin --- hw/virtio/trace-events | 6 ------ hw/virtio/vhost.c | 7 ------- 2 files changed, 13 deletions(-) (limited to 'hw/virtio') diff --git a/hw/virtio/trace-events b/hw/virtio/trace-events index 2b8f81e..775461a 100644 --- a/hw/virtio/trace-events +++ b/hw/virtio/trace-events @@ -25,9 +25,3 @@ virtio_balloon_handle_output(const char *name, uint64_t gpa) "section name: %s g virtio_balloon_get_config(uint32_t num_pages, uint32_t actual) "num_pages: %d actual: %d" virtio_balloon_set_config(uint32_t actual, uint32_t oldactual) "actual: %d oldactual: %d" virtio_balloon_to_target(uint64_t target, uint32_t num_pages) "balloon target: 0x%"PRIx64" num_pages: %d" - -# hw/virtio/vhost.c -vhost_region_add(void *p, const char *mr) "dev %p mr %s" -vhost_region_del(void *p, const char *mr) "dev %p mr %s" -vhost_iommu_region_add(void *p, const char *mr) "dev %p mr %s" -vhost_iommu_region_del(void *p, const char *mr) "dev %p mr %s" diff --git a/hw/virtio/vhost.c b/hw/virtio/vhost.c index 338e439..23b9e17 100644 --- a/hw/virtio/vhost.c +++ b/hw/virtio/vhost.c @@ -27,7 +27,6 @@ #include "hw/virtio/virtio-access.h" #include "migration/blocker.h" #include "sysemu/dma.h" -#include "trace.h" /* enabled until disconnected backend stabilizes */ #define _VHOST_DEBUG 1 @@ -694,7 +693,6 @@ static void vhost_region_add(MemoryListener *listener, return; } - trace_vhost_region_add(dev, section->mr->name ?: NULL); ++dev->n_mem_sections; dev->mem_sections = g_renew(MemoryRegionSection, dev->mem_sections, dev->n_mem_sections); @@ -714,7 +712,6 @@ static void vhost_region_del(MemoryListener *listener, return; } - trace_vhost_region_del(dev, section->mr->name ?: NULL); vhost_set_memory(listener, section, false); memory_region_unref(section->mr); for (i = 0; i < dev->n_mem_sections; ++i) { @@ -752,8 +749,6 @@ static void vhost_iommu_region_add(MemoryListener *listener, return; } - trace_vhost_iommu_region_add(dev, section->mr->name ?: NULL); - iommu = g_malloc0(sizeof(*iommu)); end = int128_add(int128_make64(section->offset_within_region), section->size); @@ -782,8 +777,6 @@ static void vhost_iommu_region_del(MemoryListener *listener, return; } - trace_vhost_iommu_region_del(dev, section->mr->name ?: NULL); - QLIST_FOREACH(iommu, &dev->iommu_list, iommu_next) { if (iommu->mr == section->mr && iommu->n.start == section->offset_within_region) { -- cgit v1.1 From 76143618a5a9f33e8bc968f27b3de79d79a286c5 Mon Sep 17 00:00:00 2001 From: Gal Hammer Date: Mon, 29 Jan 2018 16:20:56 +0200 Subject: virtio: remove event notifier cleanup call on de-assign The virtio_bus_set_host_notifier function no longer calls event_notifier_cleanup when a event notifier is removed. The commit updates the code to match the new behavior and calls virtio_bus_cleanup_host_notifier after the notifier was de-assign and no longer in use. This change is a preparation to allow executing the virtio_bus_set_host_notifier function in a memory region transaction. Signed-off-by: Gal Hammer Reviewed-by: Greg Kurz Tested-by: Greg Kurz Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/virtio/vhost.c | 2 ++ hw/virtio/virtio-bus.c | 14 ++++++++++---- hw/virtio/virtio.c | 2 ++ 3 files changed, 14 insertions(+), 4 deletions(-) (limited to 'hw/virtio') diff --git a/hw/virtio/vhost.c b/hw/virtio/vhost.c index 23b9e17..56885aa 100644 --- a/hw/virtio/vhost.c +++ b/hw/virtio/vhost.c @@ -1418,6 +1418,7 @@ fail_vq: error_report("vhost VQ %d notifier cleanup error: %d", i, -r); } assert (e >= 0); + virtio_bus_cleanup_host_notifier(VIRTIO_BUS(qbus), hdev->vq_index + i); } virtio_device_release_ioeventfd(vdev); fail: @@ -1441,6 +1442,7 @@ void vhost_dev_disable_notifiers(struct vhost_dev *hdev, VirtIODevice *vdev) error_report("vhost VQ %d notifier cleanup failed: %d", i, -r); } assert (r >= 0); + virtio_bus_cleanup_host_notifier(VIRTIO_BUS(qbus), hdev->vq_index + i); } virtio_device_release_ioeventfd(vdev); } diff --git a/hw/virtio/virtio-bus.c b/hw/virtio/virtio-bus.c index 3042232..f9bc9ea 100644 --- a/hw/virtio/virtio-bus.c +++ b/hw/virtio/virtio-bus.c @@ -283,20 +283,26 @@ int virtio_bus_set_host_notifier(VirtioBusState *bus, int n, bool assign) r = k->ioeventfd_assign(proxy, notifier, n, true); if (r < 0) { error_report("%s: unable to assign ioeventfd: %d", __func__, r); - goto cleanup_event_notifier; + virtio_bus_cleanup_host_notifier(bus, n); } - return 0; } else { k->ioeventfd_assign(proxy, notifier, n, false); } -cleanup_event_notifier: + return r; +} + +void virtio_bus_cleanup_host_notifier(VirtioBusState *bus, int n) +{ + VirtIODevice *vdev = virtio_bus_get_device(bus); + VirtQueue *vq = virtio_get_queue(vdev, n); + EventNotifier *notifier = virtio_queue_get_host_notifier(vq); + /* Test and clear notifier after disabling event, * in case poll callback didn't have time to run. */ virtio_queue_host_notifier_read(notifier); event_notifier_cleanup(notifier); - return r; } static char *virtio_bus_get_dev_path(DeviceState *dev) diff --git a/hw/virtio/virtio.c b/hw/virtio/virtio.c index d6002ee..3667cd6 100644 --- a/hw/virtio/virtio.c +++ b/hw/virtio/virtio.c @@ -2608,6 +2608,7 @@ assign_error: event_notifier_set_handler(&vq->host_notifier, NULL); r = virtio_bus_set_host_notifier(qbus, n, false); assert(r >= 0); + virtio_bus_cleanup_host_notifier(qbus, n); } return err; } @@ -2634,6 +2635,7 @@ static void virtio_device_stop_ioeventfd_impl(VirtIODevice *vdev) event_notifier_set_handler(&vq->host_notifier, NULL); r = virtio_bus_set_host_notifier(qbus, n, false); assert(r >= 0); + virtio_bus_cleanup_host_notifier(qbus, n); } } -- cgit v1.1 From 710fccf80d787911120145f508f9c4c664cf0e03 Mon Sep 17 00:00:00 2001 From: Gal Hammer Date: Mon, 29 Jan 2018 16:20:57 +0200 Subject: virtio: improve virtio devices initialization time The loading time of a VM is quite significant when its virtio devices use a large amount of virt-queues (e.g. a virtio-serial device with max_ports=511). Most of the time is spend in the creation of all the required event notifiers (ioeventfd and memory regions). This patch pack all the changes to the memory regions in a single memory transaction. Reported-by: Sitong Liu Reported-by: Xiaoling Gao Signed-off-by: Gal Hammer Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin Reviewed-by: Greg Kurz Tested-by: Greg Kurz --- hw/virtio/virtio.c | 22 ++++++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-) (limited to 'hw/virtio') diff --git a/hw/virtio/virtio.c b/hw/virtio/virtio.c index 3667cd6..006d3d1 100644 --- a/hw/virtio/virtio.c +++ b/hw/virtio/virtio.c @@ -2572,8 +2572,9 @@ static Property virtio_properties[] = { static int virtio_device_start_ioeventfd_impl(VirtIODevice *vdev) { VirtioBusState *qbus = VIRTIO_BUS(qdev_get_parent_bus(DEVICE(vdev))); - int n, r, err; + int i, n, r, err; + memory_region_transaction_begin(); for (n = 0; n < VIRTIO_QUEUE_MAX; n++) { VirtQueue *vq = &vdev->vq[n]; if (!virtio_queue_get_num(vdev, n)) { @@ -2596,9 +2597,11 @@ static int virtio_device_start_ioeventfd_impl(VirtIODevice *vdev) } event_notifier_set(&vq->host_notifier); } + memory_region_transaction_commit(); return 0; assign_error: + i = n; /* save n for a second iteration after transaction is committed. */ while (--n >= 0) { VirtQueue *vq = &vdev->vq[n]; if (!virtio_queue_get_num(vdev, n)) { @@ -2608,7 +2611,14 @@ assign_error: event_notifier_set_handler(&vq->host_notifier, NULL); r = virtio_bus_set_host_notifier(qbus, n, false); assert(r >= 0); - virtio_bus_cleanup_host_notifier(qbus, n); + } + memory_region_transaction_commit(); + + while (--i >= 0) { + if (!virtio_queue_get_num(vdev, i)) { + continue; + } + virtio_bus_cleanup_host_notifier(qbus, i); } return err; } @@ -2626,6 +2636,7 @@ static void virtio_device_stop_ioeventfd_impl(VirtIODevice *vdev) VirtioBusState *qbus = VIRTIO_BUS(qdev_get_parent_bus(DEVICE(vdev))); int n, r; + memory_region_transaction_begin(); for (n = 0; n < VIRTIO_QUEUE_MAX; n++) { VirtQueue *vq = &vdev->vq[n]; @@ -2635,6 +2646,13 @@ static void virtio_device_stop_ioeventfd_impl(VirtIODevice *vdev) event_notifier_set_handler(&vq->host_notifier, NULL); r = virtio_bus_set_host_notifier(qbus, n, false); assert(r >= 0); + } + memory_region_transaction_commit(); + + for (n = 0; n < VIRTIO_QUEUE_MAX; n++) { + if (!virtio_queue_get_num(vdev, n)) { + continue; + } virtio_bus_cleanup_host_notifier(qbus, n); } } -- cgit v1.1 From c44317efecb240b9b0951ad46ba56eb547114f1d Mon Sep 17 00:00:00 2001 From: "Dr. David Alan Gilbert" Date: Fri, 19 Jan 2018 10:39:18 +0000 Subject: vhost: Build temporary section list and deref after commit Igor spotted that there's a race, where a region that's unref'd in a _del callback might be free'd before the set_mem_table call in the _commit callback, and thus the vhost might end up using free memory. Fix this by building a complete temporary sections list, ref'ing every section (during add and nop) and then unref'ing the whole list right at the end of commit. Signed-off-by: Dr. David Alan Gilbert Reviewed-by: Igor Mammedov Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/virtio/vhost.c | 73 +++++++++++++++++++++++++++++++++++-------------------- 1 file changed, 47 insertions(+), 26 deletions(-) (limited to 'hw/virtio') diff --git a/hw/virtio/vhost.c b/hw/virtio/vhost.c index 56885aa..92c9500 100644 --- a/hw/virtio/vhost.c +++ b/hw/virtio/vhost.c @@ -627,6 +627,8 @@ static void vhost_begin(MemoryListener *listener) memory_listener); dev->mem_changed_end_addr = 0; dev->mem_changed_start_addr = -1; + dev->tmp_sections = NULL; + dev->n_tmp_sections = 0; } static void vhost_commit(MemoryListener *listener) @@ -635,17 +637,25 @@ static void vhost_commit(MemoryListener *listener) memory_listener); hwaddr start_addr = 0; ram_addr_t size = 0; + MemoryRegionSection *old_sections; + int n_old_sections; + uint64_t log_size; int r; + old_sections = dev->mem_sections; + n_old_sections = dev->n_mem_sections; + dev->mem_sections = dev->tmp_sections; + dev->n_mem_sections = dev->n_tmp_sections; + if (!dev->memory_changed) { - return; + goto out; } if (!dev->started) { - return; + goto out; } if (dev->mem_changed_start_addr > dev->mem_changed_end_addr) { - return; + goto out; } if (dev->started) { @@ -662,7 +672,7 @@ static void vhost_commit(MemoryListener *listener) VHOST_OPS_DEBUG("vhost_set_mem_table failed"); } dev->memory_changed = false; - return; + goto out; } log_size = vhost_get_log_size(dev); /* We allocate an extra 4K bytes to log, @@ -681,6 +691,27 @@ static void vhost_commit(MemoryListener *listener) vhost_dev_log_resize(dev, log_size); } dev->memory_changed = false; + +out: + /* Deref the old list of sections, this must happen _after_ the + * vhost_set_mem_table to ensure the client isn't still using the + * section we're about to unref. + */ + while (n_old_sections--) { + memory_region_unref(old_sections[n_old_sections].mr); + } + g_free(old_sections); + return; +} + +static void vhost_add_section(struct vhost_dev *dev, + MemoryRegionSection *section) +{ + ++dev->n_tmp_sections; + dev->tmp_sections = g_renew(MemoryRegionSection, dev->tmp_sections, + dev->n_tmp_sections); + dev->tmp_sections[dev->n_tmp_sections - 1] = *section; + memory_region_ref(section->mr); } static void vhost_region_add(MemoryListener *listener, @@ -693,36 +724,31 @@ static void vhost_region_add(MemoryListener *listener, return; } - ++dev->n_mem_sections; - dev->mem_sections = g_renew(MemoryRegionSection, dev->mem_sections, - dev->n_mem_sections); - dev->mem_sections[dev->n_mem_sections - 1] = *section; - memory_region_ref(section->mr); + vhost_add_section(dev, section); vhost_set_memory(listener, section, true); } -static void vhost_region_del(MemoryListener *listener, +static void vhost_region_nop(MemoryListener *listener, MemoryRegionSection *section) { struct vhost_dev *dev = container_of(listener, struct vhost_dev, memory_listener); - int i; if (!vhost_section(section)) { return; } - vhost_set_memory(listener, section, false); - memory_region_unref(section->mr); - for (i = 0; i < dev->n_mem_sections; ++i) { - if (dev->mem_sections[i].offset_within_address_space - == section->offset_within_address_space) { - --dev->n_mem_sections; - memmove(&dev->mem_sections[i], &dev->mem_sections[i+1], - (dev->n_mem_sections - i) * sizeof(*dev->mem_sections)); - break; - } + vhost_add_section(dev, section); +} + +static void vhost_region_del(MemoryListener *listener, + MemoryRegionSection *section) +{ + if (!vhost_section(section)) { + return; } + + vhost_set_memory(listener, section, false); } static void vhost_iommu_unmap_notify(IOMMUNotifier *n, IOMMUTLBEntry *iotlb) @@ -789,11 +815,6 @@ static void vhost_iommu_region_del(MemoryListener *listener, } } -static void vhost_region_nop(MemoryListener *listener, - MemoryRegionSection *section) -{ -} - static int vhost_virtqueue_set_addr(struct vhost_dev *dev, struct vhost_virtqueue *vq, unsigned idx, bool enable_log) -- cgit v1.1 From 0ca1fd2d6878a360c9e3b5be6b0bbe5d3143280e Mon Sep 17 00:00:00 2001 From: "Dr. David Alan Gilbert" Date: Fri, 19 Jan 2018 10:39:19 +0000 Subject: vhost: Simplify ring verification checks vhost_verify_ring_mappings() were used to verify that rings are still accessible and related memory hasn't been moved after flatview is updated. It was doing checks by mapping ring's GPA+len and checking that HVA hadn't changed with new memory map. To avoid maybe expensive mapping call, we were identifying address range that changed and were doing mapping only if ring was in changed range. However it's not neccessary to perform ring's GPA mapping as we already have its current HVA and all we need is to verify that ring's GPA translates to the same HVA in updated flatview. This will allow the following patches to simplify the range comparison that was previously needed to avoid expensive verify_ring_mapping calls. Signed-off-by: Igor Mammedov with modifications by: Signed-off-by: Dr. David Alan Gilbert Reviewed-by: Igor Mammedov Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/virtio/vhost.c | 79 +++++++++++++++++++++++++++++-------------------------- 1 file changed, 42 insertions(+), 37 deletions(-) (limited to 'hw/virtio') diff --git a/hw/virtio/vhost.c b/hw/virtio/vhost.c index 92c9500..91cab51 100644 --- a/hw/virtio/vhost.c +++ b/hw/virtio/vhost.c @@ -455,35 +455,37 @@ static void vhost_memory_unmap(struct vhost_dev *dev, void *buffer, } } -static int vhost_verify_ring_part_mapping(struct vhost_dev *dev, - void *part, - uint64_t part_addr, - uint64_t part_size, - uint64_t start_addr, - uint64_t size) -{ - hwaddr l; - void *p; - int r = 0; - - if (!ranges_overlap(start_addr, size, part_addr, part_size)) { +static int vhost_verify_ring_part_mapping(void *ring_hva, + uint64_t ring_gpa, + uint64_t ring_size, + void *reg_hva, + uint64_t reg_gpa, + uint64_t reg_size) +{ + uint64_t hva_ring_offset; + uint64_t ring_last = range_get_last(ring_gpa, ring_size); + uint64_t reg_last = range_get_last(reg_gpa, reg_size); + + if (ring_last < reg_gpa || ring_gpa > reg_last) { return 0; } - l = part_size; - p = vhost_memory_map(dev, part_addr, &l, 1); - if (!p || l != part_size) { - r = -ENOMEM; + /* check that whole ring's is mapped */ + if (ring_last > reg_last) { + return -ENOMEM; } - if (p != part) { - r = -EBUSY; + /* check that ring's MemoryRegion wasn't replaced */ + hva_ring_offset = ring_gpa - reg_gpa; + if (ring_hva != reg_hva + hva_ring_offset) { + return -EBUSY; } - vhost_memory_unmap(dev, p, l, 0, 0); - return r; + + return 0; } static int vhost_verify_ring_mappings(struct vhost_dev *dev, - uint64_t start_addr, - uint64_t size) + void *reg_hva, + uint64_t reg_gpa, + uint64_t reg_size) { int i, j; int r = 0; @@ -497,22 +499,25 @@ static int vhost_verify_ring_mappings(struct vhost_dev *dev, struct vhost_virtqueue *vq = dev->vqs + i; j = 0; - r = vhost_verify_ring_part_mapping(dev, vq->desc, vq->desc_phys, - vq->desc_size, start_addr, size); + r = vhost_verify_ring_part_mapping( + vq->desc, vq->desc_phys, vq->desc_size, + reg_hva, reg_gpa, reg_size); if (r) { break; } j++; - r = vhost_verify_ring_part_mapping(dev, vq->avail, vq->avail_phys, - vq->avail_size, start_addr, size); + r = vhost_verify_ring_part_mapping( + vq->desc, vq->desc_phys, vq->desc_size, + reg_hva, reg_gpa, reg_size); if (r) { break; } j++; - r = vhost_verify_ring_part_mapping(dev, vq->used, vq->used_phys, - vq->used_size, start_addr, size); + r = vhost_verify_ring_part_mapping( + vq->desc, vq->desc_phys, vq->desc_size, + reg_hva, reg_gpa, reg_size); if (r) { break; } @@ -635,13 +640,11 @@ static void vhost_commit(MemoryListener *listener) { struct vhost_dev *dev = container_of(listener, struct vhost_dev, memory_listener); - hwaddr start_addr = 0; - ram_addr_t size = 0; MemoryRegionSection *old_sections; int n_old_sections; - uint64_t log_size; int r; + int i; old_sections = dev->mem_sections; n_old_sections = dev->n_mem_sections; @@ -658,12 +661,14 @@ static void vhost_commit(MemoryListener *listener) goto out; } - if (dev->started) { - start_addr = dev->mem_changed_start_addr; - size = dev->mem_changed_end_addr - dev->mem_changed_start_addr + 1; - - r = vhost_verify_ring_mappings(dev, start_addr, size); - assert(r >= 0); + for (i = 0; i < dev->mem->nregions; i++) { + if (vhost_verify_ring_mappings(dev, + (void *)(uintptr_t)dev->mem->regions[i].userspace_addr, + dev->mem->regions[i].guest_phys_addr, + dev->mem->regions[i].memory_size)) { + error_report("Verify ring failure on region %d", i); + abort(); + } } if (!dev->log_enabled) { -- cgit v1.1 From 48d7c97577498657f9ccbcbf1f990fdb4b79501f Mon Sep 17 00:00:00 2001 From: "Dr. David Alan Gilbert" Date: Fri, 19 Jan 2018 10:39:20 +0000 Subject: vhost: Merge sections added to temporary list As sections are reported by the listener to the _nop and _add methods, add them to the temporary section list but now merge them with the previous section if the new one abuts and the backend allows. Signed-off-by: Dr. David Alan Gilbert Reviewed-by: Igor Mammedov Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/virtio/trace-events | 4 +++ hw/virtio/vhost.c | 76 ++++++++++++++++++++++++++++++++++++++++++++------ 2 files changed, 71 insertions(+), 9 deletions(-) (limited to 'hw/virtio') diff --git a/hw/virtio/trace-events b/hw/virtio/trace-events index 775461a..ab9da06 100644 --- a/hw/virtio/trace-events +++ b/hw/virtio/trace-events @@ -1,5 +1,9 @@ # See docs/devel/tracing.txt for syntax documentation. +# hw/virtio/vhost.c +vhost_region_add_section(const char *name, uint64_t gpa, uint64_t size, uint64_t host) "%s: 0x%"PRIx64"+0x%"PRIx64" @ 0x%"PRIx64 +vhost_region_add_section_abut(const char *name, uint64_t new_size) "%s: 0x%"PRIx64 + # hw/virtio/virtio.c virtqueue_alloc_element(void *elem, size_t sz, unsigned in_num, unsigned out_num) "elem %p size %zd in_num %u out_num %u" virtqueue_fill(void *vq, const void *elem, unsigned int len, unsigned int idx) "vq %p elem %p len %u idx %u" diff --git a/hw/virtio/vhost.c b/hw/virtio/vhost.c index 91cab51..351c691 100644 --- a/hw/virtio/vhost.c +++ b/hw/virtio/vhost.c @@ -709,14 +709,71 @@ out: return; } -static void vhost_add_section(struct vhost_dev *dev, - MemoryRegionSection *section) +/* Adds the section data to the tmp_section structure. + * It relies on the listener calling us in memory address order + * and for each region (via the _add and _nop methods) to + * join neighbours. + */ +static void vhost_region_add_section(struct vhost_dev *dev, + MemoryRegionSection *section) { - ++dev->n_tmp_sections; - dev->tmp_sections = g_renew(MemoryRegionSection, dev->tmp_sections, - dev->n_tmp_sections); - dev->tmp_sections[dev->n_tmp_sections - 1] = *section; - memory_region_ref(section->mr); + bool need_add = true; + uint64_t mrs_size = int128_get64(section->size); + uint64_t mrs_gpa = section->offset_within_address_space; + uintptr_t mrs_host = (uintptr_t)memory_region_get_ram_ptr(section->mr) + + section->offset_within_region; + + trace_vhost_region_add_section(section->mr->name, mrs_gpa, mrs_size, + mrs_host); + + bool log_dirty = memory_region_get_dirty_log_mask(section->mr) & + ~(1 << DIRTY_MEMORY_MIGRATION); + if (log_dirty) { + return; + } + + if (dev->n_tmp_sections) { + /* Since we already have at least one section, lets see if + * this extends it; since we're scanning in order, we only + * have to look at the last one, and the FlatView that calls + * us shouldn't have overlaps. + */ + MemoryRegionSection *prev_sec = dev->tmp_sections + + (dev->n_tmp_sections - 1); + uint64_t prev_gpa_start = prev_sec->offset_within_address_space; + uint64_t prev_size = int128_get64(prev_sec->size); + uint64_t prev_gpa_end = range_get_last(prev_gpa_start, prev_size); + uint64_t prev_host_start = + (uintptr_t)memory_region_get_ram_ptr(prev_sec->mr) + + prev_sec->offset_within_region; + uint64_t prev_host_end = range_get_last(prev_host_start, prev_size); + + if (prev_gpa_end + 1 == mrs_gpa && + prev_host_end + 1 == mrs_host && + section->mr == prev_sec->mr && + (!dev->vhost_ops->vhost_backend_can_merge || + dev->vhost_ops->vhost_backend_can_merge(dev, + mrs_host, mrs_size, + prev_host_start, prev_size))) { + /* The two sections abut */ + need_add = false; + prev_sec->size = int128_add(prev_sec->size, section->size); + trace_vhost_region_add_section_abut(section->mr->name, + mrs_size + prev_size); + } + } + + if (need_add) { + ++dev->n_tmp_sections; + dev->tmp_sections = g_renew(MemoryRegionSection, dev->tmp_sections, + dev->n_tmp_sections); + dev->tmp_sections[dev->n_tmp_sections - 1] = *section; + /* The flatview isn't stable and we don't use it, making it NULL + * means we can memcmp the list. + */ + dev->tmp_sections[dev->n_tmp_sections - 1].fv = NULL; + memory_region_ref(section->mr); + } } static void vhost_region_add(MemoryListener *listener, @@ -728,11 +785,12 @@ static void vhost_region_add(MemoryListener *listener, if (!vhost_section(section)) { return; } + vhost_region_add_section(dev, section); - vhost_add_section(dev, section); vhost_set_memory(listener, section, true); } +/* Called on regions that have not changed */ static void vhost_region_nop(MemoryListener *listener, MemoryRegionSection *section) { @@ -743,7 +801,7 @@ static void vhost_region_nop(MemoryListener *listener, return; } - vhost_add_section(dev, section); + vhost_region_add_section(dev, section); } static void vhost_region_del(MemoryListener *listener, -- cgit v1.1 From ade6d081fc33948e56e655ee37b1306b6de6e0ef Mon Sep 17 00:00:00 2001 From: "Dr. David Alan Gilbert" Date: Fri, 19 Jan 2018 10:39:21 +0000 Subject: vhost: Regenerate region list from changed sections list Compare the sections list that's just been generated, and if it's different from the old one regenerate the region list. Signed-off-by: Dr. David Alan Gilbert Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin Reviewed-by: Igor Mammedov --- hw/virtio/trace-events | 1 + hw/virtio/vhost.c | 39 +++++++++++++++++++++++++++++++++++---- 2 files changed, 36 insertions(+), 4 deletions(-) (limited to 'hw/virtio') diff --git a/hw/virtio/trace-events b/hw/virtio/trace-events index ab9da06..606e4fc 100644 --- a/hw/virtio/trace-events +++ b/hw/virtio/trace-events @@ -1,6 +1,7 @@ # See docs/devel/tracing.txt for syntax documentation. # hw/virtio/vhost.c +vhost_commit(bool started, bool changed) "Started: %d Changed: %d" vhost_region_add_section(const char *name, uint64_t gpa, uint64_t size, uint64_t host) "%s: 0x%"PRIx64"+0x%"PRIx64" @ 0x%"PRIx64 vhost_region_add_section_abut(const char *name, uint64_t new_size) "%s: 0x%"PRIx64 diff --git a/hw/virtio/vhost.c b/hw/virtio/vhost.c index 351c691..f3badc4 100644 --- a/hw/virtio/vhost.c +++ b/hw/virtio/vhost.c @@ -643,21 +643,52 @@ static void vhost_commit(MemoryListener *listener) MemoryRegionSection *old_sections; int n_old_sections; uint64_t log_size; + size_t regions_size; int r; int i; + bool changed = false; + /* Note we can be called before the device is started, but then + * starting the device calls set_mem_table, so we need to have + * built the data structures. + */ old_sections = dev->mem_sections; n_old_sections = dev->n_mem_sections; dev->mem_sections = dev->tmp_sections; dev->n_mem_sections = dev->n_tmp_sections; - if (!dev->memory_changed) { - goto out; + if (dev->n_mem_sections != n_old_sections) { + changed = true; + } else { + /* Same size, lets check the contents */ + changed = n_old_sections && memcmp(dev->mem_sections, old_sections, + n_old_sections * sizeof(old_sections[0])) != 0; } - if (!dev->started) { + + trace_vhost_commit(dev->started, changed); + if (!changed) { goto out; } - if (dev->mem_changed_start_addr > dev->mem_changed_end_addr) { + + /* Rebuild the regions list from the new sections list */ + regions_size = offsetof(struct vhost_memory, regions) + + dev->n_mem_sections * sizeof dev->mem->regions[0]; + dev->mem = g_realloc(dev->mem, regions_size); + dev->mem->nregions = dev->n_mem_sections; + used_memslots = dev->mem->nregions; + for (i = 0; i < dev->n_mem_sections; i++) { + struct vhost_memory_region *cur_vmr = dev->mem->regions + i; + struct MemoryRegionSection *mrs = dev->mem_sections + i; + + cur_vmr->guest_phys_addr = mrs->offset_within_address_space; + cur_vmr->memory_size = int128_get64(mrs->size); + cur_vmr->userspace_addr = + (uintptr_t)memory_region_get_ram_ptr(mrs->mr) + + mrs->offset_within_region; + cur_vmr->flags_padding = 0; + } + + if (!dev->started) { goto out; } -- cgit v1.1 From 06709c120ca3bae9fa243783b89005c08b71a440 Mon Sep 17 00:00:00 2001 From: "Dr. David Alan Gilbert" Date: Fri, 19 Jan 2018 10:39:22 +0000 Subject: vhost: Clean out old vhost_set_memory and friends Remove the old update mechanism, vhost_set_memory, and the functions and flags it used. Signed-off-by: Dr. David Alan Gilbert Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/virtio/vhost.c | 251 ------------------------------------------------------ 1 file changed, 251 deletions(-) (limited to 'hw/virtio') diff --git a/hw/virtio/vhost.c b/hw/virtio/vhost.c index f3badc4..c7814d1 100644 --- a/hw/virtio/vhost.c +++ b/hw/virtio/vhost.c @@ -155,160 +155,6 @@ static void vhost_log_sync_range(struct vhost_dev *dev, } } -/* Assign/unassign. Keep an unsorted array of non-overlapping - * memory regions in dev->mem. */ -static void vhost_dev_unassign_memory(struct vhost_dev *dev, - uint64_t start_addr, - uint64_t size) -{ - int from, to, n = dev->mem->nregions; - /* Track overlapping/split regions for sanity checking. */ - int overlap_start = 0, overlap_end = 0, overlap_middle = 0, split = 0; - - for (from = 0, to = 0; from < n; ++from, ++to) { - struct vhost_memory_region *reg = dev->mem->regions + to; - uint64_t reglast; - uint64_t memlast; - uint64_t change; - - /* clone old region */ - if (to != from) { - memcpy(reg, dev->mem->regions + from, sizeof *reg); - } - - /* No overlap is simple */ - if (!ranges_overlap(reg->guest_phys_addr, reg->memory_size, - start_addr, size)) { - continue; - } - - /* Split only happens if supplied region - * is in the middle of an existing one. Thus it can not - * overlap with any other existing region. */ - assert(!split); - - reglast = range_get_last(reg->guest_phys_addr, reg->memory_size); - memlast = range_get_last(start_addr, size); - - /* Remove whole region */ - if (start_addr <= reg->guest_phys_addr && memlast >= reglast) { - --dev->mem->nregions; - --to; - ++overlap_middle; - continue; - } - - /* Shrink region */ - if (memlast >= reglast) { - reg->memory_size = start_addr - reg->guest_phys_addr; - assert(reg->memory_size); - assert(!overlap_end); - ++overlap_end; - continue; - } - - /* Shift region */ - if (start_addr <= reg->guest_phys_addr) { - change = memlast + 1 - reg->guest_phys_addr; - reg->memory_size -= change; - reg->guest_phys_addr += change; - reg->userspace_addr += change; - assert(reg->memory_size); - assert(!overlap_start); - ++overlap_start; - continue; - } - - /* This only happens if supplied region - * is in the middle of an existing one. Thus it can not - * overlap with any other existing region. */ - assert(!overlap_start); - assert(!overlap_end); - assert(!overlap_middle); - /* Split region: shrink first part, shift second part. */ - memcpy(dev->mem->regions + n, reg, sizeof *reg); - reg->memory_size = start_addr - reg->guest_phys_addr; - assert(reg->memory_size); - change = memlast + 1 - reg->guest_phys_addr; - reg = dev->mem->regions + n; - reg->memory_size -= change; - assert(reg->memory_size); - reg->guest_phys_addr += change; - reg->userspace_addr += change; - /* Never add more than 1 region */ - assert(dev->mem->nregions == n); - ++dev->mem->nregions; - ++split; - } -} - -/* Called after unassign, so no regions overlap the given range. */ -static void vhost_dev_assign_memory(struct vhost_dev *dev, - uint64_t start_addr, - uint64_t size, - uint64_t uaddr) -{ - int from, to; - struct vhost_memory_region *merged = NULL; - for (from = 0, to = 0; from < dev->mem->nregions; ++from, ++to) { - struct vhost_memory_region *reg = dev->mem->regions + to; - uint64_t prlast, urlast; - uint64_t pmlast, umlast; - uint64_t s, e, u; - - /* clone old region */ - if (to != from) { - memcpy(reg, dev->mem->regions + from, sizeof *reg); - } - prlast = range_get_last(reg->guest_phys_addr, reg->memory_size); - pmlast = range_get_last(start_addr, size); - urlast = range_get_last(reg->userspace_addr, reg->memory_size); - umlast = range_get_last(uaddr, size); - - /* check for overlapping regions: should never happen. */ - assert(prlast < start_addr || pmlast < reg->guest_phys_addr); - /* Not an adjacent or overlapping region - do not merge. */ - if ((prlast + 1 != start_addr || urlast + 1 != uaddr) && - (pmlast + 1 != reg->guest_phys_addr || - umlast + 1 != reg->userspace_addr)) { - continue; - } - - if (dev->vhost_ops->vhost_backend_can_merge && - !dev->vhost_ops->vhost_backend_can_merge(dev, uaddr, size, - reg->userspace_addr, - reg->memory_size)) { - continue; - } - - if (merged) { - --to; - assert(to >= 0); - } else { - merged = reg; - } - u = MIN(uaddr, reg->userspace_addr); - s = MIN(start_addr, reg->guest_phys_addr); - e = MAX(pmlast, prlast); - uaddr = merged->userspace_addr = u; - start_addr = merged->guest_phys_addr = s; - size = merged->memory_size = e - s + 1; - assert(merged->memory_size); - } - - if (!merged) { - struct vhost_memory_region *reg = dev->mem->regions + to; - memset(reg, 0, sizeof *reg); - reg->memory_size = size; - assert(reg->memory_size); - reg->guest_phys_addr = start_addr; - reg->userspace_addr = uaddr; - ++to; - } - assert(to <= dev->mem->nregions + 1); - dev->mem->nregions = to; -} - static uint64_t vhost_get_log_size(struct vhost_dev *dev) { uint64_t log_size = 0; @@ -531,95 +377,6 @@ static int vhost_verify_ring_mappings(struct vhost_dev *dev, return r; } -static struct vhost_memory_region *vhost_dev_find_reg(struct vhost_dev *dev, - uint64_t start_addr, - uint64_t size) -{ - int i, n = dev->mem->nregions; - for (i = 0; i < n; ++i) { - struct vhost_memory_region *reg = dev->mem->regions + i; - if (ranges_overlap(reg->guest_phys_addr, reg->memory_size, - start_addr, size)) { - return reg; - } - } - return NULL; -} - -static bool vhost_dev_cmp_memory(struct vhost_dev *dev, - uint64_t start_addr, - uint64_t size, - uint64_t uaddr) -{ - struct vhost_memory_region *reg = vhost_dev_find_reg(dev, start_addr, size); - uint64_t reglast; - uint64_t memlast; - - if (!reg) { - return true; - } - - reglast = range_get_last(reg->guest_phys_addr, reg->memory_size); - memlast = range_get_last(start_addr, size); - - /* Need to extend region? */ - if (start_addr < reg->guest_phys_addr || memlast > reglast) { - return true; - } - /* userspace_addr changed? */ - return uaddr != reg->userspace_addr + start_addr - reg->guest_phys_addr; -} - -static void vhost_set_memory(MemoryListener *listener, - MemoryRegionSection *section, - bool add) -{ - struct vhost_dev *dev = container_of(listener, struct vhost_dev, - memory_listener); - hwaddr start_addr = section->offset_within_address_space; - ram_addr_t size = int128_get64(section->size); - bool log_dirty = - memory_region_get_dirty_log_mask(section->mr) & ~(1 << DIRTY_MEMORY_MIGRATION); - int s = offsetof(struct vhost_memory, regions) + - (dev->mem->nregions + 1) * sizeof dev->mem->regions[0]; - void *ram; - - dev->mem = g_realloc(dev->mem, s); - - if (log_dirty) { - add = false; - } - - assert(size); - - /* Optimize no-change case. At least cirrus_vga does this a lot at this time. */ - ram = memory_region_get_ram_ptr(section->mr) + section->offset_within_region; - if (add) { - if (!vhost_dev_cmp_memory(dev, start_addr, size, (uintptr_t)ram)) { - /* Region exists with same address. Nothing to do. */ - return; - } - } else { - if (!vhost_dev_find_reg(dev, start_addr, size)) { - /* Removing region that we don't access. Nothing to do. */ - return; - } - } - - vhost_dev_unassign_memory(dev, start_addr, size); - if (add) { - /* Add given mapping, merging adjacent regions if any */ - vhost_dev_assign_memory(dev, start_addr, size, (uintptr_t)ram); - } else { - /* Remove old mapping for this memory, if any. */ - vhost_dev_unassign_memory(dev, start_addr, size); - } - dev->mem_changed_start_addr = MIN(dev->mem_changed_start_addr, start_addr); - dev->mem_changed_end_addr = MAX(dev->mem_changed_end_addr, start_addr + size - 1); - dev->memory_changed = true; - used_memslots = dev->mem->nregions; -} - static bool vhost_section(MemoryRegionSection *section) { return memory_region_is_ram(section->mr) && @@ -630,8 +387,6 @@ static void vhost_begin(MemoryListener *listener) { struct vhost_dev *dev = container_of(listener, struct vhost_dev, memory_listener); - dev->mem_changed_end_addr = 0; - dev->mem_changed_start_addr = -1; dev->tmp_sections = NULL; dev->n_tmp_sections = 0; } @@ -707,7 +462,6 @@ static void vhost_commit(MemoryListener *listener) if (r < 0) { VHOST_OPS_DEBUG("vhost_set_mem_table failed"); } - dev->memory_changed = false; goto out; } log_size = vhost_get_log_size(dev); @@ -726,7 +480,6 @@ static void vhost_commit(MemoryListener *listener) if (dev->log_size > log_size + VHOST_LOG_BUFFER) { vhost_dev_log_resize(dev, log_size); } - dev->memory_changed = false; out: /* Deref the old list of sections, this must happen _after_ the @@ -817,8 +570,6 @@ static void vhost_region_add(MemoryListener *listener, return; } vhost_region_add_section(dev, section); - - vhost_set_memory(listener, section, true); } /* Called on regions that have not changed */ @@ -842,7 +593,6 @@ static void vhost_region_del(MemoryListener *listener, return; } - vhost_set_memory(listener, section, false); } static void vhost_iommu_unmap_notify(IOMMUNotifier *n, IOMMUTLBEntry *iotlb) @@ -1457,7 +1207,6 @@ int vhost_dev_init(struct vhost_dev *hdev, void *opaque, hdev->log_size = 0; hdev->log_enabled = false; hdev->started = false; - hdev->memory_changed = false; memory_listener_register(&hdev->memory_listener, &address_space_memory); QLIST_INSERT_HEAD(&vhost_devices, hdev, entry); return 0; -- cgit v1.1 From 938eeb640c0a006a3a53ea6f8b409cad56b80a55 Mon Sep 17 00:00:00 2001 From: "Dr. David Alan Gilbert" Date: Fri, 19 Jan 2018 10:39:23 +0000 Subject: vhost: Merge and delete unused callbacks Now that the olf vhost_set_memory code is gone, the _nop and _add callbacks are identical and can be merged. The _del callback is no longer needed. Signed-off-by: Dr. David Alan Gilbert Reviewed-by: Igor Mammedov Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/virtio/vhost.c | 33 +++++---------------------------- 1 file changed, 5 insertions(+), 28 deletions(-) (limited to 'hw/virtio') diff --git a/hw/virtio/vhost.c b/hw/virtio/vhost.c index c7814d1..326f168 100644 --- a/hw/virtio/vhost.c +++ b/hw/virtio/vhost.c @@ -560,8 +560,9 @@ static void vhost_region_add_section(struct vhost_dev *dev, } } -static void vhost_region_add(MemoryListener *listener, - MemoryRegionSection *section) +/* Used for both add and nop callbacks */ +static void vhost_region_addnop(MemoryListener *listener, + MemoryRegionSection *section) { struct vhost_dev *dev = container_of(listener, struct vhost_dev, memory_listener); @@ -572,29 +573,6 @@ static void vhost_region_add(MemoryListener *listener, vhost_region_add_section(dev, section); } -/* Called on regions that have not changed */ -static void vhost_region_nop(MemoryListener *listener, - MemoryRegionSection *section) -{ - struct vhost_dev *dev = container_of(listener, struct vhost_dev, - memory_listener); - - if (!vhost_section(section)) { - return; - } - - vhost_region_add_section(dev, section); -} - -static void vhost_region_del(MemoryListener *listener, - MemoryRegionSection *section) -{ - if (!vhost_section(section)) { - return; - } - -} - static void vhost_iommu_unmap_notify(IOMMUNotifier *n, IOMMUTLBEntry *iotlb) { struct vhost_iommu *iommu = container_of(n, struct vhost_iommu, n); @@ -1163,9 +1141,8 @@ int vhost_dev_init(struct vhost_dev *hdev, void *opaque, hdev->memory_listener = (MemoryListener) { .begin = vhost_begin, .commit = vhost_commit, - .region_add = vhost_region_add, - .region_del = vhost_region_del, - .region_nop = vhost_region_nop, + .region_add = vhost_region_addnop, + .region_nop = vhost_region_addnop, .log_start = vhost_log_start, .log_stop = vhost_log_stop, .log_sync = vhost_log_sync, -- cgit v1.1 From aa3c40f6bfae251a483b5c19f5ceb8e11bdbdb18 Mon Sep 17 00:00:00 2001 From: "Dr. David Alan Gilbert" Date: Fri, 19 Jan 2018 10:39:24 +0000 Subject: vhost: Move log_dirty check Move the log_dirty check into vhost_section. Signed-off-by: Dr. David Alan Gilbert Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/virtio/trace-events | 1 + hw/virtio/vhost.c | 20 +++++++++++++------- 2 files changed, 14 insertions(+), 7 deletions(-) (limited to 'hw/virtio') diff --git a/hw/virtio/trace-events b/hw/virtio/trace-events index 606e4fc..742ff0f 100644 --- a/hw/virtio/trace-events +++ b/hw/virtio/trace-events @@ -4,6 +4,7 @@ vhost_commit(bool started, bool changed) "Started: %d Changed: %d" vhost_region_add_section(const char *name, uint64_t gpa, uint64_t size, uint64_t host) "%s: 0x%"PRIx64"+0x%"PRIx64" @ 0x%"PRIx64 vhost_region_add_section_abut(const char *name, uint64_t new_size) "%s: 0x%"PRIx64 +vhost_section(const char *name, int r) "%s:%d" # hw/virtio/virtio.c virtqueue_alloc_element(void *elem, size_t sz, unsigned in_num, unsigned out_num) "elem %p size %zd in_num %u out_num %u" diff --git a/hw/virtio/vhost.c b/hw/virtio/vhost.c index 326f168..4a44e6e 100644 --- a/hw/virtio/vhost.c +++ b/hw/virtio/vhost.c @@ -27,6 +27,7 @@ #include "hw/virtio/virtio-access.h" #include "migration/blocker.h" #include "sysemu/dma.h" +#include "trace.h" /* enabled until disconnected backend stabilizes */ #define _VHOST_DEBUG 1 @@ -379,8 +380,19 @@ static int vhost_verify_ring_mappings(struct vhost_dev *dev, static bool vhost_section(MemoryRegionSection *section) { - return memory_region_is_ram(section->mr) && + bool result; + bool log_dirty = memory_region_get_dirty_log_mask(section->mr) & + ~(1 << DIRTY_MEMORY_MIGRATION); + result = memory_region_is_ram(section->mr) && !memory_region_is_rom(section->mr); + + /* Vhost doesn't handle any block which is doing dirty-tracking other + * than migration; this typically fires on VGA areas. + */ + result &= !log_dirty; + + trace_vhost_section(section->mr->name, result); + return result; } static void vhost_begin(MemoryListener *listener) @@ -510,12 +522,6 @@ static void vhost_region_add_section(struct vhost_dev *dev, trace_vhost_region_add_section(section->mr->name, mrs_gpa, mrs_size, mrs_host); - bool log_dirty = memory_region_get_dirty_log_mask(section->mr) & - ~(1 << DIRTY_MEMORY_MIGRATION); - if (log_dirty) { - return; - } - if (dev->n_tmp_sections) { /* Since we already have at least one section, lets see if * this extends it; since we're scanning in order, we only -- cgit v1.1 From 0ebf9a748881fa85491501f0fa3ca5aec79b7afc Mon Sep 17 00:00:00 2001 From: Changpeng Liu Date: Tue, 6 Feb 2018 09:35:34 +0800 Subject: virtio-blk: enable multiple vectors when using multiple I/O queues Currently virtio-pci driver hardcoded 2 vectors for virtio-blk device, for multiple I/O queues scenario, all the I/O queues will share one interrupt vector, while here, enable multiple vectors according to the number of I/O queues. Signed-off-by: Changpeng Liu Reviewed-by: Paolo Bonzini Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/virtio/virtio-pci.c | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) (limited to 'hw/virtio') diff --git a/hw/virtio/virtio-pci.c b/hw/virtio/virtio-pci.c index c20537f..b55dfcf 100644 --- a/hw/virtio/virtio-pci.c +++ b/hw/virtio/virtio-pci.c @@ -1932,7 +1932,8 @@ static Property virtio_blk_pci_properties[] = { DEFINE_PROP_UINT32("class", VirtIOPCIProxy, class_code, 0), DEFINE_PROP_BIT("ioeventfd", VirtIOPCIProxy, flags, VIRTIO_PCI_FLAG_USE_IOEVENTFD_BIT, true), - DEFINE_PROP_UINT32("vectors", VirtIOPCIProxy, nvectors, 2), + DEFINE_PROP_UINT32("vectors", VirtIOPCIProxy, nvectors, + DEV_NVECTORS_UNSPECIFIED), DEFINE_PROP_END_OF_LIST(), }; @@ -1941,6 +1942,10 @@ static void virtio_blk_pci_realize(VirtIOPCIProxy *vpci_dev, Error **errp) VirtIOBlkPCI *dev = VIRTIO_BLK_PCI(vpci_dev); DeviceState *vdev = DEVICE(&dev->vdev); + if (vpci_dev->nvectors == DEV_NVECTORS_UNSPECIFIED) { + vpci_dev->nvectors = dev->vdev.conf.num_queues + 1; + } + qdev_set_parent_bus(vdev, BUS(&vpci_dev->bus)); object_property_set_bool(OBJECT(vdev), true, "realized", errp); } @@ -1983,7 +1988,8 @@ static const TypeInfo virtio_blk_pci_info = { static Property vhost_user_blk_pci_properties[] = { DEFINE_PROP_UINT32("class", VirtIOPCIProxy, class_code, 0), - DEFINE_PROP_UINT32("vectors", VirtIOPCIProxy, nvectors, 2), + DEFINE_PROP_UINT32("vectors", VirtIOPCIProxy, nvectors, + DEV_NVECTORS_UNSPECIFIED), DEFINE_PROP_END_OF_LIST(), }; @@ -1992,6 +1998,10 @@ static void vhost_user_blk_pci_realize(VirtIOPCIProxy *vpci_dev, Error **errp) VHostUserBlkPCI *dev = VHOST_USER_BLK_PCI(vpci_dev); DeviceState *vdev = DEVICE(&dev->vdev); + if (vpci_dev->nvectors == DEV_NVECTORS_UNSPECIFIED) { + vpci_dev->nvectors = dev->vdev.num_queues + 1; + } + qdev_set_parent_bus(vdev, BUS(&vpci_dev->bus)); object_property_set_bool(OBJECT(vdev), true, "realized", errp); } -- cgit v1.1 From b86107ab43b804e899a226fe287e34ab8acef596 Mon Sep 17 00:00:00 2001 From: Tiwei Bie Date: Thu, 25 Jan 2018 15:12:43 +0800 Subject: virtio-balloon: unref the memory region before continuing Signed-off-by: Tiwei Bie Cc: qemu-stable@nongnu.org Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/virtio/virtio-balloon.c | 1 + 1 file changed, 1 insertion(+) (limited to 'hw/virtio') diff --git a/hw/virtio/virtio-balloon.c b/hw/virtio/virtio-balloon.c index 14e08d2..f2104bf 100644 --- a/hw/virtio/virtio-balloon.c +++ b/hw/virtio/virtio-balloon.c @@ -234,6 +234,7 @@ static void virtio_balloon_handle_output(VirtIODevice *vdev, VirtQueue *vq) memory_region_is_rom(section.mr) || memory_region_is_romd(section.mr)) { trace_virtio_balloon_bad_addr(pa); + memory_region_unref(section.mr); continue; } -- cgit v1.1 From bf1e7140ef0b3a149860ab9f05b36665133238f6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1=C5=A1=20Golembiovsk=C3=BD?= Date: Tue, 5 Dec 2017 13:14:46 +0100 Subject: virtio-balloon: include statistics of disk/file caches MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Tomáš Golembiovský Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/virtio/virtio-balloon.c | 1 + 1 file changed, 1 insertion(+) (limited to 'hw/virtio') diff --git a/hw/virtio/virtio-balloon.c b/hw/virtio/virtio-balloon.c index f2104bf..179c8f5 100644 --- a/hw/virtio/virtio-balloon.c +++ b/hw/virtio/virtio-balloon.c @@ -50,6 +50,7 @@ static const char *balloon_stat_names[] = { [VIRTIO_BALLOON_S_MEMFREE] = "stat-free-memory", [VIRTIO_BALLOON_S_MEMTOT] = "stat-total-memory", [VIRTIO_BALLOON_S_AVAIL] = "stat-available-memory", + [VIRTIO_BALLOON_S_CACHES] = "stat-disk-caches", [VIRTIO_BALLOON_S_NR] = NULL }; -- cgit v1.1