Skip to contentSkip to conversation

monitor: enable OOB by default

PATCH Applied Peter Xu 4 participants 18 messages Oct 9, 2018 – Oct 31, 2018

lore
Share & tools
lore

Peter Xu

author
#0 lore raw

v9 cover monitor: enable OOB by default

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

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

v9:
- add r-bs
- release the qmp queue lock before resume [Marc-Andre]

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                 | 82 ++++++++++++++++-----------------------
 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, 89 insertions(+), 108 deletions(-)
Signature · 1 line
2.17.1
author
#1 lore raw

PATCH v9 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 6fd2c53b09..0c0a37d8cb 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 ada9af5add..f149651a98 100644
@@ -3437,46 +3437,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
#2 lore raw

Re: [Qemu-devel] [PATCH v9 1/6] monitor: Suspend monitor instead dropping commands

Quoted 50 lines · Peter Xu

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 +0 -0
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".

docs/interop/qmp-spec.txt to pass "id" with out-of-band commands. Passing it with all commands · line 138

Quoted 10 lines
docs/interop/qmp-spec.txt +3 -2
 
 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.

Clients need to know the queue length limit to manage the flow. We better document it. Can be done on top.

Quoted 18 lines
include/monitor/monitor.h +2 -0
index 6fd2c53b09..0c0a37d8cb 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 +0 -0
index b9258a7438..1f83775fff 100644

monitor.c static void monitor_qmp_dispatch(Monitor *mon, QObject *req, QObject *id) · line 4103

Quoted 7 lines
monitor.c +4 -0
@@ -4097,8 +4097,12 @@ static void monitor_qmp_dispatch(Monitor *mon, QObject *req, QObject *id)
  * processing commands only on a very busy monitor.  To achieve that,
  * when we process one request on a specific monitor, we put that
  * monitor to the end of mon_list queue.
+ *
+ * Note: if the function returned with non-NULL, then the caller will
+ * be with mon->qmp.qmp_queue_lock held, and the caller is responsible
+ * to release it.

The English could use some polish. We can do that on top as well.

[...]

author
#3 lore raw

PATCH v9 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.

Note that now monitor_resume() is heavy weighted after 8af6bb14a3a8 and it's even possible (as pointed out by Marc-André) that the function itself may try to take the monitor lock again, so let's do the resume after the monitor lock is released to avoid possible dead lock.

---
 monitor.c | 10 ++++++----
 1 file changed, 6 insertions(+), 4 deletions(-)
monitor.c +6 -4
index 1f83775fff..f5911399d8 100644
@@ -4149,6 +4149,12 @@ static void monitor_qmp_bh_dispatcher(void *data)
     need_resume = !qmp_oob_enabled(mon) ||
         mon->qmp.qmp_requests->length == QMP_REQ_QUEUE_LEN_MAX - 1;
     qemu_mutex_unlock(&mon->qmp.qmp_queue_lock);
+
+    if (need_resume) {
+        /* Pairs with the monitor_suspend() in handle_qmp_command() */
+        monitor_resume(mon);
+    }
+
     if (req_obj->req) {
         trace_monitor_qmp_cmd_in_band(qobject_get_try_str(req_obj->id) ?: "");
         monitor_qmp_dispatch(mon, req_obj->req, req_obj->id);
@@ -4160,10 +4166,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
#4 lore raw

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

Hi

Quoted 21 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.

Note that now monitor_resume() is heavy weighted after 8af6bb14a3a8 and it's even possible (as pointed out by Marc-André) that the function itself may try to take the monitor lock again, so let's do the resume after the monitor lock is released to avoid possible dead lock.

---
 monitor.c | 10 ++++++----
 1 file changed, 6 insertions(+), 4 deletions(-)
monitor.c +0 -0
index 1f83775fff..f5911399d8 100644

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

Quoted 8 lines
monitor.c +5 -0
@@ -4149,6 +4149,12 @@ static void monitor_qmp_bh_dispatcher(void *data)
     need_resume = !qmp_oob_enabled(mon) ||
         mon->qmp.qmp_requests->length == QMP_REQ_QUEUE_LEN_MAX - 1;
     qemu_mutex_unlock(&mon->qmp.qmp_queue_lock);
+
+    if (need_resume) {
+        /* Pairs with the monitor_suspend() in handle_qmp_command() */
+        monitor_resume(mon);
+    }

"need_resume" is only set on non-oob enabled monitors.

On monitor_resume(), monitor_qmp_read() may end up being called, which may call handle_qmp_command().

With regular commands, a new command is queued. But if the command is "exec-oob", it will dispatch immediately, thus not following the QMP reply ordering constrain.

Shouldn't it be an error to call exec-oob on non-oob enabled monitors?

Quoted 19 lines
monitor.c +1 -5
+
     if (req_obj->req) {
         trace_monitor_qmp_cmd_in_band(qobject_get_try_str(req_obj->id) ?: "");
         monitor_qmp_dispatch(mon, req_obj->req, req_obj->id);
@@ -4160,10 +4166,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 */
--

2.17.1

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

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

Quoted 18 lines · Marc-André Lureau

Hi

Quoted 16 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.

Note that now monitor_resume() is heavy weighted after 8af6bb14a3a8 and it's even possible (as pointed out by Marc-André) that the function itself may try to take the monitor lock again, so let's do the resume after the monitor lock is released to avoid possible dead lock.

---
 monitor.c | 10 ++++++----
 1 file changed, 6 insertions(+), 4 deletions(-)
Quoted 15 lines

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

Quoted 13 lines
monitor.c +5 -0
index 1f83775fff..f5911399d8 100644
@@ -4149,6 +4149,12 @@ static void monitor_qmp_bh_dispatcher(void *data)
     need_resume = !qmp_oob_enabled(mon) ||
         mon->qmp.qmp_requests->length == QMP_REQ_QUEUE_LEN_MAX - 1;
     qemu_mutex_unlock(&mon->qmp.qmp_queue_lock);
+
+    if (need_resume) {
+        /* Pairs with the monitor_suspend() in handle_qmp_command() */
+        monitor_resume(mon);
+    }

"need_resume" is only set on non-oob enabled monitors.

... or on oob-enabled monitors when queue full?

Quoted 9 lines

On monitor_resume(), monitor_qmp_read() may end up being called, which may call handle_qmp_command().

With regular commands, a new command is queued. But if the command is "exec-oob", it will dispatch immediately, thus not following the QMP reply ordering constrain.

Shouldn't it be an error to call exec-oob on non-oob enabled monitors?

Do you mean a "qmp_capabilities" command to enable oob, and a continuous "exec-oob" command?

I can't say I fully understand the scenario you mentioned, but I think it does violate the rule if we resume the monitor before we finish executing the "qmp_capabilities" command since that command should still be run with "non-oob" context. So in that case we should do the resume after dispatching. For the other queue-full case we shouldn't need to, as Markus suggested.

Instead of bothering with all these, how about I drop this patch? We might resume the monitor a little bit later when queue full, but I don't think that's a big deal for now.

Regards,

Signature · 1 line
Peter Xu
#6 lore raw

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

Hi

Quoted 36 lines · Peter Xu
Quoted 18 lines · Marc-André Lureau

Hi

Quoted 16 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.

Note that now monitor_resume() is heavy weighted after 8af6bb14a3a8 and it's even possible (as pointed out by Marc-André) that the function itself may try to take the monitor lock again, so let's do the resume after the monitor lock is released to avoid possible dead lock.

---
 monitor.c | 10 ++++++----
 1 file changed, 6 insertions(+), 4 deletions(-)
Quoted 15 lines

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

Quoted 13 lines
monitor.c +5 -0
index 1f83775fff..f5911399d8 100644
@@ -4149,6 +4149,12 @@ static void monitor_qmp_bh_dispatcher(void *data)
     need_resume = !qmp_oob_enabled(mon) ||
         mon->qmp.qmp_requests->length == QMP_REQ_QUEUE_LEN_MAX - 1;
     qemu_mutex_unlock(&mon->qmp.qmp_queue_lock);
+
+    if (need_resume) {
+        /* Pairs with the monitor_suspend() in handle_qmp_command() */
+        monitor_resume(mon);
+    }

"need_resume" is only set on non-oob enabled monitors.

Quoted 1 line

... or on oob-enabled monitors when queue full?

yes, after patch 1

Quoted 5 lines
Quoted 5 lines

On monitor_resume(), monitor_qmp_read() may end up being called, which may call handle_qmp_command().

Quoted 8 lines
Quoted 5 lines

With regular commands, a new command is queued. But if the command is "exec-oob", it will dispatch immediately, thus not following the QMP reply ordering constrain.

Shouldn't it be an error to call exec-oob on non-oob enabled monitors?

Do you mean a "qmp_capabilities" command to enable oob, and a continuous "exec-oob" command?

No I meant calling "exec-oob" on a monitor without oob capability. I checked again, and it does already fail with "QMP input member 'exec-oob' is unexpected". So nevermind.

Quoted 11 lines

I can't say I fully understand the scenario you mentioned, but I think it does violate the rule if we resume the monitor before we finish executing the "qmp_capabilities" command since that command should still be run with "non-oob" context. So in that case we should do the resume after dispatching. For the other queue-full case we shouldn't need to, as Markus suggested.

Instead of bothering with all these, how about I drop this patch? We might resume the monitor a little bit later when queue full, but I don't think that's a big deal for now.

Yes, if it's a minor optimization, we can postpone it for now.

thanks

Quoted 5 lines

Regards,

--
Peter Xu

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

PATCH v9 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 0c0a37d8cb..c1b40a9cac 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 f5911399d8..65a5e5f41a 100644
@@ -4545,19 +4545,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);
 
@@ -4647,9 +4640,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 2cd5736642..8bf9fd1ae3 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 6c419f6023..030d813f77 100644
@@ -116,7 +116,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 4e25c78bff..db766f5295 100644
@@ -2282,11 +2282,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
#8 lore raw

PATCH v9 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 8bf9fd1ae3..e0bb032c5e 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 ed88ff99d5..96a6c01352 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 030d813f77..cc9907b525 100644
@@ -108,7 +108,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);
@@ -219,7 +219,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
#9 lore raw

PATCH v9 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 4ab2b6e5ce..481cb069ca 100644
@@ -126,6 +126,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)
 {
@@ -302,6 +317,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/dispatch_cmd_success_response",
Signature · 1 line
2.17.1
author
#10 lore raw

PATCH v9 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 cc9907b525..6989acbca4 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";
 
@@ -218,6 +219,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);
 
@@ -272,6 +275,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
#11 lore raw
In reply to Peter Xu
Quoted 8 lines · Peter Xu

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

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

v9:
- add r-bs
- release the qmp queue lock before resume [Marc-Andre]

I haven't reviewed closely, but did want to report that I tested that with your patches applied, there is no way to trigger OOB of the initial capability handshake (good). It's a bit odd that the initial error (input member unexpected) is different from the later error (does not support OOB), but not a show-stopper, so I don't think you need to worry about it:

{"QMP": {"version": {"qemu": {"micro": 50, "minor": 0, "major": 3}, "package": "v3.0.0-1150-g7d932cd3d53"}, "capabilities": ["oob"]}} {"exec-oob":"qmp_capabilities","arguments":{"enable":["oob"]}}
{"error": {"class": "GenericError", "desc": "QMP input member 'exec-oob' is unexpected"}} {"execute":"qmp_capabilities","arguments":{"enable":["oob"]}}
{"return": {}}
{"exec-oob":"qmp_capabilities"}
{"error": {"class": "GenericError", "desc": "The command qmp_capabilities does not support OOB"}}

Signature · 3 lines
Eric Blake, Principal Software Engineer
Red Hat, Inc.           +1-919-301-3266
Virtualization:  qemu.org | libvirt.org
#12 lore raw
Quoted 12 lines · Eric Blake
Quoted 8 lines · Peter Xu

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

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

v9:
- add r-bs
- release the qmp queue lock before resume [Marc-Andre]

I haven't reviewed closely, but did want to report that I tested that with your patches applied, there is no way to trigger OOB of the initial capability handshake (good). It's a bit odd that the initial error (input member unexpected) is different from the later error (does not support OOB), but not a show-stopper, so I don't think you need to worry about it:

Quoted 8 lines

{"QMP": {"version": {"qemu": {"micro": 50, "minor": 0, "major": 3}, "package": "v3.0.0-1150-g7d932cd3d53"}, "capabilities": ["oob"]}} {"exec-oob":"qmp_capabilities","arguments":{"enable":["oob"]}}
{"error": {"class": "GenericError", "desc": "QMP input member 'exec-oob' is unexpected"}} {"execute":"qmp_capabilities","arguments":{"enable":["oob"]}}
{"return": {}}
{"exec-oob":"qmp_capabilities"}
{"error": {"class": "GenericError", "desc": "The command qmp_capabilities does not support OOB"}}

On the other hand, when I'm trying to use a qemu binary with these patches applied, libvirt is hanging when trying to probe the capabilities of the binary, waiting for a response to "qmp_capabilities". I'll try and bisect which patch is causing the problem, and figure out why it is happening for libvirt and not running by hand (perhaps is it a tty vs. Unix socket thing?)

Signature · 3 lines
Eric Blake, Principal Software Engineer
Red Hat, Inc.           +1-919-301-3266
Virtualization:  qemu.org | libvirt.org
#13 lore raw
Quoted 2 lines · Eric Blake

On the other hand, when I'm trying to use a qemu binary with these patches applied, libvirt is hanging when trying to probe the capabilities of the binary, waiting for a response to "qmp_capabilities". I'll try and bisect which patch is causing the problem, and figure out why it is happening for libvirt and not running by hand (perhaps is it a tty vs. Unix socket thing?)

Bisect didn't help much; it landed on:

monitor: remove "x-oob", turn oob on by default

as the cause of libvirt hanging. I didn't have time to investigate further, other than the command line that is hanging:

/home/eblake/qemu/x86_64-softmmu/qemu-system-x86_64 -S -no-user-config -nodefaults -nographic -machine none,accel=kvm:tcg -qmp unix:/var/lib/libvirt/qemu/capabilities.monitor.sock,server,nowait -pidfile /var/lib/libvirt/qemu/capabilities.pidfile -daemonize

And I suspect it is the -daemonize that is causing the hang I'm seeing when run by libvirt.

Quoted 4 lines

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

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

Am I missing any prerequisite patches? Markus' monitor-next tree is currently a subset of git master (merge efd1d522).

Signature · 3 lines
Eric Blake, Principal Software Engineer
Red Hat, Inc.           +1-919-301-3266
Virtualization:  qemu.org | libvirt.org
author
#14 lore raw
Quoted 25 lines · Eric Blake
Quoted 7 lines · Eric Blake

On the other hand, when I'm trying to use a qemu binary with these patches applied, libvirt is hanging when trying to probe the capabilities of the binary, waiting for a response to "qmp_capabilities". I'll try and bisect which patch is causing the problem, and figure out why it is happening for libvirt and not running by hand (perhaps is it a tty vs. Unix socket thing?)

Bisect didn't help much; it landed on:

monitor: remove "x-oob", turn oob on by default

as the cause of libvirt hanging. I didn't have time to investigate further, other than the command line that is hanging:

/home/eblake/qemu/x86_64-softmmu/qemu-system-x86_64 -S -no-user-config -nodefaults -nographic -machine none,accel=kvm:tcg -qmp unix:/var/lib/libvirt/qemu/capabilities.monitor.sock,server,nowait -pidfile /var/lib/libvirt/qemu/capabilities.pidfile -daemonize

And I suspect it is the -daemonize that is causing the hang I'm seeing when run by libvirt.

Quoted 8 lines
Quoted 4 lines

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

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

Am I missing any prerequisite patches? Markus' monitor-next tree is currently a subset of git master (merge efd1d522).

Sorry for the confusion. I should have removed these lines from the old cover letter.

It's very possible the daemonize thing, actually Wolfgang Bumiller has posted patches to fix this up (it's not the problem of this series, but it just exposed this to libvirt by the series since it only happens when oob and daemonize are both enabled). The fixes are:

[PATCH v2 0/2] delay monitor iothread creation

Since it cannot be applied cleanly onto this series, I resolved the conflicts and pushed a tree here in case you wanna try with these two extra patches applied:

https://github.com/xzpeter/qemu/tree/test-oob

Please feel free to test with libvirt again with that.

Thanks for playing with the tree and further investigation! I will also mention this in the next version of cover letter (if there is one).

Regards,

Signature · 1 line
Peter Xu
#15 lore raw
Quoted 17 lines · Peter Xu
Quoted 10 lines

other than the command line that is hanging:

/home/eblake/qemu/x86_64-softmmu/qemu-system-x86_64 -S -no-user-config -nodefaults -nographic -machine none,accel=kvm:tcg -qmp unix:/var/lib/libvirt/qemu/capabilities.monitor.sock,server,nowait -pidfile /var/lib/libvirt/qemu/capabilities.pidfile -daemonize

And I suspect it is the -daemonize that is causing the hang I'm seeing when run by libvirt.

It's very possible the daemonize thing, actually Wolfgang Bumiller has posted patches to fix this up (it's not the problem of this series, but it just exposed this to libvirt by the series since it only happens when oob and daemonize are both enabled). The fixes are:

Quoted 7 lines

[PATCH v2 0/2] delay monitor iothread creation

Since it cannot be applied cleanly onto this series, I resolved the conflicts and pushed a tree here in case you wanna try with these two extra patches applied:

https://github.com/xzpeter/qemu/tree/test-oob

Technically, we should apply the patches in the opposite order (Wolfgang's first, then yours), so that bisection does not land on a known-bad hang situation.

Quoted 5 lines

Please feel free to test with libvirt again with that.

Thanks for playing with the tree and further investigation! I will also mention this in the next version of cover letter (if there is one).

Confirmed that libvirt no longer hung with Wolfgang's patches added in.

Signature · 3 lines
Eric Blake, Principal Software Engineer
Red Hat, Inc.           +1-919-301-3266
Virtualization:  qemu.org | libvirt.org
author
#16 lore raw
Quoted 25 lines · Eric Blake
Quoted 23 lines · Peter Xu
Quoted 10 lines

other than the command line that is hanging:

/home/eblake/qemu/x86_64-softmmu/qemu-system-x86_64 -S -no-user-config -nodefaults -nographic -machine none,accel=kvm:tcg -qmp unix:/var/lib/libvirt/qemu/capabilities.monitor.sock,server,nowait -pidfile /var/lib/libvirt/qemu/capabilities.pidfile -daemonize

And I suspect it is the -daemonize that is causing the hang I'm seeing when run by libvirt.

It's very possible the daemonize thing, actually Wolfgang Bumiller has posted patches to fix this up (it's not the problem of this series, but it just exposed this to libvirt by the series since it only happens when oob and daemonize are both enabled). The fixes are:

[PATCH v2 0/2] delay monitor iothread creation

Since it cannot be applied cleanly onto this series, I resolved the conflicts and pushed a tree here in case you wanna try with these two extra patches applied:

Quoted 5 lines
Quoted 1 line

https://github.com/xzpeter/qemu/tree/test-oob

Technically, we should apply the patches in the opposite order (Wolfgang's first, then yours), so that bisection does not land on a known-bad hang situation.

Agreed, that patch actually fixes bug of current master (current master could possibly hit the same issue when with x-oob=on and -daemonize), so should be applied earlier when proper.

Quoted 8 lines
Quoted 6 lines

Please feel free to test with libvirt again with that.

Thanks for playing with the tree and further investigation! I will also mention this in the next version of cover letter (if there is one).

Confirmed that libvirt no longer hung with Wolfgang's patches added in.

Thanks!

Signature · 1 line
Peter Xu