qemu-devel.nongnu.org archive mirror
 help / color / mirror / Atom feed
* [Qemu-devel] [PATCH v2 0/6] block: avoid recursive AioContext acquire in bdrv_inactivate_all()
@ 2017-12-07 20:13 Stefan Hajnoczi
  2017-12-07 20:13 ` [Qemu-devel] [PATCH v2 1/6] " Stefan Hajnoczi
                   ` (7 more replies)
  0 siblings, 8 replies; 15+ messages in thread
From: Stefan Hajnoczi @ 2017-12-07 20:13 UTC (permalink / raw)
  To: qemu-devel
  Cc: qemu-block, Eric Blake, Kevin Wolf, Paolo Bonzini,
	Stefan Hajnoczi

v2:
 * Added docs/devel/multiple-iothreads.txt doc update [Kevin]
 * Added qemu-iotests 203 test case [Kevin]
 * Added iothread_stop() race fix to make 203 reliable

Patch 1 is Paolo's recursive locking removal in bdrv_inactivate_all().  This
solve migration hangs and is the main point of the patch series.

Patches 2-6 add a qemu-iotests test case and update the multiple-iothreads.txt
documentation to discourage recursive AioContext locking.

Based-on: <20171206144550.22295-1-stefanha@redhat.com>

Paolo Bonzini (1):
  block: avoid recursive AioContext acquire in bdrv_inactivate_all()

Stefan Hajnoczi (5):
  docs: mark nested AioContext locking as a legacy API
  blockdev: add x-blockdev-set-iothread force boolean
  iotests: add VM.add_object()
  iothread: fix iothread_stop() race condition
  qemu-iotests: add 203 savevm with IOThreads test

 docs/devel/multiple-iothreads.txt |  7 +++--
 qapi/block-core.json              |  6 +++-
 include/sysemu/iothread.h         |  3 +-
 block.c                           | 14 ++++++++--
 blockdev.c                        | 11 ++++----
 iothread.c                        | 20 +++++++++----
 tests/qemu-iotests/203            | 59 +++++++++++++++++++++++++++++++++++++++
 tests/qemu-iotests/203.out        |  6 ++++
 tests/qemu-iotests/group          |  1 +
 tests/qemu-iotests/iotests.py     |  5 ++++
 10 files changed, 114 insertions(+), 18 deletions(-)
 create mode 100755 tests/qemu-iotests/203
 create mode 100644 tests/qemu-iotests/203.out

-- 
2.14.3

^ permalink raw reply	[flat|nested] 15+ messages in thread

* [Qemu-devel] [PATCH v2 1/6] block: avoid recursive AioContext acquire in bdrv_inactivate_all()
  2017-12-07 20:13 [Qemu-devel] [PATCH v2 0/6] block: avoid recursive AioContext acquire in bdrv_inactivate_all() Stefan Hajnoczi
@ 2017-12-07 20:13 ` Stefan Hajnoczi
  2017-12-07 22:04   ` Eric Blake
  2017-12-07 20:13 ` [Qemu-devel] [PATCH v2 2/6] docs: mark nested AioContext locking as a legacy API Stefan Hajnoczi
                   ` (6 subsequent siblings)
  7 siblings, 1 reply; 15+ messages in thread
From: Stefan Hajnoczi @ 2017-12-07 20:13 UTC (permalink / raw)
  To: qemu-devel; +Cc: qemu-block, Eric Blake, Kevin Wolf, Paolo Bonzini

From: Paolo Bonzini <pbonzini@redhat.com>

BDRV_POLL_WHILE() does not support recursive AioContext locking.  It
only releases the AioContext lock once regardless of how many times the
caller has acquired it.  This results in a hang since the IOThread does
not make progress while the AioContext is still locked.

The following steps trigger the hang:

  $ qemu-system-x86_64 -M accel=kvm -m 1G -cpu host \
                       -object iothread,id=iothread0 \
                       -device virtio-scsi-pci,iothread=iothread0 \
                       -drive if=none,id=drive0,file=test.img,format=raw \
                       -device scsi-hd,drive=drive0 \
                       -drive if=none,id=drive1,file=test.img,format=raw \
                       -device scsi-hd,drive=drive1
  $ qemu-system-x86_64 ...same options... \
                       -incoming tcp::1234
  (qemu) migrate tcp:127.0.0.1:1234
  ...hang...

Tested-by: Stefan Hajnoczi <stefanha@redhat.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
---
 block.c | 14 +++++++++++---
 1 file changed, 11 insertions(+), 3 deletions(-)

diff --git a/block.c b/block.c
index 9a1a0d1e73..1c37ce4554 100644
--- a/block.c
+++ b/block.c
@@ -4320,9 +4320,15 @@ int bdrv_inactivate_all(void)
     BdrvNextIterator it;
     int ret = 0;
     int pass;
+    GSList *aio_ctxs = NULL, *ctx;
 
     for (bs = bdrv_first(&it); bs; bs = bdrv_next(&it)) {
-        aio_context_acquire(bdrv_get_aio_context(bs));
+        AioContext *aio_context = bdrv_get_aio_context(bs);
+
+        if (!g_slist_find(aio_ctxs, aio_context)) {
+            aio_ctxs = g_slist_prepend(aio_ctxs, aio_context);
+            aio_context_acquire(aio_context);
+        }
     }
 
     /* We do two passes of inactivation. The first pass calls to drivers'
@@ -4340,9 +4346,11 @@ int bdrv_inactivate_all(void)
     }
 
 out:
-    for (bs = bdrv_first(&it); bs; bs = bdrv_next(&it)) {
-        aio_context_release(bdrv_get_aio_context(bs));
+    for (ctx = aio_ctxs; ctx != NULL; ctx = ctx->next) {
+        AioContext *aio_context = ctx->data;
+        aio_context_release(aio_context);
     }
+    g_slist_free(aio_ctxs);
 
     return ret;
 }
-- 
2.14.3

^ permalink raw reply related	[flat|nested] 15+ messages in thread

* [Qemu-devel] [PATCH v2 2/6] docs: mark nested AioContext locking as a legacy API
  2017-12-07 20:13 [Qemu-devel] [PATCH v2 0/6] block: avoid recursive AioContext acquire in bdrv_inactivate_all() Stefan Hajnoczi
  2017-12-07 20:13 ` [Qemu-devel] [PATCH v2 1/6] " Stefan Hajnoczi
@ 2017-12-07 20:13 ` Stefan Hajnoczi
  2017-12-07 22:34   ` Eric Blake
  2017-12-07 20:13 ` [Qemu-devel] [PATCH v2 3/6] blockdev: add x-blockdev-set-iothread force boolean Stefan Hajnoczi
                   ` (5 subsequent siblings)
  7 siblings, 1 reply; 15+ messages in thread
From: Stefan Hajnoczi @ 2017-12-07 20:13 UTC (permalink / raw)
  To: qemu-devel
  Cc: qemu-block, Eric Blake, Kevin Wolf, Paolo Bonzini,
	Stefan Hajnoczi

See the patch for why nested AioContext locking is no longer allowed.

Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
---
 docs/devel/multiple-iothreads.txt | 7 ++++---
 1 file changed, 4 insertions(+), 3 deletions(-)

diff --git a/docs/devel/multiple-iothreads.txt b/docs/devel/multiple-iothreads.txt
index e4d340bbb7..4f9012d154 100644
--- a/docs/devel/multiple-iothreads.txt
+++ b/docs/devel/multiple-iothreads.txt
@@ -1,4 +1,4 @@
-Copyright (c) 2014 Red Hat Inc.
+Copyright (c) 2014-2017 Red Hat Inc.
 
 This work is licensed under the terms of the GNU GPL, version 2 or later.  See
 the COPYING file in the top-level directory.
@@ -92,8 +92,9 @@ aio_context_acquire()/aio_context_release() for mutual exclusion.  Once the
 context is acquired no other thread can access it or run event loop iterations
 in this AioContext.
 
-aio_context_acquire()/aio_context_release() calls may be nested.  This
-means you can call them if you're not sure whether #2 applies.
+Legacy code sometimes nests aio_context_acquire()/aio_context_release() calls.
+Do not use nesting anymore, it is incompatible with the BDRV_POLL_WHILE() macro
+used in the block layer and can lead to hangs.
 
 There is currently no lock ordering rule if a thread needs to acquire multiple
 AioContexts simultaneously.  Therefore, it is only safe for code holding the
-- 
2.14.3

^ permalink raw reply related	[flat|nested] 15+ messages in thread

* [Qemu-devel] [PATCH v2 3/6] blockdev: add x-blockdev-set-iothread force boolean
  2017-12-07 20:13 [Qemu-devel] [PATCH v2 0/6] block: avoid recursive AioContext acquire in bdrv_inactivate_all() Stefan Hajnoczi
  2017-12-07 20:13 ` [Qemu-devel] [PATCH v2 1/6] " Stefan Hajnoczi
  2017-12-07 20:13 ` [Qemu-devel] [PATCH v2 2/6] docs: mark nested AioContext locking as a legacy API Stefan Hajnoczi
@ 2017-12-07 20:13 ` Stefan Hajnoczi
  2017-12-07 22:38   ` Eric Blake
  2017-12-07 20:13 ` [Qemu-devel] [PATCH v2 4/6] iotests: add VM.add_object() Stefan Hajnoczi
                   ` (4 subsequent siblings)
  7 siblings, 1 reply; 15+ messages in thread
From: Stefan Hajnoczi @ 2017-12-07 20:13 UTC (permalink / raw)
  To: qemu-devel
  Cc: qemu-block, Eric Blake, Kevin Wolf, Paolo Bonzini,
	Stefan Hajnoczi

When a node is already associated with a BlockBackend the
x-blockdev-set-iothread command refuses to set the IOThread.  This is to
prevent accidentally changing the IOThread when the nodes are in use.

When the nodes are created with -drive they automatically get a
BlockBackend.  In that case we know nothing is using them yet and it's
safe to set the IOThread.  Add a force boolean to override the check.

Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
---
 qapi/block-core.json |  6 +++++-
 blockdev.c           | 11 ++++++-----
 2 files changed, 11 insertions(+), 6 deletions(-)

diff --git a/qapi/block-core.json b/qapi/block-core.json
index 741d6c4367..a8cdbc300b 100644
--- a/qapi/block-core.json
+++ b/qapi/block-core.json
@@ -3962,6 +3962,9 @@
 #
 # @iothread: the name of the IOThread object or null for the main loop
 #
+# @force: true if the node and its children should be moved when a BlockBackend
+#         is already attached
+#
 # Note: this command is experimental and intended for test cases that need
 # control over IOThreads only.
 #
@@ -3984,4 +3987,5 @@
 ##
 { 'command': 'x-blockdev-set-iothread',
   'data' : { 'node-name': 'str',
-             'iothread': 'StrOrNull' } }
+             'iothread': 'StrOrNull',
+             '*force': 'bool' } }
diff --git a/blockdev.c b/blockdev.c
index f75c01f664..9c3a430cfb 100644
--- a/blockdev.c
+++ b/blockdev.c
@@ -4131,7 +4131,7 @@ BlockJobInfoList *qmp_query_block_jobs(Error **errp)
 }
 
 void qmp_x_blockdev_set_iothread(const char *node_name, StrOrNull *iothread,
-                                 Error **errp)
+                                 bool has_force, bool force, Error **errp)
 {
     AioContext *old_context;
     AioContext *new_context;
@@ -4143,10 +4143,11 @@ void qmp_x_blockdev_set_iothread(const char *node_name, StrOrNull *iothread,
         return;
     }
 
-    /* If we want to allow more extreme test scenarios this guard could be
-     * removed.  For now it protects against accidents. */
-    if (bdrv_has_blk(bs)) {
-        error_setg(errp, "Node %s is in use", node_name);
+    /* Protects against accidents. */
+    if (!(has_force && force) && bdrv_has_blk(bs)) {
+        error_setg(errp, "Node %s is associated with a BlockBackend and could "
+                         "be in use (use force=true to override this check)",
+                         node_name);
         return;
     }
 
-- 
2.14.3

^ permalink raw reply related	[flat|nested] 15+ messages in thread

* [Qemu-devel] [PATCH v2 4/6] iotests: add VM.add_object()
  2017-12-07 20:13 [Qemu-devel] [PATCH v2 0/6] block: avoid recursive AioContext acquire in bdrv_inactivate_all() Stefan Hajnoczi
                   ` (2 preceding siblings ...)
  2017-12-07 20:13 ` [Qemu-devel] [PATCH v2 3/6] blockdev: add x-blockdev-set-iothread force boolean Stefan Hajnoczi
@ 2017-12-07 20:13 ` Stefan Hajnoczi
  2017-12-07 22:39   ` Eric Blake
  2017-12-07 20:13 ` [Qemu-devel] [PATCH v2 5/6] iothread: fix iothread_stop() race condition Stefan Hajnoczi
                   ` (3 subsequent siblings)
  7 siblings, 1 reply; 15+ messages in thread
From: Stefan Hajnoczi @ 2017-12-07 20:13 UTC (permalink / raw)
  To: qemu-devel
  Cc: qemu-block, Eric Blake, Kevin Wolf, Paolo Bonzini,
	Stefan Hajnoczi

The VM.add_object() method can be used to add IOThreads or memory
backend objects.

Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
---
 tests/qemu-iotests/iotests.py | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/tests/qemu-iotests/iotests.py b/tests/qemu-iotests/iotests.py
index 6f057904a9..44477e9295 100644
--- a/tests/qemu-iotests/iotests.py
+++ b/tests/qemu-iotests/iotests.py
@@ -197,6 +197,11 @@ class VM(qtest.QEMUQtestMachine):
                                  socket_scm_helper=socket_scm_helper)
         self._num_drives = 0
 
+    def add_object(self, opts):
+        self._args.append('-object')
+        self._args.append(opts)
+        return self
+
     def add_device(self, opts):
         self._args.append('-device')
         self._args.append(opts)
-- 
2.14.3

^ permalink raw reply related	[flat|nested] 15+ messages in thread

* [Qemu-devel] [PATCH v2 5/6] iothread: fix iothread_stop() race condition
  2017-12-07 20:13 [Qemu-devel] [PATCH v2 0/6] block: avoid recursive AioContext acquire in bdrv_inactivate_all() Stefan Hajnoczi
                   ` (3 preceding siblings ...)
  2017-12-07 20:13 ` [Qemu-devel] [PATCH v2 4/6] iotests: add VM.add_object() Stefan Hajnoczi
@ 2017-12-07 20:13 ` Stefan Hajnoczi
  2017-12-07 22:42   ` Eric Blake
  2017-12-07 20:13 ` [Qemu-devel] [PATCH v2 6/6] qemu-iotests: add 203 savevm with IOThreads test Stefan Hajnoczi
                   ` (2 subsequent siblings)
  7 siblings, 1 reply; 15+ messages in thread
From: Stefan Hajnoczi @ 2017-12-07 20:13 UTC (permalink / raw)
  To: qemu-devel
  Cc: qemu-block, Eric Blake, Kevin Wolf, Paolo Bonzini,
	Stefan Hajnoczi

There is a small chance that iothread_stop() hangs as follows:

  Thread 3 (Thread 0x7f63eba5f700 (LWP 16105)):
  #0  0x00007f64012c09b6 in ppoll () at /lib64/libc.so.6
  #1  0x000055959992eac9 in ppoll (__ss=0x0, __timeout=0x0, __nfds=<optimized out>, __fds=<optimized out>) at /usr/include/bits/poll2.h:77
  #2  0x000055959992eac9 in qemu_poll_ns (fds=<optimized out>, nfds=<optimized out>, timeout=<optimized out>) at util/qemu-timer.c:322
  #3  0x0000559599930711 in aio_poll (ctx=0x55959bdb83c0, blocking=blocking@entry=true) at util/aio-posix.c:629
  #4  0x00005595996806fe in iothread_run (opaque=0x55959bd78400) at iothread.c:59
  #5  0x00007f640159f609 in start_thread () at /lib64/libpthread.so.0
  #6  0x00007f64012cce6f in clone () at /lib64/libc.so.6

  Thread 1 (Thread 0x7f640b45b280 (LWP 16103)):
  #0  0x00007f64015a0b6d in pthread_join () at /lib64/libpthread.so.0
  #1  0x00005595999332ef in qemu_thread_join (thread=<optimized out>) at util/qemu-thread-posix.c:547
  #2  0x00005595996808ae in iothread_stop (iothread=<optimized out>) at iothread.c:91
  #3  0x000055959968094d in iothread_stop_iter (object=<optimized out>, opaque=<optimized out>) at iothread.c:102
  #4  0x0000559599857d97 in do_object_child_foreach (obj=obj@entry=0x55959bdb8100, fn=fn@entry=0x559599680930 <iothread_stop_iter>, opaque=opaque@entry=0x0, recurse=recurse@entry=false) at qom/object.c:852
  #5  0x0000559599859477 in object_child_foreach (obj=obj@entry=0x55959bdb8100, fn=fn@entry=0x559599680930 <iothread_stop_iter>, opaque=opaque@entry=0x0) at qom/object.c:867
  #6  0x0000559599680a6e in iothread_stop_all () at iothread.c:341
  #7  0x000055959955b1d5 in main (argc=<optimized out>, argv=<optimized out>, envp=<optimized out>) at vl.c:4913

The relevant code from iothread_run() is:

  while (!atomic_read(&iothread->stopping)) {
      aio_poll(iothread->ctx, true);

and iothread_stop():

  iothread->stopping = true;
  aio_notify(iothread->ctx);
  ...
  qemu_thread_join(&iothread->thread);

The following scenario can occur:

1. IOThread:
  while (!atomic_read(&iothread->stopping)) -> stopping=false

2. Main loop:
  iothread->stopping = true;
  aio_notify(iothread->ctx);

3. IOThread:
  aio_poll(iothread->ctx, true); -> hang

The bug is explained by the AioContext->notify_me doc comments:

  "If this field is 0, everything (file descriptors, bottom halves,
  timers) will be re-evaluated before the next blocking poll(), thus the
  event_notifier_set call can be skipped."

The problem is that "everything" does not include checking
iothread->stopping.  This means iothread_run() will block in aio_poll()
if aio_notify() was called just before aio_poll().

This patch fixes the hang by replacing aio_notify() with
aio_bh_schedule_oneshot().  This makes aio_poll() or g_main_loop_run()
to return.

Implementing this properly required a new bool running flag.  The new
flag prevents races that are tricky if we try to use iothread->stopping.
Now iothread->stopping is purely for iothread_stop() and
iothread->running is purely for the iothread_run() thread.

Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
---
I'm including this patch in this series because it is needed to make the
test case reliable.  It's unrelated to the main goal of the patch
series.
---
 include/sysemu/iothread.h |  3 ++-
 iothread.c                | 20 +++++++++++++++-----
 2 files changed, 17 insertions(+), 6 deletions(-)

diff --git a/include/sysemu/iothread.h b/include/sysemu/iothread.h
index 55de1715c7..799614ffd2 100644
--- a/include/sysemu/iothread.h
+++ b/include/sysemu/iothread.h
@@ -29,7 +29,8 @@ typedef struct {
     GOnce once;
     QemuMutex init_done_lock;
     QemuCond init_done_cond;    /* is thread initialization done? */
-    bool stopping;
+    bool stopping;              /* has iothread_stop() been called? */
+    bool running;               /* should iothread_run() continue? */
     int thread_id;
 
     /* AioContext poll parameters */
diff --git a/iothread.c b/iothread.c
index e7b93e02a3..d8b6c1fb27 100644
--- a/iothread.c
+++ b/iothread.c
@@ -55,7 +55,7 @@ static void *iothread_run(void *opaque)
     qemu_cond_signal(&iothread->init_done_cond);
     qemu_mutex_unlock(&iothread->init_done_lock);
 
-    while (!atomic_read(&iothread->stopping)) {
+    while (iothread->running) {
         aio_poll(iothread->ctx, true);
 
         if (atomic_read(&iothread->worker_context)) {
@@ -78,16 +78,25 @@ static void *iothread_run(void *opaque)
     return NULL;
 }
 
+/* Runs in iothread_run() thread */
+static void iothread_stop_bh(void *opaque)
+{
+    IOThread *iothread = opaque;
+
+    iothread->running = false; /* stop iothread_run() */
+
+    if (iothread->main_loop) {
+        g_main_loop_quit(iothread->main_loop);
+    }
+}
+
 void iothread_stop(IOThread *iothread)
 {
     if (!iothread->ctx || iothread->stopping) {
         return;
     }
     iothread->stopping = true;
-    aio_notify(iothread->ctx);
-    if (atomic_read(&iothread->main_loop)) {
-        g_main_loop_quit(iothread->main_loop);
-    }
+    aio_bh_schedule_oneshot(iothread->ctx, iothread_stop_bh, iothread);
     qemu_thread_join(&iothread->thread);
 }
 
@@ -134,6 +143,7 @@ static void iothread_complete(UserCreatable *obj, Error **errp)
     char *name, *thread_name;
 
     iothread->stopping = false;
+    iothread->running = true;
     iothread->thread_id = -1;
     iothread->ctx = aio_context_new(&local_error);
     if (!iothread->ctx) {
-- 
2.14.3

^ permalink raw reply related	[flat|nested] 15+ messages in thread

* [Qemu-devel] [PATCH v2 6/6] qemu-iotests: add 203 savevm with IOThreads test
  2017-12-07 20:13 [Qemu-devel] [PATCH v2 0/6] block: avoid recursive AioContext acquire in bdrv_inactivate_all() Stefan Hajnoczi
                   ` (4 preceding siblings ...)
  2017-12-07 20:13 ` [Qemu-devel] [PATCH v2 5/6] iothread: fix iothread_stop() race condition Stefan Hajnoczi
@ 2017-12-07 20:13 ` Stefan Hajnoczi
  2017-12-07 22:46   ` Eric Blake
  2017-12-13 21:23 ` [Qemu-devel] [PATCH v2 0/6] block: avoid recursive AioContext acquire in bdrv_inactivate_all() Paolo Bonzini
  2017-12-14 11:12 ` Stefan Hajnoczi
  7 siblings, 1 reply; 15+ messages in thread
From: Stefan Hajnoczi @ 2017-12-07 20:13 UTC (permalink / raw)
  To: qemu-devel
  Cc: qemu-block, Eric Blake, Kevin Wolf, Paolo Bonzini,
	Stefan Hajnoczi

This test case will prevent future regressions with savevm and
IOThreads.

Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
---
 tests/qemu-iotests/203     | 59 ++++++++++++++++++++++++++++++++++++++++++++++
 tests/qemu-iotests/203.out |  6 +++++
 tests/qemu-iotests/group   |  1 +
 3 files changed, 66 insertions(+)
 create mode 100755 tests/qemu-iotests/203
 create mode 100644 tests/qemu-iotests/203.out

diff --git a/tests/qemu-iotests/203 b/tests/qemu-iotests/203
new file mode 100755
index 0000000000..2c811917d8
--- /dev/null
+++ b/tests/qemu-iotests/203
@@ -0,0 +1,59 @@
+#!/usr/bin/env python
+#
+# Copyright (C) 2017 Red Hat, Inc.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+#
+# Creator/Owner: Stefan Hajnoczi <stefanha@redhat.com>
+#
+# Check that QMP 'migrate' with multiple drives on a single IOThread completes
+# successfully.  This particular command triggered a hang in the source QEMU
+# process due to recursive AioContext locking in bdrv_invalidate_all() and
+# BDRV_POLL_WHILE().
+
+import iotests
+
+iotests.verify_image_format(supported_fmts=['qcow2'])
+iotests.verify_platform(['linux'])
+
+with iotests.FilePath('disk0.img') as disk0_img_path, \
+     iotests.FilePath('disk1.img') as disk1_img_path, \
+     iotests.VM() as vm:
+
+    img_size = '10M'
+    iotests.qemu_img_pipe('create', '-f', iotests.imgfmt, disk0_img_path, img_size)
+    iotests.qemu_img_pipe('create', '-f', iotests.imgfmt, disk1_img_path, img_size)
+
+    iotests.log('Launching VM...')
+    (vm.add_object('iothread,id=iothread0')
+       .add_drive(disk0_img_path, 'node-name=drive0-node', interface='none')
+       .add_drive(disk1_img_path, 'node-name=drive1-node', interface='none')
+       .launch())
+
+    iotests.log('Setting IOThreads...')
+    iotests.log(vm.qmp('x-blockdev-set-iothread',
+                       node_name='drive0-node', iothread='iothread0',
+                       force=True))
+    iotests.log(vm.qmp('x-blockdev-set-iothread',
+                       node_name='drive1-node', iothread='iothread0',
+                       force=True))
+
+    iotests.log('Starting migration...')
+    iotests.log(vm.qmp('migrate', uri='exec:cat >/dev/null'))
+    while True:
+        vm.get_qmp_event(wait=60.0)
+        result = vm.qmp('query-migrate')
+        status = result.get('return', {}).get('status', None)
+        if status == 'completed':
+            break
diff --git a/tests/qemu-iotests/203.out b/tests/qemu-iotests/203.out
new file mode 100644
index 0000000000..3f1ff900e4
--- /dev/null
+++ b/tests/qemu-iotests/203.out
@@ -0,0 +1,6 @@
+Launching VM...
+Setting IOThreads...
+{u'return': {}}
+{u'return': {}}
+Starting migration...
+{u'return': {}}
diff --git a/tests/qemu-iotests/group b/tests/qemu-iotests/group
index d0ee1e2e55..93d96fb22f 100644
--- a/tests/qemu-iotests/group
+++ b/tests/qemu-iotests/group
@@ -198,3 +198,4 @@
 198 rw auto
 200 rw auto
 202 rw auto quick
+203 rw auto
-- 
2.14.3

^ permalink raw reply related	[flat|nested] 15+ messages in thread

* Re: [Qemu-devel] [PATCH v2 1/6] block: avoid recursive AioContext acquire in bdrv_inactivate_all()
  2017-12-07 20:13 ` [Qemu-devel] [PATCH v2 1/6] " Stefan Hajnoczi
@ 2017-12-07 22:04   ` Eric Blake
  0 siblings, 0 replies; 15+ messages in thread
From: Eric Blake @ 2017-12-07 22:04 UTC (permalink / raw)
  To: Stefan Hajnoczi, qemu-devel; +Cc: qemu-block, Kevin Wolf, Paolo Bonzini

[-- Attachment #1: Type: text/plain, Size: 1414 bytes --]

On 12/07/2017 02:13 PM, Stefan Hajnoczi wrote:
> From: Paolo Bonzini <pbonzini@redhat.com>
> 
> BDRV_POLL_WHILE() does not support recursive AioContext locking.  It
> only releases the AioContext lock once regardless of how many times the
> caller has acquired it.  This results in a hang since the IOThread does
> not make progress while the AioContext is still locked.
> 
> The following steps trigger the hang:
> 
>   $ qemu-system-x86_64 -M accel=kvm -m 1G -cpu host \
>                        -object iothread,id=iothread0 \
>                        -device virtio-scsi-pci,iothread=iothread0 \
>                        -drive if=none,id=drive0,file=test.img,format=raw \
>                        -device scsi-hd,drive=drive0 \
>                        -drive if=none,id=drive1,file=test.img,format=raw \
>                        -device scsi-hd,drive=drive1
>   $ qemu-system-x86_64 ...same options... \
>                        -incoming tcp::1234
>   (qemu) migrate tcp:127.0.0.1:1234
>   ...hang...
> 
> Tested-by: Stefan Hajnoczi <stefanha@redhat.com>
> Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
> ---
>  block.c | 14 +++++++++++---
>  1 file changed, 11 insertions(+), 3 deletions(-)
> 

Reviewed-by: Eric Blake <eblake@redhat.com>

-- 
Eric Blake, Principal Software Engineer
Red Hat, Inc.           +1-919-301-3266
Virtualization:  qemu.org | libvirt.org


[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 619 bytes --]

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [Qemu-devel] [PATCH v2 2/6] docs: mark nested AioContext locking as a legacy API
  2017-12-07 20:13 ` [Qemu-devel] [PATCH v2 2/6] docs: mark nested AioContext locking as a legacy API Stefan Hajnoczi
@ 2017-12-07 22:34   ` Eric Blake
  0 siblings, 0 replies; 15+ messages in thread
From: Eric Blake @ 2017-12-07 22:34 UTC (permalink / raw)
  To: Stefan Hajnoczi, qemu-devel; +Cc: qemu-block, Kevin Wolf, Paolo Bonzini

[-- Attachment #1: Type: text/plain, Size: 473 bytes --]

On 12/07/2017 02:13 PM, Stefan Hajnoczi wrote:
> See the patch for why nested AioContext locking is no longer allowed.
> 
> Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
> ---
>  docs/devel/multiple-iothreads.txt | 7 ++++---
>  1 file changed, 4 insertions(+), 3 deletions(-)
> 

Reviewed-by: Eric Blake <eblake@redhat.com>

-- 
Eric Blake, Principal Software Engineer
Red Hat, Inc.           +1-919-301-3266
Virtualization:  qemu.org | libvirt.org


[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 619 bytes --]

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [Qemu-devel] [PATCH v2 3/6] blockdev: add x-blockdev-set-iothread force boolean
  2017-12-07 20:13 ` [Qemu-devel] [PATCH v2 3/6] blockdev: add x-blockdev-set-iothread force boolean Stefan Hajnoczi
@ 2017-12-07 22:38   ` Eric Blake
  0 siblings, 0 replies; 15+ messages in thread
From: Eric Blake @ 2017-12-07 22:38 UTC (permalink / raw)
  To: Stefan Hajnoczi, qemu-devel; +Cc: qemu-block, Kevin Wolf, Paolo Bonzini

[-- Attachment #1: Type: text/plain, Size: 859 bytes --]

On 12/07/2017 02:13 PM, Stefan Hajnoczi wrote:
> When a node is already associated with a BlockBackend the
> x-blockdev-set-iothread command refuses to set the IOThread.  This is to
> prevent accidentally changing the IOThread when the nodes are in use.
> 
> When the nodes are created with -drive they automatically get a
> BlockBackend.  In that case we know nothing is using them yet and it's
> safe to set the IOThread.  Add a force boolean to override the check.
> 
> Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
> ---
>  qapi/block-core.json |  6 +++++-
>  blockdev.c           | 11 ++++++-----
>  2 files changed, 11 insertions(+), 6 deletions(-)
> 

Reviewed-by: Eric Blake <eblake@redhat.com>

-- 
Eric Blake, Principal Software Engineer
Red Hat, Inc.           +1-919-301-3266
Virtualization:  qemu.org | libvirt.org


[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 619 bytes --]

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [Qemu-devel] [PATCH v2 4/6] iotests: add VM.add_object()
  2017-12-07 20:13 ` [Qemu-devel] [PATCH v2 4/6] iotests: add VM.add_object() Stefan Hajnoczi
@ 2017-12-07 22:39   ` Eric Blake
  0 siblings, 0 replies; 15+ messages in thread
From: Eric Blake @ 2017-12-07 22:39 UTC (permalink / raw)
  To: Stefan Hajnoczi, qemu-devel; +Cc: qemu-block, Kevin Wolf, Paolo Bonzini

[-- Attachment #1: Type: text/plain, Size: 467 bytes --]

On 12/07/2017 02:13 PM, Stefan Hajnoczi wrote:
> The VM.add_object() method can be used to add IOThreads or memory
> backend objects.
> 
> Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
> ---
>  tests/qemu-iotests/iotests.py | 5 +++++
>  1 file changed, 5 insertions(+)
> 

Reviewed-by: Eric Blake <eblake@redhat.com>

-- 
Eric Blake, Principal Software Engineer
Red Hat, Inc.           +1-919-301-3266
Virtualization:  qemu.org | libvirt.org


[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 619 bytes --]

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [Qemu-devel] [PATCH v2 5/6] iothread: fix iothread_stop() race condition
  2017-12-07 20:13 ` [Qemu-devel] [PATCH v2 5/6] iothread: fix iothread_stop() race condition Stefan Hajnoczi
@ 2017-12-07 22:42   ` Eric Blake
  0 siblings, 0 replies; 15+ messages in thread
From: Eric Blake @ 2017-12-07 22:42 UTC (permalink / raw)
  To: Stefan Hajnoczi, qemu-devel; +Cc: qemu-block, Kevin Wolf, Paolo Bonzini

[-- Attachment #1: Type: text/plain, Size: 1430 bytes --]

On 12/07/2017 02:13 PM, Stefan Hajnoczi wrote:
> There is a small chance that iothread_stop() hangs as follows:
> 

> 
> The bug is explained by the AioContext->notify_me doc comments:
> 
>   "If this field is 0, everything (file descriptors, bottom halves,
>   timers) will be re-evaluated before the next blocking poll(), thus the
>   event_notifier_set call can be skipped."
> 
> The problem is that "everything" does not include checking
> iothread->stopping.  This means iothread_run() will block in aio_poll()
> if aio_notify() was called just before aio_poll().
> 
> This patch fixes the hang by replacing aio_notify() with
> aio_bh_schedule_oneshot().  This makes aio_poll() or g_main_loop_run()
> to return.

s/to //

> 
> Implementing this properly required a new bool running flag.  The new
> flag prevents races that are tricky if we try to use iothread->stopping.
> Now iothread->stopping is purely for iothread_stop() and
> iothread->running is purely for the iothread_run() thread.
> 
> Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
> ---
> I'm including this patch in this series because it is needed to make the
> test case reliable.  It's unrelated to the main goal of the patch
> series.
> ---
Reviewed-by: Eric Blake <eblake@redhat.com>

-- 
Eric Blake, Principal Software Engineer
Red Hat, Inc.           +1-919-301-3266
Virtualization:  qemu.org | libvirt.org


[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 619 bytes --]

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [Qemu-devel] [PATCH v2 6/6] qemu-iotests: add 203 savevm with IOThreads test
  2017-12-07 20:13 ` [Qemu-devel] [PATCH v2 6/6] qemu-iotests: add 203 savevm with IOThreads test Stefan Hajnoczi
@ 2017-12-07 22:46   ` Eric Blake
  0 siblings, 0 replies; 15+ messages in thread
From: Eric Blake @ 2017-12-07 22:46 UTC (permalink / raw)
  To: Stefan Hajnoczi, qemu-devel; +Cc: qemu-block, Kevin Wolf, Paolo Bonzini

[-- Attachment #1: Type: text/plain, Size: 780 bytes --]

On 12/07/2017 02:13 PM, Stefan Hajnoczi wrote:
> This test case will prevent future regressions with savevm and
> IOThreads.
> 
> Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
> ---
>  tests/qemu-iotests/203     | 59 ++++++++++++++++++++++++++++++++++++++++++++++
>  tests/qemu-iotests/203.out |  6 +++++
>  tests/qemu-iotests/group   |  1 +
>  3 files changed, 66 insertions(+)
>  create mode 100755 tests/qemu-iotests/203
>  create mode 100644 tests/qemu-iotests/203.out
> 

> +#
> +# Creator/Owner: Stefan Hajnoczi <stefanha@redhat.com>

Again, not sure we need this line.

Reviewed-by: Eric Blake <eblake@redhat.com>

-- 
Eric Blake, Principal Software Engineer
Red Hat, Inc.           +1-919-301-3266
Virtualization:  qemu.org | libvirt.org


[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 619 bytes --]

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [Qemu-devel] [PATCH v2 0/6] block: avoid recursive AioContext acquire in bdrv_inactivate_all()
  2017-12-07 20:13 [Qemu-devel] [PATCH v2 0/6] block: avoid recursive AioContext acquire in bdrv_inactivate_all() Stefan Hajnoczi
                   ` (5 preceding siblings ...)
  2017-12-07 20:13 ` [Qemu-devel] [PATCH v2 6/6] qemu-iotests: add 203 savevm with IOThreads test Stefan Hajnoczi
@ 2017-12-13 21:23 ` Paolo Bonzini
  2017-12-14 11:12 ` Stefan Hajnoczi
  7 siblings, 0 replies; 15+ messages in thread
From: Paolo Bonzini @ 2017-12-13 21:23 UTC (permalink / raw)
  To: Stefan Hajnoczi, qemu-devel; +Cc: Kevin Wolf, qemu-block

On 07/12/2017 21:13, Stefan Hajnoczi wrote:
> v2:
>  * Added docs/devel/multiple-iothreads.txt doc update [Kevin]
>  * Added qemu-iotests 203 test case [Kevin]
>  * Added iothread_stop() race fix to make 203 reliable
> 
> Patch 1 is Paolo's recursive locking removal in bdrv_inactivate_all().  This
> solve migration hangs and is the main point of the patch series.
> 
> Patches 2-6 add a qemu-iotests test case and update the multiple-iothreads.txt
> documentation to discourage recursive AioContext locking.
> 
> Based-on: <20171206144550.22295-1-stefanha@redhat.com>
> 
> Paolo Bonzini (1):
>   block: avoid recursive AioContext acquire in bdrv_inactivate_all()
> 
> Stefan Hajnoczi (5):
>   docs: mark nested AioContext locking as a legacy API
>   blockdev: add x-blockdev-set-iothread force boolean
>   iotests: add VM.add_object()
>   iothread: fix iothread_stop() race condition
>   qemu-iotests: add 203 savevm with IOThreads test
> 
>  docs/devel/multiple-iothreads.txt |  7 +++--
>  qapi/block-core.json              |  6 +++-
>  include/sysemu/iothread.h         |  3 +-
>  block.c                           | 14 ++++++++--
>  blockdev.c                        | 11 ++++----
>  iothread.c                        | 20 +++++++++----
>  tests/qemu-iotests/203            | 59 +++++++++++++++++++++++++++++++++++++++
>  tests/qemu-iotests/203.out        |  6 ++++
>  tests/qemu-iotests/group          |  1 +
>  tests/qemu-iotests/iotests.py     |  5 ++++
>  10 files changed, 114 insertions(+), 18 deletions(-)
>  create mode 100755 tests/qemu-iotests/203
>  create mode 100644 tests/qemu-iotests/203.out
> 

Reviewed-by: Paolo Bonzini <pbonzini@redhat.com>

aio_notify should also be put on the blacklist of things that have
slowly become bad ideas. :|

Paolo

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [Qemu-devel] [PATCH v2 0/6] block: avoid recursive AioContext acquire in bdrv_inactivate_all()
  2017-12-07 20:13 [Qemu-devel] [PATCH v2 0/6] block: avoid recursive AioContext acquire in bdrv_inactivate_all() Stefan Hajnoczi
                   ` (6 preceding siblings ...)
  2017-12-13 21:23 ` [Qemu-devel] [PATCH v2 0/6] block: avoid recursive AioContext acquire in bdrv_inactivate_all() Paolo Bonzini
@ 2017-12-14 11:12 ` Stefan Hajnoczi
  7 siblings, 0 replies; 15+ messages in thread
From: Stefan Hajnoczi @ 2017-12-14 11:12 UTC (permalink / raw)
  To: qemu-devel; +Cc: qemu-block, Eric Blake, Kevin Wolf, Paolo Bonzini

[-- Attachment #1: Type: text/plain, Size: 1800 bytes --]

On Thu, Dec 07, 2017 at 08:13:14PM +0000, Stefan Hajnoczi wrote:
> v2:
>  * Added docs/devel/multiple-iothreads.txt doc update [Kevin]
>  * Added qemu-iotests 203 test case [Kevin]
>  * Added iothread_stop() race fix to make 203 reliable
> 
> Patch 1 is Paolo's recursive locking removal in bdrv_inactivate_all().  This
> solve migration hangs and is the main point of the patch series.
> 
> Patches 2-6 add a qemu-iotests test case and update the multiple-iothreads.txt
> documentation to discourage recursive AioContext locking.
> 
> Based-on: <20171206144550.22295-1-stefanha@redhat.com>
> 
> Paolo Bonzini (1):
>   block: avoid recursive AioContext acquire in bdrv_inactivate_all()
> 
> Stefan Hajnoczi (5):
>   docs: mark nested AioContext locking as a legacy API
>   blockdev: add x-blockdev-set-iothread force boolean
>   iotests: add VM.add_object()
>   iothread: fix iothread_stop() race condition
>   qemu-iotests: add 203 savevm with IOThreads test
> 
>  docs/devel/multiple-iothreads.txt |  7 +++--
>  qapi/block-core.json              |  6 +++-
>  include/sysemu/iothread.h         |  3 +-
>  block.c                           | 14 ++++++++--
>  blockdev.c                        | 11 ++++----
>  iothread.c                        | 20 +++++++++----
>  tests/qemu-iotests/203            | 59 +++++++++++++++++++++++++++++++++++++++
>  tests/qemu-iotests/203.out        |  6 ++++
>  tests/qemu-iotests/group          |  1 +
>  tests/qemu-iotests/iotests.py     |  5 ++++
>  10 files changed, 114 insertions(+), 18 deletions(-)
>  create mode 100755 tests/qemu-iotests/203
>  create mode 100644 tests/qemu-iotests/203.out
> 
> -- 
> 2.14.3
> 

Thanks, applied to my block-next tree:
https://github.com/stefanha/qemu/commits/block-next

Stefan

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 455 bytes --]

^ permalink raw reply	[flat|nested] 15+ messages in thread

end of thread, other threads:[~2017-12-14 11:12 UTC | newest]

Thread overview: 15+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2017-12-07 20:13 [Qemu-devel] [PATCH v2 0/6] block: avoid recursive AioContext acquire in bdrv_inactivate_all() Stefan Hajnoczi
2017-12-07 20:13 ` [Qemu-devel] [PATCH v2 1/6] " Stefan Hajnoczi
2017-12-07 22:04   ` Eric Blake
2017-12-07 20:13 ` [Qemu-devel] [PATCH v2 2/6] docs: mark nested AioContext locking as a legacy API Stefan Hajnoczi
2017-12-07 22:34   ` Eric Blake
2017-12-07 20:13 ` [Qemu-devel] [PATCH v2 3/6] blockdev: add x-blockdev-set-iothread force boolean Stefan Hajnoczi
2017-12-07 22:38   ` Eric Blake
2017-12-07 20:13 ` [Qemu-devel] [PATCH v2 4/6] iotests: add VM.add_object() Stefan Hajnoczi
2017-12-07 22:39   ` Eric Blake
2017-12-07 20:13 ` [Qemu-devel] [PATCH v2 5/6] iothread: fix iothread_stop() race condition Stefan Hajnoczi
2017-12-07 22:42   ` Eric Blake
2017-12-07 20:13 ` [Qemu-devel] [PATCH v2 6/6] qemu-iotests: add 203 savevm with IOThreads test Stefan Hajnoczi
2017-12-07 22:46   ` Eric Blake
2017-12-13 21:23 ` [Qemu-devel] [PATCH v2 0/6] block: avoid recursive AioContext acquire in bdrv_inactivate_all() Paolo Bonzini
2017-12-14 11:12 ` Stefan Hajnoczi

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).