Re: [RFC][QEMU Patch] KVM: Enable QEMU to free the pages hinted by the guest

From: Alexander Duyck
Date: Wed Mar 06 2019 - 19:35:19 EST


Here are some changes I made to your patch in order to address the sizing
issue I called out. You may want to try testing with this patch applied to
your QEMU as I am finding it is making a signficant difference. It has cut
the test time for the 32G memhog test I called out earlier in half.

Signed-off-by: Alexander Duyck <alexander.h.duyck@xxxxxxxxxxxxxxx>
---
hw/virtio/virtio-balloon.c | 28 +++++++++++++++++-----------
1 file changed, 17 insertions(+), 11 deletions(-)

diff --git a/hw/virtio/virtio-balloon.c b/hw/virtio/virtio-balloon.c
index d2cf66ada3c0..3ca6b1c6d511 100644
--- a/hw/virtio/virtio-balloon.c
+++ b/hw/virtio/virtio-balloon.c
@@ -285,7 +285,7 @@ static void balloon_stats_set_poll_interval(Object *obj, Visitor *v,
balloon_stats_change_timer(s, 0);
}

-static void *gpa2hva(MemoryRegion **p_mr, hwaddr addr, Error **errp)
+static void *gpa2hva(MemoryRegion **p_mr, unsigned long *size, hwaddr addr, Error **errp)
{
MemoryRegionSection mrs = memory_region_find(get_system_memory(),
addr, 1);
@@ -302,6 +302,7 @@ static void *gpa2hva(MemoryRegion **p_mr, hwaddr addr, Error **errp)
}

*p_mr = mrs.mr;
+ *size = mrs.mr->size - mrs.offset_within_region;
return qemu_map_ram_ptr(mrs.mr->ram_block, mrs.offset_within_region);
}

@@ -313,30 +314,35 @@ void page_hinting_request(uint64_t addr, uint32_t len)
struct guest_pages *guest_obj;
int i = 0;
void *hvaddr_to_free;
- unsigned long pfn, pfn_end;
uint64_t gpaddr_to_free;
- void * temp_addr = gpa2hva(&mr, addr, &local_err);
+ unsigned long madv_size, size;
+ void * temp_addr = gpa2hva(&mr, &madv_size, addr, &local_err);

if (local_err) {
error_report_err(local_err);
return;
}
+ if (madv_size < sizeof(*guest_obj)) {
+ printf("\nBad guest object ptr\n");
+ return;
+ }
guest_obj = temp_addr;
while (i < len) {
- pfn = guest_obj[i].pfn;
- pfn_end = guest_obj[i].pfn + (1 << guest_obj[i].order) - 1;
- trace_virtio_balloon_hinting_request(pfn,(1 << guest_obj[i].order));
- while (pfn <= pfn_end) {
- gpaddr_to_free = pfn << VIRTIO_BALLOON_PFN_SHIFT;
- hvaddr_to_free = gpa2hva(&mr, gpaddr_to_free, &local_err);
+ gpaddr_to_free = guest_obj[i].pfn << VIRTIO_BALLOON_PFN_SHIFT;
+ size = (1 << VIRTIO_BALLOON_PFN_SHIFT) << guest_obj[i].order;
+ while (size) {
+ hvaddr_to_free = gpa2hva(&mr, &madv_size, gpaddr_to_free, &local_err);
if (local_err) {
error_report_err(local_err);
return;
}
- ret = qemu_madvise((void *)hvaddr_to_free, 4096, QEMU_MADV_DONTNEED);
+ if (size < madv_size)
+ madv_size = size;
+ ret = qemu_madvise((void *)hvaddr_to_free, madv_size, QEMU_MADV_DONTNEED);
if (ret == -1)
printf("\n%d:%s Error: Madvise failed with error:%d\n", __LINE__, __func__, ret);
- pfn++;
+ gpaddr_to_free += madv_size;
+ size -= madv_size;
}
i++;
}