Commit 8d86e373 authored by Trond Myklebust's avatar Trond Myklebust

SUNRPC: Clean up helpers xdr_set_iov() and xdr_set_page_base()

Allow xdr_set_iov() to set a base so that we can use it to set the
cursor to a specific position in the kvec buffer.

If the new base overflows the kvec/pages buffer in either xdr_set_iov()
or xdr_set_page_base(), then truncate it so that we point to the end of
the buffer.

Finally, change both function to return the number of bytes remaining to
read in their buffers.
Signed-off-by: default avatarTrond Myklebust <trond.myklebust@hammerspace.com>
parent 2b1f83d1
...@@ -970,19 +970,22 @@ void xdr_write_pages(struct xdr_stream *xdr, struct page **pages, unsigned int b ...@@ -970,19 +970,22 @@ void xdr_write_pages(struct xdr_stream *xdr, struct page **pages, unsigned int b
} }
EXPORT_SYMBOL_GPL(xdr_write_pages); EXPORT_SYMBOL_GPL(xdr_write_pages);
static void xdr_set_iov(struct xdr_stream *xdr, struct kvec *iov, static unsigned int xdr_set_iov(struct xdr_stream *xdr, struct kvec *iov,
unsigned int len) unsigned int base, unsigned int len)
{ {
if (len > iov->iov_len) if (len > iov->iov_len)
len = iov->iov_len; len = iov->iov_len;
xdr->p = (__be32*)iov->iov_base; if (unlikely(base > len))
base = len;
xdr->p = (__be32*)(iov->iov_base + base);
xdr->end = (__be32*)(iov->iov_base + len); xdr->end = (__be32*)(iov->iov_base + len);
xdr->iov = iov; xdr->iov = iov;
xdr->page_ptr = NULL; xdr->page_ptr = NULL;
return len - base;
} }
static int xdr_set_page_base(struct xdr_stream *xdr, static unsigned int xdr_set_page_base(struct xdr_stream *xdr,
unsigned int base, unsigned int len) unsigned int base, unsigned int len)
{ {
unsigned int pgnr; unsigned int pgnr;
unsigned int maxlen; unsigned int maxlen;
...@@ -991,9 +994,11 @@ static int xdr_set_page_base(struct xdr_stream *xdr, ...@@ -991,9 +994,11 @@ static int xdr_set_page_base(struct xdr_stream *xdr,
void *kaddr; void *kaddr;
maxlen = xdr->buf->page_len; maxlen = xdr->buf->page_len;
if (base >= maxlen) if (base >= maxlen) {
return -EINVAL; base = maxlen;
maxlen -= base; maxlen = 0;
} else
maxlen -= base;
if (len > maxlen) if (len > maxlen)
len = maxlen; len = maxlen;
...@@ -1011,14 +1016,14 @@ static int xdr_set_page_base(struct xdr_stream *xdr, ...@@ -1011,14 +1016,14 @@ static int xdr_set_page_base(struct xdr_stream *xdr,
pgend = PAGE_SIZE; pgend = PAGE_SIZE;
xdr->end = (__be32*)(kaddr + pgend); xdr->end = (__be32*)(kaddr + pgend);
xdr->iov = NULL; xdr->iov = NULL;
return 0; return len;
} }
static void xdr_set_page(struct xdr_stream *xdr, unsigned int base, static void xdr_set_page(struct xdr_stream *xdr, unsigned int base,
unsigned int len) unsigned int len)
{ {
if (xdr_set_page_base(xdr, base, len) < 0) if (xdr_set_page_base(xdr, base, len) == 0)
xdr_set_iov(xdr, xdr->buf->tail, xdr->nwords << 2); xdr_set_iov(xdr, xdr->buf->tail, 0, xdr_stream_remaining(xdr));
} }
static void xdr_set_next_page(struct xdr_stream *xdr) static void xdr_set_next_page(struct xdr_stream *xdr)
...@@ -1055,12 +1060,9 @@ void xdr_init_decode(struct xdr_stream *xdr, struct xdr_buf *buf, __be32 *p, ...@@ -1055,12 +1060,9 @@ void xdr_init_decode(struct xdr_stream *xdr, struct xdr_buf *buf, __be32 *p,
xdr->scratch.iov_base = NULL; xdr->scratch.iov_base = NULL;
xdr->scratch.iov_len = 0; xdr->scratch.iov_len = 0;
xdr->nwords = XDR_QUADLEN(buf->len); xdr->nwords = XDR_QUADLEN(buf->len);
if (buf->head[0].iov_len != 0) if (xdr_set_iov(xdr, buf->head, 0, buf->len) == 0 &&
xdr_set_iov(xdr, buf->head, buf->len); xdr_set_page_base(xdr, 0, buf->len) == 0)
else if (buf->page_len != 0) xdr_set_iov(xdr, buf->tail, 0, buf->len);
xdr_set_page_base(xdr, 0, buf->len);
else
xdr_set_iov(xdr, buf->tail, buf->len);
if (p != NULL && p > xdr->p && xdr->end >= p) { if (p != NULL && p > xdr->p && xdr->end >= p) {
xdr->nwords -= p - xdr->p; xdr->nwords -= p - xdr->p;
xdr->p = p; xdr->p = p;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment