Blame SOURCES/kvm-aio-Do-aio_notify_accept-only-during-blocking-aio_po.patch

357786
From a2e385fea51333b9cfbf88b19cbb4f82a5677381 Mon Sep 17 00:00:00 2001
357786
From: Fam Zheng <famz@redhat.com>
357786
Date: Fri, 17 Aug 2018 03:08:36 +0200
357786
Subject: [PATCH 5/5] aio: Do aio_notify_accept only during blocking aio_poll
357786
357786
RH-Author: Fam Zheng <famz@redhat.com>
357786
Message-id: <20180817030836.20581-3-famz@redhat.com>
357786
Patchwork-id: 81862
357786
O-Subject: [RHEL-7.6 qemu-kvm-rhev PATCH 2/2] aio: Do aio_notify_accept only during blocking aio_poll
357786
Bugzilla: 1562750
357786
RH-Acked-by: Paolo Bonzini <pbonzini@redhat.com>
357786
RH-Acked-by: Thomas Huth <thuth@redhat.com>
357786
RH-Acked-by: Laszlo Ersek <lersek@redhat.com>
357786
357786
An aio_notify() pairs with an aio_notify_accept(). The former should
357786
happen in the main thread or a vCPU thread, and the latter should be
357786
done in the IOThread.
357786
357786
There is one rare case that the main thread or vCPU thread may "steal"
357786
the aio_notify() event just raised by itself, in bdrv_set_aio_context()
357786
[1]. The sequence is like this:
357786
357786
    main thread                     IO Thread
357786
    ===============================================================
357786
    bdrv_drained_begin()
357786
      aio_disable_external(ctx)
357786
                                    aio_poll(ctx, true)
357786
                                      ctx->notify_me += 2
357786
    ...
357786
    bdrv_drained_end()
357786
      ...
357786
        aio_notify()
357786
    ...
357786
    bdrv_set_aio_context()
357786
      aio_poll(ctx, false)
357786
[1]     aio_notify_accept(ctx)
357786
                                      ppoll() /* Hang! */
357786
357786
[1] is problematic. It will clear the ctx->notifier event so that
357786
the blocked ppoll() will not return.
357786
357786
(For the curious, this bug was noticed when booting a number of VMs
357786
simultaneously in RHV.  One or two of the VMs will hit this race
357786
condition, making the VIRTIO device unresponsive to I/O commands. When
357786
it hangs, Seabios is busy waiting for a read request to complete (read
357786
MBR), right after initializing the virtio-blk-pci device, using 100%
357786
guest CPU. See also https://bugzilla.redhat.com/show_bug.cgi?id=1562750
357786
for the original bug analysis.)
357786
357786
aio_notify() only injects an event when ctx->notify_me is set,
357786
correspondingly aio_notify_accept() is only useful when ctx->notify_me
357786
_was_ set. Move the call to it into the "blocking" branch. This will
357786
effectively skip [1] and fix the hang.
357786
357786
Furthermore, blocking aio_poll is only allowed on home thread
357786
(in_aio_context_home_thread), because otherwise two blocking
357786
aio_poll()'s can steal each other's ctx->notifier event and cause
357786
hanging just like described above.
357786
357786
Cc: qemu-stable@nongnu.org
357786
Suggested-by: Paolo Bonzini <pbonzini@redhat.com>
357786
Signed-off-by: Fam Zheng <famz@redhat.com>
357786
Message-Id: <20180809132259.18402-3-famz@redhat.com>
357786
Signed-off-by: Fam Zheng <famz@redhat.com>
357786
(cherry picked from commit b37548fcd1b8ac2e88e185a395bef851f3fc4e65)
357786
Signed-off-by: Fam Zheng <famz@redhat.com>
357786
Signed-off-by: Miroslav Rezanina <mrezanin@redhat.com>
357786
---
357786
 util/aio-posix.c | 4 ++--
357786
 util/aio-win32.c | 3 ++-
357786
 2 files changed, 4 insertions(+), 3 deletions(-)
357786
357786
diff --git a/util/aio-posix.c b/util/aio-posix.c
357786
index f650c7c..f05d3a8 100644
357786
--- a/util/aio-posix.c
357786
+++ b/util/aio-posix.c
357786
@@ -591,6 +591,7 @@ bool aio_poll(AioContext *ctx, bool blocking)
357786
      * so disable the optimization now.
357786
      */
357786
     if (blocking) {
357786
+        assert(in_aio_context_home_thread(ctx));
357786
         atomic_add(&ctx->notify_me, 2);
357786
     }
357786
 
357786
@@ -633,6 +634,7 @@ bool aio_poll(AioContext *ctx, bool blocking)
357786
 
357786
     if (blocking) {
357786
         atomic_sub(&ctx->notify_me, 2);
357786
+        aio_notify_accept(ctx);
357786
     }
357786
 
357786
     /* Adjust polling time */
357786
@@ -676,8 +678,6 @@ bool aio_poll(AioContext *ctx, bool blocking)
357786
         }
357786
     }
357786
 
357786
-    aio_notify_accept(ctx);
357786
-
357786
     /* if we have any readable fds, dispatch event */
357786
     if (ret > 0) {
357786
         for (i = 0; i < npfd; i++) {
357786
diff --git a/util/aio-win32.c b/util/aio-win32.c
357786
index a67b00c..ac5524c 100644
357786
--- a/util/aio-win32.c
357786
+++ b/util/aio-win32.c
357786
@@ -373,11 +373,12 @@ bool aio_poll(AioContext *ctx, bool blocking)
357786
         ret = WaitForMultipleObjects(count, events, FALSE, timeout);
357786
         if (blocking) {
357786
             assert(first);
357786
+            assert(in_aio_context_home_thread(ctx));
357786
             atomic_sub(&ctx->notify_me, 2);
357786
+            aio_notify_accept(ctx);
357786
         }
357786
 
357786
         if (first) {
357786
-            aio_notify_accept(ctx);
357786
             progress |= aio_bh_poll(ctx);
357786
             first = false;
357786
         }
357786
-- 
357786
1.8.3.1
357786