The previous has_coalesced_range counter has a problem in that it only works for additions of coalesced mmio ranges but not deletions. The reason is that has_coalesced_range information can be lost when the FlatView updates the topology again when the updated region is not covering the coalesced regions. When that happens, due to flatrange_equal() is not checking against has_coalesced_range, the new FlatRange will be seen as the same one as the old and the new instance (whose has_coalesced_range will be zero) will replace the old instance (whose has_coalesced_range _could_ be non-zero).
To fix it, we inherit the has_coalesced_range value from the old FlatRange to the new one if it's describing the identical range when updating the topology. Without this patch, MemoryListener.coalesced_io_del is hardly being called due to has_coalesced_range will be mostly zero in flat_range_coalesced_io_del() when topologies frequently change for the "memory" address space. Fixes: 3ac7d43a6fbb5d4a3 Suggested-by: Paolo Bonzini <pbonz...@redhat.com> Signed-off-by: Peter Xu <pet...@redhat.com> --- memory.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/memory.c b/memory.c index 8141486832..c53dcfc092 100644 --- a/memory.c +++ b/memory.c @@ -939,6 +939,15 @@ static void address_space_update_topology_pass(AddressSpace *as, /* In both and unchanged (except logging may have changed) */ if (adding) { + /* + * We must inherit the has_coalesced_range information + * if the new FlatRange is exactly the same as the old + * one, because it'll be used to conditionally call + * the coalesced mmio deletion listeners correctly in + * flat_range_coalesced_io_del() when the FlatRange + * needs to really go away. + */ + frnew->has_coalesced_range = frold->has_coalesced_range; MEMORY_LISTENER_UPDATE_REGION(frnew, as, Forward, region_nop); if (frnew->dirty_log_mask & ~frold->dirty_log_mask) { MEMORY_LISTENER_UPDATE_REGION(frnew, as, Forward, log_start, -- 2.21.0