@@ -1,6 +1,34 @@
QEMU Monitor Protocol Events
============================
+BALLOON_MEMORY_STATS
+--------------------
+
+Emitted when memory statistics information is made available by the guest.
+
+Data:
+
+- "memory-swapped-in": number of pages swapped in within the guest (json-int)
+- "memory-swapped-out": number of pages swapped out within the guest (json-int)
+- "major-page-faults": number of major page faults within the guest (json-int)
+- "minor-page-faults": number of minor page faults within the guest (json-int)
+- "memory-free": amount of memory (in bytes) free in the guest (json-int)
+- "memory-total": amount of memory (in bytes) visible to the guest (json-int)
+
+Example:
+
+{ "event": "BALLOON_MEMORY_STATS",
+ "data": { "memory-free": 847941632,
+ "major-page-faults": 225,
+ "memory-swapped-in": 0,
+ "minor-page-faults": 222317,
+ "memory-total": 1045516288,
+ "memory-swapped-out": 0 },
+ "timestamp": { "seconds": 1265044230, "microseconds": 450486 } }
+
+Note: The balloon-get-memory-stats command must be issued to tell the guest
+ to make memory statistics available.
+
BLOCK_IO_ERROR
--------------
@@ -33,12 +33,15 @@
static QEMUBalloonEvent *balloon_event_fn;
static QEMUBalloonInfo *balloon_info_fn;
+static QEMUBalloonStats *balloon_stats_fn;
static void *balloon_opaque;
int qemu_add_balloon_handler(QEMUBalloonEvent *event_func,
- QEMUBalloonInfo *info_func, void *opaque)
+ QEMUBalloonInfo *info_func,
+ QEMUBalloonStats *stats_func, void *opaque)
{
- if (balloon_event_fn || balloon_info_fn || balloon_opaque) {
+ if (balloon_event_fn || balloon_info_fn || balloon_stats_fn ||
+ balloon_opaque) {
/* We're already registered one balloon handler. How many can
* a guest really have?
*/
@@ -47,6 +50,7 @@ int qemu_add_balloon_handler(QEMUBalloonEvent *event_func,
}
balloon_event_fn = event_func;
balloon_info_fn = info_func;
+ balloon_stats_fn = stats_func;
balloon_opaque = opaque;
return 0;
}
@@ -58,6 +62,7 @@ void qemu_remove_balloon_handler(void *opaque)
}
balloon_event_fn = NULL;
balloon_info_fn = NULL;
+ balloon_stats_fn = NULL;
balloon_opaque = NULL;
}
@@ -80,6 +85,28 @@ static int qemu_balloon_info(BalloonInfo *info)
return 1;
}
+static int qemu_balloon_stats(void)
+{
+ if (!balloon_stats_fn) {
+ return 0;
+ }
+ balloon_stats_fn(balloon_opaque);
+ return 1;
+}
+
+void qmp_balloon_get_memory_stats(Error **errp)
+{
+ if (kvm_enabled() && !kvm_has_sync_mmu()) {
+ error_set(errp, QERR_KVM_MISSING_CAP, "synchronous MMU", "balloon");
+ return;
+ }
+
+ if (qemu_balloon_stats() == 0) {
+ error_set(errp, QERR_DEVICE_NOT_ACTIVE, "balloon");
+ return;
+ }
+}
+
BalloonInfo *qmp_query_balloon(Error **errp)
{
BalloonInfo *info;
@@ -18,9 +18,11 @@
typedef void (QEMUBalloonEvent)(void *opaque, ram_addr_t target);
typedef void (QEMUBalloonInfo)(void *opaque, BalloonInfo *info);
+typedef void (QEMUBalloonStats)(void *opaque);
int qemu_add_balloon_handler(QEMUBalloonEvent *event_func,
- QEMUBalloonInfo *info_func, void *opaque);
+ QEMUBalloonInfo *info_func, QEMUBalloonStats *stats_func,
+ void *opaque);
void qemu_remove_balloon_handler(void *opaque);
#endif
@@ -22,6 +22,8 @@
#include "virtio-balloon.h"
#include "kvm.h"
#include "exec-memory.h"
+#include "monitor.h"
+#include "qemu-objects.h"
#if defined(__linux__)
#include <sys/mman.h>
@@ -104,8 +106,10 @@ static void virtio_balloon_handle_output(VirtIODevice *vdev, VirtQueue *vq)
static void virtio_balloon_receive_stats(VirtIODevice *vdev, VirtQueue *vq)
{
VirtIOBalloon *s = DO_UPCAST(VirtIOBalloon, vdev, vdev);
+ VirtIOBalloon *dev = s;
VirtQueueElement *elem = &s->stats_vq_elem;
VirtIOBalloonStat stat;
+ QObject *stats_obj;
size_t offset = 0;
if (!virtqueue_pop(vq, elem)) {
@@ -128,6 +132,22 @@ static void virtio_balloon_receive_stats(VirtIODevice *vdev, VirtQueue *vq)
s->stats[tag] = val;
}
s->stats_vq_offset = offset;
+
+ stats_obj = qobject_from_jsonf("{ 'memory-swapped-in': %" PRId64 ", "
+ "'memory-swapped-out': %" PRId64 ", "
+ "'memory-free': %" PRId64 ", "
+ "'memory-total': %" PRId64 ", "
+ "'major-page-faults': %" PRId64 ", "
+ "'minor-page-faults': %" PRId64 " }",
+ dev->stats[VIRTIO_BALLOON_S_SWAP_IN],
+ dev->stats[VIRTIO_BALLOON_S_SWAP_OUT],
+ dev->stats[VIRTIO_BALLOON_S_MEMFREE],
+ dev->stats[VIRTIO_BALLOON_S_MEMTOT],
+ dev->stats[VIRTIO_BALLOON_S_MAJFLT],
+ dev->stats[VIRTIO_BALLOON_S_MINFLT]);
+
+ monitor_protocol_event(QEVENT_BALLOON_STATS, stats_obj);
+ qobject_decref(stats_obj);
}
static void virtio_balloon_get_config(VirtIODevice *vdev, uint8_t *config_data)
@@ -156,31 +176,25 @@ static uint32_t virtio_balloon_get_features(VirtIODevice *vdev, uint32_t f)
return f;
}
-static void virtio_balloon_info(void *opaque, BalloonInfo *info)
+static void virtio_balloon_stats(void *opaque)
{
VirtIOBalloon *dev = opaque;
-#if 0
- /* Disable guest-provided stats for now. For more details please check:
- * https://bugzilla.redhat.com/show_bug.cgi?id=623903
- *
- * If you do enable it (which is probably not going to happen as we
- * need a new command for it), remember that you also need to fill the
- * appropriate members of the BalloonInfo structure so that the stats
- * are returned to the client.
- */
if (dev->vdev.guest_features & (1 << VIRTIO_BALLOON_F_STATS_VQ)) {
virtqueue_push(dev->svq, &dev->stats_vq_elem, dev->stats_vq_offset);
virtio_notify(&dev->vdev, dev->svq);
return;
}
-#endif
/* Stats are not supported. Clear out any stale values that might
* have been set by a more featureful guest kernel.
*/
reset_stats(dev);
+}
+static void virtio_balloon_info(void *opaque, BalloonInfo *info)
+{
+ VirtIOBalloon *dev = opaque;
info->actual = ram_size - ((uint64_t) dev->actual <<
VIRTIO_BALLOON_PFN_SHIFT);
}
@@ -236,7 +250,8 @@ VirtIODevice *virtio_balloon_init(DeviceState *dev)
s->vdev.get_features = virtio_balloon_get_features;
ret = qemu_add_balloon_handler(virtio_balloon_to_target,
- virtio_balloon_info, s);
+ virtio_balloon_info,
+ virtio_balloon_stats, s);
if (ret < 0) {
virtio_cleanup(&s->vdev);
return NULL;
@@ -479,6 +479,9 @@ void monitor_protocol_event(MonitorEvent event, QObject *data)
case QEVENT_SPICE_DISCONNECTED:
event_name = "SPICE_DISCONNECTED";
break;
+ case QEVENT_BALLOON_STATS:
+ event_name = "BALLOON_MEMORY_STATS";
+ break;
default:
abort();
break;
@@ -35,6 +35,7 @@ typedef enum MonitorEvent {
QEVENT_SPICE_CONNECTED,
QEVENT_SPICE_INITIALIZED,
QEVENT_SPICE_DISCONNECTED,
+ QEVENT_BALLOON_STATS,
QEVENT_MAX,
} MonitorEvent;
@@ -1256,3 +1256,24 @@
{ 'command': 'qom-set',
'data': { 'path': 'str', 'property': 'str', 'value': 'visitor' },
'gen': 'no' }
+
+##
+# @balloon-get-memory-stats
+#
+# Ask the guest's balloon driver for guest memory statistics.
+#
+# This command will only get the process started and will return immediately.
+# The BALLOON_MEMORY_STATS event will be emitted when the statistics
+# information is returned by the guest.
+#
+# Returns: nothing on success
+# If the balloon driver is enabled but not functional because the KVM
+# kernel module cannot support it, KvmMissingCap
+# If no balloon device is present, DeviceNotActive
+#
+# Notes: There's no guarantees the guest will ever respond, thus the
+# BALLOON_MEMORY_STATS event may never be emitted.
+#
+# Since: 1.1
+##
+{ 'command': 'balloon-get-memory-stats' }
@@ -2027,3 +2027,9 @@ EQMP
.args_type = "path:s,property:s",
.mhandler.cmd_new = qmp_qom_get,
},
+
+ {
+ .name = "balloon-get-memory-stats",
+ .args_type = "",
+ .mhandler.cmd_new = qmp_marshal_input_balloon_get_memory_stats,
+ },
This commit adds a QMP API for the guest provided memory statistics (long disabled by commit 07b0403dfc2b2ac179ae5b48105096cc2d03375a). The approach taken by the original commit (625a5befc2e3200b396594f002218d235e375da5) was to extend the query-balloon command. That approach introduced a severe bug though, because query-balloon would hang if the guest didn't respond. The approach taken by this commit is asynchronous and thus avoids any QMP hangs. First, a client has to issue the balloon-get-memory-stats command. That command gets the process started by only sending a request to the guest. balloon-get-memory-stats doesn't block. When the memory stats is made available by the guest, it's returned to the client as an QMP event. Signed-off-by: Luiz Capitulino <lcapitulino@redhat.com> --- QMP/qmp-events.txt | 28 ++++++++++++++++++++++++++++ balloon.c | 31 +++++++++++++++++++++++++++++-- balloon.h | 4 +++- hw/virtio-balloon.c | 39 +++++++++++++++++++++++++++------------ monitor.c | 3 +++ monitor.h | 1 + qapi-schema.json | 21 +++++++++++++++++++++ qmp-commands.hx | 6 ++++++ 8 files changed, 118 insertions(+), 15 deletions(-)