mirror of
https://github.com/torvalds/linux.git
synced 2024-11-15 00:21:59 +00:00
SUNRPC: Add the ability to expand holes in data pages
This patch adds the ability to "read a hole" into a set of XDR data pages by taking the following steps: 1) Shift all data after the current xdr->p to the right, possibly into the tail, 2) Zero the specified range, and 3) Update xdr->p to point beyond the hole. Signed-off-by: Anna Schumaker <Anna.Schumaker@Netapp.com>
This commit is contained in:
parent
43f0f0816c
commit
84ce182ab8
@ -250,6 +250,7 @@ extern __be32 *xdr_inline_decode(struct xdr_stream *xdr, size_t nbytes);
|
||||
extern unsigned int xdr_read_pages(struct xdr_stream *xdr, unsigned int len);
|
||||
extern void xdr_enter_page(struct xdr_stream *xdr, unsigned int len);
|
||||
extern int xdr_process_buf(struct xdr_buf *buf, unsigned int offset, unsigned int len, int (*actor)(struct scatterlist *, void *), void *data);
|
||||
extern uint64_t xdr_expand_hole(struct xdr_stream *, uint64_t, uint64_t);
|
||||
|
||||
/**
|
||||
* xdr_stream_remaining - Return the number of bytes remaining in the stream
|
||||
|
@ -390,6 +390,38 @@ _copy_from_pages(char *p, struct page **pages, size_t pgbase, size_t len)
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(_copy_from_pages);
|
||||
|
||||
/**
|
||||
* _zero_pages
|
||||
* @pages: array of pages
|
||||
* @pgbase: beginning page vector address
|
||||
* @len: length
|
||||
*/
|
||||
static void
|
||||
_zero_pages(struct page **pages, size_t pgbase, size_t len)
|
||||
{
|
||||
struct page **page;
|
||||
char *vpage;
|
||||
size_t zero;
|
||||
|
||||
page = pages + (pgbase >> PAGE_SHIFT);
|
||||
pgbase &= ~PAGE_MASK;
|
||||
|
||||
do {
|
||||
zero = PAGE_SIZE - pgbase;
|
||||
if (zero > len)
|
||||
zero = len;
|
||||
|
||||
vpage = kmap_atomic(*page);
|
||||
memset(vpage + pgbase, 0, zero);
|
||||
kunmap_atomic(vpage);
|
||||
|
||||
flush_dcache_page(*page);
|
||||
pgbase = 0;
|
||||
page++;
|
||||
|
||||
} while ((len -= zero) != 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* xdr_shrink_bufhead
|
||||
* @buf: xdr_buf
|
||||
@ -1096,6 +1128,43 @@ unsigned int xdr_read_pages(struct xdr_stream *xdr, unsigned int len)
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(xdr_read_pages);
|
||||
|
||||
uint64_t xdr_expand_hole(struct xdr_stream *xdr, uint64_t offset, uint64_t length)
|
||||
{
|
||||
struct xdr_buf *buf = xdr->buf;
|
||||
unsigned int bytes;
|
||||
unsigned int from;
|
||||
unsigned int truncated = 0;
|
||||
|
||||
if ((offset + length) < offset ||
|
||||
(offset + length) > buf->page_len)
|
||||
length = buf->page_len - offset;
|
||||
|
||||
xdr_realign_pages(xdr);
|
||||
from = xdr_page_pos(xdr);
|
||||
bytes = xdr->nwords << 2;
|
||||
|
||||
if (offset + length + bytes > buf->page_len) {
|
||||
unsigned int shift = (offset + length + bytes) - buf->page_len;
|
||||
unsigned int res = _shift_data_right_tail(buf, from + bytes - shift, shift);
|
||||
truncated = shift - res;
|
||||
xdr->nwords -= XDR_QUADLEN(truncated);
|
||||
bytes -= shift;
|
||||
}
|
||||
|
||||
/* Now move the page data over and zero pages */
|
||||
if (bytes > 0)
|
||||
_shift_data_right_pages(buf->pages,
|
||||
buf->page_base + offset + length,
|
||||
buf->page_base + from,
|
||||
bytes);
|
||||
_zero_pages(buf->pages, buf->page_base + offset, length);
|
||||
|
||||
buf->len += length - (from - offset) - truncated;
|
||||
xdr_set_page(xdr, offset + length, PAGE_SIZE);
|
||||
return length;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(xdr_expand_hole);
|
||||
|
||||
/**
|
||||
* xdr_enter_page - decode data from the XDR page
|
||||
* @xdr: pointer to xdr_stream struct
|
||||
|
Loading…
Reference in New Issue
Block a user