Blame SOURCES/kvm-curl-avoid-recursive-locking-of-BDRVCURLState-mutex.patch

76daa3
From e8ba6a37c3ab919f93c82639ea646d34c0bdc23a Mon Sep 17 00:00:00 2001
76daa3
From: Paolo Bonzini <pbonzini@redhat.com>
76daa3
Date: Wed, 17 May 2017 13:09:17 +0200
76daa3
Subject: [PATCH 11/27] curl: avoid recursive locking of BDRVCURLState mutex
76daa3
76daa3
RH-Author: Paolo Bonzini <pbonzini@redhat.com>
76daa3
Message-id: <20170517130921.27402-4-pbonzini@redhat.com>
76daa3
Patchwork-id: 75261
76daa3
O-Subject: [RHEL7.4 qemu-kvm PATCH v2 3/7] curl: avoid recursive locking of BDRVCURLState mutex
76daa3
Bugzilla: 1437393
76daa3
RH-Acked-by: Max Reitz <mreitz@redhat.com>
76daa3
RH-Acked-by: Stefan Hajnoczi <stefanha@redhat.com>
76daa3
RH-Acked-by: Jeffrey Cody <jcody@redhat.com>
76daa3
76daa3
The curl driver has a ugly hack where, if it cannot find an empty CURLState,
76daa3
it just uses aio_poll to wait for one to be empty.  This is probably
76daa3
buggy when used together with dataplane, and the simplest way to fix it
76daa3
is to use coroutines instead.
76daa3
76daa3
A more immediate effect of the bug however is that it can cause a
76daa3
recursive call to curl_readv_bh_cb and recursively taking the
76daa3
BDRVCURLState mutex.  This causes a deadlock.
76daa3
76daa3
The fix is to unlock the mutex around aio_poll, but for cleanliness we
76daa3
should also take the mutex around all calls to curl_init_state, even if
76daa3
reaching the unlock/lock pair is impossible.  The same is true for
76daa3
curl_clean_state.
76daa3
76daa3
Reported-by: Kun Wei <kuwei@redhat.com>
76daa3
Tested-by: Richard W.M. Jones <rjones@redhat.com>
76daa3
Reviewed-by: Max Reitz <mreitz@redhat.com>
76daa3
Reviewed-by: Jeff Cody <jcody@redhat.com>
76daa3
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
76daa3
Message-id: 20170515100059.15795-4-pbonzini@redhat.com
76daa3
Cc: qemu-stable@nongnu.org
76daa3
Cc: Jeff Cody <jcody@redhat.com>
76daa3
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
76daa3
Signed-off-by: Jeff Cody <jcody@redhat.com>
76daa3
(cherry picked from commit 456af346297ebef86aa097b3609534d34f3d2f75)
76daa3
Signed-off-by: Miroslav Rezanina <mrezanin@redhat.com>
76daa3
---
76daa3
 block/curl.c | 14 +++++++++++++-
76daa3
 1 file changed, 13 insertions(+), 1 deletion(-)
76daa3
76daa3
diff --git a/block/curl.c b/block/curl.c
76daa3
index 94a1e16..7001476 100644
76daa3
--- a/block/curl.c
76daa3
+++ b/block/curl.c
76daa3
@@ -281,6 +281,7 @@ read_end:
76daa3
     return size * nmemb;
76daa3
 }
76daa3
 
76daa3
+/* Called with s->mutex held.  */
76daa3
 static int curl_find_buf(BDRVCURLState *s, size_t start, size_t len,
76daa3
                          CURLAIOCB *acb)
76daa3
 {
76daa3
@@ -453,6 +454,7 @@ static void curl_multi_timeout_do(void *arg)
76daa3
 #endif
76daa3
 }
76daa3
 
76daa3
+/* Called with s->mutex held.  */
76daa3
 static CURLState *curl_init_state(BlockDriverState *bs, BDRVCURLState *s)
76daa3
 {
76daa3
     CURLState *state = NULL;
76daa3
@@ -471,7 +473,9 @@ static CURLState *curl_init_state(BlockDriverState *bs, BDRVCURLState *s)
76daa3
             break;
76daa3
         }
76daa3
         if (!state) {
76daa3
+            qemu_mutex_unlock(&s->mutex);
76daa3
             aio_poll(bdrv_get_aio_context(bs), true);
76daa3
+            qemu_mutex_lock(&s->mutex);
76daa3
         }
76daa3
     } while(!state);
76daa3
 
76daa3
@@ -534,6 +538,7 @@ static CURLState *curl_init_state(BlockDriverState *bs, BDRVCURLState *s)
76daa3
     return state;
76daa3
 }
76daa3
 
76daa3
+/* Called with s->mutex held.  */
76daa3
 static void curl_clean_state(CURLState *s)
76daa3
 {
76daa3
     int j;
76daa3
@@ -565,6 +570,7 @@ static void curl_detach_aio_context(BlockDriverState *bs)
76daa3
     BDRVCURLState *s = bs->opaque;
76daa3
     int i;
76daa3
 
76daa3
+    qemu_mutex_lock(&s->mutex);
76daa3
     for (i = 0; i < CURL_NUM_STATES; i++) {
76daa3
         if (s->states[i].in_use) {
76daa3
             curl_clean_state(&s->states[i]);
76daa3
@@ -580,6 +586,7 @@ static void curl_detach_aio_context(BlockDriverState *bs)
76daa3
         curl_multi_cleanup(s->multi);
76daa3
         s->multi = NULL;
76daa3
     }
76daa3
+    qemu_mutex_unlock(&s->mutex);
76daa3
 
76daa3
     timer_del(&s->timer);
76daa3
 }
76daa3
@@ -677,6 +684,7 @@ static int curl_open(BlockDriverState *bs, QDict *options, int flags,
76daa3
         return -EROFS;
76daa3
     }
76daa3
 
76daa3
+    qemu_mutex_init(&s->mutex);
76daa3
     opts = qemu_opts_create(&runtime_opts, NULL, 0, &error_abort);
76daa3
     qemu_opts_absorb_qdict(opts, options, &local_err);
76daa3
     if (local_err) {
76daa3
@@ -747,7 +755,9 @@ static int curl_open(BlockDriverState *bs, QDict *options, int flags,
76daa3
     DPRINTF("CURL: Opening %s\n", file);
76daa3
     s->aio_context = bdrv_get_aio_context(bs);
76daa3
     s->url = g_strdup(file);
76daa3
+    qemu_mutex_lock(&s->mutex);
76daa3
     state = curl_init_state(bs, s);
76daa3
+    qemu_mutex_unlock(&s->mutex);
76daa3
     if (!state)
76daa3
         goto out_noclean;
76daa3
 
76daa3
@@ -791,11 +801,12 @@ static int curl_open(BlockDriverState *bs, QDict *options, int flags,
76daa3
     }
76daa3
     DPRINTF("CURL: Size = %zd\n", s->len);
76daa3
 
76daa3
+    qemu_mutex_lock(&s->mutex);
76daa3
     curl_clean_state(state);
76daa3
+    qemu_mutex_unlock(&s->mutex);
76daa3
     curl_easy_cleanup(state->curl);
76daa3
     state->curl = NULL;
76daa3
 
76daa3
-    qemu_mutex_init(&s->mutex);
76daa3
     curl_attach_aio_context(bs, bdrv_get_aio_context(bs));
76daa3
 
76daa3
     qemu_opts_del(opts);
76daa3
@@ -806,6 +817,7 @@ out:
76daa3
     curl_easy_cleanup(state->curl);
76daa3
     state->curl = NULL;
76daa3
 out_noclean:
76daa3
+    qemu_mutex_destroy(&s->mutex);
76daa3
     g_free(s->cookie);
76daa3
     g_free(s->url);
76daa3
     qemu_opts_del(opts);
76daa3
-- 
76daa3
1.8.3.1
76daa3