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

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