]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
NFSD: Invoke svc_encode_result_payload() in "read" NFSD encoders
authorChuck Lever <chuck.lever@oracle.com>
Thu, 5 Nov 2020 15:24:19 +0000 (10:24 -0500)
committerChuck Lever <chuck.lever@oracle.com>
Mon, 30 Nov 2020 18:00:22 +0000 (13:00 -0500)
Have the NFSD encoders annotate the boundaries of every
direct-data-placement eligible result data payload. Then change
svcrdma to use that annotation instead of the xdr->page_len
when handling Write chunks.

For NFSv4 on RDMA, that enables the ability to recognize multiple
result payloads per compound. This is a pre-requisite for supporting
multiple Write chunks per RPC transaction.

Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
fs/nfsd/nfs3xdr.c
fs/nfsd/nfs4xdr.c
fs/nfsd/nfsxdr.c
net/sunrpc/xprtrdma/svc_rdma_sendto.c

index 2277f83da25012a54acafc93248351ebfc225b53..186b07a72373e5f01df4b2ad2e960e117605cd42 100644 (file)
@@ -707,6 +707,7 @@ int
 nfs3svc_encode_readlinkres(struct svc_rqst *rqstp, __be32 *p)
 {
        struct nfsd3_readlinkres *resp = rqstp->rq_resp;
+       struct kvec *head = rqstp->rq_res.head;
 
        *p++ = resp->status;
        p = encode_post_op_attr(rqstp, p, &resp->fh);
@@ -720,6 +721,8 @@ nfs3svc_encode_readlinkres(struct svc_rqst *rqstp, __be32 *p)
                        *p = 0;
                        rqstp->rq_res.tail[0].iov_len = 4 - (resp->len&3);
                }
+               if (svc_encode_result_payload(rqstp, head->iov_len, resp->len))
+                       return 0;
                return 1;
        } else
                return xdr_ressize_check(rqstp, p);
@@ -730,6 +733,7 @@ int
 nfs3svc_encode_readres(struct svc_rqst *rqstp, __be32 *p)
 {
        struct nfsd3_readres *resp = rqstp->rq_resp;
+       struct kvec *head = rqstp->rq_res.head;
 
        *p++ = resp->status;
        p = encode_post_op_attr(rqstp, p, &resp->fh);
@@ -746,6 +750,9 @@ nfs3svc_encode_readres(struct svc_rqst *rqstp, __be32 *p)
                        *p = 0;
                        rqstp->rq_res.tail[0].iov_len = 4 - (resp->count & 3);
                }
+               if (svc_encode_result_payload(rqstp, head->iov_len,
+                                             resp->count))
+                       return 0;
                return 1;
        } else
                return xdr_ressize_check(rqstp, p);
index 7e24fb3ca36e746b434585774dcdcd1848193444..1d2c33cd3a877737eae09d481bb1d43154341a06 100644 (file)
@@ -3756,8 +3756,8 @@ static __be32 nfsd4_encode_splice_read(
 {
        struct xdr_stream *xdr = &resp->xdr;
        struct xdr_buf *buf = xdr->buf;
+       int status, space_left;
        u32 eof;
-       int space_left;
        __be32 nfserr;
        __be32 *p = xdr->p - 2;
 
@@ -3768,14 +3768,13 @@ static __be32 nfsd4_encode_splice_read(
        nfserr = nfsd_splice_read(read->rd_rqstp, read->rd_fhp,
                                  file, read->rd_offset, &maxcount, &eof);
        read->rd_length = maxcount;
-       if (nfserr) {
-               /*
-                * nfsd_splice_actor may have already messed with the
-                * page length; reset it so as not to confuse
-                * xdr_truncate_encode:
-                */
-               buf->page_len = 0;
-               return nfserr;
+       if (nfserr)
+               goto out_err;
+       status = svc_encode_result_payload(read->rd_rqstp,
+                                          buf->head[0].iov_len, maxcount);
+       if (status) {
+               nfserr = nfserrno(status);
+               goto out_err;
        }
 
        *(p++) = htonl(eof);
@@ -3806,6 +3805,15 @@ static __be32 nfsd4_encode_splice_read(
        xdr->end = (__be32 *)((void *)xdr->end + space_left);
 
        return 0;
+
+out_err:
+       /*
+        * nfsd_splice_actor may have already messed with the
+        * page length; reset it so as not to confuse
+        * xdr_truncate_encode in our caller.
+        */
+       buf->page_len = 0;
+       return nfserr;
 }
 
 static __be32 nfsd4_encode_readv(struct nfsd4_compoundres *resp,
@@ -3897,6 +3905,7 @@ nfsd4_encode_readlink(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd
        int zero = 0;
        struct xdr_stream *xdr = &resp->xdr;
        int length_offset = xdr->buf->len;
+       int status;
        __be32 *p;
 
        p = xdr_reserve_space(xdr, 4);
@@ -3917,9 +3926,13 @@ nfsd4_encode_readlink(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd
                                                (char *)p, &maxcount);
        if (nfserr == nfserr_isdir)
                nfserr = nfserr_inval;
-       if (nfserr) {
-               xdr_truncate_encode(xdr, length_offset);
-               return nfserr;
+       if (nfserr)
+               goto out_err;
+       status = svc_encode_result_payload(readlink->rl_rqstp, length_offset,
+                                          maxcount);
+       if (status) {
+               nfserr = nfserrno(status);
+               goto out_err;
        }
 
        wire_count = htonl(maxcount);
@@ -3929,6 +3942,10 @@ nfsd4_encode_readlink(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd
                write_bytes_to_xdr_buf(xdr->buf, length_offset + 4 + maxcount,
                                                &zero, 4 - (maxcount&3));
        return 0;
+
+out_err:
+       xdr_truncate_encode(xdr, length_offset);
+       return nfserr;
 }
 
 static __be32
index 8a288c8fcd57c9fbf9af41ef3a239fc3ed238d15..9e00a902113e37aa2fe057785db3e74b08bcba89 100644 (file)
@@ -469,6 +469,7 @@ int
 nfssvc_encode_readlinkres(struct svc_rqst *rqstp, __be32 *p)
 {
        struct nfsd_readlinkres *resp = rqstp->rq_resp;
+       struct kvec *head = rqstp->rq_res.head;
 
        *p++ = resp->status;
        if (resp->status != nfs_ok)
@@ -483,6 +484,8 @@ nfssvc_encode_readlinkres(struct svc_rqst *rqstp, __be32 *p)
                *p = 0;
                rqstp->rq_res.tail[0].iov_len = 4 - (resp->len&3);
        }
+       if (svc_encode_result_payload(rqstp, head->iov_len, resp->len))
+               return 0;
        return 1;
 }
 
@@ -490,6 +493,7 @@ int
 nfssvc_encode_readres(struct svc_rqst *rqstp, __be32 *p)
 {
        struct nfsd_readres *resp = rqstp->rq_resp;
+       struct kvec *head = rqstp->rq_res.head;
 
        *p++ = resp->status;
        if (resp->status != nfs_ok)
@@ -507,6 +511,8 @@ nfssvc_encode_readres(struct svc_rqst *rqstp, __be32 *p)
                *p = 0;
                rqstp->rq_res.tail[0].iov_len = 4 - (resp->count&3);
        }
+       if (svc_encode_result_payload(rqstp, head->iov_len, resp->count))
+               return 0;
        return 1;
 }
 
index c8411b4f3492a72fea773cb51396c234fb65e5cd..d6436c13d5c47a21d729e6f5c95cd2433615434e 100644 (file)
@@ -448,7 +448,6 @@ static ssize_t svc_rdma_encode_write_chunk(__be32 *src,
  * svc_rdma_encode_write_list - Encode RPC Reply's Write chunk list
  * @rctxt: Reply context with information about the RPC Call
  * @sctxt: Send context for the RPC Reply
- * @length: size in bytes of the payload in the first Write chunk
  *
  * The client provides a Write chunk list in the Call message. Fill
  * in the segments in the first Write chunk in the Reply's transport
@@ -465,12 +464,12 @@ static ssize_t svc_rdma_encode_write_chunk(__be32 *src,
  */
 static ssize_t
 svc_rdma_encode_write_list(const struct svc_rdma_recv_ctxt *rctxt,
-                          struct svc_rdma_send_ctxt *sctxt,
-                          unsigned int length)
+                          struct svc_rdma_send_ctxt *sctxt)
 {
        ssize_t len, ret;
 
-       ret = svc_rdma_encode_write_chunk(rctxt->rc_write_list, sctxt, length);
+       ret = svc_rdma_encode_write_chunk(rctxt->rc_write_list, sctxt,
+                                         rctxt->rc_read_payload_length);
        if (ret < 0)
                return ret;
        len = ret;
@@ -923,21 +922,12 @@ int svc_rdma_sendto(struct svc_rqst *rqstp)
                goto err0;
        if (wr_lst) {
                /* XXX: Presume the client sent only one Write chunk */
-               unsigned long offset;
-               unsigned int length;
-
-               if (rctxt->rc_read_payload_length) {
-                       offset = rctxt->rc_read_payload_offset;
-                       length = rctxt->rc_read_payload_length;
-               } else {
-                       offset = xdr->head[0].iov_len;
-                       length = xdr->page_len;
-               }
-               ret = svc_rdma_send_write_chunk(rdma, wr_lst, xdr, offset,
-                                               length);
+               ret = svc_rdma_send_write_chunk(rdma, wr_lst, xdr,
+                                               rctxt->rc_read_payload_offset,
+                                               rctxt->rc_read_payload_length);
                if (ret < 0)
                        goto err2;
-               if (svc_rdma_encode_write_list(rctxt, sctxt, length) < 0)
+               if (svc_rdma_encode_write_list(rctxt, sctxt) < 0)
                        goto err0;
        } else {
                if (xdr_stream_encode_item_absent(&sctxt->sc_stream) < 0)