On Sat, Jun 27, 2020 at 10:09:37AM -0700, elena.ufimtseva@oracle.com wrote: > +static bool try_merge(RemoteMemSync *sync, MemoryRegionSection *section) > +{ > + uint64_t mrs_size, mrs_gpa, mrs_page; > + MemoryRegionSection *prev_sec; > + bool merged = false; > + uintptr_t mrs_host; > + RAMBlock *mrs_rb; > + > + if (!sync->n_mr_sections) { > + return false; > + } > + > + mrs_rb = section->mr->ram_block; > + mrs_page = (uint64_t)qemu_ram_pagesize(mrs_rb); > + mrs_size = int128_get64(section->size); > + mrs_gpa = section->offset_within_address_space; > + mrs_host = (uintptr_t)memory_region_get_ram_ptr(section->mr) + > + section->offset_within_region; > + > + if (get_fd_from_hostaddr(mrs_host, NULL) < 0) { > + return true; > + } > + > + mrs_host = mrs_host & ~(mrs_page - 1); > + mrs_gpa = mrs_gpa & ~(mrs_page - 1); > + mrs_size = ROUND_UP(mrs_size, mrs_page); > + > + if (sync->n_mr_sections) { The check is unnecessary because of the if statement above: if (!sync->n_mr_sections) { return false; } > +static void proxy_ml_commit(MemoryListener *listener) > +{ > + RemoteMemSync *sync = container_of(listener, RemoteMemSync, listener); > + MPQemuMsg msg; > + MemoryRegionSection section; > + ram_addr_t offset; > + uintptr_t host_addr; > + int region; > + > + memset(&msg, 0, sizeof(MPQemuMsg)); > + > + msg.cmd = SYNC_SYSMEM; > + msg.bytestream = 0; > + msg.num_fds = sync->n_mr_sections; > + msg.size = sizeof(msg.data1); > + assert(msg.num_fds <= REMOTE_MAX_FDS); > + > + for (region = 0; region < sync->n_mr_sections; region++) { > + section = sync->mr_sections[region]; Why is section copied here? It's conventional to take a pointer to a struct instead of copying its value. > + msg.data1.sync_sysmem.gpas[region] = > + section.offset_within_address_space; > + msg.data1.sync_sysmem.sizes[region] = int128_get64(section.size); > + host_addr = (uintptr_t)memory_region_get_ram_ptr(section.mr) + > + section.offset_within_region; > + msg.fds[region] = get_fd_from_hostaddr(host_addr, &offset); > + msg.data1.sync_sysmem.offsets[region] = offset; > + } > + mpqemu_msg_send(&msg, sync->ioc); > +} > + > +void deconfigure_memory_sync(RemoteMemSync *sync) > +{ Missing proxy_ml_begin() call to free sync->mr_sections[] and unref sections. > + memory_listener_unregister(&sync->listener); > +} This function isn't called. It's good practice to implement the object lifecycle from the start.