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

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