SUNRPC: Cleanup xdr_shrink_bufhead()

Clean up xdr_shrink_bufhead() to use the new helpers instead of doing
its own thing.

Signed-off-by: Trond Myklebust <trond.myklebust@hammerspace.com>
This commit is contained in:
Trond Myklebust 2020-12-06 10:15:04 -05:00
parent c4f2f591f0
commit 6707fbd7d3
1 changed files with 87 additions and 77 deletions

View File

@ -550,6 +550,53 @@ static void xdr_buf_pages_copy_right(const struct xdr_buf *buf,
buf->page_base + base, pglen);
}
static void xdr_buf_head_copy_right(const struct xdr_buf *buf,
unsigned int base, unsigned int len,
unsigned int shift)
{
const struct kvec *head = buf->head;
const struct kvec *tail = buf->tail;
unsigned int to = base + shift;
unsigned int pglen = 0, pgto = 0;
unsigned int talen = 0, tato = 0;
if (base >= head->iov_len)
return;
if (len > head->iov_len - base)
len = head->iov_len - base;
if (to >= buf->page_len + head->iov_len) {
tato = to - buf->page_len - head->iov_len;
talen = len;
} else if (to >= head->iov_len) {
pgto = to - head->iov_len;
pglen = len;
if (pgto + pglen > buf->page_len) {
talen = pgto + pglen - buf->page_len;
pglen -= talen;
}
} else {
pglen = len - to;
if (pglen > buf->page_len) {
talen = pglen - buf->page_len;
pglen = buf->page_len;
}
}
len -= talen;
base += len;
if (talen + tato > tail->iov_len)
talen = tail->iov_len > tato ? tail->iov_len - tato : 0;
memcpy(tail->iov_base + tato, head->iov_base + base, talen);
len -= pglen;
base -= pglen;
_copy_to_pages(buf->pages, buf->page_base + pgto, head->iov_base + base,
pglen);
base -= len;
memmove(head->iov_base + to, head->iov_base + base, len);
}
static void xdr_buf_tail_shift_right(const struct xdr_buf *buf,
unsigned int base, unsigned int len,
unsigned int shift)
@ -577,6 +624,25 @@ static void xdr_buf_pages_shift_right(const struct xdr_buf *buf,
xdr_buf_pages_copy_right(buf, base, len, shift);
}
static void xdr_buf_head_shift_right(const struct xdr_buf *buf,
unsigned int base, unsigned int len,
unsigned int shift)
{
const struct kvec *head = buf->head;
if (!shift)
return;
if (base >= head->iov_len) {
xdr_buf_pages_shift_right(buf, head->iov_len - base, len,
shift);
return;
}
if (base + len > head->iov_len)
xdr_buf_pages_shift_right(buf, 0, base + len - head->iov_len,
shift);
xdr_buf_head_copy_right(buf, base, len, shift);
}
static void xdr_buf_tail_copy_left(const struct xdr_buf *buf, unsigned int base,
unsigned int len, unsigned int shift)
{
@ -683,86 +749,31 @@ static void xdr_buf_pages_shift_left(const struct xdr_buf *buf,
/**
* xdr_shrink_bufhead
* @buf: xdr_buf
* @len: bytes to remove from buf->head[0]
* @len: new length of buf->head[0]
*
* Shrinks XDR buffer's header kvec buf->head[0] by
* Shrinks XDR buffer's header kvec buf->head[0], setting it to
* 'len' bytes. The extra data is not lost, but is instead
* moved into the inlined pages and/or the tail.
*/
static unsigned int
xdr_shrink_bufhead(struct xdr_buf *buf, size_t len)
static unsigned int xdr_shrink_bufhead(struct xdr_buf *buf, unsigned int len)
{
struct kvec *head, *tail;
size_t copy, offs;
unsigned int pglen = buf->page_len;
unsigned int result;
result = 0;
tail = buf->tail;
head = buf->head;
struct kvec *head = buf->head;
unsigned int shift, buflen = max(buf->len, len);
WARN_ON_ONCE(len > head->iov_len);
if (len > head->iov_len)
len = head->iov_len;
/* Shift the tail first */
if (tail->iov_len != 0) {
if (tail->iov_len > len) {
copy = tail->iov_len - len;
memmove((char *)tail->iov_base + len,
tail->iov_base, copy);
result += copy;
if (head->iov_len > buflen) {
buf->buflen -= head->iov_len - buflen;
head->iov_len = buflen;
}
/* Copy from the inlined pages into the tail */
copy = len;
if (copy > pglen)
copy = pglen;
offs = len - copy;
if (offs >= tail->iov_len)
copy = 0;
else if (copy > tail->iov_len - offs)
copy = tail->iov_len - offs;
if (copy != 0) {
_copy_from_pages((char *)tail->iov_base + offs,
buf->pages,
buf->page_base + pglen + offs - len,
copy);
result += copy;
}
/* Do we also need to copy data from the head into the tail ? */
if (len > pglen) {
offs = copy = len - pglen;
if (copy > tail->iov_len)
copy = tail->iov_len;
memcpy(tail->iov_base,
(char *)head->iov_base +
head->iov_len - offs,
copy);
result += copy;
}
}
/* Now handle pages */
if (pglen != 0) {
if (pglen > len)
_shift_data_right_pages(buf->pages,
buf->page_base + len,
buf->page_base,
pglen - len);
copy = len;
if (len > pglen)
copy = pglen;
_copy_to_pages(buf->pages, buf->page_base,
(char *)head->iov_base + head->iov_len - len,
copy);
result += copy;
}
head->iov_len -= len;
buf->buflen -= len;
/* Have we truncated the message? */
if (buf->len > buf->buflen)
buf->len = buf->buflen;
return result;
if (len >= head->iov_len)
return 0;
shift = head->iov_len - len;
xdr_buf_try_expand(buf, shift);
xdr_buf_head_shift_right(buf, len, buflen - len, shift);
head->iov_len = len;
buf->buflen -= shift;
buf->len -= shift;
return shift;
}
/**
@ -798,7 +809,7 @@ static unsigned int xdr_shrink_pagelen(struct xdr_buf *buf, unsigned int len)
void
xdr_shift_buf(struct xdr_buf *buf, size_t len)
{
xdr_shrink_bufhead(buf, len);
xdr_shrink_bufhead(buf, buf->head->iov_len - len);
}
EXPORT_SYMBOL_GPL(xdr_shift_buf);
@ -1371,13 +1382,12 @@ static void xdr_realign_pages(struct xdr_stream *xdr)
struct xdr_buf *buf = xdr->buf;
struct kvec *iov = buf->head;
unsigned int cur = xdr_stream_pos(xdr);
unsigned int copied, offset;
unsigned int copied;
/* Realign pages to current pointer position */
if (iov->iov_len > cur) {
offset = iov->iov_len - cur;
copied = xdr_shrink_bufhead(buf, offset);
trace_rpc_xdr_alignment(xdr, offset, copied);
copied = xdr_shrink_bufhead(buf, cur);
trace_rpc_xdr_alignment(xdr, cur, copied);
xdr->nwords = XDR_QUADLEN(buf->len - cur);
}
}