Commit cf500bac authored by Chuck Lever's avatar Chuck Lever Committed by Anna Schumaker

SUNRPC: Introduce rpc_prepare_reply_pages()

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: default avatarChuck Lever <chuck.lever@oracle.com>
Signed-off-by: default avatarAnna Schumaker <Anna.Schumaker@Netapp.com>
parent 2573a464
...@@ -65,21 +65,6 @@ ...@@ -65,21 +65,6 @@
static int nfs_stat_to_errno(enum nfs_stat); 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 * Encode/decode NFSv2 basic data types
* *
...@@ -593,8 +578,8 @@ static void nfs2_xdr_enc_readlinkargs(struct rpc_rqst *req, ...@@ -593,8 +578,8 @@ static void nfs2_xdr_enc_readlinkargs(struct rpc_rqst *req,
const struct nfs_readlinkargs *args = data; const struct nfs_readlinkargs *args = data;
encode_fhandle(xdr, args->fh); encode_fhandle(xdr, args->fh);
prepare_reply_buffer(req, args->pages, args->pgbase, rpc_prepare_reply_pages(req, args->pages, args->pgbase,
args->pglen, NFS_readlinkres_sz); args->pglen, NFS_readlinkres_sz);
} }
/* /*
...@@ -629,8 +614,8 @@ static void nfs2_xdr_enc_readargs(struct rpc_rqst *req, ...@@ -629,8 +614,8 @@ static void nfs2_xdr_enc_readargs(struct rpc_rqst *req,
const struct nfs_pgio_args *args = data; const struct nfs_pgio_args *args = data;
encode_readargs(xdr, args); encode_readargs(xdr, args);
prepare_reply_buffer(req, args->pages, args->pgbase, rpc_prepare_reply_pages(req, args->pages, args->pgbase,
args->count, NFS_readres_sz); args->count, NFS_readres_sz);
req->rq_rcv_buf.flags |= XDRBUF_READ; req->rq_rcv_buf.flags |= XDRBUF_READ;
} }
...@@ -787,8 +772,8 @@ static void nfs2_xdr_enc_readdirargs(struct rpc_rqst *req, ...@@ -787,8 +772,8 @@ static void nfs2_xdr_enc_readdirargs(struct rpc_rqst *req,
const struct nfs_readdirargs *args = data; const struct nfs_readdirargs *args = data;
encode_readdirargs(xdr, args); encode_readdirargs(xdr, args);
prepare_reply_buffer(req, args->pages, 0, rpc_prepare_reply_pages(req, args->pages, 0,
args->count, NFS_readdirres_sz); args->count, NFS_readdirres_sz);
} }
/* /*
......
...@@ -104,21 +104,6 @@ static const umode_t nfs_type2fmt[] = { ...@@ -104,21 +104,6 @@ static const umode_t nfs_type2fmt[] = {
[NF3FIFO] = S_IFIFO, [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 * Encode/decode NFSv3 basic data types
* *
...@@ -910,8 +895,8 @@ static void nfs3_xdr_enc_readlink3args(struct rpc_rqst *req, ...@@ -910,8 +895,8 @@ static void nfs3_xdr_enc_readlink3args(struct rpc_rqst *req,
const struct nfs3_readlinkargs *args = data; const struct nfs3_readlinkargs *args = data;
encode_nfs_fh3(xdr, args->fh); encode_nfs_fh3(xdr, args->fh);
prepare_reply_buffer(req, args->pages, args->pgbase, rpc_prepare_reply_pages(req, args->pages, args->pgbase,
args->pglen, NFS3_readlinkres_sz); args->pglen, NFS3_readlinkres_sz);
} }
/* /*
...@@ -943,8 +928,8 @@ static void nfs3_xdr_enc_read3args(struct rpc_rqst *req, ...@@ -943,8 +928,8 @@ static void nfs3_xdr_enc_read3args(struct rpc_rqst *req,
unsigned int replen = args->replen ? args->replen : NFS3_readres_sz; unsigned int replen = args->replen ? args->replen : NFS3_readres_sz;
encode_read3args(xdr, args); encode_read3args(xdr, args);
prepare_reply_buffer(req, args->pages, args->pgbase, rpc_prepare_reply_pages(req, args->pages, args->pgbase,
args->count, replen); args->count, replen);
req->rq_rcv_buf.flags |= XDRBUF_READ; req->rq_rcv_buf.flags |= XDRBUF_READ;
} }
...@@ -1236,7 +1221,7 @@ static void nfs3_xdr_enc_readdir3args(struct rpc_rqst *req, ...@@ -1236,7 +1221,7 @@ static void nfs3_xdr_enc_readdir3args(struct rpc_rqst *req,
const struct nfs3_readdirargs *args = data; const struct nfs3_readdirargs *args = data;
encode_readdir3args(xdr, args); encode_readdir3args(xdr, args);
prepare_reply_buffer(req, args->pages, 0, rpc_prepare_reply_pages(req, args->pages, 0,
args->count, NFS3_readdirres_sz); args->count, NFS3_readdirres_sz);
} }
...@@ -1278,7 +1263,7 @@ static void nfs3_xdr_enc_readdirplus3args(struct rpc_rqst *req, ...@@ -1278,7 +1263,7 @@ static void nfs3_xdr_enc_readdirplus3args(struct rpc_rqst *req,
const struct nfs3_readdirargs *args = data; const struct nfs3_readdirargs *args = data;
encode_readdirplus3args(xdr, args); encode_readdirplus3args(xdr, args);
prepare_reply_buffer(req, args->pages, 0, rpc_prepare_reply_pages(req, args->pages, 0,
args->count, NFS3_readdirres_sz); args->count, NFS3_readdirres_sz);
} }
...@@ -1323,7 +1308,7 @@ static void nfs3_xdr_enc_getacl3args(struct rpc_rqst *req, ...@@ -1323,7 +1308,7 @@ static void nfs3_xdr_enc_getacl3args(struct rpc_rqst *req,
encode_nfs_fh3(xdr, args->fh); encode_nfs_fh3(xdr, args->fh);
encode_uint32(xdr, args->mask); encode_uint32(xdr, args->mask);
if (args->mask & (NFS_ACL | NFS_DFACL)) { 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, NFSACL_MAXPAGES << PAGE_SHIFT,
ACL3_getaclres_sz); ACL3_getaclres_sz);
req->rq_rcv_buf.flags |= XDRBUF_SPARSE_PAGES; req->rq_rcv_buf.flags |= XDRBUF_SPARSE_PAGES;
......
...@@ -1016,12 +1016,11 @@ static void encode_compound_hdr(struct xdr_stream *xdr, ...@@ -1016,12 +1016,11 @@ static void encode_compound_hdr(struct xdr_stream *xdr,
struct compound_hdr *hdr) struct compound_hdr *hdr)
{ {
__be32 *p; __be32 *p;
struct rpc_auth *auth = req->rq_cred->cr_auth;
/* initialize running count of expected bytes in reply. /* initialize running count of expected bytes in reply.
* NOTE: the replied tag SHOULD be the same is the one sent, * 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. */ * 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); WARN_ON_ONCE(hdr->taglen > NFS4_MAXTAGLEN);
encode_string(xdr, hdr->taglen, hdr->tag); 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, ...@@ -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); encode_getfattr_open(xdr, args->bitmask, args->open_bitmap, &hdr);
if (args->lg_args) { if (args->lg_args) {
encode_layoutget(xdr, args->lg_args, &hdr); encode_layoutget(xdr, args->lg_args, &hdr);
xdr_inline_pages(&req->rq_rcv_buf, hdr.replen << 2, rpc_prepare_reply_pages(req, args->lg_args->layout.pages, 0,
args->lg_args->layout.pages, args->lg_args->layout.pglen,
0, args->lg_args->layout.pglen); hdr.replen);
} }
encode_nops(&hdr); encode_nops(&hdr);
} }
...@@ -2387,9 +2386,9 @@ static void nfs4_xdr_enc_open_noattr(struct rpc_rqst *req, ...@@ -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); encode_getfattr_open(xdr, args->bitmask, args->open_bitmap, &hdr);
if (args->lg_args) { if (args->lg_args) {
encode_layoutget(xdr, args->lg_args, &hdr); encode_layoutget(xdr, args->lg_args, &hdr);
xdr_inline_pages(&req->rq_rcv_buf, hdr.replen << 2, rpc_prepare_reply_pages(req, args->lg_args->layout.pages, 0,
args->lg_args->layout.pages, args->lg_args->layout.pglen,
0, args->lg_args->layout.pglen); hdr.replen);
} }
encode_nops(&hdr); encode_nops(&hdr);
} }
...@@ -2499,8 +2498,8 @@ static void nfs4_xdr_enc_readlink(struct rpc_rqst *req, struct xdr_stream *xdr, ...@@ -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_putfh(xdr, args->fh, &hdr);
encode_readlink(xdr, args, req, &hdr); encode_readlink(xdr, args, req, &hdr);
xdr_inline_pages(&req->rq_rcv_buf, hdr.replen << 2, args->pages, rpc_prepare_reply_pages(req, args->pages, args->pgbase,
args->pgbase, args->pglen); args->pglen, hdr.replen);
encode_nops(&hdr); encode_nops(&hdr);
} }
...@@ -2520,11 +2519,8 @@ static void nfs4_xdr_enc_readdir(struct rpc_rqst *req, struct xdr_stream *xdr, ...@@ -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_putfh(xdr, args->fh, &hdr);
encode_readdir(xdr, args, req, &hdr); encode_readdir(xdr, args, req, &hdr);
xdr_inline_pages(&req->rq_rcv_buf, hdr.replen << 2, args->pages, rpc_prepare_reply_pages(req, args->pages, args->pgbase,
args->pgbase, args->count); args->count, hdr.replen);
dprintk("%s: inlined page args = (%u, %p, %u, %u)\n",
__func__, hdr.replen << 2, args->pages,
args->pgbase, args->count);
encode_nops(&hdr); encode_nops(&hdr);
} }
...@@ -2544,8 +2540,8 @@ static void nfs4_xdr_enc_read(struct rpc_rqst *req, struct xdr_stream *xdr, ...@@ -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_putfh(xdr, args->fh, &hdr);
encode_read(xdr, args, &hdr); encode_read(xdr, args, &hdr);
xdr_inline_pages(&req->rq_rcv_buf, hdr.replen << 2, rpc_prepare_reply_pages(req, args->pages, args->pgbase,
args->pages, args->pgbase, args->count); args->count, hdr.replen);
req->rq_rcv_buf.flags |= XDRBUF_READ; req->rq_rcv_buf.flags |= XDRBUF_READ;
encode_nops(&hdr); encode_nops(&hdr);
} }
...@@ -2591,9 +2587,8 @@ static void nfs4_xdr_enc_getacl(struct rpc_rqst *req, struct xdr_stream *xdr, ...@@ -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, encode_getattr(xdr, nfs4_acl_bitmap, NULL,
ARRAY_SIZE(nfs4_acl_bitmap), &hdr); ARRAY_SIZE(nfs4_acl_bitmap), &hdr);
xdr_inline_pages(&req->rq_rcv_buf, replen << 2, rpc_prepare_reply_pages(req, args->acl_pages, 0,
args->acl_pages, 0, args->acl_len); args->acl_len, replen);
encode_nops(&hdr); encode_nops(&hdr);
} }
...@@ -2814,9 +2809,8 @@ static void nfs4_xdr_enc_fs_locations(struct rpc_rqst *req, ...@@ -2814,9 +2809,8 @@ static void nfs4_xdr_enc_fs_locations(struct rpc_rqst *req,
encode_fs_locations(xdr, args->bitmask, &hdr); encode_fs_locations(xdr, args->bitmask, &hdr);
} }
/* Set up reply kvec to capture returned fs_locations array. */ rpc_prepare_reply_pages(req, (struct page **)&args->page, 0,
xdr_inline_pages(&req->rq_rcv_buf, replen << 2, PAGE_SIZE, replen);
(struct page **)&args->page, 0, PAGE_SIZE);
encode_nops(&hdr); encode_nops(&hdr);
} }
...@@ -3018,10 +3012,8 @@ static void nfs4_xdr_enc_getdeviceinfo(struct rpc_rqst *req, ...@@ -3018,10 +3012,8 @@ static void nfs4_xdr_enc_getdeviceinfo(struct rpc_rqst *req,
/* set up reply kvec. Subtract notification bitmap max size (2) /* set up reply kvec. Subtract notification bitmap max size (2)
* so that notification bitmap is put in xdr_buf tail */ * so that notification bitmap is put in xdr_buf tail */
xdr_inline_pages(&req->rq_rcv_buf, (hdr.replen - 2) << 2, rpc_prepare_reply_pages(req, args->pdev->pages, args->pdev->pgbase,
args->pdev->pages, args->pdev->pgbase, args->pdev->pglen, hdr.replen - 2);
args->pdev->pglen);
encode_nops(&hdr); encode_nops(&hdr);
} }
...@@ -3042,9 +3034,8 @@ static void nfs4_xdr_enc_layoutget(struct rpc_rqst *req, ...@@ -3042,9 +3034,8 @@ static void nfs4_xdr_enc_layoutget(struct rpc_rqst *req,
encode_putfh(xdr, NFS_FH(args->inode), &hdr); encode_putfh(xdr, NFS_FH(args->inode), &hdr);
encode_layoutget(xdr, args, &hdr); encode_layoutget(xdr, args, &hdr);
xdr_inline_pages(&req->rq_rcv_buf, hdr.replen << 2, rpc_prepare_reply_pages(req, args->layout.pages, 0,
args->layout.pages, 0, args->layout.pglen); args->layout.pglen, hdr.replen);
encode_nops(&hdr); encode_nops(&hdr);
} }
......
...@@ -169,6 +169,9 @@ int rpcb_v4_register(struct net *net, const u32 program, ...@@ -169,6 +169,9 @@ int rpcb_v4_register(struct net *net, const u32 program,
const char *netid); const char *netid);
void rpcb_getport_async(struct rpc_task *); 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 *); void rpc_call_start(struct rpc_task *);
int rpc_call_async(struct rpc_clnt *clnt, int rpc_call_async(struct rpc_clnt *clnt,
const struct rpc_message *msg, int flags, const struct rpc_message *msg, int flags,
......
...@@ -461,6 +461,43 @@ TRACE_EVENT(rpc_xdr_alignment, ...@@ -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 * First define the enums in the below macros to be exported to userspace
* via TRACE_DEFINE_ENUM(). * via TRACE_DEFINE_ENUM().
......
...@@ -1164,6 +1164,25 @@ struct rpc_task *rpc_run_bc_task(struct rpc_rqst *req) ...@@ -1164,6 +1164,25 @@ struct rpc_task *rpc_run_bc_task(struct rpc_rqst *req)
} }
#endif /* CONFIG_SUNRPC_BACKCHANNEL */ #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 void
rpc_call_start(struct rpc_task *task) rpc_call_start(struct rpc_task *task)
{ {
......
...@@ -163,6 +163,15 @@ xdr_free_bvec(struct xdr_buf *buf) ...@@ -163,6 +163,15 @@ xdr_free_bvec(struct xdr_buf *buf)
buf->bvec = NULL; 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 void
xdr_inline_pages(struct xdr_buf *xdr, unsigned int offset, xdr_inline_pages(struct xdr_buf *xdr, unsigned int offset,
struct page **pages, unsigned int base, unsigned int len) struct page **pages, unsigned int base, unsigned int len)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment