Commit 83f75c26 authored by Paolo Bonzini's avatar Paolo Bonzini
Browse files

iov: handle partial writes from sendmsg and recvmsg



Partial writes can still happen in sendmsg and recvmsg, if a
signal is received in the middle of a write.  To handle this,
retry the operation with a new offset/bytes pair.

Reviewed-by: default avatarJuan Quintela <quintela@redhat.com>
Reviewed-by: default avatarOrit Wassermann <owasserm@redhat.com>
Signed-off-by: default avatarPaolo Bonzini <pbonzini@redhat.com>
parent f48869ad
Loading
Loading
Loading
Loading
+55 −47
Original line number Diff line number Diff line
@@ -144,18 +144,12 @@ ssize_t iov_send_recv(int sockfd, struct iovec *iov, unsigned iov_cnt,
                      size_t offset, size_t bytes,
                      bool do_send)
{
    ssize_t total = 0;
    ssize_t ret;
    size_t orig_len, tail;
    unsigned niov;

    if (bytes == 0) {
        /* Catch the do-nothing case early, as otherwise we will pass an
         * empty iovec to sendmsg/recvmsg(), and not all implementations
         * accept this.
         */
        return 0;
    }

    while (bytes > 0) {
        /* Find the start position, skipping `offset' bytes:
         * first, skip all full-sized vector elements, */
        for (niov = 0; niov < iov_cnt && offset >= iov[niov].iov_len; ++niov) {
@@ -163,7 +157,7 @@ ssize_t iov_send_recv(int sockfd, struct iovec *iov, unsigned iov_cnt,
        }

        /* niov == iov_cnt would only be valid if bytes == 0, which
     * we already ruled out above.  */
         * we already ruled out in the loop condition.  */
        assert(niov < iov_cnt);
        iov += niov;
        iov_cnt -= niov;
@@ -191,7 +185,7 @@ ssize_t iov_send_recv(int sockfd, struct iovec *iov, unsigned iov_cnt,

        ret = do_send_recv(sockfd, iov, niov, do_send);

    /* Undo the changes above */
        /* Undo the changes above before checking for errors */
        if (tail) {
            iov[niov-1].iov_len = orig_len;
        }
@@ -200,7 +194,21 @@ ssize_t iov_send_recv(int sockfd, struct iovec *iov, unsigned iov_cnt,
            iov[0].iov_len += offset;
        }

    return ret;
        if (ret < 0) {
            assert(errno != EINTR);
            if (errno == EAGAIN && total > 0) {
                return total;
            }
            return -1;
        }

        /* Prepare for the next iteration */
        offset += ret;
        total += ret;
        bytes -= ret;
    }

    return total;
}