Skip to contentSkip to conversation

monitor: enable OOB by default

PATCH Superseded Peter Xu 2 participants 10 messages Sep 5, 2018 – Oct 9, 2018 2 messages not in the archive

v8 of 9 Superseded Latest is v9 →

lore
Share & tools
lore

Peter Xu

author
#0 lore raw

v8 cover monitor: enable OOB by default

Based-on: <[email protected]>
Based-on: <[email protected]>

(this series is based on Markus's monitor-next tree)

v8:
- remove patch 1 & 2 since already in the QAPI pull
- squash patch 3 & 4, use Markus's version of commit message (with some of my additions), make sure popping and reading queue length is in the same critical section [Markus]
- add one patch to cover test for queue full [Markus]
- add one patch to resume the monitor earlier when queue not full [Markus]

v7:
- use Markus's commit message for patch "qapi: Drop qapi_event_send_FOO()'s Error ** argument" [Markus]
- update commit message for "qapi: remove COMMAND_DROPPED event" since QEMU 3.0 is released [Eric/Dave]
- rebase to Markus's monitor-next tree:
http://repo.or.cz/qemu/armbru.git/shortlog/refs/heads/monitor-next
the patch "monitor: suspend monitor instead of send CMD_DROP" re-written since people prefer to drop need_resume flag so now I hand-made it. Dropped a few patches since not appliable any more.

Please review. Thanks,

Peter Xu (6):
monitor: Suspend monitor instead dropping commands
monitor: resume the monitor earlier if needed
monitor: remove "x-oob", turn oob on by default
Revert "tests: Add parameter to qtest_init_without_qmp_handshake"
tests: add oob functional test for test-qmp-cmds
tests: qmp-test: add queue full test

 docs/interop/qmp-spec.txt |  5 ++-
 include/monitor/monitor.h |  3 +-
 monitor.c                 | 80 +++++++++++++++------------------------
 qapi/misc.json            | 40 --------------------
 tests/libqtest.c          | 10 ++---
 tests/libqtest.h          |  4 +-
 tests/qmp-test.c          | 32 ++++++++++++++--
 tests/test-qmp-cmds.c     | 16 ++++++++
 vl.c                      |  5 ---
 9 files changed, 86 insertions(+), 109 deletions(-)
Signature · 1 line
2.17.1
author
#1 lore raw

PATCH v8 1/6 monitor: Suspend monitor instead dropping commands

When a QMP client sends in-band commands more quickly that we can process them, we can either queue them without limit (QUEUE), drop commands when the queue is full (DROP), or suspend receiving commands when the queue is full (SUSPEND). None of them is ideal:

* QUEUE lets a misbehaving client make QEMU eat memory without bounds. Not such a hot idea.

* With DROP, the client has to cope with dropped in-band commands. To inform the client, we send a COMMAND_DROPPED event then. The event is flawed by design in two ways: it's ambiguous (see commit d621cfe0a17), and it brings back the "eat memory without bounds" problem.

* With SUSPEND, the client has to manage the flow of in-band commands to keep the monitor available for out-of-band commands.

We currently DROP. Switch to SUSPEND.

Managing the flow of in-band commands to keep the monitor available for out-of-band commands isn't really hard: just count the number of "outstanding" in-band commands (commands sent minus replies received), and if it exceeds the limit, hold back additional ones until it drops below the limit again.

Note that we need to be careful pairing the suspend with a resume, or else the monitor will hang, possibly forever. And here since we need to make sure both:

(1) popping request from the req queue, and
(2) reading length of the req queue

will be in the same critical section, we let the pop function take the corresponding queue lock when there is a request, then we release the lock from the caller.

---
 docs/interop/qmp-spec.txt |  5 ++--
 include/monitor/monitor.h |  2 ++
 monitor.c                 | 52 +++++++++++++++++----------------------
 qapi/misc.json            | 40 ------------------------------
 4 files changed, 28 insertions(+), 71 deletions(-)
docs/interop/qmp-spec.txt +3 -2
index 8f7da0245d..67e44a8120 100644
@@ -130,8 +130,9 @@ to pass "id" with out-of-band commands.  Passing it with all commands
 is recommended for clients that accept capability "oob".
 
 If the client sends in-band commands faster than the server can
-execute them, the server will eventually drop commands to limit the
-queue length.  The sever sends event COMMAND_DROPPED then.
+execute them, the server will stop reading the requests from the QMP
+channel until the request queue length is reduced to an acceptable
+range.
 
 Only a few commands support out-of-band execution.  The ones that do
 have "allow-oob": true in output of query-qmp-schema.
include/monitor/monitor.h +2 -0
index 2ef5e04b37..76873c0d40 100644
@@ -15,6 +15,8 @@ extern __thread Monitor *cur_mon;
 #define MONITOR_USE_PRETTY    0x08
 #define MONITOR_USE_OOB       0x10
 
+#define QMP_REQ_QUEUE_LEN_MAX 8
+
 bool monitor_cur_is_qmp(void);
 
 void monitor_init_globals(void);
monitor.c +23 -29

113 lines not on this page · raw message

qapi/misc.json +0 -40
index d450cfef21..2c1a6119bf 100644
@@ -3432,46 +3432,6 @@
 ##
 { 'command': 'query-sev-capabilities', 'returns': 'SevCapability' }
 
-##
-# @CommandDropReason:
-#
-# Reasons that caused one command to be dropped.
-#
-# @queue-full: the command queue is full. This can only occur when
-#              the client sends a new non-oob command before the
-#              response to the previous non-oob command has been
-#              received.
-#
-# Since: 2.12
-##
-{ 'enum': 'CommandDropReason',
-  'data': [ 'queue-full' ] }
-
-##
-# @COMMAND_DROPPED:
-#
-# Emitted when a command is dropped due to some reason.  Commands can
-# only be dropped when the oob capability is enabled.
-#
-# @id: The dropped command's "id" field.
-# FIXME Broken by design.  Events are broadcast to all monitors.  If
-# another monitor's client has a command with the same ID in flight,
-# the event will incorrectly claim that command was dropped.
-#
-# @reason: The reason why the command is dropped.
-#
-# Since: 2.12
-#
-# Example:
-#
-# { "event": "COMMAND_DROPPED",
-#   "data": {"result": {"id": "libvirt-102",
-#                       "reason": "queue-full" } } }
-#
-##
-{ 'event': 'COMMAND_DROPPED' ,
-  'data': { 'id': 'any', 'reason': 'CommandDropReason' } }
-
 ##
 # @set-numa-node:
 #
Signature · 1 line
2.17.1
author
#2 lore raw

PATCH v8 2/6 monitor: resume the monitor earlier if needed

In reply to Peter Xu

Currently when QMP request queue full we won't resume the monitor until we have completely handled the current command. It's not necessary since even before it's handled the queue is already non-full. Moving the resume logic earlier before the command execution, hence drop the need_resume local variable.

---
 monitor.c | 12 +++++-------
 1 file changed, 5 insertions(+), 7 deletions(-)
monitor.c +5 -7
index a89bb86599..c2c9853f75 100644
@@ -4130,7 +4130,6 @@ static void monitor_qmp_bh_dispatcher(void *data)
 {
     QMPRequest *req_obj = monitor_qmp_requests_pop_any_with_lock();
     QDict *rsp;
-    bool need_resume;
     Monitor *mon;
 
     if (!req_obj) {
@@ -4139,8 +4138,11 @@ static void monitor_qmp_bh_dispatcher(void *data)
 
     mon = req_obj->mon;
     /*  qmp_oob_enabled() might change after "qmp_capabilities" */
-    need_resume = !qmp_oob_enabled(mon) ||
-        mon->qmp.qmp_requests->length == QMP_REQ_QUEUE_LEN_MAX - 1;
+    if (!qmp_oob_enabled(mon) ||
+        mon->qmp.qmp_requests->length == QMP_REQ_QUEUE_LEN_MAX - 1) {
+        /* Pairs with the monitor_suspend() in handle_qmp_command() */
+        monitor_resume(mon);
+    }
     qemu_mutex_unlock(&mon->qmp.qmp_queue_lock);
     if (req_obj->req) {
         trace_monitor_qmp_cmd_in_band(qobject_get_try_str(req_obj->id) ?: "");
@@ -4153,10 +4155,6 @@ static void monitor_qmp_bh_dispatcher(void *data)
         qobject_unref(rsp);
     }
 
-    if (need_resume) {
-        /* Pairs with the monitor_suspend() in handle_qmp_command() */
-        monitor_resume(mon);
-    }
     qmp_request_free(req_obj);
 
     /* Reschedule instead of looping so the main loop stays responsive */
Signature · 1 line
2.17.1

A message that is not in the archive (sent off-list or not yet received): CAJ+F1CJJB2ZyTQ3OBJ+c49bqZMWSKqfp7UOoM7QBEhH6Exnsbg@mail.gmail.com

A message that is not in the archive (sent off-list or not yet received): 20180929040529.GQ9560@xz-x1

#5 lore raw

Re: [Qemu-devel] [PATCH v8 2/6] monitor: resume the monitor earlier if needed

Hi Peter

Quoted 49 lines · Peter Xu
Quoted 43 lines · Marc-André Lureau

Hi

Quoted 25 lines · Peter Xu

Currently when QMP request queue full we won't resume the monitor until we have completely handled the current command. It's not necessary since even before it's handled the queue is already non-full. Moving the resume logic earlier before the command execution, hence drop the need_resume local variable.

---
 monitor.c | 12 +++++-------
 1 file changed, 5 insertions(+), 7 deletions(-)
monitor.c +0 -1
index a89bb86599..c2c9853f75 100644
@@ -4130,7 +4130,6 @@ static void monitor_qmp_bh_dispatcher(void *data)
 {
     QMPRequest *req_obj = monitor_qmp_requests_pop_any_with_lock();
     QDict *rsp;
-    bool need_resume;
     Monitor *mon;
 
     if (!req_obj) {

monitor.c static void monitor_qmp_bh_dispatcher(void *data) · line 4145

Quoted 10 lines
monitor.c +5 -2
@@ -4139,8 +4138,11 @@ static void monitor_qmp_bh_dispatcher(void *data)
 
     mon = req_obj->mon;
     /*  qmp_oob_enabled() might change after "qmp_capabilities" */
-    need_resume = !qmp_oob_enabled(mon) ||
-        mon->qmp.qmp_requests->length == QMP_REQ_QUEUE_LEN_MAX - 1;
+    if (!qmp_oob_enabled(mon) ||
+        mon->qmp.qmp_requests->length == QMP_REQ_QUEUE_LEN_MAX - 1) {
+        /* Pairs with the monitor_suspend() in handle_qmp_command() */
+        monitor_resume(mon);
+    }

With spice chardev, this may result in a synchronous write. If I read it right, this may re-enter handle_qmp_command and dead-lock on qemu_mutex_lock(&mon->qmp.qmp_queue_lock);

Quoted 1 line

So at least I would release the lock before resuming :)

For sure this I can do. :) Though I'd like to know more context too.

Quoted 8 lines

I just noticed that we added the qemu_chr_fe_accept_input() call into monitor_resume() a month ago which I completely unaware of... then the resuming could be a heavy-weighted function now. I'm a bit worried on whether this would affect the oob thing since noting that we're still in the monitor iothread (which should not block for long). Especially if you mentioned that we'll handle commands again, then could we potentially run non-oob command handlers in oob context here simply due to the call to monitor_resume()?

monitor_resume() is only called from main thread, afaict.

So I think the problem is rather that qemu_chr_fe_accept_input() is not thread safe (if the same charfe is used in a different thread, like mon_iothread).

So instead of simply kicking the mon_iothread, we should probably schedule a BH to call accept input.

Quoted 5 lines

I'm thinking whether we should use a QEMU bottom half or things alike to handle the qemu_chr_fe_accept_input(), and keep the resume and the stack simple. As we seem to be facing more dead locks recently, I'm thinking simplifying the stack might be a nice thing to have.

Sure, if that can help :)

Signature · 1 line
Marc-André Lureau
author
#6 lore raw

Re: [Qemu-devel] [PATCH v8 2/6] monitor: resume the monitor earlier if needed

Quoted 61 lines · Marc-André Lureau

Hi Peter

Quoted 49 lines · Peter Xu
Quoted 43 lines · Marc-André Lureau

Hi

Quoted 25 lines · Peter Xu

Currently when QMP request queue full we won't resume the monitor until we have completely handled the current command. It's not necessary since even before it's handled the queue is already non-full. Moving the resume logic earlier before the command execution, hence drop the need_resume local variable.

---
 monitor.c | 12 +++++-------
 1 file changed, 5 insertions(+), 7 deletions(-)
monitor.c +0 -1
index a89bb86599..c2c9853f75 100644
@@ -4130,7 +4130,6 @@ static void monitor_qmp_bh_dispatcher(void *data)
 {
     QMPRequest *req_obj = monitor_qmp_requests_pop_any_with_lock();
     QDict *rsp;
-    bool need_resume;
     Monitor *mon;
 
     if (!req_obj) {

monitor.c static void monitor_qmp_bh_dispatcher(void *data) · line 4145

Quoted 10 lines
monitor.c +5 -2
@@ -4139,8 +4138,11 @@ static void monitor_qmp_bh_dispatcher(void *data)
 
     mon = req_obj->mon;
     /*  qmp_oob_enabled() might change after "qmp_capabilities" */
-    need_resume = !qmp_oob_enabled(mon) ||
-        mon->qmp.qmp_requests->length == QMP_REQ_QUEUE_LEN_MAX - 1;
+    if (!qmp_oob_enabled(mon) ||
+        mon->qmp.qmp_requests->length == QMP_REQ_QUEUE_LEN_MAX - 1) {
+        /* Pairs with the monitor_suspend() in handle_qmp_command() */
+        monitor_resume(mon);
+    }

With spice chardev, this may result in a synchronous write. If I read it right, this may re-enter handle_qmp_command and dead-lock on qemu_mutex_lock(&mon->qmp.qmp_queue_lock);

Quoted 1 line

So at least I would release the lock before resuming :)

For sure this I can do. :) Though I'd like to know more context too.

Quoted 8 lines

I just noticed that we added the qemu_chr_fe_accept_input() call into monitor_resume() a month ago which I completely unaware of... then the resuming could be a heavy-weighted function now. I'm a bit worried on whether this would affect the oob thing since noting that we're still in the monitor iothread (which should not block for long). Especially if you mentioned that we'll handle commands again, then could we potentially run non-oob command handlers in oob context here simply due to the call to monitor_resume()?

Quoted 1 line

monitor_resume() is only called from main thread, afaict.

My fault on misreading on that; yes it's only called in main thread.

Quoted 7 lines

So I think the problem is rather that qemu_chr_fe_accept_input() is not thread safe (if the same charfe is used in a different thread, like mon_iothread).

So instead of simply kicking the mon_iothread, we should probably schedule a BH to call accept input.

Hmm, could you help explain why we need to make qemu_chr_fe_accept_input() thread safe? I see that's only called in main thread as well (besides the call in monitor_resume, it's mostly in memory region ops), or did I misread again?

Regards,

Signature · 1 line
Peter Xu
#7 lore raw

Re: [Qemu-devel] [PATCH v8 2/6] monitor: resume the monitor earlier if needed

Hi

Quoted 72 lines · Peter Xu
Quoted 61 lines · Marc-André Lureau

Hi Peter

Quoted 49 lines · Peter Xu
Quoted 43 lines · Marc-André Lureau

Hi

Quoted 25 lines · Peter Xu

Currently when QMP request queue full we won't resume the monitor until we have completely handled the current command. It's not necessary since even before it's handled the queue is already non-full. Moving the resume logic earlier before the command execution, hence drop the need_resume local variable.

---
 monitor.c | 12 +++++-------
 1 file changed, 5 insertions(+), 7 deletions(-)
monitor.c +0 -1
index a89bb86599..c2c9853f75 100644
@@ -4130,7 +4130,6 @@ static void monitor_qmp_bh_dispatcher(void *data)
 {
     QMPRequest *req_obj = monitor_qmp_requests_pop_any_with_lock();
     QDict *rsp;
-    bool need_resume;
     Monitor *mon;
 
     if (!req_obj) {

monitor.c static void monitor_qmp_bh_dispatcher(void *data) · line 4145

Quoted 10 lines
monitor.c +5 -2
@@ -4139,8 +4138,11 @@ static void monitor_qmp_bh_dispatcher(void *data)
 
     mon = req_obj->mon;
     /*  qmp_oob_enabled() might change after "qmp_capabilities" */
-    need_resume = !qmp_oob_enabled(mon) ||
-        mon->qmp.qmp_requests->length == QMP_REQ_QUEUE_LEN_MAX - 1;
+    if (!qmp_oob_enabled(mon) ||
+        mon->qmp.qmp_requests->length == QMP_REQ_QUEUE_LEN_MAX - 1) {
+        /* Pairs with the monitor_suspend() in handle_qmp_command() */
+        monitor_resume(mon);
+    }

With spice chardev, this may result in a synchronous write. If I read it right, this may re-enter handle_qmp_command and dead-lock on qemu_mutex_lock(&mon->qmp.qmp_queue_lock);

Quoted 1 line

So at least I would release the lock before resuming :)

For sure this I can do. :) Though I'd like to know more context too.

Quoted 8 lines

I just noticed that we added the qemu_chr_fe_accept_input() call into monitor_resume() a month ago which I completely unaware of... then the resuming could be a heavy-weighted function now. I'm a bit worried on whether this would affect the oob thing since noting that we're still in the monitor iothread (which should not block for long). Especially if you mentioned that we'll handle commands again, then could we potentially run non-oob command handlers in oob context here simply due to the call to monitor_resume()?

Quoted 1 line

monitor_resume() is only called from main thread, afaict.

My fault on misreading on that; yes it's only called in main thread.

Quoted 5 lines

So I think the problem is rather that qemu_chr_fe_accept_input() is not thread safe (if the same charfe is used in a different thread, like mon_iothread).

Quoted 7 lines
Quoted 2 lines

So instead of simply kicking the mon_iothread, we should probably schedule a BH to call accept input.

Hmm, could you help explain why we need to make qemu_chr_fe_accept_input() thread safe? I see that's only called in main thread as well (besides the call in monitor_resume, it's mostly in memory region ops), or did I misread again?

Yes, it's called from main thread. And that's not very safe for chardev to be called from different threads. Let's try to keep the chardev-related calls in the in mon_iothread (if it is used). I'll send a patch along with some other cleanups.

Quoted 5 lines

Regards,

--
Peter Xu

Signature · 1 line
Marc-André Lureau
author
#8 lore raw

PATCH v8 3/6 monitor: remove "x-oob", turn oob on by default

In reply to Peter Xu

OOB commands were introduced in commit cf869d53172. Unfortunately, we ran into a regression, and had to disable them by default for 2.12 (commit be933ffc23).

http://lists.gnu.org/archive/html/qemu-devel/2018-03/msg06231.html

The regression has since been fixed (commit 951702f39c7 "monitor: bind dispatch bh to iohandler context"). Time to re-enable OOB.

This patch partly reverts be933ffc23 (monitor: new parameter "x-oob"), and turns it on again for non-MUX QMPs. Note that we can't enable Out-Of-Band for monitors with MUX-typed chardev backends, because not all the chardev frontends can run without main thread, or can run in multiple threads.

Some trivial touch-up in the test code is required to make sure qmp-test won't break.

---
 include/monitor/monitor.h |  1 -
 monitor.c                 | 22 ++++++----------------
 tests/libqtest.c          |  2 +-
 tests/qmp-test.c          |  2 +-
 vl.c                      |  5 -----
 5 files changed, 8 insertions(+), 24 deletions(-)
include/monitor/monitor.h +0 -1
index 76873c0d40..281480a1e5 100644
@@ -13,7 +13,6 @@ extern __thread Monitor *cur_mon;
 #define MONITOR_USE_READLINE  0x02
 #define MONITOR_USE_CONTROL   0x04
 #define MONITOR_USE_PRETTY    0x08
-#define MONITOR_USE_OOB       0x10
 
 #define QMP_REQ_QUEUE_LEN_MAX 8
 
monitor.c +6 -16
index c2c9853f75..a465b69c62 100644
@@ -4524,19 +4524,12 @@ void monitor_init(Chardev *chr, int flags)
 {
     Monitor *mon = g_malloc(sizeof(*mon));
     bool use_readline = flags & MONITOR_USE_READLINE;
-    bool use_oob = flags & MONITOR_USE_OOB;
-
-    if (use_oob) {
-        if (CHARDEV_IS_MUX(chr)) {
-            error_report("Monitor out-of-band is not supported with "
-                         "MUX typed chardev backend");
-            exit(1);
-        }
-        if (use_readline) {
-            error_report("Monitor out-of-band is only supported by QMP");
-            exit(1);
-        }
-    }
+    /*
+     * Note: we can't enable Out-Of-Band for monitors with MUX-typed
+     * chardev backends, because not all the chardev frontends can run
+     * without main thread, or can run in multiple threads.
+     */
+    bool use_oob = (flags & MONITOR_USE_CONTROL) && !CHARDEV_IS_MUX(chr);
 
     monitor_data_init(mon, false, use_oob);
 
@@ -4626,9 +4619,6 @@ QemuOptsList qemu_mon_opts = {
         },{
             .name = "pretty",
             .type = QEMU_OPT_BOOL,
-        },{
-            .name = "x-oob",
-            .type = QEMU_OPT_BOOL,
         },
         { /* end of list */ }
     },
tests/libqtest.c +1 -1
index d635c5bea0..ebd92f22f6 100644
@@ -231,7 +231,7 @@ QTestState *qtest_init_without_qmp_handshake(bool use_oob,
                                   "-display none "
                                   "%s", qemu_binary, socket_path,
                                   getenv("QTEST_LOG") ? "/dev/fd/2" : "/dev/null",
-                                  qmp_socket_path, use_oob ? ",x-oob=on" : "",
+                                  qmp_socket_path, "",
                                   extra_args ?: "");
         execlp("/bin/sh", "sh", "-c", command, NULL);
         exit(1);
tests/qmp-test.c +1 -1
index 4ae2245484..5302bd07b9 100644
@@ -143,7 +143,7 @@ static void test_qmp_protocol(void)
     g_assert(q);
     test_version(qdict_get(q, "version"));
     capabilities = qdict_get_qlist(q, "capabilities");
-    g_assert(capabilities && qlist_empty(capabilities));
+    g_assert(capabilities);
     qobject_unref(resp);
 
     /* Test valid command before handshake */
vl.c +0 -5
index 10dd690e30..0206f0c512 100644
@@ -2323,11 +2323,6 @@ static int mon_init_func(void *opaque, QemuOpts *opts, Error **errp)
     if (qemu_opt_get_bool(opts, "pretty", 0))
         flags |= MONITOR_USE_PRETTY;
 
-    /* OOB is off by default */
-    if (qemu_opt_get_bool(opts, "x-oob", 0)) {
-        flags |= MONITOR_USE_OOB;
-    }
-
     chardev = qemu_opt_get(opts, "chardev");
     chr = qemu_chr_find(chardev);
     if (chr == NULL) {
Signature · 1 line
2.17.1
author
#9 lore raw

PATCH v8 4/6 Revert "tests: Add parameter to qtest_init_without_qmp_handshake"

In reply to Peter Xu

This reverts commit ddee57e0176f6ab53b13c6c97605b62737a8fd7a.

Meanwhile, revert one line from fa198ad9bdef to make sure qtest_init_without_qmp_handshake() will only pass in one parameter.

---
 tests/libqtest.c | 10 ++++------
 tests/libqtest.h |  4 +---
 tests/qmp-test.c |  4 ++--
 3 files changed, 7 insertions(+), 11 deletions(-)
tests/libqtest.c +4 -6
index ebd92f22f6..3c594abbc2 100644
@@ -191,8 +191,7 @@ static const char *qtest_qemu_binary(void)
     return qemu_bin;
 }
 
-QTestState *qtest_init_without_qmp_handshake(bool use_oob,
-                                             const char *extra_args)
+QTestState *qtest_init_without_qmp_handshake(const char *extra_args)
 {
     QTestState *s;
     int sock, qmpsock, i;
@@ -225,13 +224,12 @@ QTestState *qtest_init_without_qmp_handshake(bool use_oob,
         command = g_strdup_printf("exec %s "
                                   "-qtest unix:%s,nowait "
                                   "-qtest-log %s "
-                                  "-chardev socket,path=%s,nowait,id=char0 "
-                                  "-mon chardev=char0,mode=control%s "
+                                  "-qmp unix:%s,nowait "
                                   "-machine accel=qtest "
                                   "-display none "
                                   "%s", qemu_binary, socket_path,
                                   getenv("QTEST_LOG") ? "/dev/fd/2" : "/dev/null",
-                                  qmp_socket_path, "",
+                                  qmp_socket_path,
                                   extra_args ?: "");
         execlp("/bin/sh", "sh", "-c", command, NULL);
         exit(1);
@@ -266,7 +264,7 @@ QTestState *qtest_init_without_qmp_handshake(bool use_oob,
 
 QTestState *qtest_init(const char *extra_args)
 {
-    QTestState *s = qtest_init_without_qmp_handshake(false, extra_args);
+    QTestState *s = qtest_init_without_qmp_handshake(extra_args);
     QDict *greeting;
 
     /* Read the QMP greeting and then do the handshake */
tests/libqtest.h +1 -3
index 36d5caecd4..49ffc1ba9f 100644
@@ -55,14 +55,12 @@ QTestState *qtest_init(const char *extra_args);
 
 /**
  * qtest_init_without_qmp_handshake:
- * @use_oob: true to have the server advertise OOB support
  * @extra_args: other arguments to pass to QEMU.  CAUTION: these
  * arguments are subject to word splitting and shell evaluation.
  *
  * Returns: #QTestState instance.
  */
-QTestState *qtest_init_without_qmp_handshake(bool use_oob,
-                                             const char *extra_args);
+QTestState *qtest_init_without_qmp_handshake(const char *extra_args);
 
 /**
  * qtest_quit:
tests/qmp-test.c +2 -2
index 5302bd07b9..91a90d1c9d 100644
@@ -135,7 +135,7 @@ static void test_qmp_protocol(void)
     QList *capabilities;
     QTestState *qts;
 
-    qts = qtest_init_without_qmp_handshake(false, common_args);
+    qts = qtest_init_without_qmp_handshake(common_args);
 
     /* Test greeting */
     resp = qtest_qmp_receive(qts);
@@ -249,7 +249,7 @@ static void test_qmp_oob(void)
     QList *capabilities;
     QString *qstr;
 
-    qts = qtest_init_without_qmp_handshake(true, common_args);
+    qts = qtest_init_without_qmp_handshake(common_args);
 
     /* Check the greeting message. */
     resp = qtest_qmp_receive(qts);
Signature · 1 line
2.17.1
author
#10 lore raw

PATCH v8 5/6 tests: add oob functional test for test-qmp-cmds

In reply to Peter Xu

Straightforward test just to let the test-qmp-cmds be complete.

---
 tests/test-qmp-cmds.c | 16 ++++++++++++++++
 1 file changed, 16 insertions(+)
tests/test-qmp-cmds.c +16 -0
index ab414fa0c9..23c68c7944 100644
@@ -122,6 +122,21 @@ static void test_dispatch_cmd(void)
     qobject_unref(req);
 }
 
+static void test_dispatch_cmd_oob(void)
+{
+    QDict *req = qdict_new();
+    QDict *resp;
+
+    qdict_put_str(req, "exec-oob", "test-flags-command");
+
+    resp = qmp_dispatch(&qmp_commands, QOBJECT(req), true);
+    assert(resp != NULL);
+    assert(!qdict_haskey(resp, "error"));
+
+    qobject_unref(resp);
+    qobject_unref(req);
+}
+
 /* test commands that return an error due to invalid parameters */
 static void test_dispatch_cmd_failure(void)
 {
@@ -287,6 +302,7 @@ int main(int argc, char **argv)
     g_test_init(&argc, &argv, NULL);
 
     g_test_add_func("/qmp/dispatch_cmd", test_dispatch_cmd);
+    g_test_add_func("/qmp/dispatch_cmd_oob", test_dispatch_cmd_oob);
     g_test_add_func("/qmp/dispatch_cmd_failure", test_dispatch_cmd_failure);
     g_test_add_func("/qmp/dispatch_cmd_io", test_dispatch_cmd_io);
     g_test_add_func("/qmp/dealloc_types", test_dealloc_types);
Signature · 1 line
2.17.1
author
#11 lore raw

PATCH v8 6/6 tests: qmp-test: add queue full test

In reply to Peter Xu

We'll need to include "monitor/monitor.h" for the queue length macro, then we don't need to hard code it.

---
 tests/qmp-test.c | 26 ++++++++++++++++++++++++++
 1 file changed, 26 insertions(+)
tests/qmp-test.c +26 -0
index 91a90d1c9d..9e523a1806 100644
@@ -18,6 +18,7 @@
 #include "qapi/qmp/qlist.h"
 #include "qapi/qobject-input-visitor.h"
 #include "qapi/qmp/qstring.h"
+#include "monitor/monitor.h"
 
 const char common_args[] = "-nodefaults -machine none";
 
@@ -248,6 +249,8 @@ static void test_qmp_oob(void)
     const QListEntry *entry;
     QList *capabilities;
     QString *qstr;
+    gchar *id;
+    int i;
 
     qts = qtest_init_without_qmp_handshake(common_args);
 
@@ -302,6 +305,29 @@ static void test_qmp_oob(void)
     unblock_blocked_cmd();
     recv_cmd_id(qts, "blocks-2");
     recv_cmd_id(qts, "err-2");
+
+    /*
+     * Test queue full.  When that happens, the out-of-band command
+     * will only be able to be handled after the queue is shrinked, so
+     * it'll be processed only after one existing in-band command
+     * finishes.
+     */
+    for (i = 1; i <= QMP_REQ_QUEUE_LEN_MAX; i++) {
+        id = g_strdup_printf("queue-blocks-%d", i);
+        send_cmd_that_blocks(qts, id);
+        g_free(id);
+    }
+    send_oob_cmd_that_fails(qts, "oob-1");
+    unblock_blocked_cmd();
+    recv_cmd_id(qts, "queue-blocks-1");
+    recv_cmd_id(qts, "oob-1");
+    for (i = 2; i <= QMP_REQ_QUEUE_LEN_MAX; i++) {
+        unblock_blocked_cmd();
+        id = g_strdup_printf("queue-blocks-%d", i);
+        recv_cmd_id(qts, id);
+        g_free(id);
+    }
+
     cleanup_blocking_cmd();
 
     qtest_quit(qts);
Signature · 1 line
2.17.1