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

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