QAPI patches for 2016-10-07

-----BEGIN PGP SIGNATURE-----
 Version: GnuPG v1
 
 iQIcBAABAgAGBQJX9+GcAAoJEDhwtADrkYZTJ3oP/3IL9jj1aa3ypLpFEurBVAJb
 H2Izm64xbfqpAoXcq5TSec2yuo2KMAsGKZpbBdDzlN8z8eh7e8QU4J83VaZvYGo3
 0oLSZPTJ3r8Hpeb7MzJ4O7UiwiTj+6BEYSzwXLaoknBJeI/5gQmk1RUXZg1mx9k/
 BB1ADgzH/EVW9tzXva2Kd93vK1cTRU9jVADEh2AxPGsMKGA06R7TP2BV1emHso6l
 5wuwR8GLNmqbpR3xVtvycv9WlMLumhZlFdnCgjCvizhI9mNSsVMJozNaMs47lZP5
 nq7MUsOVJzOhncMmeLA/OliFQJqQG+iECpTAMqt078wbzwprG31Lu7GELXuIP11g
 MEOoT9KtKAZJRxfYKPfkRmi1rkvD5jlMuMaIlxm1n4EfZ9jk+9IiZ1QEnTWHjf6W
 x0DP7Dwio9kQDMkmGJ6O3ZdgEo3Y/Ghc2AmG3oIilU3E53R8mBifu3Fttik+M4kd
 vqNm0WC6S9v/748iTNfbuF97OBcQDrALvvMu12MZnYAcLZ3aXR/xYg5gX8WRhtyP
 Afy2qrfeZN810WIW9z7KUb0VesMi6g6OHivbaUfZ1XBJt8Omtl08f7bEfhzCBl7X
 sA3gruSEX8+Ra9F3QxTJO3Br+6V4Qx+AjxeQwxSJGNn58qqQhjJ4y4UTyBiDZwK2
 St07IDD15pAXGMqqRCXQ
 =qmII
 -----END PGP SIGNATURE-----

Merge remote-tracking branch 'remotes/armbru/tags/pull-qapi-2016-10-07' into staging

QAPI patches for 2016-10-07

# gpg: Signature made Fri 07 Oct 2016 18:55:40 BST
# gpg:                using RSA key 0x3870B400EB918653
# gpg: Good signature from "Markus Armbruster <armbru@redhat.com>"
# gpg:                 aka "Markus Armbruster <armbru@pond.sub.org>"
# Primary key fingerprint: 354B C8B3 D7EB 2A6B 6867  4E5F 3870 B400 EB91 8653

* remotes/armbru/tags/pull-qapi-2016-10-07:
  docs: Belatedly update for move of QMP/* to docs/
  docs: Belatedly update for move of qmp-commands.txt
  qmp: Disable query-cpu-* commands when they're unavailable
  MAINTAINERS: Pass the QObject staff from Luiz to Markus
  MAINTAINERS: Pass the HMP staff from Luiz to David
  qapi: return a 'missing parameter' error
  qapi: assert list entry has a value
  qapi: add assert about root value
  tests/test-qmp-input-strict: Cover missing struct members
  qapi: Fix crash when 'any' or 'null' parameter is missing
  qmp: fix object-add assert() without props

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
Peter Maydell 2016-10-10 11:45:09 +01:00
commit 0cb0155711
9 changed files with 129 additions and 28 deletions

View File

@ -1178,12 +1178,11 @@ F: qemu-timer.c
F: vl.c F: vl.c
Human Monitor (HMP) Human Monitor (HMP)
M: Luiz Capitulino <lcapitulino@redhat.com> M: Dr. David Alan Gilbert <dgilbert@redhat.com>
S: Maintained S: Maintained
F: monitor.c F: monitor.c
F: hmp.c F: hmp.c
F: hmp-commands.hx F: hmp-commands.hx
T: git git://repo.or.cz/qemu/qmp-unstable.git queue/qmp
Network device backends Network device backends
M: Jason Wang <jasowang@redhat.com> M: Jason Wang <jasowang@redhat.com>
@ -1248,8 +1247,8 @@ F: qapi/*.json
T: git git://repo.or.cz/qemu/armbru.git qapi-next T: git git://repo.or.cz/qemu/armbru.git qapi-next
QObject QObject
M: Luiz Capitulino <lcapitulino@redhat.com> M: Markus Armbruster <armbru@redhat.com>
S: Maintained S: Supported
F: qobject/ F: qobject/
F: include/qapi/qmp/ F: include/qapi/qmp/
X: include/qapi/qmp/dispatch.h X: include/qapi/qmp/dispatch.h
@ -1259,7 +1258,7 @@ F: tests/check-qint.c
F: tests/check-qjson.c F: tests/check-qjson.c
F: tests/check-qlist.c F: tests/check-qlist.c
F: tests/check-qstring.c F: tests/check-qstring.c
T: git git://repo.or.cz/qemu/qmp-unstable.git queue/qmp T: git git://repo.or.cz/qemu/armbru.git qapi-next
QEMU Guest Agent QEMU Guest Agent
M: Michael Roth <mdroth@linux.vnet.ibm.com> M: Michael Roth <mdroth@linux.vnet.ibm.com>

View File

@ -20,7 +20,7 @@ Also, the following notation is used to denote data flow:
-> data issued by the Client -> data issued by the Client
<- Server data response <- Server data response
Please, refer to the QMP specification (QMP/qmp-spec.txt) for detailed Please, refer to the QMP specification (docs/qmp-spec.txt) for detailed
information on the Server command and response formats. information on the Server command and response formats.
NOTE: This document is temporary and will be replaced soon. NOTE: This document is temporary and will be replaced soon.

View File

@ -7,8 +7,8 @@ This document doesn't discuss QMP protocol level details, nor does it dive
into the QAPI framework implementation. into the QAPI framework implementation.
For an in-depth introduction to the QAPI framework, please refer to For an in-depth introduction to the QAPI framework, please refer to
docs/qapi-code-gen.txt. For documentation about the QMP protocol, please docs/qapi-code-gen.txt. For documentation about the QMP protocol,
check the files in QMP/. start with docs/qmp-intro.txt.
== Overview == == Overview ==

View File

@ -9,7 +9,7 @@ however it is also possible to save the state of all devices to file,
without saving the RAM or the block devices of the VM. without saving the RAM or the block devices of the VM.
This operation is called "xen-save-devices-state" (see This operation is called "xen-save-devices-state" (see
QMP/qmp-commands.txt) qmp-commands.txt)
The binary format used in the file is the following: The binary format used in the file is the following:

View File

@ -986,6 +986,15 @@ static void qmp_unregister_commands_hack(void)
#ifndef TARGET_ARM #ifndef TARGET_ARM
qmp_unregister_command("query-gic-capabilities"); qmp_unregister_command("query-gic-capabilities");
#endif #endif
#if !defined(TARGET_S390X)
qmp_unregister_command("query-cpu-model-expansion");
qmp_unregister_command("query-cpu-model-baseline");
qmp_unregister_command("query-cpu-model-comparison");
#endif
#if !defined(TARGET_PPC) && !defined(TARGET_ARM) && !defined(TARGET_I386) \
&& !defined(TARGET_S390X)
qmp_unregister_command("query-cpu-definitions");
#endif
} }
static void qmp_init_marshal(void) static void qmp_init_marshal(void)

View File

@ -56,7 +56,7 @@ static QmpInputVisitor *to_qiv(Visitor *v)
static QObject *qmp_input_get_object(QmpInputVisitor *qiv, static QObject *qmp_input_get_object(QmpInputVisitor *qiv,
const char *name, const char *name,
bool consume) bool consume, Error **errp)
{ {
StackObject *tos; StackObject *tos;
QObject *qobj; QObject *qobj;
@ -64,6 +64,7 @@ static QObject *qmp_input_get_object(QmpInputVisitor *qiv,
if (QSLIST_EMPTY(&qiv->stack)) { if (QSLIST_EMPTY(&qiv->stack)) {
/* Starting at root, name is ignored. */ /* Starting at root, name is ignored. */
assert(qiv->root);
return qiv->root; return qiv->root;
} }
@ -79,10 +80,14 @@ static QObject *qmp_input_get_object(QmpInputVisitor *qiv,
bool removed = g_hash_table_remove(tos->h, name); bool removed = g_hash_table_remove(tos->h, name);
assert(removed); assert(removed);
} }
if (!ret) {
error_setg(errp, QERR_MISSING_PARAMETER, name);
}
} else { } else {
assert(qobject_type(qobj) == QTYPE_QLIST); assert(qobject_type(qobj) == QTYPE_QLIST);
assert(!name); assert(!name);
ret = qlist_entry_obj(tos->entry); ret = qlist_entry_obj(tos->entry);
assert(ret);
if (consume) { if (consume) {
tos->entry = qlist_next(tos->entry); tos->entry = qlist_next(tos->entry);
} }
@ -163,13 +168,16 @@ static void qmp_input_start_struct(Visitor *v, const char *name, void **obj,
size_t size, Error **errp) size_t size, Error **errp)
{ {
QmpInputVisitor *qiv = to_qiv(v); QmpInputVisitor *qiv = to_qiv(v);
QObject *qobj = qmp_input_get_object(qiv, name, true); QObject *qobj = qmp_input_get_object(qiv, name, true, errp);
Error *err = NULL; Error *err = NULL;
if (obj) { if (obj) {
*obj = NULL; *obj = NULL;
} }
if (!qobj || qobject_type(qobj) != QTYPE_QDICT) { if (!qobj) {
return;
}
if (qobject_type(qobj) != QTYPE_QDICT) {
error_setg(errp, QERR_INVALID_PARAMETER_TYPE, name ? name : "null", error_setg(errp, QERR_INVALID_PARAMETER_TYPE, name ? name : "null",
"QDict"); "QDict");
return; return;
@ -191,10 +199,13 @@ static void qmp_input_start_list(Visitor *v, const char *name,
GenericList **list, size_t size, Error **errp) GenericList **list, size_t size, Error **errp)
{ {
QmpInputVisitor *qiv = to_qiv(v); QmpInputVisitor *qiv = to_qiv(v);
QObject *qobj = qmp_input_get_object(qiv, name, true); QObject *qobj = qmp_input_get_object(qiv, name, true, errp);
const QListEntry *entry; const QListEntry *entry;
if (!qobj || qobject_type(qobj) != QTYPE_QLIST) { if (!qobj) {
return;
}
if (qobject_type(qobj) != QTYPE_QLIST) {
if (list) { if (list) {
*list = NULL; *list = NULL;
} }
@ -232,11 +243,10 @@ static void qmp_input_start_alternate(Visitor *v, const char *name,
bool promote_int, Error **errp) bool promote_int, Error **errp)
{ {
QmpInputVisitor *qiv = to_qiv(v); QmpInputVisitor *qiv = to_qiv(v);
QObject *qobj = qmp_input_get_object(qiv, name, false); QObject *qobj = qmp_input_get_object(qiv, name, false, errp);
if (!qobj) { if (!qobj) {
*obj = NULL; *obj = NULL;
error_setg(errp, QERR_MISSING_PARAMETER, name ? name : "null");
return; return;
} }
*obj = g_malloc0(size); *obj = g_malloc0(size);
@ -250,8 +260,13 @@ static void qmp_input_type_int64(Visitor *v, const char *name, int64_t *obj,
Error **errp) Error **errp)
{ {
QmpInputVisitor *qiv = to_qiv(v); QmpInputVisitor *qiv = to_qiv(v);
QInt *qint = qobject_to_qint(qmp_input_get_object(qiv, name, true)); QObject *qobj = qmp_input_get_object(qiv, name, true, errp);
QInt *qint;
if (!qobj) {
return;
}
qint = qobject_to_qint(qobj);
if (!qint) { if (!qint) {
error_setg(errp, QERR_INVALID_PARAMETER_TYPE, name ? name : "null", error_setg(errp, QERR_INVALID_PARAMETER_TYPE, name ? name : "null",
"integer"); "integer");
@ -266,8 +281,13 @@ static void qmp_input_type_uint64(Visitor *v, const char *name, uint64_t *obj,
{ {
/* FIXME: qobject_to_qint mishandles values over INT64_MAX */ /* FIXME: qobject_to_qint mishandles values over INT64_MAX */
QmpInputVisitor *qiv = to_qiv(v); QmpInputVisitor *qiv = to_qiv(v);
QInt *qint = qobject_to_qint(qmp_input_get_object(qiv, name, true)); QObject *qobj = qmp_input_get_object(qiv, name, true, errp);
QInt *qint;
if (!qobj) {
return;
}
qint = qobject_to_qint(qobj);
if (!qint) { if (!qint) {
error_setg(errp, QERR_INVALID_PARAMETER_TYPE, name ? name : "null", error_setg(errp, QERR_INVALID_PARAMETER_TYPE, name ? name : "null",
"integer"); "integer");
@ -281,8 +301,13 @@ static void qmp_input_type_bool(Visitor *v, const char *name, bool *obj,
Error **errp) Error **errp)
{ {
QmpInputVisitor *qiv = to_qiv(v); QmpInputVisitor *qiv = to_qiv(v);
QBool *qbool = qobject_to_qbool(qmp_input_get_object(qiv, name, true)); QObject *qobj = qmp_input_get_object(qiv, name, true, errp);
QBool *qbool;
if (!qobj) {
return;
}
qbool = qobject_to_qbool(qobj);
if (!qbool) { if (!qbool) {
error_setg(errp, QERR_INVALID_PARAMETER_TYPE, name ? name : "null", error_setg(errp, QERR_INVALID_PARAMETER_TYPE, name ? name : "null",
"boolean"); "boolean");
@ -296,10 +321,15 @@ static void qmp_input_type_str(Visitor *v, const char *name, char **obj,
Error **errp) Error **errp)
{ {
QmpInputVisitor *qiv = to_qiv(v); QmpInputVisitor *qiv = to_qiv(v);
QString *qstr = qobject_to_qstring(qmp_input_get_object(qiv, name, true)); QObject *qobj = qmp_input_get_object(qiv, name, true, errp);
QString *qstr;
*obj = NULL;
if (!qobj) {
return;
}
qstr = qobject_to_qstring(qobj);
if (!qstr) { if (!qstr) {
*obj = NULL;
error_setg(errp, QERR_INVALID_PARAMETER_TYPE, name ? name : "null", error_setg(errp, QERR_INVALID_PARAMETER_TYPE, name ? name : "null",
"string"); "string");
return; return;
@ -312,10 +342,13 @@ static void qmp_input_type_number(Visitor *v, const char *name, double *obj,
Error **errp) Error **errp)
{ {
QmpInputVisitor *qiv = to_qiv(v); QmpInputVisitor *qiv = to_qiv(v);
QObject *qobj = qmp_input_get_object(qiv, name, true); QObject *qobj = qmp_input_get_object(qiv, name, true, errp);
QInt *qint; QInt *qint;
QFloat *qfloat; QFloat *qfloat;
if (!qobj) {
return;
}
qint = qobject_to_qint(qobj); qint = qobject_to_qint(qobj);
if (qint) { if (qint) {
*obj = qint_get_int(qobject_to_qint(qobj)); *obj = qint_get_int(qobject_to_qint(qobj));
@ -336,7 +369,12 @@ static void qmp_input_type_any(Visitor *v, const char *name, QObject **obj,
Error **errp) Error **errp)
{ {
QmpInputVisitor *qiv = to_qiv(v); QmpInputVisitor *qiv = to_qiv(v);
QObject *qobj = qmp_input_get_object(qiv, name, true); QObject *qobj = qmp_input_get_object(qiv, name, true, errp);
*obj = NULL;
if (!qobj) {
return;
}
qobject_incref(qobj); qobject_incref(qobj);
*obj = qobj; *obj = qobj;
@ -345,7 +383,11 @@ static void qmp_input_type_any(Visitor *v, const char *name, QObject **obj,
static void qmp_input_type_null(Visitor *v, const char *name, Error **errp) static void qmp_input_type_null(Visitor *v, const char *name, Error **errp)
{ {
QmpInputVisitor *qiv = to_qiv(v); QmpInputVisitor *qiv = to_qiv(v);
QObject *qobj = qmp_input_get_object(qiv, name, true); QObject *qobj = qmp_input_get_object(qiv, name, true, errp);
if (!qobj) {
return;
}
if (qobject_type(qobj) != QTYPE_QNULL) { if (qobject_type(qobj) != QTYPE_QNULL) {
error_setg(errp, QERR_INVALID_PARAMETER_TYPE, name ? name : "null", error_setg(errp, QERR_INVALID_PARAMETER_TYPE, name ? name : "null",
@ -356,7 +398,7 @@ static void qmp_input_type_null(Visitor *v, const char *name, Error **errp)
static void qmp_input_optional(Visitor *v, const char *name, bool *present) static void qmp_input_optional(Visitor *v, const char *name, bool *present)
{ {
QmpInputVisitor *qiv = to_qiv(v); QmpInputVisitor *qiv = to_qiv(v);
QObject *qobj = qmp_input_get_object(qiv, name, false); QObject *qobj = qmp_input_get_object(qiv, name, false, NULL);
if (!qobj) { if (!qobj) {
*present = false; *present = false;
@ -384,6 +426,7 @@ Visitor *qmp_input_visitor_new(QObject *obj, bool strict)
{ {
QmpInputVisitor *v; QmpInputVisitor *v;
assert(obj);
v = g_malloc0(sizeof(*v)); v = g_malloc0(sizeof(*v));
v->visitor.type = VISITOR_INPUT; v->visitor.type = VISITOR_INPUT;

8
qmp.c
View File

@ -660,7 +660,7 @@ void qmp_add_client(const char *protocol, const char *fdname,
void qmp_object_add(const char *type, const char *id, void qmp_object_add(const char *type, const char *id,
bool has_props, QObject *props, Error **errp) bool has_props, QObject *props, Error **errp)
{ {
const QDict *pdict = NULL; QDict *pdict;
Visitor *v; Visitor *v;
Object *obj; Object *obj;
@ -670,14 +670,18 @@ void qmp_object_add(const char *type, const char *id,
error_setg(errp, QERR_INVALID_PARAMETER_TYPE, "props", "dict"); error_setg(errp, QERR_INVALID_PARAMETER_TYPE, "props", "dict");
return; return;
} }
QINCREF(pdict);
} else {
pdict = qdict_new();
} }
v = qmp_input_visitor_new(props, true); v = qmp_input_visitor_new(QOBJECT(pdict), true);
obj = user_creatable_add_type(type, id, pdict, v, errp); obj = user_creatable_add_type(type, id, pdict, v, errp);
visit_free(v); visit_free(v);
if (obj) { if (obj) {
object_unref(obj); object_unref(obj);
} }
QDECREF(pdict);
} }
void qmp_object_del(const char *id, Error **errp) void qmp_object_del(const char *id, Error **errp)

View File

@ -56,7 +56,7 @@ Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134217728 encryption=on
Testing: -S Testing: -S
QMP_VERSION QMP_VERSION
{"return": {}} {"return": {}}
{"error": {"class": "GenericError", "desc": "Invalid parameter type for 'driver', expected: string"}} {"error": {"class": "GenericError", "desc": "Parameter 'driver' is missing"}}
{"return": {}} {"return": {}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN"} {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN"}

View File

@ -193,6 +193,50 @@ static void test_validate_fail_struct_nested(TestInputVisitorData *data,
g_assert(!udp); g_assert(!udp);
} }
static void test_validate_fail_struct_missing(TestInputVisitorData *data,
const void *unused)
{
Error *err = NULL;
Visitor *v;
QObject *any;
GenericAlternate *alt;
bool present;
int en;
int64_t i64;
uint32_t u32;
int8_t i8;
char *str;
double dbl;
v = validate_test_init(data, "{}");
visit_start_struct(v, NULL, NULL, 0, &error_abort);
visit_start_struct(v, "struct", NULL, 0, &err);
error_free_or_abort(&err);
visit_start_list(v, "list", NULL, 0, &err);
error_free_or_abort(&err);
visit_start_alternate(v, "alternate", &alt, sizeof(*alt), false, &err);
error_free_or_abort(&err);
visit_optional(v, "optional", &present);
g_assert(!present);
visit_type_enum(v, "enum", &en, EnumOne_lookup, &err);
error_free_or_abort(&err);
visit_type_int(v, "i64", &i64, &err);
error_free_or_abort(&err);
visit_type_uint32(v, "u32", &u32, &err);
error_free_or_abort(&err);
visit_type_int8(v, "i8", &i8, &err);
error_free_or_abort(&err);
visit_type_str(v, "i8", &str, &err);
error_free_or_abort(&err);
visit_type_number(v, "dbl", &dbl, &err);
error_free_or_abort(&err);
visit_type_any(v, "any", &any, &err);
error_free_or_abort(&err);
visit_type_null(v, "null", &err);
error_free_or_abort(&err);
visit_end_struct(v, NULL);
}
static void test_validate_fail_list(TestInputVisitorData *data, static void test_validate_fail_list(TestInputVisitorData *data,
const void *unused) const void *unused)
{ {
@ -316,6 +360,8 @@ int main(int argc, char **argv)
&testdata, test_validate_fail_struct); &testdata, test_validate_fail_struct);
validate_test_add("/visitor/input-strict/fail/struct-nested", validate_test_add("/visitor/input-strict/fail/struct-nested",
&testdata, test_validate_fail_struct_nested); &testdata, test_validate_fail_struct_nested);
validate_test_add("/visitor/input-strict/fail/struct-missing",
&testdata, test_validate_fail_struct_missing);
validate_test_add("/visitor/input-strict/fail/list", validate_test_add("/visitor/input-strict/fail/list",
&testdata, test_validate_fail_list); &testdata, test_validate_fail_list);
validate_test_add("/visitor/input-strict/fail/union-flat", validate_test_add("/visitor/input-strict/fail/union-flat",