From e5554e2015f8fb452135f7b1ce1976536266379c Mon Sep 17 00:00:00 2001 From: Stratos Psomadakis Date: Mon, 15 Sep 2014 15:34:57 +0300 Subject: [PATCH 1/9] monitor: Reset HMP mon->rs in CHR_EVENT_OPEN Commit cdaa86a54 ("Add G_IO_HUP handler for socket chardev") exposed a bug in the way the HMP monitor handles its command buffer. When a client closes the connection to the monitor, tcp_chr_read() will detect the G_IO_HUP condition and call tcp_chr_disconnect() to close the server-side connection too. Due to the fact that monitor reads 1 byte at a time (for each tcp_chr_read()), the monitor readline state / buffers might contain junk (i.e. a half-finished command). Thus, without calling readline_restart() on mon->rs in CHR_EVENT_OPEN, future HMP commands will fail. Signed-off-by: Stratos Psomadakis Signed-off-by: Dimitris Aragiorgis Signed-off-by: Luiz Capitulino --- monitor.c | 1 + 1 file changed, 1 insertion(+) diff --git a/monitor.c b/monitor.c index b96710e212..48850afe86 100644 --- a/monitor.c +++ b/monitor.c @@ -5249,6 +5249,7 @@ static void monitor_event(void *opaque, int event) monitor_printf(mon, "QEMU %s monitor - type 'help' for more " "information\n", QEMU_VERSION); if (!mon->mux_out) { + readline_restart(mon->rs); readline_show_prompt(mon->rs); } mon->reset_seen = 1; From 1f9296b51a26650916a2c4191268bb64057bdc5f Mon Sep 17 00:00:00 2001 From: Luiz Capitulino Date: Mon, 15 Sep 2014 12:00:11 -0400 Subject: [PATCH 2/9] virtio-balloon: fix integer overflow in memory stats feature When a QMP client changes the polling interval time by setting the guest-stats-polling-interval property, the interval value is stored and manipulated as an int64_t variable. However, the balloon_stats_change_timer() function, which is used to set the actual timer with the interval value, takes an int instead, causing an overflow for big interval values. This commit fix this bug by changing balloon_stats_change_timer() to take an int64_t and also it limits the polling interval value to UINT_MAX to avoid other kinds of overflow. Signed-off-by: Luiz Capitulino Reviewed-by: Eric Blake Reviewed-by: Markus Armbruster --- hw/virtio/virtio-balloon.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/hw/virtio/virtio-balloon.c b/hw/virtio/virtio-balloon.c index 2c30b3d8bd..b5cf7cacc0 100644 --- a/hw/virtio/virtio-balloon.c +++ b/hw/virtio/virtio-balloon.c @@ -87,7 +87,7 @@ static void balloon_stats_destroy_timer(VirtIOBalloon *s) } } -static void balloon_stats_change_timer(VirtIOBalloon *s, int secs) +static void balloon_stats_change_timer(VirtIOBalloon *s, int64_t secs) { timer_mod(s->stats_timer, qemu_clock_get_ms(QEMU_CLOCK_VIRTUAL) + secs * 1000); } @@ -170,6 +170,11 @@ static void balloon_stats_set_poll_interval(Object *obj, struct Visitor *v, return; } + if (value > UINT_MAX) { + error_setg(errp, "timer value is too big"); + return; + } + if (value == s->stats_poll_interval) { return; } From cee2dedb85b97e4976c83bea84064c3921b8b7ac Mon Sep 17 00:00:00 2001 From: Michael Roth Date: Thu, 18 Sep 2014 15:36:40 -0500 Subject: [PATCH 3/9] qapi: add visit_start_union and visit_end_union In some cases an input visitor might bail out on filling out a struct for various reasons, such as missing fields when running in strict mode. In the case of a QAPI Union type, this may lead to cases where the .kind field which encodes the union type is uninitialized. Subsequently, other visitors, such as the dealloc visitor, may use this .kind value as if it were initialized, leading to assumptions about the union type which in this case may lead to segfaults. For example, freeing an integer value. However, we can generally rely on the fact that the always-present .data void * field that we generate for these union types will always be NULL in cases where .kind is uninitialized (at least, there shouldn't be a reason where we'd do this purposefully). So pass this information on to Visitor implementation via these optional start_union/end_union interfaces so this information can be used to guard against the situation above. We will make use of this information in a subsequent patch for the dealloc visitor. Cc: qemu-stable@nongnu.org Reported-by: Fam Zheng Suggested-by: Paolo Bonzini Reviewed-by: Paolo Bonzini Reviewed-by: Eric Blake Signed-off-by: Michael Roth Signed-off-by: Luiz Capitulino --- include/qapi/visitor-impl.h | 2 ++ include/qapi/visitor.h | 2 ++ qapi/qapi-visit-core.c | 15 +++++++++++++++ scripts/qapi-visit.py | 6 ++++++ 4 files changed, 25 insertions(+) diff --git a/include/qapi/visitor-impl.h b/include/qapi/visitor-impl.h index ecc0183196..09bb0fd408 100644 --- a/include/qapi/visitor-impl.h +++ b/include/qapi/visitor-impl.h @@ -55,6 +55,8 @@ struct Visitor void (*type_int64)(Visitor *v, int64_t *obj, const char *name, Error **errp); /* visit_type_size() falls back to (*type_uint64)() if type_size is unset */ void (*type_size)(Visitor *v, uint64_t *obj, const char *name, Error **errp); + bool (*start_union)(Visitor *v, bool data_present, Error **errp); + void (*end_union)(Visitor *v, bool data_present, Error **errp); }; void input_type_enum(Visitor *v, int *obj, const char *strings[], diff --git a/include/qapi/visitor.h b/include/qapi/visitor.h index 4a0178fa46..5934f59ad8 100644 --- a/include/qapi/visitor.h +++ b/include/qapi/visitor.h @@ -58,5 +58,7 @@ void visit_type_size(Visitor *v, uint64_t *obj, const char *name, Error **errp); void visit_type_bool(Visitor *v, bool *obj, const char *name, Error **errp); void visit_type_str(Visitor *v, char **obj, const char *name, Error **errp); void visit_type_number(Visitor *v, double *obj, const char *name, Error **errp); +bool visit_start_union(Visitor *v, bool data_present, Error **errp); +void visit_end_union(Visitor *v, bool data_present, Error **errp); #endif diff --git a/qapi/qapi-visit-core.c b/qapi/qapi-visit-core.c index 55f8d4068c..b66b93ae2b 100644 --- a/qapi/qapi-visit-core.c +++ b/qapi/qapi-visit-core.c @@ -58,6 +58,21 @@ void visit_end_list(Visitor *v, Error **errp) v->end_list(v, errp); } +bool visit_start_union(Visitor *v, bool data_present, Error **errp) +{ + if (v->start_union) { + return v->start_union(v, data_present, errp); + } + return true; +} + +void visit_end_union(Visitor *v, bool data_present, Error **errp) +{ + if (v->end_union) { + v->end_union(v, data_present, errp); + } +} + void visit_optional(Visitor *v, bool *present, const char *name, Error **errp) { diff --git a/scripts/qapi-visit.py b/scripts/qapi-visit.py index df9f7fb657..8f845a2b29 100644 --- a/scripts/qapi-visit.py +++ b/scripts/qapi-visit.py @@ -358,6 +358,9 @@ void visit_type_%(name)s(Visitor *m, %(name)s **obj, const char *name, Error **e if (err) { goto out_obj; } + if (!visit_start_union(m, !!(*obj)->data, &err) || err) { + goto out_obj; + } switch ((*obj)->kind) { ''', disc_type = disc_type, @@ -386,6 +389,9 @@ void visit_type_%(name)s(Visitor *m, %(name)s **obj, const char *name, Error **e out_obj: error_propagate(errp, err); err = NULL; + visit_end_union(m, !!(*obj)->data, &err); + error_propagate(errp, err); + err = NULL; } visit_end_struct(m, &err); out: From 146db9f91979db89a123ea10d2b825d3670d2b36 Mon Sep 17 00:00:00 2001 From: Michael Roth Date: Thu, 18 Sep 2014 15:36:41 -0500 Subject: [PATCH 4/9] qapi: dealloc visitor, implement visit_start_union If the .data field of a QAPI Union is NULL, we don't need to free any of the union fields. Make use of the new visit_start_union interface to access this information and instruct the generated code to not visit these fields when this occurs. Cc: qemu-stable@nongnu.org Reported-by: Fam Zheng Suggested-by: Paolo Bonzini Reviewed-by: Paolo Bonzini Reviewed-by: Eric Blake Signed-off-by: Michael Roth Signed-off-by: Luiz Capitulino --- qapi/qapi-dealloc-visitor.c | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/qapi/qapi-dealloc-visitor.c b/qapi/qapi-dealloc-visitor.c index dc53545fa5..a14a1c7146 100644 --- a/qapi/qapi-dealloc-visitor.c +++ b/qapi/qapi-dealloc-visitor.c @@ -162,6 +162,31 @@ static void qapi_dealloc_type_enum(Visitor *v, int *obj, const char *strings[], { } +/* If there's no data present, the dealloc visitor has nothing to free. + * Thus, indicate to visitor code that the subsequent union fields can + * be skipped. This is not an error condition, since the cleanup of the + * rest of an object can continue unhindered, so leave errp unset in + * these cases. + * + * NOTE: In cases where we're attempting to deallocate an object that + * may have missing fields, the field indicating the union type may + * be missing. In such a case, it's possible we don't have enough + * information to differentiate data_present == false from a case where + * data *is* present but happens to be a scalar with a value of 0. + * This is okay, since in the case of the dealloc visitor there's no + * work that needs to done in either situation. + * + * The current inability in QAPI code to more thoroughly verify a union + * type in such cases will likely need to be addressed if we wish to + * implement this interface for other types of visitors in the future, + * however. + */ +static bool qapi_dealloc_start_union(Visitor *v, bool data_present, + Error **errp) +{ + return data_present; +} + Visitor *qapi_dealloc_get_visitor(QapiDeallocVisitor *v) { return &v->visitor; @@ -191,6 +216,7 @@ QapiDeallocVisitor *qapi_dealloc_visitor_new(void) v->visitor.type_str = qapi_dealloc_type_str; v->visitor.type_number = qapi_dealloc_type_number; v->visitor.type_size = qapi_dealloc_type_size; + v->visitor.start_union = qapi_dealloc_start_union; QTAILQ_INIT(&v->stack); From cb55111b4e425fa3279302fa7306b9a3d5164ff4 Mon Sep 17 00:00:00 2001 From: Michael Roth Date: Thu, 18 Sep 2014 15:36:42 -0500 Subject: [PATCH 5/9] tests: add QMP input visitor test for unions with no discriminator This is more of an exercise of the dealloc visitor, where it may erroneously use an uninitialized discriminator field as indication that union fields corresponding to that discriminator field/type are present, which can lead to attempts to free random chunks of heap memory. Cc: qemu-stable@nongnu.org Reviewed-by: Eric Blake Reviewed-by: Paolo Bonzini Signed-off-by: Michael Roth Signed-off-by: Luiz Capitulino --- tests/qapi-schema/qapi-schema-test.json | 10 ++++++++++ tests/qapi-schema/qapi-schema-test.out | 3 +++ tests/test-qmp-input-strict.c | 17 +++++++++++++++++ 3 files changed, 30 insertions(+) diff --git a/tests/qapi-schema/qapi-schema-test.json b/tests/qapi-schema/qapi-schema-test.json index ab4d3d96b6..d43b5fd2e9 100644 --- a/tests/qapi-schema/qapi-schema-test.json +++ b/tests/qapi-schema/qapi-schema-test.json @@ -33,6 +33,9 @@ { 'type': 'UserDefB', 'data': { 'integer': 'int' } } +{ 'type': 'UserDefC', + 'data': { 'string1': 'str', 'string2': 'str' } } + { 'union': 'UserDefUnion', 'base': 'UserDefZero', 'data': { 'a' : 'UserDefA', 'b' : 'UserDefB' } } @@ -47,6 +50,13 @@ # FIXME generated struct UserDefFlatUnion has members for direct base # UserDefOne, but lacks members for indirect base UserDefZero +# this variant of UserDefFlatUnion defaults to a union that uses fields with +# allocated types to test corner cases in the cleanup/dealloc visitor +{ 'union': 'UserDefFlatUnion2', + 'base': 'UserDefUnionBase', + 'discriminator': 'enum1', + 'data': { 'value1' : 'UserDefC', 'value2' : 'UserDefB', 'value3' : 'UserDefA' } } + { 'union': 'UserDefAnonUnion', 'discriminator': {}, 'data': { 'uda': 'UserDefA', 's': 'str', 'i': 'int' } } diff --git a/tests/qapi-schema/qapi-schema-test.out b/tests/qapi-schema/qapi-schema-test.out index 95e989925b..08d7304dfa 100644 --- a/tests/qapi-schema/qapi-schema-test.out +++ b/tests/qapi-schema/qapi-schema-test.out @@ -6,9 +6,11 @@ OrderedDict([('type', 'UserDefNested'), ('data', OrderedDict([('string0', 'str'), ('dict1', OrderedDict([('string1', 'str'), ('dict2', OrderedDict([('userdef1', 'UserDefOne'), ('string2', 'str')])), ('*dict3', OrderedDict([('userdef2', 'UserDefOne'), ('string3', 'str')]))]))]))]), OrderedDict([('type', 'UserDefA'), ('data', OrderedDict([('boolean', 'bool')]))]), OrderedDict([('type', 'UserDefB'), ('data', OrderedDict([('integer', 'int')]))]), + OrderedDict([('type', 'UserDefC'), ('data', OrderedDict([('string1', 'str'), ('string2', 'str')]))]), OrderedDict([('union', 'UserDefUnion'), ('base', 'UserDefZero'), ('data', OrderedDict([('a', 'UserDefA'), ('b', 'UserDefB')]))]), OrderedDict([('type', 'UserDefUnionBase'), ('data', OrderedDict([('string', 'str'), ('enum1', 'EnumOne')]))]), OrderedDict([('union', 'UserDefFlatUnion'), ('base', 'UserDefUnionBase'), ('discriminator', 'enum1'), ('data', OrderedDict([('value1', 'UserDefA'), ('value2', 'UserDefB'), ('value3', 'UserDefB')]))]), + OrderedDict([('union', 'UserDefFlatUnion2'), ('base', 'UserDefUnionBase'), ('discriminator', 'enum1'), ('data', OrderedDict([('value1', 'UserDefC'), ('value2', 'UserDefB'), ('value3', 'UserDefA')]))]), OrderedDict([('union', 'UserDefAnonUnion'), ('discriminator', OrderedDict()), ('data', OrderedDict([('uda', 'UserDefA'), ('s', 'str'), ('i', 'int')]))]), OrderedDict([('union', 'UserDefNativeListUnion'), ('data', OrderedDict([('integer', ['int']), ('s8', ['int8']), ('s16', ['int16']), ('s32', ['int32']), ('s64', ['int64']), ('u8', ['uint8']), ('u16', ['uint16']), ('u32', ['uint32']), ('u64', ['uint64']), ('number', ['number']), ('boolean', ['bool']), ('string', ['str'])]))]), OrderedDict([('command', 'user_def_cmd'), ('data', OrderedDict())]), @@ -32,6 +34,7 @@ OrderedDict([('type', 'UserDefNested'), ('data', OrderedDict([('string0', 'str'), ('dict1', OrderedDict([('string1', 'str'), ('dict2', OrderedDict([('userdef1', 'UserDefOne'), ('string2', 'str')])), ('*dict3', OrderedDict([('userdef2', 'UserDefOne'), ('string3', 'str')]))]))]))]), OrderedDict([('type', 'UserDefA'), ('data', OrderedDict([('boolean', 'bool')]))]), OrderedDict([('type', 'UserDefB'), ('data', OrderedDict([('integer', 'int')]))]), + OrderedDict([('type', 'UserDefC'), ('data', OrderedDict([('string1', 'str'), ('string2', 'str')]))]), OrderedDict([('type', 'UserDefUnionBase'), ('data', OrderedDict([('string', 'str'), ('enum1', 'EnumOne')]))]), OrderedDict([('type', 'UserDefOptions'), ('data', OrderedDict([('*i64', ['int']), ('*u64', ['uint64']), ('*u16', ['uint16']), ('*i64x', 'int'), ('*u64x', 'uint64')]))]), OrderedDict([('type', 'EventStructOne'), ('data', OrderedDict([('struct1', 'UserDefOne'), ('string', 'str'), ('*enum2', 'EnumOne')]))])] diff --git a/tests/test-qmp-input-strict.c b/tests/test-qmp-input-strict.c index 0f770034b1..d5360c6a87 100644 --- a/tests/test-qmp-input-strict.c +++ b/tests/test-qmp-input-strict.c @@ -260,6 +260,21 @@ static void test_validate_fail_union_flat(TestInputVisitorData *data, qapi_free_UserDefFlatUnion(tmp); } +static void test_validate_fail_union_flat_no_discrim(TestInputVisitorData *data, + const void *unused) +{ + UserDefFlatUnion2 *tmp = NULL; + Error *err = NULL; + Visitor *v; + + /* test situation where discriminator field ('enum1' here) is missing */ + v = validate_test_init(data, "{ 'string': 'c', 'string1': 'd', 'string2': 'e' }"); + + visit_type_UserDefFlatUnion2(v, &tmp, NULL, &err); + g_assert(err); + qapi_free_UserDefFlatUnion2(tmp); +} + static void test_validate_fail_union_anon(TestInputVisitorData *data, const void *unused) { @@ -310,6 +325,8 @@ int main(int argc, char **argv) &testdata, test_validate_fail_union); validate_test_add("/visitor/input-strict/fail/union-flat", &testdata, test_validate_fail_union_flat); + validate_test_add("/visitor/input-strict/fail/union-flat-no-discriminator", + &testdata, test_validate_fail_union_flat_no_discrim); validate_test_add("/visitor/input-strict/fail/union-anon", &testdata, test_validate_fail_union_anon); From fe509ee2373078435fb8c4f68eebd2740c4e388f Mon Sep 17 00:00:00 2001 From: Fam Zheng Date: Thu, 18 Sep 2014 15:36:43 -0500 Subject: [PATCH 6/9] qemu-iotests: Test missing "driver" key for blockdev-add Signed-off-by: Fam Zheng Reviewed-by: Eric Blake Cc: qemu-stable@nongnu.org Signed-off-by: Michael Roth Signed-off-by: Luiz Capitulino --- tests/qemu-iotests/087 | 17 +++++++++++++++++ tests/qemu-iotests/087.out | 13 +++++++++++++ 2 files changed, 30 insertions(+) diff --git a/tests/qemu-iotests/087 b/tests/qemu-iotests/087 index 82c56b1394..d7454d13da 100755 --- a/tests/qemu-iotests/087 +++ b/tests/qemu-iotests/087 @@ -218,6 +218,23 @@ run_qemu < Date: Fri, 19 Sep 2014 09:27:04 +0200 Subject: [PATCH 7/9] qemu-socket: Polish errors for connect() and listen() failure connect() doesn't "connect to socket", it connects a socket to an address and, if it's of type SOCK_STREAM, initiates a connection. Scratch "to". listen() does "set socket to listening mode", but it sounds awkward. Change to "listen on socket". Signed-off-by: Markus Armbruster Reviewed-by: Gonglei Signed-off-by: Luiz Capitulino --- include/qapi/qmp/qerror.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/qapi/qmp/qerror.h b/include/qapi/qmp/qerror.h index 902d1a7a18..774e75df3b 100644 --- a/include/qapi/qmp/qerror.h +++ b/include/qapi/qmp/qerror.h @@ -155,10 +155,10 @@ void qerror_report_err(Error *err); ERROR_CLASS_GENERIC_ERROR, "this feature or command is not currently supported" #define QERR_SOCKET_CONNECT_FAILED \ - ERROR_CLASS_GENERIC_ERROR, "Failed to connect to socket" + ERROR_CLASS_GENERIC_ERROR, "Failed to connect socket" #define QERR_SOCKET_LISTEN_FAILED \ - ERROR_CLASS_GENERIC_ERROR, "Failed to set socket to listening mode" + ERROR_CLASS_GENERIC_ERROR, "Failed to listen on socket" #define QERR_SOCKET_BIND_FAILED \ ERROR_CLASS_GENERIC_ERROR, "Failed to bind socket" From 235256a2bdebf7097e524031d74b43bcb4adec30 Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Thu, 25 Sep 2014 08:49:31 +0200 Subject: [PATCH 8/9] qemu-socket: Eliminate silly QERR_ macros The QERR_ macros are leftovers from the days of "rich" error objects. They're used with error_set() and qerror_report(), and expand into the first *two* arguments. This trickiness has become pointless. Clean up. Signed-off-by: Markus Armbruster Reviewed-by: Paolo Bonzini Signed-off-by: Luiz Capitulino --- include/qapi/qmp/qerror.h | 12 ------------ util/qemu-sockets.c | 26 +++++++++++++------------- 2 files changed, 13 insertions(+), 25 deletions(-) diff --git a/include/qapi/qmp/qerror.h b/include/qapi/qmp/qerror.h index 774e75df3b..0ca6cbd0e6 100644 --- a/include/qapi/qmp/qerror.h +++ b/include/qapi/qmp/qerror.h @@ -154,16 +154,4 @@ void qerror_report_err(Error *err); #define QERR_UNSUPPORTED \ ERROR_CLASS_GENERIC_ERROR, "this feature or command is not currently supported" -#define QERR_SOCKET_CONNECT_FAILED \ - ERROR_CLASS_GENERIC_ERROR, "Failed to connect socket" - -#define QERR_SOCKET_LISTEN_FAILED \ - ERROR_CLASS_GENERIC_ERROR, "Failed to listen on socket" - -#define QERR_SOCKET_BIND_FAILED \ - ERROR_CLASS_GENERIC_ERROR, "Failed to bind socket" - -#define QERR_SOCKET_CREATE_FAILED \ - ERROR_CLASS_GENERIC_ERROR, "Failed to create socket" - #endif /* QERROR_H */ diff --git a/util/qemu-sockets.c b/util/qemu-sockets.c index 4a25585b2e..1eef590af5 100644 --- a/util/qemu-sockets.c +++ b/util/qemu-sockets.c @@ -159,7 +159,7 @@ int inet_listen_opts(QemuOpts *opts, int port_offset, Error **errp) slisten = qemu_socket(e->ai_family, e->ai_socktype, e->ai_protocol); if (slisten < 0) { if (!e->ai_next) { - error_set_errno(errp, errno, QERR_SOCKET_CREATE_FAILED); + error_setg_errno(errp, errno, "Failed to create socket"); } continue; } @@ -183,7 +183,7 @@ int inet_listen_opts(QemuOpts *opts, int port_offset, Error **errp) } if (p == port_max) { if (!e->ai_next) { - error_set_errno(errp, errno, QERR_SOCKET_BIND_FAILED); + error_setg_errno(errp, errno, "Failed to bind socket"); } } } @@ -194,7 +194,7 @@ int inet_listen_opts(QemuOpts *opts, int port_offset, Error **errp) listen: if (listen(slisten,1) != 0) { - error_set_errno(errp, errno, QERR_SOCKET_LISTEN_FAILED); + error_setg_errno(errp, errno, "Failed to listen on socket"); closesocket(slisten); freeaddrinfo(res); return -1; @@ -281,7 +281,7 @@ static int inet_connect_addr(struct addrinfo *addr, bool *in_progress, sock = qemu_socket(addr->ai_family, addr->ai_socktype, addr->ai_protocol); if (sock < 0) { - error_set_errno(errp, errno, QERR_SOCKET_CREATE_FAILED); + error_setg_errno(errp, errno, "Failed to create socket"); return -1; } socket_set_fast_reuse(sock); @@ -302,7 +302,7 @@ static int inet_connect_addr(struct addrinfo *addr, bool *in_progress, connect_state); *in_progress = true; } else if (rc < 0) { - error_set_errno(errp, errno, QERR_SOCKET_CONNECT_FAILED); + error_setg_errno(errp, errno, "Failed to connect socket"); closesocket(sock); return -1; } @@ -466,20 +466,20 @@ int inet_dgram_opts(QemuOpts *opts, Error **errp) /* create socket */ sock = qemu_socket(peer->ai_family, peer->ai_socktype, peer->ai_protocol); if (sock < 0) { - error_set_errno(errp, errno, QERR_SOCKET_CREATE_FAILED); + error_setg_errno(errp, errno, "Failed to create socket"); goto err; } socket_set_fast_reuse(sock); /* bind socket */ if (bind(sock, local->ai_addr, local->ai_addrlen) < 0) { - error_set_errno(errp, errno, QERR_SOCKET_BIND_FAILED); + error_setg_errno(errp, errno, "Failed to bind socket"); goto err; } /* connect to peer */ if (connect(sock,peer->ai_addr,peer->ai_addrlen) < 0) { - error_set_errno(errp, errno, QERR_SOCKET_CONNECT_FAILED); + error_setg_errno(errp, errno, "Failed to connect socket"); goto err; } @@ -684,7 +684,7 @@ int unix_listen_opts(QemuOpts *opts, Error **errp) sock = qemu_socket(PF_UNIX, SOCK_STREAM, 0); if (sock < 0) { - error_set_errno(errp, errno, QERR_SOCKET_CREATE_FAILED); + error_setg_errno(errp, errno, "Failed to create socket"); return -1; } @@ -709,11 +709,11 @@ int unix_listen_opts(QemuOpts *opts, Error **errp) unlink(un.sun_path); if (bind(sock, (struct sockaddr*) &un, sizeof(un)) < 0) { - error_set_errno(errp, errno, QERR_SOCKET_BIND_FAILED); + error_setg_errno(errp, errno, "Failed to bind socket"); goto err; } if (listen(sock, 1) < 0) { - error_set_errno(errp, errno, QERR_SOCKET_LISTEN_FAILED); + error_setg_errno(errp, errno, "Failed to listen on socket"); goto err; } @@ -739,7 +739,7 @@ int unix_connect_opts(QemuOpts *opts, Error **errp, sock = qemu_socket(PF_UNIX, SOCK_STREAM, 0); if (sock < 0) { - error_set_errno(errp, errno, QERR_SOCKET_CREATE_FAILED); + error_setg_errno(errp, errno, "Failed to create socket"); return -1; } if (callback != NULL) { @@ -774,7 +774,7 @@ int unix_connect_opts(QemuOpts *opts, Error **errp, } if (rc < 0) { - error_set_errno(errp, -rc, QERR_SOCKET_CONNECT_FAILED); + error_setg_errno(errp, -rc, "Failed to connect socket"); close(sock); sock = -1; } From a631892f9d6440812af98588e9635f1a2a7260ff Mon Sep 17 00:00:00 2001 From: Zhu Guihua Date: Tue, 23 Sep 2014 13:35:19 +0800 Subject: [PATCH 9/9] Add HMP command "info memory-devices" Provides HMP equivalent of QMP query-memory-devices command. Signed-off-by: Zhu Guihua Reviewed-By: Igor Mammedov Signed-off-by: Luiz Capitulino --- hmp-commands.hx | 2 ++ hmp.c | 38 ++++++++++++++++++++++++++++++++++++++ hmp.h | 1 + monitor.c | 7 +++++++ 4 files changed, 48 insertions(+) diff --git a/hmp-commands.hx b/hmp-commands.hx index f859f8d29f..0b1a4f778a 100644 --- a/hmp-commands.hx +++ b/hmp-commands.hx @@ -1778,6 +1778,8 @@ show qdev device model list show roms @item info tpm show the TPM device +@item info memory-devices +show the memory devices @end table ETEXI diff --git a/hmp.c b/hmp.c index 31fb6a15ca..63d76868b9 100644 --- a/hmp.c +++ b/hmp.c @@ -1720,3 +1720,41 @@ void hmp_info_memdev(Monitor *mon, const QDict *qdict) qapi_free_MemdevList(memdev_list); } + +void hmp_info_memory_devices(Monitor *mon, const QDict *qdict) +{ + Error *err = NULL; + MemoryDeviceInfoList *info_list = qmp_query_memory_devices(&err); + MemoryDeviceInfoList *info; + MemoryDeviceInfo *value; + PCDIMMDeviceInfo *di; + + for (info = info_list; info; info = info->next) { + value = info->value; + + if (value) { + switch (value->kind) { + case MEMORY_DEVICE_INFO_KIND_DIMM: + di = value->dimm; + + monitor_printf(mon, "Memory device [%s]: \"%s\"\n", + MemoryDeviceInfoKind_lookup[value->kind], + di->id ? di->id : ""); + monitor_printf(mon, " addr: 0x%" PRIx64 "\n", di->addr); + monitor_printf(mon, " slot: %" PRId64 "\n", di->slot); + monitor_printf(mon, " node: %" PRId64 "\n", di->node); + monitor_printf(mon, " size: %" PRIu64 "\n", di->size); + monitor_printf(mon, " memdev: %s\n", di->memdev); + monitor_printf(mon, " hotplugged: %s\n", + di->hotplugged ? "true" : "false"); + monitor_printf(mon, " hotpluggable: %s\n", + di->hotpluggable ? "true" : "false"); + break; + default: + break; + } + } + } + + qapi_free_MemoryDeviceInfoList(info_list); +} diff --git a/hmp.h b/hmp.h index 4fd3c4a901..4bb5dca45d 100644 --- a/hmp.h +++ b/hmp.h @@ -94,6 +94,7 @@ void hmp_cpu_add(Monitor *mon, const QDict *qdict); void hmp_object_add(Monitor *mon, const QDict *qdict); void hmp_object_del(Monitor *mon, const QDict *qdict); void hmp_info_memdev(Monitor *mon, const QDict *qdict); +void hmp_info_memory_devices(Monitor *mon, const QDict *qdict); void object_add_completion(ReadLineState *rs, int nb_args, const char *str); void object_del_completion(ReadLineState *rs, int nb_args, const char *str); void device_add_completion(ReadLineState *rs, int nb_args, const char *str); diff --git a/monitor.c b/monitor.c index 48850afe86..2d14f394d6 100644 --- a/monitor.c +++ b/monitor.c @@ -2921,6 +2921,13 @@ static mon_cmd_t info_cmds[] = { .help = "show memory backends", .mhandler.cmd = hmp_info_memdev, }, + { + .name = "memory-devices", + .args_type = "", + .params = "", + .help = "show memory devices", + .mhandler.cmd = hmp_info_memory_devices, + }, { .name = NULL, },