mirror of
https://github.com/torvalds/linux.git
synced 2024-11-24 05:02:12 +00:00
SUNRPC: When expanding the buffer, we may need grow the sparse pages
If we're shifting the page data to the right, and this happens to be a sparse page array, then we may need to allocate new pages in order to receive the data. Reported-by: "Mkrtchyan, Tigran" <tigran.mkrtchyan@desy.de> Signed-off-by: Trond Myklebust <trond.myklebust@hammerspace.com>
This commit is contained in:
parent
f8d0e60f10
commit
5802f7c2a6
@ -478,16 +478,47 @@ static void xdr_buf_pages_zero(const struct xdr_buf *buf, unsigned int pgbase,
|
||||
} while ((len -= zero) != 0);
|
||||
}
|
||||
|
||||
static unsigned int xdr_buf_pages_fill_sparse(const struct xdr_buf *buf,
|
||||
unsigned int buflen, gfp_t gfp)
|
||||
{
|
||||
unsigned int i, npages, pagelen;
|
||||
|
||||
if (!(buf->flags & XDRBUF_SPARSE_PAGES))
|
||||
return buflen;
|
||||
if (buflen <= buf->head->iov_len)
|
||||
return buflen;
|
||||
pagelen = buflen - buf->head->iov_len;
|
||||
if (pagelen > buf->page_len)
|
||||
pagelen = buf->page_len;
|
||||
npages = (pagelen + buf->page_base + PAGE_SIZE - 1) >> PAGE_SHIFT;
|
||||
for (i = 0; i < npages; i++) {
|
||||
if (!buf->pages[i])
|
||||
continue;
|
||||
buf->pages[i] = alloc_page(gfp);
|
||||
if (likely(buf->pages[i]))
|
||||
continue;
|
||||
buflen -= pagelen;
|
||||
pagelen = i << PAGE_SHIFT;
|
||||
if (pagelen > buf->page_base)
|
||||
buflen += pagelen - buf->page_base;
|
||||
break;
|
||||
}
|
||||
return buflen;
|
||||
}
|
||||
|
||||
static void xdr_buf_try_expand(struct xdr_buf *buf, unsigned int len)
|
||||
{
|
||||
struct kvec *head = buf->head;
|
||||
struct kvec *tail = buf->tail;
|
||||
unsigned int sum = head->iov_len + buf->page_len + tail->iov_len;
|
||||
unsigned int free_space;
|
||||
unsigned int free_space, newlen;
|
||||
|
||||
if (sum > buf->len) {
|
||||
free_space = min_t(unsigned int, sum - buf->len, len);
|
||||
buf->len += free_space;
|
||||
newlen = xdr_buf_pages_fill_sparse(buf, buf->len + free_space,
|
||||
GFP_KERNEL);
|
||||
free_space = newlen - buf->len;
|
||||
buf->len = newlen;
|
||||
len -= free_space;
|
||||
if (!len)
|
||||
return;
|
||||
|
Loading…
Reference in New Issue
Block a user