2008-12-04 23:33:06 +03:00
|
|
|
/*
|
2011-07-20 12:07:01 +04:00
|
|
|
* Virtio Balloon Device
|
2008-12-04 23:33:06 +03:00
|
|
|
*
|
|
|
|
* Copyright IBM, Corp. 2008
|
2011-07-20 12:07:01 +04:00
|
|
|
* Copyright (C) 2011 Red Hat, Inc.
|
|
|
|
* Copyright (C) 2011 Amit Shah <amit.shah@redhat.com>
|
2008-12-04 23:33:06 +03:00
|
|
|
*
|
|
|
|
* Authors:
|
|
|
|
* Anthony Liguori <aliguori@us.ibm.com>
|
|
|
|
*
|
|
|
|
* This work is licensed under the terms of the GNU GPL, version 2. See
|
|
|
|
* the COPYING file in the top-level directory.
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
|
2016-01-26 21:17:07 +03:00
|
|
|
#include "qemu/osdep.h"
|
2012-12-17 21:20:00 +04:00
|
|
|
#include "qemu/iov.h"
|
2019-05-23 17:35:07 +03:00
|
|
|
#include "qemu/module.h"
|
balloon: re-enable balloon stats
The statistics are now available through device properties via a
polling mechanism. First a client has to enable polling, then it
can query available stats.
Polling is enabled by setting an update interval (in seconds)
to a property named guest-stats-polling-interval, like this:
{ "execute": "qom-set",
"arguments": { "path": "/machine/peripheral-anon/device[1]",
"property": "guest-stats-polling-interval", "value": 4 } }
Then the available stats can be retrieved by querying the
guest-stats property. The returned object is a dict containing
all available stats. Example:
{ "execute": "qom-get",
"arguments": { "path": "/machine/peripheral-anon/device[1]",
"property": "guest-stats" } }
{
"return": {
"stats": {
"stat-swap-out": 0,
"stat-free-memory": 844943360,
"stat-minor-faults": 219028,
"stat-major-faults": 235,
"stat-total-memory": 1044406272,
"stat-swap-in": 0
},
"last-update": 1358529861
}
}
Please, check the next commit for full documentation.
Signed-off-by: Luiz Capitulino <lcapitulino@redhat.com>
Reviewed-by: Eric Blake <eblake@redhat.com>
2012-12-01 06:14:57 +04:00
|
|
|
#include "qemu/timer.h"
|
2013-02-05 20:06:20 +04:00
|
|
|
#include "hw/virtio/virtio.h"
|
2017-10-17 19:44:13 +03:00
|
|
|
#include "hw/mem/pc-dimm.h"
|
2019-08-12 08:23:51 +03:00
|
|
|
#include "hw/qdev-properties.h"
|
2012-12-17 21:20:04 +04:00
|
|
|
#include "sysemu/balloon.h"
|
2013-02-05 20:06:20 +04:00
|
|
|
#include "hw/virtio/virtio-balloon.h"
|
2012-12-17 21:19:49 +04:00
|
|
|
#include "exec/address-spaces.h"
|
2018-02-01 14:18:31 +03:00
|
|
|
#include "qapi/error.h"
|
2018-02-27 02:13:27 +03:00
|
|
|
#include "qapi/qapi-events-misc.h"
|
balloon: re-enable balloon stats
The statistics are now available through device properties via a
polling mechanism. First a client has to enable polling, then it
can query available stats.
Polling is enabled by setting an update interval (in seconds)
to a property named guest-stats-polling-interval, like this:
{ "execute": "qom-set",
"arguments": { "path": "/machine/peripheral-anon/device[1]",
"property": "guest-stats-polling-interval", "value": 4 } }
Then the available stats can be retrieved by querying the
guest-stats property. The returned object is a dict containing
all available stats. Example:
{ "execute": "qom-get",
"arguments": { "path": "/machine/peripheral-anon/device[1]",
"property": "guest-stats" } }
{
"return": {
"stats": {
"stat-swap-out": 0,
"stat-free-memory": 844943360,
"stat-minor-faults": 219028,
"stat-major-faults": 235,
"stat-total-memory": 1044406272,
"stat-swap-in": 0
},
"last-update": 1358529861
}
}
Please, check the next commit for full documentation.
Signed-off-by: Luiz Capitulino <lcapitulino@redhat.com>
Reviewed-by: Eric Blake <eblake@redhat.com>
2012-12-01 06:14:57 +04:00
|
|
|
#include "qapi/visitor.h"
|
2014-11-17 08:11:10 +03:00
|
|
|
#include "trace.h"
|
2017-09-11 22:52:50 +03:00
|
|
|
#include "qemu/error-report.h"
|
2018-12-11 11:24:53 +03:00
|
|
|
#include "migration/misc.h"
|
2008-12-04 23:33:06 +03:00
|
|
|
|
2013-02-05 20:06:20 +04:00
|
|
|
#include "hw/virtio/virtio-bus.h"
|
2014-06-24 21:43:22 +04:00
|
|
|
#include "hw/virtio/virtio-access.h"
|
2013-03-27 13:49:10 +04:00
|
|
|
|
2016-04-14 11:50:07 +03:00
|
|
|
#define BALLOON_PAGE_SIZE (1 << VIRTIO_BALLOON_PFN_SHIFT)
|
|
|
|
|
2019-07-22 16:41:08 +03:00
|
|
|
typedef struct PartiallyBalloonedPage {
|
2019-07-22 16:41:07 +03:00
|
|
|
ram_addr_t base_gpa;
|
|
|
|
unsigned long *bitmap;
|
2019-07-22 16:41:08 +03:00
|
|
|
} PartiallyBalloonedPage;
|
virtio-balloon: Safely handle BALLOON_PAGE_SIZE < host page size
The virtio-balloon always works in units of 4kiB (BALLOON_PAGE_SIZE), but
we can only actually discard memory in units of the host page size.
Now, we handle this very badly: we silently ignore balloon requests that
aren't host page aligned, and for requests that are host page aligned we
discard the entire host page. The latter can corrupt guest memory if its
page size is smaller than the host's.
The obvious choice would be to disable the balloon if the host page size is
not 4kiB. However, that would break the special case where host and guest
have the same page size, but that's larger than 4kiB. That case currently
works by accident[1] - and is used in practice on many production POWER
systems where 64kiB has long been the Linux default page size on both host
and guest.
To make the balloon safe, without breaking that useful special case, we
need to accumulate 4kiB balloon requests until we have a whole contiguous
host page to discard.
We could in principle do that across all guest memory, but it would require
a large bitmap to track. This patch represents a compromise: we track
ballooned subpages for a single contiguous host page at a time. This means
that if the guest discards all 4kiB chunks of a host page in succession,
we will discard it. This is the expected behaviour in the (host page) ==
(guest page) != 4kiB case we want to support.
If the guest scatters 4kiB requests across different host pages, we don't
discard anything, and issue a warning. Not ideal, but at least we don't
corrupt guest memory as the previous version could.
Warning reporting is kind of a compromise here. Determining whether we're
in a problematic state at realize() time is tricky, because we'd have to
look at the host pagesizes of all memory backends, but we can't really know
if some of those backends could be for special purpose memory that's not
subject to ballooning.
Reporting only when the guest tries to balloon a partial page also isn't
great because if the guest page size happens to line up it won't indicate
that we're in a non ideal situation. It could also cause alarming repeated
warnings whenever a migration is attempted.
So, what we do is warn the first time the guest attempts balloon a partial
host page, whether or not it will end up ballooning the rest of the page
immediately afterwards.
[1] Because when the guest attempts to balloon a page, it will submit
requests for each 4kiB subpage. Most will be ignored, but the one
which happens to be host page aligned will discard the whole lot.
Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
Message-Id: <20190214043916.22128-6-david@gibson.dropbear.id.au>
Reviewed-by: Michael S. Tsirkin <mst@redhat.com>
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
2019-02-14 07:39:16 +03:00
|
|
|
|
2019-07-22 16:41:07 +03:00
|
|
|
static void virtio_balloon_pbp_free(PartiallyBalloonedPage *pbp)
|
|
|
|
{
|
2019-07-25 14:54:25 +03:00
|
|
|
if (!pbp->bitmap) {
|
2019-07-22 16:41:07 +03:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
g_free(pbp->bitmap);
|
2019-07-25 14:54:25 +03:00
|
|
|
pbp->bitmap = NULL;
|
2019-07-22 16:41:07 +03:00
|
|
|
}
|
|
|
|
|
2019-07-25 14:54:25 +03:00
|
|
|
static void virtio_balloon_pbp_alloc(PartiallyBalloonedPage *pbp,
|
|
|
|
ram_addr_t base_gpa,
|
|
|
|
long subpages)
|
2019-07-22 16:41:07 +03:00
|
|
|
{
|
|
|
|
pbp->base_gpa = base_gpa;
|
|
|
|
pbp->bitmap = bitmap_new(subpages);
|
|
|
|
}
|
|
|
|
|
|
|
|
static bool virtio_balloon_pbp_matches(PartiallyBalloonedPage *pbp,
|
2019-07-25 14:36:38 +03:00
|
|
|
ram_addr_t base_gpa)
|
2019-07-22 16:41:07 +03:00
|
|
|
{
|
2019-07-25 14:36:38 +03:00
|
|
|
return pbp->base_gpa == base_gpa;
|
2019-07-22 16:41:07 +03:00
|
|
|
}
|
|
|
|
|
2019-02-14 07:39:14 +03:00
|
|
|
static void balloon_inflate_page(VirtIOBalloon *balloon,
|
2019-07-22 16:41:08 +03:00
|
|
|
MemoryRegion *mr, hwaddr mr_offset,
|
2019-07-25 14:54:25 +03:00
|
|
|
PartiallyBalloonedPage *pbp)
|
2008-12-04 23:33:06 +03:00
|
|
|
{
|
2019-07-22 16:41:06 +03:00
|
|
|
void *addr = memory_region_get_ram_ptr(mr) + mr_offset;
|
2019-07-22 16:41:07 +03:00
|
|
|
ram_addr_t rb_offset, rb_aligned_offset, base_gpa;
|
virtio-balloon: Use ram_block_discard_range() instead of raw madvise()
Currently, virtio-balloon uses madvise() with MADV_DONTNEED to actually
discard RAM pages inserted into the balloon. This is basically a Linux
only interface (MADV_DONTNEED exists on some other platforms, but doesn't
always have the same semantics). It also doesn't work on hugepages and has
some other limitations.
It turns out that postcopy also needs to discard chunks of memory, and uses
a better interface for it: ram_block_discard_range(). It doesn't cover
every case, but it covers more than going direct to madvise() and this
gives us a single place to update for more possibilities in future.
There are some subtleties here to maintain the current balloon behaviour:
* For now, we just ignore requests to balloon in a hugepage backed region.
That matches current behaviour, because MADV_DONTNEED on a hugepage would
simply fail, and we ignore the error.
* If host page size is > BALLOON_PAGE_SIZE we can frequently call this on
non-host-page-aligned addresses. These would also fail in madvise(),
which we then ignored. ram_block_discard_range() error_report()s calls
on unaligned addresses, so we explicitly check that case to avoid
spamming the logs.
* We now call ram_block_discard_range() with the *host* page size, whereas
we previously called madvise() with BALLOON_PAGE_SIZE. Surprisingly,
this also matches existing behaviour. Although the kernel fails madvise
on unaligned addresses, it will round unaligned sizes *up* to the host
page size. Yes, this means that if BALLOON_PAGE_SIZE < guest page size
we can incorrectly discard more memory than the guest asked us to. I'm
planning to address that soon.
Errors other than the ones discussed above, will now be reported by
ram_block_discard_range(), rather than silently ignored, which means we
have a much better chance of seeing when something is going wrong.
Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
Reviewed-by: Michael S. Tsirkin <mst@redhat.com>
Message-Id: <20190214043916.22128-5-david@gibson.dropbear.id.au>
Reviewed-by: Michael S. Tsirkin <mst@redhat.com>
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
2019-02-14 07:39:15 +03:00
|
|
|
RAMBlock *rb;
|
|
|
|
size_t rb_page_size;
|
virtio-balloon: Safely handle BALLOON_PAGE_SIZE < host page size
The virtio-balloon always works in units of 4kiB (BALLOON_PAGE_SIZE), but
we can only actually discard memory in units of the host page size.
Now, we handle this very badly: we silently ignore balloon requests that
aren't host page aligned, and for requests that are host page aligned we
discard the entire host page. The latter can corrupt guest memory if its
page size is smaller than the host's.
The obvious choice would be to disable the balloon if the host page size is
not 4kiB. However, that would break the special case where host and guest
have the same page size, but that's larger than 4kiB. That case currently
works by accident[1] - and is used in practice on many production POWER
systems where 64kiB has long been the Linux default page size on both host
and guest.
To make the balloon safe, without breaking that useful special case, we
need to accumulate 4kiB balloon requests until we have a whole contiguous
host page to discard.
We could in principle do that across all guest memory, but it would require
a large bitmap to track. This patch represents a compromise: we track
ballooned subpages for a single contiguous host page at a time. This means
that if the guest discards all 4kiB chunks of a host page in succession,
we will discard it. This is the expected behaviour in the (host page) ==
(guest page) != 4kiB case we want to support.
If the guest scatters 4kiB requests across different host pages, we don't
discard anything, and issue a warning. Not ideal, but at least we don't
corrupt guest memory as the previous version could.
Warning reporting is kind of a compromise here. Determining whether we're
in a problematic state at realize() time is tricky, because we'd have to
look at the host pagesizes of all memory backends, but we can't really know
if some of those backends could be for special purpose memory that's not
subject to ballooning.
Reporting only when the guest tries to balloon a partial page also isn't
great because if the guest page size happens to line up it won't indicate
that we're in a non ideal situation. It could also cause alarming repeated
warnings whenever a migration is attempted.
So, what we do is warn the first time the guest attempts balloon a partial
host page, whether or not it will end up ballooning the rest of the page
immediately afterwards.
[1] Because when the guest attempts to balloon a page, it will submit
requests for each 4kiB subpage. Most will be ignored, but the one
which happens to be host page aligned will discard the whole lot.
Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
Message-Id: <20190214043916.22128-6-david@gibson.dropbear.id.au>
Reviewed-by: Michael S. Tsirkin <mst@redhat.com>
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
2019-02-14 07:39:16 +03:00
|
|
|
int subpages;
|
2019-02-14 07:39:14 +03:00
|
|
|
|
virtio-balloon: Use ram_block_discard_range() instead of raw madvise()
Currently, virtio-balloon uses madvise() with MADV_DONTNEED to actually
discard RAM pages inserted into the balloon. This is basically a Linux
only interface (MADV_DONTNEED exists on some other platforms, but doesn't
always have the same semantics). It also doesn't work on hugepages and has
some other limitations.
It turns out that postcopy also needs to discard chunks of memory, and uses
a better interface for it: ram_block_discard_range(). It doesn't cover
every case, but it covers more than going direct to madvise() and this
gives us a single place to update for more possibilities in future.
There are some subtleties here to maintain the current balloon behaviour:
* For now, we just ignore requests to balloon in a hugepage backed region.
That matches current behaviour, because MADV_DONTNEED on a hugepage would
simply fail, and we ignore the error.
* If host page size is > BALLOON_PAGE_SIZE we can frequently call this on
non-host-page-aligned addresses. These would also fail in madvise(),
which we then ignored. ram_block_discard_range() error_report()s calls
on unaligned addresses, so we explicitly check that case to avoid
spamming the logs.
* We now call ram_block_discard_range() with the *host* page size, whereas
we previously called madvise() with BALLOON_PAGE_SIZE. Surprisingly,
this also matches existing behaviour. Although the kernel fails madvise
on unaligned addresses, it will round unaligned sizes *up* to the host
page size. Yes, this means that if BALLOON_PAGE_SIZE < guest page size
we can incorrectly discard more memory than the guest asked us to. I'm
planning to address that soon.
Errors other than the ones discussed above, will now be reported by
ram_block_discard_range(), rather than silently ignored, which means we
have a much better chance of seeing when something is going wrong.
Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
Reviewed-by: Michael S. Tsirkin <mst@redhat.com>
Message-Id: <20190214043916.22128-5-david@gibson.dropbear.id.au>
Reviewed-by: Michael S. Tsirkin <mst@redhat.com>
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
2019-02-14 07:39:15 +03:00
|
|
|
/* XXX is there a better way to get to the RAMBlock than via a
|
|
|
|
* host address? */
|
2019-07-22 16:41:06 +03:00
|
|
|
rb = qemu_ram_block_from_host(addr, false, &rb_offset);
|
virtio-balloon: Use ram_block_discard_range() instead of raw madvise()
Currently, virtio-balloon uses madvise() with MADV_DONTNEED to actually
discard RAM pages inserted into the balloon. This is basically a Linux
only interface (MADV_DONTNEED exists on some other platforms, but doesn't
always have the same semantics). It also doesn't work on hugepages and has
some other limitations.
It turns out that postcopy also needs to discard chunks of memory, and uses
a better interface for it: ram_block_discard_range(). It doesn't cover
every case, but it covers more than going direct to madvise() and this
gives us a single place to update for more possibilities in future.
There are some subtleties here to maintain the current balloon behaviour:
* For now, we just ignore requests to balloon in a hugepage backed region.
That matches current behaviour, because MADV_DONTNEED on a hugepage would
simply fail, and we ignore the error.
* If host page size is > BALLOON_PAGE_SIZE we can frequently call this on
non-host-page-aligned addresses. These would also fail in madvise(),
which we then ignored. ram_block_discard_range() error_report()s calls
on unaligned addresses, so we explicitly check that case to avoid
spamming the logs.
* We now call ram_block_discard_range() with the *host* page size, whereas
we previously called madvise() with BALLOON_PAGE_SIZE. Surprisingly,
this also matches existing behaviour. Although the kernel fails madvise
on unaligned addresses, it will round unaligned sizes *up* to the host
page size. Yes, this means that if BALLOON_PAGE_SIZE < guest page size
we can incorrectly discard more memory than the guest asked us to. I'm
planning to address that soon.
Errors other than the ones discussed above, will now be reported by
ram_block_discard_range(), rather than silently ignored, which means we
have a much better chance of seeing when something is going wrong.
Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
Reviewed-by: Michael S. Tsirkin <mst@redhat.com>
Message-Id: <20190214043916.22128-5-david@gibson.dropbear.id.au>
Reviewed-by: Michael S. Tsirkin <mst@redhat.com>
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
2019-02-14 07:39:15 +03:00
|
|
|
rb_page_size = qemu_ram_pagesize(rb);
|
virtio-balloon: Safely handle BALLOON_PAGE_SIZE < host page size
The virtio-balloon always works in units of 4kiB (BALLOON_PAGE_SIZE), but
we can only actually discard memory in units of the host page size.
Now, we handle this very badly: we silently ignore balloon requests that
aren't host page aligned, and for requests that are host page aligned we
discard the entire host page. The latter can corrupt guest memory if its
page size is smaller than the host's.
The obvious choice would be to disable the balloon if the host page size is
not 4kiB. However, that would break the special case where host and guest
have the same page size, but that's larger than 4kiB. That case currently
works by accident[1] - and is used in practice on many production POWER
systems where 64kiB has long been the Linux default page size on both host
and guest.
To make the balloon safe, without breaking that useful special case, we
need to accumulate 4kiB balloon requests until we have a whole contiguous
host page to discard.
We could in principle do that across all guest memory, but it would require
a large bitmap to track. This patch represents a compromise: we track
ballooned subpages for a single contiguous host page at a time. This means
that if the guest discards all 4kiB chunks of a host page in succession,
we will discard it. This is the expected behaviour in the (host page) ==
(guest page) != 4kiB case we want to support.
If the guest scatters 4kiB requests across different host pages, we don't
discard anything, and issue a warning. Not ideal, but at least we don't
corrupt guest memory as the previous version could.
Warning reporting is kind of a compromise here. Determining whether we're
in a problematic state at realize() time is tricky, because we'd have to
look at the host pagesizes of all memory backends, but we can't really know
if some of those backends could be for special purpose memory that's not
subject to ballooning.
Reporting only when the guest tries to balloon a partial page also isn't
great because if the guest page size happens to line up it won't indicate
that we're in a non ideal situation. It could also cause alarming repeated
warnings whenever a migration is attempted.
So, what we do is warn the first time the guest attempts balloon a partial
host page, whether or not it will end up ballooning the rest of the page
immediately afterwards.
[1] Because when the guest attempts to balloon a page, it will submit
requests for each 4kiB subpage. Most will be ignored, but the one
which happens to be host page aligned will discard the whole lot.
Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
Message-Id: <20190214043916.22128-6-david@gibson.dropbear.id.au>
Reviewed-by: Michael S. Tsirkin <mst@redhat.com>
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
2019-02-14 07:39:16 +03:00
|
|
|
|
|
|
|
if (rb_page_size == BALLOON_PAGE_SIZE) {
|
|
|
|
/* Easy case */
|
virtio-balloon: Use ram_block_discard_range() instead of raw madvise()
Currently, virtio-balloon uses madvise() with MADV_DONTNEED to actually
discard RAM pages inserted into the balloon. This is basically a Linux
only interface (MADV_DONTNEED exists on some other platforms, but doesn't
always have the same semantics). It also doesn't work on hugepages and has
some other limitations.
It turns out that postcopy also needs to discard chunks of memory, and uses
a better interface for it: ram_block_discard_range(). It doesn't cover
every case, but it covers more than going direct to madvise() and this
gives us a single place to update for more possibilities in future.
There are some subtleties here to maintain the current balloon behaviour:
* For now, we just ignore requests to balloon in a hugepage backed region.
That matches current behaviour, because MADV_DONTNEED on a hugepage would
simply fail, and we ignore the error.
* If host page size is > BALLOON_PAGE_SIZE we can frequently call this on
non-host-page-aligned addresses. These would also fail in madvise(),
which we then ignored. ram_block_discard_range() error_report()s calls
on unaligned addresses, so we explicitly check that case to avoid
spamming the logs.
* We now call ram_block_discard_range() with the *host* page size, whereas
we previously called madvise() with BALLOON_PAGE_SIZE. Surprisingly,
this also matches existing behaviour. Although the kernel fails madvise
on unaligned addresses, it will round unaligned sizes *up* to the host
page size. Yes, this means that if BALLOON_PAGE_SIZE < guest page size
we can incorrectly discard more memory than the guest asked us to. I'm
planning to address that soon.
Errors other than the ones discussed above, will now be reported by
ram_block_discard_range(), rather than silently ignored, which means we
have a much better chance of seeing when something is going wrong.
Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
Reviewed-by: Michael S. Tsirkin <mst@redhat.com>
Message-Id: <20190214043916.22128-5-david@gibson.dropbear.id.au>
Reviewed-by: Michael S. Tsirkin <mst@redhat.com>
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
2019-02-14 07:39:15 +03:00
|
|
|
|
2019-07-22 16:41:06 +03:00
|
|
|
ram_block_discard_range(rb, rb_offset, rb_page_size);
|
virtio-balloon: Safely handle BALLOON_PAGE_SIZE < host page size
The virtio-balloon always works in units of 4kiB (BALLOON_PAGE_SIZE), but
we can only actually discard memory in units of the host page size.
Now, we handle this very badly: we silently ignore balloon requests that
aren't host page aligned, and for requests that are host page aligned we
discard the entire host page. The latter can corrupt guest memory if its
page size is smaller than the host's.
The obvious choice would be to disable the balloon if the host page size is
not 4kiB. However, that would break the special case where host and guest
have the same page size, but that's larger than 4kiB. That case currently
works by accident[1] - and is used in practice on many production POWER
systems where 64kiB has long been the Linux default page size on both host
and guest.
To make the balloon safe, without breaking that useful special case, we
need to accumulate 4kiB balloon requests until we have a whole contiguous
host page to discard.
We could in principle do that across all guest memory, but it would require
a large bitmap to track. This patch represents a compromise: we track
ballooned subpages for a single contiguous host page at a time. This means
that if the guest discards all 4kiB chunks of a host page in succession,
we will discard it. This is the expected behaviour in the (host page) ==
(guest page) != 4kiB case we want to support.
If the guest scatters 4kiB requests across different host pages, we don't
discard anything, and issue a warning. Not ideal, but at least we don't
corrupt guest memory as the previous version could.
Warning reporting is kind of a compromise here. Determining whether we're
in a problematic state at realize() time is tricky, because we'd have to
look at the host pagesizes of all memory backends, but we can't really know
if some of those backends could be for special purpose memory that's not
subject to ballooning.
Reporting only when the guest tries to balloon a partial page also isn't
great because if the guest page size happens to line up it won't indicate
that we're in a non ideal situation. It could also cause alarming repeated
warnings whenever a migration is attempted.
So, what we do is warn the first time the guest attempts balloon a partial
host page, whether or not it will end up ballooning the rest of the page
immediately afterwards.
[1] Because when the guest attempts to balloon a page, it will submit
requests for each 4kiB subpage. Most will be ignored, but the one
which happens to be host page aligned will discard the whole lot.
Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
Message-Id: <20190214043916.22128-6-david@gibson.dropbear.id.au>
Reviewed-by: Michael S. Tsirkin <mst@redhat.com>
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
2019-02-14 07:39:16 +03:00
|
|
|
/* 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: Use ram_block_discard_range() instead of raw madvise()
Currently, virtio-balloon uses madvise() with MADV_DONTNEED to actually
discard RAM pages inserted into the balloon. This is basically a Linux
only interface (MADV_DONTNEED exists on some other platforms, but doesn't
always have the same semantics). It also doesn't work on hugepages and has
some other limitations.
It turns out that postcopy also needs to discard chunks of memory, and uses
a better interface for it: ram_block_discard_range(). It doesn't cover
every case, but it covers more than going direct to madvise() and this
gives us a single place to update for more possibilities in future.
There are some subtleties here to maintain the current balloon behaviour:
* For now, we just ignore requests to balloon in a hugepage backed region.
That matches current behaviour, because MADV_DONTNEED on a hugepage would
simply fail, and we ignore the error.
* If host page size is > BALLOON_PAGE_SIZE we can frequently call this on
non-host-page-aligned addresses. These would also fail in madvise(),
which we then ignored. ram_block_discard_range() error_report()s calls
on unaligned addresses, so we explicitly check that case to avoid
spamming the logs.
* We now call ram_block_discard_range() with the *host* page size, whereas
we previously called madvise() with BALLOON_PAGE_SIZE. Surprisingly,
this also matches existing behaviour. Although the kernel fails madvise
on unaligned addresses, it will round unaligned sizes *up* to the host
page size. Yes, this means that if BALLOON_PAGE_SIZE < guest page size
we can incorrectly discard more memory than the guest asked us to. I'm
planning to address that soon.
Errors other than the ones discussed above, will now be reported by
ram_block_discard_range(), rather than silently ignored, which means we
have a much better chance of seeing when something is going wrong.
Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
Reviewed-by: Michael S. Tsirkin <mst@redhat.com>
Message-Id: <20190214043916.22128-5-david@gibson.dropbear.id.au>
Reviewed-by: Michael S. Tsirkin <mst@redhat.com>
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
2019-02-14 07:39:15 +03:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
virtio-balloon: Safely handle BALLOON_PAGE_SIZE < host page size
The virtio-balloon always works in units of 4kiB (BALLOON_PAGE_SIZE), but
we can only actually discard memory in units of the host page size.
Now, we handle this very badly: we silently ignore balloon requests that
aren't host page aligned, and for requests that are host page aligned we
discard the entire host page. The latter can corrupt guest memory if its
page size is smaller than the host's.
The obvious choice would be to disable the balloon if the host page size is
not 4kiB. However, that would break the special case where host and guest
have the same page size, but that's larger than 4kiB. That case currently
works by accident[1] - and is used in practice on many production POWER
systems where 64kiB has long been the Linux default page size on both host
and guest.
To make the balloon safe, without breaking that useful special case, we
need to accumulate 4kiB balloon requests until we have a whole contiguous
host page to discard.
We could in principle do that across all guest memory, but it would require
a large bitmap to track. This patch represents a compromise: we track
ballooned subpages for a single contiguous host page at a time. This means
that if the guest discards all 4kiB chunks of a host page in succession,
we will discard it. This is the expected behaviour in the (host page) ==
(guest page) != 4kiB case we want to support.
If the guest scatters 4kiB requests across different host pages, we don't
discard anything, and issue a warning. Not ideal, but at least we don't
corrupt guest memory as the previous version could.
Warning reporting is kind of a compromise here. Determining whether we're
in a problematic state at realize() time is tricky, because we'd have to
look at the host pagesizes of all memory backends, but we can't really know
if some of those backends could be for special purpose memory that's not
subject to ballooning.
Reporting only when the guest tries to balloon a partial page also isn't
great because if the guest page size happens to line up it won't indicate
that we're in a non ideal situation. It could also cause alarming repeated
warnings whenever a migration is attempted.
So, what we do is warn the first time the guest attempts balloon a partial
host page, whether or not it will end up ballooning the rest of the page
immediately afterwards.
[1] Because when the guest attempts to balloon a page, it will submit
requests for each 4kiB subpage. Most will be ignored, but the one
which happens to be host page aligned will discard the whole lot.
Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
Message-Id: <20190214043916.22128-6-david@gibson.dropbear.id.au>
Reviewed-by: Michael S. Tsirkin <mst@redhat.com>
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
2019-02-14 07:39:16 +03:00
|
|
|
/* Hard case
|
|
|
|
*
|
|
|
|
* We've put a piece of a larger host page into the balloon - we
|
|
|
|
* need to keep track until we have a whole host page to
|
|
|
|
* discard
|
|
|
|
*/
|
|
|
|
warn_report_once(
|
|
|
|
"Balloon used with backing page size > 4kiB, this may not be reliable");
|
|
|
|
|
2019-07-22 16:41:06 +03:00
|
|
|
rb_aligned_offset = QEMU_ALIGN_DOWN(rb_offset, rb_page_size);
|
virtio-balloon: Safely handle BALLOON_PAGE_SIZE < host page size
The virtio-balloon always works in units of 4kiB (BALLOON_PAGE_SIZE), but
we can only actually discard memory in units of the host page size.
Now, we handle this very badly: we silently ignore balloon requests that
aren't host page aligned, and for requests that are host page aligned we
discard the entire host page. The latter can corrupt guest memory if its
page size is smaller than the host's.
The obvious choice would be to disable the balloon if the host page size is
not 4kiB. However, that would break the special case where host and guest
have the same page size, but that's larger than 4kiB. That case currently
works by accident[1] - and is used in practice on many production POWER
systems where 64kiB has long been the Linux default page size on both host
and guest.
To make the balloon safe, without breaking that useful special case, we
need to accumulate 4kiB balloon requests until we have a whole contiguous
host page to discard.
We could in principle do that across all guest memory, but it would require
a large bitmap to track. This patch represents a compromise: we track
ballooned subpages for a single contiguous host page at a time. This means
that if the guest discards all 4kiB chunks of a host page in succession,
we will discard it. This is the expected behaviour in the (host page) ==
(guest page) != 4kiB case we want to support.
If the guest scatters 4kiB requests across different host pages, we don't
discard anything, and issue a warning. Not ideal, but at least we don't
corrupt guest memory as the previous version could.
Warning reporting is kind of a compromise here. Determining whether we're
in a problematic state at realize() time is tricky, because we'd have to
look at the host pagesizes of all memory backends, but we can't really know
if some of those backends could be for special purpose memory that's not
subject to ballooning.
Reporting only when the guest tries to balloon a partial page also isn't
great because if the guest page size happens to line up it won't indicate
that we're in a non ideal situation. It could also cause alarming repeated
warnings whenever a migration is attempted.
So, what we do is warn the first time the guest attempts balloon a partial
host page, whether or not it will end up ballooning the rest of the page
immediately afterwards.
[1] Because when the guest attempts to balloon a page, it will submit
requests for each 4kiB subpage. Most will be ignored, but the one
which happens to be host page aligned will discard the whole lot.
Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
Message-Id: <20190214043916.22128-6-david@gibson.dropbear.id.au>
Reviewed-by: Michael S. Tsirkin <mst@redhat.com>
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
2019-02-14 07:39:16 +03:00
|
|
|
subpages = rb_page_size / BALLOON_PAGE_SIZE;
|
2019-07-22 16:41:07 +03:00
|
|
|
base_gpa = memory_region_get_ram_addr(mr) + mr_offset -
|
|
|
|
(rb_offset - rb_aligned_offset);
|
virtio-balloon: Safely handle BALLOON_PAGE_SIZE < host page size
The virtio-balloon always works in units of 4kiB (BALLOON_PAGE_SIZE), but
we can only actually discard memory in units of the host page size.
Now, we handle this very badly: we silently ignore balloon requests that
aren't host page aligned, and for requests that are host page aligned we
discard the entire host page. The latter can corrupt guest memory if its
page size is smaller than the host's.
The obvious choice would be to disable the balloon if the host page size is
not 4kiB. However, that would break the special case where host and guest
have the same page size, but that's larger than 4kiB. That case currently
works by accident[1] - and is used in practice on many production POWER
systems where 64kiB has long been the Linux default page size on both host
and guest.
To make the balloon safe, without breaking that useful special case, we
need to accumulate 4kiB balloon requests until we have a whole contiguous
host page to discard.
We could in principle do that across all guest memory, but it would require
a large bitmap to track. This patch represents a compromise: we track
ballooned subpages for a single contiguous host page at a time. This means
that if the guest discards all 4kiB chunks of a host page in succession,
we will discard it. This is the expected behaviour in the (host page) ==
(guest page) != 4kiB case we want to support.
If the guest scatters 4kiB requests across different host pages, we don't
discard anything, and issue a warning. Not ideal, but at least we don't
corrupt guest memory as the previous version could.
Warning reporting is kind of a compromise here. Determining whether we're
in a problematic state at realize() time is tricky, because we'd have to
look at the host pagesizes of all memory backends, but we can't really know
if some of those backends could be for special purpose memory that's not
subject to ballooning.
Reporting only when the guest tries to balloon a partial page also isn't
great because if the guest page size happens to line up it won't indicate
that we're in a non ideal situation. It could also cause alarming repeated
warnings whenever a migration is attempted.
So, what we do is warn the first time the guest attempts balloon a partial
host page, whether or not it will end up ballooning the rest of the page
immediately afterwards.
[1] Because when the guest attempts to balloon a page, it will submit
requests for each 4kiB subpage. Most will be ignored, but the one
which happens to be host page aligned will discard the whole lot.
Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
Message-Id: <20190214043916.22128-6-david@gibson.dropbear.id.au>
Reviewed-by: Michael S. Tsirkin <mst@redhat.com>
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
2019-02-14 07:39:16 +03:00
|
|
|
|
2019-07-25 14:54:25 +03:00
|
|
|
if (pbp->bitmap && !virtio_balloon_pbp_matches(pbp, base_gpa)) {
|
virtio-balloon: Safely handle BALLOON_PAGE_SIZE < host page size
The virtio-balloon always works in units of 4kiB (BALLOON_PAGE_SIZE), but
we can only actually discard memory in units of the host page size.
Now, we handle this very badly: we silently ignore balloon requests that
aren't host page aligned, and for requests that are host page aligned we
discard the entire host page. The latter can corrupt guest memory if its
page size is smaller than the host's.
The obvious choice would be to disable the balloon if the host page size is
not 4kiB. However, that would break the special case where host and guest
have the same page size, but that's larger than 4kiB. That case currently
works by accident[1] - and is used in practice on many production POWER
systems where 64kiB has long been the Linux default page size on both host
and guest.
To make the balloon safe, without breaking that useful special case, we
need to accumulate 4kiB balloon requests until we have a whole contiguous
host page to discard.
We could in principle do that across all guest memory, but it would require
a large bitmap to track. This patch represents a compromise: we track
ballooned subpages for a single contiguous host page at a time. This means
that if the guest discards all 4kiB chunks of a host page in succession,
we will discard it. This is the expected behaviour in the (host page) ==
(guest page) != 4kiB case we want to support.
If the guest scatters 4kiB requests across different host pages, we don't
discard anything, and issue a warning. Not ideal, but at least we don't
corrupt guest memory as the previous version could.
Warning reporting is kind of a compromise here. Determining whether we're
in a problematic state at realize() time is tricky, because we'd have to
look at the host pagesizes of all memory backends, but we can't really know
if some of those backends could be for special purpose memory that's not
subject to ballooning.
Reporting only when the guest tries to balloon a partial page also isn't
great because if the guest page size happens to line up it won't indicate
that we're in a non ideal situation. It could also cause alarming repeated
warnings whenever a migration is attempted.
So, what we do is warn the first time the guest attempts balloon a partial
host page, whether or not it will end up ballooning the rest of the page
immediately afterwards.
[1] Because when the guest attempts to balloon a page, it will submit
requests for each 4kiB subpage. Most will be ignored, but the one
which happens to be host page aligned will discard the whole lot.
Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
Message-Id: <20190214043916.22128-6-david@gibson.dropbear.id.au>
Reviewed-by: Michael S. Tsirkin <mst@redhat.com>
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
2019-02-14 07:39:16 +03:00
|
|
|
/* 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 */
|
2019-07-25 14:54:25 +03:00
|
|
|
virtio_balloon_pbp_free(pbp);
|
virtio-balloon: Use ram_block_discard_range() instead of raw madvise()
Currently, virtio-balloon uses madvise() with MADV_DONTNEED to actually
discard RAM pages inserted into the balloon. This is basically a Linux
only interface (MADV_DONTNEED exists on some other platforms, but doesn't
always have the same semantics). It also doesn't work on hugepages and has
some other limitations.
It turns out that postcopy also needs to discard chunks of memory, and uses
a better interface for it: ram_block_discard_range(). It doesn't cover
every case, but it covers more than going direct to madvise() and this
gives us a single place to update for more possibilities in future.
There are some subtleties here to maintain the current balloon behaviour:
* For now, we just ignore requests to balloon in a hugepage backed region.
That matches current behaviour, because MADV_DONTNEED on a hugepage would
simply fail, and we ignore the error.
* If host page size is > BALLOON_PAGE_SIZE we can frequently call this on
non-host-page-aligned addresses. These would also fail in madvise(),
which we then ignored. ram_block_discard_range() error_report()s calls
on unaligned addresses, so we explicitly check that case to avoid
spamming the logs.
* We now call ram_block_discard_range() with the *host* page size, whereas
we previously called madvise() with BALLOON_PAGE_SIZE. Surprisingly,
this also matches existing behaviour. Although the kernel fails madvise
on unaligned addresses, it will round unaligned sizes *up* to the host
page size. Yes, this means that if BALLOON_PAGE_SIZE < guest page size
we can incorrectly discard more memory than the guest asked us to. I'm
planning to address that soon.
Errors other than the ones discussed above, will now be reported by
ram_block_discard_range(), rather than silently ignored, which means we
have a much better chance of seeing when something is going wrong.
Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
Reviewed-by: Michael S. Tsirkin <mst@redhat.com>
Message-Id: <20190214043916.22128-5-david@gibson.dropbear.id.au>
Reviewed-by: Michael S. Tsirkin <mst@redhat.com>
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
2019-02-14 07:39:15 +03:00
|
|
|
}
|
|
|
|
|
2019-07-25 14:54:25 +03:00
|
|
|
if (!pbp->bitmap) {
|
|
|
|
virtio_balloon_pbp_alloc(pbp, base_gpa, subpages);
|
virtio-balloon: Safely handle BALLOON_PAGE_SIZE < host page size
The virtio-balloon always works in units of 4kiB (BALLOON_PAGE_SIZE), but
we can only actually discard memory in units of the host page size.
Now, we handle this very badly: we silently ignore balloon requests that
aren't host page aligned, and for requests that are host page aligned we
discard the entire host page. The latter can corrupt guest memory if its
page size is smaller than the host's.
The obvious choice would be to disable the balloon if the host page size is
not 4kiB. However, that would break the special case where host and guest
have the same page size, but that's larger than 4kiB. That case currently
works by accident[1] - and is used in practice on many production POWER
systems where 64kiB has long been the Linux default page size on both host
and guest.
To make the balloon safe, without breaking that useful special case, we
need to accumulate 4kiB balloon requests until we have a whole contiguous
host page to discard.
We could in principle do that across all guest memory, but it would require
a large bitmap to track. This patch represents a compromise: we track
ballooned subpages for a single contiguous host page at a time. This means
that if the guest discards all 4kiB chunks of a host page in succession,
we will discard it. This is the expected behaviour in the (host page) ==
(guest page) != 4kiB case we want to support.
If the guest scatters 4kiB requests across different host pages, we don't
discard anything, and issue a warning. Not ideal, but at least we don't
corrupt guest memory as the previous version could.
Warning reporting is kind of a compromise here. Determining whether we're
in a problematic state at realize() time is tricky, because we'd have to
look at the host pagesizes of all memory backends, but we can't really know
if some of those backends could be for special purpose memory that's not
subject to ballooning.
Reporting only when the guest tries to balloon a partial page also isn't
great because if the guest page size happens to line up it won't indicate
that we're in a non ideal situation. It could also cause alarming repeated
warnings whenever a migration is attempted.
So, what we do is warn the first time the guest attempts balloon a partial
host page, whether or not it will end up ballooning the rest of the page
immediately afterwards.
[1] Because when the guest attempts to balloon a page, it will submit
requests for each 4kiB subpage. Most will be ignored, but the one
which happens to be host page aligned will discard the whole lot.
Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
Message-Id: <20190214043916.22128-6-david@gibson.dropbear.id.au>
Reviewed-by: Michael S. Tsirkin <mst@redhat.com>
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
2019-02-14 07:39:16 +03:00
|
|
|
}
|
|
|
|
|
2019-07-22 16:41:07 +03:00
|
|
|
set_bit((rb_offset - rb_aligned_offset) / BALLOON_PAGE_SIZE,
|
2019-07-25 14:54:25 +03:00
|
|
|
pbp->bitmap);
|
virtio-balloon: Safely handle BALLOON_PAGE_SIZE < host page size
The virtio-balloon always works in units of 4kiB (BALLOON_PAGE_SIZE), but
we can only actually discard memory in units of the host page size.
Now, we handle this very badly: we silently ignore balloon requests that
aren't host page aligned, and for requests that are host page aligned we
discard the entire host page. The latter can corrupt guest memory if its
page size is smaller than the host's.
The obvious choice would be to disable the balloon if the host page size is
not 4kiB. However, that would break the special case where host and guest
have the same page size, but that's larger than 4kiB. That case currently
works by accident[1] - and is used in practice on many production POWER
systems where 64kiB has long been the Linux default page size on both host
and guest.
To make the balloon safe, without breaking that useful special case, we
need to accumulate 4kiB balloon requests until we have a whole contiguous
host page to discard.
We could in principle do that across all guest memory, but it would require
a large bitmap to track. This patch represents a compromise: we track
ballooned subpages for a single contiguous host page at a time. This means
that if the guest discards all 4kiB chunks of a host page in succession,
we will discard it. This is the expected behaviour in the (host page) ==
(guest page) != 4kiB case we want to support.
If the guest scatters 4kiB requests across different host pages, we don't
discard anything, and issue a warning. Not ideal, but at least we don't
corrupt guest memory as the previous version could.
Warning reporting is kind of a compromise here. Determining whether we're
in a problematic state at realize() time is tricky, because we'd have to
look at the host pagesizes of all memory backends, but we can't really know
if some of those backends could be for special purpose memory that's not
subject to ballooning.
Reporting only when the guest tries to balloon a partial page also isn't
great because if the guest page size happens to line up it won't indicate
that we're in a non ideal situation. It could also cause alarming repeated
warnings whenever a migration is attempted.
So, what we do is warn the first time the guest attempts balloon a partial
host page, whether or not it will end up ballooning the rest of the page
immediately afterwards.
[1] Because when the guest attempts to balloon a page, it will submit
requests for each 4kiB subpage. Most will be ignored, but the one
which happens to be host page aligned will discard the whole lot.
Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
Message-Id: <20190214043916.22128-6-david@gibson.dropbear.id.au>
Reviewed-by: Michael S. Tsirkin <mst@redhat.com>
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
2019-02-14 07:39:16 +03:00
|
|
|
|
2019-07-25 14:54:25 +03:00
|
|
|
if (bitmap_full(pbp->bitmap, subpages)) {
|
virtio-balloon: Safely handle BALLOON_PAGE_SIZE < host page size
The virtio-balloon always works in units of 4kiB (BALLOON_PAGE_SIZE), but
we can only actually discard memory in units of the host page size.
Now, we handle this very badly: we silently ignore balloon requests that
aren't host page aligned, and for requests that are host page aligned we
discard the entire host page. The latter can corrupt guest memory if its
page size is smaller than the host's.
The obvious choice would be to disable the balloon if the host page size is
not 4kiB. However, that would break the special case where host and guest
have the same page size, but that's larger than 4kiB. That case currently
works by accident[1] - and is used in practice on many production POWER
systems where 64kiB has long been the Linux default page size on both host
and guest.
To make the balloon safe, without breaking that useful special case, we
need to accumulate 4kiB balloon requests until we have a whole contiguous
host page to discard.
We could in principle do that across all guest memory, but it would require
a large bitmap to track. This patch represents a compromise: we track
ballooned subpages for a single contiguous host page at a time. This means
that if the guest discards all 4kiB chunks of a host page in succession,
we will discard it. This is the expected behaviour in the (host page) ==
(guest page) != 4kiB case we want to support.
If the guest scatters 4kiB requests across different host pages, we don't
discard anything, and issue a warning. Not ideal, but at least we don't
corrupt guest memory as the previous version could.
Warning reporting is kind of a compromise here. Determining whether we're
in a problematic state at realize() time is tricky, because we'd have to
look at the host pagesizes of all memory backends, but we can't really know
if some of those backends could be for special purpose memory that's not
subject to ballooning.
Reporting only when the guest tries to balloon a partial page also isn't
great because if the guest page size happens to line up it won't indicate
that we're in a non ideal situation. It could also cause alarming repeated
warnings whenever a migration is attempted.
So, what we do is warn the first time the guest attempts balloon a partial
host page, whether or not it will end up ballooning the rest of the page
immediately afterwards.
[1] Because when the guest attempts to balloon a page, it will submit
requests for each 4kiB subpage. Most will be ignored, but the one
which happens to be host page aligned will discard the whole lot.
Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
Message-Id: <20190214043916.22128-6-david@gibson.dropbear.id.au>
Reviewed-by: Michael S. Tsirkin <mst@redhat.com>
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
2019-02-14 07:39:16 +03:00
|
|
|
/* We've accumulated a full host page, we can actually discard
|
|
|
|
* it now */
|
|
|
|
|
2019-07-22 16:41:07 +03:00
|
|
|
ram_block_discard_range(rb, rb_aligned_offset, rb_page_size);
|
virtio-balloon: Safely handle BALLOON_PAGE_SIZE < host page size
The virtio-balloon always works in units of 4kiB (BALLOON_PAGE_SIZE), but
we can only actually discard memory in units of the host page size.
Now, we handle this very badly: we silently ignore balloon requests that
aren't host page aligned, and for requests that are host page aligned we
discard the entire host page. The latter can corrupt guest memory if its
page size is smaller than the host's.
The obvious choice would be to disable the balloon if the host page size is
not 4kiB. However, that would break the special case where host and guest
have the same page size, but that's larger than 4kiB. That case currently
works by accident[1] - and is used in practice on many production POWER
systems where 64kiB has long been the Linux default page size on both host
and guest.
To make the balloon safe, without breaking that useful special case, we
need to accumulate 4kiB balloon requests until we have a whole contiguous
host page to discard.
We could in principle do that across all guest memory, but it would require
a large bitmap to track. This patch represents a compromise: we track
ballooned subpages for a single contiguous host page at a time. This means
that if the guest discards all 4kiB chunks of a host page in succession,
we will discard it. This is the expected behaviour in the (host page) ==
(guest page) != 4kiB case we want to support.
If the guest scatters 4kiB requests across different host pages, we don't
discard anything, and issue a warning. Not ideal, but at least we don't
corrupt guest memory as the previous version could.
Warning reporting is kind of a compromise here. Determining whether we're
in a problematic state at realize() time is tricky, because we'd have to
look at the host pagesizes of all memory backends, but we can't really know
if some of those backends could be for special purpose memory that's not
subject to ballooning.
Reporting only when the guest tries to balloon a partial page also isn't
great because if the guest page size happens to line up it won't indicate
that we're in a non ideal situation. It could also cause alarming repeated
warnings whenever a migration is attempted.
So, what we do is warn the first time the guest attempts balloon a partial
host page, whether or not it will end up ballooning the rest of the page
immediately afterwards.
[1] Because when the guest attempts to balloon a page, it will submit
requests for each 4kiB subpage. Most will be ignored, but the one
which happens to be host page aligned will discard the whole lot.
Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
Message-Id: <20190214043916.22128-6-david@gibson.dropbear.id.au>
Reviewed-by: Michael S. Tsirkin <mst@redhat.com>
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
2019-02-14 07:39:16 +03:00
|
|
|
/* We ignore errors from ram_block_discard_range(), because it
|
|
|
|
* has already reported them, and failing to discard a balloon
|
|
|
|
* page is not fatal */
|
2019-07-25 14:54:25 +03:00
|
|
|
virtio_balloon_pbp_free(pbp);
|
virtio-balloon: Safely handle BALLOON_PAGE_SIZE < host page size
The virtio-balloon always works in units of 4kiB (BALLOON_PAGE_SIZE), but
we can only actually discard memory in units of the host page size.
Now, we handle this very badly: we silently ignore balloon requests that
aren't host page aligned, and for requests that are host page aligned we
discard the entire host page. The latter can corrupt guest memory if its
page size is smaller than the host's.
The obvious choice would be to disable the balloon if the host page size is
not 4kiB. However, that would break the special case where host and guest
have the same page size, but that's larger than 4kiB. That case currently
works by accident[1] - and is used in practice on many production POWER
systems where 64kiB has long been the Linux default page size on both host
and guest.
To make the balloon safe, without breaking that useful special case, we
need to accumulate 4kiB balloon requests until we have a whole contiguous
host page to discard.
We could in principle do that across all guest memory, but it would require
a large bitmap to track. This patch represents a compromise: we track
ballooned subpages for a single contiguous host page at a time. This means
that if the guest discards all 4kiB chunks of a host page in succession,
we will discard it. This is the expected behaviour in the (host page) ==
(guest page) != 4kiB case we want to support.
If the guest scatters 4kiB requests across different host pages, we don't
discard anything, and issue a warning. Not ideal, but at least we don't
corrupt guest memory as the previous version could.
Warning reporting is kind of a compromise here. Determining whether we're
in a problematic state at realize() time is tricky, because we'd have to
look at the host pagesizes of all memory backends, but we can't really know
if some of those backends could be for special purpose memory that's not
subject to ballooning.
Reporting only when the guest tries to balloon a partial page also isn't
great because if the guest page size happens to line up it won't indicate
that we're in a non ideal situation. It could also cause alarming repeated
warnings whenever a migration is attempted.
So, what we do is warn the first time the guest attempts balloon a partial
host page, whether or not it will end up ballooning the rest of the page
immediately afterwards.
[1] Because when the guest attempts to balloon a page, it will submit
requests for each 4kiB subpage. Most will be ignored, but the one
which happens to be host page aligned will discard the whole lot.
Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
Message-Id: <20190214043916.22128-6-david@gibson.dropbear.id.au>
Reviewed-by: Michael S. Tsirkin <mst@redhat.com>
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
2019-02-14 07:39:16 +03:00
|
|
|
}
|
2008-12-04 23:33:06 +03:00
|
|
|
}
|
|
|
|
|
2019-03-06 06:06:00 +03:00
|
|
|
static void balloon_deflate_page(VirtIOBalloon *balloon,
|
2019-07-22 16:41:06 +03:00
|
|
|
MemoryRegion *mr, hwaddr mr_offset)
|
2019-03-06 06:06:00 +03:00
|
|
|
{
|
2019-07-22 16:41:06 +03:00
|
|
|
void *addr = memory_region_get_ram_ptr(mr) + mr_offset;
|
|
|
|
ram_addr_t rb_offset;
|
2019-03-06 06:06:00 +03:00
|
|
|
RAMBlock *rb;
|
|
|
|
size_t rb_page_size;
|
2019-03-06 06:06:01 +03:00
|
|
|
void *host_addr;
|
|
|
|
int ret;
|
2019-03-06 06:06:00 +03:00
|
|
|
|
|
|
|
/* XXX is there a better way to get to the RAMBlock than via a
|
|
|
|
* host address? */
|
2019-07-22 16:41:06 +03:00
|
|
|
rb = qemu_ram_block_from_host(addr, false, &rb_offset);
|
2019-03-06 06:06:00 +03:00
|
|
|
rb_page_size = qemu_ram_pagesize(rb);
|
|
|
|
|
2019-03-06 06:06:01 +03:00
|
|
|
host_addr = (void *)((uintptr_t)addr & ~(rb_page_size - 1));
|
|
|
|
|
|
|
|
/* When a page is deflated, we hint the whole host page it lives
|
|
|
|
* on, since we can't do anything smaller */
|
|
|
|
ret = qemu_madvise(host_addr, rb_page_size, QEMU_MADV_WILLNEED);
|
|
|
|
if (ret != 0) {
|
|
|
|
warn_report("Couldn't MADV_WILLNEED on balloon deflate: %s",
|
|
|
|
strerror(errno));
|
|
|
|
/* Otherwise ignore, failing to page hint shouldn't be fatal */
|
|
|
|
}
|
2019-03-06 06:06:00 +03:00
|
|
|
}
|
|
|
|
|
balloon: re-enable balloon stats
The statistics are now available through device properties via a
polling mechanism. First a client has to enable polling, then it
can query available stats.
Polling is enabled by setting an update interval (in seconds)
to a property named guest-stats-polling-interval, like this:
{ "execute": "qom-set",
"arguments": { "path": "/machine/peripheral-anon/device[1]",
"property": "guest-stats-polling-interval", "value": 4 } }
Then the available stats can be retrieved by querying the
guest-stats property. The returned object is a dict containing
all available stats. Example:
{ "execute": "qom-get",
"arguments": { "path": "/machine/peripheral-anon/device[1]",
"property": "guest-stats" } }
{
"return": {
"stats": {
"stat-swap-out": 0,
"stat-free-memory": 844943360,
"stat-minor-faults": 219028,
"stat-major-faults": 235,
"stat-total-memory": 1044406272,
"stat-swap-in": 0
},
"last-update": 1358529861
}
}
Please, check the next commit for full documentation.
Signed-off-by: Luiz Capitulino <lcapitulino@redhat.com>
Reviewed-by: Eric Blake <eblake@redhat.com>
2012-12-01 06:14:57 +04:00
|
|
|
static const char *balloon_stat_names[] = {
|
|
|
|
[VIRTIO_BALLOON_S_SWAP_IN] = "stat-swap-in",
|
|
|
|
[VIRTIO_BALLOON_S_SWAP_OUT] = "stat-swap-out",
|
|
|
|
[VIRTIO_BALLOON_S_MAJFLT] = "stat-major-faults",
|
|
|
|
[VIRTIO_BALLOON_S_MINFLT] = "stat-minor-faults",
|
|
|
|
[VIRTIO_BALLOON_S_MEMFREE] = "stat-free-memory",
|
|
|
|
[VIRTIO_BALLOON_S_MEMTOT] = "stat-total-memory",
|
2016-02-24 10:50:48 +03:00
|
|
|
[VIRTIO_BALLOON_S_AVAIL] = "stat-available-memory",
|
2017-12-05 15:14:46 +03:00
|
|
|
[VIRTIO_BALLOON_S_CACHES] = "stat-disk-caches",
|
2018-03-20 01:28:49 +03:00
|
|
|
[VIRTIO_BALLOON_S_HTLB_PGALLOC] = "stat-htlb-pgalloc",
|
|
|
|
[VIRTIO_BALLOON_S_HTLB_PGFAIL] = "stat-htlb-pgfail",
|
balloon: re-enable balloon stats
The statistics are now available through device properties via a
polling mechanism. First a client has to enable polling, then it
can query available stats.
Polling is enabled by setting an update interval (in seconds)
to a property named guest-stats-polling-interval, like this:
{ "execute": "qom-set",
"arguments": { "path": "/machine/peripheral-anon/device[1]",
"property": "guest-stats-polling-interval", "value": 4 } }
Then the available stats can be retrieved by querying the
guest-stats property. The returned object is a dict containing
all available stats. Example:
{ "execute": "qom-get",
"arguments": { "path": "/machine/peripheral-anon/device[1]",
"property": "guest-stats" } }
{
"return": {
"stats": {
"stat-swap-out": 0,
"stat-free-memory": 844943360,
"stat-minor-faults": 219028,
"stat-major-faults": 235,
"stat-total-memory": 1044406272,
"stat-swap-in": 0
},
"last-update": 1358529861
}
}
Please, check the next commit for full documentation.
Signed-off-by: Luiz Capitulino <lcapitulino@redhat.com>
Reviewed-by: Eric Blake <eblake@redhat.com>
2012-12-01 06:14:57 +04:00
|
|
|
[VIRTIO_BALLOON_S_NR] = NULL
|
|
|
|
};
|
|
|
|
|
2010-01-26 23:17:35 +03:00
|
|
|
/*
|
|
|
|
* reset_stats - Mark all items in the stats array as unset
|
|
|
|
*
|
2013-07-24 21:48:56 +04:00
|
|
|
* This function needs to be called at device initialization and before
|
|
|
|
* updating to a set of newly-generated stats. This will ensure that no
|
2010-01-26 23:17:35 +03:00
|
|
|
* stale values stick around in case the guest reports a subset of the supported
|
|
|
|
* statistics.
|
|
|
|
*/
|
|
|
|
static inline void reset_stats(VirtIOBalloon *dev)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
for (i = 0; i < VIRTIO_BALLOON_S_NR; dev->stats[i++] = -1);
|
|
|
|
}
|
|
|
|
|
balloon: re-enable balloon stats
The statistics are now available through device properties via a
polling mechanism. First a client has to enable polling, then it
can query available stats.
Polling is enabled by setting an update interval (in seconds)
to a property named guest-stats-polling-interval, like this:
{ "execute": "qom-set",
"arguments": { "path": "/machine/peripheral-anon/device[1]",
"property": "guest-stats-polling-interval", "value": 4 } }
Then the available stats can be retrieved by querying the
guest-stats property. The returned object is a dict containing
all available stats. Example:
{ "execute": "qom-get",
"arguments": { "path": "/machine/peripheral-anon/device[1]",
"property": "guest-stats" } }
{
"return": {
"stats": {
"stat-swap-out": 0,
"stat-free-memory": 844943360,
"stat-minor-faults": 219028,
"stat-major-faults": 235,
"stat-total-memory": 1044406272,
"stat-swap-in": 0
},
"last-update": 1358529861
}
}
Please, check the next commit for full documentation.
Signed-off-by: Luiz Capitulino <lcapitulino@redhat.com>
Reviewed-by: Eric Blake <eblake@redhat.com>
2012-12-01 06:14:57 +04:00
|
|
|
static bool balloon_stats_supported(const VirtIOBalloon *s)
|
|
|
|
{
|
2013-03-27 13:49:14 +04:00
|
|
|
VirtIODevice *vdev = VIRTIO_DEVICE(s);
|
2015-08-17 12:48:29 +03:00
|
|
|
return virtio_vdev_has_feature(vdev, VIRTIO_BALLOON_F_STATS_VQ);
|
balloon: re-enable balloon stats
The statistics are now available through device properties via a
polling mechanism. First a client has to enable polling, then it
can query available stats.
Polling is enabled by setting an update interval (in seconds)
to a property named guest-stats-polling-interval, like this:
{ "execute": "qom-set",
"arguments": { "path": "/machine/peripheral-anon/device[1]",
"property": "guest-stats-polling-interval", "value": 4 } }
Then the available stats can be retrieved by querying the
guest-stats property. The returned object is a dict containing
all available stats. Example:
{ "execute": "qom-get",
"arguments": { "path": "/machine/peripheral-anon/device[1]",
"property": "guest-stats" } }
{
"return": {
"stats": {
"stat-swap-out": 0,
"stat-free-memory": 844943360,
"stat-minor-faults": 219028,
"stat-major-faults": 235,
"stat-total-memory": 1044406272,
"stat-swap-in": 0
},
"last-update": 1358529861
}
}
Please, check the next commit for full documentation.
Signed-off-by: Luiz Capitulino <lcapitulino@redhat.com>
Reviewed-by: Eric Blake <eblake@redhat.com>
2012-12-01 06:14:57 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
static bool balloon_stats_enabled(const VirtIOBalloon *s)
|
|
|
|
{
|
|
|
|
return s->stats_poll_interval > 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void balloon_stats_destroy_timer(VirtIOBalloon *s)
|
|
|
|
{
|
|
|
|
if (balloon_stats_enabled(s)) {
|
2013-08-21 19:03:08 +04:00
|
|
|
timer_del(s->stats_timer);
|
|
|
|
timer_free(s->stats_timer);
|
balloon: re-enable balloon stats
The statistics are now available through device properties via a
polling mechanism. First a client has to enable polling, then it
can query available stats.
Polling is enabled by setting an update interval (in seconds)
to a property named guest-stats-polling-interval, like this:
{ "execute": "qom-set",
"arguments": { "path": "/machine/peripheral-anon/device[1]",
"property": "guest-stats-polling-interval", "value": 4 } }
Then the available stats can be retrieved by querying the
guest-stats property. The returned object is a dict containing
all available stats. Example:
{ "execute": "qom-get",
"arguments": { "path": "/machine/peripheral-anon/device[1]",
"property": "guest-stats" } }
{
"return": {
"stats": {
"stat-swap-out": 0,
"stat-free-memory": 844943360,
"stat-minor-faults": 219028,
"stat-major-faults": 235,
"stat-total-memory": 1044406272,
"stat-swap-in": 0
},
"last-update": 1358529861
}
}
Please, check the next commit for full documentation.
Signed-off-by: Luiz Capitulino <lcapitulino@redhat.com>
Reviewed-by: Eric Blake <eblake@redhat.com>
2012-12-01 06:14:57 +04:00
|
|
|
s->stats_timer = NULL;
|
|
|
|
s->stats_poll_interval = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-09-15 20:00:11 +04:00
|
|
|
static void balloon_stats_change_timer(VirtIOBalloon *s, int64_t secs)
|
balloon: re-enable balloon stats
The statistics are now available through device properties via a
polling mechanism. First a client has to enable polling, then it
can query available stats.
Polling is enabled by setting an update interval (in seconds)
to a property named guest-stats-polling-interval, like this:
{ "execute": "qom-set",
"arguments": { "path": "/machine/peripheral-anon/device[1]",
"property": "guest-stats-polling-interval", "value": 4 } }
Then the available stats can be retrieved by querying the
guest-stats property. The returned object is a dict containing
all available stats. Example:
{ "execute": "qom-get",
"arguments": { "path": "/machine/peripheral-anon/device[1]",
"property": "guest-stats" } }
{
"return": {
"stats": {
"stat-swap-out": 0,
"stat-free-memory": 844943360,
"stat-minor-faults": 219028,
"stat-major-faults": 235,
"stat-total-memory": 1044406272,
"stat-swap-in": 0
},
"last-update": 1358529861
}
}
Please, check the next commit for full documentation.
Signed-off-by: Luiz Capitulino <lcapitulino@redhat.com>
Reviewed-by: Eric Blake <eblake@redhat.com>
2012-12-01 06:14:57 +04:00
|
|
|
{
|
2013-08-21 19:03:08 +04:00
|
|
|
timer_mod(s->stats_timer, qemu_clock_get_ms(QEMU_CLOCK_VIRTUAL) + secs * 1000);
|
balloon: re-enable balloon stats
The statistics are now available through device properties via a
polling mechanism. First a client has to enable polling, then it
can query available stats.
Polling is enabled by setting an update interval (in seconds)
to a property named guest-stats-polling-interval, like this:
{ "execute": "qom-set",
"arguments": { "path": "/machine/peripheral-anon/device[1]",
"property": "guest-stats-polling-interval", "value": 4 } }
Then the available stats can be retrieved by querying the
guest-stats property. The returned object is a dict containing
all available stats. Example:
{ "execute": "qom-get",
"arguments": { "path": "/machine/peripheral-anon/device[1]",
"property": "guest-stats" } }
{
"return": {
"stats": {
"stat-swap-out": 0,
"stat-free-memory": 844943360,
"stat-minor-faults": 219028,
"stat-major-faults": 235,
"stat-total-memory": 1044406272,
"stat-swap-in": 0
},
"last-update": 1358529861
}
}
Please, check the next commit for full documentation.
Signed-off-by: Luiz Capitulino <lcapitulino@redhat.com>
Reviewed-by: Eric Blake <eblake@redhat.com>
2012-12-01 06:14:57 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
static void balloon_stats_poll_cb(void *opaque)
|
|
|
|
{
|
|
|
|
VirtIOBalloon *s = opaque;
|
2013-03-27 13:49:14 +04:00
|
|
|
VirtIODevice *vdev = VIRTIO_DEVICE(s);
|
balloon: re-enable balloon stats
The statistics are now available through device properties via a
polling mechanism. First a client has to enable polling, then it
can query available stats.
Polling is enabled by setting an update interval (in seconds)
to a property named guest-stats-polling-interval, like this:
{ "execute": "qom-set",
"arguments": { "path": "/machine/peripheral-anon/device[1]",
"property": "guest-stats-polling-interval", "value": 4 } }
Then the available stats can be retrieved by querying the
guest-stats property. The returned object is a dict containing
all available stats. Example:
{ "execute": "qom-get",
"arguments": { "path": "/machine/peripheral-anon/device[1]",
"property": "guest-stats" } }
{
"return": {
"stats": {
"stat-swap-out": 0,
"stat-free-memory": 844943360,
"stat-minor-faults": 219028,
"stat-major-faults": 235,
"stat-total-memory": 1044406272,
"stat-swap-in": 0
},
"last-update": 1358529861
}
}
Please, check the next commit for full documentation.
Signed-off-by: Luiz Capitulino <lcapitulino@redhat.com>
Reviewed-by: Eric Blake <eblake@redhat.com>
2012-12-01 06:14:57 +04:00
|
|
|
|
2016-03-01 14:14:03 +03:00
|
|
|
if (s->stats_vq_elem == NULL || !balloon_stats_supported(s)) {
|
balloon: re-enable balloon stats
The statistics are now available through device properties via a
polling mechanism. First a client has to enable polling, then it
can query available stats.
Polling is enabled by setting an update interval (in seconds)
to a property named guest-stats-polling-interval, like this:
{ "execute": "qom-set",
"arguments": { "path": "/machine/peripheral-anon/device[1]",
"property": "guest-stats-polling-interval", "value": 4 } }
Then the available stats can be retrieved by querying the
guest-stats property. The returned object is a dict containing
all available stats. Example:
{ "execute": "qom-get",
"arguments": { "path": "/machine/peripheral-anon/device[1]",
"property": "guest-stats" } }
{
"return": {
"stats": {
"stat-swap-out": 0,
"stat-free-memory": 844943360,
"stat-minor-faults": 219028,
"stat-major-faults": 235,
"stat-total-memory": 1044406272,
"stat-swap-in": 0
},
"last-update": 1358529861
}
}
Please, check the next commit for full documentation.
Signed-off-by: Luiz Capitulino <lcapitulino@redhat.com>
Reviewed-by: Eric Blake <eblake@redhat.com>
2012-12-01 06:14:57 +04:00
|
|
|
/* re-schedule */
|
|
|
|
balloon_stats_change_timer(s, s->stats_poll_interval);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2016-02-04 17:26:51 +03:00
|
|
|
virtqueue_push(s->svq, s->stats_vq_elem, s->stats_vq_offset);
|
2013-03-27 13:49:14 +04:00
|
|
|
virtio_notify(vdev, s->svq);
|
2016-02-04 17:26:51 +03:00
|
|
|
g_free(s->stats_vq_elem);
|
|
|
|
s->stats_vq_elem = NULL;
|
balloon: re-enable balloon stats
The statistics are now available through device properties via a
polling mechanism. First a client has to enable polling, then it
can query available stats.
Polling is enabled by setting an update interval (in seconds)
to a property named guest-stats-polling-interval, like this:
{ "execute": "qom-set",
"arguments": { "path": "/machine/peripheral-anon/device[1]",
"property": "guest-stats-polling-interval", "value": 4 } }
Then the available stats can be retrieved by querying the
guest-stats property. The returned object is a dict containing
all available stats. Example:
{ "execute": "qom-get",
"arguments": { "path": "/machine/peripheral-anon/device[1]",
"property": "guest-stats" } }
{
"return": {
"stats": {
"stat-swap-out": 0,
"stat-free-memory": 844943360,
"stat-minor-faults": 219028,
"stat-major-faults": 235,
"stat-total-memory": 1044406272,
"stat-swap-in": 0
},
"last-update": 1358529861
}
}
Please, check the next commit for full documentation.
Signed-off-by: Luiz Capitulino <lcapitulino@redhat.com>
Reviewed-by: Eric Blake <eblake@redhat.com>
2012-12-01 06:14:57 +04:00
|
|
|
}
|
|
|
|
|
qom: Swap 'name' next to visitor in ObjectPropertyAccessor
Similar to the previous patch, it's nice to have all functions
in the tree that involve a visitor and a name for conversion to
or from QAPI to consistently stick the 'name' parameter next
to the Visitor parameter.
Done by manually changing include/qom/object.h and qom/object.c,
then running this Coccinelle script and touching up the fallout
(Coccinelle insisted on adding some trailing whitespace).
@ rule1 @
identifier fn;
typedef Object, Visitor, Error;
identifier obj, v, opaque, name, errp;
@@
void fn
- (Object *obj, Visitor *v, void *opaque, const char *name,
+ (Object *obj, Visitor *v, const char *name, void *opaque,
Error **errp) { ... }
@@
identifier rule1.fn;
expression obj, v, opaque, name, errp;
@@
fn(obj, v,
- opaque, name,
+ name, opaque,
errp)
Signed-off-by: Eric Blake <eblake@redhat.com>
Reviewed-by: Marc-André Lureau <marcandre.lureau@redhat.com>
Message-Id: <1454075341-13658-20-git-send-email-eblake@redhat.com>
Signed-off-by: Markus Armbruster <armbru@redhat.com>
2016-01-29 16:48:55 +03:00
|
|
|
static void balloon_stats_get_all(Object *obj, Visitor *v, const char *name,
|
|
|
|
void *opaque, Error **errp)
|
balloon: re-enable balloon stats
The statistics are now available through device properties via a
polling mechanism. First a client has to enable polling, then it
can query available stats.
Polling is enabled by setting an update interval (in seconds)
to a property named guest-stats-polling-interval, like this:
{ "execute": "qom-set",
"arguments": { "path": "/machine/peripheral-anon/device[1]",
"property": "guest-stats-polling-interval", "value": 4 } }
Then the available stats can be retrieved by querying the
guest-stats property. The returned object is a dict containing
all available stats. Example:
{ "execute": "qom-get",
"arguments": { "path": "/machine/peripheral-anon/device[1]",
"property": "guest-stats" } }
{
"return": {
"stats": {
"stat-swap-out": 0,
"stat-free-memory": 844943360,
"stat-minor-faults": 219028,
"stat-major-faults": 235,
"stat-total-memory": 1044406272,
"stat-swap-in": 0
},
"last-update": 1358529861
}
}
Please, check the next commit for full documentation.
Signed-off-by: Luiz Capitulino <lcapitulino@redhat.com>
Reviewed-by: Eric Blake <eblake@redhat.com>
2012-12-01 06:14:57 +04:00
|
|
|
{
|
2014-05-07 11:53:52 +04:00
|
|
|
Error *err = NULL;
|
balloon: re-enable balloon stats
The statistics are now available through device properties via a
polling mechanism. First a client has to enable polling, then it
can query available stats.
Polling is enabled by setting an update interval (in seconds)
to a property named guest-stats-polling-interval, like this:
{ "execute": "qom-set",
"arguments": { "path": "/machine/peripheral-anon/device[1]",
"property": "guest-stats-polling-interval", "value": 4 } }
Then the available stats can be retrieved by querying the
guest-stats property. The returned object is a dict containing
all available stats. Example:
{ "execute": "qom-get",
"arguments": { "path": "/machine/peripheral-anon/device[1]",
"property": "guest-stats" } }
{
"return": {
"stats": {
"stat-swap-out": 0,
"stat-free-memory": 844943360,
"stat-minor-faults": 219028,
"stat-major-faults": 235,
"stat-total-memory": 1044406272,
"stat-swap-in": 0
},
"last-update": 1358529861
}
}
Please, check the next commit for full documentation.
Signed-off-by: Luiz Capitulino <lcapitulino@redhat.com>
Reviewed-by: Eric Blake <eblake@redhat.com>
2012-12-01 06:14:57 +04:00
|
|
|
VirtIOBalloon *s = opaque;
|
|
|
|
int i;
|
|
|
|
|
2016-01-29 16:48:57 +03:00
|
|
|
visit_start_struct(v, name, NULL, 0, &err);
|
2014-05-07 11:53:52 +04:00
|
|
|
if (err) {
|
|
|
|
goto out;
|
|
|
|
}
|
qapi: Swap visit_* arguments for consistent 'name' placement
JSON uses "name":value, but many of our visitor interfaces were
called with visit_type_FOO(v, &value, name, errp). This can be
a bit confusing to have to mentally swap the parameter order to
match JSON order. It's particularly bad for visit_start_struct(),
where the 'name' parameter is smack in the middle of the
otherwise-related group of 'obj, kind, size' parameters! It's
time to do a global swap of the parameter ordering, so that the
'name' parameter is always immediately after the Visitor argument.
Additional reason in favor of the swap: the existing include/qjson.h
prefers listing 'name' first in json_prop_*(), and I have plans to
unify that file with the qapi visitors; listing 'name' first in
qapi will minimize churn to the (admittedly few) qjson.h clients.
Later patches will then fix docs, object.h, visitor-impl.h, and
those clients to match.
Done by first patching scripts/qapi*.py by hand to make generated
files do what I want, then by running the following Coccinelle
script to affect the rest of the code base:
$ spatch --sp-file script `git grep -l '\bvisit_' -- '**/*.[ch]'`
I then had to apply some touchups (Coccinelle insisted on TAB
indentation in visitor.h, and botched the signature of
visit_type_enum() by rewriting 'const char *const strings[]' to
the syntactically invalid 'const char*const[] strings'). The
movement of parameters is sufficient to provoke compiler errors
if any callers were missed.
// Part 1: Swap declaration order
@@
type TV, TErr, TObj, T1, T2;
identifier OBJ, ARG1, ARG2;
@@
void visit_start_struct
-(TV v, TObj OBJ, T1 ARG1, const char *name, T2 ARG2, TErr errp)
+(TV v, const char *name, TObj OBJ, T1 ARG1, T2 ARG2, TErr errp)
{ ... }
@@
type bool, TV, T1;
identifier ARG1;
@@
bool visit_optional
-(TV v, T1 ARG1, const char *name)
+(TV v, const char *name, T1 ARG1)
{ ... }
@@
type TV, TErr, TObj, T1;
identifier OBJ, ARG1;
@@
void visit_get_next_type
-(TV v, TObj OBJ, T1 ARG1, const char *name, TErr errp)
+(TV v, const char *name, TObj OBJ, T1 ARG1, TErr errp)
{ ... }
@@
type TV, TErr, TObj, T1, T2;
identifier OBJ, ARG1, ARG2;
@@
void visit_type_enum
-(TV v, TObj OBJ, T1 ARG1, T2 ARG2, const char *name, TErr errp)
+(TV v, const char *name, TObj OBJ, T1 ARG1, T2 ARG2, TErr errp)
{ ... }
@@
type TV, TErr, TObj;
identifier OBJ;
identifier VISIT_TYPE =~ "^visit_type_";
@@
void VISIT_TYPE
-(TV v, TObj OBJ, const char *name, TErr errp)
+(TV v, const char *name, TObj OBJ, TErr errp)
{ ... }
// Part 2: swap caller order
@@
expression V, NAME, OBJ, ARG1, ARG2, ERR;
identifier VISIT_TYPE =~ "^visit_type_";
@@
(
-visit_start_struct(V, OBJ, ARG1, NAME, ARG2, ERR)
+visit_start_struct(V, NAME, OBJ, ARG1, ARG2, ERR)
|
-visit_optional(V, ARG1, NAME)
+visit_optional(V, NAME, ARG1)
|
-visit_get_next_type(V, OBJ, ARG1, NAME, ERR)
+visit_get_next_type(V, NAME, OBJ, ARG1, ERR)
|
-visit_type_enum(V, OBJ, ARG1, ARG2, NAME, ERR)
+visit_type_enum(V, NAME, OBJ, ARG1, ARG2, ERR)
|
-VISIT_TYPE(V, OBJ, NAME, ERR)
+VISIT_TYPE(V, NAME, OBJ, ERR)
)
Signed-off-by: Eric Blake <eblake@redhat.com>
Reviewed-by: Marc-André Lureau <marcandre.lureau@redhat.com>
Message-Id: <1454075341-13658-19-git-send-email-eblake@redhat.com>
Signed-off-by: Markus Armbruster <armbru@redhat.com>
2016-01-29 16:48:54 +03:00
|
|
|
visit_type_int(v, "last-update", &s->stats_last_update, &err);
|
qapi: Replace uncommon use of the error API by the common one
We commonly use the error API like this:
err = NULL;
foo(..., &err);
if (err) {
goto out;
}
bar(..., &err);
Every error source is checked separately. The second function is only
called when the first one succeeds. Both functions are free to pass
their argument to error_set(). Because error_set() asserts no error
has been set, this effectively means they must not be called with an
error set.
The qapi-generated code uses the error API differently:
// *errp was initialized to NULL somewhere up the call chain
frob(..., errp);
gnat(..., errp);
Errors accumulate in *errp: first error wins, subsequent errors get
dropped. To make this work, the second function does nothing when
called with an error set. Requires non-null errp, or else the second
function can't see the first one fail.
This usage has also bled into visitor tests, and two device model
object property getters rtc_get_date() and balloon_stats_get_all().
With the "accumulate" technique, you need fewer error checks in
callers, and buy that with an error check in every callee. Can be
nice.
However, mixing the two techniques is confusing. You can't use the
"accumulate" technique with functions designed for the "check
separately" technique. You can use the "check separately" technique
with functions designed for the "accumulate" technique, but then
error_set() can't catch you setting an error more than once.
Standardize on the "check separately" technique for now, because it's
overwhelmingly prevalent.
Signed-off-by: Markus Armbruster <armbru@redhat.com>
Reviewed-by: Eric Blake <eblake@redhat.com>
Signed-off-by: Luiz Capitulino <lcapitulino@redhat.com>
2014-05-07 11:53:54 +04:00
|
|
|
if (err) {
|
|
|
|
goto out_end;
|
|
|
|
}
|
balloon: re-enable balloon stats
The statistics are now available through device properties via a
polling mechanism. First a client has to enable polling, then it
can query available stats.
Polling is enabled by setting an update interval (in seconds)
to a property named guest-stats-polling-interval, like this:
{ "execute": "qom-set",
"arguments": { "path": "/machine/peripheral-anon/device[1]",
"property": "guest-stats-polling-interval", "value": 4 } }
Then the available stats can be retrieved by querying the
guest-stats property. The returned object is a dict containing
all available stats. Example:
{ "execute": "qom-get",
"arguments": { "path": "/machine/peripheral-anon/device[1]",
"property": "guest-stats" } }
{
"return": {
"stats": {
"stat-swap-out": 0,
"stat-free-memory": 844943360,
"stat-minor-faults": 219028,
"stat-major-faults": 235,
"stat-total-memory": 1044406272,
"stat-swap-in": 0
},
"last-update": 1358529861
}
}
Please, check the next commit for full documentation.
Signed-off-by: Luiz Capitulino <lcapitulino@redhat.com>
Reviewed-by: Eric Blake <eblake@redhat.com>
2012-12-01 06:14:57 +04:00
|
|
|
|
2016-01-29 16:48:57 +03:00
|
|
|
visit_start_struct(v, "stats", NULL, 0, &err);
|
2014-05-07 11:53:52 +04:00
|
|
|
if (err) {
|
|
|
|
goto out_end;
|
|
|
|
}
|
2016-01-29 16:48:45 +03:00
|
|
|
for (i = 0; i < VIRTIO_BALLOON_S_NR; i++) {
|
qapi: Swap visit_* arguments for consistent 'name' placement
JSON uses "name":value, but many of our visitor interfaces were
called with visit_type_FOO(v, &value, name, errp). This can be
a bit confusing to have to mentally swap the parameter order to
match JSON order. It's particularly bad for visit_start_struct(),
where the 'name' parameter is smack in the middle of the
otherwise-related group of 'obj, kind, size' parameters! It's
time to do a global swap of the parameter ordering, so that the
'name' parameter is always immediately after the Visitor argument.
Additional reason in favor of the swap: the existing include/qjson.h
prefers listing 'name' first in json_prop_*(), and I have plans to
unify that file with the qapi visitors; listing 'name' first in
qapi will minimize churn to the (admittedly few) qjson.h clients.
Later patches will then fix docs, object.h, visitor-impl.h, and
those clients to match.
Done by first patching scripts/qapi*.py by hand to make generated
files do what I want, then by running the following Coccinelle
script to affect the rest of the code base:
$ spatch --sp-file script `git grep -l '\bvisit_' -- '**/*.[ch]'`
I then had to apply some touchups (Coccinelle insisted on TAB
indentation in visitor.h, and botched the signature of
visit_type_enum() by rewriting 'const char *const strings[]' to
the syntactically invalid 'const char*const[] strings'). The
movement of parameters is sufficient to provoke compiler errors
if any callers were missed.
// Part 1: Swap declaration order
@@
type TV, TErr, TObj, T1, T2;
identifier OBJ, ARG1, ARG2;
@@
void visit_start_struct
-(TV v, TObj OBJ, T1 ARG1, const char *name, T2 ARG2, TErr errp)
+(TV v, const char *name, TObj OBJ, T1 ARG1, T2 ARG2, TErr errp)
{ ... }
@@
type bool, TV, T1;
identifier ARG1;
@@
bool visit_optional
-(TV v, T1 ARG1, const char *name)
+(TV v, const char *name, T1 ARG1)
{ ... }
@@
type TV, TErr, TObj, T1;
identifier OBJ, ARG1;
@@
void visit_get_next_type
-(TV v, TObj OBJ, T1 ARG1, const char *name, TErr errp)
+(TV v, const char *name, TObj OBJ, T1 ARG1, TErr errp)
{ ... }
@@
type TV, TErr, TObj, T1, T2;
identifier OBJ, ARG1, ARG2;
@@
void visit_type_enum
-(TV v, TObj OBJ, T1 ARG1, T2 ARG2, const char *name, TErr errp)
+(TV v, const char *name, TObj OBJ, T1 ARG1, T2 ARG2, TErr errp)
{ ... }
@@
type TV, TErr, TObj;
identifier OBJ;
identifier VISIT_TYPE =~ "^visit_type_";
@@
void VISIT_TYPE
-(TV v, TObj OBJ, const char *name, TErr errp)
+(TV v, const char *name, TObj OBJ, TErr errp)
{ ... }
// Part 2: swap caller order
@@
expression V, NAME, OBJ, ARG1, ARG2, ERR;
identifier VISIT_TYPE =~ "^visit_type_";
@@
(
-visit_start_struct(V, OBJ, ARG1, NAME, ARG2, ERR)
+visit_start_struct(V, NAME, OBJ, ARG1, ARG2, ERR)
|
-visit_optional(V, ARG1, NAME)
+visit_optional(V, NAME, ARG1)
|
-visit_get_next_type(V, OBJ, ARG1, NAME, ERR)
+visit_get_next_type(V, NAME, OBJ, ARG1, ERR)
|
-visit_type_enum(V, OBJ, ARG1, ARG2, NAME, ERR)
+visit_type_enum(V, NAME, OBJ, ARG1, ARG2, ERR)
|
-VISIT_TYPE(V, OBJ, NAME, ERR)
+VISIT_TYPE(V, NAME, OBJ, ERR)
)
Signed-off-by: Eric Blake <eblake@redhat.com>
Reviewed-by: Marc-André Lureau <marcandre.lureau@redhat.com>
Message-Id: <1454075341-13658-19-git-send-email-eblake@redhat.com>
Signed-off-by: Markus Armbruster <armbru@redhat.com>
2016-01-29 16:48:54 +03:00
|
|
|
visit_type_uint64(v, balloon_stat_names[i], &s->stats[i], &err);
|
2016-01-29 16:48:45 +03:00
|
|
|
if (err) {
|
qapi: Split visit_end_struct() into pieces
As mentioned in previous patches, we want to call visit_end_struct()
functions unconditionally, so that visitors can release resources
tied up since the matching visit_start_struct() without also having
to worry about error priority if more than one error occurs.
Even though error_propagate() can be safely used to ignore a second
error during cleanup caused by a first error, it is simpler if the
cleanup cannot set an error. So, split out the error checking
portion (basically, input visitors checking for unvisited keys) into
a new function visit_check_struct(), which can be safely skipped if
any earlier errors are encountered, and leave the cleanup portion
(which never fails, but must be called unconditionally if
visit_start_struct() succeeded) in visit_end_struct().
Generated code in qapi-visit.c has diffs resembling:
|@@ -59,10 +59,12 @@ void visit_type_ACPIOSTInfo(Visitor *v,
| goto out_obj;
| }
| visit_type_ACPIOSTInfo_members(v, obj, &err);
|- error_propagate(errp, err);
|- err = NULL;
|+ if (err) {
|+ goto out_obj;
|+ }
|+ visit_check_struct(v, &err);
| out_obj:
|- visit_end_struct(v, &err);
|+ visit_end_struct(v);
| out:
and in qapi-event.c:
@@ -47,7 +47,10 @@ void qapi_event_send_acpi_device_ost(ACP
| goto out;
| }
| visit_type_q_obj_ACPI_DEVICE_OST_arg_members(v, ¶m, &err);
|- visit_end_struct(v, err ? NULL : &err);
|+ if (!err) {
|+ visit_check_struct(v, &err);
|+ }
|+ visit_end_struct(v);
| if (err) {
| goto out;
Signed-off-by: Eric Blake <eblake@redhat.com>
Message-Id: <1461879932-9020-20-git-send-email-eblake@redhat.com>
[Conflict with a doc fixup resolved]
Signed-off-by: Markus Armbruster <armbru@redhat.com>
2016-04-29 00:45:27 +03:00
|
|
|
goto out_nested;
|
2016-01-29 16:48:45 +03:00
|
|
|
}
|
balloon: re-enable balloon stats
The statistics are now available through device properties via a
polling mechanism. First a client has to enable polling, then it
can query available stats.
Polling is enabled by setting an update interval (in seconds)
to a property named guest-stats-polling-interval, like this:
{ "execute": "qom-set",
"arguments": { "path": "/machine/peripheral-anon/device[1]",
"property": "guest-stats-polling-interval", "value": 4 } }
Then the available stats can be retrieved by querying the
guest-stats property. The returned object is a dict containing
all available stats. Example:
{ "execute": "qom-get",
"arguments": { "path": "/machine/peripheral-anon/device[1]",
"property": "guest-stats" } }
{
"return": {
"stats": {
"stat-swap-out": 0,
"stat-free-memory": 844943360,
"stat-minor-faults": 219028,
"stat-major-faults": 235,
"stat-total-memory": 1044406272,
"stat-swap-in": 0
},
"last-update": 1358529861
}
}
Please, check the next commit for full documentation.
Signed-off-by: Luiz Capitulino <lcapitulino@redhat.com>
Reviewed-by: Eric Blake <eblake@redhat.com>
2012-12-01 06:14:57 +04:00
|
|
|
}
|
qapi: Split visit_end_struct() into pieces
As mentioned in previous patches, we want to call visit_end_struct()
functions unconditionally, so that visitors can release resources
tied up since the matching visit_start_struct() without also having
to worry about error priority if more than one error occurs.
Even though error_propagate() can be safely used to ignore a second
error during cleanup caused by a first error, it is simpler if the
cleanup cannot set an error. So, split out the error checking
portion (basically, input visitors checking for unvisited keys) into
a new function visit_check_struct(), which can be safely skipped if
any earlier errors are encountered, and leave the cleanup portion
(which never fails, but must be called unconditionally if
visit_start_struct() succeeded) in visit_end_struct().
Generated code in qapi-visit.c has diffs resembling:
|@@ -59,10 +59,12 @@ void visit_type_ACPIOSTInfo(Visitor *v,
| goto out_obj;
| }
| visit_type_ACPIOSTInfo_members(v, obj, &err);
|- error_propagate(errp, err);
|- err = NULL;
|+ if (err) {
|+ goto out_obj;
|+ }
|+ visit_check_struct(v, &err);
| out_obj:
|- visit_end_struct(v, &err);
|+ visit_end_struct(v);
| out:
and in qapi-event.c:
@@ -47,7 +47,10 @@ void qapi_event_send_acpi_device_ost(ACP
| goto out;
| }
| visit_type_q_obj_ACPI_DEVICE_OST_arg_members(v, ¶m, &err);
|- visit_end_struct(v, err ? NULL : &err);
|+ if (!err) {
|+ visit_check_struct(v, &err);
|+ }
|+ visit_end_struct(v);
| if (err) {
| goto out;
Signed-off-by: Eric Blake <eblake@redhat.com>
Message-Id: <1461879932-9020-20-git-send-email-eblake@redhat.com>
[Conflict with a doc fixup resolved]
Signed-off-by: Markus Armbruster <armbru@redhat.com>
2016-04-29 00:45:27 +03:00
|
|
|
visit_check_struct(v, &err);
|
|
|
|
out_nested:
|
qapi: Add parameter to visit_end_*
Rather than making the dealloc visitor track of stack of pointers
remembered during visit_start_* in order to free them during
visit_end_*, it's a lot easier to just make all callers pass the
same pointer to visit_end_*. The generated code has access to the
same pointer, while all other users are doing virtual walks and
can pass NULL. The dealloc visitor is then greatly simplified.
All three visit_end_*() functions intentionally take a void**,
even though the visit_start_*() functions differ between void**,
GenericList**, and GenericAlternate**. This is done for several
reasons: when doing a virtual walk, passing NULL doesn't care
what the type is, but when doing a generated walk, we already
have to cast the caller's specific FOO* to call visit_start,
while using void** lets us use visit_end without a cast. Also,
an upcoming patch will add a clone visitor that wants to use
the same implementation for all three visit_end callbacks,
which is made easier if all three share the same signature.
For visitors with already track per-object state (the QMP visitors
via a stack, and the string visitors which do not allow nesting),
add an assertion that the caller is indeed passing the same
pointer to paired calls.
Signed-off-by: Eric Blake <eblake@redhat.com>
Message-Id: <1465490926-28625-4-git-send-email-eblake@redhat.com>
Reviewed-by: Markus Armbruster <armbru@redhat.com>
Signed-off-by: Markus Armbruster <armbru@redhat.com>
2016-06-09 19:48:34 +03:00
|
|
|
visit_end_struct(v, NULL);
|
2014-05-07 11:53:52 +04:00
|
|
|
|
qapi: Split visit_end_struct() into pieces
As mentioned in previous patches, we want to call visit_end_struct()
functions unconditionally, so that visitors can release resources
tied up since the matching visit_start_struct() without also having
to worry about error priority if more than one error occurs.
Even though error_propagate() can be safely used to ignore a second
error during cleanup caused by a first error, it is simpler if the
cleanup cannot set an error. So, split out the error checking
portion (basically, input visitors checking for unvisited keys) into
a new function visit_check_struct(), which can be safely skipped if
any earlier errors are encountered, and leave the cleanup portion
(which never fails, but must be called unconditionally if
visit_start_struct() succeeded) in visit_end_struct().
Generated code in qapi-visit.c has diffs resembling:
|@@ -59,10 +59,12 @@ void visit_type_ACPIOSTInfo(Visitor *v,
| goto out_obj;
| }
| visit_type_ACPIOSTInfo_members(v, obj, &err);
|- error_propagate(errp, err);
|- err = NULL;
|+ if (err) {
|+ goto out_obj;
|+ }
|+ visit_check_struct(v, &err);
| out_obj:
|- visit_end_struct(v, &err);
|+ visit_end_struct(v);
| out:
and in qapi-event.c:
@@ -47,7 +47,10 @@ void qapi_event_send_acpi_device_ost(ACP
| goto out;
| }
| visit_type_q_obj_ACPI_DEVICE_OST_arg_members(v, ¶m, &err);
|- visit_end_struct(v, err ? NULL : &err);
|+ if (!err) {
|+ visit_check_struct(v, &err);
|+ }
|+ visit_end_struct(v);
| if (err) {
| goto out;
Signed-off-by: Eric Blake <eblake@redhat.com>
Message-Id: <1461879932-9020-20-git-send-email-eblake@redhat.com>
[Conflict with a doc fixup resolved]
Signed-off-by: Markus Armbruster <armbru@redhat.com>
2016-04-29 00:45:27 +03:00
|
|
|
if (!err) {
|
|
|
|
visit_check_struct(v, &err);
|
|
|
|
}
|
2014-05-07 11:53:52 +04:00
|
|
|
out_end:
|
qapi: Add parameter to visit_end_*
Rather than making the dealloc visitor track of stack of pointers
remembered during visit_start_* in order to free them during
visit_end_*, it's a lot easier to just make all callers pass the
same pointer to visit_end_*. The generated code has access to the
same pointer, while all other users are doing virtual walks and
can pass NULL. The dealloc visitor is then greatly simplified.
All three visit_end_*() functions intentionally take a void**,
even though the visit_start_*() functions differ between void**,
GenericList**, and GenericAlternate**. This is done for several
reasons: when doing a virtual walk, passing NULL doesn't care
what the type is, but when doing a generated walk, we already
have to cast the caller's specific FOO* to call visit_start,
while using void** lets us use visit_end without a cast. Also,
an upcoming patch will add a clone visitor that wants to use
the same implementation for all three visit_end callbacks,
which is made easier if all three share the same signature.
For visitors with already track per-object state (the QMP visitors
via a stack, and the string visitors which do not allow nesting),
add an assertion that the caller is indeed passing the same
pointer to paired calls.
Signed-off-by: Eric Blake <eblake@redhat.com>
Message-Id: <1465490926-28625-4-git-send-email-eblake@redhat.com>
Reviewed-by: Markus Armbruster <armbru@redhat.com>
Signed-off-by: Markus Armbruster <armbru@redhat.com>
2016-06-09 19:48:34 +03:00
|
|
|
visit_end_struct(v, NULL);
|
2014-05-07 11:53:52 +04:00
|
|
|
out:
|
|
|
|
error_propagate(errp, err);
|
balloon: re-enable balloon stats
The statistics are now available through device properties via a
polling mechanism. First a client has to enable polling, then it
can query available stats.
Polling is enabled by setting an update interval (in seconds)
to a property named guest-stats-polling-interval, like this:
{ "execute": "qom-set",
"arguments": { "path": "/machine/peripheral-anon/device[1]",
"property": "guest-stats-polling-interval", "value": 4 } }
Then the available stats can be retrieved by querying the
guest-stats property. The returned object is a dict containing
all available stats. Example:
{ "execute": "qom-get",
"arguments": { "path": "/machine/peripheral-anon/device[1]",
"property": "guest-stats" } }
{
"return": {
"stats": {
"stat-swap-out": 0,
"stat-free-memory": 844943360,
"stat-minor-faults": 219028,
"stat-major-faults": 235,
"stat-total-memory": 1044406272,
"stat-swap-in": 0
},
"last-update": 1358529861
}
}
Please, check the next commit for full documentation.
Signed-off-by: Luiz Capitulino <lcapitulino@redhat.com>
Reviewed-by: Eric Blake <eblake@redhat.com>
2012-12-01 06:14:57 +04:00
|
|
|
}
|
|
|
|
|
2016-01-29 16:48:53 +03:00
|
|
|
static void balloon_stats_get_poll_interval(Object *obj, Visitor *v,
|
qom: Swap 'name' next to visitor in ObjectPropertyAccessor
Similar to the previous patch, it's nice to have all functions
in the tree that involve a visitor and a name for conversion to
or from QAPI to consistently stick the 'name' parameter next
to the Visitor parameter.
Done by manually changing include/qom/object.h and qom/object.c,
then running this Coccinelle script and touching up the fallout
(Coccinelle insisted on adding some trailing whitespace).
@ rule1 @
identifier fn;
typedef Object, Visitor, Error;
identifier obj, v, opaque, name, errp;
@@
void fn
- (Object *obj, Visitor *v, void *opaque, const char *name,
+ (Object *obj, Visitor *v, const char *name, void *opaque,
Error **errp) { ... }
@@
identifier rule1.fn;
expression obj, v, opaque, name, errp;
@@
fn(obj, v,
- opaque, name,
+ name, opaque,
errp)
Signed-off-by: Eric Blake <eblake@redhat.com>
Reviewed-by: Marc-André Lureau <marcandre.lureau@redhat.com>
Message-Id: <1454075341-13658-20-git-send-email-eblake@redhat.com>
Signed-off-by: Markus Armbruster <armbru@redhat.com>
2016-01-29 16:48:55 +03:00
|
|
|
const char *name, void *opaque,
|
balloon: re-enable balloon stats
The statistics are now available through device properties via a
polling mechanism. First a client has to enable polling, then it
can query available stats.
Polling is enabled by setting an update interval (in seconds)
to a property named guest-stats-polling-interval, like this:
{ "execute": "qom-set",
"arguments": { "path": "/machine/peripheral-anon/device[1]",
"property": "guest-stats-polling-interval", "value": 4 } }
Then the available stats can be retrieved by querying the
guest-stats property. The returned object is a dict containing
all available stats. Example:
{ "execute": "qom-get",
"arguments": { "path": "/machine/peripheral-anon/device[1]",
"property": "guest-stats" } }
{
"return": {
"stats": {
"stat-swap-out": 0,
"stat-free-memory": 844943360,
"stat-minor-faults": 219028,
"stat-major-faults": 235,
"stat-total-memory": 1044406272,
"stat-swap-in": 0
},
"last-update": 1358529861
}
}
Please, check the next commit for full documentation.
Signed-off-by: Luiz Capitulino <lcapitulino@redhat.com>
Reviewed-by: Eric Blake <eblake@redhat.com>
2012-12-01 06:14:57 +04:00
|
|
|
Error **errp)
|
|
|
|
{
|
|
|
|
VirtIOBalloon *s = opaque;
|
qapi: Swap visit_* arguments for consistent 'name' placement
JSON uses "name":value, but many of our visitor interfaces were
called with visit_type_FOO(v, &value, name, errp). This can be
a bit confusing to have to mentally swap the parameter order to
match JSON order. It's particularly bad for visit_start_struct(),
where the 'name' parameter is smack in the middle of the
otherwise-related group of 'obj, kind, size' parameters! It's
time to do a global swap of the parameter ordering, so that the
'name' parameter is always immediately after the Visitor argument.
Additional reason in favor of the swap: the existing include/qjson.h
prefers listing 'name' first in json_prop_*(), and I have plans to
unify that file with the qapi visitors; listing 'name' first in
qapi will minimize churn to the (admittedly few) qjson.h clients.
Later patches will then fix docs, object.h, visitor-impl.h, and
those clients to match.
Done by first patching scripts/qapi*.py by hand to make generated
files do what I want, then by running the following Coccinelle
script to affect the rest of the code base:
$ spatch --sp-file script `git grep -l '\bvisit_' -- '**/*.[ch]'`
I then had to apply some touchups (Coccinelle insisted on TAB
indentation in visitor.h, and botched the signature of
visit_type_enum() by rewriting 'const char *const strings[]' to
the syntactically invalid 'const char*const[] strings'). The
movement of parameters is sufficient to provoke compiler errors
if any callers were missed.
// Part 1: Swap declaration order
@@
type TV, TErr, TObj, T1, T2;
identifier OBJ, ARG1, ARG2;
@@
void visit_start_struct
-(TV v, TObj OBJ, T1 ARG1, const char *name, T2 ARG2, TErr errp)
+(TV v, const char *name, TObj OBJ, T1 ARG1, T2 ARG2, TErr errp)
{ ... }
@@
type bool, TV, T1;
identifier ARG1;
@@
bool visit_optional
-(TV v, T1 ARG1, const char *name)
+(TV v, const char *name, T1 ARG1)
{ ... }
@@
type TV, TErr, TObj, T1;
identifier OBJ, ARG1;
@@
void visit_get_next_type
-(TV v, TObj OBJ, T1 ARG1, const char *name, TErr errp)
+(TV v, const char *name, TObj OBJ, T1 ARG1, TErr errp)
{ ... }
@@
type TV, TErr, TObj, T1, T2;
identifier OBJ, ARG1, ARG2;
@@
void visit_type_enum
-(TV v, TObj OBJ, T1 ARG1, T2 ARG2, const char *name, TErr errp)
+(TV v, const char *name, TObj OBJ, T1 ARG1, T2 ARG2, TErr errp)
{ ... }
@@
type TV, TErr, TObj;
identifier OBJ;
identifier VISIT_TYPE =~ "^visit_type_";
@@
void VISIT_TYPE
-(TV v, TObj OBJ, const char *name, TErr errp)
+(TV v, const char *name, TObj OBJ, TErr errp)
{ ... }
// Part 2: swap caller order
@@
expression V, NAME, OBJ, ARG1, ARG2, ERR;
identifier VISIT_TYPE =~ "^visit_type_";
@@
(
-visit_start_struct(V, OBJ, ARG1, NAME, ARG2, ERR)
+visit_start_struct(V, NAME, OBJ, ARG1, ARG2, ERR)
|
-visit_optional(V, ARG1, NAME)
+visit_optional(V, NAME, ARG1)
|
-visit_get_next_type(V, OBJ, ARG1, NAME, ERR)
+visit_get_next_type(V, NAME, OBJ, ARG1, ERR)
|
-visit_type_enum(V, OBJ, ARG1, ARG2, NAME, ERR)
+visit_type_enum(V, NAME, OBJ, ARG1, ARG2, ERR)
|
-VISIT_TYPE(V, OBJ, NAME, ERR)
+VISIT_TYPE(V, NAME, OBJ, ERR)
)
Signed-off-by: Eric Blake <eblake@redhat.com>
Reviewed-by: Marc-André Lureau <marcandre.lureau@redhat.com>
Message-Id: <1454075341-13658-19-git-send-email-eblake@redhat.com>
Signed-off-by: Markus Armbruster <armbru@redhat.com>
2016-01-29 16:48:54 +03:00
|
|
|
visit_type_int(v, name, &s->stats_poll_interval, errp);
|
balloon: re-enable balloon stats
The statistics are now available through device properties via a
polling mechanism. First a client has to enable polling, then it
can query available stats.
Polling is enabled by setting an update interval (in seconds)
to a property named guest-stats-polling-interval, like this:
{ "execute": "qom-set",
"arguments": { "path": "/machine/peripheral-anon/device[1]",
"property": "guest-stats-polling-interval", "value": 4 } }
Then the available stats can be retrieved by querying the
guest-stats property. The returned object is a dict containing
all available stats. Example:
{ "execute": "qom-get",
"arguments": { "path": "/machine/peripheral-anon/device[1]",
"property": "guest-stats" } }
{
"return": {
"stats": {
"stat-swap-out": 0,
"stat-free-memory": 844943360,
"stat-minor-faults": 219028,
"stat-major-faults": 235,
"stat-total-memory": 1044406272,
"stat-swap-in": 0
},
"last-update": 1358529861
}
}
Please, check the next commit for full documentation.
Signed-off-by: Luiz Capitulino <lcapitulino@redhat.com>
Reviewed-by: Eric Blake <eblake@redhat.com>
2012-12-01 06:14:57 +04:00
|
|
|
}
|
|
|
|
|
2016-01-29 16:48:53 +03:00
|
|
|
static void balloon_stats_set_poll_interval(Object *obj, Visitor *v,
|
qom: Swap 'name' next to visitor in ObjectPropertyAccessor
Similar to the previous patch, it's nice to have all functions
in the tree that involve a visitor and a name for conversion to
or from QAPI to consistently stick the 'name' parameter next
to the Visitor parameter.
Done by manually changing include/qom/object.h and qom/object.c,
then running this Coccinelle script and touching up the fallout
(Coccinelle insisted on adding some trailing whitespace).
@ rule1 @
identifier fn;
typedef Object, Visitor, Error;
identifier obj, v, opaque, name, errp;
@@
void fn
- (Object *obj, Visitor *v, void *opaque, const char *name,
+ (Object *obj, Visitor *v, const char *name, void *opaque,
Error **errp) { ... }
@@
identifier rule1.fn;
expression obj, v, opaque, name, errp;
@@
fn(obj, v,
- opaque, name,
+ name, opaque,
errp)
Signed-off-by: Eric Blake <eblake@redhat.com>
Reviewed-by: Marc-André Lureau <marcandre.lureau@redhat.com>
Message-Id: <1454075341-13658-20-git-send-email-eblake@redhat.com>
Signed-off-by: Markus Armbruster <armbru@redhat.com>
2016-01-29 16:48:55 +03:00
|
|
|
const char *name, void *opaque,
|
balloon: re-enable balloon stats
The statistics are now available through device properties via a
polling mechanism. First a client has to enable polling, then it
can query available stats.
Polling is enabled by setting an update interval (in seconds)
to a property named guest-stats-polling-interval, like this:
{ "execute": "qom-set",
"arguments": { "path": "/machine/peripheral-anon/device[1]",
"property": "guest-stats-polling-interval", "value": 4 } }
Then the available stats can be retrieved by querying the
guest-stats property. The returned object is a dict containing
all available stats. Example:
{ "execute": "qom-get",
"arguments": { "path": "/machine/peripheral-anon/device[1]",
"property": "guest-stats" } }
{
"return": {
"stats": {
"stat-swap-out": 0,
"stat-free-memory": 844943360,
"stat-minor-faults": 219028,
"stat-major-faults": 235,
"stat-total-memory": 1044406272,
"stat-swap-in": 0
},
"last-update": 1358529861
}
}
Please, check the next commit for full documentation.
Signed-off-by: Luiz Capitulino <lcapitulino@redhat.com>
Reviewed-by: Eric Blake <eblake@redhat.com>
2012-12-01 06:14:57 +04:00
|
|
|
Error **errp)
|
|
|
|
{
|
|
|
|
VirtIOBalloon *s = opaque;
|
2014-04-25 14:44:22 +04:00
|
|
|
Error *local_err = NULL;
|
balloon: re-enable balloon stats
The statistics are now available through device properties via a
polling mechanism. First a client has to enable polling, then it
can query available stats.
Polling is enabled by setting an update interval (in seconds)
to a property named guest-stats-polling-interval, like this:
{ "execute": "qom-set",
"arguments": { "path": "/machine/peripheral-anon/device[1]",
"property": "guest-stats-polling-interval", "value": 4 } }
Then the available stats can be retrieved by querying the
guest-stats property. The returned object is a dict containing
all available stats. Example:
{ "execute": "qom-get",
"arguments": { "path": "/machine/peripheral-anon/device[1]",
"property": "guest-stats" } }
{
"return": {
"stats": {
"stat-swap-out": 0,
"stat-free-memory": 844943360,
"stat-minor-faults": 219028,
"stat-major-faults": 235,
"stat-total-memory": 1044406272,
"stat-swap-in": 0
},
"last-update": 1358529861
}
}
Please, check the next commit for full documentation.
Signed-off-by: Luiz Capitulino <lcapitulino@redhat.com>
Reviewed-by: Eric Blake <eblake@redhat.com>
2012-12-01 06:14:57 +04:00
|
|
|
int64_t value;
|
|
|
|
|
qapi: Swap visit_* arguments for consistent 'name' placement
JSON uses "name":value, but many of our visitor interfaces were
called with visit_type_FOO(v, &value, name, errp). This can be
a bit confusing to have to mentally swap the parameter order to
match JSON order. It's particularly bad for visit_start_struct(),
where the 'name' parameter is smack in the middle of the
otherwise-related group of 'obj, kind, size' parameters! It's
time to do a global swap of the parameter ordering, so that the
'name' parameter is always immediately after the Visitor argument.
Additional reason in favor of the swap: the existing include/qjson.h
prefers listing 'name' first in json_prop_*(), and I have plans to
unify that file with the qapi visitors; listing 'name' first in
qapi will minimize churn to the (admittedly few) qjson.h clients.
Later patches will then fix docs, object.h, visitor-impl.h, and
those clients to match.
Done by first patching scripts/qapi*.py by hand to make generated
files do what I want, then by running the following Coccinelle
script to affect the rest of the code base:
$ spatch --sp-file script `git grep -l '\bvisit_' -- '**/*.[ch]'`
I then had to apply some touchups (Coccinelle insisted on TAB
indentation in visitor.h, and botched the signature of
visit_type_enum() by rewriting 'const char *const strings[]' to
the syntactically invalid 'const char*const[] strings'). The
movement of parameters is sufficient to provoke compiler errors
if any callers were missed.
// Part 1: Swap declaration order
@@
type TV, TErr, TObj, T1, T2;
identifier OBJ, ARG1, ARG2;
@@
void visit_start_struct
-(TV v, TObj OBJ, T1 ARG1, const char *name, T2 ARG2, TErr errp)
+(TV v, const char *name, TObj OBJ, T1 ARG1, T2 ARG2, TErr errp)
{ ... }
@@
type bool, TV, T1;
identifier ARG1;
@@
bool visit_optional
-(TV v, T1 ARG1, const char *name)
+(TV v, const char *name, T1 ARG1)
{ ... }
@@
type TV, TErr, TObj, T1;
identifier OBJ, ARG1;
@@
void visit_get_next_type
-(TV v, TObj OBJ, T1 ARG1, const char *name, TErr errp)
+(TV v, const char *name, TObj OBJ, T1 ARG1, TErr errp)
{ ... }
@@
type TV, TErr, TObj, T1, T2;
identifier OBJ, ARG1, ARG2;
@@
void visit_type_enum
-(TV v, TObj OBJ, T1 ARG1, T2 ARG2, const char *name, TErr errp)
+(TV v, const char *name, TObj OBJ, T1 ARG1, T2 ARG2, TErr errp)
{ ... }
@@
type TV, TErr, TObj;
identifier OBJ;
identifier VISIT_TYPE =~ "^visit_type_";
@@
void VISIT_TYPE
-(TV v, TObj OBJ, const char *name, TErr errp)
+(TV v, const char *name, TObj OBJ, TErr errp)
{ ... }
// Part 2: swap caller order
@@
expression V, NAME, OBJ, ARG1, ARG2, ERR;
identifier VISIT_TYPE =~ "^visit_type_";
@@
(
-visit_start_struct(V, OBJ, ARG1, NAME, ARG2, ERR)
+visit_start_struct(V, NAME, OBJ, ARG1, ARG2, ERR)
|
-visit_optional(V, ARG1, NAME)
+visit_optional(V, NAME, ARG1)
|
-visit_get_next_type(V, OBJ, ARG1, NAME, ERR)
+visit_get_next_type(V, NAME, OBJ, ARG1, ERR)
|
-visit_type_enum(V, OBJ, ARG1, ARG2, NAME, ERR)
+visit_type_enum(V, NAME, OBJ, ARG1, ARG2, ERR)
|
-VISIT_TYPE(V, OBJ, NAME, ERR)
+VISIT_TYPE(V, NAME, OBJ, ERR)
)
Signed-off-by: Eric Blake <eblake@redhat.com>
Reviewed-by: Marc-André Lureau <marcandre.lureau@redhat.com>
Message-Id: <1454075341-13658-19-git-send-email-eblake@redhat.com>
Signed-off-by: Markus Armbruster <armbru@redhat.com>
2016-01-29 16:48:54 +03:00
|
|
|
visit_type_int(v, name, &value, &local_err);
|
2014-04-25 14:44:22 +04:00
|
|
|
if (local_err) {
|
|
|
|
error_propagate(errp, local_err);
|
balloon: re-enable balloon stats
The statistics are now available through device properties via a
polling mechanism. First a client has to enable polling, then it
can query available stats.
Polling is enabled by setting an update interval (in seconds)
to a property named guest-stats-polling-interval, like this:
{ "execute": "qom-set",
"arguments": { "path": "/machine/peripheral-anon/device[1]",
"property": "guest-stats-polling-interval", "value": 4 } }
Then the available stats can be retrieved by querying the
guest-stats property. The returned object is a dict containing
all available stats. Example:
{ "execute": "qom-get",
"arguments": { "path": "/machine/peripheral-anon/device[1]",
"property": "guest-stats" } }
{
"return": {
"stats": {
"stat-swap-out": 0,
"stat-free-memory": 844943360,
"stat-minor-faults": 219028,
"stat-major-faults": 235,
"stat-total-memory": 1044406272,
"stat-swap-in": 0
},
"last-update": 1358529861
}
}
Please, check the next commit for full documentation.
Signed-off-by: Luiz Capitulino <lcapitulino@redhat.com>
Reviewed-by: Eric Blake <eblake@redhat.com>
2012-12-01 06:14:57 +04:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (value < 0) {
|
|
|
|
error_setg(errp, "timer value must be greater than zero");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2014-10-01 20:43:44 +04:00
|
|
|
if (value > UINT32_MAX) {
|
2014-09-15 20:00:11 +04:00
|
|
|
error_setg(errp, "timer value is too big");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
balloon: re-enable balloon stats
The statistics are now available through device properties via a
polling mechanism. First a client has to enable polling, then it
can query available stats.
Polling is enabled by setting an update interval (in seconds)
to a property named guest-stats-polling-interval, like this:
{ "execute": "qom-set",
"arguments": { "path": "/machine/peripheral-anon/device[1]",
"property": "guest-stats-polling-interval", "value": 4 } }
Then the available stats can be retrieved by querying the
guest-stats property. The returned object is a dict containing
all available stats. Example:
{ "execute": "qom-get",
"arguments": { "path": "/machine/peripheral-anon/device[1]",
"property": "guest-stats" } }
{
"return": {
"stats": {
"stat-swap-out": 0,
"stat-free-memory": 844943360,
"stat-minor-faults": 219028,
"stat-major-faults": 235,
"stat-total-memory": 1044406272,
"stat-swap-in": 0
},
"last-update": 1358529861
}
}
Please, check the next commit for full documentation.
Signed-off-by: Luiz Capitulino <lcapitulino@redhat.com>
Reviewed-by: Eric Blake <eblake@redhat.com>
2012-12-01 06:14:57 +04:00
|
|
|
if (value == s->stats_poll_interval) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (value == 0) {
|
|
|
|
/* timer=0 disables the timer */
|
|
|
|
balloon_stats_destroy_timer(s);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (balloon_stats_enabled(s)) {
|
|
|
|
/* timer interval change */
|
|
|
|
s->stats_poll_interval = value;
|
|
|
|
balloon_stats_change_timer(s, value);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* create a new timer */
|
|
|
|
g_assert(s->stats_timer == NULL);
|
2013-08-21 19:03:08 +04:00
|
|
|
s->stats_timer = timer_new_ms(QEMU_CLOCK_VIRTUAL, balloon_stats_poll_cb, s);
|
balloon: re-enable balloon stats
The statistics are now available through device properties via a
polling mechanism. First a client has to enable polling, then it
can query available stats.
Polling is enabled by setting an update interval (in seconds)
to a property named guest-stats-polling-interval, like this:
{ "execute": "qom-set",
"arguments": { "path": "/machine/peripheral-anon/device[1]",
"property": "guest-stats-polling-interval", "value": 4 } }
Then the available stats can be retrieved by querying the
guest-stats property. The returned object is a dict containing
all available stats. Example:
{ "execute": "qom-get",
"arguments": { "path": "/machine/peripheral-anon/device[1]",
"property": "guest-stats" } }
{
"return": {
"stats": {
"stat-swap-out": 0,
"stat-free-memory": 844943360,
"stat-minor-faults": 219028,
"stat-major-faults": 235,
"stat-total-memory": 1044406272,
"stat-swap-in": 0
},
"last-update": 1358529861
}
}
Please, check the next commit for full documentation.
Signed-off-by: Luiz Capitulino <lcapitulino@redhat.com>
Reviewed-by: Eric Blake <eblake@redhat.com>
2012-12-01 06:14:57 +04:00
|
|
|
s->stats_poll_interval = value;
|
|
|
|
balloon_stats_change_timer(s, 0);
|
|
|
|
}
|
|
|
|
|
2008-12-04 23:33:06 +03:00
|
|
|
static void virtio_balloon_handle_output(VirtIODevice *vdev, VirtQueue *vq)
|
|
|
|
{
|
2013-03-27 13:49:14 +04:00
|
|
|
VirtIOBalloon *s = VIRTIO_BALLOON(vdev);
|
2016-02-04 17:26:51 +03:00
|
|
|
VirtQueueElement *elem;
|
2011-12-19 15:18:13 +04:00
|
|
|
MemoryRegionSection section;
|
2008-12-04 23:33:06 +03:00
|
|
|
|
2016-02-04 17:26:51 +03:00
|
|
|
for (;;) {
|
2019-07-25 14:54:25 +03:00
|
|
|
PartiallyBalloonedPage pbp = {};
|
2008-12-04 23:33:06 +03:00
|
|
|
size_t offset = 0;
|
|
|
|
uint32_t pfn;
|
2019-07-25 14:54:25 +03:00
|
|
|
|
2016-02-04 17:26:51 +03:00
|
|
|
elem = virtqueue_pop(vq, sizeof(VirtQueueElement));
|
|
|
|
if (!elem) {
|
2019-07-22 16:41:08 +03:00
|
|
|
break;
|
2016-02-04 17:26:51 +03:00
|
|
|
}
|
2008-12-04 23:33:06 +03:00
|
|
|
|
2016-02-04 17:26:51 +03:00
|
|
|
while (iov_to_buf(elem->out_sg, elem->out_num, offset, &pfn, 4) == 4) {
|
2019-07-22 16:41:03 +03:00
|
|
|
unsigned int p = virtio_ldl_p(vdev, &pfn);
|
2019-02-14 07:39:13 +03:00
|
|
|
hwaddr pa;
|
2008-12-04 23:33:06 +03:00
|
|
|
|
2019-02-14 07:39:13 +03:00
|
|
|
pa = (hwaddr) p << VIRTIO_BALLOON_PFN_SHIFT;
|
2008-12-04 23:33:06 +03:00
|
|
|
offset += 4;
|
|
|
|
|
2019-02-14 07:39:13 +03:00
|
|
|
section = memory_region_find(get_system_memory(), pa,
|
|
|
|
BALLOON_PAGE_SIZE);
|
|
|
|
if (!section.mr) {
|
|
|
|
trace_virtio_balloon_bad_addr(pa);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
if (!memory_region_is_ram(section.mr) ||
|
2016-12-16 14:41:55 +03:00
|
|
|
memory_region_is_rom(section.mr) ||
|
|
|
|
memory_region_is_romd(section.mr)) {
|
|
|
|
trace_virtio_balloon_bad_addr(pa);
|
2018-01-25 10:12:43 +03:00
|
|
|
memory_region_unref(section.mr);
|
2008-12-04 23:33:06 +03:00
|
|
|
continue;
|
2016-12-16 14:41:55 +03:00
|
|
|
}
|
2008-12-04 23:33:06 +03:00
|
|
|
|
2014-11-17 08:11:10 +03:00
|
|
|
trace_virtio_balloon_handle_output(memory_region_name(section.mr),
|
|
|
|
pa);
|
2019-03-06 06:06:00 +03:00
|
|
|
if (!qemu_balloon_is_inhibited()) {
|
|
|
|
if (vq == s->ivq) {
|
|
|
|
balloon_inflate_page(s, section.mr,
|
2019-07-22 16:41:08 +03:00
|
|
|
section.offset_within_region, &pbp);
|
2019-03-06 06:06:00 +03:00
|
|
|
} else if (vq == s->dvq) {
|
|
|
|
balloon_deflate_page(s, section.mr, section.offset_within_region);
|
|
|
|
} else {
|
|
|
|
g_assert_not_reached();
|
|
|
|
}
|
2019-02-14 07:39:14 +03:00
|
|
|
}
|
2013-05-06 12:46:11 +04:00
|
|
|
memory_region_unref(section.mr);
|
2008-12-04 23:33:06 +03:00
|
|
|
}
|
|
|
|
|
2016-02-04 17:26:51 +03:00
|
|
|
virtqueue_push(vq, elem, offset);
|
2008-12-04 23:33:06 +03:00
|
|
|
virtio_notify(vdev, vq);
|
2016-02-04 17:26:51 +03:00
|
|
|
g_free(elem);
|
2019-07-25 14:54:25 +03:00
|
|
|
virtio_balloon_pbp_free(&pbp);
|
2008-12-04 23:33:06 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-01-26 23:17:35 +03:00
|
|
|
static void virtio_balloon_receive_stats(VirtIODevice *vdev, VirtQueue *vq)
|
|
|
|
{
|
2013-03-27 13:49:14 +04:00
|
|
|
VirtIOBalloon *s = VIRTIO_BALLOON(vdev);
|
2016-02-04 17:26:51 +03:00
|
|
|
VirtQueueElement *elem;
|
2010-01-26 23:17:35 +03:00
|
|
|
VirtIOBalloonStat stat;
|
|
|
|
size_t offset = 0;
|
balloon: re-enable balloon stats
The statistics are now available through device properties via a
polling mechanism. First a client has to enable polling, then it
can query available stats.
Polling is enabled by setting an update interval (in seconds)
to a property named guest-stats-polling-interval, like this:
{ "execute": "qom-set",
"arguments": { "path": "/machine/peripheral-anon/device[1]",
"property": "guest-stats-polling-interval", "value": 4 } }
Then the available stats can be retrieved by querying the
guest-stats property. The returned object is a dict containing
all available stats. Example:
{ "execute": "qom-get",
"arguments": { "path": "/machine/peripheral-anon/device[1]",
"property": "guest-stats" } }
{
"return": {
"stats": {
"stat-swap-out": 0,
"stat-free-memory": 844943360,
"stat-minor-faults": 219028,
"stat-major-faults": 235,
"stat-total-memory": 1044406272,
"stat-swap-in": 0
},
"last-update": 1358529861
}
}
Please, check the next commit for full documentation.
Signed-off-by: Luiz Capitulino <lcapitulino@redhat.com>
Reviewed-by: Eric Blake <eblake@redhat.com>
2012-12-01 06:14:57 +04:00
|
|
|
qemu_timeval tv;
|
2010-01-26 23:17:35 +03:00
|
|
|
|
2016-03-01 14:14:03 +03:00
|
|
|
elem = virtqueue_pop(vq, sizeof(VirtQueueElement));
|
2016-02-04 17:26:51 +03:00
|
|
|
if (!elem) {
|
balloon: re-enable balloon stats
The statistics are now available through device properties via a
polling mechanism. First a client has to enable polling, then it
can query available stats.
Polling is enabled by setting an update interval (in seconds)
to a property named guest-stats-polling-interval, like this:
{ "execute": "qom-set",
"arguments": { "path": "/machine/peripheral-anon/device[1]",
"property": "guest-stats-polling-interval", "value": 4 } }
Then the available stats can be retrieved by querying the
guest-stats property. The returned object is a dict containing
all available stats. Example:
{ "execute": "qom-get",
"arguments": { "path": "/machine/peripheral-anon/device[1]",
"property": "guest-stats" } }
{
"return": {
"stats": {
"stat-swap-out": 0,
"stat-free-memory": 844943360,
"stat-minor-faults": 219028,
"stat-major-faults": 235,
"stat-total-memory": 1044406272,
"stat-swap-in": 0
},
"last-update": 1358529861
}
}
Please, check the next commit for full documentation.
Signed-off-by: Luiz Capitulino <lcapitulino@redhat.com>
Reviewed-by: Eric Blake <eblake@redhat.com>
2012-12-01 06:14:57 +04:00
|
|
|
goto out;
|
2010-01-26 23:17:35 +03:00
|
|
|
}
|
|
|
|
|
2016-03-01 14:14:03 +03:00
|
|
|
if (s->stats_vq_elem != NULL) {
|
|
|
|
/* This should never happen if the driver follows the spec. */
|
|
|
|
virtqueue_push(vq, s->stats_vq_elem, 0);
|
|
|
|
virtio_notify(vdev, vq);
|
|
|
|
g_free(s->stats_vq_elem);
|
|
|
|
}
|
|
|
|
|
|
|
|
s->stats_vq_elem = elem;
|
|
|
|
|
2010-01-26 23:17:35 +03:00
|
|
|
/* Initialize the stats to get rid of any stale values. This is only
|
|
|
|
* needed to handle the case where a guest supports fewer stats than it
|
|
|
|
* used to (ie. it has booted into an old kernel).
|
|
|
|
*/
|
|
|
|
reset_stats(s);
|
|
|
|
|
change iov_* function prototypes to be more appropriate
Reorder arguments to be more natural, readable and
consistent with other iov_* functions, and change
argument names, from:
iov_from_buf(iov, iov_cnt, buf, iov_off, size)
to
iov_from_buf(iov, iov_cnt, offset, buf, bytes)
The result becomes natural English:
copy data to this `iov' vector with `iov_cnt'
elements starting at byte offset `offset'
from memory buffer `buf', processing `bytes'
bytes max.
(Try to read the original prototype this way).
Also change iov_clear() to more general iov_memset()
(it uses memset() internally anyway).
While at it, add comments to the header file
describing what the routines actually does.
The patch only renames argumens in the header, but
keeps old names in the implementation. The next
patch will touch actual code to match.
Now, it might look wrong to pay so much attention
to so small things. But we've so many badly designed
interfaces already so the whole thing becomes rather
confusing or error prone. One example of this is
previous commit and small discussion which emerged
from it, with an outcome that the utility functions
like these aren't well-understdandable, leading to
strange usage cases. That's why I paid quite some
attention to this set of functions and a few
others in subsequent patches.
Signed-off-by: Michael Tokarev <mjt@tls.msk.ru>
2012-03-11 18:05:12 +04:00
|
|
|
while (iov_to_buf(elem->out_sg, elem->out_num, offset, &stat, sizeof(stat))
|
2010-04-27 16:34:06 +04:00
|
|
|
== sizeof(stat)) {
|
2014-06-24 21:43:22 +04:00
|
|
|
uint16_t tag = virtio_tswap16(vdev, stat.tag);
|
|
|
|
uint64_t val = virtio_tswap64(vdev, stat.val);
|
2010-01-26 23:17:35 +03:00
|
|
|
|
|
|
|
offset += sizeof(stat);
|
|
|
|
if (tag < VIRTIO_BALLOON_S_NR)
|
|
|
|
s->stats[tag] = val;
|
|
|
|
}
|
|
|
|
s->stats_vq_offset = offset;
|
balloon: re-enable balloon stats
The statistics are now available through device properties via a
polling mechanism. First a client has to enable polling, then it
can query available stats.
Polling is enabled by setting an update interval (in seconds)
to a property named guest-stats-polling-interval, like this:
{ "execute": "qom-set",
"arguments": { "path": "/machine/peripheral-anon/device[1]",
"property": "guest-stats-polling-interval", "value": 4 } }
Then the available stats can be retrieved by querying the
guest-stats property. The returned object is a dict containing
all available stats. Example:
{ "execute": "qom-get",
"arguments": { "path": "/machine/peripheral-anon/device[1]",
"property": "guest-stats" } }
{
"return": {
"stats": {
"stat-swap-out": 0,
"stat-free-memory": 844943360,
"stat-minor-faults": 219028,
"stat-major-faults": 235,
"stat-total-memory": 1044406272,
"stat-swap-in": 0
},
"last-update": 1358529861
}
}
Please, check the next commit for full documentation.
Signed-off-by: Luiz Capitulino <lcapitulino@redhat.com>
Reviewed-by: Eric Blake <eblake@redhat.com>
2012-12-01 06:14:57 +04:00
|
|
|
|
|
|
|
if (qemu_gettimeofday(&tv) < 0) {
|
2017-09-11 22:52:50 +03:00
|
|
|
warn_report("%s: failed to get time of day", __func__);
|
balloon: re-enable balloon stats
The statistics are now available through device properties via a
polling mechanism. First a client has to enable polling, then it
can query available stats.
Polling is enabled by setting an update interval (in seconds)
to a property named guest-stats-polling-interval, like this:
{ "execute": "qom-set",
"arguments": { "path": "/machine/peripheral-anon/device[1]",
"property": "guest-stats-polling-interval", "value": 4 } }
Then the available stats can be retrieved by querying the
guest-stats property. The returned object is a dict containing
all available stats. Example:
{ "execute": "qom-get",
"arguments": { "path": "/machine/peripheral-anon/device[1]",
"property": "guest-stats" } }
{
"return": {
"stats": {
"stat-swap-out": 0,
"stat-free-memory": 844943360,
"stat-minor-faults": 219028,
"stat-major-faults": 235,
"stat-total-memory": 1044406272,
"stat-swap-in": 0
},
"last-update": 1358529861
}
}
Please, check the next commit for full documentation.
Signed-off-by: Luiz Capitulino <lcapitulino@redhat.com>
Reviewed-by: Eric Blake <eblake@redhat.com>
2012-12-01 06:14:57 +04:00
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
|
|
|
|
s->stats_last_update = tv.tv_sec;
|
|
|
|
|
|
|
|
out:
|
|
|
|
if (balloon_stats_enabled(s)) {
|
|
|
|
balloon_stats_change_timer(s, s->stats_poll_interval);
|
|
|
|
}
|
2010-01-26 23:17:35 +03:00
|
|
|
}
|
|
|
|
|
2018-12-11 11:24:53 +03:00
|
|
|
static void virtio_balloon_handle_free_page_vq(VirtIODevice *vdev,
|
|
|
|
VirtQueue *vq)
|
|
|
|
{
|
|
|
|
VirtIOBalloon *s = VIRTIO_BALLOON(vdev);
|
|
|
|
qemu_bh_schedule(s->free_page_bh);
|
|
|
|
}
|
|
|
|
|
|
|
|
static bool get_free_page_hints(VirtIOBalloon *dev)
|
|
|
|
{
|
|
|
|
VirtQueueElement *elem;
|
|
|
|
VirtIODevice *vdev = VIRTIO_DEVICE(dev);
|
|
|
|
VirtQueue *vq = dev->free_page_vq;
|
2019-03-12 12:34:40 +03:00
|
|
|
bool ret = true;
|
2018-12-11 11:24:53 +03:00
|
|
|
|
|
|
|
while (dev->block_iothread) {
|
|
|
|
qemu_cond_wait(&dev->free_page_cond, &dev->free_page_lock);
|
|
|
|
}
|
|
|
|
|
|
|
|
elem = virtqueue_pop(vq, sizeof(VirtQueueElement));
|
|
|
|
if (!elem) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (elem->out_num) {
|
|
|
|
uint32_t id;
|
|
|
|
size_t size = iov_to_buf(elem->out_sg, elem->out_num, 0,
|
|
|
|
&id, sizeof(id));
|
|
|
|
|
|
|
|
virtio_tswap32s(vdev, &id);
|
|
|
|
if (unlikely(size != sizeof(id))) {
|
|
|
|
virtio_error(vdev, "received an incorrect cmd id");
|
2019-03-12 12:34:40 +03:00
|
|
|
ret = false;
|
|
|
|
goto out;
|
2018-12-11 11:24:53 +03:00
|
|
|
}
|
|
|
|
if (id == dev->free_page_report_cmd_id) {
|
|
|
|
dev->free_page_report_status = FREE_PAGE_REPORT_S_START;
|
|
|
|
} else {
|
|
|
|
/*
|
|
|
|
* Stop the optimization only when it has started. This
|
|
|
|
* avoids a stale stop sign for the previous command.
|
|
|
|
*/
|
|
|
|
if (dev->free_page_report_status == FREE_PAGE_REPORT_S_START) {
|
|
|
|
dev->free_page_report_status = FREE_PAGE_REPORT_S_STOP;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (elem->in_num) {
|
|
|
|
if (dev->free_page_report_status == FREE_PAGE_REPORT_S_START) {
|
|
|
|
qemu_guest_free_page_hint(elem->in_sg[0].iov_base,
|
|
|
|
elem->in_sg[0].iov_len);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-03-12 12:34:40 +03:00
|
|
|
out:
|
|
|
|
virtqueue_push(vq, elem, 1);
|
|
|
|
g_free(elem);
|
|
|
|
return ret;
|
2018-12-11 11:24:53 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
static void virtio_ballloon_get_free_page_hints(void *opaque)
|
|
|
|
{
|
|
|
|
VirtIOBalloon *dev = opaque;
|
|
|
|
VirtIODevice *vdev = VIRTIO_DEVICE(dev);
|
|
|
|
VirtQueue *vq = dev->free_page_vq;
|
|
|
|
bool continue_to_get_hints;
|
|
|
|
|
|
|
|
do {
|
|
|
|
qemu_mutex_lock(&dev->free_page_lock);
|
|
|
|
virtio_queue_set_notification(vq, 0);
|
|
|
|
continue_to_get_hints = get_free_page_hints(dev);
|
|
|
|
qemu_mutex_unlock(&dev->free_page_lock);
|
|
|
|
virtio_notify(vdev, vq);
|
|
|
|
/*
|
|
|
|
* Start to poll the vq once the reporting started. Otherwise, continue
|
|
|
|
* only when there are entries on the vq, which need to be given back.
|
|
|
|
*/
|
|
|
|
} while (continue_to_get_hints ||
|
|
|
|
dev->free_page_report_status == FREE_PAGE_REPORT_S_START);
|
|
|
|
virtio_queue_set_notification(vq, 1);
|
|
|
|
}
|
|
|
|
|
|
|
|
static bool virtio_balloon_free_page_support(void *opaque)
|
|
|
|
{
|
|
|
|
VirtIOBalloon *s = opaque;
|
|
|
|
VirtIODevice *vdev = VIRTIO_DEVICE(s);
|
|
|
|
|
|
|
|
return virtio_vdev_has_feature(vdev, VIRTIO_BALLOON_F_FREE_PAGE_HINT);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void virtio_balloon_free_page_start(VirtIOBalloon *s)
|
|
|
|
{
|
|
|
|
VirtIODevice *vdev = VIRTIO_DEVICE(s);
|
|
|
|
|
|
|
|
/* For the stop and copy phase, we don't need to start the optimization */
|
|
|
|
if (!vdev->vm_running) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (s->free_page_report_cmd_id == UINT_MAX) {
|
|
|
|
s->free_page_report_cmd_id =
|
|
|
|
VIRTIO_BALLOON_FREE_PAGE_REPORT_CMD_ID_MIN;
|
|
|
|
} else {
|
|
|
|
s->free_page_report_cmd_id++;
|
|
|
|
}
|
|
|
|
|
|
|
|
s->free_page_report_status = FREE_PAGE_REPORT_S_REQUESTED;
|
|
|
|
virtio_notify_config(vdev);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void virtio_balloon_free_page_stop(VirtIOBalloon *s)
|
|
|
|
{
|
|
|
|
VirtIODevice *vdev = VIRTIO_DEVICE(s);
|
|
|
|
|
|
|
|
if (s->free_page_report_status != FREE_PAGE_REPORT_S_STOP) {
|
|
|
|
/*
|
|
|
|
* The lock also guarantees us that the
|
|
|
|
* virtio_ballloon_get_free_page_hints exits after the
|
|
|
|
* free_page_report_status is set to S_STOP.
|
|
|
|
*/
|
|
|
|
qemu_mutex_lock(&s->free_page_lock);
|
|
|
|
/*
|
|
|
|
* The guest hasn't done the reporting, so host sends a notification
|
|
|
|
* to the guest to actively stop the reporting.
|
|
|
|
*/
|
|
|
|
s->free_page_report_status = FREE_PAGE_REPORT_S_STOP;
|
|
|
|
qemu_mutex_unlock(&s->free_page_lock);
|
|
|
|
virtio_notify_config(vdev);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void virtio_balloon_free_page_done(VirtIOBalloon *s)
|
|
|
|
{
|
|
|
|
VirtIODevice *vdev = VIRTIO_DEVICE(s);
|
|
|
|
|
|
|
|
s->free_page_report_status = FREE_PAGE_REPORT_S_DONE;
|
|
|
|
virtio_notify_config(vdev);
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
virtio_balloon_free_page_report_notify(NotifierWithReturn *n, void *data)
|
|
|
|
{
|
|
|
|
VirtIOBalloon *dev = container_of(n, VirtIOBalloon,
|
|
|
|
free_page_report_notify);
|
|
|
|
VirtIODevice *vdev = VIRTIO_DEVICE(dev);
|
|
|
|
PrecopyNotifyData *pnd = data;
|
|
|
|
|
|
|
|
if (!virtio_balloon_free_page_support(dev)) {
|
|
|
|
/*
|
|
|
|
* This is an optimization provided to migration, so just return 0 to
|
|
|
|
* have the normal migration process not affected when this feature is
|
|
|
|
* not supported.
|
|
|
|
*/
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
switch (pnd->reason) {
|
|
|
|
case PRECOPY_NOTIFY_SETUP:
|
|
|
|
precopy_enable_free_page_optimization();
|
|
|
|
break;
|
|
|
|
case PRECOPY_NOTIFY_COMPLETE:
|
|
|
|
case PRECOPY_NOTIFY_CLEANUP:
|
|
|
|
case PRECOPY_NOTIFY_BEFORE_BITMAP_SYNC:
|
|
|
|
virtio_balloon_free_page_stop(dev);
|
|
|
|
break;
|
|
|
|
case PRECOPY_NOTIFY_AFTER_BITMAP_SYNC:
|
|
|
|
if (vdev->vm_running) {
|
|
|
|
virtio_balloon_free_page_start(dev);
|
|
|
|
} else {
|
|
|
|
virtio_balloon_free_page_done(dev);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
virtio_error(vdev, "%s: %d reason unknown", __func__, pnd->reason);
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2019-07-10 17:14:40 +03:00
|
|
|
static size_t virtio_balloon_config_size(VirtIOBalloon *s)
|
|
|
|
{
|
|
|
|
uint64_t features = s->host_features;
|
|
|
|
|
|
|
|
if (s->qemu_4_0_config_size) {
|
|
|
|
return sizeof(struct virtio_balloon_config);
|
|
|
|
}
|
|
|
|
if (virtio_has_feature(features, VIRTIO_BALLOON_F_PAGE_POISON)) {
|
|
|
|
return sizeof(struct virtio_balloon_config);
|
|
|
|
}
|
|
|
|
if (virtio_has_feature(features, VIRTIO_BALLOON_F_FREE_PAGE_HINT)) {
|
|
|
|
return offsetof(struct virtio_balloon_config, poison_val);
|
|
|
|
}
|
|
|
|
return offsetof(struct virtio_balloon_config, free_page_report_cmd_id);
|
|
|
|
}
|
|
|
|
|
2008-12-04 23:33:06 +03:00
|
|
|
static void virtio_balloon_get_config(VirtIODevice *vdev, uint8_t *config_data)
|
|
|
|
{
|
2013-03-27 13:49:14 +04:00
|
|
|
VirtIOBalloon *dev = VIRTIO_BALLOON(vdev);
|
2019-01-18 21:36:03 +03:00
|
|
|
struct virtio_balloon_config config = {};
|
2008-12-04 23:33:06 +03:00
|
|
|
|
|
|
|
config.num_pages = cpu_to_le32(dev->num_pages);
|
|
|
|
config.actual = cpu_to_le32(dev->actual);
|
|
|
|
|
2018-12-11 11:24:53 +03:00
|
|
|
if (dev->free_page_report_status == FREE_PAGE_REPORT_S_REQUESTED) {
|
|
|
|
config.free_page_report_cmd_id =
|
|
|
|
cpu_to_le32(dev->free_page_report_cmd_id);
|
|
|
|
} else if (dev->free_page_report_status == FREE_PAGE_REPORT_S_STOP) {
|
|
|
|
config.free_page_report_cmd_id =
|
|
|
|
cpu_to_le32(VIRTIO_BALLOON_CMD_ID_STOP);
|
|
|
|
} else if (dev->free_page_report_status == FREE_PAGE_REPORT_S_DONE) {
|
|
|
|
config.free_page_report_cmd_id =
|
|
|
|
cpu_to_le32(VIRTIO_BALLOON_CMD_ID_DONE);
|
|
|
|
}
|
|
|
|
|
2014-11-17 08:11:10 +03:00
|
|
|
trace_virtio_balloon_get_config(config.num_pages, config.actual);
|
2019-07-10 17:14:40 +03:00
|
|
|
memcpy(config_data, &config, virtio_balloon_config_size(dev));
|
2008-12-04 23:33:06 +03:00
|
|
|
}
|
|
|
|
|
2016-02-10 11:49:26 +03:00
|
|
|
static int build_dimm_list(Object *obj, void *opaque)
|
|
|
|
{
|
|
|
|
GSList **list = opaque;
|
|
|
|
|
|
|
|
if (object_dynamic_cast(obj, TYPE_PC_DIMM)) {
|
|
|
|
DeviceState *dev = DEVICE(obj);
|
|
|
|
if (dev->realized) { /* only realized DIMMs matter */
|
|
|
|
*list = g_slist_prepend(*list, dev);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
object_child_foreach(obj, build_dimm_list, opaque);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2016-02-10 11:49:22 +03:00
|
|
|
static ram_addr_t get_current_ram_size(void)
|
|
|
|
{
|
2016-02-10 11:49:25 +03:00
|
|
|
GSList *list = NULL, *item;
|
2016-02-10 11:49:22 +03:00
|
|
|
ram_addr_t size = ram_size;
|
|
|
|
|
2016-02-10 11:49:26 +03:00
|
|
|
build_dimm_list(qdev_get_machine(), &list);
|
2016-02-10 11:49:25 +03:00
|
|
|
for (item = list; item; item = g_slist_next(item)) {
|
|
|
|
Object *obj = OBJECT(item->data);
|
2016-02-10 11:49:26 +03:00
|
|
|
if (!strcmp(object_get_typename(obj), TYPE_PC_DIMM)) {
|
|
|
|
size += object_property_get_int(obj, PC_DIMM_SIZE_PROP,
|
|
|
|
&error_abort);
|
|
|
|
}
|
2016-02-10 11:49:22 +03:00
|
|
|
}
|
2016-02-10 11:49:25 +03:00
|
|
|
g_slist_free(list);
|
2016-02-10 11:49:22 +03:00
|
|
|
|
|
|
|
return size;
|
|
|
|
}
|
|
|
|
|
2008-12-04 23:33:06 +03:00
|
|
|
static void virtio_balloon_set_config(VirtIODevice *vdev,
|
|
|
|
const uint8_t *config_data)
|
|
|
|
{
|
2013-03-27 13:49:14 +04:00
|
|
|
VirtIOBalloon *dev = VIRTIO_BALLOON(vdev);
|
2008-12-04 23:33:06 +03:00
|
|
|
struct virtio_balloon_config config;
|
2012-06-14 21:12:56 +04:00
|
|
|
uint32_t oldactual = dev->actual;
|
2014-11-17 08:11:09 +03:00
|
|
|
ram_addr_t vm_ram_size = get_current_ram_size();
|
|
|
|
|
2019-07-10 17:14:40 +03:00
|
|
|
memcpy(&config, config_data, virtio_balloon_config_size(dev));
|
virtio-balloon: fixed endianness bug in the config space
The specification for the virtio balloon device requres that the values
in the config space be encoded little-endian. This differs from most
virtio things, where guest-native endian is the norm.
Currently, the qemu virtio-balloon code correctly makes the conversion
on get_config(), but doesn't on set_config for the 'actual' field. The
kernel driver, on the other hand, correctly converts when setting the
actual field, but does not convert when reading the config space. The
upshot is that virtio-balloon will only work correctly if both host and
guest are LE, making all the conversions nops.
This patch corrects the qemu side, correctly doing host-native <-> LE
conversions when accessing the config space. This won't break any setups
that aren't already broken, and fixes the case of BE host, LE guest.
Fixing the BE guest case will require kernel fixes as well.
Signed-off-by: Alexey Kardashevskiy <aik@ozlabs.ru>
Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
Signed-off-by: Stefan Hajnoczi <stefanha@linux.vnet.ibm.com>
2011-04-07 07:02:04 +04:00
|
|
|
dev->actual = le32_to_cpu(config.actual);
|
2012-06-14 21:12:56 +04:00
|
|
|
if (dev->actual != oldactual) {
|
2014-11-17 08:11:09 +03:00
|
|
|
qapi_event_send_balloon_change(vm_ram_size -
|
2018-08-15 16:37:37 +03:00
|
|
|
((ram_addr_t) dev->actual << VIRTIO_BALLOON_PFN_SHIFT));
|
2012-06-14 21:12:56 +04:00
|
|
|
}
|
2014-11-17 08:11:10 +03:00
|
|
|
trace_virtio_balloon_set_config(dev->actual, oldactual);
|
2008-12-04 23:33:06 +03:00
|
|
|
}
|
|
|
|
|
2015-07-27 12:49:19 +03:00
|
|
|
static uint64_t virtio_balloon_get_features(VirtIODevice *vdev, uint64_t f,
|
|
|
|
Error **errp)
|
2008-12-04 23:33:06 +03:00
|
|
|
{
|
2015-06-15 13:52:52 +03:00
|
|
|
VirtIOBalloon *dev = VIRTIO_BALLOON(vdev);
|
|
|
|
f |= dev->host_features;
|
2015-06-04 13:34:32 +03:00
|
|
|
virtio_add_feature(&f, VIRTIO_BALLOON_F_STATS_VQ);
|
2018-12-11 11:24:53 +03:00
|
|
|
|
2010-01-10 14:52:53 +03:00
|
|
|
return f;
|
2008-12-04 23:33:06 +03:00
|
|
|
}
|
|
|
|
|
2011-10-21 17:41:37 +04:00
|
|
|
static void virtio_balloon_stat(void *opaque, BalloonInfo *info)
|
2011-07-20 11:49:07 +04:00
|
|
|
{
|
|
|
|
VirtIOBalloon *dev = opaque;
|
2014-11-17 08:11:09 +03:00
|
|
|
info->actual = get_current_ram_size() - ((uint64_t) dev->actual <<
|
|
|
|
VIRTIO_BALLOON_PFN_SHIFT);
|
2011-07-20 11:49:07 +04:00
|
|
|
}
|
|
|
|
|
balloon: Separate out stat and balloon handling
Passing on '0' as ballooning target to indicate retrieval of stats is
bad API. It also makes 'balloon 0' in the monitor cause a segfault.
Have two different functions handle the different functionality instead.
Detailed explanation from Markus's review:
1. do_info_balloon() is an info_async() method. It receives a callback
with argument, to be called exactly once (callback frees the
argument). It passes the callback via qemu_balloon_status() and
indirectly through qemu_balloon_event to virtio_balloon_to_target().
virtio_balloon_to_target() executes its balloon stats half. It
stores the callback in the device state.
If it can't send a stats request, it resets stats and calls the
callback right away.
Else, it sends a stats request. The device model runs the callback
when it receives the answer.
Works.
2. do_balloon() is a cmd_async() method. It receives a callback with
argument, to be called when the command completes. do_balloon()
calls it right before it succeeds. Odd, but should work.
Nevertheless, it passes the callback on via qemu_ballon() and
indirectly through qemu_balloon_event to virtio_balloon_to_target().
a. If the argument is non-zero, virtio_balloon_to_target() executes
its balloon half, which doesn't use the callback in any way.
Odd, but works.
b. If the argument is zero, virtio_balloon_to_target() executes its
balloon stats half, just like in 1. It either calls the callback
right away, or arranges for it to be called later.
Thus, the callback runs twice: use after free and double free.
Test case: start with -S -device virtio-balloon, execute "balloon 0" in
human monitor. Runs the callback first from virtio_balloon_to_target(),
then again from do_balloon().
Reported-by: Mike Cao <bcao@redhat.com>
Signed-off-by: Amit Shah <amit.shah@redhat.com>
Reviewed-by: Markus Armbruster <armbru@redhat.com>
2011-07-20 12:00:56 +04:00
|
|
|
static void virtio_balloon_to_target(void *opaque, ram_addr_t target)
|
2008-12-04 23:33:06 +03:00
|
|
|
{
|
2013-03-27 13:49:14 +04:00
|
|
|
VirtIOBalloon *dev = VIRTIO_BALLOON(opaque);
|
|
|
|
VirtIODevice *vdev = VIRTIO_DEVICE(dev);
|
2014-11-17 08:11:09 +03:00
|
|
|
ram_addr_t vm_ram_size = get_current_ram_size();
|
2008-12-04 23:33:06 +03:00
|
|
|
|
2014-11-17 08:11:09 +03:00
|
|
|
if (target > vm_ram_size) {
|
|
|
|
target = vm_ram_size;
|
2011-07-20 11:49:07 +04:00
|
|
|
}
|
2008-12-04 23:33:06 +03:00
|
|
|
if (target) {
|
2014-11-17 08:11:09 +03:00
|
|
|
dev->num_pages = (vm_ram_size - target) >> VIRTIO_BALLOON_PFN_SHIFT;
|
2013-03-27 13:49:14 +04:00
|
|
|
virtio_notify_config(vdev);
|
2008-12-04 23:33:06 +03:00
|
|
|
}
|
2014-11-17 08:11:10 +03:00
|
|
|
trace_virtio_balloon_to_target(target, dev->num_pages);
|
2008-12-04 23:33:06 +03:00
|
|
|
}
|
|
|
|
|
2016-10-27 20:36:37 +03:00
|
|
|
static int virtio_balloon_post_load_device(void *opaque, int version_id)
|
2014-06-24 21:20:08 +04:00
|
|
|
{
|
2016-10-27 20:36:37 +03:00
|
|
|
VirtIOBalloon *s = VIRTIO_BALLOON(opaque);
|
2016-03-29 17:00:49 +03:00
|
|
|
|
|
|
|
if (balloon_stats_enabled(s)) {
|
|
|
|
balloon_stats_change_timer(s, s->stats_poll_interval);
|
|
|
|
}
|
2008-12-04 23:33:06 +03:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2018-12-11 11:24:53 +03:00
|
|
|
static const VMStateDescription vmstate_virtio_balloon_free_page_report = {
|
|
|
|
.name = "virtio-balloon-device/free-page-report",
|
|
|
|
.version_id = 1,
|
|
|
|
.minimum_version_id = 1,
|
|
|
|
.needed = virtio_balloon_free_page_support,
|
|
|
|
.fields = (VMStateField[]) {
|
|
|
|
VMSTATE_UINT32(free_page_report_cmd_id, VirtIOBalloon),
|
|
|
|
VMSTATE_UINT32(free_page_report_status, VirtIOBalloon),
|
|
|
|
VMSTATE_END_OF_LIST()
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2016-10-27 20:36:37 +03:00
|
|
|
static const VMStateDescription vmstate_virtio_balloon_device = {
|
|
|
|
.name = "virtio-balloon-device",
|
|
|
|
.version_id = 1,
|
|
|
|
.minimum_version_id = 1,
|
|
|
|
.post_load = virtio_balloon_post_load_device,
|
|
|
|
.fields = (VMStateField[]) {
|
|
|
|
VMSTATE_UINT32(num_pages, VirtIOBalloon),
|
|
|
|
VMSTATE_UINT32(actual, VirtIOBalloon),
|
|
|
|
VMSTATE_END_OF_LIST()
|
|
|
|
},
|
2018-12-11 11:24:53 +03:00
|
|
|
.subsections = (const VMStateDescription * []) {
|
|
|
|
&vmstate_virtio_balloon_free_page_report,
|
|
|
|
NULL
|
|
|
|
}
|
2016-10-27 20:36:37 +03:00
|
|
|
};
|
|
|
|
|
2013-07-30 04:51:37 +04:00
|
|
|
static void virtio_balloon_device_realize(DeviceState *dev, Error **errp)
|
2008-12-04 23:33:06 +03:00
|
|
|
{
|
2013-07-30 04:51:37 +04:00
|
|
|
VirtIODevice *vdev = VIRTIO_DEVICE(dev);
|
2013-07-30 07:33:58 +04:00
|
|
|
VirtIOBalloon *s = VIRTIO_BALLOON(dev);
|
2011-07-27 10:59:33 +04:00
|
|
|
int ret;
|
2008-12-04 23:33:06 +03:00
|
|
|
|
2014-01-09 18:58:16 +04:00
|
|
|
virtio_init(vdev, "virtio-balloon", VIRTIO_ID_BALLOON,
|
2019-07-10 17:14:40 +03:00
|
|
|
virtio_balloon_config_size(s));
|
2008-12-04 23:33:06 +03:00
|
|
|
|
2011-07-27 10:59:33 +04:00
|
|
|
ret = qemu_add_balloon_handler(virtio_balloon_to_target,
|
|
|
|
virtio_balloon_stat, s);
|
2013-03-27 13:49:13 +04:00
|
|
|
|
2013-03-27 13:49:10 +04:00
|
|
|
if (ret < 0) {
|
balloon: improve error msg when adding second device
A VM supports only one balloon device, but due to several changes
in infrastructure the error message got messed up when trying
to add a second device. Fix it.
Before this fix
Command-line:
qemu-qmp: -device virtio-balloon-pci,id=balloon0: Another balloon device already registered
qemu-qmp: -device virtio-balloon-pci,id=balloon0: Adding balloon handler failed
qemu-qmp: -device virtio-balloon-pci,id=balloon0: Device 'virtio-balloon-pci' could not be initialized
HMP:
Another balloon device already registered
Adding balloon handler failed
Device 'virtio-balloon-pci' could not be initialized
QMP:
{ "execute": "device_add", "arguments": { "driver": "virtio-balloon-pci", "id": "balloon0" } }
{
"error": {
"class": "GenericError",
"desc": "Adding balloon handler failed"
}
}
After this fix
Command-line:
qemu-qmp: -device virtio-balloon-pci,id=balloon0: Only one balloon device is supported
qemu-qmp: -device virtio-balloon-pci,id=balloon0: Device 'virtio-balloon-pci' could not be initialized
HMP:
(qemu) device_add virtio-balloon-pci,id=balloon0
Only one balloon device is supported
Device 'virtio-balloon-pci' could not be initialized
(qemu)
QMP:
{ "execute": "device_add",
"arguments": { "driver": "virtio-balloon-pci", "id": "balloon0" } }
{
"error": {
"class": "GenericError",
"desc": "Only one balloon device is supported"
}
}
Signed-off-by: Luiz Capitulino <lcapitulino@redhat.com>
Reviewed-by: Eric Blake <eblake@redhat.com>
2015-03-31 20:00:26 +03:00
|
|
|
error_setg(errp, "Only one balloon device is supported");
|
2013-07-30 07:33:58 +04:00
|
|
|
virtio_cleanup(vdev);
|
2013-07-30 04:51:37 +04:00
|
|
|
return;
|
2013-03-27 13:49:10 +04:00
|
|
|
}
|
2011-07-27 10:59:33 +04:00
|
|
|
|
2013-03-27 13:49:13 +04:00
|
|
|
s->ivq = virtio_add_queue(vdev, 128, virtio_balloon_handle_output);
|
|
|
|
s->dvq = virtio_add_queue(vdev, 128, virtio_balloon_handle_output);
|
|
|
|
s->svq = virtio_add_queue(vdev, 128, virtio_balloon_receive_stats);
|
2008-12-04 23:33:06 +03:00
|
|
|
|
2018-12-11 11:24:53 +03:00
|
|
|
if (virtio_has_feature(s->host_features,
|
|
|
|
VIRTIO_BALLOON_F_FREE_PAGE_HINT)) {
|
|
|
|
s->free_page_vq = virtio_add_queue(vdev, VIRTQUEUE_MAX_SIZE,
|
|
|
|
virtio_balloon_handle_free_page_vq);
|
|
|
|
s->free_page_report_status = FREE_PAGE_REPORT_S_STOP;
|
|
|
|
s->free_page_report_cmd_id =
|
|
|
|
VIRTIO_BALLOON_FREE_PAGE_REPORT_CMD_ID_MIN;
|
|
|
|
s->free_page_report_notify.notify =
|
|
|
|
virtio_balloon_free_page_report_notify;
|
|
|
|
precopy_add_notifier(&s->free_page_report_notify);
|
|
|
|
if (s->iothread) {
|
|
|
|
object_ref(OBJECT(s->iothread));
|
|
|
|
s->free_page_bh = aio_bh_new(iothread_get_aio_context(s->iothread),
|
|
|
|
virtio_ballloon_get_free_page_hints, s);
|
|
|
|
qemu_mutex_init(&s->free_page_lock);
|
|
|
|
qemu_cond_init(&s->free_page_cond);
|
|
|
|
s->block_iothread = false;
|
|
|
|
} else {
|
|
|
|
/* Simply disable this feature if the iothread wasn't created. */
|
|
|
|
s->host_features &= ~(1 << VIRTIO_BALLOON_F_FREE_PAGE_HINT);
|
|
|
|
virtio_error(vdev, "iothread is missing");
|
|
|
|
}
|
|
|
|
}
|
2014-05-21 13:03:47 +04:00
|
|
|
reset_stats(s);
|
2013-03-27 13:49:10 +04:00
|
|
|
}
|
|
|
|
|
2013-07-30 05:50:44 +04:00
|
|
|
static void virtio_balloon_device_unrealize(DeviceState *dev, Error **errp)
|
2013-03-27 13:49:10 +04:00
|
|
|
{
|
2013-07-30 05:50:44 +04:00
|
|
|
VirtIODevice *vdev = VIRTIO_DEVICE(dev);
|
|
|
|
VirtIOBalloon *s = VIRTIO_BALLOON(dev);
|
2013-03-27 13:49:10 +04:00
|
|
|
|
2018-12-11 11:24:53 +03:00
|
|
|
if (virtio_balloon_free_page_support(s)) {
|
|
|
|
qemu_bh_delete(s->free_page_bh);
|
|
|
|
virtio_balloon_free_page_stop(s);
|
|
|
|
precopy_remove_notifier(&s->free_page_report_notify);
|
|
|
|
}
|
2013-03-27 13:49:10 +04:00
|
|
|
balloon_stats_destroy_timer(s);
|
|
|
|
qemu_remove_balloon_handler(s);
|
2019-12-04 10:31:55 +03:00
|
|
|
|
|
|
|
virtio_delete_queue(s->ivq);
|
|
|
|
virtio_delete_queue(s->dvq);
|
|
|
|
virtio_delete_queue(s->svq);
|
|
|
|
if (s->free_page_vq) {
|
|
|
|
virtio_delete_queue(s->free_page_vq);
|
|
|
|
}
|
2013-04-24 12:21:22 +04:00
|
|
|
virtio_cleanup(vdev);
|
2013-03-27 13:49:10 +04:00
|
|
|
}
|
|
|
|
|
2016-03-01 14:14:03 +03:00
|
|
|
static void virtio_balloon_device_reset(VirtIODevice *vdev)
|
|
|
|
{
|
|
|
|
VirtIOBalloon *s = VIRTIO_BALLOON(vdev);
|
|
|
|
|
2018-12-11 11:24:53 +03:00
|
|
|
if (virtio_balloon_free_page_support(s)) {
|
|
|
|
virtio_balloon_free_page_stop(s);
|
|
|
|
}
|
|
|
|
|
2016-03-01 14:14:03 +03:00
|
|
|
if (s->stats_vq_elem != NULL) {
|
2016-11-03 11:55:49 +03:00
|
|
|
virtqueue_unpop(s->svq, s->stats_vq_elem, 0);
|
2016-03-01 14:14:03 +03:00
|
|
|
g_free(s->stats_vq_elem);
|
|
|
|
s->stats_vq_elem = NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-09-07 18:20:49 +03:00
|
|
|
static void virtio_balloon_set_status(VirtIODevice *vdev, uint8_t status)
|
|
|
|
{
|
|
|
|
VirtIOBalloon *s = VIRTIO_BALLOON(vdev);
|
|
|
|
|
|
|
|
if (!s->stats_vq_elem && vdev->vm_running &&
|
|
|
|
(status & VIRTIO_CONFIG_S_DRIVER_OK) && virtqueue_rewind(s->svq, 1)) {
|
|
|
|
/* poll stats queue for the element we have discarded when the VM
|
|
|
|
* was stopped */
|
|
|
|
virtio_balloon_receive_stats(vdev, s->svq);
|
|
|
|
}
|
2018-12-11 11:24:53 +03:00
|
|
|
|
|
|
|
if (virtio_balloon_free_page_support(s)) {
|
|
|
|
/*
|
|
|
|
* The VM is woken up and the iothread was blocked, so signal it to
|
|
|
|
* continue.
|
|
|
|
*/
|
|
|
|
if (vdev->vm_running && s->block_iothread) {
|
|
|
|
qemu_mutex_lock(&s->free_page_lock);
|
|
|
|
s->block_iothread = false;
|
|
|
|
qemu_cond_signal(&s->free_page_cond);
|
|
|
|
qemu_mutex_unlock(&s->free_page_lock);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* The VM is stopped, block the iothread. */
|
|
|
|
if (!vdev->vm_running) {
|
|
|
|
qemu_mutex_lock(&s->free_page_lock);
|
|
|
|
s->block_iothread = true;
|
|
|
|
qemu_mutex_unlock(&s->free_page_lock);
|
|
|
|
}
|
|
|
|
}
|
2016-09-07 18:20:49 +03:00
|
|
|
}
|
|
|
|
|
2015-05-11 12:34:05 +03:00
|
|
|
static void virtio_balloon_instance_init(Object *obj)
|
|
|
|
{
|
|
|
|
VirtIOBalloon *s = VIRTIO_BALLOON(obj);
|
|
|
|
|
|
|
|
object_property_add(obj, "guest-stats", "guest statistics",
|
|
|
|
balloon_stats_get_all, NULL, NULL, s, NULL);
|
|
|
|
|
|
|
|
object_property_add(obj, "guest-stats-polling-interval", "int",
|
|
|
|
balloon_stats_get_poll_interval,
|
|
|
|
balloon_stats_set_poll_interval,
|
|
|
|
NULL, s, NULL);
|
|
|
|
}
|
|
|
|
|
2016-10-06 15:55:47 +03:00
|
|
|
static const VMStateDescription vmstate_virtio_balloon = {
|
|
|
|
.name = "virtio-balloon",
|
|
|
|
.minimum_version_id = 1,
|
|
|
|
.version_id = 1,
|
|
|
|
.fields = (VMStateField[]) {
|
|
|
|
VMSTATE_VIRTIO_DEVICE,
|
|
|
|
VMSTATE_END_OF_LIST()
|
|
|
|
},
|
|
|
|
};
|
2016-07-14 20:22:49 +03:00
|
|
|
|
2013-03-27 13:49:10 +04:00
|
|
|
static Property virtio_balloon_properties[] = {
|
2015-06-15 13:52:52 +03:00
|
|
|
DEFINE_PROP_BIT("deflate-on-oom", VirtIOBalloon, host_features,
|
|
|
|
VIRTIO_BALLOON_F_DEFLATE_ON_OOM, false),
|
2018-12-11 11:24:53 +03:00
|
|
|
DEFINE_PROP_BIT("free-page-hint", VirtIOBalloon, host_features,
|
|
|
|
VIRTIO_BALLOON_F_FREE_PAGE_HINT, false),
|
2019-07-10 17:14:40 +03:00
|
|
|
/* QEMU 4.0 accidentally changed the config size even when free-page-hint
|
|
|
|
* is disabled, resulting in QEMU 3.1 migration incompatibility. This
|
|
|
|
* property retains this quirk for QEMU 4.1 machine types.
|
|
|
|
*/
|
|
|
|
DEFINE_PROP_BOOL("qemu-4-0-config-size", VirtIOBalloon,
|
|
|
|
qemu_4_0_config_size, false),
|
2018-12-11 11:24:53 +03:00
|
|
|
DEFINE_PROP_LINK("iothread", VirtIOBalloon, iothread, TYPE_IOTHREAD,
|
|
|
|
IOThread *),
|
2013-03-27 13:49:10 +04:00
|
|
|
DEFINE_PROP_END_OF_LIST(),
|
|
|
|
};
|
|
|
|
|
|
|
|
static void virtio_balloon_class_init(ObjectClass *klass, void *data)
|
|
|
|
{
|
|
|
|
DeviceClass *dc = DEVICE_CLASS(klass);
|
|
|
|
VirtioDeviceClass *vdc = VIRTIO_DEVICE_CLASS(klass);
|
2013-07-30 04:51:37 +04:00
|
|
|
|
2020-01-10 18:30:32 +03:00
|
|
|
device_class_set_props(dc, virtio_balloon_properties);
|
2016-07-14 20:22:49 +03:00
|
|
|
dc->vmsd = &vmstate_virtio_balloon;
|
2013-07-29 18:17:45 +04:00
|
|
|
set_bit(DEVICE_CATEGORY_MISC, dc->categories);
|
2013-07-30 04:51:37 +04:00
|
|
|
vdc->realize = virtio_balloon_device_realize;
|
2013-07-30 05:50:44 +04:00
|
|
|
vdc->unrealize = virtio_balloon_device_unrealize;
|
2016-03-01 14:14:03 +03:00
|
|
|
vdc->reset = virtio_balloon_device_reset;
|
2013-03-27 13:49:10 +04:00
|
|
|
vdc->get_config = virtio_balloon_get_config;
|
|
|
|
vdc->set_config = virtio_balloon_set_config;
|
|
|
|
vdc->get_features = virtio_balloon_get_features;
|
2016-09-07 18:20:49 +03:00
|
|
|
vdc->set_status = virtio_balloon_set_status;
|
2016-10-27 20:36:37 +03:00
|
|
|
vdc->vmsd = &vmstate_virtio_balloon_device;
|
2013-03-27 13:49:10 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
static const TypeInfo virtio_balloon_info = {
|
|
|
|
.name = TYPE_VIRTIO_BALLOON,
|
|
|
|
.parent = TYPE_VIRTIO_DEVICE,
|
|
|
|
.instance_size = sizeof(VirtIOBalloon),
|
2015-05-11 12:34:05 +03:00
|
|
|
.instance_init = virtio_balloon_instance_init,
|
2013-03-27 13:49:10 +04:00
|
|
|
.class_init = virtio_balloon_class_init,
|
|
|
|
};
|
|
|
|
|
|
|
|
static void virtio_register_types(void)
|
|
|
|
{
|
|
|
|
type_register_static(&virtio_balloon_info);
|
|
|
|
}
|
|
|
|
|
|
|
|
type_init(virtio_register_types)
|