Add ref/unref calls at the following places: - places where memory regions are stashed by a listener and used outside the BQL (including in Xen or KVM).
- memory_region_find callsites Signed-off-by: Paolo Bonzini <pbonz...@redhat.com> --- exec.c | 6 +++++- hw/core/loader.c | 1 + hw/display/exynos4210_fimd.c | 6 ++++++ hw/display/framebuffer.c | 10 ++++++---- hw/i386/kvm/ioapic.c | 2 ++ hw/i386/kvmvapic.c | 1 + hw/misc/vfio.c | 2 ++ hw/virtio/dataplane/hostmem.c | 7 +++++++ hw/virtio/vhost.c | 2 ++ hw/virtio/virtio-balloon.c | 1 + hw/xen/xen_pt.c | 4 ++++ include/hw/virtio/dataplane/hostmem.h | 1 + kvm-all.c | 2 ++ memory.c | 16 ++++++++++++++++ target-arm/kvm.c | 2 ++ target-sparc/mmu_helper.c | 1 + xen-all.c | 2 ++ 17 files changed, 61 insertions(+), 5 deletions(-) diff --git a/exec.c b/exec.c index 03d6ea7..f163a55 100644 --- a/exec.c +++ b/exec.c @@ -761,12 +761,16 @@ static uint16_t phys_section_add(MemoryRegionSection *section) phys_sections_nb_alloc); } phys_sections[phys_sections_nb] = *section; + memory_region_ref(section->mr); return phys_sections_nb++; } static void phys_sections_clear(void) { - phys_sections_nb = 0; + while (phys_sections_nb > 0) { + MemoryRegionSection *section = &phys_sections[--phys_sections_nb]; + memory_region_unref(section->mr); + } } static void register_subpage(AddressSpaceDispatch *d, MemoryRegionSection *section) diff --git a/hw/core/loader.c b/hw/core/loader.c index 7507914..97e7ba2 100644 --- a/hw/core/loader.c +++ b/hw/core/loader.c @@ -727,6 +727,7 @@ int rom_load_all(void) addr += rom->romsize; section = memory_region_find(get_system_memory(), rom->addr, 1); rom->isrom = section.size && memory_region_is_rom(section.mr); + memory_region_unref(section.mr); } qemu_register_reset(rom_reset, NULL); roms_loaded = 1; diff --git a/hw/display/exynos4210_fimd.c b/hw/display/exynos4210_fimd.c index 6cb5016..afa2e54 100644 --- a/hw/display/exynos4210_fimd.c +++ b/hw/display/exynos4210_fimd.c @@ -1126,6 +1126,11 @@ static void fimd_update_memory_section(Exynos4210fimdState *s, unsigned win) /* Total number of bytes of virtual screen used by current window */ w->fb_len = fb_mapped_len = (w->virtpage_width + w->virtpage_offsize) * (w->rightbot_y - w->lefttop_y + 1); + + /* TODO: add .exit and unref the region there. Not needed yet since sysbus + * does not support hot-unplug. + */ + memory_region_unref(w->mem_section.mr); w->mem_section = memory_region_find(sysbus_address_space(&s->busdev), fb_start_addr, w->fb_len); assert(w->mem_section.mr); @@ -1154,6 +1159,7 @@ static void fimd_update_memory_section(Exynos4210fimdState *s, unsigned win) return; error_return: + memory_region_unref(w->mem_section.mr); w->mem_section.mr = NULL; w->mem_section.size = 0; w->host_fb_addr = NULL; diff --git a/hw/display/framebuffer.c b/hw/display/framebuffer.c index 6be31db..8288b93 100644 --- a/hw/display/framebuffer.c +++ b/hw/display/framebuffer.c @@ -54,10 +54,10 @@ void framebuffer_update_display( src_len = src_width * rows; mem_section = memory_region_find(address_space, base, src_len); + mem = mem_section.mr; if (mem_section.size != src_len || !memory_region_is_ram(mem_section.mr)) { - return; + goto out; } - mem = mem_section.mr; assert(mem); assert(mem_section.offset_within_address_space == base); @@ -67,10 +67,10 @@ void framebuffer_update_display( but it's not really worth it as dirty flag tracking will probably already have failed above. */ if (!src_base) - return; + goto out; if (src_len != src_width * rows) { cpu_physical_memory_unmap(src_base, src_len, 0, 0); - return; + goto out; } src = src_base; dest = surface_data(ds); @@ -107,4 +107,6 @@ void framebuffer_update_display( DIRTY_MEMORY_VGA); *first_row = first; *last_row = last; +out: + memory_region_unref(mem); } diff --git a/hw/i386/kvm/ioapic.c b/hw/i386/kvm/ioapic.c index a3bd519..e3c29da 100644 --- a/hw/i386/kvm/ioapic.c +++ b/hw/i386/kvm/ioapic.c @@ -107,6 +107,8 @@ static void kvm_ioapic_put(IOAPICCommonState *s) fprintf(stderr, "KVM_GET_IRQCHIP failed: %s\n", strerror(ret)); abort(); } + + memory_region_unref(mrs.mr); } static void kvm_ioapic_reset(DeviceState *dev) diff --git a/hw/i386/kvmvapic.c b/hw/i386/kvmvapic.c index 655483b..e375c1c 100644 --- a/hw/i386/kvmvapic.c +++ b/hw/i386/kvmvapic.c @@ -605,6 +605,7 @@ static void vapic_map_rom_writable(VAPICROMState *s) rom_size); memory_region_add_subregion_overlap(as, rom_paddr, &s->rom, 1000); s->rom_mapped_writable = true; + memory_region_unref(section.mr); } static int vapic_prepare(VAPICROMState *s) diff --git a/hw/misc/vfio.c b/hw/misc/vfio.c index 178dd11..0ae6878 100644 --- a/hw/misc/vfio.c +++ b/hw/misc/vfio.c @@ -1969,6 +1969,7 @@ static void vfio_listener_region_add(MemoryListener *listener, DPRINTF("region_add %"HWADDR_PRIx" - %"HWADDR_PRIx" [%p]\n", iova, end - 1, vaddr); + memory_region_ref(section->mr); ret = vfio_dma_map(container, iova, end - iova, vaddr, section->readonly); if (ret) { error_report("vfio_dma_map(%p, 0x%"HWADDR_PRIx", " @@ -2010,6 +2011,7 @@ static void vfio_listener_region_del(MemoryListener *listener, iova, end - 1); ret = vfio_dma_unmap(container, iova, end - iova); + memory_region_unref(section->mr); if (ret) { error_report("vfio_dma_unmap(%p, 0x%"HWADDR_PRIx", " "0x%"HWADDR_PRIx") = %d (%m)", diff --git a/hw/virtio/dataplane/hostmem.c b/hw/virtio/dataplane/hostmem.c index 37292ff..66829bb 100644 --- a/hw/virtio/dataplane/hostmem.c +++ b/hw/virtio/dataplane/hostmem.c @@ -64,8 +64,12 @@ out: static void hostmem_listener_commit(MemoryListener *listener) { HostMem *hostmem = container_of(listener, HostMem, listener); + int i; qemu_mutex_lock(&hostmem->current_regions_lock); + for (i = 0; i < hostmem->num_current_regions; i++) { + memory_region_unref(hostmem->current_regions[i].mr); + } g_free(hostmem->current_regions); hostmem->current_regions = hostmem->new_regions; hostmem->num_current_regions = hostmem->num_new_regions; @@ -92,8 +96,11 @@ static void hostmem_append_new_region(HostMem *hostmem, .guest_addr = section->offset_within_address_space, .size = section->size, .readonly = section->readonly, + .mr = section->mr, }; hostmem->num_new_regions++; + + memory_region_ref(section->mr); } static void hostmem_listener_append_region(MemoryListener *listener, diff --git a/hw/virtio/vhost.c b/hw/virtio/vhost.c index fbabf99..190522b 100644 --- a/hw/virtio/vhost.c +++ b/hw/virtio/vhost.c @@ -497,6 +497,7 @@ static void vhost_region_add(MemoryListener *listener, 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_set_memory(listener, section, true); } @@ -512,6 +513,7 @@ static void vhost_region_del(MemoryListener *listener, } 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) { diff --git a/hw/virtio/virtio-balloon.c b/hw/virtio/virtio-balloon.c index d669756..fac8800 100644 --- a/hw/virtio/virtio-balloon.c +++ b/hw/virtio/virtio-balloon.c @@ -205,6 +205,7 @@ static void virtio_balloon_handle_output(VirtIODevice *vdev, VirtQueue *vq) addr = section.offset_within_region; balloon_page(memory_region_get_ram_ptr(section.mr) + addr, !!(vq == s->dvq)); + memory_region_unref(section.mr); } virtqueue_push(vq, &elem, offset); diff --git a/hw/xen/xen_pt.c b/hw/xen/xen_pt.c index c199818..be1fd52 100644 --- a/hw/xen/xen_pt.c +++ b/hw/xen/xen_pt.c @@ -606,6 +606,7 @@ static void xen_pt_region_add(MemoryListener *l, MemoryRegionSection *sec) XenPCIPassthroughState *s = container_of(l, XenPCIPassthroughState, memory_listener); + memory_region_ref(sec->mr); xen_pt_region_update(s, sec, true); } @@ -615,6 +616,7 @@ static void xen_pt_region_del(MemoryListener *l, MemoryRegionSection *sec) memory_listener); xen_pt_region_update(s, sec, false); + memory_region_unref(sec->mr); } static void xen_pt_io_region_add(MemoryListener *l, MemoryRegionSection *sec) @@ -622,6 +624,7 @@ static void xen_pt_io_region_add(MemoryListener *l, MemoryRegionSection *sec) XenPCIPassthroughState *s = container_of(l, XenPCIPassthroughState, io_listener); + memory_region_ref(sec->mr); xen_pt_region_update(s, sec, true); } @@ -631,6 +634,7 @@ static void xen_pt_io_region_del(MemoryListener *l, MemoryRegionSection *sec) io_listener); xen_pt_region_update(s, sec, false); + memory_region_unref(sec->mr); } static const MemoryListener xen_pt_memory_listener = { diff --git a/include/hw/virtio/dataplane/hostmem.h b/include/hw/virtio/dataplane/hostmem.h index b2cf093..2810f4b 100644 --- a/include/hw/virtio/dataplane/hostmem.h +++ b/include/hw/virtio/dataplane/hostmem.h @@ -18,6 +18,7 @@ #include "qemu/thread.h" typedef struct { + MemoryRegion *mr; void *host_addr; hwaddr guest_addr; uint64_t size; diff --git a/kvm-all.c b/kvm-all.c index 3a31602..1d876aa 100644 --- a/kvm-all.c +++ b/kvm-all.c @@ -766,6 +766,7 @@ static void kvm_set_phys_mem(MemoryRegionSection *section, bool add) static void kvm_region_add(MemoryListener *listener, MemoryRegionSection *section) { + memory_region_ref(section->mr); kvm_set_phys_mem(section, true); } @@ -773,6 +774,7 @@ static void kvm_region_del(MemoryListener *listener, MemoryRegionSection *section) { kvm_set_phys_mem(section, false); + memory_region_unref(section->mr); } static void kvm_log_sync(MemoryListener *listener, diff --git a/memory.c b/memory.c index c7ab19c..4b30c3f 100644 --- a/memory.c +++ b/memory.c @@ -145,6 +145,7 @@ static bool memory_listener_match(MemoryListener *listener, } \ } while (0) +/* No need to ref/unref .mr, the FlatRange keeps it alive. */ #define MEMORY_LISTENER_UPDATE_REGION(fr, as, dir, callback) \ MEMORY_LISTENER_CALL(callback, dir, (&(MemoryRegionSection) { \ .mr = (fr)->mr, \ @@ -260,11 +261,17 @@ static void flatview_insert(FlatView *view, unsigned pos, FlatRange *range) memmove(view->ranges + pos + 1, view->ranges + pos, (view->nr - pos) * sizeof(FlatRange)); view->ranges[pos] = *range; + memory_region_ref(range->mr); ++view->nr; } static void flatview_destroy(FlatView *view) { + int i; + + for (i = 0; i < view->nr; i++) { + memory_region_unref(view->ranges[i].mr); + } g_free(view->ranges); } @@ -763,6 +770,11 @@ static void memory_region_destructor_ram(MemoryRegion *mr) qemu_ram_free(mr->ram_addr); } +static void memory_region_destructor_alias(MemoryRegion *mr) +{ + memory_region_unref(mr->alias); +} + static void memory_region_destructor_ram_from_ptr(MemoryRegion *mr) { qemu_ram_free_from_ptr(mr->ram_addr); @@ -961,6 +973,8 @@ void memory_region_init_alias(MemoryRegion *mr, uint64_t size) { memory_region_init(mr, name, size); + memory_region_ref(orig); + mr->destructor = memory_region_destructor_alias; mr->alias = orig; mr->alias_offset = offset; } @@ -1539,6 +1553,8 @@ MemoryRegionSection memory_region_find(MemoryRegion *mr, ret.size = int128_get64(range.size); ret.offset_within_address_space = int128_get64(range.start); ret.readonly = fr->readonly; + memory_region_ref(ret.mr); + return ret; } diff --git a/target-arm/kvm.c b/target-arm/kvm.c index b7bdc03..b9051a4 100644 --- a/target-arm/kvm.c +++ b/target-arm/kvm.c @@ -127,6 +127,7 @@ static void kvm_arm_machine_init_done(Notifier *notifier, void *data) abort(); } } + memory_region_unref(kd->mr); g_free(kd); } } @@ -152,6 +153,7 @@ void kvm_arm_register_device(MemoryRegion *mr, uint64_t devid) kd->kda.id = devid; kd->kda.addr = -1; QSLIST_INSERT_HEAD(&kvm_devices_head, kd, entries); + memory_region_ref(kd->mr); } typedef struct Reg { diff --git a/target-sparc/mmu_helper.c b/target-sparc/mmu_helper.c index a9649ae..3c1ccc2 100644 --- a/target-sparc/mmu_helper.c +++ b/target-sparc/mmu_helper.c @@ -845,6 +845,7 @@ hwaddr cpu_get_phys_page_debug(CPUSPARCState *env, target_ulong addr) } } section = memory_region_find(get_system_memory(), phys_addr, 1); + memory_region_unref(section.mr); if (!section.size) { return -1; } diff --git a/xen-all.c b/xen-all.c index 539a154..2f24ced 100644 --- a/xen-all.c +++ b/xen-all.c @@ -459,6 +459,7 @@ static void xen_set_memory(struct MemoryListener *listener, static void xen_region_add(MemoryListener *listener, MemoryRegionSection *section) { + memory_region_ref(section->mr); xen_set_memory(listener, section, true); } @@ -466,6 +467,7 @@ static void xen_region_del(MemoryListener *listener, MemoryRegionSection *section) { xen_set_memory(listener, section, false); + memory_region_unref(section->mr); } static void xen_sync_dirty_bitmap(XenIOState *state, -- 1.7.1