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

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