|
|
05bba0 |
From a8b59fd3d7aa9f6a16caf4c13534039a81552118 Mon Sep 17 00:00:00 2001
|
|
|
05bba0 |
From: Richard Jones <rjones@redhat.com>
|
|
|
05bba0 |
Date: Thu, 11 Jun 2015 11:40:14 +0200
|
|
|
05bba0 |
Subject: [PATCH 14/30] block/curl: Implement the libcurl timer callback
|
|
|
05bba0 |
interface
|
|
|
05bba0 |
|
|
|
05bba0 |
Message-id: <1434022828-13037-8-git-send-email-rjones@redhat.com>
|
|
|
05bba0 |
Patchwork-id: 65842
|
|
|
05bba0 |
O-Subject: [RHEL-7.2 qemu-kvm v3 PATCH 07/21] block/curl: Implement the libcurl timer callback interface
|
|
|
05bba0 |
Bugzilla: 1226684
|
|
|
05bba0 |
RH-Acked-by: Miroslav Rezanina <mrezanin@redhat.com>
|
|
|
05bba0 |
RH-Acked-by: Stefan Hajnoczi <stefanha@redhat.com>
|
|
|
05bba0 |
RH-Acked-by: Laszlo Ersek <lersek@redhat.com>
|
|
|
05bba0 |
|
|
|
05bba0 |
From: Peter Maydell <peter.maydell@linaro.org>
|
|
|
05bba0 |
|
|
|
05bba0 |
libcurl versions 7.16.0 and later have a timer callback interface which
|
|
|
05bba0 |
must be implemented in order for libcurl to make forward progress (it
|
|
|
05bba0 |
will sometimes rely on being called back on the timeout if there are
|
|
|
05bba0 |
no file descriptors registered). Implement the callback, and use a
|
|
|
05bba0 |
QEMU AIO timer to ensure we prod libcurl again when it asks us to.
|
|
|
05bba0 |
|
|
|
05bba0 |
Based on Peter's original patch plus my fix to add curl_multi_timeout_do.
|
|
|
05bba0 |
Should compile just fine even on older versions of libcurl.
|
|
|
05bba0 |
|
|
|
05bba0 |
I also tried copy-on-read and streaming:
|
|
|
05bba0 |
|
|
|
05bba0 |
$ ./qemu-img create -f qcow2 -o \
|
|
|
05bba0 |
backing_file=http://download.fedoraproject.org/pub/fedora/linux/releases/20/Live/x86_64/Fedora-Live-Desktop-x86_64-20-1.iso \
|
|
|
05bba0 |
foo.qcow2 1G
|
|
|
05bba0 |
$ x86_64-softmmu/qemu-system-x86_64 \
|
|
|
05bba0 |
-drive if=none,file=foo.qcow2,copy-on-read=on,id=cd \
|
|
|
05bba0 |
-device ide-cd,drive=cd --enable-kvm -m 1024
|
|
|
05bba0 |
|
|
|
05bba0 |
Direct http usage is probably too slow, but with copy-on-read ultimately
|
|
|
05bba0 |
the image does boot!
|
|
|
05bba0 |
|
|
|
05bba0 |
After some time, streaming gets canceled by an EIO, which needs further
|
|
|
05bba0 |
investigation.
|
|
|
05bba0 |
|
|
|
05bba0 |
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
|
|
|
05bba0 |
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
|
|
|
05bba0 |
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
|
|
|
05bba0 |
|
|
|
05bba0 |
Upstream-status: 031fd1be5618c347f9aeb44ec294f14a541e42b2
|
|
|
05bba0 |
|
|
|
05bba0 |
This patch is modified from upstream by adapting the patch
|
|
|
05bba0 |
to use the timers API from qemu 1.5.3. (Thanks: Kevin Wolf)
|
|
|
05bba0 |
|
|
|
05bba0 |
Signed-off-by: Miroslav Rezanina <mrezanin@redhat.com>
|
|
|
05bba0 |
---
|
|
|
05bba0 |
block/curl.c | 81 +++++++++++++++++++++++++++++++++++++++++++++++++++---------
|
|
|
05bba0 |
1 file changed, 70 insertions(+), 11 deletions(-)
|
|
|
05bba0 |
|
|
|
05bba0 |
diff --git a/block/curl.c b/block/curl.c
|
|
|
05bba0 |
index 7569dd5..a6631fe 100644
|
|
|
05bba0 |
--- a/block/curl.c
|
|
|
05bba0 |
+++ b/block/curl.c
|
|
|
05bba0 |
@@ -34,6 +34,11 @@
|
|
|
05bba0 |
#define DPRINTF(fmt, ...) do { } while (0)
|
|
|
05bba0 |
#endif
|
|
|
05bba0 |
|
|
|
05bba0 |
+#if LIBCURL_VERSION_NUM >= 0x071000
|
|
|
05bba0 |
+/* The multi interface timer callback was introduced in 7.16.0 */
|
|
|
05bba0 |
+#define NEED_CURL_TIMER_CALLBACK
|
|
|
05bba0 |
+#endif
|
|
|
05bba0 |
+
|
|
|
05bba0 |
#define PROTOCOLS (CURLPROTO_HTTP | CURLPROTO_HTTPS | \
|
|
|
05bba0 |
CURLPROTO_FTP | CURLPROTO_FTPS | \
|
|
|
05bba0 |
CURLPROTO_TFTP)
|
|
|
05bba0 |
@@ -77,6 +82,7 @@ typedef struct CURLState
|
|
|
05bba0 |
|
|
|
05bba0 |
typedef struct BDRVCURLState {
|
|
|
05bba0 |
CURLM *multi;
|
|
|
05bba0 |
+ QEMUTimer *timer;
|
|
|
05bba0 |
size_t len;
|
|
|
05bba0 |
CURLState states[CURL_NUM_STATES];
|
|
|
05bba0 |
char *url;
|
|
|
05bba0 |
@@ -87,6 +93,23 @@ static void curl_clean_state(CURLState *s);
|
|
|
05bba0 |
static void curl_multi_do(void *arg);
|
|
|
05bba0 |
static int curl_aio_flush(void *opaque);
|
|
|
05bba0 |
|
|
|
05bba0 |
+#ifdef NEED_CURL_TIMER_CALLBACK
|
|
|
05bba0 |
+static int curl_timer_cb(CURLM *multi, long timeout_ms, void *opaque)
|
|
|
05bba0 |
+{
|
|
|
05bba0 |
+ BDRVCURLState *s = opaque;
|
|
|
05bba0 |
+
|
|
|
05bba0 |
+ DPRINTF("CURL: timer callback timeout_ms %ld\n", timeout_ms);
|
|
|
05bba0 |
+ if (timeout_ms == -1) {
|
|
|
05bba0 |
+ qemu_del_timer(s->timer);
|
|
|
05bba0 |
+ } else {
|
|
|
05bba0 |
+ int64_t timeout_ns = (int64_t)timeout_ms * 1000 * 1000;
|
|
|
05bba0 |
+ qemu_mod_timer(s->timer,
|
|
|
05bba0 |
+ qemu_get_clock_ns(rt_clock) + timeout_ns);
|
|
|
05bba0 |
+ }
|
|
|
05bba0 |
+ return 0;
|
|
|
05bba0 |
+}
|
|
|
05bba0 |
+#endif
|
|
|
05bba0 |
+
|
|
|
05bba0 |
static int curl_sock_cb(CURL *curl, curl_socket_t fd, int action,
|
|
|
05bba0 |
void *s, void *sp)
|
|
|
05bba0 |
{
|
|
|
05bba0 |
@@ -213,20 +236,10 @@ static int curl_find_buf(BDRVCURLState *s, size_t start, size_t len,
|
|
|
05bba0 |
return FIND_RET_NONE;
|
|
|
05bba0 |
}
|
|
|
05bba0 |
|
|
|
05bba0 |
-static void curl_multi_do(void *arg)
|
|
|
05bba0 |
+static void curl_multi_read(BDRVCURLState *s)
|
|
|
05bba0 |
{
|
|
|
05bba0 |
- BDRVCURLState *s = (BDRVCURLState *)arg;
|
|
|
05bba0 |
- int running;
|
|
|
05bba0 |
- int r;
|
|
|
05bba0 |
int msgs_in_queue;
|
|
|
05bba0 |
|
|
|
05bba0 |
- if (!s->multi)
|
|
|
05bba0 |
- return;
|
|
|
05bba0 |
-
|
|
|
05bba0 |
- do {
|
|
|
05bba0 |
- r = curl_multi_socket_all(s->multi, &running);
|
|
|
05bba0 |
- } while(r == CURLM_CALL_MULTI_PERFORM);
|
|
|
05bba0 |
-
|
|
|
05bba0 |
/* Try to find done transfers, so we can free the easy
|
|
|
05bba0 |
* handle again. */
|
|
|
05bba0 |
do {
|
|
|
05bba0 |
@@ -271,6 +284,41 @@ static void curl_multi_do(void *arg)
|
|
|
05bba0 |
} while(msgs_in_queue);
|
|
|
05bba0 |
}
|
|
|
05bba0 |
|
|
|
05bba0 |
+static void curl_multi_do(void *arg)
|
|
|
05bba0 |
+{
|
|
|
05bba0 |
+ BDRVCURLState *s = (BDRVCURLState *)arg;
|
|
|
05bba0 |
+ int running;
|
|
|
05bba0 |
+ int r;
|
|
|
05bba0 |
+
|
|
|
05bba0 |
+ if (!s->multi) {
|
|
|
05bba0 |
+ return;
|
|
|
05bba0 |
+ }
|
|
|
05bba0 |
+
|
|
|
05bba0 |
+ do {
|
|
|
05bba0 |
+ r = curl_multi_socket_all(s->multi, &running);
|
|
|
05bba0 |
+ } while(r == CURLM_CALL_MULTI_PERFORM);
|
|
|
05bba0 |
+
|
|
|
05bba0 |
+ curl_multi_read(s);
|
|
|
05bba0 |
+}
|
|
|
05bba0 |
+
|
|
|
05bba0 |
+static void curl_multi_timeout_do(void *arg)
|
|
|
05bba0 |
+{
|
|
|
05bba0 |
+#ifdef NEED_CURL_TIMER_CALLBACK
|
|
|
05bba0 |
+ BDRVCURLState *s = (BDRVCURLState *)arg;
|
|
|
05bba0 |
+ int running;
|
|
|
05bba0 |
+
|
|
|
05bba0 |
+ if (!s->multi) {
|
|
|
05bba0 |
+ return;
|
|
|
05bba0 |
+ }
|
|
|
05bba0 |
+
|
|
|
05bba0 |
+ curl_multi_socket_action(s->multi, CURL_SOCKET_TIMEOUT, 0, &running);
|
|
|
05bba0 |
+
|
|
|
05bba0 |
+ curl_multi_read(s);
|
|
|
05bba0 |
+#else
|
|
|
05bba0 |
+ abort();
|
|
|
05bba0 |
+#endif
|
|
|
05bba0 |
+}
|
|
|
05bba0 |
+
|
|
|
05bba0 |
static CURLState *curl_init_state(BDRVCURLState *s)
|
|
|
05bba0 |
{
|
|
|
05bba0 |
CURLState *state = NULL;
|
|
|
05bba0 |
@@ -462,12 +510,19 @@ static int curl_open(BlockDriverState *bs, QDict *options, int flags,
|
|
|
05bba0 |
curl_easy_cleanup(state->curl);
|
|
|
05bba0 |
state->curl = NULL;
|
|
|
05bba0 |
|
|
|
05bba0 |
+ s->timer = qemu_new_timer(rt_clock, SCALE_NS,
|
|
|
05bba0 |
+ curl_multi_timeout_do, s);
|
|
|
05bba0 |
+
|
|
|
05bba0 |
// Now we know the file exists and its size, so let's
|
|
|
05bba0 |
// initialize the multi interface!
|
|
|
05bba0 |
|
|
|
05bba0 |
s->multi = curl_multi_init();
|
|
|
05bba0 |
curl_multi_setopt(s->multi, CURLMOPT_SOCKETDATA, s);
|
|
|
05bba0 |
curl_multi_setopt(s->multi, CURLMOPT_SOCKETFUNCTION, curl_sock_cb);
|
|
|
05bba0 |
+#ifdef NEED_CURL_TIMER_CALLBACK
|
|
|
05bba0 |
+ curl_multi_setopt(s->multi, CURLMOPT_TIMERDATA, s);
|
|
|
05bba0 |
+ curl_multi_setopt(s->multi, CURLMOPT_TIMERFUNCTION, curl_timer_cb);
|
|
|
05bba0 |
+#endif
|
|
|
05bba0 |
curl_multi_do(s);
|
|
|
05bba0 |
|
|
|
05bba0 |
qemu_opts_del(opts);
|
|
|
05bba0 |
@@ -607,6 +662,10 @@ static void curl_close(BlockDriverState *bs)
|
|
|
05bba0 |
}
|
|
|
05bba0 |
if (s->multi)
|
|
|
05bba0 |
curl_multi_cleanup(s->multi);
|
|
|
05bba0 |
+
|
|
|
05bba0 |
+ qemu_del_timer(s->timer);
|
|
|
05bba0 |
+ qemu_free_timer(s->timer);
|
|
|
05bba0 |
+
|
|
|
05bba0 |
g_free(s->url);
|
|
|
05bba0 |
}
|
|
|
05bba0 |
|
|
|
05bba0 |
--
|
|
|
05bba0 |
1.8.3.1
|
|
|
05bba0 |
|