Server/client agnostic API changes to support padding xdr_buf::pages automatically. Signed-off-by: Chuck Lever <chuck.lever@xxxxxxxxxx> --- include/linux/sunrpc/xdr.h | 74 ++++++++++++++++++++++++++++++++++---------- net/sunrpc/svc.c | 2 + net/sunrpc/svc_xprt.c | 14 +++++--- 3 files changed, 67 insertions(+), 23 deletions(-) diff --git a/include/linux/sunrpc/xdr.h b/include/linux/sunrpc/xdr.h index b41f34977995..47f55aad5a1e 100644 --- a/include/linux/sunrpc/xdr.h +++ b/include/linux/sunrpc/xdr.h @@ -24,6 +24,34 @@ */ #define XDR_QUADLEN(l) (((l) + 3) >> 2) +/** + * xdr_align_size - Calculate padded size of an object + * @n: Size of an object being XDR encoded (in bytes) + * + * Return value: + * Size (in bytes) of the object including xdr padding + */ +static inline size_t +xdr_align_size(size_t n) +{ + const size_t mask = sizeof(__u32) - 1; + + return (n + mask) & ~mask; +} + +/** + * xdr_pad_size - Calculate XDR padding size + * @len: Actual size of object being XDR encoded (in bytes) + * + * Return value: + * Size (in bytes) of needed XDR padding + */ +static inline size_t +xdr_pad_size(size_t len) +{ + return xdr_align_size(len) - len; +} + /* * Generic opaque `network object.' At the kernel level, this type * is used only by lockd. @@ -39,9 +67,6 @@ struct xdr_netobj { * Features a header (for a linear buffer containing RPC headers * and the data payload for short messages), and then an array of * pages. - * The tail iovec allows you to append data after the page array. Its - * main interest is for appending padding to the pages in order to - * satisfy the int_32-alignment requirements in RFC1832. * * For the future, we might want to string several of these together * in a list if anybody wants to make use of NFSv4 COMPOUND @@ -55,6 +80,7 @@ struct xdr_buf { struct page ** pages; /* Array of pages */ unsigned int page_base, /* Start of page data */ page_len, /* Length of page data */ + page_pad, /* XDR padding needed for pages */ flags; /* Flags for data disposition */ #define XDRBUF_READ 0x01 /* target of file read */ #define XDRBUF_WRITE 0x02 /* source of file write */ @@ -72,11 +98,39 @@ struct xdr_buf { buf->tail[0].iov_len = 0; buf->pages = NULL; buf->page_len = 0; + buf->page_pad = 0; buf->flags = 0; buf->len = 0; buf->buflen = len; } +/** + * xdr_buf_set_pagelen - Set the length of the page list + * @buf: XDR buffer containing a message + * @len: Size of @buf's page list (in bytes) + * + */ +static inline void +xdr_buf_set_pagelen(struct xdr_buf *buf, size_t len) +{ + buf->page_len = len; + buf->page_pad = xdr_pad_size(len); +} + +/** + * xdr_buf_msglen - Return the length of the content in @buf + * @buf: XDR buffer containing an XDR-encoded message + * + * Return value: + * Size (in bytes) of the content in @buf + */ +static inline size_t +xdr_buf_msglen(const struct xdr_buf *buf) +{ + return buf->head[0].iov_len + buf->page_len + buf->page_pad + + buf->tail[0].iov_len; +} + /* * pre-xdr'ed macros. */ @@ -285,20 +339,6 @@ ssize_t xdr_stream_decode_string(struct xdr_stream *xdr, char *str, size_t size); ssize_t xdr_stream_decode_string_dup(struct xdr_stream *xdr, char **str, size_t maxlen, gfp_t gfp_flags); -/** - * xdr_align_size - Calculate padded size of an object - * @n: Size of an object being XDR encoded (in bytes) - * - * Return value: - * Size (in bytes) of the object including xdr padding - */ -static inline size_t -xdr_align_size(size_t n) -{ - const size_t mask = sizeof(__u32) - 1; - - return (n + mask) & ~mask; -} /** * xdr_stream_encode_u32 - Encode a 32-bit integer diff --git a/net/sunrpc/svc.c b/net/sunrpc/svc.c index 187dd4e73d64..63a3afac7100 100644 --- a/net/sunrpc/svc.c +++ b/net/sunrpc/svc.c @@ -1516,7 +1516,7 @@ static __printf(2,3) void svc_printk(struct svc_rqst *rqstp, const char *fmt, .. rqstp->rq_res.pages = rqstp->rq_respages + 1; rqstp->rq_res.len = 0; rqstp->rq_res.page_base = 0; - rqstp->rq_res.page_len = 0; + xdr_buf_set_pagelen(&rqstp->rq_res, 0); rqstp->rq_res.buflen = PAGE_SIZE; rqstp->rq_res.tail[0].iov_base = NULL; rqstp->rq_res.tail[0].iov_len = 0; diff --git a/net/sunrpc/svc_xprt.c b/net/sunrpc/svc_xprt.c index de3c077733a7..032c3bc91d43 100644 --- a/net/sunrpc/svc_xprt.c +++ b/net/sunrpc/svc_xprt.c @@ -510,7 +510,7 @@ static void svc_xprt_release(struct svc_rqst *rqstp) rqstp->rq_deferred = NULL; svc_free_res_pages(rqstp); - rqstp->rq_res.page_len = 0; + xdr_buf_set_pagelen(&rqstp->rq_res, 0); rqstp->rq_res.page_base = 0; /* Reset response buffer and release @@ -666,7 +666,7 @@ static int svc_alloc_arg(struct svc_rqst *rqstp) arg->pages = rqstp->rq_pages + 1; arg->page_base = 0; /* save at least one page for response */ - arg->page_len = (pages-2)*PAGE_SIZE; + xdr_buf_set_pagelen(arg, (pages - 2) << PAGE_SHIFT); arg->len = (pages-1)*PAGE_SIZE; arg->tail[0].iov_len = 0; return 0; @@ -902,9 +902,13 @@ int svc_send(struct svc_rqst *rqstp) /* calculate over-all length */ xb = &rqstp->rq_res; - xb->len = xb->head[0].iov_len + - xb->page_len + - xb->tail[0].iov_len; + xb->len = xdr_buf_msglen(xb); + if ((xb->head[0].iov_len & 3) != 0) + trace_printk("head=[%p,%zu] page=%u/%u tail=[%p,%zu] msglen=%zu buflen=%u", + xb->head[0].iov_base, xb->head[0].iov_len, + xb->page_len, xb->page_pad, + xb->tail[0].iov_base, xb->tail[0].iov_len, + xdr_buf_msglen(xb), xb->buflen); /* Grab mutex to serialize outgoing data. */ mutex_lock(&xprt->xpt_mutex);