diff options
| author | Anthony Liguori <aliguori@us.ibm.com> | 2011-12-27 08:52:42 -0600 |
|---|---|---|
| committer | Anthony Liguori <aliguori@us.ibm.com> | 2011-12-27 08:52:42 -0600 |
| commit | ebdfc3c83cef33f8f619ffcb57d297c6063db59d (patch) | |
| tree | af4c54a676ecc8b9c6bae7370a27261b640a247c /cutils.c | |
| parent | a0fa82085e175bf8ce6d69a3f83695f81af2a649 (diff) | |
| parent | 44f76b289a33399abedfbca2d92d21d910792264 (diff) | |
| download | focaccia-qemu-ebdfc3c83cef33f8f619ffcb57d297c6063db59d.tar.gz focaccia-qemu-ebdfc3c83cef33f8f619ffcb57d297c6063db59d.zip | |
Merge remote-tracking branch 'bonzini/nbd-for-anthony' into staging
* bonzini/nbd-for-anthony: (26 commits) nbd: add myself as maintainer qemu-nbd: throttle requests qemu-nbd: asynchronous operation qemu-nbd: add client pointer to NBDRequest qemu-nbd: move client handling to nbd.c qemu-nbd: use common main loop link the main loop and its dependencies into the tools qemu-nbd: introduce NBDRequest qemu-nbd: introduce NBDExport qemu-nbd: introduce nbd_do_receive_request qemu-nbd: more robust handling of invalid requests qemu-nbd: introduce nbd_do_send_reply qemu-nbd: simplify nbd_trip move corking functions to osdep.c qemu-nbd: remove data_size argument to nbd_trip qemu-nbd: remove offset argument to nbd_trip Update ioctl order in nbd_init() to detect EBUSY nbd: add support for NBD_CMD_TRIM nbd: add support for NBD_CMD_FLUSH nbd: add support for NBD_CMD_FLAG_FUA ...
Diffstat (limited to 'cutils.c')
| -rw-r--r-- | cutils.c | 111 |
1 files changed, 111 insertions, 0 deletions
diff --git a/cutils.c b/cutils.c index 24b3fe355b..a6ffd46445 100644 --- a/cutils.c +++ b/cutils.c @@ -25,6 +25,8 @@ #include "host-utils.h" #include <math.h> +#include "qemu_socket.h" + void pstrcpy(char *buf, int buf_size, const char *str) { int c; @@ -403,3 +405,112 @@ int qemu_parse_fd(const char *param) } return fd; } + +/* + * Send/recv data with iovec buffers + * + * This function send/recv data from/to the iovec buffer directly. + * The first `offset' bytes in the iovec buffer are skipped and next + * `len' bytes are used. + * + * For example, + * + * do_sendv_recvv(sockfd, iov, len, offset, 1); + * + * is equal to + * + * char *buf = malloc(size); + * iov_to_buf(iov, iovcnt, buf, offset, size); + * send(sockfd, buf, size, 0); + * free(buf); + */ +static int do_sendv_recvv(int sockfd, struct iovec *iov, int len, int offset, + int do_sendv) +{ + int ret, diff, iovlen; + struct iovec *last_iov; + + /* last_iov is inclusive, so count from one. */ + iovlen = 1; + last_iov = iov; + len += offset; + + while (last_iov->iov_len < len) { + len -= last_iov->iov_len; + + last_iov++; + iovlen++; + } + + diff = last_iov->iov_len - len; + last_iov->iov_len -= diff; + + while (iov->iov_len <= offset) { + offset -= iov->iov_len; + + iov++; + iovlen--; + } + + iov->iov_base = (char *) iov->iov_base + offset; + iov->iov_len -= offset; + + { +#if defined CONFIG_IOVEC && defined CONFIG_POSIX + struct msghdr msg; + memset(&msg, 0, sizeof(msg)); + msg.msg_iov = iov; + msg.msg_iovlen = iovlen; + + do { + if (do_sendv) { + ret = sendmsg(sockfd, &msg, 0); + } else { + ret = recvmsg(sockfd, &msg, 0); + } + } while (ret == -1 && errno == EINTR); +#else + struct iovec *p = iov; + ret = 0; + while (iovlen > 0) { + int rc; + if (do_sendv) { + rc = send(sockfd, p->iov_base, p->iov_len, 0); + } else { + rc = qemu_recv(sockfd, p->iov_base, p->iov_len, 0); + } + if (rc == -1) { + if (errno == EINTR) { + continue; + } + if (ret == 0) { + ret = -1; + } + break; + } + if (rc == 0) { + break; + } + ret += rc; + iovlen--, p++; + } +#endif + } + + /* Undo the changes above */ + iov->iov_base = (char *) iov->iov_base - offset; + iov->iov_len += offset; + last_iov->iov_len += diff; + return ret; +} + +int qemu_recvv(int sockfd, struct iovec *iov, int len, int iov_offset) +{ + return do_sendv_recvv(sockfd, iov, len, iov_offset, 0); +} + +int qemu_sendv(int sockfd, struct iovec *iov, int len, int iov_offset) +{ + return do_sendv_recvv(sockfd, iov, len, iov_offset, 1); +} + |