Pablo Greco e6a3ae
From 23f5a846f6702c456cf7cc9490e50cfd23368910 Mon Sep 17 00:00:00 2001
Pablo Greco e6a3ae
From: Max Reitz <mreitz@redhat.com>
Pablo Greco e6a3ae
Date: Tue, 19 Nov 2019 15:29:59 +0000
Pablo Greco e6a3ae
Subject: [PATCH 7/8] curl: Handle success in multi_check_completion
Pablo Greco e6a3ae
MIME-Version: 1.0
Pablo Greco e6a3ae
Content-Type: text/plain; charset=UTF-8
Pablo Greco e6a3ae
Content-Transfer-Encoding: 8bit
Pablo Greco e6a3ae
Pablo Greco e6a3ae
RH-Author: Max Reitz <mreitz@redhat.com>
Pablo Greco e6a3ae
Message-id: <20191119153000.101646-7-mreitz@redhat.com>
Pablo Greco e6a3ae
Patchwork-id: 92520
Pablo Greco e6a3ae
O-Subject: [RHEL-8.2.0 qemu-kvm PATCH 6/7] curl: Handle success in multi_check_completion
Pablo Greco e6a3ae
Bugzilla: 1744602
Pablo Greco e6a3ae
RH-Acked-by: Maxim Levitsky <mlevitsk@redhat.com>
Pablo Greco e6a3ae
RH-Acked-by: Philippe Mathieu-Daudé <philmd@redhat.com>
Pablo Greco e6a3ae
RH-Acked-by: Stefano Garzarella <sgarzare@redhat.com>
Pablo Greco e6a3ae
Pablo Greco e6a3ae
Background: As of cURL 7.59.0, it verifies that several functions are
Pablo Greco e6a3ae
not called from within a callback.  Among these functions is
Pablo Greco e6a3ae
curl_multi_add_handle().
Pablo Greco e6a3ae
Pablo Greco e6a3ae
curl_read_cb() is a callback from cURL and not a coroutine.  Waking up
Pablo Greco e6a3ae
acb->co will lead to entering it then and there, which means the current
Pablo Greco e6a3ae
request will settle and the caller (if it runs in the same coroutine)
Pablo Greco e6a3ae
may then issue the next request.  In such a case, we will enter
Pablo Greco e6a3ae
curl_setup_preadv() effectively from within curl_read_cb().
Pablo Greco e6a3ae
Pablo Greco e6a3ae
Calling curl_multi_add_handle() will then fail and the new request will
Pablo Greco e6a3ae
not be processed.
Pablo Greco e6a3ae
Pablo Greco e6a3ae
Fix this by not letting curl_read_cb() wake up acb->co.  Instead, leave
Pablo Greco e6a3ae
the whole business of settling the AIOCB objects to
Pablo Greco e6a3ae
curl_multi_check_completion() (which is called from our timer callback
Pablo Greco e6a3ae
and our FD handler, so not from any cURL callbacks).
Pablo Greco e6a3ae
Pablo Greco e6a3ae
Reported-by: Natalie Gavrielov <ngavrilo@redhat.com>
Pablo Greco e6a3ae
Buglink: https://bugzilla.redhat.com/show_bug.cgi?id=1740193
Pablo Greco e6a3ae
Cc: qemu-stable@nongnu.org
Pablo Greco e6a3ae
Signed-off-by: Max Reitz <mreitz@redhat.com>
Pablo Greco e6a3ae
Message-id: 20190910124136.10565-7-mreitz@redhat.com
Pablo Greco e6a3ae
Reviewed-by: John Snow <jsnow@redhat.com>
Pablo Greco e6a3ae
Reviewed-by: Maxim Levitsky <mlevitsk@redhat.com>
Pablo Greco e6a3ae
Signed-off-by: Max Reitz <mreitz@redhat.com>
Pablo Greco e6a3ae
(cherry picked from commit bfb23b480a49114315877aacf700b49453e0f9d9)
Pablo Greco e6a3ae
Signed-off-by: Max Reitz <mreitz@redhat.com>
Pablo Greco e6a3ae
Signed-off-by: Danilo C. L. de Paula <ddepaula@redhat.com>
Pablo Greco e6a3ae
---
Pablo Greco e6a3ae
 block/curl.c | 69 +++++++++++++++++++++++++-----------------------------------
Pablo Greco e6a3ae
 1 file changed, 29 insertions(+), 40 deletions(-)
Pablo Greco e6a3ae
Pablo Greco e6a3ae
diff --git a/block/curl.c b/block/curl.c
Pablo Greco e6a3ae
index f776615..b5899e1 100644
Pablo Greco e6a3ae
--- a/block/curl.c
Pablo Greco e6a3ae
+++ b/block/curl.c
Pablo Greco e6a3ae
@@ -238,7 +238,6 @@ static size_t curl_read_cb(void *ptr, size_t size, size_t nmemb, void *opaque)
Pablo Greco e6a3ae
 {
Pablo Greco e6a3ae
     CURLState *s = ((CURLState*)opaque);
Pablo Greco e6a3ae
     size_t realsize = size * nmemb;
Pablo Greco e6a3ae
-    int i;
Pablo Greco e6a3ae
 
Pablo Greco e6a3ae
     DPRINTF("CURL: Just reading %zd bytes\n", realsize);
Pablo Greco e6a3ae
 
Pablo Greco e6a3ae
@@ -254,32 +253,6 @@ static size_t curl_read_cb(void *ptr, size_t size, size_t nmemb, void *opaque)
Pablo Greco e6a3ae
     memcpy(s->orig_buf + s->buf_off, ptr, realsize);
Pablo Greco e6a3ae
     s->buf_off += realsize;
Pablo Greco e6a3ae
 
Pablo Greco e6a3ae
-    for(i=0; i
Pablo Greco e6a3ae
-        CURLAIOCB *acb = s->acb[i];
Pablo Greco e6a3ae
-
Pablo Greco e6a3ae
-        if (!acb)
Pablo Greco e6a3ae
-            continue;
Pablo Greco e6a3ae
-
Pablo Greco e6a3ae
-        if ((s->buf_off >= acb->end)) {
Pablo Greco e6a3ae
-            size_t request_length = acb->bytes;
Pablo Greco e6a3ae
-
Pablo Greco e6a3ae
-            qemu_iovec_from_buf(acb->qiov, 0, s->orig_buf + acb->start,
Pablo Greco e6a3ae
-                                acb->end - acb->start);
Pablo Greco e6a3ae
-
Pablo Greco e6a3ae
-            if (acb->end - acb->start < request_length) {
Pablo Greco e6a3ae
-                size_t offset = acb->end - acb->start;
Pablo Greco e6a3ae
-                qemu_iovec_memset(acb->qiov, offset, 0,
Pablo Greco e6a3ae
-                                  request_length - offset);
Pablo Greco e6a3ae
-            }
Pablo Greco e6a3ae
-
Pablo Greco e6a3ae
-            acb->ret = 0;
Pablo Greco e6a3ae
-            s->acb[i] = NULL;
Pablo Greco e6a3ae
-            qemu_mutex_unlock(&s->s->mutex);
Pablo Greco e6a3ae
-            aio_co_wake(acb->co);
Pablo Greco e6a3ae
-            qemu_mutex_lock(&s->s->mutex);
Pablo Greco e6a3ae
-        }
Pablo Greco e6a3ae
-    }
Pablo Greco e6a3ae
-
Pablo Greco e6a3ae
 read_end:
Pablo Greco e6a3ae
     /* curl will error out if we do not return this value */
Pablo Greco e6a3ae
     return size * nmemb;
Pablo Greco e6a3ae
@@ -360,13 +333,14 @@ static void curl_multi_check_completion(BDRVCURLState *s)
Pablo Greco e6a3ae
             break;
Pablo Greco e6a3ae
 
Pablo Greco e6a3ae
         if (msg->msg == CURLMSG_DONE) {
Pablo Greco e6a3ae
+            int i;
Pablo Greco e6a3ae
             CURLState *state = NULL;
Pablo Greco e6a3ae
+            bool error = msg->data.result != CURLE_OK;
Pablo Greco e6a3ae
+
Pablo Greco e6a3ae
             curl_easy_getinfo(msg->easy_handle, CURLINFO_PRIVATE,
Pablo Greco e6a3ae
                               (char **)&state);
Pablo Greco e6a3ae
 
Pablo Greco e6a3ae
-            /* ACBs for successful messages get completed in curl_read_cb */
Pablo Greco e6a3ae
-            if (msg->data.result != CURLE_OK) {
Pablo Greco e6a3ae
-                int i;
Pablo Greco e6a3ae
+            if (error) {
Pablo Greco e6a3ae
                 static int errcount = 100;
Pablo Greco e6a3ae
 
Pablo Greco e6a3ae
                 /* Don't lose the original error message from curl, since
Pablo Greco e6a3ae
@@ -378,20 +352,35 @@ static void curl_multi_check_completion(BDRVCURLState *s)
Pablo Greco e6a3ae
                         error_report("curl: further errors suppressed");
Pablo Greco e6a3ae
                     }
Pablo Greco e6a3ae
                 }
Pablo Greco e6a3ae
+            }
Pablo Greco e6a3ae
 
Pablo Greco e6a3ae
-                for (i = 0; i < CURL_NUM_ACB; i++) {
Pablo Greco e6a3ae
-                    CURLAIOCB *acb = state->acb[i];
Pablo Greco e6a3ae
+            for (i = 0; i < CURL_NUM_ACB; i++) {
Pablo Greco e6a3ae
+                CURLAIOCB *acb = state->acb[i];
Pablo Greco e6a3ae
 
Pablo Greco e6a3ae
-                    if (acb == NULL) {
Pablo Greco e6a3ae
-                        continue;
Pablo Greco e6a3ae
-                    }
Pablo Greco e6a3ae
+                if (acb == NULL) {
Pablo Greco e6a3ae
+                    continue;
Pablo Greco e6a3ae
+                }
Pablo Greco e6a3ae
+
Pablo Greco e6a3ae
+                if (!error) {
Pablo Greco e6a3ae
+                    /* Assert that we have read all data */
Pablo Greco e6a3ae
+                    assert(state->buf_off >= acb->end);
Pablo Greco e6a3ae
+
Pablo Greco e6a3ae
+                    qemu_iovec_from_buf(acb->qiov, 0,
Pablo Greco e6a3ae
+                                        state->orig_buf + acb->start,
Pablo Greco e6a3ae
+                                        acb->end - acb->start);
Pablo Greco e6a3ae
 
Pablo Greco e6a3ae
-                    acb->ret = -EIO;
Pablo Greco e6a3ae
-                    state->acb[i] = NULL;
Pablo Greco e6a3ae
-                    qemu_mutex_unlock(&s->mutex);
Pablo Greco e6a3ae
-                    aio_co_wake(acb->co);
Pablo Greco e6a3ae
-                    qemu_mutex_lock(&s->mutex);
Pablo Greco e6a3ae
+                    if (acb->end - acb->start < acb->bytes) {
Pablo Greco e6a3ae
+                        size_t offset = acb->end - acb->start;
Pablo Greco e6a3ae
+                        qemu_iovec_memset(acb->qiov, offset, 0,
Pablo Greco e6a3ae
+                                          acb->bytes - offset);
Pablo Greco e6a3ae
+                    }
Pablo Greco e6a3ae
                 }
Pablo Greco e6a3ae
+
Pablo Greco e6a3ae
+                acb->ret = error ? -EIO : 0;
Pablo Greco e6a3ae
+                state->acb[i] = NULL;
Pablo Greco e6a3ae
+                qemu_mutex_unlock(&s->mutex);
Pablo Greco e6a3ae
+                aio_co_wake(acb->co);
Pablo Greco e6a3ae
+                qemu_mutex_lock(&s->mutex);
Pablo Greco e6a3ae
             }
Pablo Greco e6a3ae
 
Pablo Greco e6a3ae
             curl_clean_state(state);
Pablo Greco e6a3ae
-- 
Pablo Greco e6a3ae
1.8.3.1
Pablo Greco e6a3ae