summaryrefslogtreecommitdiffstats
path: root/subprojects/libvhost-user
diff options
context:
space:
mode:
authorRaphael Norwitz2022-01-17 05:12:35 +0100
committerMichael S. Tsirkin2022-02-04 15:07:43 +0100
commit4fafedc9daaf7d7d5ad36d8925bdddd6da5ed8c2 (patch)
treec37fbea6c057f80d36bed7ae244f5ef19a92a906 /subprojects/libvhost-user
parentlibvhost-user: prevent over-running max RAM slots (diff)
downloadqemu-4fafedc9daaf7d7d5ad36d8925bdddd6da5ed8c2.tar.gz
qemu-4fafedc9daaf7d7d5ad36d8925bdddd6da5ed8c2.tar.xz
qemu-4fafedc9daaf7d7d5ad36d8925bdddd6da5ed8c2.zip
libvhost-user: handle removal of identical regions
Today if QEMU (or any other VMM) has sent multiple copies of the same region to a libvhost-user based backend and then attempts to remove the region, only one instance of the region will be removed, leaving stale copies of the region in dev->regions[]. This change resolves this by having vu_rem_mem_reg() iterate through all regions in dev->regions[] and delete all matching regions. Suggested-by: Stefan Hajnoczi <stefanha@redhat.com> Signed-off-by: Raphael Norwitz <raphael.norwitz@nutanix.com> Message-Id: <20220117041050.19718-7-raphael.norwitz@nutanix.com> Reviewed-by: Michael S. Tsirkin <mst@redhat.com> Signed-off-by: Michael S. Tsirkin <mst@redhat.com> Reviewed-by: David Hildenbrand <david@redhat.com>
Diffstat (limited to 'subprojects/libvhost-user')
-rw-r--r--subprojects/libvhost-user/libvhost-user.c28
1 files changed, 16 insertions, 12 deletions
diff --git a/subprojects/libvhost-user/libvhost-user.c b/subprojects/libvhost-user/libvhost-user.c
index 2a1fa00a44..0ee43b8e93 100644
--- a/subprojects/libvhost-user/libvhost-user.c
+++ b/subprojects/libvhost-user/libvhost-user.c
@@ -821,6 +821,7 @@ static bool
vu_rem_mem_reg(VuDev *dev, VhostUserMsg *vmsg) {
VhostUserMemoryRegion m = vmsg->payload.memreg.region, *msg_region = &m;
int i;
+ bool found = false;
if (vmsg->fd_num != 1) {
vmsg_close_fds(vmsg);
@@ -856,21 +857,24 @@ vu_rem_mem_reg(VuDev *dev, VhostUserMsg *vmsg) {
munmap(m, r->size + r->mmap_offset);
}
- break;
+ /*
+ * Shift all affected entries by 1 to close the hole at index i and
+ * zero out the last entry.
+ */
+ memmove(dev->regions + i, dev->regions + i + 1,
+ sizeof(VuDevRegion) * (dev->nregions - i - 1));
+ memset(dev->regions + dev->nregions - 1, 0, sizeof(VuDevRegion));
+ DPRINT("Successfully removed a region\n");
+ dev->nregions--;
+ i--;
+
+ found = true;
+
+ /* Continue the search for eventual duplicates. */
}
}
- if (i < dev->nregions) {
- /*
- * Shift all affected entries by 1 to close the hole at index i and
- * zero out the last entry.
- */
- memmove(dev->regions + i, dev->regions + i + 1,
- sizeof(VuDevRegion) * (dev->nregions - i - 1));
- memset(dev->regions + dev->nregions - 1, 0,
- sizeof(VuDevRegion));
- DPRINT("Successfully removed a region\n");
- dev->nregions--;
+ if (found) {
vmsg_set_reply_u64(vmsg, 0);
} else {
vu_panic(dev, "Specified region not found\n");