Commit 16e5e90f authored by Trond Myklebust's avatar Trond Myklebust

SUNRPC: Fix up handling of the XDRBUF_SPARSE_PAGES flag

If the allocator fails before it has reached the target number of pages,
then we need to recheck that we're not seeking past the page buffer.
Signed-off-by: default avatarTrond Myklebust <trond.myklebust@hammerspace.com>
parent c4433055
...@@ -330,18 +330,16 @@ xs_alloc_sparse_pages(struct xdr_buf *buf, size_t want, gfp_t gfp) ...@@ -330,18 +330,16 @@ xs_alloc_sparse_pages(struct xdr_buf *buf, size_t want, gfp_t gfp)
{ {
size_t i,n; size_t i,n;
if (!(buf->flags & XDRBUF_SPARSE_PAGES)) if (!want || !(buf->flags & XDRBUF_SPARSE_PAGES))
return want; return want;
if (want > buf->page_len)
want = buf->page_len;
n = (buf->page_base + want + PAGE_SIZE - 1) >> PAGE_SHIFT; n = (buf->page_base + want + PAGE_SIZE - 1) >> PAGE_SHIFT;
for (i = 0; i < n; i++) { for (i = 0; i < n; i++) {
if (buf->pages[i]) if (buf->pages[i])
continue; continue;
buf->bvec[i].bv_page = buf->pages[i] = alloc_page(gfp); buf->bvec[i].bv_page = buf->pages[i] = alloc_page(gfp);
if (!buf->pages[i]) { if (!buf->pages[i]) {
buf->page_len = (i * PAGE_SIZE) - buf->page_base; i *= PAGE_SIZE;
return buf->page_len; return i > buf->page_base ? i - buf->page_base : 0;
} }
} }
return want; return want;
...@@ -404,10 +402,11 @@ xs_read_xdr_buf(struct socket *sock, struct msghdr *msg, int flags, ...@@ -404,10 +402,11 @@ xs_read_xdr_buf(struct socket *sock, struct msghdr *msg, int flags,
seek -= buf->head[0].iov_len; seek -= buf->head[0].iov_len;
offset += buf->head[0].iov_len; offset += buf->head[0].iov_len;
} }
if (seek < buf->page_len) {
want = xs_alloc_sparse_pages(buf, want = xs_alloc_sparse_pages(buf,
min_t(size_t, count - offset, buf->page_len), min_t(size_t, count - offset, buf->page_len),
GFP_NOWAIT); GFP_NOWAIT);
if (seek < want) {
ret = xs_read_bvec(sock, msg, flags, buf->bvec, ret = xs_read_bvec(sock, msg, flags, buf->bvec,
xdr_buf_pagecount(buf), xdr_buf_pagecount(buf),
want + buf->page_base, want + buf->page_base,
...@@ -421,9 +420,10 @@ xs_read_xdr_buf(struct socket *sock, struct msghdr *msg, int flags, ...@@ -421,9 +420,10 @@ xs_read_xdr_buf(struct socket *sock, struct msghdr *msg, int flags,
goto out; goto out;
seek = 0; seek = 0;
} else { } else {
seek -= buf->page_len; seek -= want;
offset += buf->page_len; offset += want;
} }
if (seek < buf->tail[0].iov_len) { if (seek < buf->tail[0].iov_len) {
want = min_t(size_t, count - offset, buf->tail[0].iov_len); want = min_t(size_t, count - offset, buf->tail[0].iov_len);
ret = xs_read_kvec(sock, msg, flags, &buf->tail[0], want, seek); ret = xs_read_kvec(sock, msg, flags, &buf->tail[0], want, seek);
......
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