Blame SOURCES/kvm-aio-posix-fix-concurrent-access-to-poll_disable_cnt.patch

383d26
From a9becae1ae86e699ee4a606ff2319799a9fda48c Mon Sep 17 00:00:00 2001
383d26
From: Fam Zheng <famz@redhat.com>
383d26
Date: Tue, 18 Sep 2018 09:07:12 +0200
383d26
Subject: [PATCH 1/3] aio-posix: fix concurrent access to poll_disable_cnt
383d26
383d26
RH-Author: Fam Zheng <famz@redhat.com>
383d26
Message-id: <20180918090714.18069-2-famz@redhat.com>
383d26
Patchwork-id: 82215
383d26
O-Subject: [RHEL-7.6 qemu-kvm-rhev PATCH 1/3] aio-posix: fix concurrent access to poll_disable_cnt
383d26
Bugzilla: 1628191
383d26
RH-Acked-by: Paolo Bonzini <pbonzini@redhat.com>
383d26
RH-Acked-by: Jeffrey Cody <jcody@redhat.com>
383d26
RH-Acked-by: Kevin Wolf <kwolf@redhat.com>
383d26
383d26
From: Paolo Bonzini <pbonzini@redhat.com>
383d26
383d26
It is valid for an aio_set_fd_handler to happen concurrently with
383d26
aio_poll.  In that case, poll_disable_cnt can change under the heels
383d26
of aio_poll, and the assertion on poll_disable_cnt can fail in
383d26
run_poll_handlers.
383d26
383d26
Therefore, this patch simply checks the counter on every polling
383d26
iteration.  There are no particular needs for ordering, since the
383d26
polling loop is terminated anyway by aio_notify at the end of
383d26
aio_set_fd_handler.
383d26
383d26
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
383d26
Message-Id: <20180912171040.1732-2-pbonzini@redhat.com>
383d26
Reviewed-by: Fam Zheng <famz@redhat.com>
383d26
Signed-off-by: Fam Zheng <famz@redhat.com>
383d26
Signed-off-by: Miroslav Rezanina <mrezanin@redhat.com>
383d26
---
383d26
 util/aio-posix.c | 26 +++++++++++++++-----------
383d26
 1 file changed, 15 insertions(+), 11 deletions(-)
383d26
383d26
diff --git a/util/aio-posix.c b/util/aio-posix.c
383d26
index f05d3a8..1d7cc53 100644
383d26
--- a/util/aio-posix.c
383d26
+++ b/util/aio-posix.c
383d26
@@ -211,6 +211,7 @@ void aio_set_fd_handler(AioContext *ctx,
383d26
     AioHandler *node;
383d26
     bool is_new = false;
383d26
     bool deleted = false;
383d26
+    int poll_disable_change;
383d26
 
383d26
     qemu_lockcnt_lock(&ctx->list_lock);
383d26
 
383d26
@@ -244,11 +245,9 @@ void aio_set_fd_handler(AioContext *ctx,
383d26
             QLIST_REMOVE(node, node);
383d26
             deleted = true;
383d26
         }
383d26
-
383d26
-        if (!node->io_poll) {
383d26
-            ctx->poll_disable_cnt--;
383d26
-        }
383d26
+        poll_disable_change = -!node->io_poll;
383d26
     } else {
383d26
+        poll_disable_change = !io_poll - (node && !node->io_poll);
383d26
         if (node == NULL) {
383d26
             /* Alloc and insert if it's not already there */
383d26
             node = g_new0(AioHandler, 1);
383d26
@@ -257,10 +256,6 @@ void aio_set_fd_handler(AioContext *ctx,
383d26
 
383d26
             g_source_add_poll(&ctx->source, &node->pfd);
383d26
             is_new = true;
383d26
-
383d26
-            ctx->poll_disable_cnt += !io_poll;
383d26
-        } else {
383d26
-            ctx->poll_disable_cnt += !io_poll - !node->io_poll;
383d26
         }
383d26
 
383d26
         /* Update handler with latest information */
383d26
@@ -274,6 +269,15 @@ void aio_set_fd_handler(AioContext *ctx,
383d26
         node->pfd.events |= (io_write ? G_IO_OUT | G_IO_ERR : 0);
383d26
     }
383d26
 
383d26
+    /* No need to order poll_disable_cnt writes against other updates;
383d26
+     * the counter is only used to avoid wasting time and latency on
383d26
+     * iterated polling when the system call will be ultimately necessary.
383d26
+     * Changing handlers is a rare event, and a little wasted polling until
383d26
+     * the aio_notify below is not an issue.
383d26
+     */
383d26
+    atomic_set(&ctx->poll_disable_cnt,
383d26
+               atomic_read(&ctx->poll_disable_cnt) + poll_disable_change);
383d26
+
383d26
     aio_epoll_update(ctx, node, is_new);
383d26
     qemu_lockcnt_unlock(&ctx->list_lock);
383d26
     aio_notify(ctx);
383d26
@@ -525,7 +529,6 @@ static bool run_poll_handlers(AioContext *ctx, int64_t max_ns)
383d26
 
383d26
     assert(ctx->notify_me);
383d26
     assert(qemu_lockcnt_count(&ctx->list_lock) > 0);
383d26
-    assert(ctx->poll_disable_cnt == 0);
383d26
 
383d26
     trace_run_poll_handlers_begin(ctx, max_ns);
383d26
 
383d26
@@ -533,7 +536,8 @@ static bool run_poll_handlers(AioContext *ctx, int64_t max_ns)
383d26
 
383d26
     do {
383d26
         progress = run_poll_handlers_once(ctx);
383d26
-    } while (!progress && qemu_clock_get_ns(QEMU_CLOCK_REALTIME) < end_time);
383d26
+    } while (!progress && qemu_clock_get_ns(QEMU_CLOCK_REALTIME) < end_time
383d26
+             && !atomic_read(&ctx->poll_disable_cnt));
383d26
 
383d26
     trace_run_poll_handlers_end(ctx, progress);
383d26
 
383d26
@@ -552,7 +556,7 @@ static bool run_poll_handlers(AioContext *ctx, int64_t max_ns)
383d26
  */
383d26
 static bool try_poll_mode(AioContext *ctx, bool blocking)
383d26
 {
383d26
-    if (blocking && ctx->poll_max_ns && ctx->poll_disable_cnt == 0) {
383d26
+    if (blocking && ctx->poll_max_ns && !atomic_read(&ctx->poll_disable_cnt)) {
383d26
         /* See qemu_soonest_timeout() uint64_t hack */
383d26
         int64_t max_ns = MIN((uint64_t)aio_compute_timeout(ctx),
383d26
                              (uint64_t)ctx->poll_ns);
383d26
-- 
383d26
1.8.3.1
383d26