mirror of
https://gitlab.com/libvirt/libvirt.git
synced 2025-02-01 17:35:17 +00:00
Wire up handling for QMP's BALLOON_EVENT
If QEMU supports the BALLOON_EVENT QMP event, then we can avoid invoking 'query-balloon' when returning XML or the domain info. * src/qemu/qemu_capabilities.c, src/qemu/qemu_capabilities.h: Add QEMU_CAPS_BALLOON_EVENT * src/qemu/qemu_driver.c: Skip query-balloon in qemudDomainGetInfo and qemuDomainGetXMLDesc if we have QEMU_CAPS_BALLOON_EVENT set * src/qemu/qemu_monitor.c, src/qemu/qemu_monitor.h: Check for BALLOON_EVENT at connect to monitor. Add callback for balloon change notifications * src/qemu/qemu_monitor_json.c, src/qemu/qemu_monitor_json.h: Add handling of BALLOON_EVENT and impl 'query-events' check Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
This commit is contained in:
parent
7ed6d7dda7
commit
1d9d5103b4
@ -167,6 +167,7 @@ VIR_ENUM_IMPL(qemuCaps, QEMU_CAPS_LAST,
|
|||||||
"dump-guest-memory",
|
"dump-guest-memory",
|
||||||
"nec-usb-xhci",
|
"nec-usb-xhci",
|
||||||
"virtio-s390",
|
"virtio-s390",
|
||||||
|
"balloon-event",
|
||||||
|
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -134,6 +134,7 @@ enum qemuCapsFlags {
|
|||||||
QEMU_CAPS_DUMP_GUEST_MEMORY = 96, /* dump-guest-memory command */
|
QEMU_CAPS_DUMP_GUEST_MEMORY = 96, /* dump-guest-memory command */
|
||||||
QEMU_CAPS_NEC_USB_XHCI = 97, /* -device nec-usb-xhci */
|
QEMU_CAPS_NEC_USB_XHCI = 97, /* -device nec-usb-xhci */
|
||||||
QEMU_CAPS_VIRTIO_S390 = 98, /* -device virtio-*-s390 */
|
QEMU_CAPS_VIRTIO_S390 = 98, /* -device virtio-*-s390 */
|
||||||
|
QEMU_CAPS_BALLOON_EVENT = 99, /* Async event for balloon changes */
|
||||||
|
|
||||||
QEMU_CAPS_LAST, /* this must always be the last item */
|
QEMU_CAPS_LAST, /* this must always be the last item */
|
||||||
};
|
};
|
||||||
|
@ -2234,6 +2234,8 @@ static int qemudDomainGetInfo(virDomainPtr dom,
|
|||||||
if ((vm->def->memballoon != NULL) &&
|
if ((vm->def->memballoon != NULL) &&
|
||||||
(vm->def->memballoon->model == VIR_DOMAIN_MEMBALLOON_MODEL_NONE)) {
|
(vm->def->memballoon->model == VIR_DOMAIN_MEMBALLOON_MODEL_NONE)) {
|
||||||
info->memory = vm->def->mem.max_balloon;
|
info->memory = vm->def->mem.max_balloon;
|
||||||
|
} else if (qemuCapsGet(priv->qemuCaps, QEMU_CAPS_BALLOON_EVENT)) {
|
||||||
|
info->memory = vm->def->mem.cur_balloon;
|
||||||
} else if (qemuDomainJobAllowed(priv, QEMU_JOB_QUERY)) {
|
} else if (qemuDomainJobAllowed(priv, QEMU_JOB_QUERY)) {
|
||||||
if (qemuDomainObjBeginJob(driver, vm, QEMU_JOB_QUERY) < 0)
|
if (qemuDomainObjBeginJob(driver, vm, QEMU_JOB_QUERY) < 0)
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
@ -4560,6 +4562,7 @@ static char *qemuDomainGetXMLDesc(virDomainPtr dom,
|
|||||||
char *ret = NULL;
|
char *ret = NULL;
|
||||||
unsigned long long balloon;
|
unsigned long long balloon;
|
||||||
int err = 0;
|
int err = 0;
|
||||||
|
qemuDomainObjPrivatePtr priv;
|
||||||
|
|
||||||
/* Flags checked by virDomainDefFormat */
|
/* Flags checked by virDomainDefFormat */
|
||||||
|
|
||||||
@ -4574,11 +4577,13 @@ static char *qemuDomainGetXMLDesc(virDomainPtr dom,
|
|||||||
goto cleanup;
|
goto cleanup;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
priv = vm->privateData;
|
||||||
|
|
||||||
/* Refresh current memory based on balloon info if supported */
|
/* Refresh current memory based on balloon info if supported */
|
||||||
if ((vm->def->memballoon != NULL) &&
|
if ((vm->def->memballoon != NULL) &&
|
||||||
(vm->def->memballoon->model != VIR_DOMAIN_MEMBALLOON_MODEL_NONE) &&
|
(vm->def->memballoon->model != VIR_DOMAIN_MEMBALLOON_MODEL_NONE) &&
|
||||||
|
!qemuCapsGet(priv->qemuCaps, QEMU_CAPS_BALLOON_EVENT) &&
|
||||||
(virDomainObjIsActive(vm))) {
|
(virDomainObjIsActive(vm))) {
|
||||||
qemuDomainObjPrivatePtr priv = vm->privateData;
|
|
||||||
/* Don't delay if someone's using the monitor, just use
|
/* Don't delay if someone's using the monitor, just use
|
||||||
* existing most recent data instead */
|
* existing most recent data instead */
|
||||||
if (qemuDomainJobAllowed(priv, QEMU_JOB_QUERY)) {
|
if (qemuDomainJobAllowed(priv, QEMU_JOB_QUERY)) {
|
||||||
|
@ -1086,6 +1086,16 @@ int qemuMonitorEmitBlockJob(qemuMonitorPtr mon,
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int qemuMonitorEmitBalloonChange(qemuMonitorPtr mon,
|
||||||
|
unsigned long long actual)
|
||||||
|
{
|
||||||
|
int ret = -1;
|
||||||
|
VIR_DEBUG("mon=%p", mon);
|
||||||
|
|
||||||
|
QEMU_MONITOR_CALLBACK(mon, ret, domainBalloonChange, mon->vm, actual);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
int qemuMonitorSetCapabilities(qemuMonitorPtr mon,
|
int qemuMonitorSetCapabilities(qemuMonitorPtr mon,
|
||||||
virBitmapPtr qemuCaps)
|
virBitmapPtr qemuCaps)
|
||||||
@ -1102,11 +1112,17 @@ int qemuMonitorSetCapabilities(qemuMonitorPtr mon,
|
|||||||
|
|
||||||
if (mon->json) {
|
if (mon->json) {
|
||||||
ret = qemuMonitorJSONSetCapabilities(mon);
|
ret = qemuMonitorJSONSetCapabilities(mon);
|
||||||
if (ret)
|
if (ret < 0)
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
|
|
||||||
ret = qemuMonitorJSONCheckCommands(mon, qemuCaps, &json_hmp);
|
ret = qemuMonitorJSONCheckCommands(mon, qemuCaps, &json_hmp);
|
||||||
|
if (ret < 0)
|
||||||
|
goto cleanup;
|
||||||
mon->json_hmp = json_hmp > 0;
|
mon->json_hmp = json_hmp > 0;
|
||||||
|
|
||||||
|
ret = qemuMonitorJSONCheckEvents(mon, qemuCaps);
|
||||||
|
if (ret < 0)
|
||||||
|
goto cleanup;
|
||||||
} else {
|
} else {
|
||||||
ret = 0;
|
ret = 0;
|
||||||
}
|
}
|
||||||
|
@ -133,6 +133,9 @@ struct _qemuMonitorCallbacks {
|
|||||||
virDomainObjPtr vm);
|
virDomainObjPtr vm);
|
||||||
int (*domainPMSuspend)(qemuMonitorPtr mon,
|
int (*domainPMSuspend)(qemuMonitorPtr mon,
|
||||||
virDomainObjPtr vm);
|
virDomainObjPtr vm);
|
||||||
|
int (*domainBalloonChange)(qemuMonitorPtr mon,
|
||||||
|
virDomainObjPtr vm,
|
||||||
|
unsigned long long actual);
|
||||||
};
|
};
|
||||||
|
|
||||||
char *qemuMonitorEscapeArg(const char *in);
|
char *qemuMonitorEscapeArg(const char *in);
|
||||||
@ -208,6 +211,8 @@ int qemuMonitorEmitBlockJob(qemuMonitorPtr mon,
|
|||||||
const char *diskAlias,
|
const char *diskAlias,
|
||||||
int type,
|
int type,
|
||||||
int status);
|
int status);
|
||||||
|
int qemuMonitorEmitBalloonChange(qemuMonitorPtr mon,
|
||||||
|
unsigned long long actual);
|
||||||
|
|
||||||
int qemuMonitorStartCPUs(qemuMonitorPtr mon,
|
int qemuMonitorStartCPUs(qemuMonitorPtr mon,
|
||||||
virConnectPtr conn);
|
virConnectPtr conn);
|
||||||
|
@ -69,6 +69,7 @@ static void qemuMonitorJSONHandlePMWakeup(qemuMonitorPtr mon, virJSONValuePtr da
|
|||||||
static void qemuMonitorJSONHandlePMSuspend(qemuMonitorPtr mon, virJSONValuePtr data);
|
static void qemuMonitorJSONHandlePMSuspend(qemuMonitorPtr mon, virJSONValuePtr data);
|
||||||
static void qemuMonitorJSONHandleBlockJobCompleted(qemuMonitorPtr mon, virJSONValuePtr data);
|
static void qemuMonitorJSONHandleBlockJobCompleted(qemuMonitorPtr mon, virJSONValuePtr data);
|
||||||
static void qemuMonitorJSONHandleBlockJobCanceled(qemuMonitorPtr mon, virJSONValuePtr data);
|
static void qemuMonitorJSONHandleBlockJobCanceled(qemuMonitorPtr mon, virJSONValuePtr data);
|
||||||
|
static void qemuMonitorJSONHandleBalloonChange(qemuMonitorPtr mon, virJSONValuePtr data);
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
const char *type;
|
const char *type;
|
||||||
@ -76,6 +77,7 @@ typedef struct {
|
|||||||
} qemuEventHandler;
|
} qemuEventHandler;
|
||||||
|
|
||||||
static qemuEventHandler eventHandlers[] = {
|
static qemuEventHandler eventHandlers[] = {
|
||||||
|
{ "BALLOON_CHANGE", qemuMonitorJSONHandleBalloonChange, },
|
||||||
{ "BLOCK_IO_ERROR", qemuMonitorJSONHandleIOError, },
|
{ "BLOCK_IO_ERROR", qemuMonitorJSONHandleIOError, },
|
||||||
{ "BLOCK_JOB_CANCELLED", qemuMonitorJSONHandleBlockJobCanceled, },
|
{ "BLOCK_JOB_CANCELLED", qemuMonitorJSONHandleBlockJobCanceled, },
|
||||||
{ "BLOCK_JOB_COMPLETED", qemuMonitorJSONHandleBlockJobCompleted, },
|
{ "BLOCK_JOB_COMPLETED", qemuMonitorJSONHandleBlockJobCompleted, },
|
||||||
@ -875,6 +877,19 @@ qemuMonitorJSONHandleBlockJobCanceled(qemuMonitorPtr mon,
|
|||||||
VIR_DOMAIN_BLOCK_JOB_CANCELED);
|
VIR_DOMAIN_BLOCK_JOB_CANCELED);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
qemuMonitorJSONHandleBalloonChange(qemuMonitorPtr mon,
|
||||||
|
virJSONValuePtr data)
|
||||||
|
{
|
||||||
|
unsigned long long actual = 0;
|
||||||
|
if (virJSONValueObjectGetNumberUlong(data, "actual", &actual) < 0) {
|
||||||
|
VIR_WARN("missing actual in balloon change event");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
actual = VIR_DIV_UP(actual, 1024);
|
||||||
|
qemuMonitorEmitBalloonChange(mon, actual);
|
||||||
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
qemuMonitorJSONHumanCommandWithFd(qemuMonitorPtr mon,
|
qemuMonitorJSONHumanCommandWithFd(qemuMonitorPtr mon,
|
||||||
const char *cmd_str,
|
const char *cmd_str,
|
||||||
@ -1003,6 +1018,56 @@ cleanup:
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int
|
||||||
|
qemuMonitorJSONCheckEvents(qemuMonitorPtr mon,
|
||||||
|
virBitmapPtr qemuCaps)
|
||||||
|
{
|
||||||
|
int ret = -1;
|
||||||
|
virJSONValuePtr cmd = qemuMonitorJSONMakeCommand("query-events", NULL);
|
||||||
|
virJSONValuePtr reply = NULL;
|
||||||
|
virJSONValuePtr data;
|
||||||
|
int i, n;
|
||||||
|
|
||||||
|
if (!cmd)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
if (qemuMonitorJSONCommand(mon, cmd, &reply) < 0)
|
||||||
|
goto cleanup;
|
||||||
|
|
||||||
|
if (qemuMonitorJSONHasError(reply, "CommandNotFound")) {
|
||||||
|
ret = 0;
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (qemuMonitorJSONCheckError(cmd, reply) < 0)
|
||||||
|
goto cleanup;
|
||||||
|
|
||||||
|
if (!(data = virJSONValueObjectGet(reply, "return")) ||
|
||||||
|
data->type != VIR_JSON_TYPE_ARRAY ||
|
||||||
|
(n = virJSONValueArraySize(data)) <= 0)
|
||||||
|
goto cleanup;
|
||||||
|
|
||||||
|
for (i = 0; i < n; i++) {
|
||||||
|
virJSONValuePtr entry;
|
||||||
|
const char *name;
|
||||||
|
|
||||||
|
if (!(entry = virJSONValueArrayGet(data, i)) ||
|
||||||
|
!(name = virJSONValueObjectGetString(entry, "name")))
|
||||||
|
goto cleanup;
|
||||||
|
|
||||||
|
if (STREQ(name, "BALLOON_CHANGE"))
|
||||||
|
qemuCapsSet(qemuCaps, QEMU_CAPS_BALLOON_EVENT);
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = 0;
|
||||||
|
|
||||||
|
cleanup:
|
||||||
|
virJSONValueFree(cmd);
|
||||||
|
virJSONValueFree(reply);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
int
|
int
|
||||||
qemuMonitorJSONStartCPUs(qemuMonitorPtr mon,
|
qemuMonitorJSONStartCPUs(qemuMonitorPtr mon,
|
||||||
virConnectPtr conn ATTRIBUTE_UNUSED)
|
virConnectPtr conn ATTRIBUTE_UNUSED)
|
||||||
|
@ -45,6 +45,8 @@ int qemuMonitorJSONSetCapabilities(qemuMonitorPtr mon);
|
|||||||
int qemuMonitorJSONCheckCommands(qemuMonitorPtr mon,
|
int qemuMonitorJSONCheckCommands(qemuMonitorPtr mon,
|
||||||
virBitmapPtr qemuCaps,
|
virBitmapPtr qemuCaps,
|
||||||
int *json_hmp);
|
int *json_hmp);
|
||||||
|
int qemuMonitorJSONCheckEvents(qemuMonitorPtr mon,
|
||||||
|
virBitmapPtr qemuCaps);
|
||||||
|
|
||||||
int qemuMonitorJSONStartCPUs(qemuMonitorPtr mon,
|
int qemuMonitorJSONStartCPUs(qemuMonitorPtr mon,
|
||||||
virConnectPtr conn);
|
virConnectPtr conn);
|
||||||
|
@ -1148,6 +1148,36 @@ qemuProcessHandlePMSuspend(qemuMonitorPtr mon ATTRIBUTE_UNUSED,
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
qemuProcessHandleBalloonChange(qemuMonitorPtr mon ATTRIBUTE_UNUSED,
|
||||||
|
virDomainObjPtr vm,
|
||||||
|
unsigned long long actual)
|
||||||
|
{
|
||||||
|
struct qemud_driver *driver = qemu_driver;
|
||||||
|
virDomainEventPtr event;
|
||||||
|
|
||||||
|
virDomainObjLock(vm);
|
||||||
|
event = virDomainEventBalloonChangeNewFromObj(vm, actual);
|
||||||
|
|
||||||
|
VIR_DEBUG("Updating balloon from %lld to %lld kb",
|
||||||
|
vm->def->mem.cur_balloon, actual);
|
||||||
|
vm->def->mem.cur_balloon = actual;
|
||||||
|
|
||||||
|
if (virDomainSaveStatus(driver->caps, driver->stateDir, vm) < 0)
|
||||||
|
VIR_WARN("unable to save domain status with balloon change");
|
||||||
|
|
||||||
|
virDomainObjUnlock(vm);
|
||||||
|
|
||||||
|
if (event) {
|
||||||
|
qemuDriverLock(driver);
|
||||||
|
qemuDomainEventQueue(driver, event);
|
||||||
|
qemuDriverUnlock(driver);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
static qemuMonitorCallbacks monitorCallbacks = {
|
static qemuMonitorCallbacks monitorCallbacks = {
|
||||||
.destroy = qemuProcessHandleMonitorDestroy,
|
.destroy = qemuProcessHandleMonitorDestroy,
|
||||||
.eofNotify = qemuProcessHandleMonitorEOF,
|
.eofNotify = qemuProcessHandleMonitorEOF,
|
||||||
@ -1164,6 +1194,7 @@ static qemuMonitorCallbacks monitorCallbacks = {
|
|||||||
.domainTrayChange = qemuProcessHandleTrayChange,
|
.domainTrayChange = qemuProcessHandleTrayChange,
|
||||||
.domainPMWakeup = qemuProcessHandlePMWakeup,
|
.domainPMWakeup = qemuProcessHandlePMWakeup,
|
||||||
.domainPMSuspend = qemuProcessHandlePMSuspend,
|
.domainPMSuspend = qemuProcessHandlePMSuspend,
|
||||||
|
.domainBalloonChange = qemuProcessHandleBalloonChange,
|
||||||
};
|
};
|
||||||
|
|
||||||
static int
|
static int
|
||||||
|
Loading…
x
Reference in New Issue
Block a user