OSDN Git Service

SUNRPC: Add a function for directly setting the xdr page len
authorAnna Schumaker <Anna.Schumaker@Netapp.com>
Thu, 21 Jul 2022 18:21:32 +0000 (14:21 -0400)
committerTrond Myklebust <trond.myklebust@hammerspace.com>
Sat, 23 Jul 2022 19:38:29 +0000 (15:38 -0400)
We need to do this step during READ_PLUS decoding so that we know pages
are the right length and any extra data has been preserved in the tail.

Signed-off-by: Anna Schumaker <Anna.Schumaker@Netapp.com>
Signed-off-by: Trond Myklebust <trond.myklebust@hammerspace.com>
include/linux/sunrpc/xdr.h
net/sunrpc/xdr.c

index 7dcc6c3..8cd38a9 100644 (file)
@@ -258,6 +258,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(const struct xdr_buf *buf, unsigned int offset, unsigned int len, int (*actor)(struct scatterlist *, void *), void *data);
+extern void xdr_set_pagelen(struct xdr_stream *, unsigned int len);
 extern unsigned int xdr_align_data(struct xdr_stream *, unsigned int offset, unsigned int length);
 extern unsigned int xdr_expand_hole(struct xdr_stream *, unsigned int offset, unsigned int length);
 extern bool xdr_stream_subsegment(struct xdr_stream *xdr, struct xdr_buf *subbuf,
index 8ba11a7..e4ac700 100644 (file)
@@ -1500,6 +1500,36 @@ unsigned int xdr_read_pages(struct xdr_stream *xdr, unsigned int len)
 }
 EXPORT_SYMBOL_GPL(xdr_read_pages);
 
+/**
+ * xdr_set_pagelen - Sets the length of the XDR pages
+ * @xdr: pointer to xdr_stream struct
+ * @len: new length of the XDR page data
+ *
+ * Either grows or shrinks the length of the xdr pages by setting pagelen to
+ * @len bytes. When shrinking, any extra data is moved into buf->tail, whereas
+ * when growing any data beyond the current pointer is moved into the tail.
+ *
+ * Returns True if the operation was successful, and False otherwise.
+ */
+void xdr_set_pagelen(struct xdr_stream *xdr, unsigned int len)
+{
+       struct xdr_buf *buf = xdr->buf;
+       size_t remaining = xdr_stream_remaining(xdr);
+       size_t base = 0;
+
+       if (len < buf->page_len) {
+               base = buf->page_len - len;
+               xdr_shrink_pagelen(buf, len);
+       } else {
+               xdr_buf_head_shift_right(buf, xdr_stream_pos(xdr),
+                                        buf->page_len, remaining);
+               if (len > buf->page_len)
+                       xdr_buf_try_expand(buf, len - buf->page_len);
+       }
+       xdr_set_tail_base(xdr, base, remaining);
+}
+EXPORT_SYMBOL_GPL(xdr_set_pagelen);
+
 unsigned int xdr_align_data(struct xdr_stream *xdr, unsigned int offset,
                            unsigned int length)
 {