Commit 76e5492b authored by Chuck Lever's avatar Chuck Lever
Browse files

NFSD: Invoke svc_encode_result_payload() in "read" NFSD encoders



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: default avatarChuck Lever <chuck.lever@oracle.com>
parent 03493bca
Loading
Loading
Loading
Loading
+7 −0
Original line number Diff line number Diff line
@@ -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);
+29 −12
Original line number Diff line number Diff line
@@ -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
+6 −0
Original line number Diff line number Diff line
@@ -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;
}

+7 −17
Original line number Diff line number Diff line
@@ -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)