[libvirt] [PATCH 5/8] Determine whether to start balloon memory stats gathering.

John Ferlan jferlan at redhat.com
Tue Jul 2 13:39:23 UTC 2013


At vm startup, reconnect, and attach - check for the presence of the balloon
driver and save the path in the private area of the driver.  This path will
remain constant throughout the life of the domain and can then be used rather
than attempting to find the path each time balloon driver statistics are
fetched or the collection period changes. The qom object model model requires
setting object properties after device startup.  That is, it's not possible
to pass the period along via the startup code as it won't be recognized.
If a balloon driver path is found a check of the existing collection period
will be made against the saved domain value in order to determine if an
adjustment needs to be made to the period to start or stop collecting stats
---
 src/qemu/qemu_domain.c  |   1 +
 src/qemu/qemu_domain.h  |   2 +
 src/qemu/qemu_process.c | 164 +++++++++++++++++++++++++++++++++++++++++++++++-
 3 files changed, 165 insertions(+), 2 deletions(-)

diff --git a/src/qemu/qemu_domain.c b/src/qemu/qemu_domain.c
index 8d79066..5aaf1e1 100644
--- a/src/qemu/qemu_domain.c
+++ b/src/qemu/qemu_domain.c
@@ -244,6 +244,7 @@ qemuDomainObjPrivateFree(void *data)
     VIR_FREE(priv->vcpupids);
     VIR_FREE(priv->lockState);
     VIR_FREE(priv->origname);
+    VIR_FREE(priv->balloonpath);
 
     virChrdevFree(priv->devs);
 
diff --git a/src/qemu/qemu_domain.h b/src/qemu/qemu_domain.h
index 068a4c3..005fd0f 100644
--- a/src/qemu/qemu_domain.h
+++ b/src/qemu/qemu_domain.h
@@ -161,6 +161,8 @@ struct _qemuDomainObjPrivate {
     char *origname;
     int nbdPort; /* Port used for migration with NBD */
 
+    char *balloonpath;
+
     virChrdevsPtr devs;
 
     qemuDomainCleanupCallback *cleanupCallbacks;
diff --git a/src/qemu/qemu_process.c b/src/qemu/qemu_process.c
index ac5ffcf..9a2add1 100644
--- a/src/qemu/qemu_process.c
+++ b/src/qemu/qemu_process.c
@@ -1564,6 +1564,150 @@ qemuProcessLookupPTYs(virDomainChrDefPtr *devices,
     return 0;
 }
 
+/* Search the qom objects for the balloon driver object by it's known name
+ * of "virtio-balloon-pci".  The entry for the driver will be found in the
+ * returned 'type' field using the syntax "child<virtio-balloon-pci>".
+ *
+ * Once found, check the entry to ensure it has the correct property listed.
+ * If it does not, then obtaining statistics from qemu will not be possible.
+ * This feature was added to qemu 1.5.
+ *
+ * This procedure will be call recursively until found or the qom-list is
+ * exhausted.
+ *
+ * Returns:
+ *
+ *   1  - Found
+ *   0  - Not found still looking
+ *  -1  - Error bail out
+ *
+ * NOTE: This assumes we have already called qemuDomainObjEnterMonitor()
+ */
+static int
+qemuProcessFindBalloonObjectPath(qemuMonitorPtr mon,
+                                 virDomainObjPtr vm,
+                                 const char *curpath,
+                                 char **balloonpath)
+{
+    int i,j;
+    int npaths = 0;
+    int nprops = 0;
+    int ret = 0;
+    char *nextpath = NULL;
+    qemuMonitorListPathPtr *paths = NULL;
+    qemuMonitorListPathPtr *bprops = NULL;
+
+    /* Not supported */
+    if (vm->def->memballoon &&
+        vm->def->memballoon->model != VIR_DOMAIN_MEMBALLOON_MODEL_VIRTIO) {
+        VIR_DEBUG("Model must be virtio to get memballoon path");
+        return -1;
+    }
+
+    /* Already set and won't change */
+    if (*balloonpath)
+        return 1;
+
+    VIR_DEBUG("Searching for Balloon Object Path starting at %s", curpath);
+
+    npaths = qemuMonitorGetObjectListPaths(mon, curpath, &paths);
+
+    for (i = 0; i < npaths && ret == 0; i++) {
+
+        if (STREQ_NULLABLE(paths[i]->type, "link<virtio-balloon-pci>")) {
+            VIR_DEBUG("Path to <virtio-balloon-pci> is '%s/%s'",
+                      curpath, paths[i]->name);
+            if (virAsprintf(&nextpath, "%s/%s", curpath, paths[i]->name) < 0) {
+                ret = -1;
+                goto cleanup;
+            }
+
+            /* Now look at the each of the property entries to determine
+             * whether "guest-stats-polling-interval" exists.  If not,
+             * then this version of qemu/kvm does not support the feature.
+             */
+            nprops = qemuMonitorGetObjectListPaths(mon, nextpath, &bprops);
+            for (j = 0; j < nprops; j++) {
+                if (STREQ(bprops[j]->name, "guest-stats-polling-interval")) {
+                    *balloonpath = nextpath;
+                    nextpath = NULL;
+                    ret = 1;
+                    goto cleanup;
+                }
+            }
+
+            /* If we get here, we found the path, but not the property */
+            VIR_DEBUG("Property 'guest-stats-polling-interval' not found");
+            ret = -1;
+            goto cleanup;
+        }
+
+        /* Type entries that begin with "child<" are a branch that can be
+         * traversed looking for more entries
+         */
+        if (paths[i]->type && STRPREFIX(paths[i]->type, "child<")) {
+            if (virAsprintf(&nextpath, "%s/%s", curpath, paths[i]->name) < 0) {
+                virReportOOMError();
+                ret = -1;
+                goto cleanup;
+            }
+            ret = qemuProcessFindBalloonObjectPath(mon, vm, nextpath,
+                                                   balloonpath);
+        }
+    }
+
+cleanup:
+    for (i = 0; i < npaths; i++)
+        qemuMonitorListPathFree(paths[i]);
+    VIR_FREE(paths);
+    for (j = 0; j < nprops; j++)
+        qemuMonitorListPathFree(bprops[j]);
+    VIR_FREE(bprops);
+    VIR_FREE(nextpath);
+    return ret;
+}
+
+/*
+ * Using the provided balloonpath, determine if we need to set the
+ * collection interval property to enable statistics gathering.
+ *
+ * NOTE: This assumes we have already called qemuDomainObjEnterMonitor()
+ */
+static void
+qemuProcessUpdateBalloonStatsPeriod(qemuMonitorPtr mon,
+                                    char *balloonpath,
+                                    virDomainObjPtr vm)
+{
+    qemuMonitorObjectProperty prop;
+
+    /* Get the current value of the stats polling interval */
+    memset(&prop, 0, sizeof(qemuMonitorObjectProperty));
+    prop.type = QEMU_MONITOR_OBJECT_PROPERTY_INT;
+    if (qemuMonitorGetObjectProperty(mon, balloonpath,
+                                     "guest-stats-polling-interval",
+                                     &prop) < 0) {
+        VIR_DEBUG("Failed to get polling interval for balloon driver");
+        return;
+    }
+
+    VIR_DEBUG("memballoon period=%d 'guest-stats-polling-interval'=%d",
+              vm->def->memballoon->period,  prop.val.i);
+
+    /* Same value - no need to set */
+    if (vm->def->memballoon->period == prop.val.i)
+        return;
+
+    /* Set to the value in memballoon (could enable or disable) */
+    memset(&prop, 0, sizeof(qemuMonitorObjectProperty));
+    prop.type = QEMU_MONITOR_OBJECT_PROPERTY_INT;
+    prop.val.i = vm->def->memballoon->period;
+    if (qemuMonitorSetObjectProperty(mon, balloonpath,
+                                     "guest-stats-polling-interval",
+                                     &prop) < 0)
+        VIR_DEBUG("Failed to set polling interval for balloon driver");
+
+}
+
 static int
 qemuProcessFindCharDevicePTYsMonitor(virDomainObjPtr vm,
                                      virQEMUCapsPtr qemuCaps,
@@ -3047,6 +3191,12 @@ qemuProcessReconnect(void *opaque)
     if (qemuProcessRecoverJob(driver, obj, conn, &oldjob) < 0)
         goto error;
 
+    qemuDomainObjEnterMonitor(driver, obj);
+    if (qemuProcessFindBalloonObjectPath(priv->mon, obj, "/",
+                                         &priv->balloonpath) == 1)
+        qemuProcessUpdateBalloonStatsPeriod(priv->mon, priv->balloonpath, obj);
+    qemuDomainObjExitMonitor(driver, obj);
+
     /* update domain state XML with possibly updated state in virDomainObj */
     if (virDomainSaveStatus(driver->xmlopt, cfg->stateDir, obj) < 0)
         goto error;
@@ -3867,6 +4017,9 @@ int qemuProcessStart(virConnectPtr conn,
         goto cleanup;
     }
     qemuDomainObjEnterMonitor(driver, vm);
+    if (qemuProcessFindBalloonObjectPath(priv->mon, vm, "/",
+                                         &priv->balloonpath) == 1)
+        qemuProcessUpdateBalloonStatsPeriod(priv->mon, priv->balloonpath, vm);
     if (qemuMonitorSetBalloon(priv->mon, cur_balloon) < 0) {
         qemuDomainObjExitMonitor(driver, vm);
         goto cleanup;
@@ -4400,11 +4553,18 @@ int qemuProcessAttach(virConnectPtr conn ATTRIBUTE_UNUSED,
     if (!virDomainObjIsActive(vm))
         goto cleanup;
 
-    if (running)
+    if (running) {
         virDomainObjSetState(vm, VIR_DOMAIN_RUNNING,
                              VIR_DOMAIN_RUNNING_UNPAUSED);
-    else
+        qemuDomainObjEnterMonitor(driver, vm);
+        if (qemuProcessFindBalloonObjectPath(priv->mon, vm, "/",
+                                             &priv->balloonpath) == 1)
+            qemuProcessUpdateBalloonStatsPeriod(priv->mon,
+                                                priv->balloonpath, vm);
+        qemuDomainObjExitMonitor(driver, vm);
+    } else {
         virDomainObjSetState(vm, VIR_DOMAIN_PAUSED, reason);
+    }
 
     VIR_DEBUG("Writing domain status to disk");
     if (virDomainSaveStatus(driver->xmlopt, cfg->stateDir, vm) < 0)
-- 
1.8.1.4




More information about the libvir-list mailing list