SUNRPC: Introduce rpc_prepare_reply_pages()
authorChuck Lever <chuck.lever@oracle.com>
Mon, 11 Feb 2019 16:25:20 +0000 (11:25 -0500)
committerAnna Schumaker <Anna.Schumaker@Netapp.com>
Thu, 14 Feb 2019 15:04:37 +0000 (10:04 -0500)
prepare_reply_buffer() and its NFSv4 equivalents expose the details
of the RPC header and the auth slack values to upper layer
consumers, creating a layering violation, and duplicating code.

Remedy these issues by adding a new RPC client API that hides those
details from upper layers in a common helper function.

Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
Signed-off-by: Anna Schumaker <Anna.Schumaker@Netapp.com>
fs/nfs/nfs2xdr.c
fs/nfs/nfs3xdr.c
fs/nfs/nfs4xdr.c
include/linux/sunrpc/clnt.h
include/trace/events/sunrpc.h
net/sunrpc/clnt.c
net/sunrpc/xdr.c

index bac3a4e2cb5dbb8a6180447444b818db22146f8e..1dcd0feda32dd1e8fa87f6bdb264c85ac6e103fa 100644 (file)
 
 static int nfs_stat_to_errno(enum nfs_stat);
 
-/*
- * While encoding arguments, set up the reply buffer in advance to
- * receive reply data directly into the page cache.
- */
-static void prepare_reply_buffer(struct rpc_rqst *req, struct page **pages,
-                                unsigned int base, unsigned int len,
-                                unsigned int bufsize)
-{
-       struct rpc_auth *auth = req->rq_cred->cr_auth;
-       unsigned int replen;
-
-       replen = RPC_REPHDRSIZE + auth->au_rslack + bufsize;
-       xdr_inline_pages(&req->rq_rcv_buf, replen << 2, pages, base, len);
-}
-
 /*
  * Encode/decode NFSv2 basic data types
  *
@@ -593,8 +578,8 @@ static void nfs2_xdr_enc_readlinkargs(struct rpc_rqst *req,
        const struct nfs_readlinkargs *args = data;
 
        encode_fhandle(xdr, args->fh);
-       prepare_reply_buffer(req, args->pages, args->pgbase,
-                                       args->pglen, NFS_readlinkres_sz);
+       rpc_prepare_reply_pages(req, args->pages, args->pgbase,
+                               args->pglen, NFS_readlinkres_sz);
 }
 
 /*
@@ -629,8 +614,8 @@ static void nfs2_xdr_enc_readargs(struct rpc_rqst *req,
        const struct nfs_pgio_args *args = data;
 
        encode_readargs(xdr, args);
-       prepare_reply_buffer(req, args->pages, args->pgbase,
-                                       args->count, NFS_readres_sz);
+       rpc_prepare_reply_pages(req, args->pages, args->pgbase,
+                               args->count, NFS_readres_sz);
        req->rq_rcv_buf.flags |= XDRBUF_READ;
 }
 
@@ -787,8 +772,8 @@ static void nfs2_xdr_enc_readdirargs(struct rpc_rqst *req,
        const struct nfs_readdirargs *args = data;
 
        encode_readdirargs(xdr, args);
-       prepare_reply_buffer(req, args->pages, 0,
-                                       args->count, NFS_readdirres_sz);
+       rpc_prepare_reply_pages(req, args->pages, 0,
+                               args->count, NFS_readdirres_sz);
 }
 
 /*
index 4aa3ffe1800e086b321a84367185698063eb4262..a54dcf4bfb1d32c487781d7641a353fd14901b1b 100644 (file)
@@ -104,21 +104,6 @@ static const umode_t nfs_type2fmt[] = {
        [NF3FIFO] = S_IFIFO,
 };
 
-/*
- * While encoding arguments, set up the reply buffer in advance to
- * receive reply data directly into the page cache.
- */
-static void prepare_reply_buffer(struct rpc_rqst *req, struct page **pages,
-                                unsigned int base, unsigned int len,
-                                unsigned int bufsize)
-{
-       struct rpc_auth *auth = req->rq_cred->cr_auth;
-       unsigned int replen;
-
-       replen = RPC_REPHDRSIZE + auth->au_rslack + bufsize;
-       xdr_inline_pages(&req->rq_rcv_buf, replen << 2, pages, base, len);
-}
-
 /*
  * Encode/decode NFSv3 basic data types
  *
@@ -910,8 +895,8 @@ static void nfs3_xdr_enc_readlink3args(struct rpc_rqst *req,
        const struct nfs3_readlinkargs *args = data;
 
        encode_nfs_fh3(xdr, args->fh);
-       prepare_reply_buffer(req, args->pages, args->pgbase,
-                                       args->pglen, NFS3_readlinkres_sz);
+       rpc_prepare_reply_pages(req, args->pages, args->pgbase,
+                               args->pglen, NFS3_readlinkres_sz);
 }
 
 /*
@@ -943,8 +928,8 @@ static void nfs3_xdr_enc_read3args(struct rpc_rqst *req,
        unsigned int replen = args->replen ? args->replen : NFS3_readres_sz;
 
        encode_read3args(xdr, args);
-       prepare_reply_buffer(req, args->pages, args->pgbase,
-                                       args->count, replen);
+       rpc_prepare_reply_pages(req, args->pages, args->pgbase,
+                               args->count, replen);
        req->rq_rcv_buf.flags |= XDRBUF_READ;
 }
 
@@ -1236,7 +1221,7 @@ static void nfs3_xdr_enc_readdir3args(struct rpc_rqst *req,
        const struct nfs3_readdirargs *args = data;
 
        encode_readdir3args(xdr, args);
-       prepare_reply_buffer(req, args->pages, 0,
+       rpc_prepare_reply_pages(req, args->pages, 0,
                                args->count, NFS3_readdirres_sz);
 }
 
@@ -1278,7 +1263,7 @@ static void nfs3_xdr_enc_readdirplus3args(struct rpc_rqst *req,
        const struct nfs3_readdirargs *args = data;
 
        encode_readdirplus3args(xdr, args);
-       prepare_reply_buffer(req, args->pages, 0,
+       rpc_prepare_reply_pages(req, args->pages, 0,
                                args->count, NFS3_readdirres_sz);
 }
 
@@ -1323,7 +1308,7 @@ static void nfs3_xdr_enc_getacl3args(struct rpc_rqst *req,
        encode_nfs_fh3(xdr, args->fh);
        encode_uint32(xdr, args->mask);
        if (args->mask & (NFS_ACL | NFS_DFACL)) {
-               prepare_reply_buffer(req, args->pages, 0,
+               rpc_prepare_reply_pages(req, args->pages, 0,
                                        NFSACL_MAXPAGES << PAGE_SHIFT,
                                        ACL3_getaclres_sz);
                req->rq_rcv_buf.flags |= XDRBUF_SPARSE_PAGES;
index 38a4cbc18657829a7e52a945a4087715fb8c075a..d0fa18df32ea4a75fcf7a8ae0b49b436914461d0 100644 (file)
@@ -1016,12 +1016,11 @@ static void encode_compound_hdr(struct xdr_stream *xdr,
                                struct compound_hdr *hdr)
 {
        __be32 *p;
-       struct rpc_auth *auth = req->rq_cred->cr_auth;
 
        /* initialize running count of expected bytes in reply.
         * NOTE: the replied tag SHOULD be the same is the one sent,
         * but this is not required as a MUST for the server to do so. */
-       hdr->replen = RPC_REPHDRSIZE + auth->au_rslack + 3 + hdr->taglen;
+       hdr->replen = 3 + hdr->taglen;
 
        WARN_ON_ONCE(hdr->taglen > NFS4_MAXTAGLEN);
        encode_string(xdr, hdr->taglen, hdr->tag);
@@ -2341,9 +2340,9 @@ static void nfs4_xdr_enc_open(struct rpc_rqst *req, struct xdr_stream *xdr,
        encode_getfattr_open(xdr, args->bitmask, args->open_bitmap, &hdr);
        if (args->lg_args) {
                encode_layoutget(xdr, args->lg_args, &hdr);
-               xdr_inline_pages(&req->rq_rcv_buf, hdr.replen << 2,
-                                args->lg_args->layout.pages,
-                                0, args->lg_args->layout.pglen);
+               rpc_prepare_reply_pages(req, args->lg_args->layout.pages, 0,
+                                       args->lg_args->layout.pglen,
+                                       hdr.replen);
        }
        encode_nops(&hdr);
 }
@@ -2387,9 +2386,9 @@ static void nfs4_xdr_enc_open_noattr(struct rpc_rqst *req,
        encode_getfattr_open(xdr, args->bitmask, args->open_bitmap, &hdr);
        if (args->lg_args) {
                encode_layoutget(xdr, args->lg_args, &hdr);
-               xdr_inline_pages(&req->rq_rcv_buf, hdr.replen << 2,
-                                args->lg_args->layout.pages,
-                                0, args->lg_args->layout.pglen);
+               rpc_prepare_reply_pages(req, args->lg_args->layout.pages, 0,
+                                       args->lg_args->layout.pglen,
+                                       hdr.replen);
        }
        encode_nops(&hdr);
 }
@@ -2499,8 +2498,8 @@ static void nfs4_xdr_enc_readlink(struct rpc_rqst *req, struct xdr_stream *xdr,
        encode_putfh(xdr, args->fh, &hdr);
        encode_readlink(xdr, args, req, &hdr);
 
-       xdr_inline_pages(&req->rq_rcv_buf, hdr.replen << 2, args->pages,
-                       args->pgbase, args->pglen);
+       rpc_prepare_reply_pages(req, args->pages, args->pgbase,
+                               args->pglen, hdr.replen);
        encode_nops(&hdr);
 }
 
@@ -2520,11 +2519,8 @@ static void nfs4_xdr_enc_readdir(struct rpc_rqst *req, struct xdr_stream *xdr,
        encode_putfh(xdr, args->fh, &hdr);
        encode_readdir(xdr, args, req, &hdr);
 
-       xdr_inline_pages(&req->rq_rcv_buf, hdr.replen << 2, args->pages,
-                        args->pgbase, args->count);
-       dprintk("%s: inlined page args = (%u, %p, %u, %u)\n",
-                       __func__, hdr.replen << 2, args->pages,
-                       args->pgbase, args->count);
+       rpc_prepare_reply_pages(req, args->pages, args->pgbase,
+                               args->count, hdr.replen);
        encode_nops(&hdr);
 }
 
@@ -2544,8 +2540,8 @@ static void nfs4_xdr_enc_read(struct rpc_rqst *req, struct xdr_stream *xdr,
        encode_putfh(xdr, args->fh, &hdr);
        encode_read(xdr, args, &hdr);
 
-       xdr_inline_pages(&req->rq_rcv_buf, hdr.replen << 2,
-                        args->pages, args->pgbase, args->count);
+       rpc_prepare_reply_pages(req, args->pages, args->pgbase,
+                               args->count, hdr.replen);
        req->rq_rcv_buf.flags |= XDRBUF_READ;
        encode_nops(&hdr);
 }
@@ -2591,9 +2587,8 @@ static void nfs4_xdr_enc_getacl(struct rpc_rqst *req, struct xdr_stream *xdr,
        encode_getattr(xdr, nfs4_acl_bitmap, NULL,
                        ARRAY_SIZE(nfs4_acl_bitmap), &hdr);
 
-       xdr_inline_pages(&req->rq_rcv_buf, replen << 2,
-               args->acl_pages, 0, args->acl_len);
-
+       rpc_prepare_reply_pages(req, args->acl_pages, 0,
+                               args->acl_len, replen);
        encode_nops(&hdr);
 }
 
@@ -2814,9 +2809,8 @@ static void nfs4_xdr_enc_fs_locations(struct rpc_rqst *req,
                encode_fs_locations(xdr, args->bitmask, &hdr);
        }
 
-       /* Set up reply kvec to capture returned fs_locations array. */
-       xdr_inline_pages(&req->rq_rcv_buf, replen << 2,
-                        (struct page **)&args->page, 0, PAGE_SIZE);
+       rpc_prepare_reply_pages(req, (struct page **)&args->page, 0,
+                               PAGE_SIZE, replen);
        encode_nops(&hdr);
 }
 
@@ -3018,10 +3012,8 @@ static void nfs4_xdr_enc_getdeviceinfo(struct rpc_rqst *req,
 
        /* set up reply kvec. Subtract notification bitmap max size (2)
         * so that notification bitmap is put in xdr_buf tail */
-       xdr_inline_pages(&req->rq_rcv_buf, (hdr.replen - 2) << 2,
-                        args->pdev->pages, args->pdev->pgbase,
-                        args->pdev->pglen);
-
+       rpc_prepare_reply_pages(req, args->pdev->pages, args->pdev->pgbase,
+                               args->pdev->pglen, hdr.replen - 2);
        encode_nops(&hdr);
 }
 
@@ -3042,9 +3034,8 @@ static void nfs4_xdr_enc_layoutget(struct rpc_rqst *req,
        encode_putfh(xdr, NFS_FH(args->inode), &hdr);
        encode_layoutget(xdr, args, &hdr);
 
-       xdr_inline_pages(&req->rq_rcv_buf, hdr.replen << 2,
-           args->layout.pages, 0, args->layout.pglen);
-
+       rpc_prepare_reply_pages(req, args->layout.pages, 0,
+                               args->layout.pglen, hdr.replen);
        encode_nops(&hdr);
 }
 
index 1c441714d569bcb46ecae21cf96c882a7a235502..98bc9883b23096430cf7bcd36d97ea374cb88e69 100644 (file)
@@ -169,6 +169,9 @@ int         rpcb_v4_register(struct net *net, const u32 program,
                                 const char *netid);
 void           rpcb_getport_async(struct rpc_task *);
 
+void rpc_prepare_reply_pages(struct rpc_rqst *req, struct page **pages,
+                            unsigned int base, unsigned int len,
+                            unsigned int hdrsize);
 void           rpc_call_start(struct rpc_task *);
 int            rpc_call_async(struct rpc_clnt *clnt,
                               const struct rpc_message *msg, int flags,
index e58dda8e038cec2e1dcfd0b6f7b0d7919047b2bb..8451f30c6a0fe8fa216c5f57a1ae81e8bded2e91 100644 (file)
@@ -461,6 +461,43 @@ TRACE_EVENT(rpc_xdr_alignment,
        )
 );
 
+TRACE_EVENT(rpc_reply_pages,
+       TP_PROTO(
+               const struct rpc_rqst *req
+       ),
+
+       TP_ARGS(req),
+
+       TP_STRUCT__entry(
+               __field(unsigned int, task_id)
+               __field(unsigned int, client_id)
+               __field(const void *, head_base)
+               __field(size_t, head_len)
+               __field(const void *, tail_base)
+               __field(size_t, tail_len)
+               __field(unsigned int, page_len)
+       ),
+
+       TP_fast_assign(
+               __entry->task_id = req->rq_task->tk_pid;
+               __entry->client_id = req->rq_task->tk_client->cl_clid;
+
+               __entry->head_base = req->rq_rcv_buf.head[0].iov_base;
+               __entry->head_len = req->rq_rcv_buf.head[0].iov_len;
+               __entry->page_len = req->rq_rcv_buf.page_len;
+               __entry->tail_base = req->rq_rcv_buf.tail[0].iov_base;
+               __entry->tail_len = req->rq_rcv_buf.tail[0].iov_len;
+       ),
+
+       TP_printk(
+               "task:%u@%u xdr=[%p,%zu]/%u/[%p,%zu]\n",
+               __entry->task_id, __entry->client_id,
+               __entry->head_base, __entry->head_len,
+               __entry->page_len,
+               __entry->tail_base, __entry->tail_len
+       )
+);
+
 /*
  * First define the enums in the below macros to be exported to userspace
  * via TRACE_DEFINE_ENUM().
index 803e93105af15ed60e686ca2b9083ee2bf573abc..f780605fffe00334688bd20f7f79edd38a2acaf5 100644 (file)
@@ -1164,6 +1164,25 @@ struct rpc_task *rpc_run_bc_task(struct rpc_rqst *req)
 }
 #endif /* CONFIG_SUNRPC_BACKCHANNEL */
 
+/**
+ * rpc_prepare_reply_pages - Prepare to receive a reply data payload into pages
+ * @req: RPC request to prepare
+ * @pages: vector of struct page pointers
+ * @base: offset in first page where receive should start, in bytes
+ * @len: expected size of the upper layer data payload, in bytes
+ * @hdrsize: expected size of upper layer reply header, in XDR words
+ *
+ */
+void rpc_prepare_reply_pages(struct rpc_rqst *req, struct page **pages,
+                            unsigned int base, unsigned int len,
+                            unsigned int hdrsize)
+{
+       hdrsize += RPC_REPHDRSIZE + req->rq_cred->cr_auth->au_rslack;
+       xdr_inline_pages(&req->rq_rcv_buf, hdrsize << 2, pages, base, len);
+       trace_rpc_reply_pages(req);
+}
+EXPORT_SYMBOL_GPL(rpc_prepare_reply_pages);
+
 void
 rpc_call_start(struct rpc_task *task)
 {
index 4bce619780625cbbff44aa342087828adf093e84..7cca51560442dc0357435cfeaef559be164b3268 100644 (file)
@@ -163,6 +163,15 @@ xdr_free_bvec(struct xdr_buf *buf)
        buf->bvec = NULL;
 }
 
+/**
+ * xdr_inline_pages - Prepare receive buffer for a large reply
+ * @xdr: xdr_buf into which reply will be placed
+ * @offset: expected offset where data payload will start, in bytes
+ * @pages: vector of struct page pointers
+ * @base: offset in first page where receive should start, in bytes
+ * @len: expected size of the upper layer data payload, in bytes
+ *
+ */
 void
 xdr_inline_pages(struct xdr_buf *xdr, unsigned int offset,
                 struct page **pages, unsigned int base, unsigned int len)