summary refs log tree commit diff stats
path: root/nbd/common.c
diff options
context:
space:
mode:
authorDaniel P. Berrange <berrange@redhat.com>2016-02-10 18:41:04 +0000
committerPaolo Bonzini <pbonzini@redhat.com>2016-02-16 17:13:57 +0100
commit1c778ef729dd50d4b06780af1f44b69c63c532f8 (patch)
tree72727b34634cbed27f46f2dc32d5eb7c0444a6fd /nbd/common.c
parentae39827802bc2aa781137d2f41bab0b60acd4e63 (diff)
downloadfocaccia-qemu-1c778ef729dd50d4b06780af1f44b69c63c532f8.tar.gz
focaccia-qemu-1c778ef729dd50d4b06780af1f44b69c63c532f8.zip
nbd: convert to using I/O channels for actual socket I/O
Now that all callers are converted to use I/O channels for
initial connection setup, it is possible to switch the core
NBD protocol handling core over to use QIOChannel APIs for
actual sockets I/O.

Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
Message-Id: <1455129674-17255-7-git-send-email-berrange@redhat.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
Diffstat (limited to 'nbd/common.c')
-rw-r--r--nbd/common.c68
1 files changed, 40 insertions, 28 deletions
diff --git a/nbd/common.c b/nbd/common.c
index 178d4a7ff2..2b19c95099 100644
--- a/nbd/common.c
+++ b/nbd/common.c
@@ -19,47 +19,59 @@
 #include "qemu/osdep.h"
 #include "nbd-internal.h"
 
-ssize_t nbd_wr_sync(int fd, void *buffer, size_t size, bool do_read)
+ssize_t nbd_wr_syncv(QIOChannel *ioc,
+                     struct iovec *iov,
+                     size_t niov,
+                     size_t offset,
+                     size_t length,
+                     bool do_read)
 {
-    size_t offset = 0;
-    int err;
+    ssize_t done = 0;
+    Error *local_err = NULL;
+    struct iovec *local_iov = g_new(struct iovec, niov);
+    struct iovec *local_iov_head = local_iov;
+    unsigned int nlocal_iov = niov;
 
-    if (qemu_in_coroutine()) {
-        if (do_read) {
-            return qemu_co_recv(fd, buffer, size);
-        } else {
-            return qemu_co_send(fd, buffer, size);
-        }
-    }
+    nlocal_iov = iov_copy(local_iov, nlocal_iov,
+                          iov, niov,
+                          offset, length);
 
-    while (offset < size) {
+    while (nlocal_iov > 0) {
         ssize_t len;
-
         if (do_read) {
-            len = qemu_recv(fd, buffer + offset, size - offset, 0);
+            len = qio_channel_readv(ioc, local_iov, nlocal_iov, &local_err);
         } else {
-            len = send(fd, buffer + offset, size - offset, 0);
+            len = qio_channel_writev(ioc, local_iov, nlocal_iov, &local_err);
         }
-
-        if (len < 0) {
-            err = socket_error();
-
-            /* recoverable error */
-            if (err == EINTR || (offset > 0 && (err == EAGAIN || err == EWOULDBLOCK))) {
-                continue;
+        if (len == QIO_CHANNEL_ERR_BLOCK) {
+            if (qemu_in_coroutine()) {
+                /* XXX figure out if we can create a variant on
+                 * qio_channel_yield() that works with AIO contexts
+                 * and consider using that in this branch */
+                qemu_coroutine_yield();
+            } else {
+                qio_channel_wait(ioc,
+                                 do_read ? G_IO_IN : G_IO_OUT);
             }
-
-            /* unrecoverable error */
-            return -err;
+            continue;
+        }
+        if (len < 0) {
+            TRACE("I/O error: %s", error_get_pretty(local_err));
+            error_free(local_err);
+            /* XXX handle Error objects */
+            done = -EIO;
+            goto cleanup;
         }
 
-        /* eof */
-        if (len == 0) {
+        if (do_read && len == 0) {
             break;
         }
 
-        offset += len;
+        iov_discard_front(&local_iov, &nlocal_iov, len);
+        done += len;
     }
 
-    return offset;
+ cleanup:
+    g_free(local_iov_head);
+    return done;
 }