NFSD: Ensure that xdr_write_pages updates rq_next_page
authorChuck Lever <chuck.lever@oracle.com>
Thu, 18 May 2023 17:45:36 +0000 (13:45 -0400)
committerChuck Lever <chuck.lever@oracle.com>
Mon, 5 Jun 2023 13:01:44 +0000 (09:01 -0400)
All other NFSv[23] procedures manage to keep page_ptr and
rq_next_page in lock step.

Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
fs/nfsd/nfs3xdr.c
fs/nfsd/nfsxdr.c
include/linux/sunrpc/svc.h

index 3308dd6..f321289 100644 (file)
@@ -828,7 +828,8 @@ nfs3svc_encode_readlinkres(struct svc_rqst *rqstp, struct xdr_stream *xdr)
                        return false;
                if (xdr_stream_encode_u32(xdr, resp->len) < 0)
                        return false;
-               xdr_write_pages(xdr, resp->pages, 0, resp->len);
+               svcxdr_encode_opaque_pages(rqstp, xdr, resp->pages, 0,
+                                          resp->len);
                if (svc_encode_result_payload(rqstp, head->iov_len, resp->len) < 0)
                        return false;
                break;
@@ -859,8 +860,9 @@ nfs3svc_encode_readres(struct svc_rqst *rqstp, struct xdr_stream *xdr)
                        return false;
                if (xdr_stream_encode_u32(xdr, resp->count) < 0)
                        return false;
-               xdr_write_pages(xdr, resp->pages, rqstp->rq_res.page_base,
-                               resp->count);
+               svcxdr_encode_opaque_pages(rqstp, xdr, resp->pages,
+                                          rqstp->rq_res.page_base,
+                                          resp->count);
                if (svc_encode_result_payload(rqstp, head->iov_len, resp->count) < 0)
                        return false;
                break;
@@ -961,7 +963,8 @@ nfs3svc_encode_readdirres(struct svc_rqst *rqstp, struct xdr_stream *xdr)
                        return false;
                if (!svcxdr_encode_cookieverf3(xdr, resp->verf))
                        return false;
-               xdr_write_pages(xdr, dirlist->pages, 0, dirlist->len);
+               svcxdr_encode_opaque_pages(rqstp, xdr, dirlist->pages, 0,
+                                          dirlist->len);
                /* no more entries */
                if (xdr_stream_encode_item_absent(xdr) < 0)
                        return false;
index caf6355..5777f40 100644 (file)
@@ -468,7 +468,8 @@ nfssvc_encode_readlinkres(struct svc_rqst *rqstp, struct xdr_stream *xdr)
        case nfs_ok:
                if (xdr_stream_encode_u32(xdr, resp->len) < 0)
                        return false;
-               xdr_write_pages(xdr, &resp->page, 0, resp->len);
+               svcxdr_encode_opaque_pages(rqstp, xdr, &resp->page, 0,
+                                          resp->len);
                if (svc_encode_result_payload(rqstp, head->iov_len, resp->len) < 0)
                        return false;
                break;
@@ -491,8 +492,9 @@ nfssvc_encode_readres(struct svc_rqst *rqstp, struct xdr_stream *xdr)
                        return false;
                if (xdr_stream_encode_u32(xdr, resp->count) < 0)
                        return false;
-               xdr_write_pages(xdr, resp->pages, rqstp->rq_res.page_base,
-                               resp->count);
+               svcxdr_encode_opaque_pages(rqstp, xdr, resp->pages,
+                                          rqstp->rq_res.page_base,
+                                          resp->count);
                if (svc_encode_result_payload(rqstp, head->iov_len, resp->count) < 0)
                        return false;
                break;
@@ -511,7 +513,8 @@ nfssvc_encode_readdirres(struct svc_rqst *rqstp, struct xdr_stream *xdr)
                return false;
        switch (resp->status) {
        case nfs_ok:
-               xdr_write_pages(xdr, dirlist->pages, 0, dirlist->len);
+               svcxdr_encode_opaque_pages(rqstp, xdr, dirlist->pages, 0,
+                                          dirlist->len);
                /* no more entries */
                if (xdr_stream_encode_item_absent(xdr) < 0)
                        return false;
index 762d723..3b10636 100644 (file)
@@ -509,6 +509,27 @@ static inline void svcxdr_init_encode(struct svc_rqst *rqstp)
 }
 
 /**
+ * svcxdr_encode_opaque_pages - Insert pages into an xdr_stream
+ * @xdr: xdr_stream to be updated
+ * @pages: array of pages to insert
+ * @base: starting offset of first data byte in @pages
+ * @len: number of data bytes in @pages to insert
+ *
+ * After the @pages are added, the tail iovec is instantiated pointing
+ * to end of the head buffer, and the stream is set up to encode
+ * subsequent items into the tail.
+ */
+static inline void svcxdr_encode_opaque_pages(struct svc_rqst *rqstp,
+                                             struct xdr_stream *xdr,
+                                             struct page **pages,
+                                             unsigned int base,
+                                             unsigned int len)
+{
+       xdr_write_pages(xdr, pages, base, len);
+       xdr->page_ptr = rqstp->rq_next_page - 1;
+}
+
+/**
  * svcxdr_set_auth_slack -
  * @rqstp: RPC transaction
  * @slack: buffer space to reserve for the transaction's security flavor