qemu-devel.nongnu.org archive mirror
 help / color / mirror / Atom feed
* [Qemu-devel] [PATCH v3 0/5] block: fix blk_aio_*() segfault when blk->root == NULL
@ 2018-02-16 16:50 Stefan Hajnoczi
  2018-02-16 16:50 ` [Qemu-devel] [PATCH v3 1/5] aio: rename aio_context_in_iothread() to in_aio_context_home_thread() Stefan Hajnoczi
                   ` (6 more replies)
  0 siblings, 7 replies; 11+ messages in thread
From: Stefan Hajnoczi @ 2018-02-16 16:50 UTC (permalink / raw)
  To: qemu-devel; +Cc: John Snow, mark.kanda, Kevin Wolf, Stefan Hajnoczi

v3:
 * Add Patch 1 to rename aio_context_in_iothread() to
   in_aio_context_home_thread() [Eric]
v2:
 * Introduce AIO_WAIT_WHILE() since aio_poll(ctx, true) is not allowed [Paolo]

Using bdrv_inc_in_flight(blk_bs(blk)) doesn't work since BlockBackend->root may
be NULL.

This patch series solves the issue by adding an BlockBackend->in_flight counter
so requests can be tracked even when there is no BlockDriverState.

This should fix the IDE and virtio-blk segfaults that have been encountered
when there is no BlockDriverState.

The patch is based on work by Kevin Wolf.

Kevin Wolf (1):
  block: test blk_aio_flush() with blk->root == NULL

Stefan Hajnoczi (4):
  aio: rename aio_context_in_iothread() to in_aio_context_home_thread()
  block: extract AIO_WAIT_WHILE() from BlockDriverState
  block: add BlockBackend->in_flight counter
  Revert "IDE: Do not flush empty CDROM drives"

 tests/Makefile.include     |   2 +
 util/Makefile.objs         |   2 +-
 include/block/aio-wait.h   | 116 +++++++++++++++++++++++++++++++++++++++++++++
 include/block/aio.h        |   7 ++-
 include/block/block.h      |  40 +++-------------
 include/block/block_int.h  |   7 ++-
 block.c                    |   7 ++-
 block/block-backend.c      |  60 ++++++++++++++++++++---
 block/io.c                 |  10 +---
 hw/ide/core.c              |  10 +---
 tests/test-block-backend.c |  82 ++++++++++++++++++++++++++++++++
 util/aio-wait.c            |  40 ++++++++++++++++
 12 files changed, 318 insertions(+), 65 deletions(-)
 create mode 100644 include/block/aio-wait.h
 create mode 100644 tests/test-block-backend.c
 create mode 100644 util/aio-wait.c

-- 
2.14.3

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

* [Qemu-devel] [PATCH v3 1/5] aio: rename aio_context_in_iothread() to in_aio_context_home_thread()
  2018-02-16 16:50 [Qemu-devel] [PATCH v3 0/5] block: fix blk_aio_*() segfault when blk->root == NULL Stefan Hajnoczi
@ 2018-02-16 16:50 ` Stefan Hajnoczi
  2018-02-16 17:20   ` Eric Blake
  2018-02-16 16:50 ` [Qemu-devel] [PATCH v3 2/5] block: extract AIO_WAIT_WHILE() from BlockDriverState Stefan Hajnoczi
                   ` (5 subsequent siblings)
  6 siblings, 1 reply; 11+ messages in thread
From: Stefan Hajnoczi @ 2018-02-16 16:50 UTC (permalink / raw)
  To: qemu-devel; +Cc: John Snow, mark.kanda, Kevin Wolf, Stefan Hajnoczi

The name aio_context_in_iothread() is misleading because it also return
true when called on the main AioContext from the main loop thread, which
is not an IOThread.

This patch renames it to in_aio_context_home_thread() and expands the
doc comment to make the semantics clearer.

Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
---
 include/block/aio.h   | 7 +++++--
 include/block/block.h | 2 +-
 2 files changed, 6 insertions(+), 3 deletions(-)

diff --git a/include/block/aio.h b/include/block/aio.h
index e9aeeaec94..fc14a2acda 100644
--- a/include/block/aio.h
+++ b/include/block/aio.h
@@ -534,11 +534,14 @@ void aio_co_enter(AioContext *ctx, struct Coroutine *co);
 AioContext *qemu_get_current_aio_context(void);
 
 /**
+ * in_aio_context_home_thread:
  * @ctx: the aio context
  *
- * Return whether we are running in the I/O thread that manages @ctx.
+ * Return whether we are running in the thread that normally runs @ctx.  Note
+ * that acquiring/releasing ctx does not affect the outcome, each AioContext
+ * still only has a one home thread that is responsible for running it.
  */
-static inline bool aio_context_in_iothread(AioContext *ctx)
+static inline bool in_aio_context_home_thread(AioContext *ctx)
 {
     return ctx == qemu_get_current_aio_context();
 }
diff --git a/include/block/block.h b/include/block/block.h
index 19b3ab9cb5..d559419722 100644
--- a/include/block/block.h
+++ b/include/block/block.h
@@ -372,7 +372,7 @@ void bdrv_drain_all(void);
     bool busy_ = true;                                     \
     BlockDriverState *bs_ = (bs);                          \
     AioContext *ctx_ = bdrv_get_aio_context(bs_);          \
-    if (aio_context_in_iothread(ctx_)) {                   \
+    if (in_aio_context_home_thread(ctx_)) {                \
         while ((cond) || busy_) {                          \
             busy_ = aio_poll(ctx_, (cond));                \
             waited_ |= !!(cond) | busy_;                   \
-- 
2.14.3

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

* [Qemu-devel] [PATCH v3 2/5] block: extract AIO_WAIT_WHILE() from BlockDriverState
  2018-02-16 16:50 [Qemu-devel] [PATCH v3 0/5] block: fix blk_aio_*() segfault when blk->root == NULL Stefan Hajnoczi
  2018-02-16 16:50 ` [Qemu-devel] [PATCH v3 1/5] aio: rename aio_context_in_iothread() to in_aio_context_home_thread() Stefan Hajnoczi
@ 2018-02-16 16:50 ` Stefan Hajnoczi
  2018-02-16 17:28   ` Eric Blake
  2018-02-16 16:50 ` [Qemu-devel] [PATCH v3 3/5] block: add BlockBackend->in_flight counter Stefan Hajnoczi
                   ` (4 subsequent siblings)
  6 siblings, 1 reply; 11+ messages in thread
From: Stefan Hajnoczi @ 2018-02-16 16:50 UTC (permalink / raw)
  To: qemu-devel; +Cc: John Snow, mark.kanda, Kevin Wolf, Stefan Hajnoczi

BlockDriverState has the BDRV_POLL_WHILE() macro to wait on event loop
activity while a condition evaluates to true.  This is used to implement
synchronous operations where it acts as a condvar between the IOThread
running the operation and the main loop waiting for the operation.  It
can also be called from the thread that owns the AioContext and in that
case it's just a nested event loop.

BlockBackend needs this behavior but doesn't always have a
BlockDriverState it can use.  This patch extracts BDRV_POLL_WHILE() into
the AioWait abstraction, which can be used with AioContext and isn't
tied to BlockDriverState anymore.

This feature could be built directly into AioContext but then all users
would kick the event loop even if they signal different conditions.
Imagine an AioContext with many BlockDriverStates, each time a request
completes any waiter would wake up and re-check their condition.  It's
nicer to keep a separate AioWait object for each condition instead.

Please see "block/aio-wait.h" for details on the API.

The name AIO_WAIT_WHILE() avoids the confusion between AIO_POLL_WHILE()
and AioContext polling.

Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
---
 util/Makefile.objs        |   2 +-
 include/block/aio-wait.h  | 116 ++++++++++++++++++++++++++++++++++++++++++++++
 include/block/block.h     |  40 +++-------------
 include/block/block_int.h |   7 ++-
 block.c                   |   5 ++
 block/io.c                |  10 +---
 util/aio-wait.c           |  40 ++++++++++++++++
 7 files changed, 174 insertions(+), 46 deletions(-)
 create mode 100644 include/block/aio-wait.h
 create mode 100644 util/aio-wait.c

diff --git a/util/Makefile.objs b/util/Makefile.objs
index 3fb611631f..ae90b9963d 100644
--- a/util/Makefile.objs
+++ b/util/Makefile.objs
@@ -1,7 +1,7 @@
 util-obj-y = osdep.o cutils.o unicode.o qemu-timer-common.o
 util-obj-y += bufferiszero.o
 util-obj-y += lockcnt.o
-util-obj-y += aiocb.o async.o thread-pool.o qemu-timer.o
+util-obj-y += aiocb.o async.o aio-wait.o thread-pool.o qemu-timer.o
 util-obj-y += main-loop.o iohandler.o
 util-obj-$(CONFIG_POSIX) += aio-posix.o
 util-obj-$(CONFIG_POSIX) += compatfd.o
diff --git a/include/block/aio-wait.h b/include/block/aio-wait.h
new file mode 100644
index 0000000000..a48c744fa8
--- /dev/null
+++ b/include/block/aio-wait.h
@@ -0,0 +1,116 @@
+/*
+ * AioContext wait support
+ *
+ * Copyright (C) 2018 Red Hat, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#ifndef QEMU_AIO_WAIT_H
+#define QEMU_AIO_WAIT_H
+
+#include "block/aio.h"
+
+/**
+ * AioWait:
+ *
+ * An object that facilitates synchronous waiting on a condition.  The main
+ * loop can wait on an operation running in an IOThread as follows:
+ *
+ *   AioWait *wait = ...;
+ *   AioContext *ctx = ...;
+ *   MyWork work = { .done = false };
+ *   schedule_my_work_in_iothread(ctx, &work);
+ *   AIO_WAIT_WHILE(wait, ctx, !work.done);
+ *
+ * The IOThread must call aio_wait_kick() to notify the main loop when
+ * work.done changes:
+ *
+ *   static void do_work(...)
+ *   {
+ *       ...
+ *       work.done = true;
+ *       aio_wait_kick(wait);
+ *   }
+ */
+typedef struct {
+    /* Is the main loop waiting for a kick?  Accessed with atomic ops. */
+    bool need_kick;
+} AioWait;
+
+/**
+ * AIO_WAIT_WHILE:
+ * @wait: the aio wait object
+ * @ctx: the aio context
+ * @cond: wait while this conditional expression is true
+ *
+ * Wait while a condition is true.  Use this to implement synchronous
+ * operations that require event loop activity.
+ *
+ * The caller must be sure that something calls aio_wait_kick() when the value
+ * of @cond might have changed.
+ *
+ * The caller's thread must be the IOThread that owns @ctx or the main loop
+ * thread (with @ctx acquired exactly once).  This function cannot be used to
+ * wait on conditions between two IOThreads since that could lead to deadlock,
+ * go via the main loop instead.
+ */
+#define AIO_WAIT_WHILE(wait, ctx, cond) ({                  \
+    bool waited_ = false;                                   \
+    bool busy_ = true;                                      \
+    AioWait *wait_ = (wait);                                \
+    AioContext *ctx_ = (ctx);                               \
+    if (in_aio_context_home_thread(ctx_)) {                 \
+        while ((cond) || busy_) {                           \
+            busy_ = aio_poll(ctx_, (cond));                 \
+            waited_ |= !!(cond) | busy_;                    \
+        }                                                   \
+    } else {                                                \
+        assert(qemu_get_current_aio_context() ==            \
+               qemu_get_aio_context());                     \
+        assert(!wait_->need_kick);                          \
+        /* Set wait_->need_kick before evaluating cond.  */ \
+        atomic_mb_set(&wait_->need_kick, true);             \
+        while (busy_) {                                     \
+            if ((cond)) {                                   \
+                waited_ = busy_ = true;                     \
+                aio_context_release(ctx_);                  \
+                aio_poll(qemu_get_aio_context(), true);     \
+                aio_context_acquire(ctx_);                  \
+            } else {                                        \
+                busy_ = aio_poll(ctx_, false);              \
+                waited_ |= busy_;                           \
+            }                                               \
+        }                                                   \
+        atomic_set(&wait_->need_kick, false);               \
+    }                                                       \
+    waited_; })
+
+/**
+ * aio_wait_kick:
+ * @wait: the aio wait object that should re-evaluate its condition
+ *
+ * Wake up the main thread if it is waiting on AIO_WAIT_WHILE().  During
+ * synchronous operations performed in an IOThread, the main thread lets the
+ * IOThread's event loop run, waiting for the operation to complete.  A
+ * aio_wait_kick() call will wake up the main thread.
+ */
+void aio_wait_kick(AioWait *wait);
+
+#endif /* QEMU_AIO_WAIT */
diff --git a/include/block/block.h b/include/block/block.h
index d559419722..c4beda33a8 100644
--- a/include/block/block.h
+++ b/include/block/block.h
@@ -2,6 +2,7 @@
 #define BLOCK_H
 
 #include "block/aio.h"
+#include "block/aio-wait.h"
 #include "qapi-types.h"
 #include "qemu/iov.h"
 #include "qemu/coroutine.h"
@@ -367,41 +368,14 @@ void bdrv_drain_all_begin(void);
 void bdrv_drain_all_end(void);
 void bdrv_drain_all(void);
 
+/* Returns NULL when bs == NULL */
+AioWait *bdrv_get_aio_wait(BlockDriverState *bs);
+
 #define BDRV_POLL_WHILE(bs, cond) ({                       \
-    bool waited_ = false;                                  \
-    bool busy_ = true;                                     \
     BlockDriverState *bs_ = (bs);                          \
-    AioContext *ctx_ = bdrv_get_aio_context(bs_);          \
-    if (in_aio_context_home_thread(ctx_)) {                \
-        while ((cond) || busy_) {                          \
-            busy_ = aio_poll(ctx_, (cond));                \
-            waited_ |= !!(cond) | busy_;                   \
-        }                                                  \
-    } else {                                               \
-        assert(qemu_get_current_aio_context() ==           \
-               qemu_get_aio_context());                    \
-        /* Ask bdrv_dec_in_flight to wake up the main      \
-         * QEMU AioContext.  Extra I/O threads never take  \
-         * other I/O threads' AioContexts (see for example \
-         * block_job_defer_to_main_loop for how to do it). \
-         */                                                \
-        assert(!bs_->wakeup);                              \
-        /* Set bs->wakeup before evaluating cond.  */      \
-        atomic_mb_set(&bs_->wakeup, true);                 \
-        while (busy_) {                                    \
-            if ((cond)) {                                  \
-                waited_ = busy_ = true;                    \
-                aio_context_release(ctx_);                 \
-                aio_poll(qemu_get_aio_context(), true);    \
-                aio_context_acquire(ctx_);                 \
-            } else {                                       \
-                busy_ = aio_poll(ctx_, false);             \
-                waited_ |= busy_;                          \
-            }                                              \
-        }                                                  \
-        atomic_set(&bs_->wakeup, false);                   \
-    }                                                      \
-    waited_; })
+    AIO_WAIT_WHILE(bdrv_get_aio_wait(bs_),                 \
+                   bdrv_get_aio_context(bs_),              \
+                   cond); })
 
 int bdrv_pdiscard(BlockDriverState *bs, int64_t offset, int bytes);
 int bdrv_co_pdiscard(BlockDriverState *bs, int64_t offset, int bytes);
diff --git a/include/block/block_int.h b/include/block/block_int.h
index 5ea63f8fa8..c1f6ee961a 100644
--- a/include/block/block_int.h
+++ b/include/block/block_int.h
@@ -26,6 +26,7 @@
 
 #include "block/accounting.h"
 #include "block/block.h"
+#include "block/aio-wait.h"
 #include "qemu/queue.h"
 #include "qemu/coroutine.h"
 #include "qemu/stats64.h"
@@ -709,10 +710,8 @@ struct BlockDriverState {
     unsigned int in_flight;
     unsigned int serialising_in_flight;
 
-    /* Internal to BDRV_POLL_WHILE and bdrv_wakeup.  Accessed with atomic
-     * ops.
-     */
-    bool wakeup;
+    /* Kicked to signal main loop when a request completes. */
+    AioWait wait;
 
     /* counter for nested bdrv_io_plug.
      * Accessed with atomic ops.
diff --git a/block.c b/block.c
index 814e5a02da..9e4da81213 100644
--- a/block.c
+++ b/block.c
@@ -4716,6 +4716,11 @@ AioContext *bdrv_get_aio_context(BlockDriverState *bs)
     return bs->aio_context;
 }
 
+AioWait *bdrv_get_aio_wait(BlockDriverState *bs)
+{
+    return bs ? &bs->wait : NULL;
+}
+
 void bdrv_coroutine_enter(BlockDriverState *bs, Coroutine *co)
 {
     aio_co_enter(bdrv_get_aio_context(bs), co);
diff --git a/block/io.c b/block/io.c
index 89d0745e95..69170ee234 100644
--- a/block/io.c
+++ b/block/io.c
@@ -25,6 +25,7 @@
 #include "qemu/osdep.h"
 #include "trace.h"
 #include "sysemu/block-backend.h"
+#include "block/aio-wait.h"
 #include "block/blockjob.h"
 #include "block/blockjob_int.h"
 #include "block/block_int.h"
@@ -587,16 +588,9 @@ void bdrv_inc_in_flight(BlockDriverState *bs)
     atomic_inc(&bs->in_flight);
 }
 
-static void dummy_bh_cb(void *opaque)
-{
-}
-
 void bdrv_wakeup(BlockDriverState *bs)
 {
-    /* The barrier (or an atomic op) is in the caller.  */
-    if (atomic_read(&bs->wakeup)) {
-        aio_bh_schedule_oneshot(qemu_get_aio_context(), dummy_bh_cb, NULL);
-    }
+    aio_wait_kick(bdrv_get_aio_wait(bs));
 }
 
 void bdrv_dec_in_flight(BlockDriverState *bs)
diff --git a/util/aio-wait.c b/util/aio-wait.c
new file mode 100644
index 0000000000..a487cdb852
--- /dev/null
+++ b/util/aio-wait.c
@@ -0,0 +1,40 @@
+/*
+ * AioContext wait support
+ *
+ * Copyright (C) 2018 Red Hat, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "qemu/osdep.h"
+#include "qemu/main-loop.h"
+#include "block/aio-wait.h"
+
+static void dummy_bh_cb(void *opaque)
+{
+    /* The point is to make AIO_WAIT_WHILE()'s aio_poll() return */
+}
+
+void aio_wait_kick(AioWait *wait)
+{
+    /* The barrier (or an atomic op) is in the caller.  */
+    if (atomic_read(&wait->need_kick)) {
+        aio_bh_schedule_oneshot(qemu_get_aio_context(), dummy_bh_cb, NULL);
+    }
+}
-- 
2.14.3

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

* [Qemu-devel] [PATCH v3 3/5] block: add BlockBackend->in_flight counter
  2018-02-16 16:50 [Qemu-devel] [PATCH v3 0/5] block: fix blk_aio_*() segfault when blk->root == NULL Stefan Hajnoczi
  2018-02-16 16:50 ` [Qemu-devel] [PATCH v3 1/5] aio: rename aio_context_in_iothread() to in_aio_context_home_thread() Stefan Hajnoczi
  2018-02-16 16:50 ` [Qemu-devel] [PATCH v3 2/5] block: extract AIO_WAIT_WHILE() from BlockDriverState Stefan Hajnoczi
@ 2018-02-16 16:50 ` Stefan Hajnoczi
  2018-02-16 16:50 ` [Qemu-devel] [PATCH v3 4/5] block: test blk_aio_flush() with blk->root == NULL Stefan Hajnoczi
                   ` (3 subsequent siblings)
  6 siblings, 0 replies; 11+ messages in thread
From: Stefan Hajnoczi @ 2018-02-16 16:50 UTC (permalink / raw)
  To: qemu-devel; +Cc: John Snow, mark.kanda, Kevin Wolf, Stefan Hajnoczi

BlockBackend currently relies on BlockDriverState->in_flight to track
requests for blk_drain().  There is a corner case where
BlockDriverState->in_flight cannot be used though: blk->root can be NULL
when there is no medium.  This results in a segfault when the NULL
pointer is dereferenced.

Introduce a BlockBackend->in_flight counter for aio requests so it works
even when blk->root == NULL.

Based on a patch by Kevin Wolf <kwolf@redhat.com>.

Signed-off-by: Kevin Wolf <kwolf@redhat.com>
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
---
 block.c               |  2 +-
 block/block-backend.c | 60 +++++++++++++++++++++++++++++++++++++++++++++------
 2 files changed, 54 insertions(+), 8 deletions(-)

diff --git a/block.c b/block.c
index 9e4da81213..a83037c2a5 100644
--- a/block.c
+++ b/block.c
@@ -4713,7 +4713,7 @@ out:
 
 AioContext *bdrv_get_aio_context(BlockDriverState *bs)
 {
-    return bs->aio_context;
+    return bs ? bs->aio_context : qemu_get_aio_context();
 }
 
 AioWait *bdrv_get_aio_wait(BlockDriverState *bs)
diff --git a/block/block-backend.c b/block/block-backend.c
index 0266ac990b..a775a3dd2f 100644
--- a/block/block-backend.c
+++ b/block/block-backend.c
@@ -73,6 +73,14 @@ struct BlockBackend {
     int quiesce_counter;
     VMChangeStateEntry *vmsh;
     bool force_allow_inactivate;
+
+    /* Number of in-flight aio requests.  BlockDriverState also counts
+     * in-flight requests but aio requests can exist even when blk->root is
+     * NULL, so we cannot rely on its counter for that case.
+     * Accessed with atomic ops.
+     */
+    unsigned int in_flight;
+    AioWait wait;
 };
 
 typedef struct BlockBackendAIOCB {
@@ -1225,11 +1233,22 @@ int blk_make_zero(BlockBackend *blk, BdrvRequestFlags flags)
     return bdrv_make_zero(blk->root, flags);
 }
 
+static void blk_inc_in_flight(BlockBackend *blk)
+{
+    atomic_inc(&blk->in_flight);
+}
+
+static void blk_dec_in_flight(BlockBackend *blk)
+{
+    atomic_dec(&blk->in_flight);
+    aio_wait_kick(&blk->wait);
+}
+
 static void error_callback_bh(void *opaque)
 {
     struct BlockBackendAIOCB *acb = opaque;
 
-    bdrv_dec_in_flight(acb->common.bs);
+    blk_dec_in_flight(acb->blk);
     acb->common.cb(acb->common.opaque, acb->ret);
     qemu_aio_unref(acb);
 }
@@ -1240,7 +1259,7 @@ BlockAIOCB *blk_abort_aio_request(BlockBackend *blk,
 {
     struct BlockBackendAIOCB *acb;
 
-    bdrv_inc_in_flight(blk_bs(blk));
+    blk_inc_in_flight(blk);
     acb = blk_aio_get(&block_backend_aiocb_info, blk, cb, opaque);
     acb->blk = blk;
     acb->ret = ret;
@@ -1263,7 +1282,7 @@ static const AIOCBInfo blk_aio_em_aiocb_info = {
 static void blk_aio_complete(BlkAioEmAIOCB *acb)
 {
     if (acb->has_returned) {
-        bdrv_dec_in_flight(acb->common.bs);
+        blk_dec_in_flight(acb->rwco.blk);
         acb->common.cb(acb->common.opaque, acb->rwco.ret);
         qemu_aio_unref(acb);
     }
@@ -1284,7 +1303,7 @@ static BlockAIOCB *blk_aio_prwv(BlockBackend *blk, int64_t offset, int bytes,
     BlkAioEmAIOCB *acb;
     Coroutine *co;
 
-    bdrv_inc_in_flight(blk_bs(blk));
+    blk_inc_in_flight(blk);
     acb = blk_aio_get(&blk_aio_em_aiocb_info, blk, cb, opaque);
     acb->rwco = (BlkRwCo) {
         .blk    = blk,
@@ -1521,14 +1540,41 @@ int blk_flush(BlockBackend *blk)
 
 void blk_drain(BlockBackend *blk)
 {
-    if (blk_bs(blk)) {
-        bdrv_drain(blk_bs(blk));
+    BlockDriverState *bs = blk_bs(blk);
+
+    if (bs) {
+        bdrv_drained_begin(bs);
+    }
+
+    /* We may have -ENOMEDIUM completions in flight */
+    AIO_WAIT_WHILE(&blk->wait,
+            blk_get_aio_context(blk),
+            atomic_mb_read(&blk->in_flight) > 0);
+
+    if (bs) {
+        bdrv_drained_end(bs);
     }
 }
 
 void blk_drain_all(void)
 {
-    bdrv_drain_all();
+    BlockBackend *blk = NULL;
+
+    bdrv_drain_all_begin();
+
+    while ((blk = blk_all_next(blk)) != NULL) {
+        AioContext *ctx = blk_get_aio_context(blk);
+
+        aio_context_acquire(ctx);
+
+        /* We may have -ENOMEDIUM completions in flight */
+        AIO_WAIT_WHILE(&blk->wait, ctx,
+                atomic_mb_read(&blk->in_flight) > 0);
+
+        aio_context_release(ctx);
+    }
+
+    bdrv_drain_all_end();
 }
 
 void blk_set_on_error(BlockBackend *blk, BlockdevOnError on_read_error,
-- 
2.14.3

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

* [Qemu-devel] [PATCH v3 4/5] block: test blk_aio_flush() with blk->root == NULL
  2018-02-16 16:50 [Qemu-devel] [PATCH v3 0/5] block: fix blk_aio_*() segfault when blk->root == NULL Stefan Hajnoczi
                   ` (2 preceding siblings ...)
  2018-02-16 16:50 ` [Qemu-devel] [PATCH v3 3/5] block: add BlockBackend->in_flight counter Stefan Hajnoczi
@ 2018-02-16 16:50 ` Stefan Hajnoczi
  2018-02-16 16:50 ` [Qemu-devel] [PATCH v3 5/5] Revert "IDE: Do not flush empty CDROM drives" Stefan Hajnoczi
                   ` (2 subsequent siblings)
  6 siblings, 0 replies; 11+ messages in thread
From: Stefan Hajnoczi @ 2018-02-16 16:50 UTC (permalink / raw)
  To: qemu-devel; +Cc: John Snow, mark.kanda, Kevin Wolf, Stefan Hajnoczi

From: Kevin Wolf <kwolf@redhat.com>

This patch adds test cases for the scenario where blk_aio_flush() is
called on a BlockBackend with no root.  Calling drain afterwards should
complete the requests with -ENOMEDIUM.

Signed-off-by: Kevin Wolf <kwolf@redhat.com>
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
Reviewed-by: Eric Blake <eblake@redhat.com>
---
 tests/Makefile.include     |  2 ++
 tests/test-block-backend.c | 82 ++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 84 insertions(+)
 create mode 100644 tests/test-block-backend.c

diff --git a/tests/Makefile.include b/tests/Makefile.include
index a1bcbffe12..c15cb2dca4 100644
--- a/tests/Makefile.include
+++ b/tests/Makefile.include
@@ -83,6 +83,7 @@ gcov-files-test-hbitmap-y = blockjob.c
 check-unit-y += tests/test-bdrv-drain$(EXESUF)
 check-unit-y += tests/test-blockjob$(EXESUF)
 check-unit-y += tests/test-blockjob-txn$(EXESUF)
+check-unit-y += tests/test-block-backend$(EXESUF)
 check-unit-y += tests/test-x86-cpuid$(EXESUF)
 # all code tested by test-x86-cpuid is inside topology.h
 gcov-files-test-x86-cpuid-y =
@@ -612,6 +613,7 @@ tests/test-throttle$(EXESUF): tests/test-throttle.o $(test-block-obj-y)
 tests/test-bdrv-drain$(EXESUF): tests/test-bdrv-drain.o $(test-block-obj-y) $(test-util-obj-y)
 tests/test-blockjob$(EXESUF): tests/test-blockjob.o $(test-block-obj-y) $(test-util-obj-y)
 tests/test-blockjob-txn$(EXESUF): tests/test-blockjob-txn.o $(test-block-obj-y) $(test-util-obj-y)
+tests/test-block-backend$(EXESUF): tests/test-block-backend.o $(test-block-obj-y) $(test-util-obj-y)
 tests/test-thread-pool$(EXESUF): tests/test-thread-pool.o $(test-block-obj-y)
 tests/test-iov$(EXESUF): tests/test-iov.o $(test-util-obj-y)
 tests/test-hbitmap$(EXESUF): tests/test-hbitmap.o $(test-util-obj-y) $(test-crypto-obj-y)
diff --git a/tests/test-block-backend.c b/tests/test-block-backend.c
new file mode 100644
index 0000000000..fd59f02bd0
--- /dev/null
+++ b/tests/test-block-backend.c
@@ -0,0 +1,82 @@
+/*
+ * BlockBackend tests
+ *
+ * Copyright (c) 2017 Kevin Wolf <kwolf@redhat.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "qemu/osdep.h"
+#include "block/block.h"
+#include "sysemu/block-backend.h"
+#include "qapi/error.h"
+
+static void test_drain_aio_error_flush_cb(void *opaque, int ret)
+{
+    bool *completed = opaque;
+
+    g_assert(ret == -ENOMEDIUM);
+    *completed = true;
+}
+
+static void test_drain_aio_error(void)
+{
+    BlockBackend *blk = blk_new(BLK_PERM_ALL, BLK_PERM_ALL);
+    BlockAIOCB *acb;
+    bool completed = false;
+
+    acb = blk_aio_flush(blk, test_drain_aio_error_flush_cb, &completed);
+    g_assert(acb != NULL);
+    g_assert(completed == false);
+
+    blk_drain(blk);
+    g_assert(completed == true);
+
+    blk_unref(blk);
+}
+
+static void test_drain_all_aio_error(void)
+{
+    BlockBackend *blk = blk_new(BLK_PERM_ALL, BLK_PERM_ALL);
+    BlockAIOCB *acb;
+    bool completed = false;
+
+    acb = blk_aio_flush(blk, test_drain_aio_error_flush_cb, &completed);
+    g_assert(acb != NULL);
+    g_assert(completed == false);
+
+    blk_drain_all();
+    g_assert(completed == true);
+
+    blk_unref(blk);
+}
+
+int main(int argc, char **argv)
+{
+    bdrv_init();
+    qemu_init_main_loop(&error_abort);
+
+    g_test_init(&argc, &argv, NULL);
+
+    g_test_add_func("/block-backend/drain_aio_error", test_drain_aio_error);
+    g_test_add_func("/block-backend/drain_all_aio_error",
+                    test_drain_all_aio_error);
+
+    return g_test_run();
+}
-- 
2.14.3

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

* [Qemu-devel] [PATCH v3 5/5] Revert "IDE: Do not flush empty CDROM drives"
  2018-02-16 16:50 [Qemu-devel] [PATCH v3 0/5] block: fix blk_aio_*() segfault when blk->root == NULL Stefan Hajnoczi
                   ` (3 preceding siblings ...)
  2018-02-16 16:50 ` [Qemu-devel] [PATCH v3 4/5] block: test blk_aio_flush() with blk->root == NULL Stefan Hajnoczi
@ 2018-02-16 16:50 ` Stefan Hajnoczi
  2018-02-28 15:48 ` [Qemu-devel] [PATCH v3 0/5] block: fix blk_aio_*() segfault when blk->root == NULL Stefan Hajnoczi
  2018-03-01 15:09 ` Kevin Wolf
  6 siblings, 0 replies; 11+ messages in thread
From: Stefan Hajnoczi @ 2018-02-16 16:50 UTC (permalink / raw)
  To: qemu-devel; +Cc: John Snow, mark.kanda, Kevin Wolf, Stefan Hajnoczi

This reverts commit 4da97120d51a4383aa96d741a2b837f8c4bbcd0b.

blk_aio_flush() now handles the blk->root == NULL case, so we no longer
need this workaround.

Cc: John Snow <jsnow@redhat.com>
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
Reviewed-by: Eric Blake <eblake@redhat.com>
---
 hw/ide/core.c | 10 +---------
 1 file changed, 1 insertion(+), 9 deletions(-)

diff --git a/hw/ide/core.c b/hw/ide/core.c
index 257b429381..139c843514 100644
--- a/hw/ide/core.c
+++ b/hw/ide/core.c
@@ -1087,15 +1087,7 @@ static void ide_flush_cache(IDEState *s)
     s->status |= BUSY_STAT;
     ide_set_retry(s);
     block_acct_start(blk_get_stats(s->blk), &s->acct, 0, BLOCK_ACCT_FLUSH);
-
-    if (blk_bs(s->blk)) {
-        s->pio_aiocb = blk_aio_flush(s->blk, ide_flush_cb, s);
-    } else {
-        /* XXX blk_aio_flush() crashes when blk_bs(blk) is NULL, remove this
-         * temporary workaround when blk_aio_*() functions handle NULL blk_bs.
-         */
-        ide_flush_cb(s, 0);
-    }
+    s->pio_aiocb = blk_aio_flush(s->blk, ide_flush_cb, s);
 }
 
 static void ide_cfata_metadata_inquiry(IDEState *s)
-- 
2.14.3

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

* Re: [Qemu-devel] [PATCH v3 1/5] aio: rename aio_context_in_iothread() to in_aio_context_home_thread()
  2018-02-16 16:50 ` [Qemu-devel] [PATCH v3 1/5] aio: rename aio_context_in_iothread() to in_aio_context_home_thread() Stefan Hajnoczi
@ 2018-02-16 17:20   ` Eric Blake
  0 siblings, 0 replies; 11+ messages in thread
From: Eric Blake @ 2018-02-16 17:20 UTC (permalink / raw)
  To: Stefan Hajnoczi, qemu-devel; +Cc: Kevin Wolf, John Snow

On 02/16/2018 10:50 AM, Stefan Hajnoczi wrote:
> The name aio_context_in_iothread() is misleading because it also return

s/return/returns/

> true when called on the main AioContext from the main loop thread, which
> is not an IOThread.
> 
> This patch renames it to in_aio_context_home_thread() and expands the
> doc comment to make the semantics clearer.
> 
> Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
> ---
>   include/block/aio.h   | 7 +++++--
>   include/block/block.h | 2 +-
>   2 files changed, 6 insertions(+), 3 deletions(-)
> 

>   /**
> + * in_aio_context_home_thread:
>    * @ctx: the aio context
>    *
> - * Return whether we are running in the I/O thread that manages @ctx.
> + * Return whether we are running in the thread that normally runs @ctx.  Note
> + * that acquiring/releasing ctx does not affect the outcome, each AioContext
> + * still only has a one home thread that is responsible for running it.

s/a one/one/

Typo fixes are trivial, so

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

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

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

* Re: [Qemu-devel] [PATCH v3 2/5] block: extract AIO_WAIT_WHILE() from BlockDriverState
  2018-02-16 16:50 ` [Qemu-devel] [PATCH v3 2/5] block: extract AIO_WAIT_WHILE() from BlockDriverState Stefan Hajnoczi
@ 2018-02-16 17:28   ` Eric Blake
  0 siblings, 0 replies; 11+ messages in thread
From: Eric Blake @ 2018-02-16 17:28 UTC (permalink / raw)
  To: Stefan Hajnoczi, qemu-devel; +Cc: Kevin Wolf, John Snow

On 02/16/2018 10:50 AM, Stefan Hajnoczi wrote:
> BlockDriverState has the BDRV_POLL_WHILE() macro to wait on event loop
> activity while a condition evaluates to true.  This is used to implement
> synchronous operations where it acts as a condvar between the IOThread
> running the operation and the main loop waiting for the operation.  It
> can also be called from the thread that owns the AioContext and in that
> case it's just a nested event loop.
> 
> BlockBackend needs this behavior but doesn't always have a
> BlockDriverState it can use.  This patch extracts BDRV_POLL_WHILE() into
> the AioWait abstraction, which can be used with AioContext and isn't
> tied to BlockDriverState anymore.
> 
> This feature could be built directly into AioContext but then all users
> would kick the event loop even if they signal different conditions.
> Imagine an AioContext with many BlockDriverStates, each time a request
> completes any waiter would wake up and re-check their condition.  It's
> nicer to keep a separate AioWait object for each condition instead.
> 
> Please see "block/aio-wait.h" for details on the API.
> 
> The name AIO_WAIT_WHILE() avoids the confusion between AIO_POLL_WHILE()
> and AioContext polling.
> 
> Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
> ---

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

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

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

* Re: [Qemu-devel] [PATCH v3 0/5] block: fix blk_aio_*() segfault when blk->root == NULL
  2018-02-16 16:50 [Qemu-devel] [PATCH v3 0/5] block: fix blk_aio_*() segfault when blk->root == NULL Stefan Hajnoczi
                   ` (4 preceding siblings ...)
  2018-02-16 16:50 ` [Qemu-devel] [PATCH v3 5/5] Revert "IDE: Do not flush empty CDROM drives" Stefan Hajnoczi
@ 2018-02-28 15:48 ` Stefan Hajnoczi
  2018-02-28 15:53   ` Paolo Bonzini
  2018-03-01 15:09 ` Kevin Wolf
  6 siblings, 1 reply; 11+ messages in thread
From: Stefan Hajnoczi @ 2018-02-28 15:48 UTC (permalink / raw)
  To: Stefan Hajnoczi; +Cc: qemu-devel, Kevin Wolf, John Snow, Paolo Bonzini

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

On Fri, Feb 16, 2018 at 04:50:10PM +0000, Stefan Hajnoczi wrote:
> v3:
>  * Add Patch 1 to rename aio_context_in_iothread() to
>    in_aio_context_home_thread() [Eric]
> v2:
>  * Introduce AIO_WAIT_WHILE() since aio_poll(ctx, true) is not allowed [Paolo]
> 
> Using bdrv_inc_in_flight(blk_bs(blk)) doesn't work since BlockBackend->root may
> be NULL.
> 
> This patch series solves the issue by adding an BlockBackend->in_flight counter
> so requests can be tracked even when there is no BlockDriverState.
> 
> This should fix the IDE and virtio-blk segfaults that have been encountered
> when there is no BlockDriverState.
> 
> The patch is based on work by Kevin Wolf.
> 
> Kevin Wolf (1):
>   block: test blk_aio_flush() with blk->root == NULL
> 
> Stefan Hajnoczi (4):
>   aio: rename aio_context_in_iothread() to in_aio_context_home_thread()
>   block: extract AIO_WAIT_WHILE() from BlockDriverState
>   block: add BlockBackend->in_flight counter
>   Revert "IDE: Do not flush empty CDROM drives"
> 
>  tests/Makefile.include     |   2 +
>  util/Makefile.objs         |   2 +-
>  include/block/aio-wait.h   | 116 +++++++++++++++++++++++++++++++++++++++++++++
>  include/block/aio.h        |   7 ++-
>  include/block/block.h      |  40 +++-------------
>  include/block/block_int.h  |   7 ++-
>  block.c                    |   7 ++-
>  block/block-backend.c      |  60 ++++++++++++++++++++---
>  block/io.c                 |  10 +---
>  hw/ide/core.c              |  10 +---
>  tests/test-block-backend.c |  82 ++++++++++++++++++++++++++++++++
>  util/aio-wait.c            |  40 ++++++++++++++++
>  12 files changed, 318 insertions(+), 65 deletions(-)
>  create mode 100644 include/block/aio-wait.h
>  create mode 100644 tests/test-block-backend.c
>  create mode 100644 util/aio-wait.c

Any more comments?

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

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

* Re: [Qemu-devel] [PATCH v3 0/5] block: fix blk_aio_*() segfault when blk->root == NULL
  2018-02-28 15:48 ` [Qemu-devel] [PATCH v3 0/5] block: fix blk_aio_*() segfault when blk->root == NULL Stefan Hajnoczi
@ 2018-02-28 15:53   ` Paolo Bonzini
  0 siblings, 0 replies; 11+ messages in thread
From: Paolo Bonzini @ 2018-02-28 15:53 UTC (permalink / raw)
  To: Stefan Hajnoczi, Stefan Hajnoczi; +Cc: qemu-devel, Kevin Wolf, John Snow

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

On 28/02/2018 16:48, Stefan Hajnoczi wrote:
> On Fri, Feb 16, 2018 at 04:50:10PM +0000, Stefan Hajnoczi wrote:
>> v3:
>>  * Add Patch 1 to rename aio_context_in_iothread() to
>>    in_aio_context_home_thread() [Eric]
>> v2:
>>  * Introduce AIO_WAIT_WHILE() since aio_poll(ctx, true) is not allowed [Paolo]
>>
>> Using bdrv_inc_in_flight(blk_bs(blk)) doesn't work since BlockBackend->root may
>> be NULL.
>>
>> This patch series solves the issue by adding an BlockBackend->in_flight counter
>> so requests can be tracked even when there is no BlockDriverState.
>>
>> This should fix the IDE and virtio-blk segfaults that have been encountered
>> when there is no BlockDriverState.
>>
>> The patch is based on work by Kevin Wolf.
>>
>> Kevin Wolf (1):
>>   block: test blk_aio_flush() with blk->root == NULL
>>
>> Stefan Hajnoczi (4):
>>   aio: rename aio_context_in_iothread() to in_aio_context_home_thread()
>>   block: extract AIO_WAIT_WHILE() from BlockDriverState
>>   block: add BlockBackend->in_flight counter
>>   Revert "IDE: Do not flush empty CDROM drives"
>>
>>  tests/Makefile.include     |   2 +
>>  util/Makefile.objs         |   2 +-
>>  include/block/aio-wait.h   | 116 +++++++++++++++++++++++++++++++++++++++++++++
>>  include/block/aio.h        |   7 ++-
>>  include/block/block.h      |  40 +++-------------
>>  include/block/block_int.h  |   7 ++-
>>  block.c                    |   7 ++-
>>  block/block-backend.c      |  60 ++++++++++++++++++++---
>>  block/io.c                 |  10 +---
>>  hw/ide/core.c              |  10 +---
>>  tests/test-block-backend.c |  82 ++++++++++++++++++++++++++++++++
>>  util/aio-wait.c            |  40 ++++++++++++++++
>>  12 files changed, 318 insertions(+), 65 deletions(-)
>>  create mode 100644 include/block/aio-wait.h
>>  create mode 100644 tests/test-block-backend.c
>>  create mode 100644 util/aio-wait.c
> 
> Any more comments?
> 

Not from me. :)

Paolo


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

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

* Re: [Qemu-devel] [PATCH v3 0/5] block: fix blk_aio_*() segfault when blk->root == NULL
  2018-02-16 16:50 [Qemu-devel] [PATCH v3 0/5] block: fix blk_aio_*() segfault when blk->root == NULL Stefan Hajnoczi
                   ` (5 preceding siblings ...)
  2018-02-28 15:48 ` [Qemu-devel] [PATCH v3 0/5] block: fix blk_aio_*() segfault when blk->root == NULL Stefan Hajnoczi
@ 2018-03-01 15:09 ` Kevin Wolf
  6 siblings, 0 replies; 11+ messages in thread
From: Kevin Wolf @ 2018-03-01 15:09 UTC (permalink / raw)
  To: Stefan Hajnoczi; +Cc: qemu-devel, John Snow, mark.kanda, qemu-block

Am 16.02.2018 um 17:50 hat Stefan Hajnoczi geschrieben:
> v3:
>  * Add Patch 1 to rename aio_context_in_iothread() to
>    in_aio_context_home_thread() [Eric]
> v2:
>  * Introduce AIO_WAIT_WHILE() since aio_poll(ctx, true) is not allowed [Paolo]
> 
> Using bdrv_inc_in_flight(blk_bs(blk)) doesn't work since BlockBackend->root may
> be NULL.
> 
> This patch series solves the issue by adding an BlockBackend->in_flight counter
> so requests can be tracked even when there is no BlockDriverState.
> 
> This should fix the IDE and virtio-blk segfaults that have been encountered
> when there is no BlockDriverState.
> 
> The patch is based on work by Kevin Wolf.

Thanks, applied to the block branch.

Kevin

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

end of thread, other threads:[~2018-03-01 15:09 UTC | newest]

Thread overview: 11+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2018-02-16 16:50 [Qemu-devel] [PATCH v3 0/5] block: fix blk_aio_*() segfault when blk->root == NULL Stefan Hajnoczi
2018-02-16 16:50 ` [Qemu-devel] [PATCH v3 1/5] aio: rename aio_context_in_iothread() to in_aio_context_home_thread() Stefan Hajnoczi
2018-02-16 17:20   ` Eric Blake
2018-02-16 16:50 ` [Qemu-devel] [PATCH v3 2/5] block: extract AIO_WAIT_WHILE() from BlockDriverState Stefan Hajnoczi
2018-02-16 17:28   ` Eric Blake
2018-02-16 16:50 ` [Qemu-devel] [PATCH v3 3/5] block: add BlockBackend->in_flight counter Stefan Hajnoczi
2018-02-16 16:50 ` [Qemu-devel] [PATCH v3 4/5] block: test blk_aio_flush() with blk->root == NULL Stefan Hajnoczi
2018-02-16 16:50 ` [Qemu-devel] [PATCH v3 5/5] Revert "IDE: Do not flush empty CDROM drives" Stefan Hajnoczi
2018-02-28 15:48 ` [Qemu-devel] [PATCH v3 0/5] block: fix blk_aio_*() segfault when blk->root == NULL Stefan Hajnoczi
2018-02-28 15:53   ` Paolo Bonzini
2018-03-01 15:09 ` Kevin Wolf

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).