[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[qemu-xen stable-4.13] curl: Handle success in multi_check_completion



commit 2d86df1f78d71ca30a4bff84002ada70e6a04169
Author:     Max Reitz <mreitz@xxxxxxxxxx>
AuthorDate: Tue Sep 10 14:41:35 2019 +0200
Commit:     Michael Roth <mdroth@xxxxxxxxxxxxxxxxxx>
CommitDate: Wed Oct 30 11:34:26 2019 -0500

    curl: Handle success in multi_check_completion
    
    Background: As of cURL 7.59.0, it verifies that several functions are
    not called from within a callback.  Among these functions is
    curl_multi_add_handle().
    
    curl_read_cb() is a callback from cURL and not a coroutine.  Waking up
    acb->co will lead to entering it then and there, which means the current
    request will settle and the caller (if it runs in the same coroutine)
    may then issue the next request.  In such a case, we will enter
    curl_setup_preadv() effectively from within curl_read_cb().
    
    Calling curl_multi_add_handle() will then fail and the new request will
    not be processed.
    
    Fix this by not letting curl_read_cb() wake up acb->co.  Instead, leave
    the whole business of settling the AIOCB objects to
    curl_multi_check_completion() (which is called from our timer callback
    and our FD handler, so not from any cURL callbacks).
    
    Reported-by: Natalie Gavrielov <ngavrilo@xxxxxxxxxx>
    Buglink: https://bugzilla.redhat.com/show_bug.cgi?id=1740193
    Cc: qemu-stable@xxxxxxxxxx
    Signed-off-by: Max Reitz <mreitz@xxxxxxxxxx>
    Message-id: 20190910124136.10565-7-mreitz@xxxxxxxxxx
    Reviewed-by: John Snow <jsnow@xxxxxxxxxx>
    Reviewed-by: Maxim Levitsky <mlevitsk@xxxxxxxxxx>
    Signed-off-by: Max Reitz <mreitz@xxxxxxxxxx>
    (cherry picked from commit bfb23b480a49114315877aacf700b49453e0f9d9)
    Signed-off-by: Michael Roth <mdroth@xxxxxxxxxxxxxxxxxx>
---
 block/curl.c | 69 +++++++++++++++++++++++++-----------------------------------
 1 file changed, 29 insertions(+), 40 deletions(-)

diff --git a/block/curl.c b/block/curl.c
index fd70f1ebc4..c343c7ed3d 100644
--- a/block/curl.c
+++ b/block/curl.c
@@ -229,7 +229,6 @@ static size_t curl_read_cb(void *ptr, size_t size, size_t 
nmemb, void *opaque)
 {
     CURLState *s = ((CURLState*)opaque);
     size_t realsize = size * nmemb;
-    int i;
 
     trace_curl_read_cb(realsize);
 
@@ -245,32 +244,6 @@ static size_t curl_read_cb(void *ptr, size_t size, size_t 
nmemb, void *opaque)
     memcpy(s->orig_buf + s->buf_off, ptr, realsize);
     s->buf_off += realsize;
 
-    for(i=0; i<CURL_NUM_ACB; i++) {
-        CURLAIOCB *acb = s->acb[i];
-
-        if (!acb)
-            continue;
-
-        if ((s->buf_off >= acb->end)) {
-            size_t request_length = acb->bytes;
-
-            qemu_iovec_from_buf(acb->qiov, 0, s->orig_buf + acb->start,
-                                acb->end - acb->start);
-
-            if (acb->end - acb->start < request_length) {
-                size_t offset = acb->end - acb->start;
-                qemu_iovec_memset(acb->qiov, offset, 0,
-                                  request_length - offset);
-            }
-
-            acb->ret = 0;
-            s->acb[i] = NULL;
-            qemu_mutex_unlock(&s->s->mutex);
-            aio_co_wake(acb->co);
-            qemu_mutex_lock(&s->s->mutex);
-        }
-    }
-
 read_end:
     /* curl will error out if we do not return this value */
     return size * nmemb;
@@ -351,13 +324,14 @@ static void curl_multi_check_completion(BDRVCURLState *s)
             break;
 
         if (msg->msg == CURLMSG_DONE) {
+            int i;
             CURLState *state = NULL;
+            bool error = msg->data.result != CURLE_OK;
+
             curl_easy_getinfo(msg->easy_handle, CURLINFO_PRIVATE,
                               (char **)&state);
 
-            /* ACBs for successful messages get completed in curl_read_cb */
-            if (msg->data.result != CURLE_OK) {
-                int i;
+            if (error) {
                 static int errcount = 100;
 
                 /* Don't lose the original error message from curl, since
@@ -369,20 +343,35 @@ static void curl_multi_check_completion(BDRVCURLState *s)
                         error_report("curl: further errors suppressed");
                     }
                 }
+            }
 
-                for (i = 0; i < CURL_NUM_ACB; i++) {
-                    CURLAIOCB *acb = state->acb[i];
+            for (i = 0; i < CURL_NUM_ACB; i++) {
+                CURLAIOCB *acb = state->acb[i];
 
-                    if (acb == NULL) {
-                        continue;
-                    }
+                if (acb == NULL) {
+                    continue;
+                }
+
+                if (!error) {
+                    /* Assert that we have read all data */
+                    assert(state->buf_off >= acb->end);
+
+                    qemu_iovec_from_buf(acb->qiov, 0,
+                                        state->orig_buf + acb->start,
+                                        acb->end - acb->start);
 
-                    acb->ret = -EIO;
-                    state->acb[i] = NULL;
-                    qemu_mutex_unlock(&s->mutex);
-                    aio_co_wake(acb->co);
-                    qemu_mutex_lock(&s->mutex);
+                    if (acb->end - acb->start < acb->bytes) {
+                        size_t offset = acb->end - acb->start;
+                        qemu_iovec_memset(acb->qiov, offset, 0,
+                                          acb->bytes - offset);
+                    }
                 }
+
+                acb->ret = error ? -EIO : 0;
+                state->acb[i] = NULL;
+                qemu_mutex_unlock(&s->mutex);
+                aio_co_wake(acb->co);
+                qemu_mutex_lock(&s->mutex);
             }
 
             curl_clean_state(state);
--
generated by git-patchbot for /home/xen/git/qemu-xen.git#stable-4.13



 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.