This uses nonblocking connect functions to connect to the sheepdog
server.  The connect operation is done in a coroutine function and it
will be yielded until the created socked is ready for IO.

Signed-off-by: MORITA Kazutaka <morita.kazut...@lab.ntt.co.jp>
---
 block/sheepdog.c | 70 ++++++++++++++++++++++++++++++++++++++++++++++++++------
 1 file changed, 63 insertions(+), 7 deletions(-)

diff --git a/block/sheepdog.c b/block/sheepdog.c
index 6a41ad9..6f5ede4 100644
--- a/block/sheepdog.c
+++ b/block/sheepdog.c
@@ -455,18 +455,51 @@ static SheepdogAIOCB *sd_aio_setup(BlockDriverState *bs, 
QEMUIOVector *qiov,
     return acb;
 }
 
-static int connect_to_sdog(BDRVSheepdogState *s)
-{
+typedef struct SheepdogConnectCo {
+    BDRVSheepdogState *bs;
+    Coroutine *co;
     int fd;
+    bool finished;
+} SheepdogConnectCo;
+
+static void sd_connect_completed(int fd, void *opaque)
+{
+    SheepdogConnectCo *scco = opaque;
+
+    if (fd < 0) {
+        int val, rc;
+        socklen_t valsize = sizeof(val);
+
+        do {
+            rc = qemu_getsockopt(scco->fd, SOL_SOCKET, SO_ERROR, &val,
+                                 &valsize);
+        } while (rc == -1 && socket_error() == EINTR);
+
+        scco->fd = rc < 0 ? -errno : -val;
+    }
+
+    scco->finished = true;
+
+    if (scco->co != NULL) {
+        qemu_coroutine_enter(scco->co, NULL);
+    }
+}
+
+static coroutine_fn void co_connect_to_sdog(void *opaque)
+{
+    SheepdogConnectCo *scco = opaque;
+    BDRVSheepdogState *s = scco->bs;
     Error *err = NULL;
 
     if (s->is_unix) {
-        fd = unix_connect(s->host_spec, &err);
+        scco->fd = unix_nonblocking_connect(s->host_spec, sd_connect_completed,
+                                            opaque, &err);
     } else {
-        fd = inet_connect(s->host_spec, &err);
+        scco->fd = inet_nonblocking_connect(s->host_spec, sd_connect_completed,
+                                            opaque, &err);
 
         if (err == NULL) {
-            int ret = socket_set_nodelay(fd);
+            int ret = socket_set_nodelay(scco->fd);
             if (ret < 0) {
                 error_report("%s", strerror(errno));
             }
@@ -476,11 +509,34 @@ static int connect_to_sdog(BDRVSheepdogState *s)
     if (err != NULL) {
         qerror_report_err(err);
         error_free(err);
+    }
+
+    if (!scco->finished) {
+        /* wait for connect to finish */
+        scco->co = qemu_coroutine_self();
+        qemu_coroutine_yield();
+    }
+}
+
+static int connect_to_sdog(BDRVSheepdogState *s)
+{
+    Coroutine *co;
+    SheepdogConnectCo scco = {
+        .bs = s,
+        .finished = false,
+    };
+
+    if (qemu_in_coroutine()) {
+        co_connect_to_sdog(&scco);
     } else {
-        qemu_set_nonblock(fd);
+        co = qemu_coroutine_create(co_connect_to_sdog);
+        qemu_coroutine_enter(co, &scco);
+        while (!scco.finished) {
+            qemu_aio_wait();
+        }
     }
 
-    return fd;
+    return scco.fd;
 }
 
 static coroutine_fn int send_co_req(int sockfd, SheepdogReq *hdr, void *data,
-- 
1.8.1.3.566.gaa39828


Reply via email to