diff options
author | Daniel P. Berrange <berrange@redhat.com> | 2016-02-10 18:41:04 +0000 |
---|---|---|
committer | Paolo Bonzini <pbonzini@redhat.com> | 2016-02-16 17:13:57 +0100 |
commit | 1c778ef729dd50d4b06780af1f44b69c63c532f8 (patch) | |
tree | 72727b34634cbed27f46f2dc32d5eb7c0444a6fd /nbd/common.c | |
parent | ae39827802bc2aa781137d2f41bab0b60acd4e63 (diff) |
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.c | 68 |
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; } |