|
|
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 |
|