2008-12-05 04:33:06 +08:00
|
|
|
/*
|
2011-07-20 16:07:01 +08:00
|
|
|
* Virtio Balloon Device
|
2008-12-05 04:33:06 +08:00
|
|
|
*
|
|
|
|
* Copyright IBM, Corp. 2008
|
2011-07-20 16:07:01 +08:00
|
|
|
* Copyright (C) 2011 Red Hat, Inc.
|
|
|
|
* Copyright (C) 2011 Amit Shah <amit.shah@redhat.com>
|
2008-12-05 04:33:06 +08: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.
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
|
2012-12-18 01:20:00 +08:00
|
|
|
#include "qemu/iov.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 10:14:57 +08:00
|
|
|
#include "qemu/timer.h"
|
2008-12-05 04:33:06 +08:00
|
|
|
#include "qemu-common.h"
|
2013-02-04 22:40:22 +08:00
|
|
|
#include "hw/virtio.h"
|
|
|
|
#include "hw/pc.h"
|
2008-12-05 04:33:06 +08:00
|
|
|
#include "cpu.h"
|
2012-12-18 01:20:04 +08:00
|
|
|
#include "sysemu/balloon.h"
|
2013-02-04 22:40:22 +08:00
|
|
|
#include "hw/virtio-balloon.h"
|
2012-12-18 01:20:04 +08:00
|
|
|
#include "sysemu/kvm.h"
|
2012-12-18 01:19:49 +08:00
|
|
|
#include "exec/address-spaces.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 10:14:57 +08:00
|
|
|
#include "qapi/visitor.h"
|
2008-12-05 04:33:06 +08:00
|
|
|
|
|
|
|
#if defined(__linux__)
|
|
|
|
#include <sys/mman.h>
|
|
|
|
#endif
|
|
|
|
|
2013-03-27 17:49:10 +08:00
|
|
|
#include "hw/virtio-bus.h"
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Will be modified later in the serie.
|
|
|
|
*/
|
2008-12-05 04:33:06 +08:00
|
|
|
static VirtIOBalloon *to_virtio_balloon(VirtIODevice *vdev)
|
|
|
|
{
|
|
|
|
return (VirtIOBalloon *)vdev;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void balloon_page(void *addr, int deflate)
|
|
|
|
{
|
|
|
|
#if defined(__linux__)
|
|
|
|
if (!kvm_enabled() || kvm_has_sync_mmu())
|
2010-09-25 19:26:05 +08:00
|
|
|
qemu_madvise(addr, TARGET_PAGE_SIZE,
|
|
|
|
deflate ? QEMU_MADV_WILLNEED : QEMU_MADV_DONTNEED);
|
2008-12-05 04:33:06 +08:00
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
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 10:14:57 +08: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",
|
|
|
|
[VIRTIO_BALLOON_S_NR] = NULL
|
|
|
|
};
|
|
|
|
|
2010-01-27 04:17:35 +08:00
|
|
|
/*
|
|
|
|
* reset_stats - Mark all items in the stats array as unset
|
|
|
|
*
|
|
|
|
* This function needs to be called at device intialization and before
|
|
|
|
* before updating to a set of newly-generated stats. This will ensure that no
|
|
|
|
* 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 10:14:57 +08:00
|
|
|
static bool balloon_stats_supported(const VirtIOBalloon *s)
|
|
|
|
{
|
|
|
|
return s->vdev.guest_features & (1 << VIRTIO_BALLOON_F_STATS_VQ);
|
|
|
|
}
|
|
|
|
|
|
|
|
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)) {
|
|
|
|
qemu_del_timer(s->stats_timer);
|
|
|
|
qemu_free_timer(s->stats_timer);
|
|
|
|
s->stats_timer = NULL;
|
|
|
|
s->stats_poll_interval = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void balloon_stats_change_timer(VirtIOBalloon *s, int secs)
|
|
|
|
{
|
|
|
|
qemu_mod_timer(s->stats_timer, qemu_get_clock_ms(vm_clock) + secs * 1000);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void balloon_stats_poll_cb(void *opaque)
|
|
|
|
{
|
|
|
|
VirtIOBalloon *s = opaque;
|
|
|
|
|
|
|
|
if (!balloon_stats_supported(s)) {
|
|
|
|
/* re-schedule */
|
|
|
|
balloon_stats_change_timer(s, s->stats_poll_interval);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
virtqueue_push(s->svq, &s->stats_vq_elem, s->stats_vq_offset);
|
|
|
|
virtio_notify(&s->vdev, s->svq);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void balloon_stats_get_all(Object *obj, struct Visitor *v,
|
|
|
|
void *opaque, const char *name, Error **errp)
|
|
|
|
{
|
|
|
|
VirtIOBalloon *s = opaque;
|
|
|
|
int i;
|
|
|
|
|
|
|
|
if (!s->stats_last_update) {
|
|
|
|
error_setg(errp, "guest hasn't updated any stats yet");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
visit_start_struct(v, NULL, "guest-stats", name, 0, errp);
|
|
|
|
visit_type_int(v, &s->stats_last_update, "last-update", errp);
|
|
|
|
|
|
|
|
visit_start_struct(v, NULL, NULL, "stats", 0, errp);
|
|
|
|
for (i = 0; i < VIRTIO_BALLOON_S_NR; i++) {
|
|
|
|
visit_type_int64(v, (int64_t *) &s->stats[i], balloon_stat_names[i],
|
|
|
|
errp);
|
|
|
|
}
|
|
|
|
visit_end_struct(v, errp);
|
|
|
|
|
|
|
|
visit_end_struct(v, errp);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void balloon_stats_get_poll_interval(Object *obj, struct Visitor *v,
|
|
|
|
void *opaque, const char *name,
|
|
|
|
Error **errp)
|
|
|
|
{
|
|
|
|
VirtIOBalloon *s = opaque;
|
|
|
|
visit_type_int(v, &s->stats_poll_interval, name, errp);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void balloon_stats_set_poll_interval(Object *obj, struct Visitor *v,
|
|
|
|
void *opaque, const char *name,
|
|
|
|
Error **errp)
|
|
|
|
{
|
|
|
|
VirtIOBalloon *s = opaque;
|
|
|
|
int64_t value;
|
|
|
|
|
|
|
|
visit_type_int(v, &value, name, errp);
|
|
|
|
if (error_is_set(errp)) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (value < 0) {
|
|
|
|
error_setg(errp, "timer value must be greater than zero");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
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);
|
|
|
|
s->stats_timer = qemu_new_timer_ms(vm_clock, balloon_stats_poll_cb, s);
|
|
|
|
s->stats_poll_interval = value;
|
|
|
|
balloon_stats_change_timer(s, 0);
|
|
|
|
}
|
|
|
|
|
2008-12-05 04:33:06 +08:00
|
|
|
static void virtio_balloon_handle_output(VirtIODevice *vdev, VirtQueue *vq)
|
|
|
|
{
|
|
|
|
VirtIOBalloon *s = to_virtio_balloon(vdev);
|
|
|
|
VirtQueueElement elem;
|
2011-12-19 19:18:13 +08:00
|
|
|
MemoryRegionSection section;
|
2008-12-05 04:33:06 +08:00
|
|
|
|
|
|
|
while (virtqueue_pop(vq, &elem)) {
|
|
|
|
size_t offset = 0;
|
|
|
|
uint32_t pfn;
|
|
|
|
|
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 22:05:12 +08:00
|
|
|
while (iov_to_buf(elem.out_sg, elem.out_num, offset, &pfn, 4) == 4) {
|
2009-10-02 05:12:16 +08:00
|
|
|
ram_addr_t pa;
|
|
|
|
ram_addr_t addr;
|
2008-12-05 04:33:06 +08:00
|
|
|
|
2009-10-02 05:12:16 +08:00
|
|
|
pa = (ram_addr_t)ldl_p(&pfn) << VIRTIO_BALLOON_PFN_SHIFT;
|
2008-12-05 04:33:06 +08:00
|
|
|
offset += 4;
|
|
|
|
|
2011-12-19 19:18:13 +08:00
|
|
|
/* FIXME: remove get_system_memory(), but how? */
|
|
|
|
section = memory_region_find(get_system_memory(), pa, 1);
|
|
|
|
if (!section.size || !memory_region_is_ram(section.mr))
|
2008-12-05 04:33:06 +08:00
|
|
|
continue;
|
|
|
|
|
2011-12-19 19:18:13 +08:00
|
|
|
/* Using memory_region_get_ram_ptr is bending the rules a bit, but
|
2009-04-10 22:29:45 +08:00
|
|
|
should be OK because we only want a single page. */
|
2011-12-19 19:18:13 +08:00
|
|
|
addr = section.offset_within_region;
|
|
|
|
balloon_page(memory_region_get_ram_ptr(section.mr) + addr,
|
|
|
|
!!(vq == s->dvq));
|
2008-12-05 04:33:06 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
virtqueue_push(vq, &elem, offset);
|
|
|
|
virtio_notify(vdev, vq);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-01-27 04:17:35 +08:00
|
|
|
static void virtio_balloon_receive_stats(VirtIODevice *vdev, VirtQueue *vq)
|
|
|
|
{
|
|
|
|
VirtIOBalloon *s = DO_UPCAST(VirtIOBalloon, vdev, vdev);
|
|
|
|
VirtQueueElement *elem = &s->stats_vq_elem;
|
|
|
|
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 10:14:57 +08:00
|
|
|
qemu_timeval tv;
|
2010-01-27 04:17:35 +08:00
|
|
|
|
|
|
|
if (!virtqueue_pop(vq, 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 10:14:57 +08:00
|
|
|
goto out;
|
2010-01-27 04:17:35 +08: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 22:05:12 +08:00
|
|
|
while (iov_to_buf(elem->out_sg, elem->out_num, offset, &stat, sizeof(stat))
|
2010-04-27 20:34:06 +08:00
|
|
|
== sizeof(stat)) {
|
2010-01-27 04:17:35 +08:00
|
|
|
uint16_t tag = tswap16(stat.tag);
|
|
|
|
uint64_t val = tswap64(stat.val);
|
|
|
|
|
|
|
|
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 10:14:57 +08:00
|
|
|
|
|
|
|
if (qemu_gettimeofday(&tv) < 0) {
|
|
|
|
fprintf(stderr, "warning: %s: failed to get time of day\n", __func__);
|
|
|
|
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-27 04:17:35 +08:00
|
|
|
}
|
|
|
|
|
2008-12-05 04:33:06 +08:00
|
|
|
static void virtio_balloon_get_config(VirtIODevice *vdev, uint8_t *config_data)
|
|
|
|
{
|
|
|
|
VirtIOBalloon *dev = to_virtio_balloon(vdev);
|
|
|
|
struct virtio_balloon_config config;
|
|
|
|
|
|
|
|
config.num_pages = cpu_to_le32(dev->num_pages);
|
|
|
|
config.actual = cpu_to_le32(dev->actual);
|
|
|
|
|
|
|
|
memcpy(config_data, &config, 8);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void virtio_balloon_set_config(VirtIODevice *vdev,
|
|
|
|
const uint8_t *config_data)
|
|
|
|
{
|
|
|
|
VirtIOBalloon *dev = to_virtio_balloon(vdev);
|
|
|
|
struct virtio_balloon_config config;
|
2012-06-15 01:12:56 +08:00
|
|
|
uint32_t oldactual = dev->actual;
|
2008-12-05 04:33:06 +08:00
|
|
|
memcpy(&config, config_data, 8);
|
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 11:02:04 +08:00
|
|
|
dev->actual = le32_to_cpu(config.actual);
|
2012-06-15 01:12:56 +08:00
|
|
|
if (dev->actual != oldactual) {
|
|
|
|
qemu_balloon_changed(ram_size -
|
|
|
|
(dev->actual << VIRTIO_BALLOON_PFN_SHIFT));
|
|
|
|
}
|
2008-12-05 04:33:06 +08:00
|
|
|
}
|
|
|
|
|
2010-01-10 19:52:53 +08:00
|
|
|
static uint32_t virtio_balloon_get_features(VirtIODevice *vdev, uint32_t f)
|
2008-12-05 04:33:06 +08:00
|
|
|
{
|
2010-01-27 04:17:35 +08:00
|
|
|
f |= (1 << VIRTIO_BALLOON_F_STATS_VQ);
|
2010-01-10 19:52:53 +08:00
|
|
|
return f;
|
2008-12-05 04:33:06 +08:00
|
|
|
}
|
|
|
|
|
2011-10-21 21:41:37 +08:00
|
|
|
static void virtio_balloon_stat(void *opaque, BalloonInfo *info)
|
2011-07-20 15:49:07 +08:00
|
|
|
{
|
|
|
|
VirtIOBalloon *dev = opaque;
|
2011-10-21 21:41:37 +08:00
|
|
|
info->actual = ram_size - ((uint64_t) dev->actual <<
|
|
|
|
VIRTIO_BALLOON_PFN_SHIFT);
|
2011-07-20 15:49:07 +08: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 16:00:56 +08:00
|
|
|
static void virtio_balloon_to_target(void *opaque, ram_addr_t target)
|
2008-12-05 04:33:06 +08:00
|
|
|
{
|
|
|
|
VirtIOBalloon *dev = opaque;
|
|
|
|
|
2011-07-20 15:49:07 +08:00
|
|
|
if (target > ram_size) {
|
2008-12-05 04:33:06 +08:00
|
|
|
target = ram_size;
|
2011-07-20 15:49:07 +08:00
|
|
|
}
|
2008-12-05 04:33:06 +08:00
|
|
|
if (target) {
|
|
|
|
dev->num_pages = (ram_size - target) >> VIRTIO_BALLOON_PFN_SHIFT;
|
|
|
|
virtio_notify_config(&dev->vdev);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void virtio_balloon_save(QEMUFile *f, void *opaque)
|
|
|
|
{
|
|
|
|
VirtIOBalloon *s = opaque;
|
|
|
|
|
|
|
|
virtio_save(&s->vdev, f);
|
|
|
|
|
|
|
|
qemu_put_be32(f, s->num_pages);
|
|
|
|
qemu_put_be32(f, s->actual);
|
|
|
|
}
|
|
|
|
|
|
|
|
static int virtio_balloon_load(QEMUFile *f, void *opaque, int version_id)
|
|
|
|
{
|
|
|
|
VirtIOBalloon *s = opaque;
|
2012-05-16 18:21:35 +08:00
|
|
|
int ret;
|
2008-12-05 04:33:06 +08:00
|
|
|
|
|
|
|
if (version_id != 1)
|
|
|
|
return -EINVAL;
|
|
|
|
|
2012-05-16 18:21:35 +08:00
|
|
|
ret = virtio_load(&s->vdev, f);
|
|
|
|
if (ret) {
|
|
|
|
return ret;
|
|
|
|
}
|
2008-12-05 04:33:06 +08:00
|
|
|
|
|
|
|
s->num_pages = qemu_get_be32(f);
|
|
|
|
s->actual = qemu_get_be32(f);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2013-03-27 17:49:13 +08:00
|
|
|
static int virtio_balloon_device_init(VirtIODevice *vdev)
|
2008-12-05 04:33:06 +08:00
|
|
|
{
|
2013-03-27 17:49:13 +08:00
|
|
|
DeviceState *qdev = DEVICE(vdev);
|
|
|
|
VirtIOBalloon *s = VIRTIO_BALLOON(vdev);
|
2011-07-27 14:59:33 +08:00
|
|
|
int ret;
|
2008-12-05 04:33:06 +08:00
|
|
|
|
2013-03-27 17:49:13 +08:00
|
|
|
virtio_init(vdev, "virtio-balloon", VIRTIO_ID_BALLOON, 8);
|
2008-12-05 04:33:06 +08:00
|
|
|
|
|
|
|
s->vdev.get_config = virtio_balloon_get_config;
|
|
|
|
s->vdev.set_config = virtio_balloon_set_config;
|
|
|
|
s->vdev.get_features = virtio_balloon_get_features;
|
|
|
|
|
2011-07-27 14:59:33 +08:00
|
|
|
ret = qemu_add_balloon_handler(virtio_balloon_to_target,
|
|
|
|
virtio_balloon_stat, s);
|
2013-03-27 17:49:13 +08:00
|
|
|
|
2013-03-27 17:49:10 +08:00
|
|
|
if (ret < 0) {
|
|
|
|
virtio_common_cleanup(VIRTIO_DEVICE(s));
|
2013-03-27 17:49:13 +08:00
|
|
|
return -1;
|
2013-03-27 17:49:10 +08:00
|
|
|
}
|
2011-07-27 14:59:33 +08:00
|
|
|
|
2013-03-27 17:49:13 +08: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-05 04:33:06 +08:00
|
|
|
|
2013-03-27 17:49:13 +08:00
|
|
|
s->qdev = qdev;
|
|
|
|
register_savevm(qdev, "virtio-balloon", -1, 1,
|
2010-06-26 01:09:07 +08:00
|
|
|
virtio_balloon_save, virtio_balloon_load, s);
|
2008-12-05 04:33:06 +08:00
|
|
|
|
2013-03-27 17:49:13 +08:00
|
|
|
object_property_add(OBJECT(qdev), "guest-stats", "guest statistics",
|
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 10:14:57 +08:00
|
|
|
balloon_stats_get_all, NULL, NULL, s, NULL);
|
|
|
|
|
2013-03-27 17:49:13 +08:00
|
|
|
object_property_add(OBJECT(qdev), "guest-stats-polling-interval", "int",
|
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 10:14:57 +08:00
|
|
|
balloon_stats_get_poll_interval,
|
|
|
|
balloon_stats_set_poll_interval,
|
|
|
|
NULL, s, NULL);
|
2013-03-27 17:49:10 +08:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int virtio_balloon_device_exit(DeviceState *qdev)
|
|
|
|
{
|
|
|
|
VirtIOBalloon *s = VIRTIO_BALLOON(qdev);
|
|
|
|
VirtIODevice *vdev = VIRTIO_DEVICE(qdev);
|
|
|
|
|
|
|
|
balloon_stats_destroy_timer(s);
|
|
|
|
qemu_remove_balloon_handler(s);
|
|
|
|
unregister_savevm(qdev, "virtio-balloon", s);
|
|
|
|
virtio_common_cleanup(vdev);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static Property virtio_balloon_properties[] = {
|
|
|
|
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);
|
|
|
|
dc->exit = virtio_balloon_device_exit;
|
|
|
|
dc->props = virtio_balloon_properties;
|
|
|
|
vdc->init = virtio_balloon_device_init;
|
|
|
|
vdc->get_config = virtio_balloon_get_config;
|
|
|
|
vdc->set_config = virtio_balloon_set_config;
|
|
|
|
vdc->get_features = virtio_balloon_get_features;
|
|
|
|
}
|
|
|
|
|
|
|
|
static const TypeInfo virtio_balloon_info = {
|
|
|
|
.name = TYPE_VIRTIO_BALLOON,
|
|
|
|
.parent = TYPE_VIRTIO_DEVICE,
|
|
|
|
.instance_size = sizeof(VirtIOBalloon),
|
|
|
|
.class_init = virtio_balloon_class_init,
|
|
|
|
};
|
|
|
|
|
|
|
|
static void virtio_register_types(void)
|
|
|
|
{
|
|
|
|
type_register_static(&virtio_balloon_info);
|
|
|
|
}
|
|
|
|
|
|
|
|
type_init(virtio_register_types)
|