]> www.infradead.org Git - users/jedix/linux-maple.git/commitdiff
SUNRPC: Cleanup xdr_shrink_bufhead()
authorTrond Myklebust <trond.myklebust@hammerspace.com>
Sun, 6 Dec 2020 15:15:04 +0000 (10:15 -0500)
committerTrond Myklebust <trond.myklebust@hammerspace.com>
Mon, 14 Dec 2020 11:51:07 +0000 (06:51 -0500)
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>
net/sunrpc/xdr.c

index e0906ed243744f2dccdb1ebaeba7d9a0bc0ffdd1..19eaa38f7d160844c258a44a905844be8e87838b 100644 (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;
-               }
-               /* 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;
-               }
+       if (head->iov_len > buflen) {
+               buf->buflen -= head->iov_len - buflen;
+               head->iov_len = buflen;
        }
-       /* 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);
        }
 }