Skip to content

Commit

Permalink
virtio-balloon: free pbp more aggressively
Browse files Browse the repository at this point in the history
Previous patches switched to a temporary pbp but that does not go far
enough: after device uses a buffer, guest is free to reuse it, so
tracking the page and freeing it later is wrong.

Free and reset the pbp after we push each element.

Fixes: ed48c59 ("virtio-balloon: Safely handle BALLOON_PAGE_SIZE < host page size")
Cc: qemu-stable@nongnu.org #v4.0.0
Cc: David Hildenbrand <david@redhat.com>
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
(cherry picked from commit 1b47b37)
Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
  • Loading branch information
mstsirkin authored and mdroth committed Jul 30, 2019
1 parent 0965d55 commit c6b77a6
Showing 1 changed file with 16 additions and 21 deletions.
37 changes: 16 additions & 21 deletions hw/virtio/virtio-balloon.c
Expand Up @@ -40,22 +40,19 @@ typedef struct PartiallyBalloonedPage {

static void virtio_balloon_pbp_free(PartiallyBalloonedPage *pbp)
{
if (!pbp) {
if (!pbp->bitmap) {
return;
}
g_free(pbp->bitmap);
g_free(pbp);
pbp->bitmap = NULL;
}

static PartiallyBalloonedPage *virtio_balloon_pbp_alloc(ram_addr_t base_gpa,
long subpages)
static void virtio_balloon_pbp_alloc(PartiallyBalloonedPage *pbp,
ram_addr_t base_gpa,
long subpages)
{
PartiallyBalloonedPage *pbp = g_new0(PartiallyBalloonedPage, 1);

pbp->base_gpa = base_gpa;
pbp->bitmap = bitmap_new(subpages);

return pbp;
}

static bool virtio_balloon_pbp_matches(PartiallyBalloonedPage *pbp,
Expand All @@ -66,7 +63,7 @@ static bool virtio_balloon_pbp_matches(PartiallyBalloonedPage *pbp,

static void balloon_inflate_page(VirtIOBalloon *balloon,
MemoryRegion *mr, hwaddr mr_offset,
PartiallyBalloonedPage **pbp)
PartiallyBalloonedPage *pbp)
{
void *addr = memory_region_get_ram_ptr(mr) + mr_offset;
ram_addr_t rb_offset, rb_aligned_offset, base_gpa;
Expand Down Expand Up @@ -103,31 +100,29 @@ static void balloon_inflate_page(VirtIOBalloon *balloon,
base_gpa = memory_region_get_ram_addr(mr) + mr_offset -
(rb_offset - rb_aligned_offset);

if (*pbp && !virtio_balloon_pbp_matches(*pbp, base_gpa)) {
if (pbp->bitmap && !virtio_balloon_pbp_matches(pbp, base_gpa)) {
/* We've partially ballooned part of a host page, but now
* we're trying to balloon part of a different one. Too hard,
* give up on the old partial page */
virtio_balloon_pbp_free(*pbp);
*pbp = NULL;
virtio_balloon_pbp_free(pbp);
}

if (!*pbp) {
*pbp = virtio_balloon_pbp_alloc(base_gpa, subpages);
if (!pbp->bitmap) {
virtio_balloon_pbp_alloc(pbp, base_gpa, subpages);
}

set_bit((rb_offset - rb_aligned_offset) / BALLOON_PAGE_SIZE,
(*pbp)->bitmap);
pbp->bitmap);

if (bitmap_full((*pbp)->bitmap, subpages)) {
if (bitmap_full(pbp->bitmap, subpages)) {
/* We've accumulated a full host page, we can actually discard
* it now */

ram_block_discard_range(rb, rb_aligned_offset, rb_page_size);
/* We ignore errors from ram_block_discard_range(), because it
* has already reported them, and failing to discard a balloon
* page is not fatal */
virtio_balloon_pbp_free(*pbp);
*pbp = NULL;
virtio_balloon_pbp_free(pbp);
}
}

Expand Down Expand Up @@ -327,13 +322,14 @@ static void balloon_stats_set_poll_interval(Object *obj, Visitor *v,
static void virtio_balloon_handle_output(VirtIODevice *vdev, VirtQueue *vq)
{
VirtIOBalloon *s = VIRTIO_BALLOON(vdev);
PartiallyBalloonedPage *pbp = NULL;
VirtQueueElement *elem;
MemoryRegionSection section;

for (;;) {
PartiallyBalloonedPage pbp = {};
size_t offset = 0;
uint32_t pfn;

elem = virtqueue_pop(vq, sizeof(VirtQueueElement));
if (!elem) {
break;
Expand Down Expand Up @@ -378,9 +374,8 @@ static void virtio_balloon_handle_output(VirtIODevice *vdev, VirtQueue *vq)
virtqueue_push(vq, elem, offset);
virtio_notify(vdev, vq);
g_free(elem);
virtio_balloon_pbp_free(&pbp);
}

virtio_balloon_pbp_free(pbp);
}

static void virtio_balloon_receive_stats(VirtIODevice *vdev, VirtQueue *vq)
Expand Down

0 comments on commit c6b77a6

Please sign in to comment.