Signed-off-by: Chuck Lever <chuck.lever@xxxxxxxxxx> --- net/sunrpc/svcsock.c | 39 ++++++++++++++++++++++++--------------- 1 file changed, 24 insertions(+), 15 deletions(-) diff --git a/net/sunrpc/svcsock.c b/net/sunrpc/svcsock.c index 2934dd711715..966ea431f845 100644 --- a/net/sunrpc/svcsock.c +++ b/net/sunrpc/svcsock.c @@ -187,14 +187,12 @@ int svc_send_common(struct socket *sock, struct xdr_buf *xdr, size_t base = xdr->page_base; unsigned int pglen = xdr->page_len; unsigned int flags = MSG_MORE | MSG_SENDPAGE_NOTLAST; - int slen; + int slen = xdr_buf_msglen(xdr); int len = 0; - slen = xdr->len; - /* send head */ if (slen == xdr->head[0].iov_len) - flags = 0; + flags = MSG_EOR; len = kernel_sendpage(sock, headpage, headoffset, xdr->head[0].iov_len, flags); if (len != xdr->head[0].iov_len) @@ -207,7 +205,7 @@ int svc_send_common(struct socket *sock, struct xdr_buf *xdr, size = PAGE_SIZE - base < pglen ? PAGE_SIZE - base : pglen; while (pglen > 0) { if (slen == size) - flags = 0; + flags = MSG_EOR; result = kernel_sendpage(sock, *ppage, base, size, flags); if (result > 0) len += result; @@ -219,11 +217,21 @@ int svc_send_common(struct socket *sock, struct xdr_buf *xdr, base = 0; ppage++; } + if (xdr->page_pad) { + if (!xdr->tail[0].iov_len) + flags = MSG_EOR; + result = kernel_sendpage(sock, ZERO_PAGE(0), 0, + xdr->page_pad, flags); + if (result > 0) + len += result; + if (result != xdr->page_pad) + goto out; + } /* send tail */ if (xdr->tail[0].iov_len) { result = kernel_sendpage(sock, tailpage, tailoffset, - xdr->tail[0].iov_len, 0); + xdr->tail[0].iov_len, MSG_EOR); if (result > 0) len += result; } @@ -272,9 +280,9 @@ static int svc_sendto(struct svc_rqst *rqstp, struct xdr_buf *xdr) rqstp->rq_respages[0], tailoff); out: - dprintk("svc: socket %p sendto([%p %zu... ], %d) = %d (addr %s)\n", + dprintk("svc: socket %p sendto([%p %zu... ], %zu) = %d (addr %s)\n", svsk, xdr->head[0].iov_base, xdr->head[0].iov_len, - xdr->len, len, svc_print_addr(rqstp, buf, sizeof(buf))); + xdr_buf_msglen(xdr), len, svc_print_addr(rqstp, buf, sizeof(buf))); return len; } @@ -1134,24 +1142,25 @@ static int svc_tcp_recvfrom(struct svc_rqst *rqstp) static int svc_tcp_sendto(struct svc_rqst *rqstp) { struct xdr_buf *xbufp = &rqstp->rq_res; + u32 reclen = xdr_buf_msglen(xbufp); + __be32 marker; int sent; - __be32 reclen; /* Set up the first element of the reply kvec. * Any other kvecs that may be in use have been taken * care of by the server implementation itself. */ - reclen = htonl(0x80000000|((xbufp->len ) - 4)); - memcpy(xbufp->head[0].iov_base, &reclen, 4); + marker = cpu_to_be32(0x80000000 | (reclen - sizeof(marker))); + memcpy(xbufp->head[0].iov_base, &marker, sizeof(marker)); sent = svc_sendto(rqstp, &rqstp->rq_res); - if (sent != xbufp->len) { + if (sent != reclen) { printk(KERN_NOTICE - "rpc-srv/tcp: %s: %s %d when sending %d bytes " + "rpc-srv/tcp: %s: %s %d when sending %u bytes " "- shutting down socket\n", rqstp->rq_xprt->xpt_server->sv_name, - (sent<0)?"got error":"sent only", - sent, xbufp->len); + (sent<0)?"got error":"sent", + sent, reclen); set_bit(XPT_CLOSE, &rqstp->rq_xprt->xpt_flags); svc_xprt_enqueue(rqstp->rq_xprt); sent = -EAGAIN;