[libvirt] [PATCH v3 00/10] Re-enable memballoon driver statistics reporting

This patch set replaces: https://www.redhat.com/archives/libvir-list/2013-July/msg00435.html Changes 01 -> No change 02 & 03 -> Adjust typecaste to switch() and remove "default:" 04 -> Use "unsigned int" as requested 05 -> Add ballooninit, remove get of period before set, remove setting of period during reconnect, other changes per review 06 -> Remove the opaque structure, replace with direct call through "qom-get" to return "guest-stats" and fill in stats[] directly 07 -> 09-> Remove the "flags", "Flags", "FLAGS" (learned something new!) 10 -> Add virsh.pod (hopefully have syntax right). NOTE: The formatdomain.html.in was already updated in 04 to describe the <stats period='#'/> XML syntax. This change describes the virsh command in order to set the period since this is the change where virsh code was adjusted. In 04, all one could do would be virsh edit John Ferlan (10): Add qemuMonitorJSONGetObjectListPaths() method for QMP qom-list command Add qemuMonitorJSONGetObjectProperty() method for QMP qom-get command Add qemuMonitorJSONSetObjectProperty() method for QMP qom-set command Add 'period' for Memballoon statistics gathering capability Determine whether to start balloon memory stats gathering. Add capability to fetch balloon stats Add new public API virDomainSetMemoryStatsPeriodFlags Specify remote protocol for virDomainSetMemoryStatsPeriodFlags Implement the virDomainSetMemoryStatsPeriodFlags for QEMU driver Allow balloon driver collection to be adjusted dynamically docs/formatdomain.html.in | 19 ++ docs/schemas/domaincommon.rng | 7 + include/libvirt/libvirt.h.in | 3 + src/conf/domain_conf.c | 38 +++- src/conf/domain_conf.h | 1 + src/driver.h | 6 + src/libvirt.c | 64 ++++++ src/libvirt_public.syms | 5 + src/qemu/qemu_driver.c | 65 ++++++ src/qemu/qemu_monitor.c | 140 ++++++++++++- src/qemu/qemu_monitor.h | 2 + src/qemu/qemu_monitor_json.c | 460 ++++++++++++++++++++++++++++++++---------- src/qemu/qemu_monitor_json.h | 60 ++++++ src/qemu/qemu_process.c | 14 +- src/remote/remote_driver.c | 1 + src/remote/remote_protocol.x | 15 +- src/remote_protocol-structs | 6 + tests/qemumonitorjsontest.c | 186 +++++++++++++++++ tools/virsh-domain-monitor.c | 66 +++++- tools/virsh.pod | 22 +- 20 files changed, 1060 insertions(+), 120 deletions(-) -- 1.8.1.4

Add a new qemuMonitorJSONGetObjectListPaths() method to support invocation of the 'qom-list' JSON monitor command with a provided path. The returned list of paired data fields of "name" and "type" that can be used to peruse QOM configuration data and eventually utilize for the balloon statistics. The test does a "{"execute":"qom-list", "arguments": { "path": "/"}}" which returns "{"return": [{"name": "machine", "type": "child<container>"}, {"name": "type", "type": "string"}]}" resulting in a return of an array of 2 elements with [0].name="machine", [0].type="child<container>". The [1] entry appears to be a header that could be used some day via a command such as "virsh qemuobject --list" to format output. --- src/qemu/qemu_monitor_json.c | 98 ++++++++++++++++++++++++++++++++++++++++++++ src/qemu/qemu_monitor_json.h | 16 ++++++++ tests/qemumonitorjsontest.c | 79 +++++++++++++++++++++++++++++++++++ 3 files changed, 193 insertions(+) diff --git a/src/qemu/qemu_monitor_json.c b/src/qemu/qemu_monitor_json.c index 63e890a..216a58c 100644 --- a/src/qemu/qemu_monitor_json.c +++ b/src/qemu/qemu_monitor_json.c @@ -4507,6 +4507,104 @@ cleanup: } +int qemuMonitorJSONGetObjectListPaths(qemuMonitorPtr mon, + const char *path, + qemuMonitorJSONListPathPtr **paths) +{ + int ret; + virJSONValuePtr cmd; + virJSONValuePtr reply = NULL; + virJSONValuePtr data; + qemuMonitorJSONListPathPtr *pathlist = NULL; + int n = 0; + size_t i; + + *paths = NULL; + + if (!(cmd = qemuMonitorJSONMakeCommand("qom-list", + "s:path", path, + NULL))) + return -1; + + ret = qemuMonitorJSONCommand(mon, cmd, &reply); + + if (ret == 0) + ret = qemuMonitorJSONCheckError(cmd, reply); + + if (ret < 0) + goto cleanup; + + ret = -1; + + if (!(data = virJSONValueObjectGet(reply, "return"))) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("qom-list reply was missing return data")); + goto cleanup; + } + + if ((n = virJSONValueArraySize(data)) < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("qom-list reply data was not an array")); + goto cleanup; + } + + /* null-terminated list */ + if (VIR_ALLOC_N(pathlist, n + 1) < 0) + goto cleanup; + + for (i = 0; i < n; i++) { + virJSONValuePtr child = virJSONValueArrayGet(data, i); + const char *tmp; + qemuMonitorJSONListPathPtr info; + + if (VIR_ALLOC(info) < 0) + goto cleanup; + + pathlist[i] = info; + + if (!(tmp = virJSONValueObjectGetString(child, "name"))) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("qom-list reply data was missing 'name'")); + goto cleanup; + } + + if (VIR_STRDUP(info->name, tmp) < 0) + goto cleanup; + + if (virJSONValueObjectHasKey(child, "type")) { + if (!(tmp = virJSONValueObjectGetString(child, "type"))) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("qom-list reply has malformed 'type' data")); + goto cleanup; + } + if (VIR_STRDUP(info->type, tmp) < 0) + goto cleanup; + } + } + + ret = n; + *paths = pathlist; + +cleanup: + if (ret < 0 && pathlist) { + for (i = 0; i < n; i++) + qemuMonitorJSONListPathFree(pathlist[i]); + VIR_FREE(pathlist); + } + virJSONValueFree(cmd); + virJSONValueFree(reply); + return ret; +} + +void qemuMonitorJSONListPathFree(qemuMonitorJSONListPathPtr paths) +{ + if (!paths) + return; + VIR_FREE(paths->name); + VIR_FREE(paths->type); + VIR_FREE(paths); +} + int qemuMonitorJSONGetObjectProps(qemuMonitorPtr mon, const char *type, char ***props) diff --git a/src/qemu/qemu_monitor_json.h b/src/qemu/qemu_monitor_json.h index d79b86b..e7ce145 100644 --- a/src/qemu/qemu_monitor_json.h +++ b/src/qemu/qemu_monitor_json.h @@ -332,6 +332,22 @@ int qemuMonitorJSONGetKVMState(qemuMonitorPtr mon, int qemuMonitorJSONGetObjectTypes(qemuMonitorPtr mon, char ***types) ATTRIBUTE_NONNULL(2); + +typedef struct _qemuMonitorJSONListPath qemuMonitorJSONListPath; +typedef qemuMonitorJSONListPath *qemuMonitorJSONListPathPtr; + +struct _qemuMonitorJSONListPath { + char *name; + char *type; +}; + +int qemuMonitorJSONGetObjectListPaths(qemuMonitorPtr mon, + const char *path, + qemuMonitorJSONListPathPtr **paths) + ATTRIBUTE_NONNULL(2) ATTRIBUTE_NONNULL(3); + +void qemuMonitorJSONListPathFree(qemuMonitorJSONListPathPtr paths); + int qemuMonitorJSONGetObjectProps(qemuMonitorPtr mon, const char *type, char ***props) diff --git a/tests/qemumonitorjsontest.c b/tests/qemumonitorjsontest.c index 14d3700..7841658 100644 --- a/tests/qemumonitorjsontest.c +++ b/tests/qemumonitorjsontest.c @@ -23,6 +23,7 @@ #include "testutilsqemu.h" #include "qemumonitortestutils.h" #include "qemu/qemu_conf.h" +#include "qemu/qemu_monitor_json.h" #include "virthread.h" #include "virerror.h" #include "virstring.h" @@ -595,6 +596,83 @@ cleanup: } +/* + * This test will request to return a list of paths for "/". It should be + * a simple list of 1 real element that being the "machine". The following + * is the execution and expected return: + * + * {"execute":"qom-list", "arguments": { "path": "/"}}" + * {"return": [{"name": "machine", "type": "child<container>"}, \ + * {"name": "type", "type": "string"}]} + */ +static int +testQemuMonitorJSONGetListPaths(const void *data) +{ + const virDomainXMLOptionPtr xmlopt = (virDomainXMLOptionPtr)data; + qemuMonitorTestPtr test = qemuMonitorTestNew(true, xmlopt); + int ret = -1; + qemuMonitorJSONListPathPtr *paths; + int npaths = 0; + size_t i; + + if (!test) + return -1; + + if (qemuMonitorTestAddItem(test, "qom-list", + "{ " + " \"return\": [ " + " {\"name\": \"machine\", " + " \"type\": \"child<container>\"}, " + " {\"name\": \"type\", " + " \"type\": \"string\"} " + " ]" + "}") < 0) + goto cleanup; + + /* present with path */ + if ((npaths = qemuMonitorJSONGetObjectListPaths( + qemuMonitorTestGetMonitor(test), + "/", + &paths)) < 0) + goto cleanup; + + if (npaths != 2) { + virReportError(VIR_ERR_INTERNAL_ERROR, + "npaths was %d, expected 1", npaths); + goto cleanup; + } + +#define CHECK(i, wantname, wanttype) \ + do { \ + if (STRNEQ(paths[i]->name, (wantname))) { \ + virReportError(VIR_ERR_INTERNAL_ERROR, \ + "name was %s, expected %s", \ + paths[i]->name, (wantname)); \ + goto cleanup; \ + } \ + if (STRNEQ_NULLABLE(paths[i]->type, (wanttype))) { \ + virReportError(VIR_ERR_INTERNAL_ERROR, \ + "type was %s, expected %s", \ + NULLSTR(paths[i]->type), (wanttype)); \ + goto cleanup; \ + } \ + } while (0) + + CHECK(0, "machine", "child<container>"); + +#undef CHECK + + ret = 0; + +cleanup: + qemuMonitorTestFree(test); + for (i = 0; i < npaths; i++) + qemuMonitorJSONListPathFree(paths[i]); + VIR_FREE(paths); + return ret; +} + + static int mymain(void) { @@ -623,6 +701,7 @@ mymain(void) DO_TEST(GetCommands); DO_TEST(GetTPMModels); DO_TEST(GetCommandLineOptionParameters); + DO_TEST(GetListPaths); virObjectUnref(xmlopt); -- 1.8.1.4

On Thu, Jul 11, 2013 at 07:55:51PM -0400, John Ferlan wrote:
Add a new qemuMonitorJSONGetObjectListPaths() method to support invocation of the 'qom-list' JSON monitor command with a provided path.
The returned list of paired data fields of "name" and "type" that can be used to peruse QOM configuration data and eventually utilize for the balloon statistics.
The test does a "{"execute":"qom-list", "arguments": { "path": "/"}}" which returns "{"return": [{"name": "machine", "type": "child<container>"}, {"name": "type", "type": "string"}]}" resulting in a return of an array of 2 elements with [0].name="machine", [0].type="child<container>". The [1] entry appears to be a header that could be used some day via a command such as "virsh qemuobject --list" to format output. --- src/qemu/qemu_monitor_json.c | 98 ++++++++++++++++++++++++++++++++++++++++++++ src/qemu/qemu_monitor_json.h | 16 ++++++++ tests/qemumonitorjsontest.c | 79 +++++++++++++++++++++++++++++++++++ 3 files changed, 193 insertions(+)
ACK Daniel -- |: http://berrange.com -o- http://www.flickr.com/photos/dberrange/ :| |: http://libvirt.org -o- http://virt-manager.org :| |: http://autobuild.org -o- http://search.cpan.org/~danberr/ :| |: http://entangle-photo.org -o- http://live.gnome.org/gtk-vnc :|

On 07/12/2013 06:34 AM, Daniel P. Berrange wrote:
On Thu, Jul 11, 2013 at 07:55:51PM -0400, John Ferlan wrote:
Add a new qemuMonitorJSONGetObjectListPaths() method to support invocation of the 'qom-list' JSON monitor command with a provided path.
The returned list of paired data fields of "name" and "type" that can be used to peruse QOM configuration data and eventually utilize for the balloon statistics.
The test does a "{"execute":"qom-list", "arguments": { "path": "/"}}" which returns "{"return": [{"name": "machine", "type": "child<container>"}, {"name": "type", "type": "string"}]}" resulting in a return of an array of 2 elements with [0].name="machine", [0].type="child<container>". The [1] entry appears to be a header that could be used some day via a command such as "virsh qemuobject --list" to format output. --- src/qemu/qemu_monitor_json.c | 98 ++++++++++++++++++++++++++++++++++++++++++++ src/qemu/qemu_monitor_json.h | 16 ++++++++ tests/qemumonitorjsontest.c | 79 +++++++++++++++++++++++++++++++++++ 3 files changed, 193 insertions(+)
ACK
I'm still not convinced we need to touch the .h file; why can't the new function be static and the data types be local to the .c file? -- Eric Blake eblake redhat com +1-919-301-3266 Libvirt virtualization library http://libvirt.org

Add a new qemuMonitorJSONGetObjectProperty() method to support invocation of the 'qom-get' JSON monitor command with a provided path, property, and expected data type return. The qemuMonitorJSONObjectProperty is similar to virTypedParameter; however, a future patch will extend it a bit to include a void pointer to balloon driver statistic data. The provided test will execute a qom-get on "/machine/i440fx" which will return a property "realized". --- src/qemu/qemu_monitor_json.c | 86 ++++++++++++++++++++++++++++++++++++++++++++ src/qemu/qemu_monitor_json.h | 34 ++++++++++++++++++ tests/qemumonitorjsontest.c | 48 +++++++++++++++++++++++++ 3 files changed, 168 insertions(+) diff --git a/src/qemu/qemu_monitor_json.c b/src/qemu/qemu_monitor_json.c index 216a58c..62f2bf0 100644 --- a/src/qemu/qemu_monitor_json.c +++ b/src/qemu/qemu_monitor_json.c @@ -4605,6 +4605,92 @@ void qemuMonitorJSONListPathFree(qemuMonitorJSONListPathPtr paths) VIR_FREE(paths); } + +int qemuMonitorJSONGetObjectProperty(qemuMonitorPtr mon, + const char *path, + const char *property, + qemuMonitorJSONObjectPropertyPtr prop) +{ + int ret; + virJSONValuePtr cmd; + virJSONValuePtr reply = NULL; + virJSONValuePtr data; + const char *tmp; + + if (!(cmd = qemuMonitorJSONMakeCommand("qom-get", + "s:path", path, + "s:property", property, + NULL))) + return -1; + + ret = qemuMonitorJSONCommand(mon, cmd, &reply); + + if (ret == 0) + ret = qemuMonitorJSONCheckError(cmd, reply); + + if (ret < 0) + goto cleanup; + + ret = -1; + + if (!(data = virJSONValueObjectGet(reply, "return"))) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("qom-get reply was missing return data")); + goto cleanup; + } + + switch ((qemuMonitorJSONObjectPropertyType) prop->type) { + /* Simple cases of boolean, int, long, uint, ulong, double, and string + * will receive return value as part of {"return": xxx} statement + */ + case QEMU_MONITOR_OBJECT_PROPERTY_BOOLEAN: + ret = virJSONValueGetBoolean(data, &prop->val.b); + break; + case QEMU_MONITOR_OBJECT_PROPERTY_INT: + ret = virJSONValueGetNumberInt(data, &prop->val.iv); + break; + case QEMU_MONITOR_OBJECT_PROPERTY_LONG: + ret = virJSONValueGetNumberLong(data, &prop->val.l); + break; + case QEMU_MONITOR_OBJECT_PROPERTY_UINT: + ret = virJSONValueGetNumberUint(data, &prop->val.ui); + break; + case QEMU_MONITOR_OBJECT_PROPERTY_ULONG: + ret = virJSONValueGetNumberUlong(data, &prop->val.ul); + break; + case QEMU_MONITOR_OBJECT_PROPERTY_DOUBLE: + ret = virJSONValueGetNumberDouble(data, &prop->val.d); + break; + case QEMU_MONITOR_OBJECT_PROPERTY_STRING: + tmp = virJSONValueGetString(data); + if (tmp && VIR_STRDUP(prop->val.str, tmp) < 0) + goto cleanup; + if (tmp) + ret = 0; + break; + case QEMU_MONITOR_OBJECT_PROPERTY_LAST: + virReportError(VIR_ERR_INTERNAL_ERROR, + _("qom-get invalid object property type %d"), + prop->type); + goto cleanup; + break; + } + + if (ret == -1) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("qom-get reply was missing return data")); + goto cleanup; + } + + ret = 0; +cleanup: + virJSONValueFree(cmd); + virJSONValueFree(reply); + + return ret; +} + + int qemuMonitorJSONGetObjectProps(qemuMonitorPtr mon, const char *type, char ***props) diff --git a/src/qemu/qemu_monitor_json.h b/src/qemu/qemu_monitor_json.h index e7ce145..322e3fd 100644 --- a/src/qemu/qemu_monitor_json.h +++ b/src/qemu/qemu_monitor_json.h @@ -348,6 +348,40 @@ int qemuMonitorJSONGetObjectListPaths(qemuMonitorPtr mon, void qemuMonitorJSONListPathFree(qemuMonitorJSONListPathPtr paths); +/* Flags for the 'type' field in _qemuMonitorJSONObjectProperty */ +typedef enum { + QEMU_MONITOR_OBJECT_PROPERTY_BOOLEAN=1, + QEMU_MONITOR_OBJECT_PROPERTY_INT, + QEMU_MONITOR_OBJECT_PROPERTY_LONG, + QEMU_MONITOR_OBJECT_PROPERTY_UINT, + QEMU_MONITOR_OBJECT_PROPERTY_ULONG, + QEMU_MONITOR_OBJECT_PROPERTY_DOUBLE, + QEMU_MONITOR_OBJECT_PROPERTY_STRING, + + QEMU_MONITOR_OBJECT_PROPERTY_LAST +} qemuMonitorJSONObjectPropertyType; + +typedef struct _qemuMonitorJSONObjectProperty qemuMonitorJSONObjectProperty; +typedef qemuMonitorJSONObjectProperty *qemuMonitorJSONObjectPropertyPtr; +struct _qemuMonitorJSONObjectProperty { + int type; /* qemuMonitorJSONObjectPropertyType */ + union { + bool b; + int iv; + long long l; + unsigned int ui; + unsigned long long ul; + double d; + char *str; + } val; +}; + +int qemuMonitorJSONGetObjectProperty(qemuMonitorPtr mon, + const char *path, + const char *property, + qemuMonitorJSONObjectPropertyPtr prop) + ATTRIBUTE_NONNULL(2) ATTRIBUTE_NONNULL(3) ATTRIBUTE_NONNULL(4); + int qemuMonitorJSONGetObjectProps(qemuMonitorPtr mon, const char *type, char ***props) diff --git a/tests/qemumonitorjsontest.c b/tests/qemumonitorjsontest.c index 7841658..660f251 100644 --- a/tests/qemumonitorjsontest.c +++ b/tests/qemumonitorjsontest.c @@ -673,6 +673,53 @@ cleanup: } +/* + * This test will use a path to /machine/i440fx which should exist in order + * to ensure that the qom-get property fetch works properly. The following + * is the execution and expected return: + * + * + * { "execute": "qom-get","arguments": \ + * { "path": "/machine/i440fx","property": "realized"}} + * {"return": true} + */ +static int +testQemuMonitorJSONGetObjectProperty(const void *data) +{ + const virDomainXMLOptionPtr xmlopt = (virDomainXMLOptionPtr)data; + qemuMonitorTestPtr test = qemuMonitorTestNew(true, xmlopt); + int ret = -1; + qemuMonitorJSONObjectProperty prop; + + if (!test) + return -1; + + if (qemuMonitorTestAddItem(test, "qom-get", + "{ \"return\": true }") < 0) + goto cleanup; + + /* Present with path and property */ + memset(&prop, 0, sizeof(qemuMonitorJSONObjectProperty)); + prop.type = QEMU_MONITOR_OBJECT_PROPERTY_BOOLEAN; + if (qemuMonitorJSONGetObjectProperty(qemuMonitorTestGetMonitor(test), + "/machine/i440fx", + "realized", + &prop) < 0) + goto cleanup; + + if (!prop.val.b) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + "expected true, but false returned"); + goto cleanup; + } + + ret = 0; +cleanup: + qemuMonitorTestFree(test); + return ret; +} + + static int mymain(void) { @@ -702,6 +749,7 @@ mymain(void) DO_TEST(GetTPMModels); DO_TEST(GetCommandLineOptionParameters); DO_TEST(GetListPaths); + DO_TEST(GetObjectProperty); virObjectUnref(xmlopt); -- 1.8.1.4

On Thu, Jul 11, 2013 at 07:55:52PM -0400, John Ferlan wrote:
Add a new qemuMonitorJSONGetObjectProperty() method to support invocation of the 'qom-get' JSON monitor command with a provided path, property, and expected data type return. The qemuMonitorJSONObjectProperty is similar to virTypedParameter; however, a future patch will extend it a bit to include a void pointer to balloon driver statistic data.
The provided test will execute a qom-get on "/machine/i440fx" which will return a property "realized". --- src/qemu/qemu_monitor_json.c | 86 ++++++++++++++++++++++++++++++++++++++++++++ src/qemu/qemu_monitor_json.h | 34 ++++++++++++++++++ tests/qemumonitorjsontest.c | 48 +++++++++++++++++++++++++ 3 files changed, 168 insertions(+)
ACK Daniel -- |: http://berrange.com -o- http://www.flickr.com/photos/dberrange/ :| |: http://libvirt.org -o- http://virt-manager.org :| |: http://autobuild.org -o- http://search.cpan.org/~danberr/ :| |: http://entangle-photo.org -o- http://live.gnome.org/gtk-vnc :|

Add a new qemuMonitorJSONSetObjectProperty() method to support invocation of the 'qom-set' JSON monitor command with a provided path, property, and expected data type to set. The test code uses the same "/machine/i440fx" property as the get test and attempts to set the "realized" property to "true" (which it should be set at anyway). --- src/qemu/qemu_monitor_json.c | 62 ++++++++++++++++++++++++++++++++++++++++++++ src/qemu/qemu_monitor_json.h | 6 +++++ tests/qemumonitorjsontest.c | 59 +++++++++++++++++++++++++++++++++++++++++ 3 files changed, 127 insertions(+) diff --git a/src/qemu/qemu_monitor_json.c b/src/qemu/qemu_monitor_json.c index 62f2bf0..92d458c 100644 --- a/src/qemu/qemu_monitor_json.c +++ b/src/qemu/qemu_monitor_json.c @@ -4691,6 +4691,68 @@ cleanup: } +#define MAKE_SET_CMD(STRING, VALUE) \ + cmd = qemuMonitorJSONMakeCommand("qom-set", \ + "s:path", path, \ + "s:property", property, \ + STRING, VALUE, \ + NULL) +int qemuMonitorJSONSetObjectProperty(qemuMonitorPtr mon, + const char *path, + const char *property, + qemuMonitorJSONObjectPropertyPtr prop) +{ + int ret = -1; + virJSONValuePtr cmd = NULL; + virJSONValuePtr reply = NULL; + + switch ((qemuMonitorJSONObjectPropertyType) prop->type) { + /* Simple cases of boolean, int, long, uint, ulong, double, and string + * will receive return value as part of {"return": xxx} statement + */ + case QEMU_MONITOR_OBJECT_PROPERTY_BOOLEAN: + MAKE_SET_CMD("b:value", prop->val.b); + break; + case QEMU_MONITOR_OBJECT_PROPERTY_INT: + MAKE_SET_CMD("i:value", prop->val.iv); + break; + case QEMU_MONITOR_OBJECT_PROPERTY_LONG: + MAKE_SET_CMD("I:value", prop->val.l); + break; + case QEMU_MONITOR_OBJECT_PROPERTY_UINT: + MAKE_SET_CMD("u:value", prop->val.ui); + break; + case QEMU_MONITOR_OBJECT_PROPERTY_ULONG: + MAKE_SET_CMD("U:value", prop->val.ul); + break; + case QEMU_MONITOR_OBJECT_PROPERTY_DOUBLE: + MAKE_SET_CMD("d:value", prop->val.d); + break; + case QEMU_MONITOR_OBJECT_PROPERTY_STRING: + MAKE_SET_CMD("s:value", prop->val.str); + break; + case QEMU_MONITOR_OBJECT_PROPERTY_LAST: + virReportError(VIR_ERR_INTERNAL_ERROR, + _("qom-set invalid object property type %d"), + prop->type); + goto cleanup; + + } + if (!cmd) + return -1; + + if ((ret = qemuMonitorJSONCommand(mon, cmd, &reply)) == 0) + ret = qemuMonitorJSONCheckError(cmd, reply); + +cleanup: + virJSONValueFree(cmd); + virJSONValueFree(reply); + + return ret; +} +#undef MAKE_SET_CMD + + int qemuMonitorJSONGetObjectProps(qemuMonitorPtr mon, const char *type, char ***props) diff --git a/src/qemu/qemu_monitor_json.h b/src/qemu/qemu_monitor_json.h index 322e3fd..a857d86 100644 --- a/src/qemu/qemu_monitor_json.h +++ b/src/qemu/qemu_monitor_json.h @@ -382,6 +382,12 @@ int qemuMonitorJSONGetObjectProperty(qemuMonitorPtr mon, qemuMonitorJSONObjectPropertyPtr prop) ATTRIBUTE_NONNULL(2) ATTRIBUTE_NONNULL(3) ATTRIBUTE_NONNULL(4); +int qemuMonitorJSONSetObjectProperty(qemuMonitorPtr mon, + const char *path, + const char *property, + qemuMonitorJSONObjectPropertyPtr prop) + ATTRIBUTE_NONNULL(2) ATTRIBUTE_NONNULL(3) ATTRIBUTE_NONNULL(4); + int qemuMonitorJSONGetObjectProps(qemuMonitorPtr mon, const char *type, char ***props) diff --git a/tests/qemumonitorjsontest.c b/tests/qemumonitorjsontest.c index 660f251..edabca8 100644 --- a/tests/qemumonitorjsontest.c +++ b/tests/qemumonitorjsontest.c @@ -720,6 +720,64 @@ cleanup: } +/* + * This test will use a path to /machine/i440fx which should exist in order + * to ensure that the qom-set property set works properly. The test will + * set a true property to true just as a proof of concept. Setting it to + * false is not a good idea... + */ +static int +testQemuMonitorJSONSetObjectProperty(const void *data) +{ + const virDomainXMLOptionPtr xmlopt = (virDomainXMLOptionPtr)data; + qemuMonitorTestPtr test = qemuMonitorTestNew(true, xmlopt); + int ret = -1; + qemuMonitorJSONObjectProperty prop; + + if (!test) + return -1; + + if (qemuMonitorTestAddItem(test, "qom-set", + "{ \"return\": {} }") < 0) + goto cleanup; + if (qemuMonitorTestAddItem(test, "qom-get", + "{ \"return\": true }") < 0) + goto cleanup; + + /* Let's attempt the setting */ + memset(&prop, 0, sizeof(qemuMonitorJSONObjectProperty)); + prop.type = QEMU_MONITOR_OBJECT_PROPERTY_BOOLEAN; + prop.val.b = true; + if (qemuMonitorJSONSetObjectProperty(qemuMonitorTestGetMonitor(test), + "/machine/i440fx", + "realized", + &prop) < 0) + goto cleanup; + + /* To make sure it worked, fetch the property - if this succeeds then + * we didn't hose things + */ + memset(&prop, 0, sizeof(qemuMonitorJSONObjectProperty)); + prop.type = QEMU_MONITOR_OBJECT_PROPERTY_BOOLEAN; + if (qemuMonitorJSONGetObjectProperty(qemuMonitorTestGetMonitor(test), + "/machine/i440fx", + "realized", + &prop) < 0) + goto cleanup; + + if (!prop.val.b) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + "expected true, but false returned"); + goto cleanup; + } + + ret = 0; +cleanup: + qemuMonitorTestFree(test); + return ret; +} + + static int mymain(void) { @@ -750,6 +808,7 @@ mymain(void) DO_TEST(GetCommandLineOptionParameters); DO_TEST(GetListPaths); DO_TEST(GetObjectProperty); + DO_TEST(SetObjectProperty); virObjectUnref(xmlopt); -- 1.8.1.4

On Thu, Jul 11, 2013 at 07:55:53PM -0400, John Ferlan wrote:
Add a new qemuMonitorJSONSetObjectProperty() method to support invocation of the 'qom-set' JSON monitor command with a provided path, property, and expected data type to set.
The test code uses the same "/machine/i440fx" property as the get test and attempts to set the "realized" property to "true" (which it should be set at anyway). --- src/qemu/qemu_monitor_json.c | 62 ++++++++++++++++++++++++++++++++++++++++++++ src/qemu/qemu_monitor_json.h | 6 +++++ tests/qemumonitorjsontest.c | 59 +++++++++++++++++++++++++++++++++++++++++ 3 files changed, 127 insertions(+)
ACK Daniel -- |: http://berrange.com -o- http://www.flickr.com/photos/dberrange/ :| |: http://libvirt.org -o- http://virt-manager.org :| |: http://autobuild.org -o- http://search.cpan.org/~danberr/ :| |: http://entangle-photo.org -o- http://live.gnome.org/gtk-vnc :|

On 07/12/2013 06:35 AM, Daniel P. Berrange wrote:
On Thu, Jul 11, 2013 at 07:55:53PM -0400, John Ferlan wrote:
Add a new qemuMonitorJSONSetObjectProperty() method to support invocation of the 'qom-set' JSON monitor command with a provided path, property, and expected data type to set.
The test code uses the same "/machine/i440fx" property as the get test and attempts to set the "realized" property to "true" (which it should be set at anyway). --- src/qemu/qemu_monitor_json.c | 62 ++++++++++++++++++++++++++++++++++++++++++++ src/qemu/qemu_monitor_json.h | 6 +++++ tests/qemumonitorjsontest.c | 59 +++++++++++++++++++++++++++++++++++++++++ 3 files changed, 127 insertions(+)
ACK
Again, shouldn't this function be marked static, and the .h file left alone? -- Eric Blake eblake redhat com +1-919-301-3266 Libvirt virtualization library http://libvirt.org

On 07/12/2013 11:57 AM, Eric Blake wrote:
On 07/12/2013 06:35 AM, Daniel P. Berrange wrote:
On Thu, Jul 11, 2013 at 07:55:53PM -0400, John Ferlan wrote:
Add a new qemuMonitorJSONSetObjectProperty() method to support invocation of the 'qom-set' JSON monitor command with a provided path, property, and expected data type to set.
The test code uses the same "/machine/i440fx" property as the get test and attempts to set the "realized" property to "true" (which it should be set at anyway). --- src/qemu/qemu_monitor_json.c | 62 ++++++++++++++++++++++++++++++++++++++++++++ src/qemu/qemu_monitor_json.h | 6 +++++ tests/qemumonitorjsontest.c | 59 +++++++++++++++++++++++++++++++++++++++++ 3 files changed, 127 insertions(+)
ACK
Again, shouldn't this function be marked static, and the .h file left alone?
I can go either way on this - without the .h changes, we don't have the test though. So whichever way is preferred - I'll go with it... John

On 07/12/2013 10:34 AM, John Ferlan wrote:
On 07/12/2013 11:57 AM, Eric Blake wrote:
On 07/12/2013 06:35 AM, Daniel P. Berrange wrote:
On Thu, Jul 11, 2013 at 07:55:53PM -0400, John Ferlan wrote:
Add a new qemuMonitorJSONSetObjectProperty() method to support invocation of the 'qom-set' JSON monitor command with a provided path, property, and expected data type to set.
The test code uses the same "/machine/i440fx" property as the get test and attempts to set the "realized" property to "true" (which it should be set at anyway). --- src/qemu/qemu_monitor_json.c | 62 ++++++++++++++++++++++++++++++++++++++++++++ src/qemu/qemu_monitor_json.h | 6 +++++ tests/qemumonitorjsontest.c | 59 +++++++++++++++++++++++++++++++++++++++++ 3 files changed, 127 insertions(+)
ACK
Again, shouldn't this function be marked static, and the .h file left alone?
I can go either way on this - without the .h changes, we don't have the test though. So whichever way is preferred - I'll go with it...
Ah, so the test case is the reason you are exporting the file. That's reason enough to leave the patch body as-is, but do amend the commit message to mention this. It might also be worth a comment in the .h that the function is public only for the testsuite, so we aren't tempted to use it from qemu_driver.c later. -- Eric Blake eblake redhat com +1-919-301-3266 Libvirt virtualization library http://libvirt.org

On Fri, Jul 12, 2013 at 10:37:12AM -0600, Eric Blake wrote:
On 07/12/2013 10:34 AM, John Ferlan wrote:
On 07/12/2013 11:57 AM, Eric Blake wrote:
On 07/12/2013 06:35 AM, Daniel P. Berrange wrote:
On Thu, Jul 11, 2013 at 07:55:53PM -0400, John Ferlan wrote:
Add a new qemuMonitorJSONSetObjectProperty() method to support invocation of the 'qom-set' JSON monitor command with a provided path, property, and expected data type to set.
The test code uses the same "/machine/i440fx" property as the get test and attempts to set the "realized" property to "true" (which it should be set at anyway). --- src/qemu/qemu_monitor_json.c | 62 ++++++++++++++++++++++++++++++++++++++++++++ src/qemu/qemu_monitor_json.h | 6 +++++ tests/qemumonitorjsontest.c | 59 +++++++++++++++++++++++++++++++++++++++++ 3 files changed, 127 insertions(+)
ACK
Again, shouldn't this function be marked static, and the .h file left alone?
I can go either way on this - without the .h changes, we don't have the test though. So whichever way is preferred - I'll go with it...
Ah, so the test case is the reason you are exporting the file. That's reason enough to leave the patch body as-is, but do amend the commit message to mention this. It might also be worth a comment in the .h that the function is public only for the testsuite, so we aren't tempted to use it from qemu_driver.c later.
This isn't specific to this api - nothing in qemu_monitor_json.h should be used directly by qemu_driver.c It is exclusively for use by the qemu_monitor.c file & the test suite. Daniel -- |: http://berrange.com -o- http://www.flickr.com/photos/dberrange/ :| |: http://libvirt.org -o- http://virt-manager.org :| |: http://autobuild.org -o- http://search.cpan.org/~danberr/ :| |: http://entangle-photo.org -o- http://live.gnome.org/gtk-vnc :|

Add a period in seconds to allow/enable statistics gathering from the Balloon driver for 'virsh dommemstat <domain>'. --- docs/formatdomain.html.in | 10 ++++++++++ docs/schemas/domaincommon.rng | 7 +++++++ src/conf/domain_conf.c | 38 +++++++++++++++++++++++++++++++------- src/conf/domain_conf.h | 1 + 4 files changed, 49 insertions(+), 7 deletions(-) diff --git a/docs/formatdomain.html.in b/docs/formatdomain.html.in index 52a6353..93d2416 100644 --- a/docs/formatdomain.html.in +++ b/docs/formatdomain.html.in @@ -4637,6 +4637,7 @@ qemu-kvm -net nic,model=? /dev/null <devices> <memballoon model='virtio'> <address type='pci' domain='0x0000' bus='0x00' slot='0x02' function='0x0'/> + <stats period='10'/> </memballoon> </devices> </domain></pre> @@ -4654,6 +4655,15 @@ qemu-kvm -net nic,model=? /dev/null <li>'xen' — default with Xen</li> </ul> </dd> + <dt><code>period</code></dt> + <dd> + <p> + The optional <code>period</code> allows the QEMU virtio memory + balloon driver to provide statistics through the <code>virsh + dommemstat [domain]</code> command. + <span class='since'>Since 1.1.1, requires QEMU 1.5</span> + </p> + </dd> </dl> <h4><a name="elementsRng">Random number generator device</a></h4> diff --git a/docs/schemas/domaincommon.rng b/docs/schemas/domaincommon.rng index c135530..7a6852b 100644 --- a/docs/schemas/domaincommon.rng +++ b/docs/schemas/domaincommon.rng @@ -2946,6 +2946,13 @@ <optional> <ref name="address"/> </optional> + <optional> + <element name="stats"> + <attribute name="period"> + <ref name="positiveInteger"/> + </attribute> + </element> + </optional> </element> </define> <define name="parallel"> diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c index 33ae4a7..816b96c 100644 --- a/src/conf/domain_conf.c +++ b/src/conf/domain_conf.c @@ -8530,32 +8530,43 @@ error: static virDomainMemballoonDefPtr virDomainMemballoonDefParseXML(const xmlNodePtr node, + xmlXPathContextPtr ctxt, unsigned int flags) { char *model; virDomainMemballoonDefPtr def; + xmlNodePtr save = ctxt->node; if (VIR_ALLOC(def) < 0) return NULL; model = virXMLPropString(node, "model"); if (model == NULL) { - virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + virReportError(VIR_ERR_XML_ERROR, "%s", _("balloon memory must contain model name")); goto error; } + if ((def->model = virDomainMemballoonModelTypeFromString(model)) < 0) { - virReportError(VIR_ERR_INTERNAL_ERROR, + virReportError(VIR_ERR_XML_ERROR, _("unknown memory balloon model '%s'"), model); goto error; } + ctxt->node = node; + if (virXPathUInt("string(./stats/@period)", ctxt, &def->period) < -1) { + virReportError(VIR_ERR_XML_ERROR, "%s", + _("invalid statistics collection period")); + goto error; + } + if (virDomainDeviceInfoParseXML(node, NULL, &def->info, flags) < 0) goto error; cleanup: VIR_FREE(model); + ctxt->node = save; return def; error: @@ -9428,7 +9439,9 @@ virDomainDeviceDefParse(const char *xmlStr, goto error; break; case VIR_DOMAIN_DEVICE_MEMBALLOON: - if (!(dev->data.memballoon = virDomainMemballoonDefParseXML(node, flags))) + if (!(dev->data.memballoon = virDomainMemballoonDefParseXML(node, + ctxt, + flags))) goto error; break; case VIR_DOMAIN_DEVICE_NVRAM: @@ -11931,7 +11944,7 @@ virDomainDefParseXML(xmlDocPtr xml, } if (n > 0) { virDomainMemballoonDefPtr memballoon = - virDomainMemballoonDefParseXML(nodes[0], flags); + virDomainMemballoonDefParseXML(nodes[0], ctxt, flags); if (!memballoon) goto error; @@ -15127,6 +15140,7 @@ virDomainMemballoonDefFormat(virBufferPtr buf, unsigned int flags) { const char *model = virDomainMemballoonModelTypeToString(def->model); + bool noopts = true; if (!model) { virReportError(VIR_ERR_INTERNAL_ERROR, @@ -15140,11 +15154,21 @@ virDomainMemballoonDefFormat(virBufferPtr buf, virBufferAddLit(buf, ">\n"); if (virDomainDeviceInfoFormat(buf, &def->info, flags) < 0) return -1; - virBufferAddLit(buf, " </memballoon>\n"); - } else { - virBufferAddLit(buf, "/>\n"); + noopts = false; } + if (def->period) { + if (noopts) + virBufferAddLit(buf, ">\n"); + virBufferAsprintf(buf, " <stats period='%u'/>\n", def->period); + noopts = false; + } + + if (noopts) + virBufferAddLit(buf, "/>\n"); + else + virBufferAddLit(buf, " </memballoon>\n"); + return 0; } diff --git a/src/conf/domain_conf.h b/src/conf/domain_conf.h index 4a7dcd2..ed314d9 100644 --- a/src/conf/domain_conf.h +++ b/src/conf/domain_conf.h @@ -1533,6 +1533,7 @@ enum { struct _virDomainMemballoonDef { int model; virDomainDeviceInfo info; + unsigned int period; /* seconds between collections */ }; struct _virDomainNVRAMDef { -- 1.8.1.4

On Thu, Jul 11, 2013 at 07:55:54PM -0400, John Ferlan wrote:
Add a period in seconds to allow/enable statistics gathering from the Balloon driver for 'virsh dommemstat <domain>'. --- docs/formatdomain.html.in | 10 ++++++++++ docs/schemas/domaincommon.rng | 7 +++++++ src/conf/domain_conf.c | 38 +++++++++++++++++++++++++++++++------- src/conf/domain_conf.h | 1 + 4 files changed, 49 insertions(+), 7 deletions(-)
Opps, forgot to mention last time that you need to add a test case for this new XML - or just add the XML to an existing test data file Daniel -- |: http://berrange.com -o- http://www.flickr.com/photos/dberrange/ :| |: http://libvirt.org -o- http://virt-manager.org :| |: http://autobuild.org -o- http://search.cpan.org/~danberr/ :| |: http://entangle-photo.org -o- http://live.gnome.org/gtk-vnc :|

On 07/12/2013 08:35 AM, Daniel P. Berrange wrote:
ps, forgot to mention last time that you need to add a test case for this new XML - or just add the XML to
1. Copied qemuxml2argv-balloon-device.xml to qemuxml2argv-balloon-device-period.xml, adding <stats period='10'/> 2. Copied qemuxml2argv-balloon-device.arg to qemuxml2argv-balloon-device-period.arg - made no changes since the period is not part of the command 3. Added the "balloon-device-period" I will squash in the following: diff --git a/tests/qemuxml2argvdata/qemuxml2argv-balloon-device-period.args b/te new file mode 100644 index 0000000..48af1c4 --- /dev/null +++ b/tests/qemuxml2argvdata/qemuxml2argv-balloon-device-period.args @@ -0,0 +1,5 @@ +LC_ALL=C PATH=/bin HOME=/home/test USER=test LOGNAME=test /usr/bin/qemu -S -M \ +pc -m 214 -smp 1 -nographic -nodefconfig -nodefaults -monitor \ +unix:/tmp/test-monitor,server,nowait -no-acpi -boot c -usb -hda \ +/dev/HostVG/QEMUGuest1 -device virtio-balloon-pci,id=balloon0,bus=pci.0,\ +addr=0x12 diff --git a/tests/qemuxml2argvdata/qemuxml2argv-balloon-device-period.xml b/tes new file mode 100644 index 0000000..c47c9bf --- /dev/null +++ b/tests/qemuxml2argvdata/qemuxml2argv-balloon-device-period.xml @@ -0,0 +1,26 @@ +<domain type='qemu'> + <name>QEMUGuest1</name> + <uuid>c7a5fdbd-edaf-9455-926a-d65c16db1809</uuid> + <memory unit='KiB'>219136</memory> + <currentMemory unit='KiB'>219136</currentMemory> + <vcpu placement='static'>1</vcpu> + <os> + <type arch='i686' machine='pc'>hvm</type> + <boot dev='hd'/> + </os> + <clock offset='utc'/> + <on_poweroff>destroy</on_poweroff> + <on_reboot>restart</on_reboot> + <on_crash>destroy</on_crash> + <devices> + <emulator>/usr/bin/qemu</emulator> + <disk type='block' device='disk'> + <source dev='/dev/HostVG/QEMUGuest1'/> + <target dev='hda' bus='ide'/> + </disk> + <memballoon model='virtio'> + <address type='pci' domain='0' bus='0' slot='18' function='0'/> + <stats period='10'/> + </memballoon> + </devices> +</domain> diff --git a/tests/qemuxml2argvtest.c b/tests/qemuxml2argvtest.c index 7d7332f..0f96eef 100644 --- a/tests/qemuxml2argvtest.c +++ b/tests/qemuxml2argvtest.c @@ -837,6 +837,7 @@ mymain(void) DO_TEST("balloon-device", QEMU_CAPS_DEVICE, QEMU_CAPS_NODEFCONFIG); DO_TEST("balloon-device-auto", QEMU_CAPS_DEVICE, QEMU_CAPS_NODEFCONFIG); + DO_TEST("balloon-device-period", QEMU_CAPS_DEVICE, QEMU_CAPS_NODEFCONFIG); DO_TEST("sound", NONE); DO_TEST("sound-device", QEMU_CAPS_DEVICE, QEMU_CAPS_NODEFCONFIG, John

On Fri, Jul 12, 2013 at 10:16:20AM -0400, John Ferlan wrote:
On 07/12/2013 08:35 AM, Daniel P. Berrange wrote:
ps, forgot to mention last time that you need to add a test case for this new XML - or just add the XML to
1. Copied qemuxml2argv-balloon-device.xml to qemuxml2argv-balloon-device-period.xml, adding <stats period='10'/>
2. Copied qemuxml2argv-balloon-device.arg to qemuxml2argv-balloon-device-period.arg - made no changes since the period is not part of the command
3. Added the "balloon-device-period"
I will squash in the following:
ACK Daniel -- |: http://berrange.com -o- http://www.flickr.com/photos/dberrange/ :| |: http://libvirt.org -o- http://virt-manager.org :| |: http://autobuild.org -o- http://search.cpan.org/~danberr/ :| |: http://entangle-photo.org -o- http://live.gnome.org/gtk-vnc :|

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; + + /* 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; + } + + 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; + 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) + 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) { + 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) -- 1.8.1.4

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 -- |: http://berrange.com -o- http://www.flickr.com/photos/dberrange/ :| |: http://libvirt.org -o- http://virt-manager.org :| |: http://autobuild.org -o- http://search.cpan.org/~danberr/ :| |: http://entangle-photo.org -o- http://live.gnome.org/gtk-vnc :|

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; }
This is a recursive function - setting ballooninit in here means I have to know when I'm back at the first call. That's why it's set in the callers. Since ballooninit means I've either made the call and was successful or I've made the call and wasn't successful. I think an argument could be made that the checking of balloonpath probably is extraneous. Since the balloon driver stats are only supported in qemu 1.5 and beyond, do we really want an error message?
+ + /* 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.
hmm... Do we really want to virReportError() in either case? They're not necessarily specifically asking for the statistics here... Although with your suggestion to only call SetMemoryStatsPeriod if the period is defined, I do see the point. Although the first time someone does a 'virsh dommemstats domain' they'd see this message and perhaps wonder. Also if the user didn't have the balloon driver configured, then this would be spit out.
+ 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
It's possible with 'earlier' versions of qemu (eg, pre 1.5) that we won't find the property. Thus if we provide an error message here, then couldn't that be a "false positive" to the user?
+ 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);
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ hence why ballooninit is set outside the context of this function.
+ } + } + +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.
Ah - sure. That's fine.
+ 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.
Yep - I can do that. These were done this way because the only way to get the path prior to patch 6 is if we called the setting of the period. In patch 6 I added the call to get the path in the GetStats logic to check for the path as well; otherwise, the Reconnect'd guest wouldn't find its path and thus wouldn't show the stats...
+ 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

On Fri, Jul 12, 2013 at 09:15:40AM -0400, John Ferlan wrote:
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; }
This is a recursive function - setting ballooninit in here means I have to know when I'm back at the first call. That's why it's set in the callers. Since ballooninit means I've either made the call and was successful or I've made the call and wasn't successful.
I think an argument could be made that the checking of balloonpath probably is extraneous.
Since the balloon driver stats are only supported in qemu 1.5 and beyond, do we really want an error message?
+ + /* 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.
hmm... Do we really want to virReportError() in either case? They're not necessarily specifically asking for the statistics here... Although with your suggestion to only call SetMemoryStatsPeriod if the period is defined, I do see the point. Although the first time someone does a 'virsh dommemstats domain' they'd see this message and perhaps wonder. Also if the user didn't have the balloon driver configured, then this would be spit out.
The scenario is that an application invokes virDomainSetMemoryStatsPeriod(). This calls qemuMonitorFindBalloonObjectPath(). If that returns -1, then virDomainSetMemoryStatsPeriod will return -1. For any function that returns a -1 error condition it is mandatory to have called 'virReportError', otherwise the caller will just see "unknown error occurred". Daniel -- |: http://berrange.com -o- http://www.flickr.com/photos/dberrange/ :| |: http://libvirt.org -o- http://virt-manager.org :| |: http://autobuild.org -o- http://search.cpan.org/~danberr/ :| |: http://entangle-photo.org -o- http://live.gnome.org/gtk-vnc :|

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);

On Fri, Jul 12, 2013 at 10:40:01AM -0400, John Ferlan wrote:
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(-)
I've squashed the following in:
ACK Daniel -- |: http://berrange.com -o- http://www.flickr.com/photos/dberrange/ :| |: http://libvirt.org -o- http://virt-manager.org :| |: http://autobuild.org -o- http://search.cpan.org/~danberr/ :| |: http://entangle-photo.org -o- http://live.gnome.org/gtk-vnc :|

This patch will add the qemuMonitorJSONGetMemoryStats() to execute a "guest-stats" on the balloonpath using "get-qom" replacing the former mechanism which looked through the "query-ballon" returned data for the fields. The "query-balloon" code only returns 'actual' memory. Rather than duplicating the existing code, have the JSON API use the GetBalloonInfo API. A check in the qemuMonitorGetMemoryStats() will be made to ensure the balloon driver path has been set. Since the underlying JSON code can return data not associated with the balloon driver, we don't fail on a failure to get the balloonpath. Of course since we've made the check, we can then set the ballooninit flag. Getting the path here is primarily due to the process reconnect path which doesn't attempt to set the collection period. --- src/qemu/qemu_monitor.c | 10 ++- src/qemu/qemu_monitor_json.c | 190 ++++++++++++++++++++----------------------- src/qemu/qemu_monitor_json.h | 1 + 3 files changed, 95 insertions(+), 106 deletions(-) diff --git a/src/qemu/qemu_monitor.c b/src/qemu/qemu_monitor.c index a3e250c..14b80e3 100644 --- a/src/qemu/qemu_monitor.c +++ b/src/qemu/qemu_monitor.c @@ -1483,10 +1483,14 @@ int qemuMonitorGetMemoryStats(qemuMonitorPtr mon, return -1; } - if (mon->json) - ret = qemuMonitorJSONGetMemoryStats(mon, stats, nr_stats); - else + if (mon->json) { + ignore_value(qemuMonitorFindBalloonObjectPath(mon, mon->vm, "/")); + mon->ballooninit = true; + ret = qemuMonitorJSONGetMemoryStats(mon, mon->balloonpath, + stats, nr_stats); + } else { ret = qemuMonitorTextGetMemoryStats(mon, stats, nr_stats); + } return ret; } diff --git a/src/qemu/qemu_monitor_json.c b/src/qemu/qemu_monitor_json.c index a9e8723..45edbd3 100644 --- a/src/qemu/qemu_monitor_json.c +++ b/src/qemu/qemu_monitor_json.c @@ -1361,131 +1361,115 @@ cleanup: } +/* Process the balloon driver statistics. The request and data returned + * will be as follows (although the 'child[#]' entry will differ based on + * where it's run). + * + * { "execute": "qom-get","arguments": \ + * { "path": "/machine/i440fx/pci.0/child[7]","property": "guest-stats"} } + * + * {"return": {"stats": \ + * {"stat-swap-out": 0, + * "stat-free-memory": 686350336, + * "stat-minor-faults": 697283, + * "stat-major-faults": 951, + * "stat-total-memory": 1019924480, + * "stat-swap-in": 0}, + * "last-update": 1371221540}} + * + * A value in "stats" can be -1 indicating it's never been collected/stored. + * The 'last-update' value could be used in the future in order to determine + * rates and/or whether data has been collected since a previous cycle. + * It's currently unused. + */ +#define GET_BALLOON_STATS(FIELD, TAG, DIVISOR) \ + if (virJSONValueObjectHasKey(statsdata, FIELD) && \ + (got < nr_stats)) { \ + if (virJSONValueObjectGetNumberUlong(statsdata, FIELD, &mem) < 0) { \ + VIR_DEBUG("Failed to get '%s' value", FIELD); \ + } else { \ + /* Not being collected? No point in providing bad data */ \ + if (mem != -1UL) { \ + stats[got].tag = TAG; \ + stats[got].val = mem / DIVISOR; \ + got++; \ + } \ + } \ + } + + int qemuMonitorJSONGetMemoryStats(qemuMonitorPtr mon, + char *balloonpath, virDomainMemoryStatPtr stats, unsigned int nr_stats) { int ret; - int got = 0; - virJSONValuePtr cmd = qemuMonitorJSONMakeCommand("query-balloon", - NULL); + virJSONValuePtr cmd = NULL; virJSONValuePtr reply = NULL; + virJSONValuePtr data; + virJSONValuePtr statsdata; + unsigned long long mem; + int got = 0; - if (!cmd) - return -1; + ret = qemuMonitorJSONGetBalloonInfo(mon, &mem); + if (ret == 1 && (got < nr_stats)) { + stats[got].tag = VIR_DOMAIN_MEMORY_STAT_ACTUAL_BALLOON; + stats[got].val = mem; + got++; + } - ret = qemuMonitorJSONCommand(mon, cmd, &reply); + if (!balloonpath) + goto cleanup; - if (ret == 0) { - /* See if balloon soft-failed */ - if (qemuMonitorJSONHasError(reply, "DeviceNotActive") || - qemuMonitorJSONHasError(reply, "KVMMissingCap")) - goto cleanup; + if (!(cmd = qemuMonitorJSONMakeCommand("qom-get", + "s:path", balloonpath, + "s:property", "guest-stats", + NULL))) + goto cleanup; - /* See if any other fatal error occurred */ - ret = qemuMonitorJSONCheckError(cmd, reply); + ret = qemuMonitorJSONCommand(mon, cmd, &reply); - /* Success */ - if (ret == 0) { - virJSONValuePtr data; - unsigned long long mem; + if (ret == 0) + ret = qemuMonitorJSONCheckError(cmd, reply); - if (!(data = virJSONValueObjectGet(reply, "return"))) { - virReportError(VIR_ERR_INTERNAL_ERROR, "%s", - _("info balloon reply was missing return data")); - ret = -1; - goto cleanup; - } + if (ret < 0) + goto cleanup; - if (virJSONValueObjectHasKey(data, "actual") && (got < nr_stats)) { - if (virJSONValueObjectGetNumberUlong(data, "actual", &mem) < 0) { - virReportError(VIR_ERR_INTERNAL_ERROR, "%s", - _("info balloon reply was missing balloon actual")); - ret = -1; - goto cleanup; - } - stats[got].tag = VIR_DOMAIN_MEMORY_STAT_ACTUAL_BALLOON; - stats[got].val = (mem/1024); - got++; - } + if (!(data = virJSONValueObjectGet(reply, "return"))) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("qom-get reply was missing return data")); + goto cleanup; + } - if (virJSONValueObjectHasKey(data, "mem_swapped_in") && (got < nr_stats)) { - if (virJSONValueObjectGetNumberUlong(data, "mem_swapped_in", &mem) < 0) { - virReportError(VIR_ERR_INTERNAL_ERROR, "%s", - _("info balloon reply was missing balloon mem_swapped_in")); - ret = -1; - goto cleanup; - } - stats[got].tag = VIR_DOMAIN_MEMORY_STAT_SWAP_IN; - stats[got].val = (mem/1024); - got++; - } - if (virJSONValueObjectHasKey(data, "mem_swapped_out") && (got < nr_stats)) { - if (virJSONValueObjectGetNumberUlong(data, "mem_swapped_out", &mem) < 0) { - virReportError(VIR_ERR_INTERNAL_ERROR, "%s", - _("info balloon reply was missing balloon mem_swapped_out")); - ret = -1; - goto cleanup; - } - stats[got].tag = VIR_DOMAIN_MEMORY_STAT_SWAP_OUT; - stats[got].val = (mem/1024); - got++; - } - if (virJSONValueObjectHasKey(data, "major_page_faults") && (got < nr_stats)) { - if (virJSONValueObjectGetNumberUlong(data, "major_page_faults", &mem) < 0) { - virReportError(VIR_ERR_INTERNAL_ERROR, "%s", - _("info balloon reply was missing balloon major_page_faults")); - ret = -1; - goto cleanup; - } - stats[got].tag = VIR_DOMAIN_MEMORY_STAT_MAJOR_FAULT; - stats[got].val = mem; - got++; - } - if (virJSONValueObjectHasKey(data, "minor_page_faults") && (got < nr_stats)) { - if (virJSONValueObjectGetNumberUlong(data, "minor_page_faults", &mem) < 0) { - virReportError(VIR_ERR_INTERNAL_ERROR, "%s", - _("info balloon reply was missing balloon minor_page_faults")); - ret = -1; - goto cleanup; - } - stats[got].tag = VIR_DOMAIN_MEMORY_STAT_MINOR_FAULT; - stats[got].val = mem; - got++; - } - if (virJSONValueObjectHasKey(data, "free_mem") && (got < nr_stats)) { - if (virJSONValueObjectGetNumberUlong(data, "free_mem", &mem) < 0) { - virReportError(VIR_ERR_INTERNAL_ERROR, "%s", - _("info balloon reply was missing balloon free_mem")); - ret = -1; - goto cleanup; - } - stats[got].tag = VIR_DOMAIN_MEMORY_STAT_UNUSED; - stats[got].val = (mem/1024); - got++; - } - if (virJSONValueObjectHasKey(data, "total_mem") && (got < nr_stats)) { - if (virJSONValueObjectGetNumberUlong(data, "total_mem", &mem) < 0) { - virReportError(VIR_ERR_INTERNAL_ERROR, "%s", - _("info balloon reply was missing balloon total_mem")); - ret = -1; - goto cleanup; - } - stats[got].tag = VIR_DOMAIN_MEMORY_STAT_AVAILABLE; - stats[got].val = (mem/1024); - got++; - } - } + if (!(statsdata = virJSONValueObjectGet(data, "stats"))) { + VIR_DEBUG("data does not include 'stats'"); + goto cleanup; } - if (got > 0) - ret = got; + GET_BALLOON_STATS("stat-swap-in", + VIR_DOMAIN_MEMORY_STAT_SWAP_IN, 1024); + GET_BALLOON_STATS("stat-swap-out", + VIR_DOMAIN_MEMORY_STAT_SWAP_OUT, 1024); + GET_BALLOON_STATS("stat-major-faults", + VIR_DOMAIN_MEMORY_STAT_MAJOR_FAULT, 1); + GET_BALLOON_STATS("stat-minor-faults", + VIR_DOMAIN_MEMORY_STAT_MINOR_FAULT, 1); + GET_BALLOON_STATS("stat-free-memory", + VIR_DOMAIN_MEMORY_STAT_UNUSED, 1024); + GET_BALLOON_STATS("stat-total-memory", + VIR_DOMAIN_MEMORY_STAT_AVAILABLE, 1024); + cleanup: virJSONValueFree(cmd); virJSONValueFree(reply); + + if (got > 0) + ret = got; + return ret; } +#undef GET_BALLOON_STATS /* diff --git a/src/qemu/qemu_monitor_json.h b/src/qemu/qemu_monitor_json.h index e2324f1..c97cd66 100644 --- a/src/qemu/qemu_monitor_json.h +++ b/src/qemu/qemu_monitor_json.h @@ -59,6 +59,7 @@ int qemuMonitorJSONGetVirtType(qemuMonitorPtr mon, int qemuMonitorJSONGetBalloonInfo(qemuMonitorPtr mon, unsigned long long *currmem); int qemuMonitorJSONGetMemoryStats(qemuMonitorPtr mon, + char *balloonpath, virDomainMemoryStatPtr stats, unsigned int nr_stats); int qemuMonitorJSONSetMemoryStatsPeriod(qemuMonitorPtr mon, -- 1.8.1.4

On Thu, Jul 11, 2013 at 07:55:56PM -0400, John Ferlan wrote:
This patch will add the qemuMonitorJSONGetMemoryStats() to execute a "guest-stats" on the balloonpath using "get-qom" replacing the former mechanism which looked through the "query-ballon" returned data for the fields. The "query-balloon" code only returns 'actual' memory. Rather than duplicating the existing code, have the JSON API use the GetBalloonInfo API.
A check in the qemuMonitorGetMemoryStats() will be made to ensure the balloon driver path has been set. Since the underlying JSON code can return data not associated with the balloon driver, we don't fail on a failure to get the balloonpath. Of course since we've made the check, we can then set the ballooninit flag. Getting the path here is primarily due to the process reconnect path which doesn't attempt to set the collection period. --- src/qemu/qemu_monitor.c | 10 ++- src/qemu/qemu_monitor_json.c | 190 ++++++++++++++++++++----------------------- src/qemu/qemu_monitor_json.h | 1 + 3 files changed, 95 insertions(+), 106 deletions(-)
Can you also extend qemumonitorjsontest.c to cover the new code in qemuMonitorJSONGetMemoryStats.
diff --git a/src/qemu/qemu_monitor.c b/src/qemu/qemu_monitor.c index a3e250c..14b80e3 100644 --- a/src/qemu/qemu_monitor.c +++ b/src/qemu/qemu_monitor.c @@ -1483,10 +1483,14 @@ int qemuMonitorGetMemoryStats(qemuMonitorPtr mon, return -1; }
- if (mon->json) - ret = qemuMonitorJSONGetMemoryStats(mon, stats, nr_stats); - else + if (mon->json) { + ignore_value(qemuMonitorFindBalloonObjectPath(mon, mon->vm, "/")); + mon->ballooninit = true;
Hmm, I think that qemuMonitorFindBalloonObjectPath ought to be setting 'mon->ballooninit = true' itself, rather than expecting all the callers to do it. Actually I should have mentioned this against the previous patch.
+ ret = qemuMonitorJSONGetMemoryStats(mon, mon->balloonpath, + stats, nr_stats); + } else { ret = qemuMonitorTextGetMemoryStats(mon, stats, nr_stats); + } return ret; }
Daniel -- |: http://berrange.com -o- http://www.flickr.com/photos/dberrange/ :| |: http://libvirt.org -o- http://virt-manager.org :| |: http://autobuild.org -o- http://search.cpan.org/~danberr/ :| |: http://entangle-photo.org -o- http://live.gnome.org/gtk-vnc :|

On 07/12/2013 08:42 AM, Daniel P. Berrange wrote:
On Thu, Jul 11, 2013 at 07:55:56PM -0400, John Ferlan wrote:
This patch will add the qemuMonitorJSONGetMemoryStats() to execute a "guest-stats" on the balloonpath using "get-qom" replacing the former mechanism which looked through the "query-ballon" returned data for the fields. The "query-balloon" code only returns 'actual' memory. Rather than duplicating the existing code, have the JSON API use the GetBalloonInfo API.
A check in the qemuMonitorGetMemoryStats() will be made to ensure the balloon driver path has been set. Since the underlying JSON code can return data not associated with the balloon driver, we don't fail on a failure to get the balloonpath. Of course since we've made the check, we can then set the ballooninit flag. Getting the path here is primarily due to the process reconnect path which doesn't attempt to set the collection period. --- src/qemu/qemu_monitor.c | 10 ++- src/qemu/qemu_monitor_json.c | 190 ++++++++++++++++++++----------------------- src/qemu/qemu_monitor_json.h | 1 + 3 files changed, 95 insertions(+), 106 deletions(-)
Can you also extend qemumonitorjsontest.c to cover the new code in qemuMonitorJSONGetMemoryStats.
diff --git a/src/qemu/qemu_monitor.c b/src/qemu/qemu_monitor.c index a3e250c..14b80e3 100644 --- a/src/qemu/qemu_monitor.c +++ b/src/qemu/qemu_monitor.c @@ -1483,10 +1483,14 @@ int qemuMonitorGetMemoryStats(qemuMonitorPtr mon, return -1; }
- if (mon->json) - ret = qemuMonitorJSONGetMemoryStats(mon, stats, nr_stats); - else + if (mon->json) { + ignore_value(qemuMonitorFindBalloonObjectPath(mon, mon->vm, "/")); + mon->ballooninit = true;
Hmm, I think that qemuMonitorFindBalloonObjectPath ought to be setting 'mon->ballooninit = true' itself, rather than expecting all the callers to do it.
Actually I should have mentioned this against the previous patch.
Was the previous explanation "good enough"? Since it's recursive I see no where in the function that one could safely set the value. John
+ ret = qemuMonitorJSONGetMemoryStats(mon, mon->balloonpath, + stats, nr_stats); + } else { ret = qemuMonitorTextGetMemoryStats(mon, stats, nr_stats); + } return ret; }
Daniel

Add new API in order to set the balloon memory driver statistics collection period in order to allow dynamic period adjustment for the virsh dommemstats to display balloon stats data --- include/libvirt/libvirt.h.in | 3 +++ src/driver.h | 6 +++++ src/libvirt.c | 64 ++++++++++++++++++++++++++++++++++++++++++++ src/libvirt_public.syms | 5 ++++ 4 files changed, 78 insertions(+) diff --git a/include/libvirt/libvirt.h.in b/include/libvirt/libvirt.h.in index b87255a..32c36f1 100644 --- a/include/libvirt/libvirt.h.in +++ b/include/libvirt/libvirt.h.in @@ -1909,6 +1909,9 @@ int virDomainSetMemory (virDomainPtr domain, int virDomainSetMemoryFlags (virDomainPtr domain, unsigned long memory, unsigned int flags); +int virDomainSetMemoryStatsPeriod (virDomainPtr domain, + int period, + unsigned int flags); int virDomainGetMaxVcpus (virDomainPtr domain); int virDomainGetSecurityLabel (virDomainPtr domain, virSecurityLabelPtr seclabel); diff --git a/src/driver.h b/src/driver.h index 31851cb..da03021 100644 --- a/src/driver.h +++ b/src/driver.h @@ -207,6 +207,11 @@ typedef int unsigned int flags); typedef int +(*virDrvDomainSetMemoryStatsPeriod)(virDomainPtr domain, + int period, + unsigned int flags); + +typedef int (*virDrvDomainSetMemoryParameters)(virDomainPtr domain, virTypedParameterPtr params, int nparams, @@ -1158,6 +1163,7 @@ struct _virDriver { virDrvDomainSetMaxMemory domainSetMaxMemory; virDrvDomainSetMemory domainSetMemory; virDrvDomainSetMemoryFlags domainSetMemoryFlags; + virDrvDomainSetMemoryStatsPeriod domainSetMemoryStatsPeriod; virDrvDomainSetMemoryParameters domainSetMemoryParameters; virDrvDomainGetMemoryParameters domainGetMemoryParameters; virDrvDomainSetNumaParameters domainSetNumaParameters; diff --git a/src/libvirt.c b/src/libvirt.c index 4dc91d7..0cdac0d 100644 --- a/src/libvirt.c +++ b/src/libvirt.c @@ -3781,6 +3781,70 @@ error: return -1; } +/** + * virDomainSetMemoryStatsPeriod: + * @domain: a domain object or NULL + * @period: the period in seconds for stats collection + * @flags: bitwise-OR of virDomainMemoryModFlags + * + * Dynamically change the domain memory balloon driver statistics collection + * period. Use 0 to disable and a positive value to enable. + * + * @flags may include VIR_DOMAIN_AFFECT_LIVE or VIR_DOMAIN_AFFECT_CONFIG. + * Both flags may be set. If VIR_DOMAIN_AFFECT_LIVE is set, the change affects + * a running domain and will fail if domain is not active. + * If VIR_DOMAIN_AFFECT_CONFIG is set, the change affects persistent state, + * and will fail for transient domains. If neither flag is specified + * (that is, @flags is VIR_DOMAIN_AFFECT_CURRENT), then an inactive domain + * modifies persistent setup, while an active domain is hypervisor-dependent + * on whether just live or both live and persistent state is changed. + * + * Not all hypervisors can support all flag combinations. + * + * Returns 0 in case of success, -1 in case of failure. + */ + +int +virDomainSetMemoryStatsPeriod(virDomainPtr domain, int period, + unsigned int flags) +{ + virConnectPtr conn; + + VIR_DOMAIN_DEBUG(domain, "peroid=%d, flags=%x", period, flags); + + virResetLastError(); + + if (!VIR_IS_CONNECTED_DOMAIN(domain)) { + virLibDomainError(VIR_ERR_INVALID_DOMAIN, __FUNCTION__); + virDispatchError(NULL); + return -1; + } + + if (domain->conn->flags & VIR_CONNECT_RO) { + virLibDomainError(VIR_ERR_OPERATION_DENIED, __FUNCTION__); + goto error; + } + + /* This must be positive to set the balloon collection period */ + virCheckNonNegativeArgGoto(period, error); + + conn = domain->conn; + + if (conn->driver->domainSetMemoryStatsPeriod) { + int ret; + ret = conn->driver->domainSetMemoryStatsPeriod(domain, period, flags); + if (ret < 0) + goto error; + return ret; + } + + virLibConnError(VIR_ERR_NO_SUPPORT, __FUNCTION__); + +error: + virDispatchError(domain->conn); + return -1; +} + /* Helper function called to validate incoming client array on any * interface that sets typed parameters in the hypervisor. */ static int diff --git a/src/libvirt_public.syms b/src/libvirt_public.syms index 7c6edf6..4be5104 100644 --- a/src/libvirt_public.syms +++ b/src/libvirt_public.syms @@ -627,4 +627,9 @@ LIBVIRT_1.1.0 { virDomainMigrateToURI3; } LIBVIRT_1.0.6; +LIBVIRT_1.1.1 { + global: + virDomainSetMemoryStatsPeriod; +} LIBVIRT_1.1.0; + # .... define new API here using predicted next version number .... -- 1.8.1.4

On Thu, Jul 11, 2013 at 07:55:57PM -0400, John Ferlan wrote:
Add new API in order to set the balloon memory driver statistics collection period in order to allow dynamic period adjustment for the virsh dommemstats to display balloon stats data --- include/libvirt/libvirt.h.in | 3 +++ src/driver.h | 6 +++++ src/libvirt.c | 64 ++++++++++++++++++++++++++++++++++++++++++++ src/libvirt_public.syms | 5 ++++ 4 files changed, 78 insertions(+)
ACK Daniel -- |: http://berrange.com -o- http://www.flickr.com/photos/dberrange/ :| |: http://libvirt.org -o- http://virt-manager.org :| |: http://autobuild.org -o- http://search.cpan.org/~danberr/ :| |: http://entangle-photo.org -o- http://live.gnome.org/gtk-vnc :|

Wire up the remote protocol --- src/remote/remote_driver.c | 1 + src/remote/remote_protocol.x | 15 ++++++++++++++- src/remote_protocol-structs | 6 ++++++ 3 files changed, 21 insertions(+), 1 deletion(-) diff --git a/src/remote/remote_driver.c b/src/remote/remote_driver.c index 94d3b83..d9505cf 100644 --- a/src/remote/remote_driver.c +++ b/src/remote/remote_driver.c @@ -6561,6 +6561,7 @@ static virDriver remote_driver = { .domainSetMaxMemory = remoteDomainSetMaxMemory, /* 0.3.0 */ .domainSetMemory = remoteDomainSetMemory, /* 0.3.0 */ .domainSetMemoryFlags = remoteDomainSetMemoryFlags, /* 0.9.0 */ + .domainSetMemoryStatsPeriod = remoteDomainSetMemoryStatsPeriod, /* 1.1.1 */ .domainSetMemoryParameters = remoteDomainSetMemoryParameters, /* 0.8.5 */ .domainGetMemoryParameters = remoteDomainGetMemoryParameters, /* 0.8.5 */ .domainSetBlkioParameters = remoteDomainSetBlkioParameters, /* 0.9.0 */ diff --git a/src/remote/remote_protocol.x b/src/remote/remote_protocol.x index 2e9dc1d..d1c77f5 100644 --- a/src/remote/remote_protocol.x +++ b/src/remote/remote_protocol.x @@ -833,6 +833,12 @@ struct remote_domain_set_memory_flags_args { unsigned int flags; }; +struct remote_domain_set_memory_stats_period_args { + remote_nonnull_domain dom; + int period; + unsigned int flags; +}; + struct remote_domain_get_info_args { remote_nonnull_domain dom; }; @@ -4944,6 +4950,13 @@ enum remote_procedure { * @generate: none * @acl: domain:migrate */ - REMOTE_PROC_DOMAIN_MIGRATE_CONFIRM3_PARAMS = 307 + REMOTE_PROC_DOMAIN_MIGRATE_CONFIRM3_PARAMS = 307, + /** + * @generate: both + * @acl: domain:write + * @acl: domain:save:!VIR_DOMAIN_AFFECT_CONFIG|VIR_DOMAIN_AFFECT_LIVE + * @acl: domain:save:VIR_DOMAIN_AFFECT_CONFIG + */ + REMOTE_PROC_DOMAIN_SET_MEMORY_STATS_PERIOD = 308 }; diff --git a/src/remote_protocol-structs b/src/remote_protocol-structs index e38d24a..86e7650 100644 --- a/src/remote_protocol-structs +++ b/src/remote_protocol-structs @@ -500,6 +500,11 @@ struct remote_domain_set_memory_flags_args { uint64_t memory; u_int flags; }; +struct remote_domain_set_memory_stats_period_args { + remote_nonnull_domain dom; + int period; + u_int flags; +}; struct remote_domain_get_info_args { remote_nonnull_domain dom; }; @@ -2601,4 +2606,5 @@ enum remote_procedure { REMOTE_PROC_DOMAIN_MIGRATE_PERFORM3_PARAMS = 305, REMOTE_PROC_DOMAIN_MIGRATE_FINISH3_PARAMS = 306, REMOTE_PROC_DOMAIN_MIGRATE_CONFIRM3_PARAMS = 307, + REMOTE_PROC_DOMAIN_SET_MEMORY_STATS_PERIOD = 308, }; -- 1.8.1.4

On Thu, Jul 11, 2013 at 07:55:58PM -0400, John Ferlan wrote:
Wire up the remote protocol --- src/remote/remote_driver.c | 1 + src/remote/remote_protocol.x | 15 ++++++++++++++- src/remote_protocol-structs | 6 ++++++ 3 files changed, 21 insertions(+), 1 deletion(-)
ACK Daniel -- |: http://berrange.com -o- http://www.flickr.com/photos/dberrange/ :| |: http://libvirt.org -o- http://virt-manager.org :| |: http://autobuild.org -o- http://search.cpan.org/~danberr/ :| |: http://entangle-photo.org -o- http://live.gnome.org/gtk-vnc :|

Implement the new API that will handle setting the balloon driver statistics collection period in order to enable or disable the collection dynamically. --- src/qemu/qemu_driver.c | 65 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 65 insertions(+) diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c index 495867a..a71908c 100644 --- a/src/qemu/qemu_driver.c +++ b/src/qemu/qemu_driver.c @@ -2270,6 +2270,70 @@ static int qemuDomainSetMaxMemory(virDomainPtr dom, unsigned long memory) return qemuDomainSetMemoryFlags(dom, memory, VIR_DOMAIN_MEM_MAXIMUM); } +static int qemuDomainSetMemoryStatsPeriod(virDomainPtr dom, int period, + unsigned int flags) +{ + virQEMUDriverPtr driver = dom->conn->privateData; + qemuDomainObjPrivatePtr priv; + virDomainObjPtr vm; + virDomainDefPtr persistentDef = NULL; + int ret = -1, r; + virQEMUDriverConfigPtr cfg = NULL; + virCapsPtr caps = NULL; + + virCheckFlags(VIR_DOMAIN_AFFECT_LIVE | + VIR_DOMAIN_AFFECT_CONFIG, -1); + + if (!(vm = qemuDomObjFromDomain(dom))) + goto cleanup; + + cfg = virQEMUDriverGetConfig(driver); + + if (virDomainSetMemoryStatsPeriodEnsureACL(dom->conn, vm->def, flags) < 0) + goto cleanup; + + if (qemuDomainObjBeginJob(driver, vm, QEMU_JOB_MODIFY) < 0) + goto cleanup; + + if (!(caps = virQEMUDriverGetCapabilities(driver, false))) + goto endjob; + if (virDomainLiveConfigHelperMethod(caps, driver->xmlopt, vm, &flags, + &persistentDef) < 0) + goto endjob; + + /* Set the balloon driver collection interval */ + priv = vm->privateData; + + if (flags & VIR_DOMAIN_AFFECT_LIVE) { + + qemuDomainObjEnterMonitor(driver, vm); + r = qemuMonitorSetMemoryStatsPeriod(priv->mon, period); + qemuDomainObjExitMonitor(driver, vm); + if (r < 0) + virReportError(VIR_ERR_OPERATION_INVALID, "%s", + _("unable to set balloon driver collection period")); + } + + if (flags & VIR_DOMAIN_AFFECT_CONFIG) { + sa_assert(persistentDef); + persistentDef->memballoon->period = period; + ret = virDomainSaveConfig(cfg->configDir, persistentDef); + goto endjob; + } + + ret = 0; +endjob: + if (qemuDomainObjEndJob(driver, vm) == 0) + vm = NULL; + +cleanup: + if (vm) + virObjectUnlock(vm); + virObjectUnref(caps); + virObjectUnref(cfg); + return ret; +} + static int qemuDomainInjectNMI(virDomainPtr domain, unsigned int flags) { virQEMUDriverPtr driver = domain->conn->privateData; @@ -16032,6 +16096,7 @@ static virDriver qemuDriver = { .domainSetMemoryFlags = qemuDomainSetMemoryFlags, /* 0.9.0 */ .domainSetMemoryParameters = qemuDomainSetMemoryParameters, /* 0.8.5 */ .domainGetMemoryParameters = qemuDomainGetMemoryParameters, /* 0.8.5 */ + .domainSetMemoryStatsPeriod = qemuDomainSetMemoryStatsPeriod, /* 1.1.1 */ .domainSetBlkioParameters = qemuDomainSetBlkioParameters, /* 0.9.0 */ .domainGetBlkioParameters = qemuDomainGetBlkioParameters, /* 0.9.0 */ .domainGetInfo = qemuDomainGetInfo, /* 0.2.0 */ -- 1.8.1.4

On Thu, Jul 11, 2013 at 07:55:59PM -0400, John Ferlan wrote:
Implement the new API that will handle setting the balloon driver statistics collection period in order to enable or disable the collection dynamically. --- src/qemu/qemu_driver.c | 65 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 65 insertions(+)
ACK Daniel -- |: http://berrange.com -o- http://www.flickr.com/photos/dberrange/ :| |: http://libvirt.org -o- http://virt-manager.org :| |: http://autobuild.org -o- http://search.cpan.org/~danberr/ :| |: http://entangle-photo.org -o- http://live.gnome.org/gtk-vnc :|

Use the virDomainSetMemoryStatsPeriodFlags() to pass a period defined by usage of a new --period option in order to set the collection period for the balloon driver. This may enable or disable the collection based on the value. Add the --current, --live, & --config options to dommemstat. --- docs/formatdomain.html.in | 11 +++++++- tools/virsh-domain-monitor.c | 66 ++++++++++++++++++++++++++++++++++++++++++-- tools/virsh.pod | 22 ++++++++++++++- 3 files changed, 94 insertions(+), 5 deletions(-) diff --git a/docs/formatdomain.html.in b/docs/formatdomain.html.in index 93d2416..df84ed2 100644 --- a/docs/formatdomain.html.in +++ b/docs/formatdomain.html.in @@ -4660,7 +4660,16 @@ qemu-kvm -net nic,model=? /dev/null <p> The optional <code>period</code> allows the QEMU virtio memory balloon driver to provide statistics through the <code>virsh - dommemstat [domain]</code> command. + dommemstat [domain]</code> command. By default, collection is + not enabled. In order to enable, use the <code>virsh dommemstat + [domain] --period [number]</code> command or <code>virsh edit</code> + command to add the option to the XML definition. + The <code>virsh dommemstat</code> will accept the options + <code>--live</code>, <code>--current</code>, or <code>--config</code>. + If an option is not provided, the change for a running domain will + only be made to the active guest. + If the QEMU driver is not at the right + revision, the attempt to set the period will fail. <span class='since'>Since 1.1.1, requires QEMU 1.5</span> </p> </dd> diff --git a/tools/virsh-domain-monitor.c b/tools/virsh-domain-monitor.c index 5fbd32c..4cbf105 100644 --- a/tools/virsh-domain-monitor.c +++ b/tools/virsh-domain-monitor.c @@ -314,6 +314,23 @@ static const vshCmdOptDef opts_dommemstat[] = { .flags = VSH_OFLAG_REQ, .help = N_("domain name, id or uuid") }, + {.name = "period", + .type = VSH_OT_DATA, + .flags = VSH_OFLAG_EMPTY_OK, + .help = N_("period in seconds to set collection") + }, + {.name = "config", + .type = VSH_OT_BOOL, + .help = N_("affect next boot") + }, + {.name = "live", + .type = VSH_OT_BOOL, + .help = N_("affect running domain") + }, + {.name = "current", + .type = VSH_OT_BOOL, + .help = N_("affect current domain") + }, {.name = NULL} }; @@ -325,15 +342,56 @@ cmdDomMemStat(vshControl *ctl, const vshCmd *cmd) struct _virDomainMemoryStat stats[VIR_DOMAIN_MEMORY_STAT_NR]; unsigned int nr_stats; size_t i; + int ret = false; + int rv = 0; + int period = -1; + bool config = vshCommandOptBool(cmd, "config"); + bool live = vshCommandOptBool(cmd, "live"); + bool current = vshCommandOptBool(cmd, "current"); + unsigned int flags = VIR_DOMAIN_AFFECT_CURRENT; + + VSH_EXCLUSIVE_OPTIONS_VAR(current, live); + VSH_EXCLUSIVE_OPTIONS_VAR(current, config); + if (config) + flags |= VIR_DOMAIN_AFFECT_CONFIG; + if (live) + flags |= VIR_DOMAIN_AFFECT_LIVE; if (!(dom = vshCommandOptDomain(ctl, cmd, &name))) return false; + /* If none of the options were specified and we're active + * then be sure to allow active modification */ + if (!current && !live && !config && virDomainIsActive(dom) == 1) + flags |= VIR_DOMAIN_AFFECT_LIVE; + + /* Providing a period will adjust the balloon driver collection period. + * This is not really an unsigned long, but it + */ + if ((rv = vshCommandOptInt(cmd, "period", &period)) < 0) { + vshError(ctl, "%s", + _("Unable to parse integer parameter.")); + goto cleanup; + } + if (rv > 0) { + if (period < 0) { + vshError(ctl, _("Invalid collection period value '%d'"), period); + goto cleanup; + } + + if (virDomainSetMemoryStatsPeriod(dom, period, flags) < 0) { + vshError(ctl, "%s", + _("Unable to change balloon collection period.")); + } else { + ret = true; + } + goto cleanup; + } + nr_stats = virDomainMemoryStats(dom, stats, VIR_DOMAIN_MEMORY_STAT_NR, 0); if (nr_stats == -1) { vshError(ctl, _("Failed to get memory statistics for domain %s"), name); - virDomainFree(dom); - return false; + goto cleanup; } for (i = 0; i < nr_stats; i++) { @@ -355,8 +413,10 @@ cmdDomMemStat(vshControl *ctl, const vshCmd *cmd) vshPrint(ctl, "rss %llu\n", stats[i].val); } + ret = true; +cleanup: virDomainFree(dom); - return true; + return ret; } /* diff --git a/tools/virsh.pod b/tools/virsh.pod index 94fe897..729a6e3 100644 --- a/tools/virsh.pod +++ b/tools/virsh.pod @@ -668,10 +668,30 @@ Both I<--live> and I<--current> flags may be given, but I<--current> is exclusive. If no flag is specified, behavior is different depending on hypervisor. -=item B<dommemstat> I<domain> +=item B<dommemstat> I<domain> [I<period> B<seconds>] +[[I<--config>] [I<--live>] | [I<--current>]] Get memory stats for a running domain. +Depending on the hypervisor a variety of statistics can be returned + +For QEMU/KVM with a memory balloon, setting the optional I<period> to a +value larger than 0 in seconds will allow the balloon driver to return +additional statistics which will be displayed by subsequent B<dommemstat> +commands. Setting the I<period> to 0 will stop the balloon driver collection, +but does not clear the statistics in the balloon driver. Requires at least +QEMU/KVM 1.5 to be running on the host. + +The I<--live>, I<--config>, and I<--current> flags are only valid when using +the I<period> option in order to set the collection period for the balloon +driver. If I<--live> is specified, only the running guest collection period +is affected. If I<--config> is specified, affect the next boot of a persistent +guest. If I<--current> is specified, affect the current guest state. + +Both I<--live> and I<--config> flags may be given, but I<--current> is +exclusive. If no flag is specified, behavior is different depending +on the guest state. + =item B<domblkerror> I<domain> Show errors on block devices. This command usually comes handy when -- 1.8.1.4

On Thu, Jul 11, 2013 at 07:56:00PM -0400, John Ferlan wrote:
Use the virDomainSetMemoryStatsPeriodFlags() to pass a period defined by usage of a new --period option in order to set the collection period for the balloon driver. This may enable or disable the collection based on the value.
Add the --current, --live, & --config options to dommemstat. --- docs/formatdomain.html.in | 11 +++++++- tools/virsh-domain-monitor.c | 66 ++++++++++++++++++++++++++++++++++++++++++-- tools/virsh.pod | 22 ++++++++++++++- 3 files changed, 94 insertions(+), 5 deletions(-)
diff --git a/docs/formatdomain.html.in b/docs/formatdomain.html.in index 93d2416..df84ed2 100644 --- a/docs/formatdomain.html.in +++ b/docs/formatdomain.html.in @@ -4660,7 +4660,16 @@ qemu-kvm -net nic,model=? /dev/null <p> The optional <code>period</code> allows the QEMU virtio memory balloon driver to provide statistics through the <code>virsh - dommemstat [domain]</code> command. + dommemstat [domain]</code> command. By default, collection is + not enabled. In order to enable, use the <code>virsh dommemstat + [domain] --period [number]</code> command or <code>virsh edit</code> + command to add the option to the XML definition. + The <code>virsh dommemstat</code> will accept the options + <code>--live</code>, <code>--current</code>, or <code>--config</code>. + If an option is not provided, the change for a running domain will + only be made to the active guest. + If the QEMU driver is not at the right + revision, the attempt to set the period will fail. <span class='since'>Since 1.1.1, requires QEMU 1.5</span> </p> </dd> diff --git a/tools/virsh-domain-monitor.c b/tools/virsh-domain-monitor.c index 5fbd32c..4cbf105 100644 --- a/tools/virsh-domain-monitor.c +++ b/tools/virsh-domain-monitor.c @@ -314,6 +314,23 @@ static const vshCmdOptDef opts_dommemstat[] = { .flags = VSH_OFLAG_REQ, .help = N_("domain name, id or uuid") }, + {.name = "period", + .type = VSH_OT_DATA, + .flags = VSH_OFLAG_EMPTY_OK, + .help = N_("period in seconds to set collection") + },
Hmm, I think I'd prefer to see the 'period' specified as a flag, rather than positional arg. eg virsh dommemstat --period NNN
@@ -668,10 +668,30 @@ Both I<--live> and I<--current> flags may be given, but I<--current> is exclusive. If no flag is specified, behavior is different depending on hypervisor.
-=item B<dommemstat> I<domain> +=item B<dommemstat> I<domain> [I<period> B<seconds>] +[[I<--config>] [I<--live>] | [I<--current>]]
Get memory stats for a running domain.
+Depending on the hypervisor a variety of statistics can be returned + +For QEMU/KVM with a memory balloon, setting the optional I<period> to a +value larger than 0 in seconds will allow the balloon driver to return +additional statistics which will be displayed by subsequent B<dommemstat> +commands. Setting the I<period> to 0 will stop the balloon driver collection, +but does not clear the statistics in the balloon driver. Requires at least +QEMU/KVM 1.5 to be running on the host. + +The I<--live>, I<--config>, and I<--current> flags are only valid when using +the I<period> option in order to set the collection period for the balloon +driver. If I<--live> is specified, only the running guest collection period +is affected. If I<--config> is specified, affect the next boot of a persistent +guest. If I<--current> is specified, affect the current guest state. + +Both I<--live> and I<--config> flags may be given, but I<--current> is +exclusive. If no flag is specified, behavior is different depending +on the guest state. + =item B<domblkerror> I<domain>
Show errors on block devices. This command usually comes handy when
Daniel -- |: http://berrange.com -o- http://www.flickr.com/photos/dberrange/ :| |: http://libvirt.org -o- http://virt-manager.org :| |: http://autobuild.org -o- http://search.cpan.org/~danberr/ :| |: http://entangle-photo.org -o- http://live.gnome.org/gtk-vnc :|

On 07/12/2013 08:45 AM, Daniel P. Berrange wrote:
On Thu, Jul 11, 2013 at 07:56:00PM -0400, John Ferlan wrote: <...snip...>
index 5fbd32c..4cbf105 100644 --- a/tools/virsh-domain-monitor.c +++ b/tools/virsh-domain-monitor.c @@ -314,6 +314,23 @@ static const vshCmdOptDef opts_dommemstat[] = { .flags = VSH_OFLAG_REQ, .help = N_("domain name, id or uuid") }, + {.name = "period", + .type = VSH_OT_DATA, + .flags = VSH_OFLAG_EMPTY_OK, + .help = N_("period in seconds to set collection") + },
Hmm, I think I'd prefer to see the 'period' specified as a flag, rather than positional arg. eg
virsh dommemstat --period NNN
I've squashed the following: diff --git a/tools/virsh-domain-monitor.c b/tools/virsh-domain-monitor.c index 4cbf105..773f96d 100644 --- a/tools/virsh-domain-monitor.c +++ b/tools/virsh-domain-monitor.c @@ -316,7 +316,7 @@ static const vshCmdOptDef opts_dommemstat[] = { }, {.name = "period", .type = VSH_OT_DATA, - .flags = VSH_OFLAG_EMPTY_OK, + .flags = VSH_OFLAG_REQ_OPT, .help = N_("period in seconds to set collection") }, {.name = "config",

On Fri, Jul 12, 2013 at 10:41:23AM -0400, John Ferlan wrote:
On 07/12/2013 08:45 AM, Daniel P. Berrange wrote:
On Thu, Jul 11, 2013 at 07:56:00PM -0400, John Ferlan wrote: <...snip...>
index 5fbd32c..4cbf105 100644 --- a/tools/virsh-domain-monitor.c +++ b/tools/virsh-domain-monitor.c @@ -314,6 +314,23 @@ static const vshCmdOptDef opts_dommemstat[] = { .flags = VSH_OFLAG_REQ, .help = N_("domain name, id or uuid") }, + {.name = "period", + .type = VSH_OT_DATA, + .flags = VSH_OFLAG_EMPTY_OK, + .help = N_("period in seconds to set collection") + },
Hmm, I think I'd prefer to see the 'period' specified as a flag, rather than positional arg. eg
virsh dommemstat --period NNN
I've squashed the following:
diff --git a/tools/virsh-domain-monitor.c b/tools/virsh-domain-monitor.c index 4cbf105..773f96d 100644 --- a/tools/virsh-domain-monitor.c +++ b/tools/virsh-domain-monitor.c @@ -316,7 +316,7 @@ static const vshCmdOptDef opts_dommemstat[] = { }, {.name = "period", .type = VSH_OT_DATA, - .flags = VSH_OFLAG_EMPTY_OK, + .flags = VSH_OFLAG_REQ_OPT, .help = N_("period in seconds to set collection") }, {.name = "config",
Need to update the .pod man page to say I<--period> too. Daniel -- |: http://berrange.com -o- http://www.flickr.com/photos/dberrange/ :| |: http://libvirt.org -o- http://virt-manager.org :| |: http://autobuild.org -o- http://search.cpan.org/~danberr/ :| |: http://entangle-photo.org -o- http://live.gnome.org/gtk-vnc :|

On Thu, Jul 11, 2013 at 19:55:50 -0400, John Ferlan wrote:
This patch set replaces:
https://www.redhat.com/archives/libvir-list/2013-July/msg00435.html
Changes
07 -> 09-> Remove the "flags", "Flags", "FLAGS" (learned something new!)
Just remember to do the same in the subject of those patches before pushing. Jirka

On 07/15/2013 05:57 AM, Jiri Denemark wrote:
On Thu, Jul 11, 2013 at 19:55:50 -0400, John Ferlan wrote:
This patch set replaces:
https://www.redhat.com/archives/libvir-list/2013-July/msg00435.html
Changes
07 -> 09-> Remove the "flags", "Flags", "FLAGS" (learned something new!)
Just remember to do the same in the subject of those patches before pushing.
Jirka
Yep - will do. Just waiting to find out if what I proposed to squash in for 4, 5, & 10 is sufficient to push. John

On 07/11/2013 07:55 PM, John Ferlan wrote:
This patch set replaces:
https://www.redhat.com/archives/libvir-list/2013-July/msg00435.html
Changes
01 -> No change 02 & 03 -> Adjust typecaste to switch() and remove "default:" 04 -> Use "unsigned int" as requested 05 -> Add ballooninit, remove get of period before set, remove setting of period during reconnect, other changes per review 06 -> Remove the opaque structure, replace with direct call through "qom-get" to return "guest-stats" and fill in stats[] directly 07 -> 09-> Remove the "flags", "Flags", "FLAGS" (learned something new!) 10 -> Add virsh.pod (hopefully have syntax right). NOTE: The formatdomain.html.in was already updated in 04 to describe the <stats period='#'/> XML syntax. This change describes the virsh command in order to set the period since this is the change where virsh code was adjusted. In 04, all one could do would be virsh edit
John Ferlan (10): Add qemuMonitorJSONGetObjectListPaths() method for QMP qom-list command Add qemuMonitorJSONGetObjectProperty() method for QMP qom-get command Add qemuMonitorJSONSetObjectProperty() method for QMP qom-set command Add 'period' for Memballoon statistics gathering capability Determine whether to start balloon memory stats gathering. Add capability to fetch balloon stats Add new public API virDomainSetMemoryStatsPeriodFlags Specify remote protocol for virDomainSetMemoryStatsPeriodFlags Implement the virDomainSetMemoryStatsPeriodFlags for QEMU driver Allow balloon driver collection to be adjusted dynamically
docs/formatdomain.html.in | 19 ++ docs/schemas/domaincommon.rng | 7 + include/libvirt/libvirt.h.in | 3 + src/conf/domain_conf.c | 38 +++- src/conf/domain_conf.h | 1 + src/driver.h | 6 + src/libvirt.c | 64 ++++++ src/libvirt_public.syms | 5 + src/qemu/qemu_driver.c | 65 ++++++ src/qemu/qemu_monitor.c | 140 ++++++++++++- src/qemu/qemu_monitor.h | 2 + src/qemu/qemu_monitor_json.c | 460 ++++++++++++++++++++++++++++++++---------- src/qemu/qemu_monitor_json.h | 60 ++++++ src/qemu/qemu_process.c | 14 +- src/remote/remote_driver.c | 1 + src/remote/remote_protocol.x | 15 +- src/remote_protocol-structs | 6 + tests/qemumonitorjsontest.c | 186 +++++++++++++++++ tools/virsh-domain-monitor.c | 66 +++++- tools/virsh.pod | 22 +- 20 files changed, 1060 insertions(+), 120 deletions(-)
I have pushed the first 3 patches. Still need closure on 4, 5, & 10. John

On 07/11/2013 07:55 PM, John Ferlan wrote:
This patch set replaces:
https://www.redhat.com/archives/libvir-list/2013-July/msg00435.html
Changes
01 -> No change 02 & 03 -> Adjust typecaste to switch() and remove "default:" 04 -> Use "unsigned int" as requested 05 -> Add ballooninit, remove get of period before set, remove setting of period during reconnect, other changes per review 06 -> Remove the opaque structure, replace with direct call through "qom-get" to return "guest-stats" and fill in stats[] directly 07 -> 09-> Remove the "flags", "Flags", "FLAGS" (learned something new!) 10 -> Add virsh.pod (hopefully have syntax right). NOTE: The formatdomain.html.in was already updated in 04 to describe the <stats period='#'/> XML syntax. This change describes the virsh command in order to set the period since this is the change where virsh code was adjusted. In 04, all one could do would be virsh edit
John Ferlan (10): Add qemuMonitorJSONGetObjectListPaths() method for QMP qom-list command Add qemuMonitorJSONGetObjectProperty() method for QMP qom-get command Add qemuMonitorJSONSetObjectProperty() method for QMP qom-set command Add 'period' for Memballoon statistics gathering capability Determine whether to start balloon memory stats gathering. Add capability to fetch balloon stats Add new public API virDomainSetMemoryStatsPeriodFlags Specify remote protocol for virDomainSetMemoryStatsPeriodFlags Implement the virDomainSetMemoryStatsPeriodFlags for QEMU driver Allow balloon driver collection to be adjusted dynamically
docs/formatdomain.html.in | 19 ++ docs/schemas/domaincommon.rng | 7 + include/libvirt/libvirt.h.in | 3 + src/conf/domain_conf.c | 38 +++- src/conf/domain_conf.h | 1 + src/driver.h | 6 + src/libvirt.c | 64 ++++++ src/libvirt_public.syms | 5 + src/qemu/qemu_driver.c | 65 ++++++ src/qemu/qemu_monitor.c | 140 ++++++++++++- src/qemu/qemu_monitor.h | 2 + src/qemu/qemu_monitor_json.c | 460 ++++++++++++++++++++++++++++++++---------- src/qemu/qemu_monitor_json.h | 60 ++++++ src/qemu/qemu_process.c | 14 +- src/remote/remote_driver.c | 1 + src/remote/remote_protocol.x | 15 +- src/remote_protocol-structs | 6 + tests/qemumonitorjsontest.c | 186 +++++++++++++++++ tools/virsh-domain-monitor.c | 66 +++++- tools/virsh.pod | 22 +- 20 files changed, 1060 insertions(+), 120 deletions(-)
I updated the .pod file to have the I<--period> and pushed the remaining patches. Thanks for the reviews, John
participants (4)
-
Daniel P. Berrange
-
Eric Blake
-
Jiri Denemark
-
John Ferlan