qemu with hax to log dma reads & writes jcs.org/2018/11/12/vfio

Merge remote-tracking branch 'remotes/ericb/tags/pull-qapi-2018-03-27-v2' into staging

qapi patches for 2018-03-27, 2.12-rc1

- Marc-André Lureau: qmp-test: fix response leak
- Eric Blake: tests: Silence false positive warning on generated test name
- Laurent Vivier: 0/4 (partial) coccinelle: re-run scripts from scripst/coccinelle
- Peter Xu: 0/8 Monitor: some oob related patches (fixes, new param, tests)
- Satheesh Rajendran: hmp.c: Revert hmp_info_cpus output format change

# gpg: Signature made Tue 27 Mar 2018 16:18:36 BST
# gpg: using RSA key A7A16B4A2527436A
# gpg: Good signature from "Eric Blake <eblake@redhat.com>"
# gpg: aka "Eric Blake (Free Software Programmer) <ebb9@byu.net>"
# gpg: aka "[jpeg image of size 6874]"
# Primary key fingerprint: 71C2 CC22 B1C4 6029 27D2 F3AA A7A1 6B4A 2527 436A

* remotes/ericb/tags/pull-qapi-2018-03-27-v2:
hmp.c: Revert hmp_info_cpus output format change
tests: qmp-test: add test for new "x-oob"
tests: Add parameter to qtest_init_without_qmp_handshake
monitor: new parameter "x-oob"
qmp: cleanup qmp queues properly
tests: add oob-test for qapi-schema
tests: let qapi-schema tests detect oob
qapi: restrict allow-oob value to be "true"
qmp: fix qmp_capabilities error regression
qdict: remove useless cast
error: Remove NULL checks on error_propagate() calls
error: Strip trailing '\n' from error string arguments (again again)
tests: Silence false positive warning on generated test name
qmp-test: fix response leak

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>

+233 -84
+5 -6
block/nvme.c
··· 695 695 unsigned long ns; 696 696 const char *slash = strchr(tmp, '/'); 697 697 if (!slash) { 698 - qdict_put(options, NVME_BLOCK_OPT_DEVICE, 699 - qstring_from_str(tmp)); 698 + qdict_put_str(options, NVME_BLOCK_OPT_DEVICE, tmp); 700 699 return; 701 700 } 702 701 device = g_strndup(tmp, slash - tmp); 703 - qdict_put(options, NVME_BLOCK_OPT_DEVICE, qstring_from_str(device)); 702 + qdict_put_str(options, NVME_BLOCK_OPT_DEVICE, device); 704 703 g_free(device); 705 704 namespace = slash + 1; 706 705 if (*namespace && qemu_strtoul(namespace, NULL, 10, &ns)) { ··· 708 707 namespace); 709 708 return; 710 709 } 711 - qdict_put(options, NVME_BLOCK_OPT_NAMESPACE, 712 - qstring_from_str(*namespace ? namespace : "1")); 710 + qdict_put_str(options, NVME_BLOCK_OPT_NAMESPACE, 711 + *namespace ? namespace : "1"); 713 712 } 714 713 } 715 714 ··· 1082 1081 bs->drv->format_name); 1083 1082 } 1084 1083 1085 - qdict_put(opts, "driver", qstring_from_str(bs->drv->format_name)); 1084 + qdict_put_str(opts, "driver", bs->drv->format_name); 1086 1085 bs->full_open_options = opts; 1087 1086 } 1088 1087
+1 -1
hmp.c
··· 381 381 382 382 monitor_printf(mon, "%c CPU #%" PRId64 ":", active, 383 383 cpu->value->cpu_index); 384 - monitor_printf(mon, " thread-id=%" PRId64 "\n", cpu->value->thread_id); 384 + monitor_printf(mon, " thread_id=%" PRId64 "\n", cpu->value->thread_id); 385 385 } 386 386 387 387 qapi_free_CpuInfoFastList(cpu_list);
+1
include/monitor/monitor.h
··· 13 13 #define MONITOR_USE_READLINE 0x02 14 14 #define MONITOR_USE_CONTROL 0x04 15 15 #define MONITOR_USE_PRETTY 0x08 16 + #define MONITOR_USE_OOB 0x10 16 17 17 18 bool monitor_cur_is_qmp(void); 18 19
+1 -3
io/channel-websock.c
··· 586 586 return TRUE; 587 587 } 588 588 589 - if (err) { 590 - error_propagate(&wioc->io_err, err); 591 - } 589 + error_propagate(&wioc->io_err, err); 592 590 593 591 trace_qio_channel_websock_handshake_reply(ioc); 594 592 qio_channel_add_watch(
+81 -37
monitor.c
··· 36 36 #include "net/slirp.h" 37 37 #include "chardev/char-fe.h" 38 38 #include "chardev/char-io.h" 39 + #include "chardev/char-mux.h" 39 40 #include "ui/qemu-spice.h" 40 41 #include "sysemu/numa.h" 41 42 #include "monitor/monitor.h" ··· 234 235 QEMUBH *qmp_respond_bh; 235 236 } mon_global; 236 237 238 + struct QMPRequest { 239 + /* Owner of the request */ 240 + Monitor *mon; 241 + /* "id" field of the request */ 242 + QObject *id; 243 + /* Request object to be handled */ 244 + QObject *req; 245 + /* 246 + * Whether we need to resume the monitor afterward. This flag is 247 + * used to emulate the old QMP server behavior that the current 248 + * command must be completed before execution of the next one. 249 + */ 250 + bool need_resume; 251 + }; 252 + typedef struct QMPRequest QMPRequest; 253 + 237 254 /* QMP checker flags */ 238 255 #define QMP_ACCEPT_UNKNOWNS 1 239 256 ··· 310 327 } 311 328 } 312 329 330 + static void qmp_request_free(QMPRequest *req) 331 + { 332 + qobject_decref(req->id); 333 + qobject_decref(req->req); 334 + g_free(req); 335 + } 336 + 337 + /* Must with the mon->qmp.qmp_queue_lock held */ 338 + static void monitor_qmp_cleanup_req_queue_locked(Monitor *mon) 339 + { 340 + while (!g_queue_is_empty(mon->qmp.qmp_requests)) { 341 + qmp_request_free(g_queue_pop_head(mon->qmp.qmp_requests)); 342 + } 343 + } 344 + 345 + /* Must with the mon->qmp.qmp_queue_lock held */ 346 + static void monitor_qmp_cleanup_resp_queue_locked(Monitor *mon) 347 + { 348 + while (!g_queue_is_empty(mon->qmp.qmp_responses)) { 349 + qobject_decref(g_queue_pop_head(mon->qmp.qmp_responses)); 350 + } 351 + } 352 + 353 + static void monitor_qmp_cleanup_queues(Monitor *mon) 354 + { 355 + qemu_mutex_lock(&mon->qmp.qmp_queue_lock); 356 + monitor_qmp_cleanup_req_queue_locked(mon); 357 + monitor_qmp_cleanup_resp_queue_locked(mon); 358 + qemu_mutex_unlock(&mon->qmp.qmp_queue_lock); 359 + } 360 + 361 + 313 362 static void monitor_flush_locked(Monitor *mon); 314 363 315 364 static gboolean monitor_unblocked(GIOChannel *chan, GIOCondition cond, ··· 701 750 QDECREF(mon->outbuf); 702 751 qemu_mutex_destroy(&mon->out_lock); 703 752 qemu_mutex_destroy(&mon->qmp.qmp_queue_lock); 753 + monitor_qmp_cleanup_req_queue_locked(mon); 754 + monitor_qmp_cleanup_resp_queue_locked(mon); 704 755 g_queue_free(mon->qmp.qmp_requests); 705 756 g_queue_free(mon->qmp.qmp_responses); 706 757 } ··· 1203 1254 1204 1255 cmd = qmp_find_command(mon->qmp.commands, command); 1205 1256 if (!cmd) { 1206 - error_set(errp, ERROR_CLASS_COMMAND_NOT_FOUND, 1207 - "The command %s has not been found", command); 1257 + if (mon->qmp.commands == &qmp_cap_negotiation_commands) { 1258 + error_set(errp, ERROR_CLASS_COMMAND_NOT_FOUND, 1259 + "Expecting capabilities negotiation " 1260 + "with 'qmp_capabilities'"); 1261 + } else { 1262 + error_set(errp, ERROR_CLASS_COMMAND_NOT_FOUND, 1263 + "The command %s has not been found", command); 1264 + } 1208 1265 return false; 1209 1266 } 1210 1267 ··· 4003 4060 qobject_decref(rsp); 4004 4061 } 4005 4062 4006 - struct QMPRequest { 4007 - /* Owner of the request */ 4008 - Monitor *mon; 4009 - /* "id" field of the request */ 4010 - QObject *id; 4011 - /* Request object to be handled */ 4012 - QObject *req; 4013 - /* 4014 - * Whether we need to resume the monitor afterward. This flag is 4015 - * used to emulate the old QMP server behavior that the current 4016 - * command must be completed before execution of the next one. 4017 - */ 4018 - bool need_resume; 4019 - }; 4020 - typedef struct QMPRequest QMPRequest; 4021 - 4022 4063 /* 4023 4064 * Dispatch one single QMP request. The function will free the req_obj 4024 4065 * and objects inside it before return. ··· 4027 4068 { 4028 4069 Monitor *mon, *old_mon; 4029 4070 QObject *req, *rsp = NULL, *id; 4030 - QDict *qdict = NULL; 4031 4071 bool need_resume; 4032 4072 4033 4073 req = req_obj->req; ··· 4049 4089 rsp = qmp_dispatch(mon->qmp.commands, req); 4050 4090 4051 4091 cur_mon = old_mon; 4052 - 4053 - if (mon->qmp.commands == &qmp_cap_negotiation_commands) { 4054 - qdict = qdict_get_qdict(qobject_to(QDict, rsp), "error"); 4055 - if (qdict 4056 - && !g_strcmp0(qdict_get_try_str(qdict, "class"), 4057 - QapiErrorClass_str(ERROR_CLASS_COMMAND_NOT_FOUND))) { 4058 - /* Provide a more useful error message */ 4059 - qdict_del(qdict, "desc"); 4060 - qdict_put_str(qdict, "desc", "Expecting capabilities negotiation" 4061 - " with 'qmp_capabilities'"); 4062 - } 4063 - } 4064 4092 4065 4093 /* Respond if necessary */ 4066 4094 monitor_qmp_respond(mon, rsp, NULL, id); ··· 4198 4226 qapi_event_send_command_dropped(id, 4199 4227 COMMAND_DROP_REASON_QUEUE_FULL, 4200 4228 &error_abort); 4201 - qobject_decref(id); 4202 - qobject_decref(req); 4203 - g_free(req_obj); 4229 + qmp_request_free(req_obj); 4204 4230 return; 4205 4231 } 4206 4232 } ··· 4315 4341 /* Monitors that are not using IOThread won't support OOB */ 4316 4342 continue; 4317 4343 } 4318 - qlist_append(cap_list, qstring_from_str(QMPCapability_str(cap))); 4344 + qlist_append_str(cap_list, QMPCapability_str(cap)); 4319 4345 } 4320 4346 4321 4347 return qobject_from_jsonf("{'QMP': {'version': %p, 'capabilities': %p}}", ··· 4342 4368 mon_refcount++; 4343 4369 break; 4344 4370 case CHR_EVENT_CLOSED: 4371 + monitor_qmp_cleanup_queues(mon); 4345 4372 json_message_parser_destroy(&mon->qmp.parser); 4346 4373 json_message_parser_init(&mon->qmp.parser, handle_qmp_command); 4347 4374 mon_refcount--; ··· 4536 4563 void monitor_init(Chardev *chr, int flags) 4537 4564 { 4538 4565 Monitor *mon = g_malloc(sizeof(*mon)); 4566 + bool use_readline = flags & MONITOR_USE_READLINE; 4567 + bool use_oob = flags & MONITOR_USE_OOB; 4539 4568 4540 - monitor_data_init(mon, false, false); 4569 + if (use_oob) { 4570 + if (CHARDEV_IS_MUX(chr)) { 4571 + error_report("Monitor Out-Of-Band is not supported with " 4572 + "MUX typed chardev backend"); 4573 + exit(1); 4574 + } 4575 + if (use_readline) { 4576 + error_report("Monitor Out-Of-band is only supported by QMP"); 4577 + exit(1); 4578 + } 4579 + } 4580 + 4581 + monitor_data_init(mon, false, use_oob); 4541 4582 4542 4583 qemu_chr_fe_init(&mon->chr, chr, &error_abort); 4543 4584 mon->flags = flags; 4544 - if (flags & MONITOR_USE_READLINE) { 4585 + if (use_readline) { 4545 4586 mon->rs = readline_init(monitor_readline_printf, 4546 4587 monitor_readline_flush, 4547 4588 mon, ··· 4636 4677 .type = QEMU_OPT_STRING, 4637 4678 },{ 4638 4679 .name = "pretty", 4680 + .type = QEMU_OPT_BOOL, 4681 + },{ 4682 + .name = "x-oob", 4639 4683 .type = QEMU_OPT_BOOL, 4640 4684 }, 4641 4685 { /* end of list */ }
+1 -1
scripts/qapi/common.py
··· 872 872 raise QAPISemError(info, 873 873 "'%s' of %s '%s' should only use false value" 874 874 % (key, meta, name)) 875 - if key == 'boxed' and value is not True: 875 + if (key == 'boxed' or key == 'allow-oob') and value is not True: 876 876 raise QAPISemError(info, 877 877 "'%s' of %s '%s' should only use true value" 878 878 % (key, meta, name))
+12 -12
target/i386/hvf/hvf.c
··· 86 86 87 87 switch (ret) { 88 88 case HV_ERROR: 89 - error_report("Error: HV_ERROR\n"); 89 + error_report("Error: HV_ERROR"); 90 90 break; 91 91 case HV_BUSY: 92 - error_report("Error: HV_BUSY\n"); 92 + error_report("Error: HV_BUSY"); 93 93 break; 94 94 case HV_BAD_ARGUMENT: 95 - error_report("Error: HV_BAD_ARGUMENT\n"); 95 + error_report("Error: HV_BAD_ARGUMENT"); 96 96 break; 97 97 case HV_NO_RESOURCES: 98 - error_report("Error: HV_NO_RESOURCES\n"); 98 + error_report("Error: HV_NO_RESOURCES"); 99 99 break; 100 100 case HV_NO_DEVICE: 101 - error_report("Error: HV_NO_DEVICE\n"); 101 + error_report("Error: HV_NO_DEVICE"); 102 102 break; 103 103 case HV_UNSUPPORTED: 104 - error_report("Error: HV_UNSUPPORTED\n"); 104 + error_report("Error: HV_UNSUPPORTED"); 105 105 break; 106 106 default: 107 - error_report("Unknown Error\n"); 107 + error_report("Unknown Error"); 108 108 } 109 109 110 110 abort(); ··· 191 191 if (mem) { 192 192 mem->size = 0; 193 193 if (do_hvf_set_memory(mem)) { 194 - error_report("Failed to reset overlapping slot\n"); 194 + error_report("Failed to reset overlapping slot"); 195 195 abort(); 196 196 } 197 197 } ··· 211 211 } 212 212 213 213 if (x == hvf_state->num_slots) { 214 - error_report("No free slots\n"); 214 + error_report("No free slots"); 215 215 abort(); 216 216 } 217 217 ··· 221 221 mem->region = area; 222 222 223 223 if (do_hvf_set_memory(mem)) { 224 - error_report("Error registering new memory slot\n"); 224 + error_report("Error registering new memory slot"); 225 225 abort(); 226 226 } 227 227 } ··· 884 884 break; 885 885 } 886 886 default: 887 - error_report("Unrecognized CR %d\n", cr); 887 + error_report("Unrecognized CR %d", cr); 888 888 abort(); 889 889 } 890 890 RIP(env) += ins_len; ··· 930 930 env->error_code = 0; 931 931 break; 932 932 default: 933 - error_report("%llx: unhandled exit %llx\n", rip, exit_reason); 933 + error_report("%llx: unhandled exit %llx", rip, exit_reason); 934 934 } 935 935 } while (ret == 0); 936 936
+1
tests/Makefile.include
··· 523 523 qapi-schema += missing-type.json 524 524 qapi-schema += nested-struct-data.json 525 525 qapi-schema += non-objects.json 526 + qapi-schema += oob-test.json 526 527 qapi-schema += pragma-doc-required-crap.json 527 528 qapi-schema += pragma-extra-junk.json 528 529 qapi-schema += pragma-name-case-whitelist-crap.json
+6 -4
tests/libqtest.c
··· 166 166 return qemu_bin; 167 167 } 168 168 169 - QTestState *qtest_init_without_qmp_handshake(const char *extra_args) 169 + QTestState *qtest_init_without_qmp_handshake(bool use_oob, 170 + const char *extra_args) 170 171 { 171 172 QTestState *s; 172 173 int sock, qmpsock, i; ··· 199 200 command = g_strdup_printf("exec %s " 200 201 "-qtest unix:%s,nowait " 201 202 "-qtest-log %s " 202 - "-qmp unix:%s,nowait " 203 + "-chardev socket,path=%s,nowait,id=char0 " 204 + "-mon chardev=char0,mode=control%s " 203 205 "-machine accel=qtest " 204 206 "-display none " 205 207 "%s", qemu_binary, socket_path, 206 208 getenv("QTEST_LOG") ? "/dev/fd/2" : "/dev/null", 207 - qmp_socket_path, 209 + qmp_socket_path, use_oob ? ",x-oob=on" : "", 208 210 extra_args ?: ""); 209 211 execlp("/bin/sh", "sh", "-c", command, NULL); 210 212 exit(1); ··· 239 241 240 242 QTestState *qtest_init(const char *extra_args) 241 243 { 242 - QTestState *s = qtest_init_without_qmp_handshake(extra_args); 244 + QTestState *s = qtest_init_without_qmp_handshake(false, extra_args); 243 245 244 246 /* Read the QMP greeting and then do the handshake */ 245 247 qtest_qmp_discard_response(s, "");
+5 -2
tests/libqtest.h
··· 56 56 57 57 /** 58 58 * qtest_init_without_qmp_handshake: 59 - * @extra_args: other arguments to pass to QEMU. 59 + * @use_oob: true to have the server advertise OOB support 60 + * @extra_args: other arguments to pass to QEMU. CAUTION: these 61 + * arguments are subject to word splitting and shell evaluation. 60 62 * 61 63 * Returns: #QTestState instance. 62 64 */ 63 - QTestState *qtest_init_without_qmp_handshake(const char *extra_args); 65 + QTestState *qtest_init_without_qmp_handshake(bool use_oob, 66 + const char *extra_args); 64 67 65 68 /** 66 69 * qtest_quit:
+2 -2
tests/qapi-schema/doc-good.out
··· 28 28 member arg2: str optional=True 29 29 member arg3: bool optional=False 30 30 command cmd q_obj_cmd-arg -> Object 31 - gen=True success_response=True boxed=False 31 + gen=True success_response=True boxed=False oob=False 32 32 command cmd-boxed Object -> None 33 - gen=True success_response=True boxed=True 33 + gen=True success_response=True boxed=True oob=False 34 34 doc freeform 35 35 body= 36 36 = Section
+1 -1
tests/qapi-schema/ident-with-escape.out
··· 5 5 object q_obj_fooA-arg 6 6 member bar1: str optional=False 7 7 command fooA q_obj_fooA-arg -> None 8 - gen=True success_response=True boxed=False 8 + gen=True success_response=True boxed=False oob=False
+2 -2
tests/qapi-schema/indented-expr.out
··· 3 3 prefix QTYPE 4 4 module indented-expr.json 5 5 command eins None -> None 6 - gen=True success_response=True boxed=False 6 + gen=True success_response=True boxed=False oob=False 7 7 command zwei None -> None 8 - gen=True success_response=True boxed=False 8 + gen=True success_response=True boxed=False oob=False
+1
tests/qapi-schema/oob-test.err
··· 1 + tests/qapi-schema/oob-test.json:2: 'allow-oob' of command 'oob-command-1' should only use true value
+1
tests/qapi-schema/oob-test.exit
··· 1 + 1
+2
tests/qapi-schema/oob-test.json
··· 1 + # Check against oob illegal value 2 + { 'command': 'oob-command-1', 'allow-oob': 'some-string' }
tests/qapi-schema/oob-test.out

This is a binary file and will not be displayed.

+3
tests/qapi-schema/qapi-schema-test.json
··· 139 139 { 'command': 'boxed-struct', 'boxed': true, 'data': 'UserDefZero' } 140 140 { 'command': 'boxed-union', 'data': 'UserDefNativeListUnion', 'boxed': true } 141 141 142 + # Smoke test on Out-Of-Band 143 + { 'command': 'an-oob-command', 'allow-oob': true } 144 + 142 145 # For testing integer range flattening in opts-visitor. The following schema 143 146 # corresponds to the option format: 144 147 #
+11 -9
tests/qapi-schema/qapi-schema-test.out
··· 16 16 object Empty2 17 17 base Empty1 18 18 command user_def_cmd0 Empty2 -> Empty2 19 - gen=True success_response=True boxed=False 19 + gen=True success_response=True boxed=False oob=False 20 20 enum QEnumTwo ['value1', 'value2'] 21 21 prefix QENUM_TWO 22 22 object UserDefOne ··· 143 143 case sizes: q_obj_sizeList-wrapper 144 144 case any: q_obj_anyList-wrapper 145 145 command user_def_cmd None -> None 146 - gen=True success_response=True boxed=False 146 + gen=True success_response=True boxed=False oob=False 147 147 object q_obj_user_def_cmd1-arg 148 148 member ud1a: UserDefOne optional=False 149 149 command user_def_cmd1 q_obj_user_def_cmd1-arg -> None 150 - gen=True success_response=True boxed=False 150 + gen=True success_response=True boxed=False oob=False 151 151 object q_obj_user_def_cmd2-arg 152 152 member ud1a: UserDefOne optional=False 153 153 member ud1b: UserDefOne optional=True 154 154 command user_def_cmd2 q_obj_user_def_cmd2-arg -> UserDefTwo 155 - gen=True success_response=True boxed=False 155 + gen=True success_response=True boxed=False oob=False 156 156 object q_obj_guest-get-time-arg 157 157 member a: int optional=False 158 158 member b: int optional=True 159 159 command guest-get-time q_obj_guest-get-time-arg -> int 160 - gen=True success_response=True boxed=False 160 + gen=True success_response=True boxed=False oob=False 161 161 object q_obj_guest-sync-arg 162 162 member arg: any optional=False 163 163 command guest-sync q_obj_guest-sync-arg -> any 164 - gen=True success_response=True boxed=False 164 + gen=True success_response=True boxed=False oob=False 165 165 command boxed-struct UserDefZero -> None 166 - gen=True success_response=True boxed=True 166 + gen=True success_response=True boxed=True oob=False 167 167 command boxed-union UserDefNativeListUnion -> None 168 - gen=True success_response=True boxed=True 168 + gen=True success_response=True boxed=True oob=False 169 + command an-oob-command None -> None 170 + gen=True success_response=True boxed=False oob=True 169 171 object UserDefOptions 170 172 member i64: intList optional=True 171 173 member u64: uint64List optional=True ··· 229 231 member c: __org.qemu_x-Union2 optional=False 230 232 member d: __org.qemu_x-Alt optional=False 231 233 command __org.qemu_x-command q_obj___org.qemu_x-command-arg -> __org.qemu_x-Union1 232 - gen=True success_response=True boxed=False 234 + gen=True success_response=True boxed=False oob=False
+2 -2
tests/qapi-schema/test-qapi.py
··· 45 45 gen, success_response, boxed, allow_oob): 46 46 print('command %s %s -> %s' % \ 47 47 (name, arg_type and arg_type.name, ret_type and ret_type.name)) 48 - print(' gen=%s success_response=%s boxed=%s' % \ 49 - (gen, success_response, boxed)) 48 + print(' gen=%s success_response=%s boxed=%s oob=%s' % \ 49 + (gen, success_response, boxed, allow_oob)) 50 50 51 51 def visit_event(self, name, info, arg_type, boxed): 52 52 print('event %s %s' % (name, arg_type and arg_type.name))
+84 -1
tests/qmp-test.c
··· 81 81 QList *capabilities; 82 82 QTestState *qts; 83 83 84 - qts = qtest_init_without_qmp_handshake(common_args); 84 + qts = qtest_init_without_qmp_handshake(false, common_args); 85 85 86 86 /* Test greeting */ 87 87 resp = qtest_qmp_receive(qts); ··· 90 90 test_version(qdict_get(q, "version")); 91 91 capabilities = qdict_get_qlist(q, "capabilities"); 92 92 g_assert(capabilities && qlist_empty(capabilities)); 93 + QDECREF(resp); 93 94 94 95 /* Test valid command before handshake */ 95 96 resp = qtest_qmp(qts, "{ 'execute': 'query-version' }"); ··· 130 131 g_assert_cmpstr(get_error_class(resp), ==, "GenericError"); 131 132 g_assert_cmpint(qdict_get_int(resp, "id"), ==, 2); 132 133 QDECREF(resp); 134 + 135 + qtest_quit(qts); 136 + } 137 + 138 + /* Tests for Out-Of-Band support. */ 139 + static void test_qmp_oob(void) 140 + { 141 + QTestState *qts; 142 + QDict *resp, *q; 143 + int acks = 0; 144 + const QListEntry *entry; 145 + QList *capabilities; 146 + QString *qstr; 147 + const char *cmd_id; 148 + 149 + qts = qtest_init_without_qmp_handshake(true, common_args); 150 + 151 + /* Check the greeting message. */ 152 + resp = qtest_qmp_receive(qts); 153 + q = qdict_get_qdict(resp, "QMP"); 154 + g_assert(q); 155 + capabilities = qdict_get_qlist(q, "capabilities"); 156 + g_assert(capabilities && !qlist_empty(capabilities)); 157 + entry = qlist_first(capabilities); 158 + g_assert(entry); 159 + qstr = qobject_to(QString, entry->value); 160 + g_assert(qstr); 161 + g_assert_cmpstr(qstring_get_str(qstr), ==, "oob"); 162 + QDECREF(resp); 163 + 164 + /* Try a fake capability, it should fail. */ 165 + resp = qtest_qmp(qts, 166 + "{ 'execute': 'qmp_capabilities', " 167 + " 'arguments': { 'enable': [ 'cap-does-not-exist' ] } }"); 168 + g_assert(qdict_haskey(resp, "error")); 169 + QDECREF(resp); 170 + 171 + /* Now, enable OOB in current QMP session, it should succeed. */ 172 + resp = qtest_qmp(qts, 173 + "{ 'execute': 'qmp_capabilities', " 174 + " 'arguments': { 'enable': [ 'oob' ] } }"); 175 + g_assert(qdict_haskey(resp, "return")); 176 + QDECREF(resp); 177 + 178 + /* 179 + * Try any command that does not support OOB but with OOB flag. We 180 + * should get failure. 181 + */ 182 + resp = qtest_qmp(qts, 183 + "{ 'execute': 'query-cpus'," 184 + " 'control': { 'run-oob': true } }"); 185 + g_assert(qdict_haskey(resp, "error")); 186 + QDECREF(resp); 187 + 188 + /* 189 + * First send the "x-oob-test" command with lock=true and 190 + * oob=false, it should hang the dispatcher and main thread; 191 + * later, we send another lock=false with oob=true to continue 192 + * that thread processing. Finally we should receive replies from 193 + * both commands. 194 + */ 195 + qtest_async_qmp(qts, 196 + "{ 'execute': 'x-oob-test'," 197 + " 'arguments': { 'lock': true }, " 198 + " 'id': 'lock-cmd'}"); 199 + qtest_async_qmp(qts, 200 + "{ 'execute': 'x-oob-test', " 201 + " 'arguments': { 'lock': false }, " 202 + " 'control': { 'run-oob': true }, " 203 + " 'id': 'unlock-cmd' }"); 204 + 205 + /* Ignore all events. Wait for 2 acks */ 206 + while (acks < 2) { 207 + resp = qtest_qmp_receive(qts); 208 + cmd_id = qdict_get_str(resp, "id"); 209 + if (!g_strcmp0(cmd_id, "lock-cmd") || 210 + !g_strcmp0(cmd_id, "unlock-cmd")) { 211 + acks++; 212 + } 213 + QDECREF(resp); 214 + } 133 215 134 216 qtest_quit(qts); 135 217 } ··· 318 400 g_test_init(&argc, &argv, NULL); 319 401 320 402 qtest_add_func("qmp/protocol", test_qmp_protocol); 403 + qtest_add_func("qmp/oob", test_qmp_oob); 321 404 qmp_schema_init(&schema); 322 405 add_query_tests(&schema); 323 406
+4
tests/test-qmp-cmds.c
··· 16 16 { 17 17 } 18 18 19 + void qmp_an_oob_command(Error **errp) 20 + { 21 + } 22 + 19 23 Empty2 *qmp_user_def_cmd0(Error **errp) 20 24 { 21 25 return g_new0(Empty2, 1);
+1 -1
tests/test-visitor-serialization.c
··· 1115 1115 1116 1116 static void add_visitor_type(const SerializeOps *ops) 1117 1117 { 1118 - char testname_prefix[128]; 1118 + char testname_prefix[32]; 1119 1119 char testname[128]; 1120 1120 TestArgs *args; 1121 1121 int i = 0;
+5
vl.c
··· 2404 2404 if (qemu_opt_get_bool(opts, "pretty", 0)) 2405 2405 flags |= MONITOR_USE_PRETTY; 2406 2406 2407 + /* OOB is off by default */ 2408 + if (qemu_opt_get_bool(opts, "x-oob", 0)) { 2409 + flags |= MONITOR_USE_OOB; 2410 + } 2411 + 2407 2412 chardev = qemu_opt_get(opts, "chardev"); 2408 2413 chr = qemu_chr_find(chardev); 2409 2414 if (chr == NULL) {