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); 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, static void xdr_buf_tail_shift_right(const struct xdr_buf *buf,
unsigned int base, unsigned int len, unsigned int base, unsigned int len,
unsigned int shift) 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); 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, static void xdr_buf_tail_copy_left(const struct xdr_buf *buf, unsigned int base,
unsigned int len, unsigned int shift) 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 * xdr_shrink_bufhead
* @buf: xdr_buf * @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 * 'len' bytes. The extra data is not lost, but is instead
* moved into the inlined pages and/or the tail. * moved into the inlined pages and/or the tail.
*/ */
static unsigned int static unsigned int xdr_shrink_bufhead(struct xdr_buf *buf, unsigned int len)
xdr_shrink_bufhead(struct xdr_buf *buf, size_t len)
{ {
struct kvec *head, *tail; struct kvec *head = buf->head;
size_t copy, offs; unsigned int shift, buflen = max(buf->len, len);
unsigned int pglen = buf->page_len;
unsigned int result;
result = 0;
tail = buf->tail;
head = buf->head;
WARN_ON_ONCE(len > head->iov_len); WARN_ON_ONCE(len > head->iov_len);
if (len > head->iov_len) if (head->iov_len > buflen) {
len = head->iov_len; buf->buflen -= head->iov_len - buflen;
head->iov_len = buflen;
/* 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;
}
/* 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 (len >= head->iov_len)
if (pglen != 0) { return 0;
if (pglen > len) shift = head->iov_len - len;
_shift_data_right_pages(buf->pages, xdr_buf_try_expand(buf, shift);
buf->page_base + len, xdr_buf_head_shift_right(buf, len, buflen - len, shift);
buf->page_base, head->iov_len = len;
pglen - len); buf->buflen -= shift;
copy = len; buf->len -= shift;
if (len > pglen) return shift;
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;
} }
/** /**
@ -798,7 +809,7 @@ static unsigned int xdr_shrink_pagelen(struct xdr_buf *buf, unsigned int len)
void void
xdr_shift_buf(struct xdr_buf *buf, size_t len) 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); 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 xdr_buf *buf = xdr->buf;
struct kvec *iov = buf->head; struct kvec *iov = buf->head;
unsigned int cur = xdr_stream_pos(xdr); unsigned int cur = xdr_stream_pos(xdr);
unsigned int copied, offset; unsigned int copied;
/* Realign pages to current pointer position */ /* Realign pages to current pointer position */
if (iov->iov_len > cur) { if (iov->iov_len > cur) {
offset = iov->iov_len - cur; copied = xdr_shrink_bufhead(buf, cur);
copied = xdr_shrink_bufhead(buf, offset); trace_rpc_xdr_alignment(xdr, cur, copied);
trace_rpc_xdr_alignment(xdr, offset, copied);
xdr->nwords = XDR_QUADLEN(buf->len - cur); xdr->nwords = XDR_QUADLEN(buf->len - cur);
} }
} }