From: "Maciej S. Szmigiero" <maciej.szmigiero@oracle.com>
Used by the hv-balloon driver for (optional) guest memory status reports.
Acked-by: David Hildenbrand <david@redhat.com>
Signed-off-by: Maciej S. Szmigiero <maciej.szmigiero@oracle.com>
---
hw/hyperv/hv-balloon-stub.c | 19 ++++++++++++
hw/hyperv/hv-balloon.c | 30 +++++++++++++++++-
hw/hyperv/meson.build | 2 +-
monitor/monitor.c | 1 +
qapi/machine.json | 62 +++++++++++++++++++++++++++++++++++++
tests/qtest/qmp-cmd-test.c | 1 +
6 files changed, 113 insertions(+), 2 deletions(-)
create mode 100644 hw/hyperv/hv-balloon-stub.c
diff --git a/hw/hyperv/hv-balloon-stub.c b/hw/hyperv/hv-balloon-stub.c
new file mode 100644
index 000000000000..a47412d4a8ad
--- /dev/null
+++ b/hw/hyperv/hv-balloon-stub.c
@@ -0,0 +1,19 @@
+/*
+ * QEMU Hyper-V Dynamic Memory Protocol driver
+ *
+ * Copyright (C) 2023 Oracle and/or its affiliates.
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ */
+
+#include "qemu/osdep.h"
+#include "qapi/error.h"
+#include "qapi/qapi-commands-machine.h"
+#include "qapi/qapi-types-machine.h"
+
+HvBalloonInfo *qmp_query_hv_balloon_status_report(Error **errp)
+{
+ error_setg(errp, "hv-balloon device not enabled in this build");
+ return NULL;
+}
diff --git a/hw/hyperv/hv-balloon.c b/hw/hyperv/hv-balloon.c
index 44a8d15cc841..66f297c1d7e3 100644
--- a/hw/hyperv/hv-balloon.c
+++ b/hw/hyperv/hv-balloon.c
@@ -1102,7 +1102,35 @@ static void hv_balloon_handle_status_report(HvBalloon *balloon,
balloon->status_report.available *= HV_BALLOON_PAGE_SIZE;
balloon->status_report.received = true;
- /* report event */
+ qapi_event_send_hv_balloon_status_report(balloon->status_report.committed,
+ balloon->status_report.available);
+}
+
+HvBalloonInfo *qmp_query_hv_balloon_status_report(Error **errp)
+{
+ HvBalloon *balloon;
+ HvBalloonInfo *info;
+
+ balloon = HV_BALLOON(object_resolve_path_type("", TYPE_HV_BALLOON, NULL));
+ if (!balloon) {
+ error_setg(errp, "no %s device present", TYPE_HV_BALLOON);
+ return NULL;
+ }
+
+ if (!balloon->status_report.enabled) {
+ error_setg(errp, "guest memory status reporting not enabled");
+ return NULL;
+ }
+
+ if (!balloon->status_report.received) {
+ error_setg(errp, "no guest memory status report received yet");
+ return NULL;
+ }
+
+ info = g_malloc0(sizeof(*info));
+ info->committed = balloon->status_report.committed;
+ info->available = balloon->status_report.available;
+ return info;
}
static void hv_balloon_handle_unballoon_response(HvBalloon *balloon,
diff --git a/hw/hyperv/meson.build b/hw/hyperv/meson.build
index 852d4f4a2ee2..d3d2668c71ae 100644
--- a/hw/hyperv/meson.build
+++ b/hw/hyperv/meson.build
@@ -2,4 +2,4 @@ specific_ss.add(when: 'CONFIG_HYPERV', if_true: files('hyperv.c'))
specific_ss.add(when: 'CONFIG_HYPERV_TESTDEV', if_true: files('hyperv_testdev.c'))
specific_ss.add(when: 'CONFIG_VMBUS', if_true: files('vmbus.c'))
specific_ss.add(when: 'CONFIG_SYNDBG', if_true: files('syndbg.c'))
-specific_ss.add(when: 'CONFIG_HV_BALLOON', if_true: files('hv-balloon.c', 'hv-balloon-page_range_tree.c', 'hv-balloon-our_range_memslots.c'))
+specific_ss.add(when: 'CONFIG_HV_BALLOON', if_true: files('hv-balloon.c', 'hv-balloon-page_range_tree.c', 'hv-balloon-our_range_memslots.c'), if_false: files('hv-balloon-stub.c'))
diff --git a/monitor/monitor.c b/monitor/monitor.c
index 941f87815aa4..01ede1babd3d 100644
--- a/monitor/monitor.c
+++ b/monitor/monitor.c
@@ -315,6 +315,7 @@ static MonitorQAPIEventConf monitor_qapi_event_conf[QAPI_EVENT__MAX] = {
[QAPI_EVENT_QUORUM_FAILURE] = { 1000 * SCALE_MS },
[QAPI_EVENT_VSERPORT_CHANGE] = { 1000 * SCALE_MS },
[QAPI_EVENT_MEMORY_DEVICE_SIZE_CHANGE] = { 1000 * SCALE_MS },
+ [QAPI_EVENT_HV_BALLOON_STATUS_REPORT] = { 1000 * SCALE_MS },
};
/*
diff --git a/qapi/machine.json b/qapi/machine.json
index 2985d043c00d..b6d634b30d55 100644
--- a/qapi/machine.json
+++ b/qapi/machine.json
@@ -1137,6 +1137,68 @@
{ 'event': 'BALLOON_CHANGE',
'data': { 'actual': 'int' } }
+##
+# @HvBalloonInfo:
+#
+# hv-balloon guest-provided memory status information.
+#
+# @committed: the amount of memory in use inside the guest plus the
+# amount of the memory unusable inside the guest (ballooned out,
+# offline, etc.)
+#
+# @available: the amount of the memory inside the guest available for
+# new allocations ("free")
+#
+# Since: 8.2
+##
+{ 'struct': 'HvBalloonInfo',
+ 'data': { 'committed': 'size', 'available': 'size' } }
+
+##
+# @query-hv-balloon-status-report:
+#
+# Returns the hv-balloon driver data contained in the last received "STATUS"
+# message from the guest.
+#
+# Returns:
+# - @HvBalloonInfo on success
+# - If no hv-balloon device is present, guest memory status reporting
+# is not enabled or no guest memory status report received yet,
+# GenericError
+#
+# Since: 8.2
+#
+# Example:
+#
+# -> { "execute": "query-hv-balloon-status-report" }
+# <- { "return": {
+# "committed": 816640000,
+# "available": 3333054464
+# }
+# }
+##
+{ 'command': 'query-hv-balloon-status-report', 'returns': 'HvBalloonInfo' }
+
+##
+# @HV_BALLOON_STATUS_REPORT:
+#
+# Emitted when the hv-balloon driver receives a "STATUS" message from
+# the guest.
+#
+# Note: this event is rate-limited.
+#
+# Since: 8.2
+#
+# Example:
+#
+# <- { "event": "HV_BALLOON_STATUS_REPORT",
+# "data": { "committed": 816640000, "available": 3333054464 },
+# "timestamp": { "seconds": 1600295492, "microseconds": 661044 } }
+#
+##
+{ 'event': 'HV_BALLOON_STATUS_REPORT',
+ 'data': 'HvBalloonInfo' }
+
##
# @MemoryInfo:
#
diff --git a/tests/qtest/qmp-cmd-test.c b/tests/qtest/qmp-cmd-test.c
index 73a670e8fa9d..2c15f6095848 100644
--- a/tests/qtest/qmp-cmd-test.c
+++ b/tests/qtest/qmp-cmd-test.c
@@ -45,6 +45,7 @@ static int query_error_class(const char *cmd)
{ "query-acpi-ospm-status", ERROR_CLASS_GENERIC_ERROR },
{ "query-balloon", ERROR_CLASS_DEVICE_NOT_ACTIVE },
{ "query-hotpluggable-cpus", ERROR_CLASS_GENERIC_ERROR },
+ { "query-hv-balloon-status-report", ERROR_CLASS_GENERIC_ERROR },
{ "query-vm-generation-id", ERROR_CLASS_GENERIC_ERROR },
/* Only valid with a USB bus added */
{ "x-query-usb", ERROR_CLASS_GENERIC_ERROR },