]> xenbits.xensource.com Git - people/liuw/libxenctrl-split/libvirt.git/commitdiff
Determine whether to start balloon memory stats gathering.
authorJohn Ferlan <jferlan@redhat.com>
Thu, 27 Jun 2013 15:00:31 +0000 (11:00 -0400)
committerJohn Ferlan <jferlan@redhat.com>
Tue, 16 Jul 2013 12:44:52 +0000 (08:44 -0400)
At vm startup and attach attempt to set the balloon driver statistics
collection period based on the value found in the domain xml file. This
is not done at reconnect since it's possible that a collection period
was set on the live guest and making the set period call would reset to
whatever value is stored in the config file.

Setting the stats collection period has a side effect of searching through
the qom-list output for the virtio balloon driver and making sure that it
has the right properties in order to allow setting of a collection period
and eventually fetching of statistics.

The walk through the qom-list is expensive and thus the balloonpath will
be saved in the monitor private structure as well as a flag indicating
that the initialization has already been attempted (in the event that a
path is not found, no sense to keep checking).

This processing model conforms to the qom object model model which
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.

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 c1ac49324edfd15dfa7090fb54b407e26735c6fe..82d59591c8e324aa39dcc702f1f19d04daf11108 100644 (file)
@@ -83,6 +83,10 @@ struct _qemuMonitor {
 
     /* cache of query-command-line-options results */
     virJSONValuePtr options;
+
+    /* If found, path to the virtio memballoon driver */
+    char *balloonpath;
+    bool ballooninit;
 };
 
 static virClassPtr qemuMonitorClass;
@@ -248,6 +252,7 @@ static void qemuMonitorDispose(void *obj)
     virCondDestroy(&mon->notify);
     VIR_FREE(mon->buffer);
     virJSONValueFree(mon->options);
+    VIR_FREE(mon->balloonpath);
 }
 
 
@@ -925,6 +930,113 @@ qemuMonitorSetOptions(qemuMonitorPtr mon, virJSONValuePtr options)
     mon->options = options;
 }
 
+/* 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
+qemuMonitorFindBalloonObjectPath(qemuMonitorPtr mon,
+                                 virDomainObjPtr vm,
+                                 const char *curpath)
+{
+    size_t i, j, npaths = 0, nprops = 0;
+    int ret = 0;
+    char *nextpath = NULL;
+    qemuMonitorJSONListPathPtr *paths = NULL;
+    qemuMonitorJSONListPathPtr *bprops = NULL;
+
+    if (mon->balloonpath) {
+        return 1;
+    } else if (mon->ballooninit) {
+        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+                       _("Cannot determine balloon device path"));
+        return -1;
+    }
+
+    /* Not supported */
+    if (!vm->def->memballoon ||
+        vm->def->memballoon->model != VIR_DOMAIN_MEMBALLOON_MODEL_VIRTIO) {
+        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+                       _("Memory balloon model must be virtio to "
+                         "get memballoon path"));
+        return -1;
+    }
+
+    VIR_DEBUG("Searching for Balloon Object Path starting at %s", curpath);
+
+    npaths = qemuMonitorJSONGetObjectListPaths(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 = qemuMonitorJSONGetObjectListPaths(mon, nextpath, &bprops);
+            for (j = 0; j < nprops; j++) {
+                if (STREQ(bprops[j]->name, "guest-stats-polling-interval")) {
+                    VIR_DEBUG("Found Balloon Object Path %s", nextpath);
+                    mon->balloonpath = nextpath;
+                    nextpath = NULL;
+                    ret = 1;
+                    goto cleanup;
+                }
+            }
+
+            /* If we get here, we found the path, but not the property */
+            virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+                           _("Property 'guest-stats-polling-interval' "
+                             "not found on memory balloon driver."));
+            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) {
+                ret = -1;
+                goto cleanup;
+            }
+            ret = qemuMonitorFindBalloonObjectPath(mon, vm, nextpath);
+        }
+    }
+
+cleanup:
+    for (i = 0; i < npaths; i++)
+        qemuMonitorJSONListPathFree(paths[i]);
+    VIR_FREE(paths);
+    for (j = 0; j < nprops; j++)
+        qemuMonitorJSONListPathFree(bprops[j]);
+    VIR_FREE(bprops);
+    VIR_FREE(nextpath);
+    return ret;
+}
+
 int qemuMonitorHMPCommandWithFd(qemuMonitorPtr mon,
                                 const char *cmd,
                                 int scm_fd,
@@ -1386,6 +1498,32 @@ int qemuMonitorGetMemoryStats(qemuMonitorPtr mon,
     return ret;
 }
 
+int qemuMonitorSetMemoryStatsPeriod(qemuMonitorPtr mon,
+                                    int period)
+{
+    int ret = -1;
+    VIR_DEBUG("mon=%p period=%d", mon, period);
+
+    if (!mon) {
+        virReportError(VIR_ERR_INVALID_ARG, "%s",
+                       _("monitor must not be NULL"));
+        return -1;
+    }
+
+    if (!mon->json) {
+        virReportError(VIR_ERR_OPERATION_UNSUPPORTED, "%s",
+                       _("JSON monitor is required"));
+        return -1;
+    }
+
+    if (qemuMonitorFindBalloonObjectPath(mon, mon->vm, "/") == 1) {
+        ret = qemuMonitorJSONSetMemoryStatsPeriod(mon, mon->balloonpath,
+                                                  period);
+    }
+    mon->ballooninit = true;
+    return ret;
+}
+
 int
 qemuMonitorBlockIOStatusToError(const char *status)
 {
index 4d83bef815e5b706274a3c92ee1c935b5befbbf4..62df6b142c059ffbad67456afc058ef128057719 100644 (file)
@@ -265,6 +265,8 @@ int qemuMonitorGetBalloonInfo(qemuMonitorPtr mon,
 int qemuMonitorGetMemoryStats(qemuMonitorPtr mon,
                               virDomainMemoryStatPtr stats,
                               unsigned int nr_stats);
+int qemuMonitorSetMemoryStatsPeriod(qemuMonitorPtr mon,
+                                    int period);
 
 int qemuMonitorBlockIOStatusToError(const char *status);
 virHashTablePtr qemuMonitorGetBlockInfo(qemuMonitorPtr mon);
index 81af4f37956066252e388092917e333c4aa6e77a..40e1de412d10c6c5306bf2b69c6a998cf351f092 100644 (file)
@@ -1488,6 +1488,30 @@ cleanup:
 }
 
 
+/*
+ * Using the provided balloonpath, determine if we need to set the
+ * collection interval property to enable statistics gathering.
+ */
+int
+qemuMonitorJSONSetMemoryStatsPeriod(qemuMonitorPtr mon,
+                                    char *balloonpath,
+                                    int period)
+{
+    qemuMonitorJSONObjectProperty prop;
+
+    /* Set to the value in memballoon (could enable or disable) */
+    memset(&prop, 0, sizeof(qemuMonitorJSONObjectProperty));
+    prop.type = QEMU_MONITOR_OBJECT_PROPERTY_INT;
+    prop.val.iv = period;
+    if (qemuMonitorJSONSetObjectProperty(mon, balloonpath,
+                                         "guest-stats-polling-interval",
+                                         &prop) < 0) {
+        return -1;
+    }
+    return 0;
+}
+
+
 int qemuMonitorJSONGetBlockInfo(qemuMonitorPtr mon,
                                 virHashTablePtr table)
 {
index 658c451660932f0c2bae16903643394ff4480447..8daa7173e74f4abf6aee22511f5f79badbea90d1 100644 (file)
@@ -61,6 +61,9 @@ int qemuMonitorJSONGetBalloonInfo(qemuMonitorPtr mon,
 int qemuMonitorJSONGetMemoryStats(qemuMonitorPtr mon,
                                   virDomainMemoryStatPtr stats,
                                   unsigned int nr_stats);
+int qemuMonitorJSONSetMemoryStatsPeriod(qemuMonitorPtr mon,
+                                        char *balloonpath,
+                                        int period);
 int qemuMonitorJSONGetBlockInfo(qemuMonitorPtr mon,
                                 virHashTablePtr table);
 int qemuMonitorJSONGetBlockStatsInfo(qemuMonitorPtr mon,
index 574abf2500094740f013737c408a8fc4632844ec..3d5e8f6c4f00aa9bab60bd6d8cf932e7114de291 100644 (file)
@@ -3883,6 +3883,8 @@ int qemuProcessStart(virConnectPtr conn,
         goto cleanup;
     }
     qemuDomainObjEnterMonitor(driver, vm);
+    if (vm->def->memballoon && vm->def->memballoon->period)
+        qemuMonitorSetMemoryStatsPeriod(priv->mon, vm->def->memballoon->period);
     if (qemuMonitorSetBalloon(priv->mon, cur_balloon) < 0) {
         qemuDomainObjExitMonitor(driver, vm);
         goto cleanup;
@@ -4409,11 +4411,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
+        if (vm->def->memballoon && vm->def->memballoon->period) {
+            qemuDomainObjEnterMonitor(driver, vm);
+            qemuMonitorSetMemoryStatsPeriod(priv->mon,
+                                            vm->def->memballoon->period);
+            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)