fs/nfs/nfs2xdr.c | 6 - fs/nfs/nfs3xdr.c | 6 - fs/nfs/nfs4xdr.c | 6 - include/linux/sunrpc/xdr.h | 83 +---------------------- include/linux/sunrpc/xprt.h | 2 net/sunrpc/clnt.c | 10 ++ net/sunrpc/sunrpc_syms.c | 2 net/sunrpc/xdr.c | 154 ++++++++++++++++++++++++++++++++++++++++---- net/sunrpc/xprt.c | 6 - 9 files changed, 168 insertions(+), 107 deletions(-) diff -u --recursive --new-file --show-c-function linux-2.6.5-29-cleanup_fsinfo/fs/nfs/nfs2xdr.c linux-2.6.5-30-xdr_length/fs/nfs/nfs2xdr.c --- linux-2.6.5-29-cleanup_fsinfo/fs/nfs/nfs2xdr.c 2004-03-23 10:33:06.000000000 -0500 +++ linux-2.6.5-30-xdr_length/fs/nfs/nfs2xdr.c 2004-03-24 00:49:39.000000000 -0500 @@ -231,7 +231,7 @@ nfs_xdr_readargs(struct rpc_rqst *req, u static int nfs_xdr_readres(struct rpc_rqst *req, u32 *p, struct nfs_readres *res) { - struct iovec *iov = req->rq_rvec; + struct iovec *iov = req->rq_rcv_buf.head; int status, count, recvd, hdrlen; if ((status = ntohl(*p++))) @@ -250,7 +250,7 @@ nfs_xdr_readres(struct rpc_rqst *req, u3 xdr_shift_buf(&req->rq_rcv_buf, iov->iov_len - hdrlen); } - recvd = req->rq_received - hdrlen; + recvd = req->rq_rcv_buf.len - hdrlen; if (count > recvd) { printk(KERN_WARNING "NFS: server cheating in read reply: " "count %d > recvd %d\n", count, recvd); @@ -396,7 +396,7 @@ nfs_xdr_readdirres(struct rpc_rqst *req, } pglen = rcvbuf->page_len; - recvd = req->rq_received - hdrlen; + recvd = rcvbuf->len - hdrlen; if (pglen > recvd) pglen = recvd; page = rcvbuf->pages; diff -u --recursive --new-file --show-c-function linux-2.6.5-29-cleanup_fsinfo/fs/nfs/nfs3xdr.c linux-2.6.5-30-xdr_length/fs/nfs/nfs3xdr.c --- linux-2.6.5-29-cleanup_fsinfo/fs/nfs/nfs3xdr.c 2004-03-23 10:34:03.000000000 -0500 +++ linux-2.6.5-30-xdr_length/fs/nfs/nfs3xdr.c 2004-03-24 00:49:40.000000000 -0500 @@ -515,7 +515,7 @@ nfs3_xdr_readdirres(struct rpc_rqst *req } pglen = rcvbuf->page_len; - recvd = req->rq_received - hdrlen; + recvd = rcvbuf->len - hdrlen; if (pglen > recvd) pglen = recvd; page = rcvbuf->pages; @@ -758,7 +758,7 @@ nfs3_xdr_readlinkres(struct rpc_rqst *re static int nfs3_xdr_readres(struct rpc_rqst *req, u32 *p, struct nfs_readres *res) { - struct iovec *iov = req->rq_rvec; + struct iovec *iov = req->rq_rcv_buf.head; int status, count, ocount, recvd, hdrlen; status = ntohl(*p++); @@ -789,7 +789,7 @@ nfs3_xdr_readres(struct rpc_rqst *req, u xdr_shift_buf(&req->rq_rcv_buf, iov->iov_len - hdrlen); } - recvd = req->rq_received - hdrlen; + recvd = req->rq_rcv_buf.len - hdrlen; if (count > recvd) { printk(KERN_WARNING "NFS: server cheating in read reply: " "count %d > recvd %d\n", count, recvd); diff -u --recursive --new-file --show-c-function linux-2.6.5-29-cleanup_fsinfo/fs/nfs/nfs4xdr.c linux-2.6.5-30-xdr_length/fs/nfs/nfs4xdr.c --- linux-2.6.5-29-cleanup_fsinfo/fs/nfs/nfs4xdr.c 2004-03-24 00:49:32.000000000 -0500 +++ linux-2.6.5-30-xdr_length/fs/nfs/nfs4xdr.c 2004-03-24 00:49:40.000000000 -0500 @@ -2675,7 +2675,7 @@ static int decode_putrootfh(struct xdr_s static int decode_read(struct xdr_stream *xdr, struct rpc_rqst *req, struct nfs_readres *res) { - struct iovec *iov = req->rq_rvec; + struct iovec *iov = req->rq_rcv_buf.head; uint32_t *p; uint32_t count, eof, recvd, hdrlen; int status; @@ -2687,7 +2687,7 @@ static int decode_read(struct xdr_stream READ32(eof); READ32(count); hdrlen = (u8 *) p - (u8 *) iov->iov_base; - recvd = req->rq_received - hdrlen; + recvd = req->rq_rcv_buf.len - hdrlen; if (count > recvd) { printk(KERN_WARNING "NFS: server cheating in read reply: " "count %u > recvd %u\n", count, recvd); @@ -2717,7 +2717,7 @@ static int decode_readdir(struct xdr_str COPYMEM(readdir->verifier.data, 8); hdrlen = (char *) p - (char *) iov->iov_base; - recvd = req->rq_received - hdrlen; + recvd = rcvbuf->len - hdrlen; if (pglen > recvd) pglen = recvd; xdr_read_pages(xdr, pglen); diff -u --recursive --new-file --show-c-function linux-2.6.5-29-cleanup_fsinfo/include/linux/sunrpc/xdr.h linux-2.6.5-30-xdr_length/include/linux/sunrpc/xdr.h --- linux-2.6.5-29-cleanup_fsinfo/include/linux/sunrpc/xdr.h 2004-03-24 00:47:00.000000000 -0500 +++ linux-2.6.5-30-xdr_length/include/linux/sunrpc/xdr.h 2004-03-24 00:49:40.000000000 -0500 @@ -55,7 +55,8 @@ struct xdr_buf { unsigned int page_base, /* Start of page data */ page_len; /* Length of page data */ - unsigned int len; /* Total length of data */ + unsigned int buflen, /* Total length of storage buffer */ + len; /* Length of XDR encoded message */ }; @@ -183,86 +184,14 @@ struct xdr_stream { struct iovec *iov; /* pointer to the current iovec */ }; -/* - * Initialize an xdr_stream for encoding data. - * - * Note: at the moment the RPC client only passes the length of our - * scratch buffer in the xdr_buf's header iovec. Previously this - * meant we needed to call xdr_adjust_iovec() after encoding the - * data. With the new scheme, the xdr_stream manages the details - * of the buffer length, and takes care of adjusting the iovec - * length for us. - */ -static inline void -xdr_init_encode(struct xdr_stream *xdr, struct xdr_buf *buf, uint32_t *p) -{ - struct iovec *iov = buf->head; - - xdr->buf = buf; - xdr->iov = iov; - xdr->end = (uint32_t *)((char *)iov->iov_base + iov->iov_len); - buf->len = iov->iov_len = (char *)p - (char *)iov->iov_base; - xdr->p = p; -} - -/* - * Check that we have enough buffer space to encode 'nbytes' more - * bytes of data. If so, update the total xdr_buf length, and - * adjust the length of the current iovec. - */ -static inline uint32_t * -xdr_reserve_space(struct xdr_stream *xdr, size_t nbytes) -{ - uint32_t *p = xdr->p; - uint32_t *q; - - /* align nbytes on the next 32-bit boundary */ - nbytes += 3; - nbytes &= ~3; - q = p + (nbytes >> 2); - if (unlikely(q > xdr->end || q < p)) - return NULL; - xdr->p = q; - xdr->iov->iov_len += nbytes; - xdr->buf->len += nbytes; - return p; -} - +extern void xdr_init_encode(struct xdr_stream *xdr, struct xdr_buf *buf, uint32_t *p); +extern uint32_t *xdr_reserve_space(struct xdr_stream *xdr, size_t nbytes); extern void xdr_write_pages(struct xdr_stream *xdr, struct page **pages, unsigned int base, unsigned int len); +extern void xdr_init_decode(struct xdr_stream *xdr, struct xdr_buf *buf, uint32_t *p); +extern uint32_t *xdr_inline_decode(struct xdr_stream *xdr, size_t nbytes); extern void xdr_read_pages(struct xdr_stream *xdr, unsigned int len); -/* - * Initialize an xdr_stream for decoding data. - */ -static inline void -xdr_init_decode(struct xdr_stream *xdr, struct xdr_buf *buf, uint32_t *p) -{ - struct iovec *iov = buf->head; - xdr->buf = buf; - xdr->iov = iov; - xdr->p = p; - xdr->end = (uint32_t *)((char *)iov->iov_base + iov->iov_len); -} - -/* - * Check if the input buffer is long enough to enable us to decode - * 'nbytes' more bytes of data starting at the current position. - * If so return the current pointer, then update the current - * position. - */ -static inline uint32_t * -xdr_inline_decode(struct xdr_stream *xdr, size_t nbytes) -{ - uint32_t *p = xdr->p; - uint32_t *q = p + XDR_QUADLEN(nbytes); - - if (unlikely(q > xdr->end || q < p)) - return NULL; - xdr->p = q; - return p; -} - #endif /* __KERNEL__ */ #endif /* _SUNRPC_XDR_H_ */ diff -u --recursive --new-file --show-c-function linux-2.6.5-29-cleanup_fsinfo/include/linux/sunrpc/xprt.h linux-2.6.5-30-xdr_length/include/linux/sunrpc/xprt.h --- linux-2.6.5-29-cleanup_fsinfo/include/linux/sunrpc/xprt.h 2004-03-23 10:33:29.000000000 -0500 +++ linux-2.6.5-30-xdr_length/include/linux/sunrpc/xprt.h 2004-03-24 00:49:40.000000000 -0500 @@ -120,8 +120,6 @@ struct rpc_rqst { }; #define rq_svec rq_snd_buf.head #define rq_slen rq_snd_buf.len -#define rq_rvec rq_rcv_buf.head -#define rq_rlen rq_rcv_buf.len #define XPRT_LAST_FRAG (1 << 0) #define XPRT_COPY_RECM (1 << 1) diff -u --recursive --new-file --show-c-function linux-2.6.5-29-cleanup_fsinfo/net/sunrpc/clnt.c linux-2.6.5-30-xdr_length/net/sunrpc/clnt.c --- linux-2.6.5-29-cleanup_fsinfo/net/sunrpc/clnt.c 2004-03-24 00:46:21.000000000 -0500 +++ linux-2.6.5-30-xdr_length/net/sunrpc/clnt.c 2004-03-24 00:49:40.000000000 -0500 @@ -605,11 +605,13 @@ call_encode(struct rpc_task *task) sndbuf->tail[0].iov_len = 0; sndbuf->page_len = 0; sndbuf->len = 0; + sndbuf->buflen = bufsiz; rcvbuf->head[0].iov_base = (void *)((char *)task->tk_buffer + bufsiz); rcvbuf->head[0].iov_len = bufsiz; rcvbuf->tail[0].iov_len = 0; rcvbuf->page_len = 0; - rcvbuf->len = bufsiz; + rcvbuf->len = 0; + rcvbuf->buflen = bufsiz; /* Encode header and provided arguments */ encode = task->tk_msg.rpc_proc->p_encode; @@ -849,6 +851,8 @@ call_decode(struct rpc_task *task) return; } + req->rq_rcv_buf.len = req->rq_private_buf.len; + /* Check that the softirq receive buffer is valid */ WARN_ON(memcmp(&req->rq_rcv_buf, &req->rq_private_buf, sizeof(req->rq_rcv_buf)) != 0); @@ -884,7 +888,7 @@ call_decode(struct rpc_task *task) task->tk_status); return; out_retry: - req->rq_received = 0; + req->rq_received = req->rq_private_buf.len = 0; task->tk_status = 0; } @@ -956,7 +960,7 @@ call_header(struct rpc_task *task) static u32 * call_verify(struct rpc_task *task) { - u32 *p = task->tk_rqstp->rq_rvec[0].iov_base, n; + u32 *p = task->tk_rqstp->rq_rcv_buf.head[0].iov_base, n; p += 1; /* skip XID */ diff -u --recursive --new-file --show-c-function linux-2.6.5-29-cleanup_fsinfo/net/sunrpc/sunrpc_syms.c linux-2.6.5-30-xdr_length/net/sunrpc/sunrpc_syms.c --- linux-2.6.5-29-cleanup_fsinfo/net/sunrpc/sunrpc_syms.c 2004-03-24 00:47:00.000000000 -0500 +++ linux-2.6.5-30-xdr_length/net/sunrpc/sunrpc_syms.c 2004-03-24 00:49:40.000000000 -0500 @@ -128,8 +128,6 @@ EXPORT_SYMBOL(xdr_encode_netobj); EXPORT_SYMBOL(xdr_encode_pages); EXPORT_SYMBOL(xdr_inline_pages); EXPORT_SYMBOL(xdr_shift_buf); -EXPORT_SYMBOL(xdr_write_pages); -EXPORT_SYMBOL(xdr_read_pages); EXPORT_SYMBOL(xdr_buf_from_iov); EXPORT_SYMBOL(xdr_buf_subsegment); EXPORT_SYMBOL(xdr_buf_read_netobj); diff -u --recursive --new-file --show-c-function linux-2.6.5-29-cleanup_fsinfo/net/sunrpc/xdr.c linux-2.6.5-30-xdr_length/net/sunrpc/xdr.c --- linux-2.6.5-29-cleanup_fsinfo/net/sunrpc/xdr.c 2004-03-24 00:47:00.000000000 -0500 +++ linux-2.6.5-30-xdr_length/net/sunrpc/xdr.c 2004-03-24 00:49:40.000000000 -0500 @@ -160,6 +160,7 @@ xdr_encode_pages(struct xdr_buf *xdr, st tail->iov_len = pad; len += pad; } + xdr->buflen += len; xdr->len += len; } @@ -181,7 +182,7 @@ xdr_inline_pages(struct xdr_buf *xdr, un tail->iov_base = buf + offset; tail->iov_len = buflen - offset; - xdr->len += len; + xdr->buflen += len; } /* @@ -675,7 +676,10 @@ xdr_shrink_bufhead(struct xdr_buf *buf, copy); } head->iov_len -= len; - buf->len -= len; + buf->buflen -= len; + /* Have we truncated the message? */ + if (buf->len > buf->buflen) + buf->len = buf->buflen; } /* @@ -705,7 +709,7 @@ xdr_shrink_pagelen(struct xdr_buf *buf, copy = tail->iov_len - len; memmove(p, tail->iov_base, copy); } else - buf->len -= len; + buf->buflen -= len; /* Copy from the inlined pages into the tail */ copy = len; if (copy > tail->iov_len) @@ -715,7 +719,10 @@ xdr_shrink_pagelen(struct xdr_buf *buf, copy); } buf->page_len -= len; - buf->len -= len; + buf->buflen -= len; + /* Have we truncated the message? */ + if (buf->len > buf->buflen) + buf->len = buf->buflen; } void @@ -724,8 +731,67 @@ xdr_shift_buf(struct xdr_buf *buf, size_ xdr_shrink_bufhead(buf, len); } -void -xdr_write_pages(struct xdr_stream *xdr, struct page **pages, unsigned int base, +/** + * xdr_init_encode - Initialize a struct xdr_stream for sending data. + * @xdr: pointer to xdr_stream struct + * @buf: pointer to XDR buffer in which to encode data + * @p: current pointer inside XDR buffer + * + * Note: at the moment the RPC client only passes the length of our + * scratch buffer in the xdr_buf's header iovec. Previously this + * meant we needed to call xdr_adjust_iovec() after encoding the + * data. With the new scheme, the xdr_stream manages the details + * of the buffer length, and takes care of adjusting the iovec + * length for us. + */ +void xdr_init_encode(struct xdr_stream *xdr, struct xdr_buf *buf, uint32_t *p) +{ + struct iovec *iov = buf->head; + + xdr->buf = buf; + xdr->iov = iov; + xdr->end = (uint32_t *)((char *)iov->iov_base + iov->iov_len); + buf->len = iov->iov_len = (char *)p - (char *)iov->iov_base; + xdr->p = p; +} +EXPORT_SYMBOL(xdr_init_encode); + +/** + * xdr_reserve_space - Reserve buffer space for sending + * @xdr: pointer to xdr_stream + * @nbytes: number of bytes to reserve + * + * Checks that we have enough buffer space to encode 'nbytes' more + * bytes of data. If so, update the total xdr_buf length, and + * adjust the length of the current iovec. + */ +uint32_t * xdr_reserve_space(struct xdr_stream *xdr, size_t nbytes) +{ + uint32_t *p = xdr->p; + uint32_t *q; + + /* align nbytes on the next 32-bit boundary */ + nbytes += 3; + nbytes &= ~3; + q = p + (nbytes >> 2); + if (unlikely(q > xdr->end || q < p)) + return NULL; + xdr->p = q; + xdr->iov->iov_len += nbytes; + xdr->buf->len += nbytes; + return p; +} +EXPORT_SYMBOL(xdr_reserve_space); + +/** + * xdr_write_pages - Insert a list of pages into an XDR buffer for sending + * @xdr: pointer to xdr_stream + * @pages: list of pages + * @base: offset of first byte + * @len: length of data in bytes + * + */ +void xdr_write_pages(struct xdr_stream *xdr, struct page **pages, unsigned int base, unsigned int len) { struct xdr_buf *buf = xdr->buf; @@ -747,15 +813,69 @@ xdr_write_pages(struct xdr_stream *xdr, len += pad; *xdr->p++ = 0; } + buf->buflen += len; buf->len += len; } +EXPORT_SYMBOL(xdr_write_pages); -void -xdr_read_pages(struct xdr_stream *xdr, unsigned int len) +/** + * xdr_init_decode - Initialize an xdr_stream for decoding data. + * @xdr: pointer to xdr_stream struct + * @buf: pointer to XDR buffer from which to decode data + * @p: current pointer inside XDR buffer + */ +void xdr_init_decode(struct xdr_stream *xdr, struct xdr_buf *buf, uint32_t *p) +{ + struct iovec *iov = buf->head; + unsigned int len = iov->iov_len; + + if (len > buf->len) + len = buf->len; + xdr->buf = buf; + xdr->iov = iov; + xdr->p = p; + xdr->end = (uint32_t *)((char *)iov->iov_base + len); +} +EXPORT_SYMBOL(xdr_init_decode); + +/** + * xdr_inline_decode - Retrieve non-page XDR data to decode + * @xdr: pointer to xdr_stream struct + * @nbytes: number of bytes of data to decode + * + * Check if the input buffer is long enough to enable us to decode + * 'nbytes' more bytes of data starting at the current position. + * If so return the current pointer, then update the current + * pointer position. + */ +uint32_t * xdr_inline_decode(struct xdr_stream *xdr, size_t nbytes) +{ + uint32_t *p = xdr->p; + uint32_t *q = p + XDR_QUADLEN(nbytes); + + if (unlikely(q > xdr->end || q < p)) + return NULL; + xdr->p = q; + return p; +} +EXPORT_SYMBOL(xdr_inline_decode); + +/** + * xdr_read_pages - Ensure page-based XDR data to decode is aligned at current pointer position + * @xdr: pointer to xdr_stream struct + * @len: number of bytes of page data + * + * Moves data beyond the current pointer position from the XDR head[] buffer + * into the page list. Any data that lies beyond current position + "len" + * bytes is moved into the XDR tail[]. The current pointer is then + * repositioned at the beginning of the XDR tail. + */ +void xdr_read_pages(struct xdr_stream *xdr, unsigned int len) { struct xdr_buf *buf = xdr->buf; struct iovec *iov; ssize_t shift; + unsigned int end; int padding; /* Realign pages to current pointer position */ @@ -769,9 +889,21 @@ xdr_read_pages(struct xdr_stream *xdr, u xdr_shrink_pagelen(buf, buf->page_len - len); padding = (XDR_QUADLEN(len) << 2) - len; xdr->iov = iov = buf->tail; + /* Compute remaining message length. */ + end = iov->iov_len; + shift = buf->buflen - buf->len; + if (shift < end) + end -= shift; + else if (shift > 0) + end = 0; + /* + * Position current pointer at beginning of tail, and + * set remaining message length. + */ xdr->p = (uint32_t *)((char *)iov->iov_base + padding); - xdr->end = (uint32_t *)((char *)iov->iov_base + iov->iov_len); + xdr->end = (uint32_t *)((char *)iov->iov_base + end); } +EXPORT_SYMBOL(xdr_read_pages); static struct iovec empty_iov = {.iov_base = NULL, .iov_len = 0}; @@ -781,7 +913,7 @@ xdr_buf_from_iov(struct iovec *iov, stru buf->head[0] = *iov; buf->tail[0] = empty_iov; buf->page_len = 0; - buf->len = iov->iov_len; + buf->buflen = buf->len = iov->iov_len; } /* Sets subiov to the intersection of iov with the buffer of length len @@ -811,7 +943,7 @@ xdr_buf_subsegment(struct xdr_buf *buf, { int i; - subbuf->len = len; + subbuf->buflen = subbuf->len = len; iov_subsegment(buf->head, subbuf->head, &base, &len); if (base < buf->page_len) { diff -u --recursive --new-file --show-c-function linux-2.6.5-29-cleanup_fsinfo/net/sunrpc/xprt.c linux-2.6.5-30-xdr_length/net/sunrpc/xprt.c --- linux-2.6.5-29-cleanup_fsinfo/net/sunrpc/xprt.c 2004-03-24 00:46:21.000000000 -0500 +++ linux-2.6.5-30-xdr_length/net/sunrpc/xprt.c 2004-03-24 00:49:40.000000000 -0500 @@ -647,8 +647,8 @@ xprt_complete_rqst(struct rpc_xprt *xprt #endif dprintk("RPC: %4d has input (%d bytes)\n", task->tk_pid, copied); - req->rq_received = copied; list_del_init(&req->rq_list); + req->rq_received = req->rq_private_buf.len = copied; /* ... and wake up the process. */ rpc_wake_up_task(task); @@ -765,7 +765,7 @@ udp_data_ready(struct sock *sk, int len) dprintk("RPC: %4d received reply\n", task->tk_pid); - if ((copied = rovr->rq_private_buf.len) > repsize) + if ((copied = rovr->rq_private_buf.buflen) > repsize) copied = repsize; /* Suck it into the iovec, verify checksum if not done by hw. */ @@ -908,7 +908,7 @@ tcp_read_request(struct rpc_xprt *xprt, xprt->tcp_copied += len; xprt->tcp_offset += len; - if (xprt->tcp_copied == req->rq_private_buf.len) + if (xprt->tcp_copied == req->rq_private_buf.buflen) xprt->tcp_flags &= ~XPRT_COPY_DATA; else if (xprt->tcp_offset == xprt->tcp_reclen) { if (xprt->tcp_flags & XPRT_LAST_FRAG)