[libvirt] [PATCH v3 05/10] Determine whether to start balloon memory stats gathering.
John Ferlan
jferlan at redhat.com
Fri Jul 12 14:40:01 UTC 2013
On 07/12/2013 08:39 AM, Daniel P. Berrange wrote:
> On Thu, Jul 11, 2013 at 07:55:55PM -0400, John Ferlan wrote:
>> 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 | 130 +++++++++++++++++++++++++++++++++++++++++++
>> src/qemu/qemu_monitor.h | 2 +
>> src/qemu/qemu_monitor_json.c | 24 ++++++++
>> src/qemu/qemu_monitor_json.h | 3 +
>> src/qemu/qemu_process.c | 14 ++++-
>> 5 files changed, 171 insertions(+), 2 deletions(-)
>>
>> diff --git a/src/qemu/qemu_monitor.c b/src/qemu/qemu_monitor.c
>> index 6f9a8fc..a3e250c 100644
>> --- a/src/qemu/qemu_monitor.c
>> +++ b/src/qemu/qemu_monitor.c
>> @@ -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,105 @@ 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;
>> +
>> + /* Already set and won't change or we already search and failed to find */
>> + if (mon->balloonpath || mon->ballooninit)
>> + return 1;
>
> This isn't correct logic. You need
>
> 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) {
>> + VIR_DEBUG("Model must be virtio to get memballoon path");
>
> You need to use virReportError here, so the caller sees an error
> messages.
>
>> + 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 */
>> + VIR_DEBUG("Property 'guest-stats-polling-interval' not found");
>> + ret = -1;
>
> And virReportERror here too
>
>> + 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 +1490,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)
>> {
>> diff --git a/src/qemu/qemu_monitor.h b/src/qemu/qemu_monitor.h
>> index 78011ee..12b730a 100644
>> --- a/src/qemu/qemu_monitor.h
>> +++ b/src/qemu/qemu_monitor.h
>> @@ -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);
>> diff --git a/src/qemu/qemu_monitor_json.c b/src/qemu/qemu_monitor_json.c
>> index 92d458c..a9e8723 100644
>> --- a/src/qemu/qemu_monitor_json.c
>> +++ b/src/qemu/qemu_monitor_json.c
>> @@ -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)
>> {
>> diff --git a/src/qemu/qemu_monitor_json.h b/src/qemu/qemu_monitor_json.h
>> index a857d86..e2324f1 100644
>> --- a/src/qemu/qemu_monitor_json.h
>> +++ b/src/qemu/qemu_monitor_json.h
>> @@ -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,
>> diff --git a/src/qemu/qemu_process.c b/src/qemu/qemu_process.c
>> index 574abf2..239c65f 100644
>> --- a/src/qemu/qemu_process.c
>> +++ b/src/qemu/qemu_process.c
>> @@ -3883,6 +3883,9 @@ int qemuProcessStart(virConnectPtr conn,
>> goto cleanup;
>> }
>> qemuDomainObjEnterMonitor(driver, vm);
>> + if (vm->def->memballoon)
>
> Should that be vm->def->memballoon && vm->def->memballoon->period.
>
> eg we don't want to call this if no balloon stats period was set
> in the XML.
>
>> + qemuMonitorSetMemoryStatsPeriod(priv->mon,
>> + vm->def->memballoon->period);
>> if (qemuMonitorSetBalloon(priv->mon, cur_balloon) < 0) {
>> qemuDomainObjExitMonitor(driver, vm);
>> goto cleanup;
>> @@ -4409,11 +4412,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) {
>
> Same here.
>
>> + 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)
>
> Regards,
> Daniel
>
I've squashed the following in:
diff --git a/src/qemu/qemu_monitor.c b/src/qemu/qemu_monitor.c
index 424af38..82d5959 100644
--- a/src/qemu/qemu_monitor.c
+++ b/src/qemu/qemu_monitor.c
@@ -960,14 +960,20 @@ qemuMonitorFindBalloonObjectPath(qemuMonitorPtr mon,
qemuMonitorJSONListPathPtr *paths = NULL;
qemuMonitorJSONListPathPtr *bprops = NULL;
- /* Already set and won't change or we already search and failed to find */
- if (mon->balloonpath || mon->ballooninit)
+ 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) {
- VIR_DEBUG("Model must be virtio to get memballoon path");
+ virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+ _("Memory balloon model must be virtio to "
+ "get memballoon path"));
return -1;
}
@@ -1001,7 +1007,9 @@ qemuMonitorFindBalloonObjectPath(qemuMonitorPtr mon,
}
/* If we get here, we found the path, but not the property */
- VIR_DEBUG("Property 'guest-stats-polling-interval' not found");
+ virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+ _("Property 'guest-stats-polling-interval' "
+ "not found on memory balloon driver."));
ret = -1;
goto cleanup;
}
diff --git a/src/qemu/qemu_process.c b/src/qemu/qemu_process.c
index 239c65f..3d5e8f6 100644
--- a/src/qemu/qemu_process.c
+++ b/src/qemu/qemu_process.c
@@ -3883,9 +3883,8 @@ int qemuProcessStart(virConnectPtr conn,
goto cleanup;
}
qemuDomainObjEnterMonitor(driver, vm);
- if (vm->def->memballoon)
- qemuMonitorSetMemoryStatsPeriod(priv->mon,
- vm->def->memballoon->period);
+ 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;
@@ -4415,7 +4414,7 @@ int qemuProcessAttach(virConnectPtr conn ATTRIBUTE_UNUSED,
if (running) {
virDomainObjSetState(vm, VIR_DOMAIN_RUNNING,
VIR_DOMAIN_RUNNING_UNPAUSED);
- if (vm->def->memballoon) {
+ if (vm->def->memballoon && vm->def->memballoon->period) {
qemuDomainObjEnterMonitor(driver, vm);
qemuMonitorSetMemoryStatsPeriod(priv->mon,
vm->def->memballoon->period);
More information about the libvir-list
mailing list