]> xenbits.xensource.com Git - libvirt.git/commitdiff
Wire up handling for QMP's BALLOON_EVENT
authorDaniel P. Berrange <berrange@redhat.com>
Thu, 12 Jul 2012 15:45:57 +0000 (23:45 +0800)
committerGuannan Ren <gren@redhat.com>
Sat, 14 Jul 2012 08:02:34 +0000 (16:02 +0800)
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>
src/qemu/qemu_capabilities.c
src/qemu/qemu_capabilities.h
src/qemu/qemu_driver.c
src/qemu/qemu_monitor.c
src/qemu/qemu_monitor.h
src/qemu/qemu_monitor_json.c
src/qemu/qemu_monitor_json.h
src/qemu/qemu_process.c

index 9e4d927dd5e0ba9d004f5f445decc0e6d2b5695c..d438c06112bc20754d843e1e6936169b5ce7dc81 100644 (file)
@@ -167,6 +167,7 @@ VIR_ENUM_IMPL(qemuCaps, QEMU_CAPS_LAST,
               "dump-guest-memory",
               "nec-usb-xhci",
               "virtio-s390",
+              "balloon-event",
 
     );
 
index 9b5ff302b7edc44b20db59772b32acf9139aa4d4..6526ea838df9a982484e938aa7cac30e5d40b192 100644 (file)
@@ -134,6 +134,7 @@ enum qemuCapsFlags {
     QEMU_CAPS_DUMP_GUEST_MEMORY  = 96, /* dump-guest-memory command */
     QEMU_CAPS_NEC_USB_XHCI       = 97, /* -device nec-usb-xhci */
     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 */
 };
index dc04d133c7c9225596b94ad4b59705956c6c722c..29ebb4c5402c20dd49ceb92e71928ede7c38a3fa 100644 (file)
@@ -2234,6 +2234,8 @@ static int qemudDomainGetInfo(virDomainPtr dom,
         if ((vm->def->memballoon != NULL) &&
             (vm->def->memballoon->model == VIR_DOMAIN_MEMBALLOON_MODEL_NONE)) {
             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)) {
             if (qemuDomainObjBeginJob(driver, vm, QEMU_JOB_QUERY) < 0)
                 goto cleanup;
@@ -4560,6 +4562,7 @@ static char *qemuDomainGetXMLDesc(virDomainPtr dom,
     char *ret = NULL;
     unsigned long long balloon;
     int err = 0;
+    qemuDomainObjPrivatePtr priv;
 
     /* Flags checked by virDomainDefFormat */
 
@@ -4574,11 +4577,13 @@ static char *qemuDomainGetXMLDesc(virDomainPtr dom,
         goto cleanup;
     }
 
+    priv = vm->privateData;
+
     /* Refresh current memory based on balloon info if supported */
     if ((vm->def->memballoon != NULL) &&
         (vm->def->memballoon->model != VIR_DOMAIN_MEMBALLOON_MODEL_NONE) &&
+        !qemuCapsGet(priv->qemuCaps, QEMU_CAPS_BALLOON_EVENT) &&
         (virDomainObjIsActive(vm))) {
-        qemuDomainObjPrivatePtr priv = vm->privateData;
         /* Don't delay if someone's using the monitor, just use
          * existing most recent data instead */
         if (qemuDomainJobAllowed(priv, QEMU_JOB_QUERY)) {
index b8a2f2fbcd6465bd93f3c1d73dd3e204a0109be4..42a5d6cbe8b7ff1ecbcc608d649926efc143134e 100644 (file)
@@ -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,
                                virBitmapPtr qemuCaps)
@@ -1102,11 +1112,17 @@ int qemuMonitorSetCapabilities(qemuMonitorPtr mon,
 
     if (mon->json) {
         ret = qemuMonitorJSONSetCapabilities(mon);
-        if (ret)
+        if (ret < 0)
             goto cleanup;
 
         ret = qemuMonitorJSONCheckCommands(mon, qemuCaps, &json_hmp);
+        if (ret < 0)
+            goto cleanup;
         mon->json_hmp = json_hmp > 0;
+
+        ret = qemuMonitorJSONCheckEvents(mon, qemuCaps);
+        if (ret < 0)
+            goto cleanup;
     } else {
         ret = 0;
     }
index 66bec38982bcac2afb931f52a6d2d3c3eee03ff4..c96282b230812547a4b71e77c2f60c7cc6028db2 100644 (file)
@@ -133,6 +133,9 @@ struct _qemuMonitorCallbacks {
                           virDomainObjPtr vm);
     int (*domainPMSuspend)(qemuMonitorPtr mon,
                            virDomainObjPtr vm);
+    int (*domainBalloonChange)(qemuMonitorPtr mon,
+                               virDomainObjPtr vm,
+                               unsigned long long actual);
 };
 
 char *qemuMonitorEscapeArg(const char *in);
@@ -208,6 +211,8 @@ int qemuMonitorEmitBlockJob(qemuMonitorPtr mon,
                             const char *diskAlias,
                             int type,
                             int status);
+int qemuMonitorEmitBalloonChange(qemuMonitorPtr mon,
+                                 unsigned long long actual);
 
 int qemuMonitorStartCPUs(qemuMonitorPtr mon,
                          virConnectPtr conn);
index 7317c42c45158f467b7d044ab18027bc971b37a1..a99bf60ed1f58530f53778780402ccda2cec53ea 100644 (file)
@@ -69,6 +69,7 @@ static void qemuMonitorJSONHandlePMWakeup(qemuMonitorPtr mon, virJSONValuePtr da
 static void qemuMonitorJSONHandlePMSuspend(qemuMonitorPtr mon, virJSONValuePtr data);
 static void qemuMonitorJSONHandleBlockJobCompleted(qemuMonitorPtr mon, virJSONValuePtr data);
 static void qemuMonitorJSONHandleBlockJobCanceled(qemuMonitorPtr mon, virJSONValuePtr data);
+static void qemuMonitorJSONHandleBalloonChange(qemuMonitorPtr mon, virJSONValuePtr data);
 
 typedef struct {
     const char *type;
@@ -76,6 +77,7 @@ typedef struct {
 } qemuEventHandler;
 
 static qemuEventHandler eventHandlers[] = {
+    { "BALLOON_CHANGE", qemuMonitorJSONHandleBalloonChange, },
     { "BLOCK_IO_ERROR", qemuMonitorJSONHandleIOError, },
     { "BLOCK_JOB_CANCELLED", qemuMonitorJSONHandleBlockJobCanceled, },
     { "BLOCK_JOB_COMPLETED", qemuMonitorJSONHandleBlockJobCompleted, },
@@ -875,6 +877,19 @@ qemuMonitorJSONHandleBlockJobCanceled(qemuMonitorPtr mon,
                                       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
 qemuMonitorJSONHumanCommandWithFd(qemuMonitorPtr mon,
                                   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
 qemuMonitorJSONStartCPUs(qemuMonitorPtr mon,
                          virConnectPtr conn ATTRIBUTE_UNUSED)
index e8bd9b8841c6ee846f2693022c2566e0305f180e..52938957d8a5fe75e863d04d0c0fc897d971d570 100644 (file)
@@ -45,6 +45,8 @@ int qemuMonitorJSONSetCapabilities(qemuMonitorPtr mon);
 int qemuMonitorJSONCheckCommands(qemuMonitorPtr mon,
                                  virBitmapPtr qemuCaps,
                                  int *json_hmp);
+int qemuMonitorJSONCheckEvents(qemuMonitorPtr mon,
+                               virBitmapPtr qemuCaps);
 
 int qemuMonitorJSONStartCPUs(qemuMonitorPtr mon,
                              virConnectPtr conn);
index bf324870f1af5ef3d6b99af1c0a9a1803e3cebbf..c120517d162a4563889365dbe9bc396473dc1d04 100644 (file)
@@ -1148,6 +1148,36 @@ qemuProcessHandlePMSuspend(qemuMonitorPtr mon ATTRIBUTE_UNUSED,
     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 = {
     .destroy = qemuProcessHandleMonitorDestroy,
     .eofNotify = qemuProcessHandleMonitorEOF,
@@ -1164,6 +1194,7 @@ static qemuMonitorCallbacks monitorCallbacks = {
     .domainTrayChange = qemuProcessHandleTrayChange,
     .domainPMWakeup = qemuProcessHandlePMWakeup,
     .domainPMSuspend = qemuProcessHandlePMSuspend,
+    .domainBalloonChange = qemuProcessHandleBalloonChange,
 };
 
 static int