@@ -41,11 +41,13 @@ void qemu_add_balloon_handler(QEMUBalloonEvent *func, void *opaque)
qemu_balloon_event_opaque = opaque;
}
-int qemu_balloon(ram_addr_t target, MonitorCompletion cb, void *opaque)
+int qemu_balloon(ram_addr_t target, bool reclaim_cache_first,
+ MonitorCompletion cb, void *opaque)
{
if (qemu_balloon_event) {
trace_balloon_event(qemu_balloon_event_opaque, target);
- qemu_balloon_event(qemu_balloon_event_opaque, target, cb, opaque);
+ qemu_balloon_event(qemu_balloon_event_opaque, target,
+ reclaim_cache_first, cb, opaque);
return 1;
} else {
return 0;
@@ -55,7 +57,7 @@ int qemu_balloon(ram_addr_t target, MonitorCompletion cb, void *opaque)
int qemu_balloon_status(MonitorCompletion cb, void *opaque)
{
if (qemu_balloon_event) {
- qemu_balloon_event(qemu_balloon_event_opaque, 0, cb, opaque);
+ qemu_balloon_event(qemu_balloon_event_opaque, 0, 0, cb, opaque);
return 1;
} else {
return 0;
@@ -131,13 +133,21 @@ int do_balloon(Monitor *mon, const QDict *params,
MonitorCompletion cb, void *opaque)
{
int ret;
+ int val;
+ const char *cache_hint;
+ int reclaim_cache_first = 0;
if (kvm_enabled() && !kvm_has_sync_mmu()) {
qerror_report(QERR_KVM_MISSING_CAP, "synchronous MMU", "balloon");
return -1;
}
- ret = qemu_balloon(qdict_get_int(params, "value"), cb, opaque);
+ val = qdict_get_int(params, "value");
+ cache_hint = qdict_get_try_str(params, "hint");
+ if (cache_hint)
+ reclaim_cache_first = 1;
+
+ ret = qemu_balloon(val, reclaim_cache_first, cb, opaque);
if (ret == 0) {
qerror_report(QERR_DEVICE_NOT_ACTIVE, "balloon");
return -1;
@@ -17,11 +17,13 @@
#include "monitor.h"
typedef void (QEMUBalloonEvent)(void *opaque, ram_addr_t target,
+ bool reclaim_cache_first,
MonitorCompletion cb, void *cb_data);
void qemu_add_balloon_handler(QEMUBalloonEvent *func, void *opaque);
-int qemu_balloon(ram_addr_t target, MonitorCompletion cb, void *opaque);
+int qemu_balloon(ram_addr_t target, bool reclaim_cache_first,
+ MonitorCompletion cb, void *opaque);
int qemu_balloon_status(MonitorCompletion cb, void *opaque);
@@ -925,8 +925,8 @@ ETEXI
{
.name = "balloon",
- .args_type = "value:M",
- .params = "target",
+ .args_type = "value:M,hint:s?",
+ .params = "target [cache]",
.help = "request VM to change its memory allocation (in MB)",
.user_print = monitor_user_noop,
.mhandler.cmd_async = do_balloon,
@@ -937,6 +937,9 @@ STEXI
@item balloon @var{value}
@findex balloon
Request VM to change its memory allocation to @var{value} (in MB).
+An optional @var{hint} can be specified to indicate if the guest
+should reclaim from the cached memory in the guest first. The
+@var{hint} may be ignored by the guest.
ETEXI
{
@@ -44,6 +44,7 @@ typedef struct VirtIOBalloon
size_t stats_vq_offset;
MonitorCompletion *stats_callback;
void *stats_opaque_callback_data;
+ uint32_t reclaim_cache_first;
} VirtIOBalloon;
static VirtIOBalloon *to_virtio_balloon(VirtIODevice *vdev)
@@ -181,8 +182,11 @@ static void virtio_balloon_get_config(VirtIODevice *vdev, uint8_t *config_data)
config.num_pages = cpu_to_le32(dev->num_pages);
config.actual = cpu_to_le32(dev->actual);
-
- memcpy(config_data, &config, 8);
+ if (vdev->guest_features & (1 << VIRTIO_BALLOON_F_BALLOON_HINT)) {
+ config.reclaim_cache_first = cpu_to_le32(dev->reclaim_cache_first);
+ memcpy(config_data, &config, 12);
+ } else
+ memcpy(config_data, &config, 8);
}
static void virtio_balloon_set_config(VirtIODevice *vdev,
@@ -196,11 +200,13 @@ static void virtio_balloon_set_config(VirtIODevice *vdev,
static uint32_t virtio_balloon_get_features(VirtIODevice *vdev, uint32_t f)
{
- f |= (1 << VIRTIO_BALLOON_F_STATS_VQ);
+ f |= (1 << VIRTIO_BALLOON_F_STATS_VQ) |
+ (1 << VIRTIO_BALLOON_F_BALLOON_HINT);
return f;
}
static void virtio_balloon_to_target(void *opaque, ram_addr_t target,
+ bool reclaim_cache_first,
MonitorCompletion cb, void *cb_data)
{
VirtIOBalloon *dev = opaque;
@@ -210,6 +216,7 @@ static void virtio_balloon_to_target(void *opaque, ram_addr_t target,
if (target) {
dev->num_pages = (ram_size - target) >> VIRTIO_BALLOON_PFN_SHIFT;
+ dev->reclaim_cache_first = reclaim_cache_first;
virtio_notify_config(&dev->vdev);
} else {
/* For now, only allow one request at a time. This restriction can be
@@ -263,7 +270,7 @@ VirtIODevice *virtio_balloon_init(DeviceState *dev)
s = (VirtIOBalloon *)virtio_common_init("virtio-balloon",
VIRTIO_ID_BALLOON,
- 8, sizeof(VirtIOBalloon));
+ 12, sizeof(VirtIOBalloon));
s->vdev.get_config = virtio_balloon_get_config;
s->vdev.set_config = virtio_balloon_set_config;
@@ -26,6 +26,7 @@
/* The feature bitmap for virtio balloon */
#define VIRTIO_BALLOON_F_MUST_TELL_HOST 0 /* Tell before reclaiming pages */
#define VIRTIO_BALLOON_F_STATS_VQ 1 /* Memory stats virtqueue */
+#define VIRTIO_BALLOON_F_BALLOON_HINT 2 /* Ballon hint */
/* Size of a PFN in the balloon interface. */
#define VIRTIO_BALLOON_PFN_SHIFT 12
@@ -36,6 +37,8 @@ struct virtio_balloon_config
uint32_t num_pages;
/* Number of pages we've actually got in balloon. */
uint32_t actual;
+ /* Hint, should we reclaim cached pages first? */
+ uint32_t reclaim_cache_first;
};
/* Memory Statistics */
@@ -605,8 +605,8 @@ EQMP
{
.name = "balloon",
- .args_type = "value:M",
- .params = "target",
+ .args_type = "value:M,hint:s?",
+ .params = "target [cache]",
.help = "request VM to change its memory allocation (in MB)",
.user_print = monitor_user_noop,
.mhandler.cmd_async = do_balloon,
@@ -622,10 +622,11 @@ Request VM to change its memory allocation (in bytes).
Arguments:
- "value": New memory allocation (json-int)
+- "hint": Optional hint (json-string, optional)
Example:
--> { "execute": "balloon", "arguments": { "value": 536870912 } }
++-> { "execute": "balloon", "arguments": { "value": 536870912, "hint":"cache" } }
<- { "return": {} }
EQMP