linux-nfs.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH v1 00/42] NFSv2/3 XDR encoder overhaul
@ 2021-03-01 15:15 Chuck Lever
  2021-03-01 15:15 ` [PATCH v1 01/42] NFSD: Extract the svcxdr_init_encode() helper Chuck Lever
                   ` (41 more replies)
  0 siblings, 42 replies; 58+ messages in thread
From: Chuck Lever @ 2021-03-01 15:15 UTC (permalink / raw)
  To: linux-nfs

Hi-

This patch series updates the server-side XDR encoder functions for
NFS versions 2 and 3. The series was available on both test servers
I maintained at last week's virtual bake-a-thon event.

I expect that the only controversial part of the series is the
changes to NFSv3 READDIR and the per-entry encoders. If the reader
has no time for anything else, please have a close look at those.

The series is also available in the for-next topic branch here:

git://git.kernel.org/pub/scm/linux/kernel/git/cel/linux.git

---

Chuck Lever (42):
      NFSD: Extract the svcxdr_init_encode() helper
      NFSD: Update the GETATTR3res encoder to use struct xdr_stream
      NFSD: Update the NFSv3 ACCESS3res encoder to use struct xdr_stream
      NFSD: Update the NFSv3 LOOKUP3res encoder to use struct xdr_stream
      NFSD: Update the NFSv3 wccstat result encoder to use struct xdr_stream
      NFSD: Update the NFSv3 READLINK3res encoder to use struct xdr_stream
      NFSD: Update the NFSv3 READ3res encode to use struct xdr_stream
      NFSD: Update the NFSv3 WRITE3res encoder to use struct xdr_stream
      NFSD: Update the NFSv3 CREATE family of encoders to use struct xdr_stream
      NFSD: Update the NFSv3 RENAMEv3res encoder to use struct xdr_stream
      NFSD: Update the NFSv3 LINK3res encoder to use struct xdr_stream
      NFSD: Update the NFSv3 FSSTAT3res encoder to use struct xdr_stream
      NFSD: Update the NFSv3 FSINFO3res encoder to use struct xdr_stream
      NFSD: Update the NFSv3 PATHCONF3res encoder to use struct xdr_stream
      NFSD: Update the NFSv3 COMMIT3res encoder to use struct xdr_stream
      NFSD: Add a helper that encodes NFSv3 directory offset cookies
      NFSD: Count bytes instead of pages in the NFSv3 READDIR encoder
      NFSD: Update the NFSv3 READDIR3res encoder to use struct xdr_stream
      SUNRPC: Fix xdr_get_next_encode_buffer() page boundary handling
      NFSD: Update NFSv3 READDIR entry encoders to use struct xdr_stream
      NFSD: Remove unused NFSv3 directory entry encoders
      NFSD: Reduce svc_rqst::rq_pages churn during READDIR operations
      NFSD: Update the NFSv2 stat encoder to use struct xdr_stream
      NFSD: Update the NFSv2 attrstat encoder to use struct xdr_stream
      NFSD: Update the NFSv2 diropres encoder to use struct xdr_stream
      NFSD: Update the NFSv2 READLINK result encoder to use struct xdr_stream
      NFSD: Update the NFSv2 READ result encoder to use struct xdr_stream
      NFSD: Update the NFSv2 STATFS result encoder to use struct xdr_stream
      NFSD: Add a helper that encodes NFSv3 directory offset cookies
      NFSD: Count bytes instead of pages in the NFSv2 READDIR encoder
      NFSD: Update the NFSv2 READDIR result encoder to use struct xdr_stream
      NFSD: Update the NFSv2 READDIR entry encoder to use struct xdr_stream
      NFSD: Remove unused NFSv2 directory entry encoders
      NFSD: Add an xdr_stream-based encoder for NFSv2/3 ACLs
      NFSD: Update the NFSv2 GETACL result encoder to use struct xdr_stream
      NFSD: Update the NFSv2 SETACL result encoder to use struct xdr_stream
      NFSD: Update the NFSv2 ACL GETATTR result encoder to use struct xdr_stream
      NFSD: Update the NFSv2 ACL ACCESS result encoder to use struct xdr_stream
      NFSD: Clean up after updating NFSv2 ACL encoders
      NFSD: Update the NFSv3 GETACL result encoder to use struct xdr_stream
      NFSD: Update the NFSv3 SETACL result encoder to use struct xdr_stream
      NFSD: Clean up after updating NFSv3 ACL encoders


 fs/nfs_common/nfsacl.c     |   71 +++
 fs/nfsd/nfs2acl.c          |   87 ++-
 fs/nfsd/nfs3acl.c          |   39 +-
 fs/nfsd/nfs3proc.c         |   97 ++--
 fs/nfsd/nfs3xdr.c          | 1044 ++++++++++++++++++++++--------------
 fs/nfsd/nfsfh.c            |    2 +-
 fs/nfsd/nfsfh.h            |    2 +-
 fs/nfsd/nfsproc.c          |   53 +-
 fs/nfsd/nfsxdr.c           |  411 ++++++++------
 fs/nfsd/vfs.h              |    2 +-
 fs/nfsd/xdr.h              |   23 +-
 fs/nfsd/xdr3.h             |   37 +-
 include/linux/nfsacl.h     |    3 +
 include/linux/sunrpc/xdr.h |   20 +
 net/sunrpc/xdr.c           |    2 +-
 15 files changed, 1143 insertions(+), 750 deletions(-)

--
Chuck Lever


^ permalink raw reply	[flat|nested] 58+ messages in thread

* [PATCH v1 01/42] NFSD: Extract the svcxdr_init_encode() helper
  2021-03-01 15:15 [PATCH v1 00/42] NFSv2/3 XDR encoder overhaul Chuck Lever
@ 2021-03-01 15:15 ` Chuck Lever
  2021-03-02 16:47   ` J. Bruce Fields
  2021-03-01 15:15 ` [PATCH v1 02/42] NFSD: Update the GETATTR3res encoder to use struct xdr_stream Chuck Lever
                   ` (40 subsequent siblings)
  41 siblings, 1 reply; 58+ messages in thread
From: Chuck Lever @ 2021-03-01 15:15 UTC (permalink / raw)
  To: linux-nfs

NFSD initializes an encode xdr_stream only after the RPC layer has
already inserted the RPC Reply header. Thus it behaves differently
than xdr_init_encode does, which assumes the passed-in xdr_buf is
entirely devoid of content.

nfs4proc.c has this server-side stream initialization helper, but
it is visible only to the NFSv4 code. Move this helper to a place
that can be accessed by NFSv2 and NFSv3 server XDR functions.

Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
---
 fs/nfsd/nfs4proc.c         |   31 +++---------
 fs/nfsd/nfs4state.c        |    6 +-
 fs/nfsd/nfs4xdr.c          |  110 ++++++++++++++++++++++----------------------
 fs/nfsd/nfssvc.c           |    4 +-
 fs/nfsd/xdr4.h             |    2 -
 include/linux/sunrpc/svc.h |   25 ++++++++++
 6 files changed, 94 insertions(+), 84 deletions(-)

diff --git a/fs/nfsd/nfs4proc.c b/fs/nfsd/nfs4proc.c
index acdb3cd806a1..b749033e467f 100644
--- a/fs/nfsd/nfs4proc.c
+++ b/fs/nfsd/nfs4proc.c
@@ -2262,25 +2262,6 @@ static bool need_wrongsec_check(struct svc_rqst *rqstp)
 	return !(nextd->op_flags & OP_HANDLES_WRONGSEC);
 }
 
-static void svcxdr_init_encode(struct svc_rqst *rqstp,
-			       struct nfsd4_compoundres *resp)
-{
-	struct xdr_stream *xdr = &resp->xdr;
-	struct xdr_buf *buf = &rqstp->rq_res;
-	struct kvec *head = buf->head;
-
-	xdr->buf = buf;
-	xdr->iov = head;
-	xdr->p   = head->iov_base + head->iov_len;
-	xdr->end = head->iov_base + PAGE_SIZE - rqstp->rq_auth_slack;
-	/* Tail and page_len should be zero at this point: */
-	buf->len = buf->head[0].iov_len;
-	xdr_reset_scratch_buffer(xdr);
-	xdr->page_ptr = buf->pages - 1;
-	buf->buflen = PAGE_SIZE * (1 + rqstp->rq_page_end - buf->pages)
-		- rqstp->rq_auth_slack;
-}
-
 #ifdef CONFIG_NFSD_V4_2_INTER_SSC
 static void
 check_if_stalefh_allowed(struct nfsd4_compoundargs *args)
@@ -2335,10 +2316,14 @@ nfsd4_proc_compound(struct svc_rqst *rqstp)
 	struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id);
 	__be32		status;
 
-	svcxdr_init_encode(rqstp, resp);
-	resp->tagp = resp->xdr.p;
+	resp->xdr = &rqstp->rq_res_stream;
+
+	/* reserve space for: NFS status code */
+	xdr_reserve_space(resp->xdr, XDR_UNIT);
+
+	resp->tagp = resp->xdr->p;
 	/* reserve space for: taglen, tag, and opcnt */
-	xdr_reserve_space(&resp->xdr, 8 + args->taglen);
+	xdr_reserve_space(resp->xdr, XDR_UNIT * 2 + args->taglen);
 	resp->taglen = args->taglen;
 	resp->tag = args->tag;
 	resp->rqstp = rqstp;
@@ -2444,7 +2429,7 @@ nfsd4_proc_compound(struct svc_rqst *rqstp)
 encode_op:
 		if (op->status == nfserr_replay_me) {
 			op->replay = &cstate->replay_owner->so_replay;
-			nfsd4_encode_replay(&resp->xdr, op);
+			nfsd4_encode_replay(resp->xdr, op);
 			status = op->status = op->replay->rp_status;
 		} else {
 			nfsd4_encode_operation(resp, op);
diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c
index 61552e89bd89..83a498ccab19 100644
--- a/fs/nfsd/nfs4state.c
+++ b/fs/nfsd/nfs4state.c
@@ -2903,7 +2903,7 @@ gen_callback(struct nfs4_client *clp, struct nfsd4_setclientid *se, struct svc_r
 static void
 nfsd4_store_cache_entry(struct nfsd4_compoundres *resp)
 {
-	struct xdr_buf *buf = resp->xdr.buf;
+	struct xdr_buf *buf = resp->xdr->buf;
 	struct nfsd4_slot *slot = resp->cstate.slot;
 	unsigned int base;
 
@@ -2973,7 +2973,7 @@ nfsd4_replay_cache_entry(struct nfsd4_compoundres *resp,
 			 struct nfsd4_sequence *seq)
 {
 	struct nfsd4_slot *slot = resp->cstate.slot;
-	struct xdr_stream *xdr = &resp->xdr;
+	struct xdr_stream *xdr = resp->xdr;
 	__be32 *p;
 	__be32 status;
 
@@ -3708,7 +3708,7 @@ nfsd4_sequence(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
 {
 	struct nfsd4_sequence *seq = &u->sequence;
 	struct nfsd4_compoundres *resp = rqstp->rq_resp;
-	struct xdr_stream *xdr = &resp->xdr;
+	struct xdr_stream *xdr = resp->xdr;
 	struct nfsd4_session *session;
 	struct nfs4_client *clp;
 	struct nfsd4_slot *slot;
diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c
index eaaa1605b5b5..e0f06d3cbd44 100644
--- a/fs/nfsd/nfs4xdr.c
+++ b/fs/nfsd/nfs4xdr.c
@@ -3581,7 +3581,7 @@ nfsd4_encode_stateid(struct xdr_stream *xdr, stateid_t *sid)
 static __be32
 nfsd4_encode_access(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_access *access)
 {
-	struct xdr_stream *xdr = &resp->xdr;
+	struct xdr_stream *xdr = resp->xdr;
 	__be32 *p;
 
 	p = xdr_reserve_space(xdr, 8);
@@ -3594,7 +3594,7 @@ nfsd4_encode_access(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_
 
 static __be32 nfsd4_encode_bind_conn_to_session(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_bind_conn_to_session *bcts)
 {
-	struct xdr_stream *xdr = &resp->xdr;
+	struct xdr_stream *xdr = resp->xdr;
 	__be32 *p;
 
 	p = xdr_reserve_space(xdr, NFS4_MAX_SESSIONID_LEN + 8);
@@ -3611,7 +3611,7 @@ static __be32 nfsd4_encode_bind_conn_to_session(struct nfsd4_compoundres *resp,
 static __be32
 nfsd4_encode_close(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_close *close)
 {
-	struct xdr_stream *xdr = &resp->xdr;
+	struct xdr_stream *xdr = resp->xdr;
 
 	return nfsd4_encode_stateid(xdr, &close->cl_stateid);
 }
@@ -3620,7 +3620,7 @@ nfsd4_encode_close(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_c
 static __be32
 nfsd4_encode_commit(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_commit *commit)
 {
-	struct xdr_stream *xdr = &resp->xdr;
+	struct xdr_stream *xdr = resp->xdr;
 	__be32 *p;
 
 	p = xdr_reserve_space(xdr, NFS4_VERIFIER_SIZE);
@@ -3634,7 +3634,7 @@ nfsd4_encode_commit(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_
 static __be32
 nfsd4_encode_create(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_create *create)
 {
-	struct xdr_stream *xdr = &resp->xdr;
+	struct xdr_stream *xdr = resp->xdr;
 	__be32 *p;
 
 	p = xdr_reserve_space(xdr, 20);
@@ -3649,7 +3649,7 @@ static __be32
 nfsd4_encode_getattr(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_getattr *getattr)
 {
 	struct svc_fh *fhp = getattr->ga_fhp;
-	struct xdr_stream *xdr = &resp->xdr;
+	struct xdr_stream *xdr = resp->xdr;
 
 	return nfsd4_encode_fattr(xdr, fhp, fhp->fh_export, fhp->fh_dentry,
 				    getattr->ga_bmval, resp->rqstp, 0);
@@ -3658,7 +3658,7 @@ nfsd4_encode_getattr(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4
 static __be32
 nfsd4_encode_getfh(struct nfsd4_compoundres *resp, __be32 nfserr, struct svc_fh **fhpp)
 {
-	struct xdr_stream *xdr = &resp->xdr;
+	struct xdr_stream *xdr = resp->xdr;
 	struct svc_fh *fhp = *fhpp;
 	unsigned int len;
 	__be32 *p;
@@ -3713,7 +3713,7 @@ nfsd4_encode_lock_denied(struct xdr_stream *xdr, struct nfsd4_lock_denied *ld)
 static __be32
 nfsd4_encode_lock(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_lock *lock)
 {
-	struct xdr_stream *xdr = &resp->xdr;
+	struct xdr_stream *xdr = resp->xdr;
 
 	if (!nfserr)
 		nfserr = nfsd4_encode_stateid(xdr, &lock->lk_resp_stateid);
@@ -3726,7 +3726,7 @@ nfsd4_encode_lock(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_lo
 static __be32
 nfsd4_encode_lockt(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_lockt *lockt)
 {
-	struct xdr_stream *xdr = &resp->xdr;
+	struct xdr_stream *xdr = resp->xdr;
 
 	if (nfserr == nfserr_denied)
 		nfsd4_encode_lock_denied(xdr, &lockt->lt_denied);
@@ -3736,7 +3736,7 @@ nfsd4_encode_lockt(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_l
 static __be32
 nfsd4_encode_locku(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_locku *locku)
 {
-	struct xdr_stream *xdr = &resp->xdr;
+	struct xdr_stream *xdr = resp->xdr;
 
 	return nfsd4_encode_stateid(xdr, &locku->lu_stateid);
 }
@@ -3745,7 +3745,7 @@ nfsd4_encode_locku(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_l
 static __be32
 nfsd4_encode_link(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_link *link)
 {
-	struct xdr_stream *xdr = &resp->xdr;
+	struct xdr_stream *xdr = resp->xdr;
 	__be32 *p;
 
 	p = xdr_reserve_space(xdr, 20);
@@ -3759,7 +3759,7 @@ nfsd4_encode_link(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_li
 static __be32
 nfsd4_encode_open(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_open *open)
 {
-	struct xdr_stream *xdr = &resp->xdr;
+	struct xdr_stream *xdr = resp->xdr;
 	__be32 *p;
 
 	nfserr = nfsd4_encode_stateid(xdr, &open->op_stateid);
@@ -3853,7 +3853,7 @@ nfsd4_encode_open(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_op
 static __be32
 nfsd4_encode_open_confirm(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_open_confirm *oc)
 {
-	struct xdr_stream *xdr = &resp->xdr;
+	struct xdr_stream *xdr = resp->xdr;
 
 	return nfsd4_encode_stateid(xdr, &oc->oc_resp_stateid);
 }
@@ -3861,7 +3861,7 @@ nfsd4_encode_open_confirm(struct nfsd4_compoundres *resp, __be32 nfserr, struct
 static __be32
 nfsd4_encode_open_downgrade(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_open_downgrade *od)
 {
-	struct xdr_stream *xdr = &resp->xdr;
+	struct xdr_stream *xdr = resp->xdr;
 
 	return nfsd4_encode_stateid(xdr, &od->od_stateid);
 }
@@ -3871,7 +3871,7 @@ static __be32 nfsd4_encode_splice_read(
 				struct nfsd4_read *read,
 				struct file *file, unsigned long maxcount)
 {
-	struct xdr_stream *xdr = &resp->xdr;
+	struct xdr_stream *xdr = resp->xdr;
 	struct xdr_buf *buf = xdr->buf;
 	int status, space_left;
 	u32 eof;
@@ -3937,7 +3937,7 @@ static __be32 nfsd4_encode_readv(struct nfsd4_compoundres *resp,
 				 struct nfsd4_read *read,
 				 struct file *file, unsigned long maxcount)
 {
-	struct xdr_stream *xdr = &resp->xdr;
+	struct xdr_stream *xdr = resp->xdr;
 	u32 eof;
 	int starting_len = xdr->buf->len - 8;
 	__be32 nfserr;
@@ -3976,7 +3976,7 @@ nfsd4_encode_read(struct nfsd4_compoundres *resp, __be32 nfserr,
 		  struct nfsd4_read *read)
 {
 	unsigned long maxcount;
-	struct xdr_stream *xdr = &resp->xdr;
+	struct xdr_stream *xdr = resp->xdr;
 	struct file *file;
 	int starting_len = xdr->buf->len;
 	__be32 *p;
@@ -3990,7 +3990,7 @@ nfsd4_encode_read(struct nfsd4_compoundres *resp, __be32 nfserr,
 		WARN_ON_ONCE(test_bit(RQ_SPLICE_OK, &resp->rqstp->rq_flags));
 		return nfserr_resource;
 	}
-	if (resp->xdr.buf->page_len &&
+	if (resp->xdr->buf->page_len &&
 	    test_bit(RQ_SPLICE_OK, &resp->rqstp->rq_flags)) {
 		WARN_ON_ONCE(1);
 		return nfserr_resource;
@@ -4020,7 +4020,7 @@ nfsd4_encode_readlink(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd
 	int maxcount;
 	__be32 wire_count;
 	int zero = 0;
-	struct xdr_stream *xdr = &resp->xdr;
+	struct xdr_stream *xdr = resp->xdr;
 	int length_offset = xdr->buf->len;
 	int status;
 	__be32 *p;
@@ -4072,7 +4072,7 @@ nfsd4_encode_readdir(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4
 	int bytes_left;
 	loff_t offset;
 	__be64 wire_offset;
-	struct xdr_stream *xdr = &resp->xdr;
+	struct xdr_stream *xdr = resp->xdr;
 	int starting_len = xdr->buf->len;
 	__be32 *p;
 
@@ -4083,8 +4083,8 @@ nfsd4_encode_readdir(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4
 	/* XXX: Following NFSv3, we ignore the READDIR verifier for now. */
 	*p++ = cpu_to_be32(0);
 	*p++ = cpu_to_be32(0);
-	resp->xdr.buf->head[0].iov_len = ((char *)resp->xdr.p)
-				- (char *)resp->xdr.buf->head[0].iov_base;
+	xdr->buf->head[0].iov_len = (char *)xdr->p -
+				    (char *)xdr->buf->head[0].iov_base;
 
 	/*
 	 * Number of bytes left for directory entries allowing for the
@@ -4159,7 +4159,7 @@ nfsd4_encode_readdir(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4
 static __be32
 nfsd4_encode_remove(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_remove *remove)
 {
-	struct xdr_stream *xdr = &resp->xdr;
+	struct xdr_stream *xdr = resp->xdr;
 	__be32 *p;
 
 	p = xdr_reserve_space(xdr, 20);
@@ -4172,7 +4172,7 @@ nfsd4_encode_remove(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_
 static __be32
 nfsd4_encode_rename(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_rename *rename)
 {
-	struct xdr_stream *xdr = &resp->xdr;
+	struct xdr_stream *xdr = resp->xdr;
 	__be32 *p;
 
 	p = xdr_reserve_space(xdr, 40);
@@ -4255,7 +4255,7 @@ static __be32
 nfsd4_encode_secinfo(struct nfsd4_compoundres *resp, __be32 nfserr,
 		     struct nfsd4_secinfo *secinfo)
 {
-	struct xdr_stream *xdr = &resp->xdr;
+	struct xdr_stream *xdr = resp->xdr;
 
 	return nfsd4_do_encode_secinfo(xdr, secinfo->si_exp);
 }
@@ -4264,7 +4264,7 @@ static __be32
 nfsd4_encode_secinfo_no_name(struct nfsd4_compoundres *resp, __be32 nfserr,
 		     struct nfsd4_secinfo_no_name *secinfo)
 {
-	struct xdr_stream *xdr = &resp->xdr;
+	struct xdr_stream *xdr = resp->xdr;
 
 	return nfsd4_do_encode_secinfo(xdr, secinfo->sin_exp);
 }
@@ -4276,7 +4276,7 @@ nfsd4_encode_secinfo_no_name(struct nfsd4_compoundres *resp, __be32 nfserr,
 static __be32
 nfsd4_encode_setattr(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_setattr *setattr)
 {
-	struct xdr_stream *xdr = &resp->xdr;
+	struct xdr_stream *xdr = resp->xdr;
 	__be32 *p;
 
 	p = xdr_reserve_space(xdr, 16);
@@ -4300,7 +4300,7 @@ nfsd4_encode_setattr(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4
 static __be32
 nfsd4_encode_setclientid(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_setclientid *scd)
 {
-	struct xdr_stream *xdr = &resp->xdr;
+	struct xdr_stream *xdr = resp->xdr;
 	__be32 *p;
 
 	if (!nfserr) {
@@ -4324,7 +4324,7 @@ nfsd4_encode_setclientid(struct nfsd4_compoundres *resp, __be32 nfserr, struct n
 static __be32
 nfsd4_encode_write(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_write *write)
 {
-	struct xdr_stream *xdr = &resp->xdr;
+	struct xdr_stream *xdr = resp->xdr;
 	__be32 *p;
 
 	p = xdr_reserve_space(xdr, 16);
@@ -4341,7 +4341,7 @@ static __be32
 nfsd4_encode_exchange_id(struct nfsd4_compoundres *resp, __be32 nfserr,
 			 struct nfsd4_exchange_id *exid)
 {
-	struct xdr_stream *xdr = &resp->xdr;
+	struct xdr_stream *xdr = resp->xdr;
 	__be32 *p;
 	char *major_id;
 	char *server_scope;
@@ -4419,7 +4419,7 @@ static __be32
 nfsd4_encode_create_session(struct nfsd4_compoundres *resp, __be32 nfserr,
 			    struct nfsd4_create_session *sess)
 {
-	struct xdr_stream *xdr = &resp->xdr;
+	struct xdr_stream *xdr = resp->xdr;
 	__be32 *p;
 
 	p = xdr_reserve_space(xdr, 24);
@@ -4472,7 +4472,7 @@ static __be32
 nfsd4_encode_sequence(struct nfsd4_compoundres *resp, __be32 nfserr,
 		      struct nfsd4_sequence *seq)
 {
-	struct xdr_stream *xdr = &resp->xdr;
+	struct xdr_stream *xdr = resp->xdr;
 	__be32 *p;
 
 	p = xdr_reserve_space(xdr, NFS4_MAX_SESSIONID_LEN + 20);
@@ -4495,7 +4495,7 @@ static __be32
 nfsd4_encode_test_stateid(struct nfsd4_compoundres *resp, __be32 nfserr,
 			  struct nfsd4_test_stateid *test_stateid)
 {
-	struct xdr_stream *xdr = &resp->xdr;
+	struct xdr_stream *xdr = resp->xdr;
 	struct nfsd4_test_stateid_id *stateid, *next;
 	__be32 *p;
 
@@ -4516,7 +4516,7 @@ static __be32
 nfsd4_encode_getdeviceinfo(struct nfsd4_compoundres *resp, __be32 nfserr,
 		struct nfsd4_getdeviceinfo *gdev)
 {
-	struct xdr_stream *xdr = &resp->xdr;
+	struct xdr_stream *xdr = resp->xdr;
 	const struct nfsd4_layout_ops *ops;
 	u32 starting_len = xdr->buf->len, needed_len;
 	__be32 *p;
@@ -4572,7 +4572,7 @@ static __be32
 nfsd4_encode_layoutget(struct nfsd4_compoundres *resp, __be32 nfserr,
 		struct nfsd4_layoutget *lgp)
 {
-	struct xdr_stream *xdr = &resp->xdr;
+	struct xdr_stream *xdr = resp->xdr;
 	const struct nfsd4_layout_ops *ops;
 	__be32 *p;
 
@@ -4599,7 +4599,7 @@ static __be32
 nfsd4_encode_layoutcommit(struct nfsd4_compoundres *resp, __be32 nfserr,
 			  struct nfsd4_layoutcommit *lcp)
 {
-	struct xdr_stream *xdr = &resp->xdr;
+	struct xdr_stream *xdr = resp->xdr;
 	__be32 *p;
 
 	p = xdr_reserve_space(xdr, 4);
@@ -4620,7 +4620,7 @@ static __be32
 nfsd4_encode_layoutreturn(struct nfsd4_compoundres *resp, __be32 nfserr,
 		struct nfsd4_layoutreturn *lrp)
 {
-	struct xdr_stream *xdr = &resp->xdr;
+	struct xdr_stream *xdr = resp->xdr;
 	__be32 *p;
 
 	p = xdr_reserve_space(xdr, 4);
@@ -4638,7 +4638,7 @@ nfsd42_encode_write_res(struct nfsd4_compoundres *resp,
 		struct nfsd42_write_res *write, bool sync)
 {
 	__be32 *p;
-	p = xdr_reserve_space(&resp->xdr, 4);
+	p = xdr_reserve_space(resp->xdr, 4);
 	if (!p)
 		return nfserr_resource;
 
@@ -4647,11 +4647,11 @@ nfsd42_encode_write_res(struct nfsd4_compoundres *resp,
 	else {
 		__be32 nfserr;
 		*p++ = cpu_to_be32(1);
-		nfserr = nfsd4_encode_stateid(&resp->xdr, &write->cb_stateid);
+		nfserr = nfsd4_encode_stateid(resp->xdr, &write->cb_stateid);
 		if (nfserr)
 			return nfserr;
 	}
-	p = xdr_reserve_space(&resp->xdr, 8 + 4 + NFS4_VERIFIER_SIZE);
+	p = xdr_reserve_space(resp->xdr, 8 + 4 + NFS4_VERIFIER_SIZE);
 	if (!p)
 		return nfserr_resource;
 
@@ -4665,7 +4665,7 @@ nfsd42_encode_write_res(struct nfsd4_compoundres *resp,
 static __be32
 nfsd42_encode_nl4_server(struct nfsd4_compoundres *resp, struct nl4_server *ns)
 {
-	struct xdr_stream *xdr = &resp->xdr;
+	struct xdr_stream *xdr = resp->xdr;
 	struct nfs42_netaddr *addr;
 	__be32 *p;
 
@@ -4713,7 +4713,7 @@ nfsd4_encode_copy(struct nfsd4_compoundres *resp, __be32 nfserr,
 	if (nfserr)
 		return nfserr;
 
-	p = xdr_reserve_space(&resp->xdr, 4 + 4);
+	p = xdr_reserve_space(resp->xdr, 4 + 4);
 	*p++ = xdr_one; /* cr_consecutive */
 	*p++ = cpu_to_be32(copy->cp_synchronous);
 	return 0;
@@ -4723,7 +4723,7 @@ static __be32
 nfsd4_encode_offload_status(struct nfsd4_compoundres *resp, __be32 nfserr,
 			    struct nfsd4_offload_status *os)
 {
-	struct xdr_stream *xdr = &resp->xdr;
+	struct xdr_stream *xdr = resp->xdr;
 	__be32 *p;
 
 	p = xdr_reserve_space(xdr, 8 + 4);
@@ -4740,7 +4740,7 @@ nfsd4_encode_read_plus_data(struct nfsd4_compoundres *resp,
 			    unsigned long *maxcount, u32 *eof,
 			    loff_t *pos)
 {
-	struct xdr_stream *xdr = &resp->xdr;
+	struct xdr_stream *xdr = resp->xdr;
 	struct file *file = read->rd_nf->nf_file;
 	int starting_len = xdr->buf->len;
 	loff_t hole_pos;
@@ -4799,7 +4799,7 @@ nfsd4_encode_read_plus_hole(struct nfsd4_compoundres *resp,
 	count = data_pos - read->rd_offset;
 
 	/* Content type, offset, byte count */
-	p = xdr_reserve_space(&resp->xdr, 4 + 8 + 8);
+	p = xdr_reserve_space(resp->xdr, 4 + 8 + 8);
 	if (!p)
 		return nfserr_resource;
 
@@ -4817,7 +4817,7 @@ nfsd4_encode_read_plus(struct nfsd4_compoundres *resp, __be32 nfserr,
 		       struct nfsd4_read *read)
 {
 	unsigned long maxcount, count;
-	struct xdr_stream *xdr = &resp->xdr;
+	struct xdr_stream *xdr = resp->xdr;
 	struct file *file;
 	int starting_len = xdr->buf->len;
 	int last_segment = xdr->buf->len;
@@ -4888,7 +4888,7 @@ static __be32
 nfsd4_encode_copy_notify(struct nfsd4_compoundres *resp, __be32 nfserr,
 			 struct nfsd4_copy_notify *cn)
 {
-	struct xdr_stream *xdr = &resp->xdr;
+	struct xdr_stream *xdr = resp->xdr;
 	__be32 *p;
 
 	if (nfserr)
@@ -4924,7 +4924,7 @@ nfsd4_encode_seek(struct nfsd4_compoundres *resp, __be32 nfserr,
 {
 	__be32 *p;
 
-	p = xdr_reserve_space(&resp->xdr, 4 + 8);
+	p = xdr_reserve_space(resp->xdr, 4 + 8);
 	*p++ = cpu_to_be32(seek->seek_eof);
 	p = xdr_encode_hyper(p, seek->seek_pos);
 
@@ -4985,7 +4985,7 @@ static __be32
 nfsd4_encode_getxattr(struct nfsd4_compoundres *resp, __be32 nfserr,
 		      struct nfsd4_getxattr *getxattr)
 {
-	struct xdr_stream *xdr = &resp->xdr;
+	struct xdr_stream *xdr = resp->xdr;
 	__be32 *p, err;
 
 	p = xdr_reserve_space(xdr, 4);
@@ -5009,7 +5009,7 @@ static __be32
 nfsd4_encode_setxattr(struct nfsd4_compoundres *resp, __be32 nfserr,
 		      struct nfsd4_setxattr *setxattr)
 {
-	struct xdr_stream *xdr = &resp->xdr;
+	struct xdr_stream *xdr = resp->xdr;
 	__be32 *p;
 
 	p = xdr_reserve_space(xdr, 20);
@@ -5050,7 +5050,7 @@ static __be32
 nfsd4_encode_listxattrs(struct nfsd4_compoundres *resp, __be32 nfserr,
 			struct nfsd4_listxattrs *listxattrs)
 {
-	struct xdr_stream *xdr = &resp->xdr;
+	struct xdr_stream *xdr = resp->xdr;
 	u32 cookie_offset, count_offset, eof;
 	u32 left, xdrleft, slen, count;
 	u32 xdrlen, offset;
@@ -5161,7 +5161,7 @@ static __be32
 nfsd4_encode_removexattr(struct nfsd4_compoundres *resp, __be32 nfserr,
 			 struct nfsd4_removexattr *removexattr)
 {
-	struct xdr_stream *xdr = &resp->xdr;
+	struct xdr_stream *xdr = resp->xdr;
 	__be32 *p;
 
 	p = xdr_reserve_space(xdr, 20);
@@ -5301,7 +5301,7 @@ __be32 nfsd4_check_resp_size(struct nfsd4_compoundres *resp, u32 respsize)
 void
 nfsd4_encode_operation(struct nfsd4_compoundres *resp, struct nfsd4_op *op)
 {
-	struct xdr_stream *xdr = &resp->xdr;
+	struct xdr_stream *xdr = resp->xdr;
 	struct nfs4_stateowner *so = resp->cstate.replay_owner;
 	struct svc_rqst *rqstp = resp->rqstp;
 	const struct nfsd4_operation *opdesc = op->opdesc;
@@ -5430,14 +5430,14 @@ int
 nfs4svc_encode_compoundres(struct svc_rqst *rqstp, __be32 *p)
 {
 	struct nfsd4_compoundres *resp = rqstp->rq_resp;
-	struct xdr_buf *buf = resp->xdr.buf;
+	struct xdr_buf *buf = resp->xdr->buf;
 
 	WARN_ON_ONCE(buf->len != buf->head[0].iov_len + buf->page_len +
 				 buf->tail[0].iov_len);
 
 	*p = resp->cstate.status;
 
-	rqstp->rq_next_page = resp->xdr.page_ptr + 1;
+	rqstp->rq_next_page = resp->xdr->page_ptr + 1;
 
 	p = resp->tagp;
 	*p++ = htonl(resp->taglen);
diff --git a/fs/nfsd/nfssvc.c b/fs/nfsd/nfssvc.c
index 6de406322106..d909e4956244 100644
--- a/fs/nfsd/nfssvc.c
+++ b/fs/nfsd/nfssvc.c
@@ -997,7 +997,7 @@ int nfsd_dispatch(struct svc_rqst *rqstp, __be32 *statp)
 	 * NFSv4 does some encoding while processing
 	 */
 	p = resv->iov_base + resv->iov_len;
-	resv->iov_len += sizeof(__be32);
+	svcxdr_init_encode(rqstp);
 
 	*statp = proc->pc_func(rqstp);
 	if (*statp == rpc_drop_reply || test_bit(RQ_DROPME, &rqstp->rq_flags))
@@ -1052,7 +1052,7 @@ int nfssvc_decode_voidarg(struct svc_rqst *rqstp, __be32 *p)
  */
 int nfssvc_encode_voidres(struct svc_rqst *rqstp, __be32 *p)
 {
-        return xdr_ressize_check(rqstp, p);
+	return 1;
 }
 
 int nfsd_pool_stats_open(struct inode *inode, struct file *file)
diff --git a/fs/nfsd/xdr4.h b/fs/nfsd/xdr4.h
index c300885ae75d..fe540a3415c6 100644
--- a/fs/nfsd/xdr4.h
+++ b/fs/nfsd/xdr4.h
@@ -698,7 +698,7 @@ struct nfsd4_compoundargs {
 
 struct nfsd4_compoundres {
 	/* scratch variables for XDR encode */
-	struct xdr_stream		xdr;
+	struct xdr_stream		*xdr;
 	struct svc_rqst *		rqstp;
 
 	u32				taglen;
diff --git a/include/linux/sunrpc/svc.h b/include/linux/sunrpc/svc.h
index 31ee3b6047c3..e91d51ea028b 100644
--- a/include/linux/sunrpc/svc.h
+++ b/include/linux/sunrpc/svc.h
@@ -248,6 +248,7 @@ struct svc_rqst {
 	size_t			rq_xprt_hlen;	/* xprt header len */
 	struct xdr_buf		rq_arg;
 	struct xdr_stream	rq_arg_stream;
+	struct xdr_stream	rq_res_stream;
 	struct page		*rq_scratch_page;
 	struct xdr_buf		rq_res;
 	struct page		*rq_pages[RPCSVC_MAXPAGES + 1];
@@ -574,4 +575,28 @@ static inline void svcxdr_init_decode(struct svc_rqst *rqstp)
 	xdr_set_scratch_page(xdr, rqstp->rq_scratch_page);
 }
 
+/**
+ * svcxdr_init_encode - Prepare an xdr_stream for svc Reply encoding
+ * @rqstp: controlling server RPC transaction context
+ *
+ */
+static inline void svcxdr_init_encode(struct svc_rqst *rqstp)
+{
+	struct xdr_stream *xdr = &rqstp->rq_res_stream;
+	struct xdr_buf *buf = &rqstp->rq_res;
+	struct kvec *resv = buf->head;
+
+	xdr_reset_scratch_buffer(xdr);
+
+	xdr->buf = buf;
+	xdr->iov = resv;
+	xdr->p   = resv->iov_base + resv->iov_len;
+	xdr->end = resv->iov_base + PAGE_SIZE - rqstp->rq_auth_slack;
+	buf->len = resv->iov_len;
+	xdr->page_ptr = buf->pages - 1;
+	buf->buflen = PAGE_SIZE * (1 + rqstp->rq_page_end - buf->pages);
+	buf->buflen -= rqstp->rq_auth_slack;
+	xdr->rqst = NULL;
+}
+
 #endif /* SUNRPC_SVC_H */



^ permalink raw reply related	[flat|nested] 58+ messages in thread

* [PATCH v1 02/42] NFSD: Update the GETATTR3res encoder to use struct xdr_stream
  2021-03-01 15:15 [PATCH v1 00/42] NFSv2/3 XDR encoder overhaul Chuck Lever
  2021-03-01 15:15 ` [PATCH v1 01/42] NFSD: Extract the svcxdr_init_encode() helper Chuck Lever
@ 2021-03-01 15:15 ` Chuck Lever
  2021-03-01 15:15 ` [PATCH v1 03/42] NFSD: Update the NFSv3 ACCESS3res " Chuck Lever
                   ` (39 subsequent siblings)
  41 siblings, 0 replies; 58+ messages in thread
From: Chuck Lever @ 2021-03-01 15:15 UTC (permalink / raw)
  To: linux-nfs

As an additional clean up, some renaming is done to more closely
reflect the data type and variable names used in the NFSv3 XDR
definition provided in RFC 1813. "attrstat" is an NFSv2 thingie.

Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
---
 fs/nfsd/nfs3proc.c |    2 +
 fs/nfsd/nfs3xdr.c  |   95 ++++++++++++++++++++++++++++++++++++++++++++++++----
 fs/nfsd/nfsfh.c    |    2 +
 fs/nfsd/nfsfh.h    |    2 +
 fs/nfsd/xdr3.h     |    2 +
 5 files changed, 91 insertions(+), 12 deletions(-)

diff --git a/fs/nfsd/nfs3proc.c b/fs/nfsd/nfs3proc.c
index 8675851199f8..76a84481d526 100644
--- a/fs/nfsd/nfs3proc.c
+++ b/fs/nfsd/nfs3proc.c
@@ -736,7 +736,7 @@ static const struct svc_procedure nfsd_procedures3[22] = {
 	[NFS3PROC_GETATTR] = {
 		.pc_func = nfsd3_proc_getattr,
 		.pc_decode = nfs3svc_decode_fhandleargs,
-		.pc_encode = nfs3svc_encode_attrstatres,
+		.pc_encode = nfs3svc_encode_getattrres,
 		.pc_release = nfs3svc_release_fhandle,
 		.pc_argsize = sizeof(struct nfsd_fhandle),
 		.pc_ressize = sizeof(struct nfsd3_attrstatres),
diff --git a/fs/nfsd/nfs3xdr.c b/fs/nfsd/nfs3xdr.c
index 9d9a01ce0b27..75739861d235 100644
--- a/fs/nfsd/nfs3xdr.c
+++ b/fs/nfsd/nfs3xdr.c
@@ -20,7 +20,7 @@
 /*
  * Mapping of S_IF* types to NFS file types
  */
-static u32	nfs3_ftypes[] = {
+static const u32 nfs3_ftypes[] = {
 	NF3NON,  NF3FIFO, NF3CHR, NF3BAD,
 	NF3DIR,  NF3BAD,  NF3BLK, NF3BAD,
 	NF3REG,  NF3BAD,  NF3LNK, NF3BAD,
@@ -39,6 +39,15 @@ encode_time3(__be32 *p, struct timespec64 *time)
 	return p;
 }
 
+static __be32 *
+encode_nfstime3(__be32 *p, const struct timespec64 *time)
+{
+	*p++ = cpu_to_be32((u32)time->tv_sec);
+	*p++ = cpu_to_be32(time->tv_nsec);
+
+	return p;
+}
+
 static bool
 svcxdr_decode_nfstime3(struct xdr_stream *xdr, struct timespec64 *timep)
 {
@@ -82,6 +91,19 @@ svcxdr_decode_nfs_fh3(struct xdr_stream *xdr, struct svc_fh *fhp)
 	return true;
 }
 
+static bool
+svcxdr_encode_nfsstat3(struct xdr_stream *xdr, __be32 status)
+{
+	__be32 *p;
+
+	p = xdr_reserve_space(xdr, sizeof(status));
+	if (!p)
+		return false;
+	*p = status;
+
+	return true;
+}
+
 static __be32 *
 encode_fh(__be32 *p, struct svc_fh *fhp)
 {
@@ -253,6 +275,58 @@ svcxdr_decode_devicedata3(struct svc_rqst *rqstp, struct xdr_stream *xdr,
 		svcxdr_decode_specdata3(xdr, args);
 }
 
+static bool
+svcxdr_encode_fattr3(struct svc_rqst *rqstp, struct xdr_stream *xdr,
+		     const struct svc_fh *fhp, const struct kstat *stat)
+{
+	struct user_namespace *userns = nfsd_user_namespace(rqstp);
+	__be32 *p;
+	u64 fsid;
+
+	p = xdr_reserve_space(xdr, XDR_UNIT * 21);
+	if (!p)
+		return false;
+
+	*p++ = cpu_to_be32(nfs3_ftypes[(stat->mode & S_IFMT) >> 12]);
+	*p++ = cpu_to_be32((u32)(stat->mode & S_IALLUGO));
+	*p++ = cpu_to_be32((u32)stat->nlink);
+	*p++ = cpu_to_be32((u32)from_kuid_munged(userns, stat->uid));
+	*p++ = cpu_to_be32((u32)from_kgid_munged(userns, stat->gid));
+	if (S_ISLNK(stat->mode) && stat->size > NFS3_MAXPATHLEN)
+		p = xdr_encode_hyper(p, (u64)NFS3_MAXPATHLEN);
+	else
+		p = xdr_encode_hyper(p, (u64)stat->size);
+
+	/* used */
+	p = xdr_encode_hyper(p, ((u64)stat->blocks) << 9);
+
+	/* rdev */
+	*p++ = cpu_to_be32((u32)MAJOR(stat->rdev));
+	*p++ = cpu_to_be32((u32)MINOR(stat->rdev));
+
+	switch(fsid_source(fhp)) {
+	case FSIDSOURCE_FSID:
+		fsid = (u64)fhp->fh_export->ex_fsid;
+		break;
+	case FSIDSOURCE_UUID:
+		fsid = ((u64 *)fhp->fh_export->ex_uuid)[0];
+		fsid ^= ((u64 *)fhp->fh_export->ex_uuid)[1];
+		break;
+	default:
+		fsid = (u64)huge_encode_dev(fhp->fh_dentry->d_sb->s_dev);
+	}
+	p = xdr_encode_hyper(p, fsid);
+
+	/* fileid */
+	p = xdr_encode_hyper(p, stat->ino);
+
+	p = encode_nfstime3(p, &stat->atime);
+	p = encode_nfstime3(p, &stat->mtime);
+	encode_nfstime3(p, &stat->ctime);
+
+	return true;
+}
+
 static __be32 *encode_fsid(__be32 *p, struct svc_fh *fhp)
 {
 	u64 f;
@@ -713,17 +787,22 @@ nfs3svc_decode_commitargs(struct svc_rqst *rqstp, __be32 *p)
 
 /* GETATTR */
 int
-nfs3svc_encode_attrstat(struct svc_rqst *rqstp, __be32 *p)
+nfs3svc_encode_getattrres(struct svc_rqst *rqstp, __be32 *p)
 {
+	struct xdr_stream *xdr = &rqstp->rq_res_stream;
 	struct nfsd3_attrstat *resp = rqstp->rq_resp;
 
-	*p++ = resp->status;
-	if (resp->status == 0) {
-		lease_get_mtime(d_inode(resp->fh.fh_dentry),
-				&resp->stat.mtime);
-		p = encode_fattr3(rqstp, p, &resp->fh, &resp->stat);
+	if (!svcxdr_encode_nfsstat3(xdr, resp->status))
+		return 0;
+	switch (resp->status) {
+	case nfs_ok:
+		lease_get_mtime(d_inode(resp->fh.fh_dentry), &resp->stat.mtime);
+		if (!svcxdr_encode_fattr3(rqstp, xdr, &resp->fh, &resp->stat))
+			return 0;
+		break;
 	}
-	return xdr_ressize_check(rqstp, p);
+
+	return 1;
 }
 
 /* SETATTR, REMOVE, RMDIR */
diff --git a/fs/nfsd/nfsfh.c b/fs/nfsd/nfsfh.c
index 10b44421eace..c475d2271f9c 100644
--- a/fs/nfsd/nfsfh.c
+++ b/fs/nfsd/nfsfh.c
@@ -711,7 +711,7 @@ char * SVCFH_fmt(struct svc_fh *fhp)
 	return buf;
 }
 
-enum fsid_source fsid_source(struct svc_fh *fhp)
+enum fsid_source fsid_source(const struct svc_fh *fhp)
 {
 	if (fhp->fh_handle.fh_version != 1)
 		return FSIDSOURCE_DEV;
diff --git a/fs/nfsd/nfsfh.h b/fs/nfsd/nfsfh.h
index f58933519f38..aff2cda5c6c3 100644
--- a/fs/nfsd/nfsfh.h
+++ b/fs/nfsd/nfsfh.h
@@ -82,7 +82,7 @@ enum fsid_source {
 	FSIDSOURCE_FSID,
 	FSIDSOURCE_UUID,
 };
-extern enum fsid_source fsid_source(struct svc_fh *fhp);
+extern enum fsid_source fsid_source(const struct svc_fh *fhp);
 
 
 /*
diff --git a/fs/nfsd/xdr3.h b/fs/nfsd/xdr3.h
index 3e1578953f54..0822981c61b9 100644
--- a/fs/nfsd/xdr3.h
+++ b/fs/nfsd/xdr3.h
@@ -280,7 +280,7 @@ int nfs3svc_decode_symlinkargs(struct svc_rqst *, __be32 *);
 int nfs3svc_decode_readdirargs(struct svc_rqst *, __be32 *);
 int nfs3svc_decode_readdirplusargs(struct svc_rqst *, __be32 *);
 int nfs3svc_decode_commitargs(struct svc_rqst *, __be32 *);
-int nfs3svc_encode_attrstat(struct svc_rqst *, __be32 *);
+int nfs3svc_encode_getattrres(struct svc_rqst *, __be32 *);
 int nfs3svc_encode_wccstat(struct svc_rqst *, __be32 *);
 int nfs3svc_encode_diropres(struct svc_rqst *, __be32 *);
 int nfs3svc_encode_accessres(struct svc_rqst *, __be32 *);



^ permalink raw reply related	[flat|nested] 58+ messages in thread

* [PATCH v1 03/42] NFSD: Update the NFSv3 ACCESS3res encoder to use struct xdr_stream
  2021-03-01 15:15 [PATCH v1 00/42] NFSv2/3 XDR encoder overhaul Chuck Lever
  2021-03-01 15:15 ` [PATCH v1 01/42] NFSD: Extract the svcxdr_init_encode() helper Chuck Lever
  2021-03-01 15:15 ` [PATCH v1 02/42] NFSD: Update the GETATTR3res encoder to use struct xdr_stream Chuck Lever
@ 2021-03-01 15:15 ` Chuck Lever
  2021-03-01 15:15 ` [PATCH v1 04/42] NFSD: Update the NFSv3 LOOKUP3res " Chuck Lever
                   ` (38 subsequent siblings)
  41 siblings, 0 replies; 58+ messages in thread
From: Chuck Lever @ 2021-03-01 15:15 UTC (permalink / raw)
  To: linux-nfs

Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
---
 fs/nfsd/nfs3xdr.c |   50 +++++++++++++++++++++++++++++++++++++++++++++-----
 fs/nfsd/vfs.h     |    2 +-
 2 files changed, 46 insertions(+), 6 deletions(-)

diff --git a/fs/nfsd/nfs3xdr.c b/fs/nfsd/nfs3xdr.c
index 75739861d235..9d6c989df6d8 100644
--- a/fs/nfsd/nfs3xdr.c
+++ b/fs/nfsd/nfs3xdr.c
@@ -383,6 +383,35 @@ encode_saved_post_attr(struct svc_rqst *rqstp, __be32 *p, struct svc_fh *fhp)
 	return encode_fattr3(rqstp, p, fhp, &fhp->fh_post_attr);
 }
 
+static bool
+svcxdr_encode_post_op_attr(struct svc_rqst *rqstp, struct xdr_stream *xdr,
+			   const struct svc_fh *fhp)
+{
+	struct dentry *dentry = fhp->fh_dentry;
+	struct kstat stat;
+
+	/*
+	 * The inode may be NULL if the call failed because of a
+	 * stale file handle. In this case, no attributes are
+	 * returned.
+	 */
+	if (fhp->fh_no_wcc || !dentry || !d_really_is_positive(dentry))
+		goto no_post_op_attrs;
+	if (fh_getattr(fhp, &stat) != nfs_ok)
+		goto no_post_op_attrs;
+
+	if (xdr_stream_encode_item_present(xdr) < 0)
+		return false;
+	lease_get_mtime(d_inode(dentry), &stat.mtime);
+	if (!svcxdr_encode_fattr3(rqstp, xdr, fhp, &stat))
+		return false;
+
+	return true;
+
+no_post_op_attrs:
+	return xdr_stream_encode_item_absent(xdr) > 0;
+}
+
 /*
  * Encode post-operation attributes.
  * The inode may be NULL if the call failed because of a stale file
@@ -835,13 +864,24 @@ nfs3svc_encode_diropres(struct svc_rqst *rqstp, __be32 *p)
 int
 nfs3svc_encode_accessres(struct svc_rqst *rqstp, __be32 *p)
 {
+	struct xdr_stream *xdr = &rqstp->rq_res_stream;
 	struct nfsd3_accessres *resp = rqstp->rq_resp;
 
-	*p++ = resp->status;
-	p = encode_post_op_attr(rqstp, p, &resp->fh);
-	if (resp->status == 0)
-		*p++ = htonl(resp->access);
-	return xdr_ressize_check(rqstp, p);
+	if (!svcxdr_encode_nfsstat3(xdr, resp->status))
+		return 0;
+	switch (resp->status) {
+	case nfs_ok:
+		if (!svcxdr_encode_post_op_attr(rqstp, xdr, &resp->fh))
+			return 0;
+		if (xdr_stream_encode_u32(xdr, resp->access) < 0)
+			return 0;
+		break;
+	default:
+		if (!svcxdr_encode_post_op_attr(rqstp, xdr, &resp->fh))
+			return 0;
+	}
+
+	return 1;
 }
 
 /* READLINK */
diff --git a/fs/nfsd/vfs.h b/fs/nfsd/vfs.h
index a2442ebe5acf..b21b76e6b9a8 100644
--- a/fs/nfsd/vfs.h
+++ b/fs/nfsd/vfs.h
@@ -152,7 +152,7 @@ static inline void fh_drop_write(struct svc_fh *fh)
 	}
 }
 
-static inline __be32 fh_getattr(struct svc_fh *fh, struct kstat *stat)
+static inline __be32 fh_getattr(const struct svc_fh *fh, struct kstat *stat)
 {
 	struct path p = {.mnt = fh->fh_export->ex_path.mnt,
 			 .dentry = fh->fh_dentry};



^ permalink raw reply related	[flat|nested] 58+ messages in thread

* [PATCH v1 04/42] NFSD: Update the NFSv3 LOOKUP3res encoder to use struct xdr_stream
  2021-03-01 15:15 [PATCH v1 00/42] NFSv2/3 XDR encoder overhaul Chuck Lever
                   ` (2 preceding siblings ...)
  2021-03-01 15:15 ` [PATCH v1 03/42] NFSD: Update the NFSv3 ACCESS3res " Chuck Lever
@ 2021-03-01 15:15 ` Chuck Lever
  2021-03-01 15:15 ` [PATCH v1 05/42] NFSD: Update the NFSv3 wccstat result " Chuck Lever
                   ` (37 subsequent siblings)
  41 siblings, 0 replies; 58+ messages in thread
From: Chuck Lever @ 2021-03-01 15:15 UTC (permalink / raw)
  To: linux-nfs

Also, clean up: Rename the encoder function to match the name of
the result structure in RFC 1813, consistent with other encoder
function names in nfs3xdr.c. "diropres" is an NFSv2 thingie.

Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
---
 fs/nfsd/nfs3proc.c |    2 +-
 fs/nfsd/nfs3xdr.c  |   43 +++++++++++++++++++++++++++++++++++--------
 fs/nfsd/xdr3.h     |    2 +-
 3 files changed, 37 insertions(+), 10 deletions(-)

diff --git a/fs/nfsd/nfs3proc.c b/fs/nfsd/nfs3proc.c
index 76a84481d526..49b018afc6ea 100644
--- a/fs/nfsd/nfs3proc.c
+++ b/fs/nfsd/nfs3proc.c
@@ -758,7 +758,7 @@ static const struct svc_procedure nfsd_procedures3[22] = {
 	[NFS3PROC_LOOKUP] = {
 		.pc_func = nfsd3_proc_lookup,
 		.pc_decode = nfs3svc_decode_diropargs,
-		.pc_encode = nfs3svc_encode_diropres,
+		.pc_encode = nfs3svc_encode_lookupres,
 		.pc_release = nfs3svc_release_fhandle2,
 		.pc_argsize = sizeof(struct nfsd3_diropargs),
 		.pc_ressize = sizeof(struct nfsd3_diropres),
diff --git a/fs/nfsd/nfs3xdr.c b/fs/nfsd/nfs3xdr.c
index 9d6c989df6d8..2bb998b3834b 100644
--- a/fs/nfsd/nfs3xdr.c
+++ b/fs/nfsd/nfs3xdr.c
@@ -104,6 +104,23 @@ svcxdr_encode_nfsstat3(struct xdr_stream *xdr, __be32 status)
 	return true;
 }
 
+static bool
+svcxdr_encode_nfs_fh3(struct xdr_stream *xdr, const struct svc_fh *fhp)
+{
+	u32 size = fhp->fh_handle.fh_size;
+	__be32 *p;
+
+	p = xdr_reserve_space(xdr, XDR_UNIT + size);
+	if (!p)
+		return false;
+	*p++ = cpu_to_be32(size);
+	if (size)
+		p[XDR_QUADLEN(size) - 1] = 0;
+	memcpy(p, &fhp->fh_handle.fh_base, size);
+
+	return true;
+}
+
 static __be32 *
 encode_fh(__be32 *p, struct svc_fh *fhp)
 {
@@ -846,18 +863,28 @@ nfs3svc_encode_wccstat(struct svc_rqst *rqstp, __be32 *p)
 }
 
 /* LOOKUP */
-int
-nfs3svc_encode_diropres(struct svc_rqst *rqstp, __be32 *p)
+int nfs3svc_encode_lookupres(struct svc_rqst *rqstp, __be32 *p)
 {
+	struct xdr_stream *xdr = &rqstp->rq_res_stream;
 	struct nfsd3_diropres *resp = rqstp->rq_resp;
 
-	*p++ = resp->status;
-	if (resp->status == 0) {
-		p = encode_fh(p, &resp->fh);
-		p = encode_post_op_attr(rqstp, p, &resp->fh);
+	if (!svcxdr_encode_nfsstat3(xdr, resp->status))
+		return 0;
+	switch (resp->status) {
+	case nfs_ok:
+		if (!svcxdr_encode_nfs_fh3(xdr, &resp->fh))
+			return 0;
+		if (!svcxdr_encode_post_op_attr(rqstp, xdr, &resp->fh))
+			return 0;
+		if (!svcxdr_encode_post_op_attr(rqstp, xdr, &resp->dirfh))
+			return 0;
+		break;
+	default:
+		if (!svcxdr_encode_post_op_attr(rqstp, xdr, &resp->dirfh))
+			return 0;
 	}
-	p = encode_post_op_attr(rqstp, p, &resp->dirfh);
-	return xdr_ressize_check(rqstp, p);
+
+	return 1;
 }
 
 /* ACCESS */
diff --git a/fs/nfsd/xdr3.h b/fs/nfsd/xdr3.h
index 0822981c61b9..7db4ee17aa20 100644
--- a/fs/nfsd/xdr3.h
+++ b/fs/nfsd/xdr3.h
@@ -282,7 +282,7 @@ int nfs3svc_decode_readdirplusargs(struct svc_rqst *, __be32 *);
 int nfs3svc_decode_commitargs(struct svc_rqst *, __be32 *);
 int nfs3svc_encode_getattrres(struct svc_rqst *, __be32 *);
 int nfs3svc_encode_wccstat(struct svc_rqst *, __be32 *);
-int nfs3svc_encode_diropres(struct svc_rqst *, __be32 *);
+int nfs3svc_encode_lookupres(struct svc_rqst *, __be32 *);
 int nfs3svc_encode_accessres(struct svc_rqst *, __be32 *);
 int nfs3svc_encode_readlinkres(struct svc_rqst *, __be32 *);
 int nfs3svc_encode_readres(struct svc_rqst *, __be32 *);



^ permalink raw reply related	[flat|nested] 58+ messages in thread

* [PATCH v1 05/42] NFSD: Update the NFSv3 wccstat result encoder to use struct xdr_stream
  2021-03-01 15:15 [PATCH v1 00/42] NFSv2/3 XDR encoder overhaul Chuck Lever
                   ` (3 preceding siblings ...)
  2021-03-01 15:15 ` [PATCH v1 04/42] NFSD: Update the NFSv3 LOOKUP3res " Chuck Lever
@ 2021-03-01 15:15 ` Chuck Lever
  2021-03-01 15:15 ` [PATCH v1 06/42] NFSD: Update the NFSv3 READLINK3res " Chuck Lever
                   ` (36 subsequent siblings)
  41 siblings, 0 replies; 58+ messages in thread
From: Chuck Lever @ 2021-03-01 15:15 UTC (permalink / raw)
  To: linux-nfs

Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
---
 fs/nfsd/nfs3xdr.c |   68 +++++++++++++++++++++++++++++++++++++++++++++++++++--
 1 file changed, 65 insertions(+), 3 deletions(-)

diff --git a/fs/nfsd/nfs3xdr.c b/fs/nfsd/nfs3xdr.c
index 2bb998b3834b..29b923a497f4 100644
--- a/fs/nfsd/nfs3xdr.c
+++ b/fs/nfsd/nfs3xdr.c
@@ -400,6 +400,35 @@ encode_saved_post_attr(struct svc_rqst *rqstp, __be32 *p, struct svc_fh *fhp)
 	return encode_fattr3(rqstp, p, fhp, &fhp->fh_post_attr);
 }
 
+static bool
+svcxdr_encode_wcc_attr(struct xdr_stream *xdr, const struct svc_fh *fhp)
+{
+	__be32 *p;
+
+	p = xdr_reserve_space(xdr, XDR_UNIT * 6);
+	if (!p)
+		return false;
+	p = xdr_encode_hyper(p, (u64)fhp->fh_pre_size);
+	p = encode_nfstime3(p, &fhp->fh_pre_mtime);
+	encode_nfstime3(p, &fhp->fh_pre_ctime);
+
+	return true;
+}
+
+static bool
+svcxdr_encode_pre_op_attr(struct xdr_stream *xdr, const struct svc_fh *fhp)
+{
+	if (!fhp->fh_pre_saved) {
+		if (xdr_stream_encode_item_absent(xdr) < 0)
+			return false;
+		return true;
+	}
+
+	if (xdr_stream_encode_item_present(xdr) < 0)
+		return false;
+	return svcxdr_encode_wcc_attr(xdr, fhp);
+}
+
 static bool
 svcxdr_encode_post_op_attr(struct svc_rqst *rqstp, struct xdr_stream *xdr,
 			   const struct svc_fh *fhp)
@@ -460,6 +489,39 @@ nfs3svc_encode_post_op_attr(struct svc_rqst *rqstp, __be32 *p, struct svc_fh *fh
 	return encode_post_op_attr(rqstp, p, fhp);
 }
 
+/*
+ * Encode weak cache consistency data
+ */
+static bool
+svcxdr_encode_wcc_data(struct svc_rqst *rqstp, struct xdr_stream *xdr,
+		       const struct svc_fh *fhp)
+{
+	struct dentry *dentry = fhp->fh_dentry;
+
+	if (!dentry || !d_really_is_positive(dentry) || !fhp->fh_post_saved)
+		goto neither;
+
+	/* before */
+	if (!svcxdr_encode_pre_op_attr(xdr, fhp))
+		return false;
+
+	/* after */
+	if (xdr_stream_encode_item_present(xdr) < 0)
+		return false;
+	if (!svcxdr_encode_fattr3(rqstp, xdr, fhp, &fhp->fh_post_attr))
+		return false;
+
+	return true;
+
+neither:
+	if (xdr_stream_encode_item_absent(xdr) < 0)
+		return false;
+	if (!svcxdr_encode_post_op_attr(rqstp, xdr, fhp))
+		return false;
+
+	return true;
+}
+
 /*
  * Enocde weak cache consistency data
  */
@@ -855,11 +917,11 @@ nfs3svc_encode_getattrres(struct svc_rqst *rqstp, __be32 *p)
 int
 nfs3svc_encode_wccstat(struct svc_rqst *rqstp, __be32 *p)
 {
+	struct xdr_stream *xdr = &rqstp->rq_res_stream;
 	struct nfsd3_attrstat *resp = rqstp->rq_resp;
 
-	*p++ = resp->status;
-	p = encode_wcc_data(rqstp, p, &resp->fh);
-	return xdr_ressize_check(rqstp, p);
+	return svcxdr_encode_nfsstat3(xdr, resp->status) &&
+		svcxdr_encode_wcc_data(rqstp, xdr, &resp->fh);
 }
 
 /* LOOKUP */



^ permalink raw reply related	[flat|nested] 58+ messages in thread

* [PATCH v1 06/42] NFSD: Update the NFSv3 READLINK3res encoder to use struct xdr_stream
  2021-03-01 15:15 [PATCH v1 00/42] NFSv2/3 XDR encoder overhaul Chuck Lever
                   ` (4 preceding siblings ...)
  2021-03-01 15:15 ` [PATCH v1 05/42] NFSD: Update the NFSv3 wccstat result " Chuck Lever
@ 2021-03-01 15:15 ` Chuck Lever
  2021-03-01 15:16 ` [PATCH v1 07/42] NFSD: Update the NFSv3 READ3res encode " Chuck Lever
                   ` (35 subsequent siblings)
  41 siblings, 0 replies; 58+ messages in thread
From: Chuck Lever @ 2021-03-01 15:15 UTC (permalink / raw)
  To: linux-nfs

Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
---
 fs/nfsd/nfs3proc.c |    5 +++--
 fs/nfsd/nfs3xdr.c  |   34 ++++++++++++++++++----------------
 fs/nfsd/xdr3.h     |    1 +
 3 files changed, 22 insertions(+), 18 deletions(-)

diff --git a/fs/nfsd/nfs3proc.c b/fs/nfsd/nfs3proc.c
index 49b018afc6ea..e55a1d14ede2 100644
--- a/fs/nfsd/nfs3proc.c
+++ b/fs/nfsd/nfs3proc.c
@@ -126,14 +126,15 @@ nfsd3_proc_readlink(struct svc_rqst *rqstp)
 {
 	struct nfsd_fhandle *argp = rqstp->rq_argp;
 	struct nfsd3_readlinkres *resp = rqstp->rq_resp;
-	char *buffer = page_address(*(rqstp->rq_next_page++));
 
 	dprintk("nfsd: READLINK(3) %s\n", SVCFH_fmt(&argp->fh));
 
 	/* Read the symlink. */
 	fh_copy(&resp->fh, &argp->fh);
 	resp->len = NFS3_MAXPATHLEN;
-	resp->status = nfsd_readlink(rqstp, &resp->fh, buffer, &resp->len);
+	resp->pages = rqstp->rq_next_page++;
+	resp->status = nfsd_readlink(rqstp, &resp->fh,
+				     page_address(*resp->pages), &resp->len);
 	return rpc_success;
 }
 
diff --git a/fs/nfsd/nfs3xdr.c b/fs/nfsd/nfs3xdr.c
index 29b923a497f4..352691c3e246 100644
--- a/fs/nfsd/nfs3xdr.c
+++ b/fs/nfsd/nfs3xdr.c
@@ -977,26 +977,28 @@ nfs3svc_encode_accessres(struct svc_rqst *rqstp, __be32 *p)
 int
 nfs3svc_encode_readlinkres(struct svc_rqst *rqstp, __be32 *p)
 {
+	struct xdr_stream *xdr = &rqstp->rq_res_stream;
 	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);
-	if (resp->status == 0) {
-		*p++ = htonl(resp->len);
-		xdr_ressize_check(rqstp, p);
-		rqstp->rq_res.page_len = resp->len;
-		if (resp->len & 3) {
-			/* need to pad the tail */
-			rqstp->rq_res.tail[0].iov_base = 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))
+	if (!svcxdr_encode_nfsstat3(xdr, resp->status))
+		return 0;
+	switch (resp->status) {
+	case nfs_ok:
+		if (!svcxdr_encode_post_op_attr(rqstp, xdr, &resp->fh))
 			return 0;
-		return 1;
-	} else
-		return xdr_ressize_check(rqstp, p);
+		if (xdr_stream_encode_u32(xdr, resp->len) < 0)
+			return 0;
+		xdr_write_pages(xdr, resp->pages, 0, resp->len);
+		if (svc_encode_result_payload(rqstp, head->iov_len, resp->len) < 0)
+			return 0;
+		break;
+	default:
+		if (!svcxdr_encode_post_op_attr(rqstp, xdr, &resp->fh))
+			return 0;
+	}
+
+	return 1;
 }
 
 /* READ */
diff --git a/fs/nfsd/xdr3.h b/fs/nfsd/xdr3.h
index 7db4ee17aa20..1d633c5d5fa2 100644
--- a/fs/nfsd/xdr3.h
+++ b/fs/nfsd/xdr3.h
@@ -137,6 +137,7 @@ struct nfsd3_readlinkres {
 	__be32			status;
 	struct svc_fh		fh;
 	__u32			len;
+	struct page		**pages;
 };
 
 struct nfsd3_readres {



^ permalink raw reply related	[flat|nested] 58+ messages in thread

* [PATCH v1 07/42] NFSD: Update the NFSv3 READ3res encode to use struct xdr_stream
  2021-03-01 15:15 [PATCH v1 00/42] NFSv2/3 XDR encoder overhaul Chuck Lever
                   ` (5 preceding siblings ...)
  2021-03-01 15:15 ` [PATCH v1 06/42] NFSD: Update the NFSv3 READLINK3res " Chuck Lever
@ 2021-03-01 15:16 ` Chuck Lever
  2021-03-01 15:16 ` [PATCH v1 08/42] NFSD: Update the NFSv3 WRITE3res encoder " Chuck Lever
                   ` (34 subsequent siblings)
  41 siblings, 0 replies; 58+ messages in thread
From: Chuck Lever @ 2021-03-01 15:16 UTC (permalink / raw)
  To: linux-nfs

Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
---
 fs/nfsd/nfs3proc.c         |    1 +
 fs/nfsd/nfs3xdr.c          |   43 +++++++++++++++++++++++--------------------
 fs/nfsd/xdr3.h             |    1 +
 include/linux/sunrpc/xdr.h |   20 ++++++++++++++++++++
 4 files changed, 45 insertions(+), 20 deletions(-)

diff --git a/fs/nfsd/nfs3proc.c b/fs/nfsd/nfs3proc.c
index e55a1d14ede2..93d196752f87 100644
--- a/fs/nfsd/nfs3proc.c
+++ b/fs/nfsd/nfs3proc.c
@@ -159,6 +159,7 @@ nfsd3_proc_read(struct svc_rqst *rqstp)
 
 	v = 0;
 	len = argp->count;
+	resp->pages = rqstp->rq_next_page;
 	while (len > 0) {
 		struct page *page = *(rqstp->rq_next_page++);
 
diff --git a/fs/nfsd/nfs3xdr.c b/fs/nfsd/nfs3xdr.c
index 352691c3e246..859cc6c51c1a 100644
--- a/fs/nfsd/nfs3xdr.c
+++ b/fs/nfsd/nfs3xdr.c
@@ -1005,30 +1005,33 @@ nfs3svc_encode_readlinkres(struct svc_rqst *rqstp, __be32 *p)
 int
 nfs3svc_encode_readres(struct svc_rqst *rqstp, __be32 *p)
 {
+	struct xdr_stream *xdr = &rqstp->rq_res_stream;
 	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);
-	if (resp->status == 0) {
-		*p++ = htonl(resp->count);
-		*p++ = htonl(resp->eof);
-		*p++ = htonl(resp->count);	/* xdr opaque count */
-		xdr_ressize_check(rqstp, p);
-		/* now update rqstp->rq_res to reflect data as well */
-		rqstp->rq_res.page_len = resp->count;
-		if (resp->count & 3) {
-			/* need to pad the tail */
-			rqstp->rq_res.tail[0].iov_base = 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))
+	if (!svcxdr_encode_nfsstat3(xdr, resp->status))
+		return 0;
+	switch (resp->status) {
+	case nfs_ok:
+		if (!svcxdr_encode_post_op_attr(rqstp, xdr, &resp->fh))
 			return 0;
-		return 1;
-	} else
-		return xdr_ressize_check(rqstp, p);
+		if (xdr_stream_encode_u32(xdr, resp->count) < 0)
+			return 0;
+		if (xdr_stream_encode_bool(xdr, resp->eof) < 0)
+			return 0;
+		if (xdr_stream_encode_u32(xdr, resp->count) < 0)
+			return 0;
+		xdr_write_pages(xdr, resp->pages, rqstp->rq_res.page_base,
+				resp->count);
+		if (svc_encode_result_payload(rqstp, head->iov_len, resp->count) < 0)
+			return 0;
+		break;
+	default:
+		if (!svcxdr_encode_post_op_attr(rqstp, xdr, &resp->fh))
+			return 0;
+	}
+
+	return 1;
 }
 
 /* WRITE */
diff --git a/fs/nfsd/xdr3.h b/fs/nfsd/xdr3.h
index 1d633c5d5fa2..8073350418ae 100644
--- a/fs/nfsd/xdr3.h
+++ b/fs/nfsd/xdr3.h
@@ -145,6 +145,7 @@ struct nfsd3_readres {
 	struct svc_fh		fh;
 	unsigned long		count;
 	__u32			eof;
+	struct page		**pages;
 };
 
 struct nfsd3_writeres {
diff --git a/include/linux/sunrpc/xdr.h b/include/linux/sunrpc/xdr.h
index 2bc75c167f00..9dda7171b7b4 100644
--- a/include/linux/sunrpc/xdr.h
+++ b/include/linux/sunrpc/xdr.h
@@ -394,6 +394,26 @@ static inline int xdr_stream_encode_item_absent(struct xdr_stream *xdr)
 	return len;
 }
 
+/**
+ * xdr_stream_encode_bool - Encode a "not present" list item
+ * @xdr: pointer to xdr_stream
+ * @n: boolean value to encode
+ *
+ * Return values:
+ *   On success, returns length in bytes of XDR buffer consumed
+ *   %-EMSGSIZE on XDR buffer overflow
+ */
+static inline int xdr_stream_encode_bool(struct xdr_stream *xdr, __u32 n)
+{
+	const size_t len = XDR_UNIT;
+	__be32 *p = xdr_reserve_space(xdr, len);
+
+	if (unlikely(!p))
+		return -EMSGSIZE;
+	*p = n ? xdr_one : xdr_zero;
+	return len;
+}
+
 /**
  * xdr_stream_encode_u32 - Encode a 32-bit integer
  * @xdr: pointer to xdr_stream



^ permalink raw reply related	[flat|nested] 58+ messages in thread

* [PATCH v1 08/42] NFSD: Update the NFSv3 WRITE3res encoder to use struct xdr_stream
  2021-03-01 15:15 [PATCH v1 00/42] NFSv2/3 XDR encoder overhaul Chuck Lever
                   ` (6 preceding siblings ...)
  2021-03-01 15:16 ` [PATCH v1 07/42] NFSD: Update the NFSv3 READ3res encode " Chuck Lever
@ 2021-03-01 15:16 ` Chuck Lever
  2021-03-01 15:16 ` [PATCH v1 09/42] NFSD: Update the NFSv3 CREATE family of encoders " Chuck Lever
                   ` (33 subsequent siblings)
  41 siblings, 0 replies; 58+ messages in thread
From: Chuck Lever @ 2021-03-01 15:16 UTC (permalink / raw)
  To: linux-nfs

Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
---
 fs/nfsd/nfs3xdr.c |   40 ++++++++++++++++++++++++++++++++--------
 1 file changed, 32 insertions(+), 8 deletions(-)

diff --git a/fs/nfsd/nfs3xdr.c b/fs/nfsd/nfs3xdr.c
index 859cc6c51c1a..0191cbfc486b 100644
--- a/fs/nfsd/nfs3xdr.c
+++ b/fs/nfsd/nfs3xdr.c
@@ -131,6 +131,19 @@ encode_fh(__be32 *p, struct svc_fh *fhp)
 	return p + XDR_QUADLEN(size);
 }
 
+static bool
+svcxdr_encode_writeverf3(struct xdr_stream *xdr, const __be32 *verf)
+{
+	__be32 *p;
+
+	p = xdr_reserve_space(xdr, NFS3_WRITEVERFSIZE);
+	if (!p)
+		return false;
+	memcpy(p, verf, NFS3_WRITEVERFSIZE);
+
+	return true;
+}
+
 static bool
 svcxdr_decode_filename3(struct xdr_stream *xdr, char **name, unsigned int *len)
 {
@@ -1038,17 +1051,28 @@ nfs3svc_encode_readres(struct svc_rqst *rqstp, __be32 *p)
 int
 nfs3svc_encode_writeres(struct svc_rqst *rqstp, __be32 *p)
 {
+	struct xdr_stream *xdr = &rqstp->rq_res_stream;
 	struct nfsd3_writeres *resp = rqstp->rq_resp;
 
-	*p++ = resp->status;
-	p = encode_wcc_data(rqstp, p, &resp->fh);
-	if (resp->status == 0) {
-		*p++ = htonl(resp->count);
-		*p++ = htonl(resp->committed);
-		*p++ = resp->verf[0];
-		*p++ = resp->verf[1];
+	if (!svcxdr_encode_nfsstat3(xdr, resp->status))
+		return 0;
+	switch (resp->status) {
+	case nfs_ok:
+		if (!svcxdr_encode_wcc_data(rqstp, xdr, &resp->fh))
+			return 0;
+		if (xdr_stream_encode_u32(xdr, resp->count) < 0)
+			return 0;
+		if (xdr_stream_encode_u32(xdr, resp->committed) < 0)
+			return 0;
+		if (!svcxdr_encode_writeverf3(xdr, resp->verf))
+			return 0;
+		break;
+	default:
+		if (!svcxdr_encode_wcc_data(rqstp, xdr, &resp->fh))
+			return 0;
 	}
-	return xdr_ressize_check(rqstp, p);
+
+	return 1;
 }
 
 /* CREATE, MKDIR, SYMLINK, MKNOD */



^ permalink raw reply related	[flat|nested] 58+ messages in thread

* [PATCH v1 09/42] NFSD: Update the NFSv3 CREATE family of encoders to use struct xdr_stream
  2021-03-01 15:15 [PATCH v1 00/42] NFSv2/3 XDR encoder overhaul Chuck Lever
                   ` (7 preceding siblings ...)
  2021-03-01 15:16 ` [PATCH v1 08/42] NFSD: Update the NFSv3 WRITE3res encoder " Chuck Lever
@ 2021-03-01 15:16 ` Chuck Lever
  2021-03-01 15:16 ` [PATCH v1 10/42] NFSD: Update the NFSv3 RENAMEv3res encoder " Chuck Lever
                   ` (32 subsequent siblings)
  41 siblings, 0 replies; 58+ messages in thread
From: Chuck Lever @ 2021-03-01 15:16 UTC (permalink / raw)
  To: linux-nfs

Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
---
 fs/nfsd/nfs3xdr.c |   35 ++++++++++++++++++++++++++++-------
 1 file changed, 28 insertions(+), 7 deletions(-)

diff --git a/fs/nfsd/nfs3xdr.c b/fs/nfsd/nfs3xdr.c
index 0191cbfc486b..052376a65f72 100644
--- a/fs/nfsd/nfs3xdr.c
+++ b/fs/nfsd/nfs3xdr.c
@@ -121,6 +121,17 @@ svcxdr_encode_nfs_fh3(struct xdr_stream *xdr, const struct svc_fh *fhp)
 	return true;
 }
 
+static bool
+svcxdr_encode_post_op_fh3(struct xdr_stream *xdr, const struct svc_fh *fhp)
+{
+	if (xdr_stream_encode_item_present(xdr) < 0)
+		return false;
+	if (!svcxdr_encode_nfs_fh3(xdr, fhp))
+		return false;
+
+	return true;
+}
+
 static __be32 *
 encode_fh(__be32 *p, struct svc_fh *fhp)
 {
@@ -1079,16 +1090,26 @@ nfs3svc_encode_writeres(struct svc_rqst *rqstp, __be32 *p)
 int
 nfs3svc_encode_createres(struct svc_rqst *rqstp, __be32 *p)
 {
+	struct xdr_stream *xdr = &rqstp->rq_res_stream;
 	struct nfsd3_diropres *resp = rqstp->rq_resp;
 
-	*p++ = resp->status;
-	if (resp->status == 0) {
-		*p++ = xdr_one;
-		p = encode_fh(p, &resp->fh);
-		p = encode_post_op_attr(rqstp, p, &resp->fh);
+	if (!svcxdr_encode_nfsstat3(xdr, resp->status))
+		return 0;
+	switch (resp->status) {
+	case nfs_ok:
+		if (!svcxdr_encode_post_op_fh3(xdr, &resp->fh))
+			return 0;
+		if (!svcxdr_encode_post_op_attr(rqstp, xdr, &resp->fh))
+			return 0;
+		if (!svcxdr_encode_wcc_data(rqstp, xdr, &resp->dirfh))
+			return 0;
+		break;
+	default:
+		if (!svcxdr_encode_wcc_data(rqstp, xdr, &resp->dirfh))
+			return 0;
 	}
-	p = encode_wcc_data(rqstp, p, &resp->dirfh);
-	return xdr_ressize_check(rqstp, p);
+
+	return 1;
 }
 
 /* RENAME */



^ permalink raw reply related	[flat|nested] 58+ messages in thread

* [PATCH v1 10/42] NFSD: Update the NFSv3 RENAMEv3res encoder to use struct xdr_stream
  2021-03-01 15:15 [PATCH v1 00/42] NFSv2/3 XDR encoder overhaul Chuck Lever
                   ` (8 preceding siblings ...)
  2021-03-01 15:16 ` [PATCH v1 09/42] NFSD: Update the NFSv3 CREATE family of encoders " Chuck Lever
@ 2021-03-01 15:16 ` Chuck Lever
  2021-03-01 15:16 ` [PATCH v1 11/42] NFSD: Update the NFSv3 LINK3res " Chuck Lever
                   ` (31 subsequent siblings)
  41 siblings, 0 replies; 58+ messages in thread
From: Chuck Lever @ 2021-03-01 15:16 UTC (permalink / raw)
  To: linux-nfs

Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
---
 fs/nfsd/nfs3xdr.c |    8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/fs/nfsd/nfs3xdr.c b/fs/nfsd/nfs3xdr.c
index 052376a65f72..1d52a69562b8 100644
--- a/fs/nfsd/nfs3xdr.c
+++ b/fs/nfsd/nfs3xdr.c
@@ -1116,12 +1116,12 @@ nfs3svc_encode_createres(struct svc_rqst *rqstp, __be32 *p)
 int
 nfs3svc_encode_renameres(struct svc_rqst *rqstp, __be32 *p)
 {
+	struct xdr_stream *xdr = &rqstp->rq_res_stream;
 	struct nfsd3_renameres *resp = rqstp->rq_resp;
 
-	*p++ = resp->status;
-	p = encode_wcc_data(rqstp, p, &resp->ffh);
-	p = encode_wcc_data(rqstp, p, &resp->tfh);
-	return xdr_ressize_check(rqstp, p);
+	return svcxdr_encode_nfsstat3(xdr, resp->status) &&
+		svcxdr_encode_wcc_data(rqstp, xdr, &resp->ffh) &&
+		svcxdr_encode_wcc_data(rqstp, xdr, &resp->tfh);
 }
 
 /* LINK */



^ permalink raw reply related	[flat|nested] 58+ messages in thread

* [PATCH v1 11/42] NFSD: Update the NFSv3 LINK3res encoder to use struct xdr_stream
  2021-03-01 15:15 [PATCH v1 00/42] NFSv2/3 XDR encoder overhaul Chuck Lever
                   ` (9 preceding siblings ...)
  2021-03-01 15:16 ` [PATCH v1 10/42] NFSD: Update the NFSv3 RENAMEv3res encoder " Chuck Lever
@ 2021-03-01 15:16 ` Chuck Lever
  2021-03-01 15:16 ` [PATCH v1 12/42] NFSD: Update the NFSv3 FSSTAT3res " Chuck Lever
                   ` (30 subsequent siblings)
  41 siblings, 0 replies; 58+ messages in thread
From: Chuck Lever @ 2021-03-01 15:16 UTC (permalink / raw)
  To: linux-nfs

Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
---
 fs/nfsd/nfs3xdr.c |    8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/fs/nfsd/nfs3xdr.c b/fs/nfsd/nfs3xdr.c
index 1d52a69562b8..e159e4557428 100644
--- a/fs/nfsd/nfs3xdr.c
+++ b/fs/nfsd/nfs3xdr.c
@@ -1128,12 +1128,12 @@ nfs3svc_encode_renameres(struct svc_rqst *rqstp, __be32 *p)
 int
 nfs3svc_encode_linkres(struct svc_rqst *rqstp, __be32 *p)
 {
+	struct xdr_stream *xdr = &rqstp->rq_res_stream;
 	struct nfsd3_linkres *resp = rqstp->rq_resp;
 
-	*p++ = resp->status;
-	p = encode_post_op_attr(rqstp, p, &resp->fh);
-	p = encode_wcc_data(rqstp, p, &resp->tfh);
-	return xdr_ressize_check(rqstp, p);
+	return svcxdr_encode_nfsstat3(xdr, resp->status) &&
+		svcxdr_encode_post_op_attr(rqstp, xdr, &resp->fh) &&
+		svcxdr_encode_wcc_data(rqstp, xdr, &resp->tfh);
 }
 
 /* READDIR */



^ permalink raw reply related	[flat|nested] 58+ messages in thread

* [PATCH v1 12/42] NFSD: Update the NFSv3 FSSTAT3res encoder to use struct xdr_stream
  2021-03-01 15:15 [PATCH v1 00/42] NFSv2/3 XDR encoder overhaul Chuck Lever
                   ` (10 preceding siblings ...)
  2021-03-01 15:16 ` [PATCH v1 11/42] NFSD: Update the NFSv3 LINK3res " Chuck Lever
@ 2021-03-01 15:16 ` Chuck Lever
  2021-03-02 20:45   ` J. Bruce Fields
  2021-03-01 15:16 ` [PATCH v1 13/42] NFSD: Update the NFSv3 FSINFO3res " Chuck Lever
                   ` (29 subsequent siblings)
  41 siblings, 1 reply; 58+ messages in thread
From: Chuck Lever @ 2021-03-01 15:16 UTC (permalink / raw)
  To: linux-nfs

Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
---
 fs/nfsd/nfs3xdr.c |   58 ++++++++++++++++++++++++++++++++++++++++-------------
 1 file changed, 44 insertions(+), 14 deletions(-)

diff --git a/fs/nfsd/nfs3xdr.c b/fs/nfsd/nfs3xdr.c
index e159e4557428..e4a569e7216d 100644
--- a/fs/nfsd/nfs3xdr.c
+++ b/fs/nfsd/nfs3xdr.c
@@ -17,6 +17,13 @@
 #define NFSDDBG_FACILITY		NFSDDBG_XDR
 
 
+/*
+ * Force construction of an empty post-op attr
+ */
+static const struct svc_fh nfs3svc_null_fh = {
+	.fh_no_wcc	= true,
+};
+
 /*
  * Mapping of S_IF* types to NFS file types
  */
@@ -1392,27 +1399,50 @@ nfs3svc_encode_entry_plus(void *cd, const char *name,
 	return encode_entry(cd, name, namlen, offset, ino, d_type, 1);
 }
 
+static bool
+svcxdr_encode_fsstat3resok(struct xdr_stream *xdr,
+			   const struct nfsd3_fsstatres *resp)
+{
+	const struct kstatfs *s = &resp->stats;
+	u64 bs = s->f_bsize;
+	__be32 *p;
+
+	p = xdr_reserve_space(xdr, XDR_UNIT * 13);
+	if (!p)
+		return false;
+	p = xdr_encode_hyper(p, bs * s->f_blocks);	/* total bytes */
+	p = xdr_encode_hyper(p, bs * s->f_bfree);	/* free bytes */
+	p = xdr_encode_hyper(p, bs * s->f_bavail);	/* user available bytes */
+	p = xdr_encode_hyper(p, s->f_files);		/* total inodes */
+	p = xdr_encode_hyper(p, s->f_ffree);		/* free inodes */
+	p = xdr_encode_hyper(p, s->f_ffree);		/* user available inodes */
+	*p = cpu_to_be32(resp->invarsec);		/* mean unchanged time */
+
+	return true;
+}
+
 /* FSSTAT */
 int
 nfs3svc_encode_fsstatres(struct svc_rqst *rqstp, __be32 *p)
 {
+	struct xdr_stream *xdr = &rqstp->rq_res_stream;
 	struct nfsd3_fsstatres *resp = rqstp->rq_resp;
-	struct kstatfs	*s = &resp->stats;
-	u64		bs = s->f_bsize;
 
-	*p++ = resp->status;
-	*p++ = xdr_zero;	/* no post_op_attr */
-
-	if (resp->status == 0) {
-		p = xdr_encode_hyper(p, bs * s->f_blocks);	/* total bytes */
-		p = xdr_encode_hyper(p, bs * s->f_bfree);	/* free bytes */
-		p = xdr_encode_hyper(p, bs * s->f_bavail);	/* user available bytes */
-		p = xdr_encode_hyper(p, s->f_files);	/* total inodes */
-		p = xdr_encode_hyper(p, s->f_ffree);	/* free inodes */
-		p = xdr_encode_hyper(p, s->f_ffree);	/* user available inodes */
-		*p++ = htonl(resp->invarsec);	/* mean unchanged time */
+	if (!svcxdr_encode_nfsstat3(xdr, resp->status))
+		return 0;
+	switch (resp->status) {
+	case nfs_ok:
+		if (!svcxdr_encode_post_op_attr(rqstp, xdr, &nfs3svc_null_fh))
+			return 0;
+		if (!svcxdr_encode_fsstat3resok(xdr, resp))
+			return 0;
+		break;
+	default:
+		if (!svcxdr_encode_post_op_attr(rqstp, xdr, &nfs3svc_null_fh))
+			return 0;
 	}
-	return xdr_ressize_check(rqstp, p);
+
+	return 1;
 }
 
 /* FSINFO */



^ permalink raw reply related	[flat|nested] 58+ messages in thread

* [PATCH v1 13/42] NFSD: Update the NFSv3 FSINFO3res encoder to use struct xdr_stream
  2021-03-01 15:15 [PATCH v1 00/42] NFSv2/3 XDR encoder overhaul Chuck Lever
                   ` (11 preceding siblings ...)
  2021-03-01 15:16 ` [PATCH v1 12/42] NFSD: Update the NFSv3 FSSTAT3res " Chuck Lever
@ 2021-03-01 15:16 ` Chuck Lever
  2021-03-01 15:16 ` [PATCH v1 14/42] NFSD: Update the NFSv3 PATHCONF3res " Chuck Lever
                   ` (28 subsequent siblings)
  41 siblings, 0 replies; 58+ messages in thread
From: Chuck Lever @ 2021-03-01 15:16 UTC (permalink / raw)
  To: linux-nfs

Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
---
 fs/nfsd/nfs3xdr.c |   62 +++++++++++++++++++++++++++++++++++++++--------------
 1 file changed, 46 insertions(+), 16 deletions(-)

diff --git a/fs/nfsd/nfs3xdr.c b/fs/nfsd/nfs3xdr.c
index e4a569e7216d..514f53ad7302 100644
--- a/fs/nfsd/nfs3xdr.c
+++ b/fs/nfsd/nfs3xdr.c
@@ -24,6 +24,15 @@ static const struct svc_fh nfs3svc_null_fh = {
 	.fh_no_wcc	= true,
 };
 
+/*
+ * time_delta. {1, 0} means the server is accurate only
+ * to the nearest second.
+ */
+static const struct timespec64 nfs3svc_time_delta = {
+	.tv_sec		= 1,
+	.tv_nsec	= 0,
+};
+
 /*
  * Mapping of S_IF* types to NFS file types
  */
@@ -1445,30 +1454,51 @@ nfs3svc_encode_fsstatres(struct svc_rqst *rqstp, __be32 *p)
 	return 1;
 }
 
+static bool
+svcxdr_encode_fsinfo3resok(struct xdr_stream *xdr,
+			   const struct nfsd3_fsinfores *resp)
+{
+	__be32 *p;
+
+	p = xdr_reserve_space(xdr, XDR_UNIT * 12);
+	if (!p)
+		return false;
+	*p++ = cpu_to_be32(resp->f_rtmax);
+	*p++ = cpu_to_be32(resp->f_rtpref);
+	*p++ = cpu_to_be32(resp->f_rtmult);
+	*p++ = cpu_to_be32(resp->f_wtmax);
+	*p++ = cpu_to_be32(resp->f_wtpref);
+	*p++ = cpu_to_be32(resp->f_wtmult);
+	*p++ = cpu_to_be32(resp->f_dtpref);
+	p = xdr_encode_hyper(p, resp->f_maxfilesize);
+	p = encode_nfstime3(p, &nfs3svc_time_delta);
+	*p = cpu_to_be32(resp->f_properties);
+
+	return true;
+}
+
 /* FSINFO */
 int
 nfs3svc_encode_fsinfores(struct svc_rqst *rqstp, __be32 *p)
 {
+	struct xdr_stream *xdr = &rqstp->rq_res_stream;
 	struct nfsd3_fsinfores *resp = rqstp->rq_resp;
 
-	*p++ = resp->status;
-	*p++ = xdr_zero;	/* no post_op_attr */
-
-	if (resp->status == 0) {
-		*p++ = htonl(resp->f_rtmax);
-		*p++ = htonl(resp->f_rtpref);
-		*p++ = htonl(resp->f_rtmult);
-		*p++ = htonl(resp->f_wtmax);
-		*p++ = htonl(resp->f_wtpref);
-		*p++ = htonl(resp->f_wtmult);
-		*p++ = htonl(resp->f_dtpref);
-		p = xdr_encode_hyper(p, resp->f_maxfilesize);
-		*p++ = xdr_one;
-		*p++ = xdr_zero;
-		*p++ = htonl(resp->f_properties);
+	if (!svcxdr_encode_nfsstat3(xdr, resp->status))
+		return 0;
+	switch (resp->status) {
+	case nfs_ok:
+		if (!svcxdr_encode_post_op_attr(rqstp, xdr, &nfs3svc_null_fh))
+			return 0;
+		if (!svcxdr_encode_fsinfo3resok(xdr, resp))
+			return 0;
+		break;
+	default:
+		if (!svcxdr_encode_post_op_attr(rqstp, xdr, &nfs3svc_null_fh))
+			return 0;
 	}
 
-	return xdr_ressize_check(rqstp, p);
+	return 1;
 }
 
 /* PATHCONF */



^ permalink raw reply related	[flat|nested] 58+ messages in thread

* [PATCH v1 14/42] NFSD: Update the NFSv3 PATHCONF3res encoder to use struct xdr_stream
  2021-03-01 15:15 [PATCH v1 00/42] NFSv2/3 XDR encoder overhaul Chuck Lever
                   ` (12 preceding siblings ...)
  2021-03-01 15:16 ` [PATCH v1 13/42] NFSD: Update the NFSv3 FSINFO3res " Chuck Lever
@ 2021-03-01 15:16 ` Chuck Lever
  2021-03-03  7:13   ` Christoph Hellwig
  2021-03-01 15:16 ` [PATCH v1 15/42] NFSD: Update the NFSv3 COMMIT3res " Chuck Lever
                   ` (27 subsequent siblings)
  41 siblings, 1 reply; 58+ messages in thread
From: Chuck Lever @ 2021-03-01 15:16 UTC (permalink / raw)
  To: linux-nfs

Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
---
 fs/nfsd/nfs3xdr.c |   44 +++++++++++++++++++++++++++++++++-----------
 1 file changed, 33 insertions(+), 11 deletions(-)

diff --git a/fs/nfsd/nfs3xdr.c b/fs/nfsd/nfs3xdr.c
index 514f53ad7302..8485ab50ff3f 100644
--- a/fs/nfsd/nfs3xdr.c
+++ b/fs/nfsd/nfs3xdr.c
@@ -1501,25 +1501,47 @@ nfs3svc_encode_fsinfores(struct svc_rqst *rqstp, __be32 *p)
 	return 1;
 }
 
+static bool
+svcxdr_encode_pathconf3resok(struct xdr_stream *xdr,
+			     const struct nfsd3_pathconfres *resp)
+{
+	__be32 *p;
+
+	p = xdr_reserve_space(xdr, XDR_UNIT * 6);
+	if (!p)
+		return false;
+	*p++ = cpu_to_be32(resp->p_link_max);
+	*p++ = cpu_to_be32(resp->p_name_max);
+	*p++ = resp->p_no_trunc ? xdr_one : xdr_zero;
+	*p++ = resp->p_chown_restricted ? xdr_one : xdr_zero;
+	*p++ = resp->p_case_insensitive ? xdr_one : xdr_zero;
+	*p = resp->p_case_preserving ? xdr_one : xdr_zero;
+
+	return true;
+}
+
 /* PATHCONF */
 int
 nfs3svc_encode_pathconfres(struct svc_rqst *rqstp, __be32 *p)
 {
+	struct xdr_stream *xdr = &rqstp->rq_res_stream;
 	struct nfsd3_pathconfres *resp = rqstp->rq_resp;
 
-	*p++ = resp->status;
-	*p++ = xdr_zero;	/* no post_op_attr */
-
-	if (resp->status == 0) {
-		*p++ = htonl(resp->p_link_max);
-		*p++ = htonl(resp->p_name_max);
-		*p++ = htonl(resp->p_no_trunc);
-		*p++ = htonl(resp->p_chown_restricted);
-		*p++ = htonl(resp->p_case_insensitive);
-		*p++ = htonl(resp->p_case_preserving);
+	if (!svcxdr_encode_nfsstat3(xdr, resp->status))
+		return 0;
+	switch (resp->status) {
+	case nfs_ok:
+		if (!svcxdr_encode_post_op_attr(rqstp, xdr, &nfs3svc_null_fh))
+			return 0;
+		if (!svcxdr_encode_pathconf3resok(xdr, resp))
+			return 0;
+		break;
+	default:
+		if (!svcxdr_encode_post_op_attr(rqstp, xdr, &nfs3svc_null_fh))
+			return 0;
 	}
 
-	return xdr_ressize_check(rqstp, p);
+	return 1;
 }
 
 /* COMMIT */



^ permalink raw reply related	[flat|nested] 58+ messages in thread

* [PATCH v1 15/42] NFSD: Update the NFSv3 COMMIT3res encoder to use struct xdr_stream
  2021-03-01 15:15 [PATCH v1 00/42] NFSv2/3 XDR encoder overhaul Chuck Lever
                   ` (13 preceding siblings ...)
  2021-03-01 15:16 ` [PATCH v1 14/42] NFSD: Update the NFSv3 PATHCONF3res " Chuck Lever
@ 2021-03-01 15:16 ` Chuck Lever
  2021-03-01 15:16 ` [PATCH v1 16/42] NFSD: Add a helper that encodes NFSv3 directory offset cookies Chuck Lever
                   ` (26 subsequent siblings)
  41 siblings, 0 replies; 58+ messages in thread
From: Chuck Lever @ 2021-03-01 15:16 UTC (permalink / raw)
  To: linux-nfs

As an additional clean up, encode_wcc_data() is removed because it
is now no longer used.

Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
---
 fs/nfsd/nfs3xdr.c |   54 +++++++++++++++--------------------------------------
 1 file changed, 15 insertions(+), 39 deletions(-)

diff --git a/fs/nfsd/nfs3xdr.c b/fs/nfsd/nfs3xdr.c
index 8485ab50ff3f..034e18d9b040 100644
--- a/fs/nfsd/nfs3xdr.c
+++ b/fs/nfsd/nfs3xdr.c
@@ -432,14 +432,6 @@ encode_fattr3(struct svc_rqst *rqstp, __be32 *p, struct svc_fh *fhp,
 	return p;
 }
 
-static __be32 *
-encode_saved_post_attr(struct svc_rqst *rqstp, __be32 *p, struct svc_fh *fhp)
-{
-	/* Attributes to follow */
-	*p++ = xdr_one;
-	return encode_fattr3(rqstp, p, fhp, &fhp->fh_post_attr);
-}
-
 static bool
 svcxdr_encode_wcc_attr(struct xdr_stream *xdr, const struct svc_fh *fhp)
 {
@@ -562,30 +554,6 @@ svcxdr_encode_wcc_data(struct svc_rqst *rqstp, struct xdr_stream *xdr,
 	return true;
 }
 
-/*
- * Enocde weak cache consistency data
- */
-static __be32 *
-encode_wcc_data(struct svc_rqst *rqstp, __be32 *p, struct svc_fh *fhp)
-{
-	struct dentry	*dentry = fhp->fh_dentry;
-
-	if (dentry && d_really_is_positive(dentry) && fhp->fh_post_saved) {
-		if (fhp->fh_pre_saved) {
-			*p++ = xdr_one;
-			p = xdr_encode_hyper(p, (u64) fhp->fh_pre_size);
-			p = encode_time3(p, &fhp->fh_pre_mtime);
-			p = encode_time3(p, &fhp->fh_pre_ctime);
-		} else {
-			*p++ = xdr_zero;
-		}
-		return encode_saved_post_attr(rqstp, p, fhp);
-	}
-	/* no pre- or post-attrs */
-	*p++ = xdr_zero;
-	return encode_post_op_attr(rqstp, p, fhp);
-}
-
 static bool fs_supports_change_attribute(struct super_block *sb)
 {
 	return sb->s_flags & SB_I_VERSION || sb->s_export_op->fetch_iversion;
@@ -1548,16 +1516,24 @@ nfs3svc_encode_pathconfres(struct svc_rqst *rqstp, __be32 *p)
 int
 nfs3svc_encode_commitres(struct svc_rqst *rqstp, __be32 *p)
 {
+	struct xdr_stream *xdr = &rqstp->rq_res_stream;
 	struct nfsd3_commitres *resp = rqstp->rq_resp;
 
-	*p++ = resp->status;
-	p = encode_wcc_data(rqstp, p, &resp->fh);
-	/* Write verifier */
-	if (resp->status == 0) {
-		*p++ = resp->verf[0];
-		*p++ = resp->verf[1];
+	if (!svcxdr_encode_nfsstat3(xdr, resp->status))
+		return 0;
+	switch (resp->status) {
+	case nfs_ok:
+		if (!svcxdr_encode_wcc_data(rqstp, xdr, &resp->fh))
+			return 0;
+		if (!svcxdr_encode_writeverf3(xdr, resp->verf))
+			return 0;
+		break;
+	default:
+		if (!svcxdr_encode_wcc_data(rqstp, xdr, &resp->fh))
+			return 0;
 	}
-	return xdr_ressize_check(rqstp, p);
+
+	return 1;
 }
 
 /*



^ permalink raw reply related	[flat|nested] 58+ messages in thread

* [PATCH v1 16/42] NFSD: Add a helper that encodes NFSv3 directory offset cookies
  2021-03-01 15:15 [PATCH v1 00/42] NFSv2/3 XDR encoder overhaul Chuck Lever
                   ` (14 preceding siblings ...)
  2021-03-01 15:16 ` [PATCH v1 15/42] NFSD: Update the NFSv3 COMMIT3res " Chuck Lever
@ 2021-03-01 15:16 ` Chuck Lever
  2021-03-01 15:17 ` [PATCH v1 17/42] NFSD: Count bytes instead of pages in the NFSv3 READDIR encoder Chuck Lever
                   ` (25 subsequent siblings)
  41 siblings, 0 replies; 58+ messages in thread
From: Chuck Lever @ 2021-03-01 15:16 UTC (permalink / raw)
  To: linux-nfs

Refactor: De-duplicate identical code that handles encoding of
directory offset cookies across page boundaries.

Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
---
 fs/nfsd/nfs3proc.c |   24 ++----------------------
 fs/nfsd/nfs3xdr.c  |   36 +++++++++++++++++++++++-------------
 fs/nfsd/xdr3.h     |    2 ++
 3 files changed, 27 insertions(+), 35 deletions(-)

diff --git a/fs/nfsd/nfs3proc.c b/fs/nfsd/nfs3proc.c
index 93d196752f87..90566cd01bdc 100644
--- a/fs/nfsd/nfs3proc.c
+++ b/fs/nfsd/nfs3proc.c
@@ -495,17 +495,7 @@ nfsd3_proc_readdir(struct svc_rqst *rqstp)
 		count += PAGE_SIZE;
 	}
 	resp->count = count >> 2;
-	if (resp->offset) {
-		if (unlikely(resp->offset1)) {
-			/* we ended up with offset on a page boundary */
-			*resp->offset = htonl(offset >> 32);
-			*resp->offset1 = htonl(offset & 0xffffffff);
-			resp->offset1 = NULL;
-		} else {
-			xdr_encode_hyper(resp->offset, offset);
-		}
-		resp->offset = NULL;
-	}
+	nfs3svc_encode_cookie3(resp, offset);
 
 	return rpc_success;
 }
@@ -560,17 +550,7 @@ nfsd3_proc_readdirplus(struct svc_rqst *rqstp)
 		count += PAGE_SIZE;
 	}
 	resp->count = count >> 2;
-	if (resp->offset) {
-		if (unlikely(resp->offset1)) {
-			/* we ended up with offset on a page boundary */
-			*resp->offset = htonl(offset >> 32);
-			*resp->offset1 = htonl(offset & 0xffffffff);
-			resp->offset1 = NULL;
-		} else {
-			xdr_encode_hyper(resp->offset, offset);
-		}
-		resp->offset = NULL;
-	}
+	nfs3svc_encode_cookie3(resp, offset);
 
 out:
 	return rpc_success;
diff --git a/fs/nfsd/nfs3xdr.c b/fs/nfsd/nfs3xdr.c
index 034e18d9b040..aef72d00d5a9 100644
--- a/fs/nfsd/nfs3xdr.c
+++ b/fs/nfsd/nfs3xdr.c
@@ -1219,6 +1219,28 @@ static __be32 *encode_entryplus_baggage(struct nfsd3_readdirres *cd, __be32 *p,
 	return p;
 }
 
+/**
+ * nfs3svc_encode_cookie3 - Encode a directory offset cookie
+ * @resp: readdir result context
+ * @offset: offset cookie to encode
+ *
+ */
+void nfs3svc_encode_cookie3(struct nfsd3_readdirres *resp, u64 offset)
+{
+	if (!resp->offset)
+		return;
+
+	if (resp->offset1) {
+		/* we ended up with offset on a page boundary */
+		*resp->offset = cpu_to_be32(offset >> 32);
+		*resp->offset1 = cpu_to_be32(offset & 0xffffffff);
+		resp->offset1 = NULL;
+	} else {
+		xdr_encode_hyper(resp->offset, offset);
+	}
+	resp->offset = NULL;
+}
+
 /*
  * Encode a directory entry. This one works for both normal readdir
  * and readdirplus.
@@ -1244,19 +1266,7 @@ encode_entry(struct readdir_cd *ccd, const char *name, int namlen,
 	int		elen;		/* estimated entry length in words */
 	int		num_entry_words = 0;	/* actual number of words */
 
-	if (cd->offset) {
-		u64 offset64 = offset;
-
-		if (unlikely(cd->offset1)) {
-			/* we ended up with offset on a page boundary */
-			*cd->offset = htonl(offset64 >> 32);
-			*cd->offset1 = htonl(offset64 & 0xffffffff);
-			cd->offset1 = NULL;
-		} else {
-			xdr_encode_hyper(cd->offset, offset64);
-		}
-		cd->offset = NULL;
-	}
+	nfs3svc_encode_cookie3(cd, offset);
 
 	/*
 	dprintk("encode_entry(%.*s @%ld%s)\n",
diff --git a/fs/nfsd/xdr3.h b/fs/nfsd/xdr3.h
index 8073350418ae..e76e9230827e 100644
--- a/fs/nfsd/xdr3.h
+++ b/fs/nfsd/xdr3.h
@@ -300,6 +300,8 @@ int nfs3svc_encode_commitres(struct svc_rqst *, __be32 *);
 
 void nfs3svc_release_fhandle(struct svc_rqst *);
 void nfs3svc_release_fhandle2(struct svc_rqst *);
+
+void nfs3svc_encode_cookie3(struct nfsd3_readdirres *resp, u64 offset);
 int nfs3svc_encode_entry(void *, const char *name,
 				int namlen, loff_t offset, u64 ino,
 				unsigned int);



^ permalink raw reply related	[flat|nested] 58+ messages in thread

* [PATCH v1 17/42] NFSD: Count bytes instead of pages in the NFSv3 READDIR encoder
  2021-03-01 15:15 [PATCH v1 00/42] NFSv2/3 XDR encoder overhaul Chuck Lever
                   ` (15 preceding siblings ...)
  2021-03-01 15:16 ` [PATCH v1 16/42] NFSD: Add a helper that encodes NFSv3 directory offset cookies Chuck Lever
@ 2021-03-01 15:17 ` Chuck Lever
  2021-03-01 15:17 ` [PATCH v1 18/42] NFSD: Update the NFSv3 READDIR3res encoder to use struct xdr_stream Chuck Lever
                   ` (24 subsequent siblings)
  41 siblings, 0 replies; 58+ messages in thread
From: Chuck Lever @ 2021-03-01 15:17 UTC (permalink / raw)
  To: linux-nfs

Clean up: Counting the bytes used by each returned directory entry
seems less brittle to me than trying to measure consumed pages after
the fact.

Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
---
 fs/nfsd/nfs3proc.c |   31 ++-----------------------------
 fs/nfsd/nfs3xdr.c  |    1 +
 2 files changed, 3 insertions(+), 29 deletions(-)

diff --git a/fs/nfsd/nfs3proc.c b/fs/nfsd/nfs3proc.c
index 90566cd01bdc..791d77363acd 100644
--- a/fs/nfsd/nfs3proc.c
+++ b/fs/nfsd/nfs3proc.c
@@ -462,10 +462,7 @@ nfsd3_proc_readdir(struct svc_rqst *rqstp)
 {
 	struct nfsd3_readdirargs *argp = rqstp->rq_argp;
 	struct nfsd3_readdirres  *resp = rqstp->rq_resp;
-	int		count = 0;
 	loff_t		offset;
-	struct page	**p;
-	caddr_t		page_addr = NULL;
 
 	dprintk("nfsd: READDIR(3)  %s %d bytes at %d\n",
 				SVCFH_fmt(&argp->fh),
@@ -476,6 +473,7 @@ nfsd3_proc_readdir(struct svc_rqst *rqstp)
 	/* Read directory and encode entries on the fly */
 	fh_copy(&resp->fh, &argp->fh);
 
+	resp->count = 0;
 	resp->common.err = nfs_ok;
 	resp->rqstp = rqstp;
 	offset = argp->cookie;
@@ -483,18 +481,6 @@ nfsd3_proc_readdir(struct svc_rqst *rqstp)
 	resp->status = nfsd_readdir(rqstp, &resp->fh, &offset,
 				    &resp->common, nfs3svc_encode_entry);
 	memcpy(resp->verf, argp->verf, 8);
-	count = 0;
-	for (p = rqstp->rq_respages + 1; p < rqstp->rq_next_page; p++) {
-		page_addr = page_address(*p);
-
-		if (((caddr_t)resp->buffer >= page_addr) &&
-		    ((caddr_t)resp->buffer < page_addr + PAGE_SIZE)) {
-			count += (caddr_t)resp->buffer - page_addr;
-			break;
-		}
-		count += PAGE_SIZE;
-	}
-	resp->count = count >> 2;
 	nfs3svc_encode_cookie3(resp, offset);
 
 	return rpc_success;
@@ -509,10 +495,7 @@ nfsd3_proc_readdirplus(struct svc_rqst *rqstp)
 {
 	struct nfsd3_readdirargs *argp = rqstp->rq_argp;
 	struct nfsd3_readdirres  *resp = rqstp->rq_resp;
-	int	count = 0;
 	loff_t	offset;
-	struct page **p;
-	caddr_t	page_addr = NULL;
 
 	dprintk("nfsd: READDIR+(3) %s %d bytes at %d\n",
 				SVCFH_fmt(&argp->fh),
@@ -523,6 +506,7 @@ nfsd3_proc_readdirplus(struct svc_rqst *rqstp)
 	/* Read directory and encode entries on the fly */
 	fh_copy(&resp->fh, &argp->fh);
 
+	resp->count = 0;
 	resp->common.err = nfs_ok;
 	resp->rqstp = rqstp;
 	offset = argp->cookie;
@@ -539,17 +523,6 @@ nfsd3_proc_readdirplus(struct svc_rqst *rqstp)
 	resp->status = nfsd_readdir(rqstp, &resp->fh, &offset,
 				    &resp->common, nfs3svc_encode_entry_plus);
 	memcpy(resp->verf, argp->verf, 8);
-	for (p = rqstp->rq_respages + 1; p < rqstp->rq_next_page; p++) {
-		page_addr = page_address(*p);
-
-		if (((caddr_t)resp->buffer >= page_addr) &&
-		    ((caddr_t)resp->buffer < page_addr + PAGE_SIZE)) {
-			count += (caddr_t)resp->buffer - page_addr;
-			break;
-		}
-		count += PAGE_SIZE;
-	}
-	resp->count = count >> 2;
 	nfs3svc_encode_cookie3(resp, offset);
 
 out:
diff --git a/fs/nfsd/nfs3xdr.c b/fs/nfsd/nfs3xdr.c
index aef72d00d5a9..9f8afc5b126b 100644
--- a/fs/nfsd/nfs3xdr.c
+++ b/fs/nfsd/nfs3xdr.c
@@ -1364,6 +1364,7 @@ encode_entry(struct readdir_cd *ccd, const char *name, int namlen,
 		return -EINVAL;
 	}
 
+	cd->count += num_entry_words;
 	cd->buflen -= num_entry_words;
 	cd->buffer = p;
 	cd->common.err = nfs_ok;



^ permalink raw reply related	[flat|nested] 58+ messages in thread

* [PATCH v1 18/42] NFSD: Update the NFSv3 READDIR3res encoder to use struct xdr_stream
  2021-03-01 15:15 [PATCH v1 00/42] NFSv2/3 XDR encoder overhaul Chuck Lever
                   ` (16 preceding siblings ...)
  2021-03-01 15:17 ` [PATCH v1 17/42] NFSD: Count bytes instead of pages in the NFSv3 READDIR encoder Chuck Lever
@ 2021-03-01 15:17 ` Chuck Lever
  2021-03-01 15:17 ` [PATCH v1 19/42] SUNRPC: Fix xdr_get_next_encode_buffer() page boundary handling Chuck Lever
                   ` (23 subsequent siblings)
  41 siblings, 0 replies; 58+ messages in thread
From: Chuck Lever @ 2021-03-01 15:17 UTC (permalink / raw)
  To: linux-nfs

Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
---
 fs/nfsd/nfs3proc.c |    3 ++-
 fs/nfsd/nfs3xdr.c  |   54 ++++++++++++++++++++++++++++++++++------------------
 fs/nfsd/xdr3.h     |    1 +
 3 files changed, 38 insertions(+), 20 deletions(-)

diff --git a/fs/nfsd/nfs3proc.c b/fs/nfsd/nfs3proc.c
index 791d77363acd..f1096aa0f47c 100644
--- a/fs/nfsd/nfs3proc.c
+++ b/fs/nfsd/nfs3proc.c
@@ -447,7 +447,8 @@ static void nfsd3_init_dirlist_pages(struct svc_rqst *rqstp,
 	 * and reserve room for the NULL ptr & eof flag (-2 words) */
 	resp->buflen = (count >> 2) - 2;
 
-	resp->buffer = page_address(*rqstp->rq_next_page);
+	resp->pages = rqstp->rq_next_page;
+	resp->buffer = page_address(*resp->pages);
 	while (count > 0) {
 		rqstp->rq_next_page++;
 		count -= PAGE_SIZE;
diff --git a/fs/nfsd/nfs3xdr.c b/fs/nfsd/nfs3xdr.c
index 9f8afc5b126b..f8362b5ea98f 100644
--- a/fs/nfsd/nfs3xdr.c
+++ b/fs/nfsd/nfs3xdr.c
@@ -158,6 +158,19 @@ encode_fh(__be32 *p, struct svc_fh *fhp)
 	return p + XDR_QUADLEN(size);
 }
 
+static bool
+svcxdr_encode_cookieverf3(struct xdr_stream *xdr, const __be32 *verf)
+{
+	__be32 *p;
+
+	p = xdr_reserve_space(xdr, NFS3_COOKIEVERFSIZE);
+	if (!p)
+		return false;
+	memcpy(p, verf, NFS3_COOKIEVERFSIZE);
+
+	return true;
+}
+
 static bool
 svcxdr_encode_writeverf3(struct xdr_stream *xdr, const __be32 *verf)
 {
@@ -1124,27 +1137,30 @@ nfs3svc_encode_linkres(struct svc_rqst *rqstp, __be32 *p)
 int
 nfs3svc_encode_readdirres(struct svc_rqst *rqstp, __be32 *p)
 {
+	struct xdr_stream *xdr = &rqstp->rq_res_stream;
 	struct nfsd3_readdirres *resp = rqstp->rq_resp;
 
-	*p++ = resp->status;
-	p = encode_post_op_attr(rqstp, p, &resp->fh);
-
-	if (resp->status == 0) {
-		/* stupid readdir cookie */
-		memcpy(p, resp->verf, 8); p += 2;
-		xdr_ressize_check(rqstp, p);
-		if (rqstp->rq_res.head[0].iov_len + (2<<2) > PAGE_SIZE)
-			return 1; /*No room for trailer */
-		rqstp->rq_res.page_len = (resp->count) << 2;
-
-		/* add the 'tail' to the end of the 'head' page - page 0. */
-		rqstp->rq_res.tail[0].iov_base = p;
-		*p++ = 0;		/* no more entries */
-		*p++ = htonl(resp->common.err == nfserr_eof);
-		rqstp->rq_res.tail[0].iov_len = 2<<2;
-		return 1;
-	} else
-		return xdr_ressize_check(rqstp, p);
+	if (!svcxdr_encode_nfsstat3(xdr, resp->status))
+		return 0;
+	switch (resp->status) {
+	case nfs_ok:
+		if (!svcxdr_encode_post_op_attr(rqstp, xdr, &resp->fh))
+			return 0;
+		if (!svcxdr_encode_cookieverf3(xdr, resp->verf))
+			return 0;
+		xdr_write_pages(xdr, resp->pages, 0, resp->count << 2);
+		/* no more entries */
+		if (xdr_stream_encode_item_absent(xdr) < 0)
+			return 0;
+		if (xdr_stream_encode_bool(xdr, resp->common.err == nfserr_eof) < 0)
+			return 0;
+		break;
+	default:
+		if (!svcxdr_encode_post_op_attr(rqstp, xdr, &resp->fh))
+			return 0;
+	}
+
+	return 1;
 }
 
 static __be32 *
diff --git a/fs/nfsd/xdr3.h b/fs/nfsd/xdr3.h
index e76e9230827e..a4cdd8ccb175 100644
--- a/fs/nfsd/xdr3.h
+++ b/fs/nfsd/xdr3.h
@@ -176,6 +176,7 @@ struct nfsd3_readdirres {
 	struct svc_fh		scratch;
 	int			count;
 	__be32			verf[2];
+	struct page		**pages;
 
 	struct readdir_cd	common;
 	__be32 *		buffer;



^ permalink raw reply related	[flat|nested] 58+ messages in thread

* [PATCH v1 19/42] SUNRPC: Fix xdr_get_next_encode_buffer() page boundary handling
  2021-03-01 15:15 [PATCH v1 00/42] NFSv2/3 XDR encoder overhaul Chuck Lever
                   ` (17 preceding siblings ...)
  2021-03-01 15:17 ` [PATCH v1 18/42] NFSD: Update the NFSv3 READDIR3res encoder to use struct xdr_stream Chuck Lever
@ 2021-03-01 15:17 ` Chuck Lever
  2021-03-02 22:11   ` J. Bruce Fields
  2021-03-01 15:17 ` [PATCH v1 20/42] NFSD: Update NFSv3 READDIR entry encoders to use struct xdr_stream Chuck Lever
                   ` (22 subsequent siblings)
  41 siblings, 1 reply; 58+ messages in thread
From: Chuck Lever @ 2021-03-01 15:17 UTC (permalink / raw)
  To: linux-nfs

The description of commit 2825a7f90753 ("nfsd4: allow encoding
across page boundaries") states:

> Also we can't handle a new operation starting close to the end of
> a page.

But does not detail why this is the case.

Subtracting the scratch buffer's "shift" value from the remaining
stream space seems to make reserving space close to the end of the
buf->pages array reliable.

This change is needed to make entry encoding with struct xdr_stream,
introduced in a subsequent patch, work correctly when it approaches
the end of the dirlist buffer.

Fixes: 2825a7f90753 ("nfsd4: allow encoding across page boundaries")
Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
---
 net/sunrpc/xdr.c |    2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/net/sunrpc/xdr.c b/net/sunrpc/xdr.c
index 3964ff74ee51..043b67229792 100644
--- a/net/sunrpc/xdr.c
+++ b/net/sunrpc/xdr.c
@@ -978,7 +978,7 @@ static __be32 *xdr_get_next_encode_buffer(struct xdr_stream *xdr,
 	 * shifted this one back:
 	 */
 	xdr->p = (void *)p + frag2bytes;
-	space_left = xdr->buf->buflen - xdr->buf->len;
+	space_left = xdr->buf->buflen - xdr->buf->len - frag1bytes;
 	xdr->end = (void *)p + min_t(int, space_left, PAGE_SIZE);
 	xdr->buf->page_len += frag2bytes;
 	xdr->buf->len += nbytes;



^ permalink raw reply related	[flat|nested] 58+ messages in thread

* [PATCH v1 20/42] NFSD: Update NFSv3 READDIR entry encoders to use struct xdr_stream
  2021-03-01 15:15 [PATCH v1 00/42] NFSv2/3 XDR encoder overhaul Chuck Lever
                   ` (18 preceding siblings ...)
  2021-03-01 15:17 ` [PATCH v1 19/42] SUNRPC: Fix xdr_get_next_encode_buffer() page boundary handling Chuck Lever
@ 2021-03-01 15:17 ` Chuck Lever
  2021-03-01 15:17 ` [PATCH v1 21/42] NFSD: Remove unused NFSv3 directory entry encoders Chuck Lever
                   ` (21 subsequent siblings)
  41 siblings, 0 replies; 58+ messages in thread
From: Chuck Lever @ 2021-03-01 15:17 UTC (permalink / raw)
  To: linux-nfs

The benefit of the xdr_stream helpers is that they transparently
handle encoding an XDR data item that crosses page boundaries.
Most of the open-coded logic to do that here can be eliminated.

A sub-buffer and sub-stream are set up as a sink buffer for the
directory entry encoder. As an entry is encoded, it is added to
the end of the content in this buffer/stream. The total length of
the directory list is tracked in the buffer's @len field.

When it comes time to encode the Reply, the sub-buffer is merged
into rq_res's page array at the correct place using
xdr_write_pages().

Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
---
 fs/nfsd/nfs3proc.c |   35 +++++++----
 fs/nfsd/nfs3xdr.c  |  166 ++++++++++++++++++++++++++++++++++++++++++++++++----
 fs/nfsd/xdr3.h     |   14 +++-
 3 files changed, 185 insertions(+), 30 deletions(-)

diff --git a/fs/nfsd/nfs3proc.c b/fs/nfsd/nfs3proc.c
index f1096aa0f47c..bc64e95a168d 100644
--- a/fs/nfsd/nfs3proc.c
+++ b/fs/nfsd/nfs3proc.c
@@ -441,18 +441,30 @@ static void nfsd3_init_dirlist_pages(struct svc_rqst *rqstp,
 				     struct nfsd3_readdirres *resp,
 				     int count)
 {
+	struct xdr_buf *buf = &resp->dirlist;
+	struct xdr_stream *xdr = &resp->xdr;
+
 	count = min_t(u32, count, svc_max_payload(rqstp));
 
-	/* Convert byte count to number of words (i.e. >> 2),
-	 * and reserve room for the NULL ptr & eof flag (-2 words) */
-	resp->buflen = (count >> 2) - 2;
+	memset(buf, 0, sizeof(*buf));
 
-	resp->pages = rqstp->rq_next_page;
-	resp->buffer = page_address(*resp->pages);
+	/* Reserve room for the NULL ptr & eof flag (-2 words) */
+	buf->buflen = count - XDR_UNIT * 2;
+	buf->pages = rqstp->rq_next_page;
 	while (count > 0) {
 		rqstp->rq_next_page++;
 		count -= PAGE_SIZE;
 	}
+
+	/* This is xdr_init_encode(), but it assumes that
+	 * the head kvec has already been consumed. */
+	xdr_set_scratch_buffer(xdr, NULL, 0);
+	xdr->buf = buf;
+	xdr->page_ptr = buf->pages;
+	xdr->iov = NULL;
+	xdr->p = page_address(*buf->pages);
+	xdr->end = xdr->p + (PAGE_SIZE >> 2);
+	xdr->rqst = NULL;
 }
 
 /*
@@ -471,16 +483,13 @@ nfsd3_proc_readdir(struct svc_rqst *rqstp)
 
 	nfsd3_init_dirlist_pages(rqstp, resp, argp->count);
 
-	/* Read directory and encode entries on the fly */
 	fh_copy(&resp->fh, &argp->fh);
-
-	resp->count = 0;
 	resp->common.err = nfs_ok;
+	resp->cookie_offset = 0;
 	resp->rqstp = rqstp;
 	offset = argp->cookie;
-
 	resp->status = nfsd_readdir(rqstp, &resp->fh, &offset,
-				    &resp->common, nfs3svc_encode_entry);
+				    &resp->common, nfs3svc_encode_entry3);
 	memcpy(resp->verf, argp->verf, 8);
 	nfs3svc_encode_cookie3(resp, offset);
 
@@ -504,11 +513,9 @@ nfsd3_proc_readdirplus(struct svc_rqst *rqstp)
 
 	nfsd3_init_dirlist_pages(rqstp, resp, argp->count);
 
-	/* Read directory and encode entries on the fly */
 	fh_copy(&resp->fh, &argp->fh);
-
-	resp->count = 0;
 	resp->common.err = nfs_ok;
+	resp->cookie_offset = 0;
 	resp->rqstp = rqstp;
 	offset = argp->cookie;
 
@@ -522,7 +529,7 @@ nfsd3_proc_readdirplus(struct svc_rqst *rqstp)
 	}
 
 	resp->status = nfsd_readdir(rqstp, &resp->fh, &offset,
-				    &resp->common, nfs3svc_encode_entry_plus);
+				    &resp->common, nfs3svc_encode_entryplus3);
 	memcpy(resp->verf, argp->verf, 8);
 	nfs3svc_encode_cookie3(resp, offset);
 
diff --git a/fs/nfsd/nfs3xdr.c b/fs/nfsd/nfs3xdr.c
index f8362b5ea98f..9c799fec5044 100644
--- a/fs/nfsd/nfs3xdr.c
+++ b/fs/nfsd/nfs3xdr.c
@@ -1139,6 +1139,7 @@ nfs3svc_encode_readdirres(struct svc_rqst *rqstp, __be32 *p)
 {
 	struct xdr_stream *xdr = &rqstp->rq_res_stream;
 	struct nfsd3_readdirres *resp = rqstp->rq_resp;
+	struct xdr_buf *dirlist = &resp->dirlist;
 
 	if (!svcxdr_encode_nfsstat3(xdr, resp->status))
 		return 0;
@@ -1148,7 +1149,7 @@ nfs3svc_encode_readdirres(struct svc_rqst *rqstp, __be32 *p)
 			return 0;
 		if (!svcxdr_encode_cookieverf3(xdr, resp->verf))
 			return 0;
-		xdr_write_pages(xdr, resp->pages, 0, resp->count << 2);
+		xdr_write_pages(xdr, dirlist->pages, 0, dirlist->len);
 		/* no more entries */
 		if (xdr_stream_encode_item_absent(xdr) < 0)
 			return 0;
@@ -1240,21 +1241,18 @@ static __be32 *encode_entryplus_baggage(struct nfsd3_readdirres *cd, __be32 *p,
  * @resp: readdir result context
  * @offset: offset cookie to encode
  *
+ * The buffer space for the offset cookie has already been reserved
+ * by svcxdr_encode_entry3_common().
  */
 void nfs3svc_encode_cookie3(struct nfsd3_readdirres *resp, u64 offset)
 {
-	if (!resp->offset)
-		return;
+	__be64 cookie = cpu_to_be64(offset);
 
-	if (resp->offset1) {
-		/* we ended up with offset on a page boundary */
-		*resp->offset = cpu_to_be32(offset >> 32);
-		*resp->offset1 = cpu_to_be32(offset & 0xffffffff);
-		resp->offset1 = NULL;
-	} else {
-		xdr_encode_hyper(resp->offset, offset);
-	}
-	resp->offset = NULL;
+	if (!resp->cookie_offset)
+		return;
+	write_bytes_to_xdr_buf(&resp->dirlist, resp->cookie_offset, &cookie,
+			       sizeof(cookie));
+	resp->cookie_offset = 0;
 }
 
 /*
@@ -1403,6 +1401,150 @@ nfs3svc_encode_entry_plus(void *cd, const char *name,
 	return encode_entry(cd, name, namlen, offset, ino, d_type, 1);
 }
 
+static bool
+svcxdr_encode_entry3_common(struct nfsd3_readdirres *resp, const char *name,
+			    int namlen, loff_t offset, u64 ino)
+{
+	struct xdr_buf *dirlist = &resp->dirlist;
+	struct xdr_stream *xdr = &resp->xdr;
+
+	if (xdr_stream_encode_item_present(xdr) < 0)
+		return false;
+	/* fileid */
+	if (xdr_stream_encode_u64(xdr, ino) < 0)
+		return false;
+	/* name */
+	if (xdr_stream_encode_opaque(xdr, name, min(namlen, NFS3_MAXNAMLEN)) < 0)
+		return false;
+	/* cookie */
+	resp->cookie_offset = dirlist->len;
+	if (xdr_stream_encode_u64(xdr, NFS_OFFSET_MAX) < 0)
+		return false;
+
+	return true;
+}
+
+/**
+ * nfs3svc_encode_entry3 - encode one NFSv3 READDIR entry
+ * @data: directory context
+ * @name: name of the object to be encoded
+ * @namlen: length of that name, in bytes
+ * @offset: the offset of the previous entry
+ * @ino: the fileid of this entry
+ * @d_type: unused
+ *
+ * Return values:
+ *   %0: Entry was successfully encoded.
+ *   %-EINVAL: An encoding problem occured, secondary status code in resp->common.err
+ *
+ * On exit, the following fields are updated:
+ *   - resp->xdr
+ *   - resp->common.err
+ *   - resp->cookie_offset
+ */
+int nfs3svc_encode_entry3(void *data, const char *name, int namlen,
+			  loff_t offset, u64 ino, unsigned int d_type)
+{
+	struct readdir_cd *ccd = data;
+	struct nfsd3_readdirres *resp = container_of(ccd,
+						     struct nfsd3_readdirres,
+						     common);
+	unsigned int starting_length = resp->dirlist.len;
+
+	/* The offset cookie for the previous entry */
+	nfs3svc_encode_cookie3(resp, offset);
+
+	if (!svcxdr_encode_entry3_common(resp, name, namlen, offset, ino))
+		goto out_toosmall;
+
+	xdr_commit_encode(&resp->xdr);
+	resp->common.err = nfs_ok;
+	return 0;
+
+out_toosmall:
+	resp->cookie_offset = 0;
+	resp->common.err = nfserr_toosmall;
+	resp->dirlist.len = starting_length;
+	return -EINVAL;
+}
+
+static bool
+svcxdr_encode_entry3_plus(struct nfsd3_readdirres *resp, const char *name,
+			  int namlen, u64 ino)
+{
+	struct xdr_stream *xdr = &resp->xdr;
+	struct svc_fh *fhp = &resp->scratch;
+	bool result;
+
+	result = false;
+	fh_init(fhp, NFS3_FHSIZE);
+	if (compose_entry_fh(resp, fhp, name, namlen, ino) != nfs_ok)
+		goto out_noattrs;
+
+	if (!svcxdr_encode_post_op_attr(resp->rqstp, xdr, fhp))
+		goto out;
+	if (!svcxdr_encode_post_op_fh3(xdr, fhp))
+		goto out;
+	result = true;
+
+out:
+	fh_put(fhp);
+	return result;
+
+out_noattrs:
+	if (xdr_stream_encode_item_absent(xdr) < 0)
+		return false;
+	if (xdr_stream_encode_item_absent(xdr) < 0)
+		return false;
+	return true;
+}
+
+/**
+ * nfs3svc_encode_entryplus3 - encode one NFSv3 READDIRPLUS entry
+ * @data: directory context
+ * @name: name of the object to be encoded
+ * @namlen: length of that name, in bytes
+ * @offset: the offset of the previous entry
+ * @ino: the fileid of this entry
+ * @d_type: unused
+ *
+ * Return values:
+ *   %0: Entry was successfully encoded.
+ *   %-EINVAL: An encoding problem occured, secondary status code in resp->common.err
+ *
+ * On exit, the following fields are updated:
+ *   - resp->xdr
+ *   - resp->common.err
+ *   - resp->cookie_offset
+ */
+int nfs3svc_encode_entryplus3(void *data, const char *name, int namlen,
+			      loff_t offset, u64 ino, unsigned int d_type)
+{
+	struct readdir_cd *ccd = data;
+	struct nfsd3_readdirres *resp = container_of(ccd,
+						     struct nfsd3_readdirres,
+						     common);
+	unsigned int starting_length = resp->dirlist.len;
+
+	/* The offset cookie for the previous entry */
+	nfs3svc_encode_cookie3(resp, offset);
+
+	if (!svcxdr_encode_entry3_common(resp, name, namlen, offset, ino))
+		goto out_toosmall;
+	if (!svcxdr_encode_entry3_plus(resp, name, namlen, ino))
+		goto out_toosmall;
+
+	xdr_commit_encode(&resp->xdr);
+	resp->common.err = nfs_ok;
+	return 0;
+
+out_toosmall:
+	resp->cookie_offset = 0;
+	resp->common.err = nfserr_toosmall;
+	resp->dirlist.len = starting_length;
+	return -EINVAL;
+}
+
 static bool
 svcxdr_encode_fsstat3resok(struct xdr_stream *xdr,
 			   const struct nfsd3_fsstatres *resp)
diff --git a/fs/nfsd/xdr3.h b/fs/nfsd/xdr3.h
index a4cdd8ccb175..81dea78b0f17 100644
--- a/fs/nfsd/xdr3.h
+++ b/fs/nfsd/xdr3.h
@@ -169,20 +169,22 @@ struct nfsd3_linkres {
 };
 
 struct nfsd3_readdirres {
+	/* Components of the reply */
 	__be32			status;
 	struct svc_fh		fh;
-	/* Just to save kmalloc on every readdirplus entry (svc_fh is a
-	 * little large for the stack): */
-	struct svc_fh		scratch;
 	int			count;
 	__be32			verf[2];
-	struct page		**pages;
 
+	/* Used to encode the reply's entry list */
+	struct xdr_stream	xdr;
+	struct xdr_buf		dirlist;
+	struct svc_fh		scratch;
 	struct readdir_cd	common;
 	__be32 *		buffer;
 	int			buflen;
 	__be32 *		offset;
 	__be32 *		offset1;
+	unsigned int		cookie_offset;
 	struct svc_rqst *	rqstp;
 
 };
@@ -309,6 +311,10 @@ int nfs3svc_encode_entry(void *, const char *name,
 int nfs3svc_encode_entry_plus(void *, const char *name,
 				int namlen, loff_t offset, u64 ino,
 				unsigned int);
+int nfs3svc_encode_entry3(void *data, const char *name, int namlen,
+			  loff_t offset, u64 ino, unsigned int d_type);
+int nfs3svc_encode_entryplus3(void *data, const char *name, int namlen,
+			      loff_t offset, u64 ino, unsigned int d_type);
 /* Helper functions for NFSv3 ACL code */
 __be32 *nfs3svc_encode_post_op_attr(struct svc_rqst *rqstp, __be32 *p,
 				struct svc_fh *fhp);



^ permalink raw reply related	[flat|nested] 58+ messages in thread

* [PATCH v1 21/42] NFSD: Remove unused NFSv3 directory entry encoders
  2021-03-01 15:15 [PATCH v1 00/42] NFSv2/3 XDR encoder overhaul Chuck Lever
                   ` (19 preceding siblings ...)
  2021-03-01 15:17 ` [PATCH v1 20/42] NFSD: Update NFSv3 READDIR entry encoders to use struct xdr_stream Chuck Lever
@ 2021-03-01 15:17 ` Chuck Lever
  2021-03-01 15:17 ` [PATCH v1 22/42] NFSD: Reduce svc_rqst::rq_pages churn during READDIR operations Chuck Lever
                   ` (20 subsequent siblings)
  41 siblings, 0 replies; 58+ messages in thread
From: Chuck Lever @ 2021-03-01 15:17 UTC (permalink / raw)
  To: linux-nfs

Clean up.

Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
---
 fs/nfsd/nfs3xdr.c |  190 -----------------------------------------------------
 fs/nfsd/xdr3.h    |   11 ---
 2 files changed, 201 deletions(-)

diff --git a/fs/nfsd/nfs3xdr.c b/fs/nfsd/nfs3xdr.c
index 9c799fec5044..a37ea9fb8214 100644
--- a/fs/nfsd/nfs3xdr.c
+++ b/fs/nfsd/nfs3xdr.c
@@ -148,16 +148,6 @@ svcxdr_encode_post_op_fh3(struct xdr_stream *xdr, const struct svc_fh *fhp)
 	return true;
 }
 
-static __be32 *
-encode_fh(__be32 *p, struct svc_fh *fhp)
-{
-	unsigned int size = fhp->fh_handle.fh_size;
-	*p++ = htonl(size);
-	if (size) p[XDR_QUADLEN(size)-1]=0;
-	memcpy(p, &fhp->fh_handle.fh_base, size);
-	return p + XDR_QUADLEN(size);
-}
-
 static bool
 svcxdr_encode_cookieverf3(struct xdr_stream *xdr, const __be32 *verf)
 {
@@ -1164,20 +1154,6 @@ nfs3svc_encode_readdirres(struct svc_rqst *rqstp, __be32 *p)
 	return 1;
 }
 
-static __be32 *
-encode_entry_baggage(struct nfsd3_readdirres *cd, __be32 *p, const char *name,
-	     int namlen, u64 ino)
-{
-	*p++ = xdr_one;				 /* mark entry present */
-	p    = xdr_encode_hyper(p, ino);	 /* file id */
-	p    = xdr_encode_array(p, name, namlen);/* name length & name */
-
-	cd->offset = p;				/* remember pointer */
-	p = xdr_encode_hyper(p, NFS_OFFSET_MAX);/* offset of next entry */
-
-	return p;
-}
-
 static __be32
 compose_entry_fh(struct nfsd3_readdirres *cd, struct svc_fh *fhp,
 		 const char *name, int namlen, u64 ino)
@@ -1216,26 +1192,6 @@ compose_entry_fh(struct nfsd3_readdirres *cd, struct svc_fh *fhp,
 	return rv;
 }
 
-static __be32 *encode_entryplus_baggage(struct nfsd3_readdirres *cd, __be32 *p, const char *name, int namlen, u64 ino)
-{
-	struct svc_fh	*fh = &cd->scratch;
-	__be32 err;
-
-	fh_init(fh, NFS3_FHSIZE);
-	err = compose_entry_fh(cd, fh, name, namlen, ino);
-	if (err) {
-		*p++ = 0;
-		*p++ = 0;
-		goto out;
-	}
-	p = encode_post_op_attr(cd->rqstp, p, fh);
-	*p++ = xdr_one;			/* yes, a file handle follows */
-	p = encode_fh(p, fh);
-out:
-	fh_put(fh);
-	return p;
-}
-
 /**
  * nfs3svc_encode_cookie3 - Encode a directory offset cookie
  * @resp: readdir result context
@@ -1255,152 +1211,6 @@ void nfs3svc_encode_cookie3(struct nfsd3_readdirres *resp, u64 offset)
 	resp->cookie_offset = 0;
 }
 
-/*
- * Encode a directory entry. This one works for both normal readdir
- * and readdirplus.
- * The normal readdir reply requires 2 (fileid) + 1 (stringlen)
- * + string + 2 (cookie) + 1 (next) words, i.e. 6 + strlen.
- * 
- * The readdirplus baggage is 1+21 words for post_op_attr, plus the
- * file handle.
- */
-
-#define NFS3_ENTRY_BAGGAGE	(2 + 1 + 2 + 1)
-#define NFS3_ENTRYPLUS_BAGGAGE	(1 + 21 + 1 + (NFS3_FHSIZE >> 2))
-static int
-encode_entry(struct readdir_cd *ccd, const char *name, int namlen,
-	     loff_t offset, u64 ino, unsigned int d_type, int plus)
-{
-	struct nfsd3_readdirres *cd = container_of(ccd, struct nfsd3_readdirres,
-		       					common);
-	__be32		*p = cd->buffer;
-	caddr_t		curr_page_addr = NULL;
-	struct page **	page;
-	int		slen;		/* string (name) length */
-	int		elen;		/* estimated entry length in words */
-	int		num_entry_words = 0;	/* actual number of words */
-
-	nfs3svc_encode_cookie3(cd, offset);
-
-	/*
-	dprintk("encode_entry(%.*s @%ld%s)\n",
-		namlen, name, (long) offset, plus? " plus" : "");
-	 */
-
-	/* truncate filename if too long */
-	namlen = min(namlen, NFS3_MAXNAMLEN);
-
-	slen = XDR_QUADLEN(namlen);
-	elen = slen + NFS3_ENTRY_BAGGAGE
-		+ (plus? NFS3_ENTRYPLUS_BAGGAGE : 0);
-
-	if (cd->buflen < elen) {
-		cd->common.err = nfserr_toosmall;
-		return -EINVAL;
-	}
-
-	/* determine which page in rq_respages[] we are currently filling */
-	for (page = cd->rqstp->rq_respages + 1;
-				page < cd->rqstp->rq_next_page; page++) {
-		curr_page_addr = page_address(*page);
-
-		if (((caddr_t)cd->buffer >= curr_page_addr) &&
-		    ((caddr_t)cd->buffer <  curr_page_addr + PAGE_SIZE))
-			break;
-	}
-
-	if ((caddr_t)(cd->buffer + elen) < (curr_page_addr + PAGE_SIZE)) {
-		/* encode entry in current page */
-
-		p = encode_entry_baggage(cd, p, name, namlen, ino);
-
-		if (plus)
-			p = encode_entryplus_baggage(cd, p, name, namlen, ino);
-		num_entry_words = p - cd->buffer;
-	} else if (*(page+1) != NULL) {
-		/* temporarily encode entry into next page, then move back to
-		 * current and next page in rq_respages[] */
-		__be32 *p1, *tmp;
-		int len1, len2;
-
-		/* grab next page for temporary storage of entry */
-		p1 = tmp = page_address(*(page+1));
-
-		p1 = encode_entry_baggage(cd, p1, name, namlen, ino);
-
-		if (plus)
-			p1 = encode_entryplus_baggage(cd, p1, name, namlen, ino);
-
-		/* determine entry word length and lengths to go in pages */
-		num_entry_words = p1 - tmp;
-		len1 = curr_page_addr + PAGE_SIZE - (caddr_t)cd->buffer;
-		if ((num_entry_words << 2) < len1) {
-			/* the actual number of words in the entry is less
-			 * than elen and can still fit in the current page
-			 */
-			memmove(p, tmp, num_entry_words << 2);
-			p += num_entry_words;
-
-			/* update offset */
-			cd->offset = cd->buffer + (cd->offset - tmp);
-		} else {
-			unsigned int offset_r = (cd->offset - tmp) << 2;
-
-			/* update pointer to offset location.
-			 * This is a 64bit quantity, so we need to
-			 * deal with 3 cases:
-			 *  -	entirely in first page
-			 *  -	entirely in second page
-			 *  -	4 bytes in each page
-			 */
-			if (offset_r + 8 <= len1) {
-				cd->offset = p + (cd->offset - tmp);
-			} else if (offset_r >= len1) {
-				cd->offset -= len1 >> 2;
-			} else {
-				/* sitting on the fence */
-				BUG_ON(offset_r != len1 - 4);
-				cd->offset = p + (cd->offset - tmp);
-				cd->offset1 = tmp;
-			}
-
-			len2 = (num_entry_words << 2) - len1;
-
-			/* move from temp page to current and next pages */
-			memmove(p, tmp, len1);
-			memmove(tmp, (caddr_t)tmp+len1, len2);
-
-			p = tmp + (len2 >> 2);
-		}
-	}
-	else {
-		cd->common.err = nfserr_toosmall;
-		return -EINVAL;
-	}
-
-	cd->count += num_entry_words;
-	cd->buflen -= num_entry_words;
-	cd->buffer = p;
-	cd->common.err = nfs_ok;
-	return 0;
-
-}
-
-int
-nfs3svc_encode_entry(void *cd, const char *name,
-		     int namlen, loff_t offset, u64 ino, unsigned int d_type)
-{
-	return encode_entry(cd, name, namlen, offset, ino, d_type, 0);
-}
-
-int
-nfs3svc_encode_entry_plus(void *cd, const char *name,
-			  int namlen, loff_t offset, u64 ino,
-			  unsigned int d_type)
-{
-	return encode_entry(cd, name, namlen, offset, ino, d_type, 1);
-}
-
 static bool
 svcxdr_encode_entry3_common(struct nfsd3_readdirres *resp, const char *name,
 			    int namlen, loff_t offset, u64 ino)
diff --git a/fs/nfsd/xdr3.h b/fs/nfsd/xdr3.h
index 81dea78b0f17..b851458373db 100644
--- a/fs/nfsd/xdr3.h
+++ b/fs/nfsd/xdr3.h
@@ -172,7 +172,6 @@ struct nfsd3_readdirres {
 	/* Components of the reply */
 	__be32			status;
 	struct svc_fh		fh;
-	int			count;
 	__be32			verf[2];
 
 	/* Used to encode the reply's entry list */
@@ -180,10 +179,6 @@ struct nfsd3_readdirres {
 	struct xdr_buf		dirlist;
 	struct svc_fh		scratch;
 	struct readdir_cd	common;
-	__be32 *		buffer;
-	int			buflen;
-	__be32 *		offset;
-	__be32 *		offset1;
 	unsigned int		cookie_offset;
 	struct svc_rqst *	rqstp;
 
@@ -305,12 +300,6 @@ void nfs3svc_release_fhandle(struct svc_rqst *);
 void nfs3svc_release_fhandle2(struct svc_rqst *);
 
 void nfs3svc_encode_cookie3(struct nfsd3_readdirres *resp, u64 offset);
-int nfs3svc_encode_entry(void *, const char *name,
-				int namlen, loff_t offset, u64 ino,
-				unsigned int);
-int nfs3svc_encode_entry_plus(void *, const char *name,
-				int namlen, loff_t offset, u64 ino,
-				unsigned int);
 int nfs3svc_encode_entry3(void *data, const char *name, int namlen,
 			  loff_t offset, u64 ino, unsigned int d_type);
 int nfs3svc_encode_entryplus3(void *data, const char *name, int namlen,



^ permalink raw reply related	[flat|nested] 58+ messages in thread

* [PATCH v1 22/42] NFSD: Reduce svc_rqst::rq_pages churn during READDIR operations
  2021-03-01 15:15 [PATCH v1 00/42] NFSv2/3 XDR encoder overhaul Chuck Lever
                   ` (20 preceding siblings ...)
  2021-03-01 15:17 ` [PATCH v1 21/42] NFSD: Remove unused NFSv3 directory entry encoders Chuck Lever
@ 2021-03-01 15:17 ` Chuck Lever
  2021-03-01 15:17 ` [PATCH v1 23/42] NFSD: Update the NFSv2 stat encoder to use struct xdr_stream Chuck Lever
                   ` (19 subsequent siblings)
  41 siblings, 0 replies; 58+ messages in thread
From: Chuck Lever @ 2021-03-01 15:17 UTC (permalink / raw)
  To: linux-nfs

During NFSv2 and NFSv3 READDIR/PLUS operations, NFSD advances
rq_next_page to the full size of the client-requested buffer, then
releases all those pages at the end of the request. The next request
to use that nfsd thread has to refill the pages.

NFSD does this even when the dirlist in the reply is small. With
NFSv3 clients that send READDIR operations with large buffer sizes,
that can be 256 put_page/alloc_page pairs per READDIR request, even
though those pages often remain unused.

We can save some work by not releasing dirlist buffer pages that
were not used to form the READDIR Reply. I've left the NFSv2 code
alone since there are never more than three pages involved in an
NFSv2 READDIR Reply.

Eventually we should nail down why these pages need to be released
at all in order to avoid allocating and releasing pages
unnecessarily.

Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
---
 fs/nfsd/nfs3proc.c |    6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/fs/nfsd/nfs3proc.c b/fs/nfsd/nfs3proc.c
index bc64e95a168d..17715a6c7a40 100644
--- a/fs/nfsd/nfs3proc.c
+++ b/fs/nfsd/nfs3proc.c
@@ -493,6 +493,9 @@ nfsd3_proc_readdir(struct svc_rqst *rqstp)
 	memcpy(resp->verf, argp->verf, 8);
 	nfs3svc_encode_cookie3(resp, offset);
 
+	/* Recycle only pages that were part of the reply */
+	rqstp->rq_next_page = resp->xdr.page_ptr + 1;
+
 	return rpc_success;
 }
 
@@ -533,6 +536,9 @@ nfsd3_proc_readdirplus(struct svc_rqst *rqstp)
 	memcpy(resp->verf, argp->verf, 8);
 	nfs3svc_encode_cookie3(resp, offset);
 
+	/* Recycle only pages that were part of the reply */
+	rqstp->rq_next_page = resp->xdr.page_ptr + 1;
+
 out:
 	return rpc_success;
 }



^ permalink raw reply related	[flat|nested] 58+ messages in thread

* [PATCH v1 23/42] NFSD: Update the NFSv2 stat encoder to use struct xdr_stream
  2021-03-01 15:15 [PATCH v1 00/42] NFSv2/3 XDR encoder overhaul Chuck Lever
                   ` (21 preceding siblings ...)
  2021-03-01 15:17 ` [PATCH v1 22/42] NFSD: Reduce svc_rqst::rq_pages churn during READDIR operations Chuck Lever
@ 2021-03-01 15:17 ` Chuck Lever
  2021-03-01 15:17 ` [PATCH v1 24/42] NFSD: Update the NFSv2 attrstat " Chuck Lever
                   ` (18 subsequent siblings)
  41 siblings, 0 replies; 58+ messages in thread
From: Chuck Lever @ 2021-03-01 15:17 UTC (permalink / raw)
  To: linux-nfs

Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
---
 fs/nfsd/nfsproc.c |   10 +++++-----
 fs/nfsd/nfsxdr.c  |   19 ++++++++++++++++---
 fs/nfsd/xdr.h     |    2 +-
 3 files changed, 22 insertions(+), 9 deletions(-)

diff --git a/fs/nfsd/nfsproc.c b/fs/nfsd/nfsproc.c
index a8d5449dd0e9..59080e6793b9 100644
--- a/fs/nfsd/nfsproc.c
+++ b/fs/nfsd/nfsproc.c
@@ -736,7 +736,7 @@ static const struct svc_procedure nfsd_procedures2[18] = {
 	[NFSPROC_REMOVE] = {
 		.pc_func = nfsd_proc_remove,
 		.pc_decode = nfssvc_decode_diropargs,
-		.pc_encode = nfssvc_encode_stat,
+		.pc_encode = nfssvc_encode_statres,
 		.pc_argsize = sizeof(struct nfsd_diropargs),
 		.pc_ressize = sizeof(struct nfsd_stat),
 		.pc_cachetype = RC_REPLSTAT,
@@ -746,7 +746,7 @@ static const struct svc_procedure nfsd_procedures2[18] = {
 	[NFSPROC_RENAME] = {
 		.pc_func = nfsd_proc_rename,
 		.pc_decode = nfssvc_decode_renameargs,
-		.pc_encode = nfssvc_encode_stat,
+		.pc_encode = nfssvc_encode_statres,
 		.pc_argsize = sizeof(struct nfsd_renameargs),
 		.pc_ressize = sizeof(struct nfsd_stat),
 		.pc_cachetype = RC_REPLSTAT,
@@ -756,7 +756,7 @@ static const struct svc_procedure nfsd_procedures2[18] = {
 	[NFSPROC_LINK] = {
 		.pc_func = nfsd_proc_link,
 		.pc_decode = nfssvc_decode_linkargs,
-		.pc_encode = nfssvc_encode_stat,
+		.pc_encode = nfssvc_encode_statres,
 		.pc_argsize = sizeof(struct nfsd_linkargs),
 		.pc_ressize = sizeof(struct nfsd_stat),
 		.pc_cachetype = RC_REPLSTAT,
@@ -766,7 +766,7 @@ static const struct svc_procedure nfsd_procedures2[18] = {
 	[NFSPROC_SYMLINK] = {
 		.pc_func = nfsd_proc_symlink,
 		.pc_decode = nfssvc_decode_symlinkargs,
-		.pc_encode = nfssvc_encode_stat,
+		.pc_encode = nfssvc_encode_statres,
 		.pc_argsize = sizeof(struct nfsd_symlinkargs),
 		.pc_ressize = sizeof(struct nfsd_stat),
 		.pc_cachetype = RC_REPLSTAT,
@@ -787,7 +787,7 @@ static const struct svc_procedure nfsd_procedures2[18] = {
 	[NFSPROC_RMDIR] = {
 		.pc_func = nfsd_proc_rmdir,
 		.pc_decode = nfssvc_decode_diropargs,
-		.pc_encode = nfssvc_encode_stat,
+		.pc_encode = nfssvc_encode_statres,
 		.pc_argsize = sizeof(struct nfsd_diropargs),
 		.pc_ressize = sizeof(struct nfsd_stat),
 		.pc_cachetype = RC_REPLSTAT,
diff --git a/fs/nfsd/nfsxdr.c b/fs/nfsd/nfsxdr.c
index 5d79ef6a0c7f..10cd120044b3 100644
--- a/fs/nfsd/nfsxdr.c
+++ b/fs/nfsd/nfsxdr.c
@@ -26,6 +26,19 @@ static u32	nfs_ftypes[] = {
  * Basic NFSv2 data types (RFC 1094 Section 2.3)
  */
 
+static bool
+svcxdr_encode_stat(struct xdr_stream *xdr, __be32 status)
+{
+	__be32 *p;
+
+	p = xdr_reserve_space(xdr, sizeof(status));
+	if (!p)
+		return false;
+	*p = status;
+
+	return true;
+}
+
 /**
  * svcxdr_decode_fhandle - Decode an NFSv2 file handle
  * @xdr: XDR stream positioned at an encoded NFSv2 FH
@@ -390,12 +403,12 @@ nfssvc_decode_readdirargs(struct svc_rqst *rqstp, __be32 *p)
  */
 
 int
-nfssvc_encode_stat(struct svc_rqst *rqstp, __be32 *p)
+nfssvc_encode_statres(struct svc_rqst *rqstp, __be32 *p)
 {
+	struct xdr_stream *xdr = &rqstp->rq_res_stream;
 	struct nfsd_stat *resp = rqstp->rq_resp;
 
-	*p++ = resp->status;
-	return xdr_ressize_check(rqstp, p);
+	return svcxdr_encode_stat(xdr, resp->status);
 }
 
 int
diff --git a/fs/nfsd/xdr.h b/fs/nfsd/xdr.h
index 3018b52b6d5e..a74ffcf8b9c6 100644
--- a/fs/nfsd/xdr.h
+++ b/fs/nfsd/xdr.h
@@ -147,7 +147,7 @@ int nfssvc_decode_renameargs(struct svc_rqst *, __be32 *);
 int nfssvc_decode_linkargs(struct svc_rqst *, __be32 *);
 int nfssvc_decode_symlinkargs(struct svc_rqst *, __be32 *);
 int nfssvc_decode_readdirargs(struct svc_rqst *, __be32 *);
-int nfssvc_encode_stat(struct svc_rqst *, __be32 *);
+int nfssvc_encode_statres(struct svc_rqst *, __be32 *);
 int nfssvc_encode_attrstat(struct svc_rqst *, __be32 *);
 int nfssvc_encode_diropres(struct svc_rqst *, __be32 *);
 int nfssvc_encode_readlinkres(struct svc_rqst *, __be32 *);



^ permalink raw reply related	[flat|nested] 58+ messages in thread

* [PATCH v1 24/42] NFSD: Update the NFSv2 attrstat encoder to use struct xdr_stream
  2021-03-01 15:15 [PATCH v1 00/42] NFSv2/3 XDR encoder overhaul Chuck Lever
                   ` (22 preceding siblings ...)
  2021-03-01 15:17 ` [PATCH v1 23/42] NFSD: Update the NFSv2 stat encoder to use struct xdr_stream Chuck Lever
@ 2021-03-01 15:17 ` Chuck Lever
  2021-03-01 15:17 ` [PATCH v1 25/42] NFSD: Update the NFSv2 diropres " Chuck Lever
                   ` (17 subsequent siblings)
  41 siblings, 0 replies; 58+ messages in thread
From: Chuck Lever @ 2021-03-01 15:17 UTC (permalink / raw)
  To: linux-nfs

Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
---
 fs/nfsd/nfsproc.c |    6 ++--
 fs/nfsd/nfsxdr.c  |   90 ++++++++++++++++++++++++++++++++++++++++++++++++-----
 fs/nfsd/xdr.h     |    2 +
 3 files changed, 86 insertions(+), 12 deletions(-)

diff --git a/fs/nfsd/nfsproc.c b/fs/nfsd/nfsproc.c
index 59080e6793b9..2ae6409ee39e 100644
--- a/fs/nfsd/nfsproc.c
+++ b/fs/nfsd/nfsproc.c
@@ -640,7 +640,7 @@ static const struct svc_procedure nfsd_procedures2[18] = {
 	[NFSPROC_GETATTR] = {
 		.pc_func = nfsd_proc_getattr,
 		.pc_decode = nfssvc_decode_fhandleargs,
-		.pc_encode = nfssvc_encode_attrstat,
+		.pc_encode = nfssvc_encode_attrstatres,
 		.pc_release = nfssvc_release_attrstat,
 		.pc_argsize = sizeof(struct nfsd_fhandle),
 		.pc_ressize = sizeof(struct nfsd_attrstat),
@@ -651,7 +651,7 @@ static const struct svc_procedure nfsd_procedures2[18] = {
 	[NFSPROC_SETATTR] = {
 		.pc_func = nfsd_proc_setattr,
 		.pc_decode = nfssvc_decode_sattrargs,
-		.pc_encode = nfssvc_encode_attrstat,
+		.pc_encode = nfssvc_encode_attrstatres,
 		.pc_release = nfssvc_release_attrstat,
 		.pc_argsize = sizeof(struct nfsd_sattrargs),
 		.pc_ressize = sizeof(struct nfsd_attrstat),
@@ -714,7 +714,7 @@ static const struct svc_procedure nfsd_procedures2[18] = {
 	[NFSPROC_WRITE] = {
 		.pc_func = nfsd_proc_write,
 		.pc_decode = nfssvc_decode_writeargs,
-		.pc_encode = nfssvc_encode_attrstat,
+		.pc_encode = nfssvc_encode_attrstatres,
 		.pc_release = nfssvc_release_attrstat,
 		.pc_argsize = sizeof(struct nfsd_writeargs),
 		.pc_ressize = sizeof(struct nfsd_attrstat),
diff --git a/fs/nfsd/nfsxdr.c b/fs/nfsd/nfsxdr.c
index 10cd120044b3..65c8f8f31444 100644
--- a/fs/nfsd/nfsxdr.c
+++ b/fs/nfsd/nfsxdr.c
@@ -14,7 +14,7 @@
 /*
  * Mapping of S_IF* types to NFS file types
  */
-static u32	nfs_ftypes[] = {
+static const u32 nfs_ftypes[] = {
 	NFNON,  NFCHR,  NFCHR, NFBAD,
 	NFDIR,  NFBAD,  NFBLK, NFBAD,
 	NFREG,  NFBAD,  NFLNK, NFBAD,
@@ -70,6 +70,17 @@ encode_fh(__be32 *p, struct svc_fh *fhp)
 	return p + (NFS_FHSIZE>> 2);
 }
 
+static __be32 *
+encode_timeval(__be32 *p, const struct timespec64 *time)
+{
+	*p++ = cpu_to_be32((u32)time->tv_sec);
+	if (time->tv_nsec)
+		*p++ = cpu_to_be32(time->tv_nsec / NSEC_PER_USEC);
+	else
+		*p++ = xdr_zero;
+	return p;
+}
+
 static bool
 svcxdr_decode_filename(struct xdr_stream *xdr, char **name, unsigned int *len)
 {
@@ -233,6 +244,64 @@ encode_fattr(struct svc_rqst *rqstp, __be32 *p, struct svc_fh *fhp,
 	return p;
 }
 
+static int
+svcxdr_encode_fattr(struct svc_rqst *rqstp, struct xdr_stream *xdr,
+		    const struct svc_fh *fhp, const struct kstat *stat)
+{
+	struct user_namespace *userns = nfsd_user_namespace(rqstp);
+	struct dentry *dentry = fhp->fh_dentry;
+	int type = stat->mode & S_IFMT;
+	struct timespec64 time;
+	__be32 *p;
+	u32 fsid;
+
+	p = xdr_reserve_space(xdr, XDR_UNIT * 17);
+	if (!p)
+		return 0;
+
+	*p++ = cpu_to_be32(nfs_ftypes[type >> 12]);
+	*p++ = cpu_to_be32((u32)stat->mode);
+	*p++ = cpu_to_be32((u32)stat->nlink);
+	*p++ = cpu_to_be32((u32)from_kuid_munged(userns, stat->uid));
+	*p++ = cpu_to_be32((u32)from_kgid_munged(userns, stat->gid));
+
+	if (S_ISLNK(type) && stat->size > NFS_MAXPATHLEN)
+		*p++ = cpu_to_be32(NFS_MAXPATHLEN);
+	else
+		*p++ = cpu_to_be32((u32) stat->size);
+	*p++ = cpu_to_be32((u32) stat->blksize);
+	if (S_ISCHR(type) || S_ISBLK(type))
+		*p++ = cpu_to_be32(new_encode_dev(stat->rdev));
+	else
+		*p++ = cpu_to_be32(0xffffffff);
+	*p++ = cpu_to_be32((u32)stat->blocks);
+
+	switch (fsid_source(fhp)) {
+	case FSIDSOURCE_FSID:
+		fsid = (u32)fhp->fh_export->ex_fsid;
+		break;
+	case FSIDSOURCE_UUID:
+		fsid = ((u32 *)fhp->fh_export->ex_uuid)[0];
+		fsid ^= ((u32 *)fhp->fh_export->ex_uuid)[1];
+		fsid ^= ((u32 *)fhp->fh_export->ex_uuid)[2];
+		fsid ^= ((u32 *)fhp->fh_export->ex_uuid)[3];
+		break;
+	default:
+		fsid = new_encode_dev(stat->dev);
+		break;
+	}
+	*p++ = cpu_to_be32(fsid);
+
+	*p++ = cpu_to_be32((u32)stat->ino);
+	p = encode_timeval(p, &stat->atime);
+	time = stat->mtime;
+	lease_get_mtime(d_inode(dentry), &time);
+	p = encode_timeval(p, &time);
+	encode_timeval(p, &stat->ctime);
+
+	return 1;
+}
+
 /* Helper function for NFSv2 ACL code */
 __be32 *nfs2svc_encode_fattr(struct svc_rqst *rqstp, __be32 *p, struct svc_fh *fhp, struct kstat *stat)
 {
@@ -412,16 +481,21 @@ nfssvc_encode_statres(struct svc_rqst *rqstp, __be32 *p)
 }
 
 int
-nfssvc_encode_attrstat(struct svc_rqst *rqstp, __be32 *p)
+nfssvc_encode_attrstatres(struct svc_rqst *rqstp, __be32 *p)
 {
+	struct xdr_stream *xdr = &rqstp->rq_res_stream;
 	struct nfsd_attrstat *resp = rqstp->rq_resp;
 
-	*p++ = resp->status;
-	if (resp->status != nfs_ok)
-		goto out;
-	p = encode_fattr(rqstp, p, &resp->fh, &resp->stat);
-out:
-	return xdr_ressize_check(rqstp, p);
+	if (!svcxdr_encode_stat(xdr, resp->status))
+		return 0;
+	switch (resp->status) {
+	case nfs_ok:
+		if (!svcxdr_encode_fattr(rqstp, xdr, &resp->fh, &resp->stat))
+			return 0;
+		break;
+	}
+
+	return 1;
 }
 
 int
diff --git a/fs/nfsd/xdr.h b/fs/nfsd/xdr.h
index a74ffcf8b9c6..a9b4ee6d098b 100644
--- a/fs/nfsd/xdr.h
+++ b/fs/nfsd/xdr.h
@@ -148,7 +148,7 @@ int nfssvc_decode_linkargs(struct svc_rqst *, __be32 *);
 int nfssvc_decode_symlinkargs(struct svc_rqst *, __be32 *);
 int nfssvc_decode_readdirargs(struct svc_rqst *, __be32 *);
 int nfssvc_encode_statres(struct svc_rqst *, __be32 *);
-int nfssvc_encode_attrstat(struct svc_rqst *, __be32 *);
+int nfssvc_encode_attrstatres(struct svc_rqst *, __be32 *);
 int nfssvc_encode_diropres(struct svc_rqst *, __be32 *);
 int nfssvc_encode_readlinkres(struct svc_rqst *, __be32 *);
 int nfssvc_encode_readres(struct svc_rqst *, __be32 *);



^ permalink raw reply related	[flat|nested] 58+ messages in thread

* [PATCH v1 25/42] NFSD: Update the NFSv2 diropres encoder to use struct xdr_stream
  2021-03-01 15:15 [PATCH v1 00/42] NFSv2/3 XDR encoder overhaul Chuck Lever
                   ` (23 preceding siblings ...)
  2021-03-01 15:17 ` [PATCH v1 24/42] NFSD: Update the NFSv2 attrstat " Chuck Lever
@ 2021-03-01 15:17 ` Chuck Lever
  2021-03-01 15:17 ` [PATCH v1 26/42] NFSD: Update the NFSv2 READLINK result " Chuck Lever
                   ` (16 subsequent siblings)
  41 siblings, 0 replies; 58+ messages in thread
From: Chuck Lever @ 2021-03-01 15:17 UTC (permalink / raw)
  To: linux-nfs

Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
---
 fs/nfsd/nfsxdr.c |   38 +++++++++++++++++++++++++-------------
 1 file changed, 25 insertions(+), 13 deletions(-)

diff --git a/fs/nfsd/nfsxdr.c b/fs/nfsd/nfsxdr.c
index 65c8f8f31444..989144b0d5be 100644
--- a/fs/nfsd/nfsxdr.c
+++ b/fs/nfsd/nfsxdr.c
@@ -63,11 +63,17 @@ svcxdr_decode_fhandle(struct xdr_stream *xdr, struct svc_fh *fhp)
 	return true;
 }
 
-static __be32 *
-encode_fh(__be32 *p, struct svc_fh *fhp)
+static bool
+svcxdr_encode_fhandle(struct xdr_stream *xdr, const struct svc_fh *fhp)
 {
+	__be32 *p;
+
+	p = xdr_reserve_space(xdr, NFS_FHSIZE);
+	if (!p)
+		return false;
 	memcpy(p, &fhp->fh_handle.fh_base, NFS_FHSIZE);
-	return p + (NFS_FHSIZE>> 2);
+
+	return true;
 }
 
 static __be32 *
@@ -244,7 +250,7 @@ encode_fattr(struct svc_rqst *rqstp, __be32 *p, struct svc_fh *fhp,
 	return p;
 }
 
-static int
+static bool
 svcxdr_encode_fattr(struct svc_rqst *rqstp, struct xdr_stream *xdr,
 		    const struct svc_fh *fhp, const struct kstat *stat)
 {
@@ -257,7 +263,7 @@ svcxdr_encode_fattr(struct svc_rqst *rqstp, struct xdr_stream *xdr,
 
 	p = xdr_reserve_space(xdr, XDR_UNIT * 17);
 	if (!p)
-		return 0;
+		return false;
 
 	*p++ = cpu_to_be32(nfs_ftypes[type >> 12]);
 	*p++ = cpu_to_be32((u32)stat->mode);
@@ -299,7 +305,7 @@ svcxdr_encode_fattr(struct svc_rqst *rqstp, struct xdr_stream *xdr,
 	p = encode_timeval(p, &time);
 	encode_timeval(p, &stat->ctime);
 
-	return 1;
+	return true;
 }
 
 /* Helper function for NFSv2 ACL code */
@@ -501,15 +507,21 @@ nfssvc_encode_attrstatres(struct svc_rqst *rqstp, __be32 *p)
 int
 nfssvc_encode_diropres(struct svc_rqst *rqstp, __be32 *p)
 {
+	struct xdr_stream *xdr = &rqstp->rq_res_stream;
 	struct nfsd_diropres *resp = rqstp->rq_resp;
 
-	*p++ = resp->status;
-	if (resp->status != nfs_ok)
-		goto out;
-	p = encode_fh(p, &resp->fh);
-	p = encode_fattr(rqstp, p, &resp->fh, &resp->stat);
-out:
-	return xdr_ressize_check(rqstp, p);
+	if (!svcxdr_encode_stat(xdr, resp->status))
+		return 0;
+	switch (resp->status) {
+	case nfs_ok:
+		if (!svcxdr_encode_fhandle(xdr, &resp->fh))
+			return 0;
+		if (!svcxdr_encode_fattr(rqstp, xdr, &resp->fh, &resp->stat))
+			return 0;
+		break;
+	}
+
+	return 1;
 }
 
 int



^ permalink raw reply related	[flat|nested] 58+ messages in thread

* [PATCH v1 26/42] NFSD: Update the NFSv2 READLINK result encoder to use struct xdr_stream
  2021-03-01 15:15 [PATCH v1 00/42] NFSv2/3 XDR encoder overhaul Chuck Lever
                   ` (24 preceding siblings ...)
  2021-03-01 15:17 ` [PATCH v1 25/42] NFSD: Update the NFSv2 diropres " Chuck Lever
@ 2021-03-01 15:17 ` Chuck Lever
  2021-03-01 15:18 ` [PATCH v1 27/42] NFSD: Update the NFSv2 READ " Chuck Lever
                   ` (15 subsequent siblings)
  41 siblings, 0 replies; 58+ messages in thread
From: Chuck Lever @ 2021-03-01 15:17 UTC (permalink / raw)
  To: linux-nfs

Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
---
 fs/nfsd/nfsproc.c |    5 +++--
 fs/nfsd/nfsxdr.c  |   26 ++++++++++++--------------
 fs/nfsd/xdr.h     |    1 +
 3 files changed, 16 insertions(+), 16 deletions(-)

diff --git a/fs/nfsd/nfsproc.c b/fs/nfsd/nfsproc.c
index 2ae6409ee39e..f55080482997 100644
--- a/fs/nfsd/nfsproc.c
+++ b/fs/nfsd/nfsproc.c
@@ -151,13 +151,14 @@ nfsd_proc_readlink(struct svc_rqst *rqstp)
 {
 	struct nfsd_fhandle *argp = rqstp->rq_argp;
 	struct nfsd_readlinkres *resp = rqstp->rq_resp;
-	char *buffer = page_address(*(rqstp->rq_next_page++));
 
 	dprintk("nfsd: READLINK %s\n", SVCFH_fmt(&argp->fh));
 
 	/* Read the symlink. */
 	resp->len = NFS_MAXPATHLEN;
-	resp->status = nfsd_readlink(rqstp, &argp->fh, buffer, &resp->len);
+	resp->page = *(rqstp->rq_next_page++);
+	resp->status = nfsd_readlink(rqstp, &argp->fh,
+				     page_address(resp->page), &resp->len);
 
 	fh_put(&argp->fh);
 	return rpc_success;
diff --git a/fs/nfsd/nfsxdr.c b/fs/nfsd/nfsxdr.c
index 989144b0d5be..74d9d11949c6 100644
--- a/fs/nfsd/nfsxdr.c
+++ b/fs/nfsd/nfsxdr.c
@@ -527,24 +527,22 @@ nfssvc_encode_diropres(struct svc_rqst *rqstp, __be32 *p)
 int
 nfssvc_encode_readlinkres(struct svc_rqst *rqstp, __be32 *p)
 {
+	struct xdr_stream *xdr = &rqstp->rq_res_stream;
 	struct nfsd_readlinkres *resp = rqstp->rq_resp;
 	struct kvec *head = rqstp->rq_res.head;
 
-	*p++ = resp->status;
-	if (resp->status != nfs_ok)
-		return xdr_ressize_check(rqstp, p);
-
-	*p++ = htonl(resp->len);
-	xdr_ressize_check(rqstp, p);
-	rqstp->rq_res.page_len = resp->len;
-	if (resp->len & 3) {
-		/* need to pad the tail */
-		rqstp->rq_res.tail[0].iov_base = 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))
+	if (!svcxdr_encode_stat(xdr, resp->status))
 		return 0;
+	switch (resp->status) {
+	case nfs_ok:
+		if (xdr_stream_encode_u32(xdr, resp->len) < 0)
+			return 0;
+		xdr_write_pages(xdr, &resp->page, 0, resp->len);
+		if (svc_encode_result_payload(rqstp, head->iov_len, resp->len) < 0)
+			return 0;
+		break;
+	}
+
 	return 1;
 }
 
diff --git a/fs/nfsd/xdr.h b/fs/nfsd/xdr.h
index a9b4ee6d098b..b868565c471f 100644
--- a/fs/nfsd/xdr.h
+++ b/fs/nfsd/xdr.h
@@ -94,6 +94,7 @@ struct nfsd_diropres  {
 struct nfsd_readlinkres {
 	__be32			status;
 	int			len;
+	struct page		*page;
 };
 
 struct nfsd_readres {



^ permalink raw reply related	[flat|nested] 58+ messages in thread

* [PATCH v1 27/42] NFSD: Update the NFSv2 READ result encoder to use struct xdr_stream
  2021-03-01 15:15 [PATCH v1 00/42] NFSv2/3 XDR encoder overhaul Chuck Lever
                   ` (25 preceding siblings ...)
  2021-03-01 15:17 ` [PATCH v1 26/42] NFSD: Update the NFSv2 READLINK result " Chuck Lever
@ 2021-03-01 15:18 ` Chuck Lever
  2021-03-01 15:18 ` [PATCH v1 28/42] NFSD: Update the NFSv2 STATFS " Chuck Lever
                   ` (14 subsequent siblings)
  41 siblings, 0 replies; 58+ messages in thread
From: Chuck Lever @ 2021-03-01 15:18 UTC (permalink / raw)
  To: linux-nfs

Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
---
 fs/nfsd/nfsproc.c |    1 +
 fs/nfsd/nfsxdr.c  |   32 +++++++++++++++-----------------
 fs/nfsd/xdr.h     |    1 +
 3 files changed, 17 insertions(+), 17 deletions(-)

diff --git a/fs/nfsd/nfsproc.c b/fs/nfsd/nfsproc.c
index f55080482997..2088bb0887ba 100644
--- a/fs/nfsd/nfsproc.c
+++ b/fs/nfsd/nfsproc.c
@@ -185,6 +185,7 @@ nfsd_proc_read(struct svc_rqst *rqstp)
 
 	v = 0;
 	len = argp->count;
+	resp->pages = rqstp->rq_next_page;
 	while (len > 0) {
 		struct page *page = *(rqstp->rq_next_page++);
 
diff --git a/fs/nfsd/nfsxdr.c b/fs/nfsd/nfsxdr.c
index 74d9d11949c6..d6d7d07dbb1b 100644
--- a/fs/nfsd/nfsxdr.c
+++ b/fs/nfsd/nfsxdr.c
@@ -549,27 +549,25 @@ nfssvc_encode_readlinkres(struct svc_rqst *rqstp, __be32 *p)
 int
 nfssvc_encode_readres(struct svc_rqst *rqstp, __be32 *p)
 {
+	struct xdr_stream *xdr = &rqstp->rq_res_stream;
 	struct nfsd_readres *resp = rqstp->rq_resp;
 	struct kvec *head = rqstp->rq_res.head;
 
-	*p++ = resp->status;
-	if (resp->status != nfs_ok)
-		return xdr_ressize_check(rqstp, p);
-
-	p = encode_fattr(rqstp, p, &resp->fh, &resp->stat);
-	*p++ = htonl(resp->count);
-	xdr_ressize_check(rqstp, p);
-
-	/* now update rqstp->rq_res to reflect data as well */
-	rqstp->rq_res.page_len = resp->count;
-	if (resp->count & 3) {
-		/* need to pad the tail */
-		rqstp->rq_res.tail[0].iov_base = 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))
+	if (!svcxdr_encode_stat(xdr, resp->status))
 		return 0;
+	switch (resp->status) {
+	case nfs_ok:
+		if (!svcxdr_encode_fattr(rqstp, xdr, &resp->fh, &resp->stat))
+			return 0;
+		if (xdr_stream_encode_u32(xdr, resp->count) < 0)
+			return 0;
+		xdr_write_pages(xdr, resp->pages, rqstp->rq_res.page_base,
+				resp->count);
+		if (svc_encode_result_payload(rqstp, head->iov_len, resp->count) < 0)
+			return 0;
+		break;
+	}
+
 	return 1;
 }
 
diff --git a/fs/nfsd/xdr.h b/fs/nfsd/xdr.h
index b868565c471f..277b74c511ce 100644
--- a/fs/nfsd/xdr.h
+++ b/fs/nfsd/xdr.h
@@ -102,6 +102,7 @@ struct nfsd_readres {
 	struct svc_fh		fh;
 	unsigned long		count;
 	struct kstat		stat;
+	struct page		**pages;
 };
 
 struct nfsd_readdirres {



^ permalink raw reply related	[flat|nested] 58+ messages in thread

* [PATCH v1 28/42] NFSD: Update the NFSv2 STATFS result encoder to use struct xdr_stream
  2021-03-01 15:15 [PATCH v1 00/42] NFSv2/3 XDR encoder overhaul Chuck Lever
                   ` (26 preceding siblings ...)
  2021-03-01 15:18 ` [PATCH v1 27/42] NFSD: Update the NFSv2 READ " Chuck Lever
@ 2021-03-01 15:18 ` Chuck Lever
  2021-03-01 15:18 ` [PATCH v1 29/42] NFSD: Add a helper that encodes NFSv3 directory offset cookies Chuck Lever
                   ` (13 subsequent siblings)
  41 siblings, 0 replies; 58+ messages in thread
From: Chuck Lever @ 2021-03-01 15:18 UTC (permalink / raw)
  To: linux-nfs

Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
---
 fs/nfsd/nfsxdr.c |   25 ++++++++++++++++---------
 1 file changed, 16 insertions(+), 9 deletions(-)

diff --git a/fs/nfsd/nfsxdr.c b/fs/nfsd/nfsxdr.c
index d6d7d07dbb1b..39d296aecd3e 100644
--- a/fs/nfsd/nfsxdr.c
+++ b/fs/nfsd/nfsxdr.c
@@ -592,19 +592,26 @@ nfssvc_encode_readdirres(struct svc_rqst *rqstp, __be32 *p)
 int
 nfssvc_encode_statfsres(struct svc_rqst *rqstp, __be32 *p)
 {
+	struct xdr_stream *xdr = &rqstp->rq_res_stream;
 	struct nfsd_statfsres *resp = rqstp->rq_resp;
 	struct kstatfs	*stat = &resp->stats;
 
-	*p++ = resp->status;
-	if (resp->status != nfs_ok)
-		return xdr_ressize_check(rqstp, p);
+	if (!svcxdr_encode_stat(xdr, resp->status))
+		return 0;
+	switch (resp->status) {
+	case nfs_ok:
+		p = xdr_reserve_space(xdr, XDR_UNIT * 5);
+		if (!p)
+			return 0;
+		*p++ = cpu_to_be32(NFSSVC_MAXBLKSIZE_V2);
+		*p++ = cpu_to_be32(stat->f_bsize);
+		*p++ = cpu_to_be32(stat->f_blocks);
+		*p++ = cpu_to_be32(stat->f_bfree);
+		*p = cpu_to_be32(stat->f_bavail);
+		break;
+	}
 
-	*p++ = htonl(NFSSVC_MAXBLKSIZE_V2);	/* max transfer size */
-	*p++ = htonl(stat->f_bsize);
-	*p++ = htonl(stat->f_blocks);
-	*p++ = htonl(stat->f_bfree);
-	*p++ = htonl(stat->f_bavail);
-	return xdr_ressize_check(rqstp, p);
+	return 1;
 }
 
 int



^ permalink raw reply related	[flat|nested] 58+ messages in thread

* [PATCH v1 29/42] NFSD: Add a helper that encodes NFSv3 directory offset cookies
  2021-03-01 15:15 [PATCH v1 00/42] NFSv2/3 XDR encoder overhaul Chuck Lever
                   ` (27 preceding siblings ...)
  2021-03-01 15:18 ` [PATCH v1 28/42] NFSD: Update the NFSv2 STATFS " Chuck Lever
@ 2021-03-01 15:18 ` Chuck Lever
  2021-03-01 15:18 ` [PATCH v1 30/42] NFSD: Count bytes instead of pages in the NFSv2 READDIR encoder Chuck Lever
                   ` (12 subsequent siblings)
  41 siblings, 0 replies; 58+ messages in thread
From: Chuck Lever @ 2021-03-01 15:18 UTC (permalink / raw)
  To: linux-nfs

Refactor: Add helper function similar to nfs3svc_encode_cookie3().

Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
---
 fs/nfsd/nfsproc.c |    3 +--
 fs/nfsd/nfsxdr.c  |   18 ++++++++++++++++--
 fs/nfsd/xdr.h     |    1 +
 3 files changed, 18 insertions(+), 4 deletions(-)

diff --git a/fs/nfsd/nfsproc.c b/fs/nfsd/nfsproc.c
index 2088bb0887ba..5a0dd6e23c85 100644
--- a/fs/nfsd/nfsproc.c
+++ b/fs/nfsd/nfsproc.c
@@ -595,8 +595,7 @@ nfsd_proc_readdir(struct svc_rqst *rqstp)
 				    &resp->common, nfssvc_encode_entry);
 
 	resp->count = resp->buffer - buffer;
-	if (resp->offset)
-		*resp->offset = htonl(offset);
+	nfssvc_encode_nfscookie(resp, offset);
 
 	fh_put(&argp->fh);
 	return rpc_success;
diff --git a/fs/nfsd/nfsxdr.c b/fs/nfsd/nfsxdr.c
index 39d296aecd3e..a87b21cfe0d0 100644
--- a/fs/nfsd/nfsxdr.c
+++ b/fs/nfsd/nfsxdr.c
@@ -614,6 +614,21 @@ nfssvc_encode_statfsres(struct svc_rqst *rqstp, __be32 *p)
 	return 1;
 }
 
+/**
+ * nfssvc_encode_nfscookie - Encode a directory offset cookie
+ * @resp: readdir result context
+ * @offset: offset cookie to encode
+ *
+ */
+void nfssvc_encode_nfscookie(struct nfsd_readdirres *resp, u32 offset)
+{
+	if (!resp->offset)
+		return;
+
+	*resp->offset = cpu_to_be32(offset);
+	resp->offset = NULL;
+}
+
 int
 nfssvc_encode_entry(void *ccdv, const char *name,
 		    int namlen, loff_t offset, u64 ino, unsigned int d_type)
@@ -632,8 +647,7 @@ nfssvc_encode_entry(void *ccdv, const char *name,
 		cd->common.err = nfserr_fbig;
 		return -EINVAL;
 	}
-	if (cd->offset)
-		*cd->offset = htonl(offset);
+	nfssvc_encode_nfscookie(cd, offset);
 
 	/* truncate filename */
 	namlen = min(namlen, NFS2_MAXNAMLEN);
diff --git a/fs/nfsd/xdr.h b/fs/nfsd/xdr.h
index 277b74c511ce..651de13e62fe 100644
--- a/fs/nfsd/xdr.h
+++ b/fs/nfsd/xdr.h
@@ -157,6 +157,7 @@ int nfssvc_encode_readres(struct svc_rqst *, __be32 *);
 int nfssvc_encode_statfsres(struct svc_rqst *, __be32 *);
 int nfssvc_encode_readdirres(struct svc_rqst *, __be32 *);
 
+void nfssvc_encode_nfscookie(struct nfsd_readdirres *resp, u32 offset);
 int nfssvc_encode_entry(void *, const char *name,
 			int namlen, loff_t offset, u64 ino, unsigned int);
 



^ permalink raw reply related	[flat|nested] 58+ messages in thread

* [PATCH v1 30/42] NFSD: Count bytes instead of pages in the NFSv2 READDIR encoder
  2021-03-01 15:15 [PATCH v1 00/42] NFSv2/3 XDR encoder overhaul Chuck Lever
                   ` (28 preceding siblings ...)
  2021-03-01 15:18 ` [PATCH v1 29/42] NFSD: Add a helper that encodes NFSv3 directory offset cookies Chuck Lever
@ 2021-03-01 15:18 ` Chuck Lever
  2021-03-01 15:18 ` [PATCH v1 31/42] NFSD: Update the NFSv2 READDIR result encoder to use struct xdr_stream Chuck Lever
                   ` (11 subsequent siblings)
  41 siblings, 0 replies; 58+ messages in thread
From: Chuck Lever @ 2021-03-01 15:18 UTC (permalink / raw)
  To: linux-nfs

Clean up: Counting the bytes used by each returned directory entry
seems less brittle to me than trying to measure consumed pages after
the fact.

Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
---
 fs/nfsd/nfsproc.c |    4 ----
 fs/nfsd/nfsxdr.c  |    3 ++-
 2 files changed, 2 insertions(+), 5 deletions(-)

diff --git a/fs/nfsd/nfsproc.c b/fs/nfsd/nfsproc.c
index 5a0dd6e23c85..1acff9f4aaf1 100644
--- a/fs/nfsd/nfsproc.c
+++ b/fs/nfsd/nfsproc.c
@@ -578,14 +578,12 @@ nfsd_proc_readdir(struct svc_rqst *rqstp)
 	struct nfsd_readdirargs *argp = rqstp->rq_argp;
 	struct nfsd_readdirres *resp = rqstp->rq_resp;
 	loff_t		offset;
-	__be32		*buffer;
 
 	dprintk("nfsd: READDIR  %s %d bytes at %d\n",
 		SVCFH_fmt(&argp->fh),		
 		argp->count, argp->cookie);
 
 	nfsd_init_dirlist_pages(rqstp, resp, argp->count);
-	buffer = resp->buffer;
 
 	resp->offset = NULL;
 	resp->common.err = nfs_ok;
@@ -593,8 +591,6 @@ nfsd_proc_readdir(struct svc_rqst *rqstp)
 	offset = argp->cookie;
 	resp->status = nfsd_readdir(rqstp, &argp->fh, &offset,
 				    &resp->common, nfssvc_encode_entry);
-
-	resp->count = resp->buffer - buffer;
 	nfssvc_encode_nfscookie(resp, offset);
 
 	fh_put(&argp->fh);
diff --git a/fs/nfsd/nfsxdr.c b/fs/nfsd/nfsxdr.c
index a87b21cfe0d0..8ae23ed6dc5d 100644
--- a/fs/nfsd/nfsxdr.c
+++ b/fs/nfsd/nfsxdr.c
@@ -584,7 +584,7 @@ nfssvc_encode_readdirres(struct svc_rqst *rqstp, __be32 *p)
 	p = resp->buffer;
 	*p++ = 0;			/* no more entries */
 	*p++ = htonl((resp->common.err == nfserr_eof));
-	rqstp->rq_res.page_len = (((unsigned long)p-1) & ~PAGE_MASK)+1;
+	rqstp->rq_res.page_len = resp->count << 2;
 
 	return 1;
 }
@@ -667,6 +667,7 @@ nfssvc_encode_entry(void *ccdv, const char *name,
 	cd->offset = p;			/* remember pointer */
 	*p++ = htonl(~0U);		/* offset of next entry */
 
+	cd->count += p - cd->buffer;
 	cd->buflen = buflen;
 	cd->buffer = p;
 	cd->common.err = nfs_ok;



^ permalink raw reply related	[flat|nested] 58+ messages in thread

* [PATCH v1 31/42] NFSD: Update the NFSv2 READDIR result encoder to use struct xdr_stream
  2021-03-01 15:15 [PATCH v1 00/42] NFSv2/3 XDR encoder overhaul Chuck Lever
                   ` (29 preceding siblings ...)
  2021-03-01 15:18 ` [PATCH v1 30/42] NFSD: Count bytes instead of pages in the NFSv2 READDIR encoder Chuck Lever
@ 2021-03-01 15:18 ` Chuck Lever
  2021-03-01 15:18 ` [PATCH v1 32/42] NFSD: Update the NFSv2 READDIR entry " Chuck Lever
                   ` (10 subsequent siblings)
  41 siblings, 0 replies; 58+ messages in thread
From: Chuck Lever @ 2021-03-01 15:18 UTC (permalink / raw)
  To: linux-nfs

Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
---
 fs/nfsd/nfsxdr.c |   22 +++++++++++++---------
 fs/nfsd/xdr.h    |    1 +
 2 files changed, 14 insertions(+), 9 deletions(-)

diff --git a/fs/nfsd/nfsxdr.c b/fs/nfsd/nfsxdr.c
index 8ae23ed6dc5d..9522e5c5f49d 100644
--- a/fs/nfsd/nfsxdr.c
+++ b/fs/nfsd/nfsxdr.c
@@ -574,17 +574,21 @@ nfssvc_encode_readres(struct svc_rqst *rqstp, __be32 *p)
 int
 nfssvc_encode_readdirres(struct svc_rqst *rqstp, __be32 *p)
 {
+	struct xdr_stream *xdr = &rqstp->rq_res_stream;
 	struct nfsd_readdirres *resp = rqstp->rq_resp;
 
-	*p++ = resp->status;
-	if (resp->status != nfs_ok)
-		return xdr_ressize_check(rqstp, p);
-
-	xdr_ressize_check(rqstp, p);
-	p = resp->buffer;
-	*p++ = 0;			/* no more entries */
-	*p++ = htonl((resp->common.err == nfserr_eof));
-	rqstp->rq_res.page_len = resp->count << 2;
+	if (!svcxdr_encode_stat(xdr, resp->status))
+		return 0;
+	switch (resp->status) {
+	case nfs_ok:
+		xdr_write_pages(xdr, &resp->page, 0, resp->count << 2);
+		/* no more entries */
+		if (xdr_stream_encode_item_absent(xdr) < 0)
+			return 0;
+		if (xdr_stream_encode_bool(xdr, resp->common.err == nfserr_eof) < 0)
+			return 0;
+		break;
+	}
 
 	return 1;
 }
diff --git a/fs/nfsd/xdr.h b/fs/nfsd/xdr.h
index 651de13e62fe..69a6efc71ecb 100644
--- a/fs/nfsd/xdr.h
+++ b/fs/nfsd/xdr.h
@@ -114,6 +114,7 @@ struct nfsd_readdirres {
 	__be32 *		buffer;
 	int			buflen;
 	__be32 *		offset;
+	struct page		*page;
 };
 
 struct nfsd_statfsres {



^ permalink raw reply related	[flat|nested] 58+ messages in thread

* [PATCH v1 32/42] NFSD: Update the NFSv2 READDIR entry encoder to use struct xdr_stream
  2021-03-01 15:15 [PATCH v1 00/42] NFSv2/3 XDR encoder overhaul Chuck Lever
                   ` (30 preceding siblings ...)
  2021-03-01 15:18 ` [PATCH v1 31/42] NFSD: Update the NFSv2 READDIR result encoder to use struct xdr_stream Chuck Lever
@ 2021-03-01 15:18 ` Chuck Lever
  2021-03-01 15:18 ` [PATCH v1 33/42] NFSD: Remove unused NFSv2 directory entry encoders Chuck Lever
                   ` (9 subsequent siblings)
  41 siblings, 0 replies; 58+ messages in thread
From: Chuck Lever @ 2021-03-01 15:18 UTC (permalink / raw)
  To: linux-nfs

Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
---
 fs/nfsd/nfsproc.c |   26 ++++++++++++-----
 fs/nfsd/nfsxdr.c  |   81 ++++++++++++++++++++++++++++++++++++++++++++++++++---
 fs/nfsd/xdr.h     |    7 +++++
 3 files changed, 103 insertions(+), 11 deletions(-)

diff --git a/fs/nfsd/nfsproc.c b/fs/nfsd/nfsproc.c
index 1acff9f4aaf1..86d438fbd576 100644
--- a/fs/nfsd/nfsproc.c
+++ b/fs/nfsd/nfsproc.c
@@ -559,14 +559,27 @@ static void nfsd_init_dirlist_pages(struct svc_rqst *rqstp,
 				    struct nfsd_readdirres *resp,
 				    int count)
 {
+	struct xdr_buf *buf = &resp->dirlist;
+	struct xdr_stream *xdr = &resp->xdr;
+
 	count = min_t(u32, count, PAGE_SIZE);
 
-	/* Convert byte count to number of words (i.e. >> 2),
-	 * and reserve room for the NULL ptr & eof flag (-2 words) */
-	resp->buflen = (count >> 2) - 2;
+	memset(buf, 0, sizeof(*buf));
 
-	resp->buffer = page_address(*rqstp->rq_next_page);
+	/* Reserve room for the NULL ptr & eof flag (-2 words) */
+	buf->buflen = count - sizeof(__be32) * 2;
+	buf->pages = rqstp->rq_next_page;
 	rqstp->rq_next_page++;
+
+	/* This is xdr_init_encode(), but it assumes that
+	 * the head kvec has already been consumed. */
+	xdr_set_scratch_buffer(xdr, NULL, 0);
+	xdr->buf = buf;
+	xdr->page_ptr = buf->pages;
+	xdr->iov = NULL;
+	xdr->p = page_address(*buf->pages);
+	xdr->end = xdr->p + (PAGE_SIZE >> 2);
+	xdr->rqst = NULL;
 }
 
 /*
@@ -585,12 +598,11 @@ nfsd_proc_readdir(struct svc_rqst *rqstp)
 
 	nfsd_init_dirlist_pages(rqstp, resp, argp->count);
 
-	resp->offset = NULL;
 	resp->common.err = nfs_ok;
-	/* Read directory and encode entries on the fly */
+	resp->cookie_offset = 0;
 	offset = argp->cookie;
 	resp->status = nfsd_readdir(rqstp, &argp->fh, &offset,
-				    &resp->common, nfssvc_encode_entry);
+				    &resp->common, nfs2svc_encode_entry);
 	nfssvc_encode_nfscookie(resp, offset);
 
 	fh_put(&argp->fh);
diff --git a/fs/nfsd/nfsxdr.c b/fs/nfsd/nfsxdr.c
index 9522e5c5f49d..1102d40ded03 100644
--- a/fs/nfsd/nfsxdr.c
+++ b/fs/nfsd/nfsxdr.c
@@ -576,12 +576,13 @@ nfssvc_encode_readdirres(struct svc_rqst *rqstp, __be32 *p)
 {
 	struct xdr_stream *xdr = &rqstp->rq_res_stream;
 	struct nfsd_readdirres *resp = rqstp->rq_resp;
+	struct xdr_buf *dirlist = &resp->dirlist;
 
 	if (!svcxdr_encode_stat(xdr, resp->status))
 		return 0;
 	switch (resp->status) {
 	case nfs_ok:
-		xdr_write_pages(xdr, &resp->page, 0, resp->count << 2);
+		xdr_write_pages(xdr, dirlist->pages, 0, dirlist->len);
 		/* no more entries */
 		if (xdr_stream_encode_item_absent(xdr) < 0)
 			return 0;
@@ -623,14 +624,86 @@ nfssvc_encode_statfsres(struct svc_rqst *rqstp, __be32 *p)
  * @resp: readdir result context
  * @offset: offset cookie to encode
  *
+ * The buffer space for the offset cookie has already been reserved
+ * by svcxdr_encode_entry_common().
  */
 void nfssvc_encode_nfscookie(struct nfsd_readdirres *resp, u32 offset)
 {
-	if (!resp->offset)
+	__be32 cookie = cpu_to_be32(offset);
+
+	if (!resp->cookie_offset)
 		return;
 
-	*resp->offset = cpu_to_be32(offset);
-	resp->offset = NULL;
+	write_bytes_to_xdr_buf(&resp->dirlist, resp->cookie_offset, &cookie,
+			       sizeof(cookie));
+	resp->cookie_offset = 0;
+}
+
+static bool
+svcxdr_encode_entry_common(struct nfsd_readdirres *resp, const char *name,
+			   int namlen, loff_t offset, u64 ino)
+{
+	struct xdr_buf *dirlist = &resp->dirlist;
+	struct xdr_stream *xdr = &resp->xdr;
+
+	if (xdr_stream_encode_item_present(xdr) < 0)
+		return false;
+	/* fileid */
+	if (xdr_stream_encode_u32(xdr, (u32)ino) < 0)
+		return false;
+	/* name */
+	if (xdr_stream_encode_opaque(xdr, name, min(namlen, NFS2_MAXNAMLEN)) < 0)
+		return false;
+	/* cookie */
+	resp->cookie_offset = dirlist->len;
+	if (xdr_stream_encode_u32(xdr, ~0U) < 0)
+		return false;
+
+	return true;
+}
+
+/**
+ * nfs2svc_encode_entry - encode one NFSv2 READDIR entry
+ * @data: directory context
+ * @name: name of the object to be encoded
+ * @namlen: length of that name, in bytes
+ * @offset: the offset of the previous entry
+ * @ino: the fileid of this entry
+ * @d_type: unused
+ *
+ * Return values:
+ *   %0: Entry was successfully encoded.
+ *   %-EINVAL: An encoding problem occured, secondary status code in resp->common.err
+ *
+ * On exit, the following fields are updated:
+ *   - resp->xdr
+ *   - resp->common.err
+ *   - resp->cookie_offset
+ */
+int nfs2svc_encode_entry(void *data, const char *name, int namlen,
+			 loff_t offset, u64 ino, unsigned int d_type)
+{
+	struct readdir_cd *ccd = data;
+	struct nfsd_readdirres *resp = container_of(ccd,
+						    struct nfsd_readdirres,
+						    common);
+	unsigned int starting_length = resp->dirlist.len;
+
+	/* The offset cookie for the previous entry */
+	nfssvc_encode_nfscookie(resp, offset);
+
+	if (!svcxdr_encode_entry_common(resp, name, namlen, offset, ino))
+		goto out_toosmall;
+
+	xdr_commit_encode(&resp->xdr);
+	resp->common.err = nfs_ok;
+	return 0;
+
+out_toosmall:
+	resp->cookie_offset = 0;
+	resp->common.err = nfserr_toosmall;
+	resp->dirlist.len = starting_length;
+	return -EINVAL;
 }
 
 int
diff --git a/fs/nfsd/xdr.h b/fs/nfsd/xdr.h
index 69a6efc71ecb..082f262a1bf9 100644
--- a/fs/nfsd/xdr.h
+++ b/fs/nfsd/xdr.h
@@ -106,15 +106,20 @@ struct nfsd_readres {
 };
 
 struct nfsd_readdirres {
+	/* Components of the reply */
 	__be32			status;
 
 	int			count;
 
+	/* Used to encode the reply's entry list */
+	struct xdr_stream	xdr;
+	struct xdr_buf		dirlist;
 	struct readdir_cd	common;
 	__be32 *		buffer;
 	int			buflen;
 	__be32 *		offset;
 	struct page		*page;
+	unsigned int		cookie_offset;
 };
 
 struct nfsd_statfsres {
@@ -159,6 +164,8 @@ int nfssvc_encode_statfsres(struct svc_rqst *, __be32 *);
 int nfssvc_encode_readdirres(struct svc_rqst *, __be32 *);
 
 void nfssvc_encode_nfscookie(struct nfsd_readdirres *resp, u32 offset);
+int nfs2svc_encode_entry(void *data, const char *name, int namlen,
+			 loff_t offset, u64 ino, unsigned int d_type);
 int nfssvc_encode_entry(void *, const char *name,
 			int namlen, loff_t offset, u64 ino, unsigned int);
 



^ permalink raw reply related	[flat|nested] 58+ messages in thread

* [PATCH v1 33/42] NFSD: Remove unused NFSv2 directory entry encoders
  2021-03-01 15:15 [PATCH v1 00/42] NFSv2/3 XDR encoder overhaul Chuck Lever
                   ` (31 preceding siblings ...)
  2021-03-01 15:18 ` [PATCH v1 32/42] NFSD: Update the NFSv2 READDIR entry " Chuck Lever
@ 2021-03-01 15:18 ` Chuck Lever
  2021-03-01 15:18 ` [PATCH v1 34/42] NFSD: Add an xdr_stream-based encoder for NFSv2/3 ACLs Chuck Lever
                   ` (8 subsequent siblings)
  41 siblings, 0 replies; 58+ messages in thread
From: Chuck Lever @ 2021-03-01 15:18 UTC (permalink / raw)
  To: linux-nfs

Clean up.

Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
---
 fs/nfsd/nfsproc.c |    2 +-
 fs/nfsd/nfsxdr.c  |   51 +++------------------------------------------------
 fs/nfsd/xdr.h     |   10 ++--------
 3 files changed, 6 insertions(+), 57 deletions(-)

diff --git a/fs/nfsd/nfsproc.c b/fs/nfsd/nfsproc.c
index 86d438fbd576..c2cd2984e41d 100644
--- a/fs/nfsd/nfsproc.c
+++ b/fs/nfsd/nfsproc.c
@@ -602,7 +602,7 @@ nfsd_proc_readdir(struct svc_rqst *rqstp)
 	resp->cookie_offset = 0;
 	offset = argp->cookie;
 	resp->status = nfsd_readdir(rqstp, &argp->fh, &offset,
-				    &resp->common, nfs2svc_encode_entry);
+				    &resp->common, nfssvc_encode_entry);
 	nfssvc_encode_nfscookie(resp, offset);
 
 	fh_put(&argp->fh);
diff --git a/fs/nfsd/nfsxdr.c b/fs/nfsd/nfsxdr.c
index 1102d40ded03..5df6f00d76fd 100644
--- a/fs/nfsd/nfsxdr.c
+++ b/fs/nfsd/nfsxdr.c
@@ -663,7 +663,7 @@ svcxdr_encode_entry_common(struct nfsd_readdirres *resp, const char *name,
 }
 
 /**
- * nfs2svc_encode_entry - encode one NFSv2 READDIR entry
+ * nfssvc_encode_entry - encode one NFSv2 READDIR entry
  * @data: directory context
  * @name: name of the object to be encoded
  * @namlen: length of that name, in bytes
@@ -680,8 +680,8 @@ svcxdr_encode_entry_common(struct nfsd_readdirres *resp, const char *name,
  *   - resp->common.err
  *   - resp->cookie_offset
  */
-int nfs2svc_encode_entry(void *data, const char *name, int namlen,
-			 loff_t offset, u64 ino, unsigned int d_type)
+int nfssvc_encode_entry(void *data, const char *name, int namlen,
+			loff_t offset, u64 ino, unsigned int d_type)
 {
 	struct readdir_cd *ccd = data;
 	struct nfsd_readdirres *resp = container_of(ccd,
@@ -706,51 +706,6 @@ int nfs2svc_encode_entry(void *data, const char *name, int namlen,
 	return -EINVAL;
 }
 
-int
-nfssvc_encode_entry(void *ccdv, const char *name,
-		    int namlen, loff_t offset, u64 ino, unsigned int d_type)
-{
-	struct readdir_cd *ccd = ccdv;
-	struct nfsd_readdirres *cd = container_of(ccd, struct nfsd_readdirres, common);
-	__be32	*p = cd->buffer;
-	int	buflen, slen;
-
-	/*
-	dprintk("nfsd: entry(%.*s off %ld ino %ld)\n",
-			namlen, name, offset, ino);
-	 */
-
-	if (offset > ~((u32) 0)) {
-		cd->common.err = nfserr_fbig;
-		return -EINVAL;
-	}
-	nfssvc_encode_nfscookie(cd, offset);
-
-	/* truncate filename */
-	namlen = min(namlen, NFS2_MAXNAMLEN);
-	slen = XDR_QUADLEN(namlen);
-
-	if ((buflen = cd->buflen - slen - 4) < 0) {
-		cd->common.err = nfserr_toosmall;
-		return -EINVAL;
-	}
-	if (ino > ~((u32) 0)) {
-		cd->common.err = nfserr_fbig;
-		return -EINVAL;
-	}
-	*p++ = xdr_one;				/* mark entry present */
-	*p++ = htonl((u32) ino);		/* file id */
-	p    = xdr_encode_array(p, name, namlen);/* name length & name */
-	cd->offset = p;			/* remember pointer */
-	*p++ = htonl(~0U);		/* offset of next entry */
-
-	cd->count += p - cd->buffer;
-	cd->buflen = buflen;
-	cd->buffer = p;
-	cd->common.err = nfs_ok;
-	return 0;
-}
-
 /*
  * XDR release functions
  */
diff --git a/fs/nfsd/xdr.h b/fs/nfsd/xdr.h
index 082f262a1bf9..bfffcb70a5f8 100644
--- a/fs/nfsd/xdr.h
+++ b/fs/nfsd/xdr.h
@@ -115,10 +115,6 @@ struct nfsd_readdirres {
 	struct xdr_stream	xdr;
 	struct xdr_buf		dirlist;
 	struct readdir_cd	common;
-	__be32 *		buffer;
-	int			buflen;
-	__be32 *		offset;
-	struct page		*page;
 	unsigned int		cookie_offset;
 };
 
@@ -164,10 +160,8 @@ int nfssvc_encode_statfsres(struct svc_rqst *, __be32 *);
 int nfssvc_encode_readdirres(struct svc_rqst *, __be32 *);
 
 void nfssvc_encode_nfscookie(struct nfsd_readdirres *resp, u32 offset);
-int nfs2svc_encode_entry(void *data, const char *name, int namlen,
-			 loff_t offset, u64 ino, unsigned int d_type);
-int nfssvc_encode_entry(void *, const char *name,
-			int namlen, loff_t offset, u64 ino, unsigned int);
+int nfssvc_encode_entry(void *data, const char *name, int namlen,
+			loff_t offset, u64 ino, unsigned int d_type);
 
 void nfssvc_release_attrstat(struct svc_rqst *rqstp);
 void nfssvc_release_diropres(struct svc_rqst *rqstp);



^ permalink raw reply related	[flat|nested] 58+ messages in thread

* [PATCH v1 34/42] NFSD: Add an xdr_stream-based encoder for NFSv2/3 ACLs
  2021-03-01 15:15 [PATCH v1 00/42] NFSv2/3 XDR encoder overhaul Chuck Lever
                   ` (32 preceding siblings ...)
  2021-03-01 15:18 ` [PATCH v1 33/42] NFSD: Remove unused NFSv2 directory entry encoders Chuck Lever
@ 2021-03-01 15:18 ` Chuck Lever
  2021-03-01 15:18 ` [PATCH v1 35/42] NFSD: Update the NFSv2 GETACL result encoder to use struct xdr_stream Chuck Lever
                   ` (7 subsequent siblings)
  41 siblings, 0 replies; 58+ messages in thread
From: Chuck Lever @ 2021-03-01 15:18 UTC (permalink / raw)
  To: linux-nfs

Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
---
 fs/nfs_common/nfsacl.c |   71 ++++++++++++++++++++++++++++++++++++++++++++++++
 include/linux/nfsacl.h |    3 ++
 2 files changed, 74 insertions(+)

diff --git a/fs/nfs_common/nfsacl.c b/fs/nfs_common/nfsacl.c
index 79c563c1a5e8..5a5bd85d08f8 100644
--- a/fs/nfs_common/nfsacl.c
+++ b/fs/nfs_common/nfsacl.c
@@ -136,6 +136,77 @@ int nfsacl_encode(struct xdr_buf *buf, unsigned int base, struct inode *inode,
 }
 EXPORT_SYMBOL_GPL(nfsacl_encode);
 
+/**
+ * nfs_stream_encode_acl - Encode an NFSv3 ACL
+ *
+ * @xdr: an xdr_stream positioned to receive an encoded ACL
+ * @inode: inode of file whose ACL this is
+ * @acl: posix_acl to encode
+ * @encode_entries: whether to encode ACEs as well
+ * @typeflag: ACL type: NFS_ACL_DEFAULT or zero
+ *
+ * Return values:
+ *   %false: The ACL could not be encoded
+ *   %true: @xdr is advanced to the next available position
+ */
+bool nfs_stream_encode_acl(struct xdr_stream *xdr, struct inode *inode,
+			   struct posix_acl *acl, int encode_entries,
+			   int typeflag)
+{
+	const size_t elem_size = XDR_UNIT * 3;
+	u32 entries = (acl && acl->a_count) ? max_t(int, acl->a_count, 4) : 0;
+	struct nfsacl_encode_desc nfsacl_desc = {
+		.desc = {
+			.elem_size = elem_size,
+			.array_len = encode_entries ? entries : 0,
+			.xcode = xdr_nfsace_encode,
+		},
+		.acl = acl,
+		.typeflag = typeflag,
+		.uid = inode->i_uid,
+		.gid = inode->i_gid,
+	};
+	struct nfsacl_simple_acl aclbuf;
+	unsigned int base;
+	int err;
+
+	if (entries > NFS_ACL_MAX_ENTRIES)
+		return false;
+	if (xdr_stream_encode_u32(xdr, entries) < 0)
+		return false;
+
+	if (encode_entries && acl && acl->a_count == 3) {
+		struct posix_acl *acl2 = &aclbuf.acl;
+
+		/* Avoid the use of posix_acl_alloc().  nfsacl_encode() is
+		 * invoked in contexts where a memory allocation failure is
+		 * fatal.  Fortunately this fake ACL is small enough to
+		 * construct on the stack. */
+		posix_acl_init(acl2, 4);
+
+		/* Insert entries in canonical order: other orders seem
+		 to confuse Solaris VxFS. */
+		acl2->a_entries[0] = acl->a_entries[0];  /* ACL_USER_OBJ */
+		acl2->a_entries[1] = acl->a_entries[1];  /* ACL_GROUP_OBJ */
+		acl2->a_entries[2] = acl->a_entries[1];  /* ACL_MASK */
+		acl2->a_entries[2].e_tag = ACL_MASK;
+		acl2->a_entries[3] = acl->a_entries[2];  /* ACL_OTHER */
+		nfsacl_desc.acl = acl2;
+	}
+
+	base = xdr_stream_pos(xdr);
+	if (!xdr_reserve_space(xdr, XDR_UNIT +
+			       elem_size * nfsacl_desc.desc.array_len))
+		return false;
+	err = xdr_encode_array2(xdr->buf, base, &nfsacl_desc.desc);
+	if (err)
+		return false;
+
+	return true;
+}
+EXPORT_SYMBOL_GPL(nfs_stream_encode_acl);
+
+
 struct nfsacl_decode_desc {
 	struct xdr_array2_desc desc;
 	unsigned int count;
diff --git a/include/linux/nfsacl.h b/include/linux/nfsacl.h
index 0ba99c513649..8e76a79cdc6a 100644
--- a/include/linux/nfsacl.h
+++ b/include/linux/nfsacl.h
@@ -41,5 +41,8 @@ nfsacl_decode(struct xdr_buf *buf, unsigned int base, unsigned int *aclcnt,
 extern bool
 nfs_stream_decode_acl(struct xdr_stream *xdr, unsigned int *aclcnt,
 		      struct posix_acl **pacl);
+extern bool
+nfs_stream_encode_acl(struct xdr_stream *xdr, struct inode *inode,
+		      struct posix_acl *acl, int encode_entries, int typeflag);
 
 #endif  /* __LINUX_NFSACL_H */



^ permalink raw reply related	[flat|nested] 58+ messages in thread

* [PATCH v1 35/42] NFSD: Update the NFSv2 GETACL result encoder to use struct xdr_stream
  2021-03-01 15:15 [PATCH v1 00/42] NFSv2/3 XDR encoder overhaul Chuck Lever
                   ` (33 preceding siblings ...)
  2021-03-01 15:18 ` [PATCH v1 34/42] NFSD: Add an xdr_stream-based encoder for NFSv2/3 ACLs Chuck Lever
@ 2021-03-01 15:18 ` Chuck Lever
  2021-03-01 15:18 ` [PATCH v1 36/42] NFSD: Update the NFSv2 SETACL " Chuck Lever
                   ` (6 subsequent siblings)
  41 siblings, 0 replies; 58+ messages in thread
From: Chuck Lever @ 2021-03-01 15:18 UTC (permalink / raw)
  To: linux-nfs

Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
---
 fs/nfsd/nfs2acl.c |   42 ++++++++++++++++--------------------------
 fs/nfsd/nfsxdr.c  |   24 ++++++++++++++++++++++--
 fs/nfsd/xdr.h     |    3 +++
 3 files changed, 41 insertions(+), 28 deletions(-)

diff --git a/fs/nfsd/nfs2acl.c b/fs/nfsd/nfs2acl.c
index 855e17772eba..4a15ae6fdbc2 100644
--- a/fs/nfsd/nfs2acl.c
+++ b/fs/nfsd/nfs2acl.c
@@ -242,51 +242,41 @@ static int nfsaclsvc_decode_accessargs(struct svc_rqst *rqstp, __be32 *p)
 /* GETACL */
 static int nfsaclsvc_encode_getaclres(struct svc_rqst *rqstp, __be32 *p)
 {
+	struct xdr_stream *xdr = &rqstp->rq_res_stream;
 	struct nfsd3_getaclres *resp = rqstp->rq_resp;
 	struct dentry *dentry = resp->fh.fh_dentry;
 	struct inode *inode;
-	struct kvec *head = rqstp->rq_res.head;
-	unsigned int base;
-	int n;
 	int w;
 
-	*p++ = resp->status;
-	if (resp->status != nfs_ok)
-		return xdr_ressize_check(rqstp, p);
+	if (!svcxdr_encode_stat(xdr, resp->status))
+		return 0;
 
-	/*
-	 * Since this is version 2, the check for nfserr in
-	 * nfsd_dispatch actually ensures the following cannot happen.
-	 * However, it seems fragile to depend on that.
-	 */
 	if (dentry == NULL || d_really_is_negative(dentry))
-		return 0;
+		return 1;
 	inode = d_inode(dentry);
 
-	p = nfs2svc_encode_fattr(rqstp, p, &resp->fh, &resp->stat);
-	*p++ = htonl(resp->mask);
-	if (!xdr_ressize_check(rqstp, p))
+	if (!svcxdr_encode_fattr(rqstp, xdr, &resp->fh, &resp->stat))
+		return 0;
+	if (xdr_stream_encode_u32(xdr, resp->mask) < 0)
 		return 0;
-	base = (char *)p - (char *)head->iov_base;
 
 	rqstp->rq_res.page_len = w = nfsacl_size(
 		(resp->mask & NFS_ACL)   ? resp->acl_access  : NULL,
 		(resp->mask & NFS_DFACL) ? resp->acl_default : NULL);
 	while (w > 0) {
 		if (!*(rqstp->rq_next_page++))
-			return 0;
+			return 1;
 		w -= PAGE_SIZE;
 	}
 
-	n = nfsacl_encode(&rqstp->rq_res, base, inode,
-			  resp->acl_access,
-			  resp->mask & NFS_ACL, 0);
-	if (n > 0)
-		n = nfsacl_encode(&rqstp->rq_res, base + n, inode,
-				  resp->acl_default,
-				  resp->mask & NFS_DFACL,
-				  NFS_ACL_DEFAULT);
-	return (n > 0);
+	if (!nfs_stream_encode_acl(xdr, inode, resp->acl_access,
+				   resp->mask & NFS_ACL, 0))
+		return 0;
+	if (!nfs_stream_encode_acl(xdr, inode, resp->acl_default,
+				   resp->mask & NFS_DFACL, NFS_ACL_DEFAULT))
+		return 0;
+
+	return 1;
 }
 
 static int nfsaclsvc_encode_attrstatres(struct svc_rqst *rqstp, __be32 *p)
diff --git a/fs/nfsd/nfsxdr.c b/fs/nfsd/nfsxdr.c
index 5df6f00d76fd..1fed3a8deb18 100644
--- a/fs/nfsd/nfsxdr.c
+++ b/fs/nfsd/nfsxdr.c
@@ -26,7 +26,16 @@ static const u32 nfs_ftypes[] = {
  * Basic NFSv2 data types (RFC 1094 Section 2.3)
  */
 
-static bool
+/**
+ * svcxdr_encode_stat - Encode an NFSv2 status code
+ * @xdr: XDR stream
+ * @status: status value to encode
+ *
+ * Return values:
+ *   %false: Send buffer space was exhausted
+ *   %true: Success
+ */
+bool
 svcxdr_encode_stat(struct xdr_stream *xdr, __be32 status)
 {
 	__be32 *p;
@@ -250,7 +259,18 @@ encode_fattr(struct svc_rqst *rqstp, __be32 *p, struct svc_fh *fhp,
 	return p;
 }
 
-static bool
+/**
+ * svcxdr_encode_fattr - Encode NFSv2 file attributes
+ * @rqstp: Context of a completed RPC transaction
+ * @xdr: XDR stream
+ * @fhp: File handle to encode
+ * @stat: Attributes to encode
+ *
+ * Return values:
+ *   %false: Send buffer space was exhausted
+ *   %true: Success
+ */
+bool
 svcxdr_encode_fattr(struct svc_rqst *rqstp, struct xdr_stream *xdr,
 		    const struct svc_fh *fhp, const struct kstat *stat)
 {
diff --git a/fs/nfsd/xdr.h b/fs/nfsd/xdr.h
index bfffcb70a5f8..ad7f7eabf41a 100644
--- a/fs/nfsd/xdr.h
+++ b/fs/nfsd/xdr.h
@@ -170,5 +170,8 @@ void nfssvc_release_readres(struct svc_rqst *rqstp);
 /* Helper functions for NFSv2 ACL code */
 __be32 *nfs2svc_encode_fattr(struct svc_rqst *rqstp, __be32 *p, struct svc_fh *fhp, struct kstat *stat);
 bool svcxdr_decode_fhandle(struct xdr_stream *xdr, struct svc_fh *fhp);
+bool svcxdr_encode_stat(struct xdr_stream *xdr, __be32 status);
+bool svcxdr_encode_fattr(struct svc_rqst *rqstp, struct xdr_stream *xdr,
+			 const struct svc_fh *fhp, const struct kstat *stat);
 
 #endif /* LINUX_NFSD_H */



^ permalink raw reply related	[flat|nested] 58+ messages in thread

* [PATCH v1 36/42] NFSD: Update the NFSv2 SETACL result encoder to use struct xdr_stream
  2021-03-01 15:15 [PATCH v1 00/42] NFSv2/3 XDR encoder overhaul Chuck Lever
                   ` (34 preceding siblings ...)
  2021-03-01 15:18 ` [PATCH v1 35/42] NFSD: Update the NFSv2 GETACL result encoder to use struct xdr_stream Chuck Lever
@ 2021-03-01 15:18 ` Chuck Lever
  2021-03-01 15:19 ` [PATCH v1 37/42] NFSD: Update the NFSv2 ACL GETATTR " Chuck Lever
                   ` (5 subsequent siblings)
  41 siblings, 0 replies; 58+ messages in thread
From: Chuck Lever @ 2021-03-01 15:18 UTC (permalink / raw)
  To: linux-nfs

The SETACL result encoder is exactly the same as the NFSv2
attrstatres decoder.

Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
---
 fs/nfsd/nfs2acl.c |    4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/fs/nfsd/nfs2acl.c b/fs/nfsd/nfs2acl.c
index 4a15ae6fdbc2..9c572ffa5e7b 100644
--- a/fs/nfsd/nfs2acl.c
+++ b/fs/nfsd/nfs2acl.c
@@ -365,8 +365,8 @@ static const struct svc_procedure nfsd_acl_procedures2[5] = {
 	[ACLPROC2_SETACL] = {
 		.pc_func = nfsacld_proc_setacl,
 		.pc_decode = nfsaclsvc_decode_setaclargs,
-		.pc_encode = nfsaclsvc_encode_attrstatres,
-		.pc_release = nfsaclsvc_release_attrstat,
+		.pc_encode = nfssvc_encode_attrstatres,
+		.pc_release = nfssvc_release_attrstat,
 		.pc_argsize = sizeof(struct nfsd3_setaclargs),
 		.pc_ressize = sizeof(struct nfsd_attrstat),
 		.pc_cachetype = RC_NOCACHE,



^ permalink raw reply related	[flat|nested] 58+ messages in thread

* [PATCH v1 37/42] NFSD: Update the NFSv2 ACL GETATTR result encoder to use struct xdr_stream
  2021-03-01 15:15 [PATCH v1 00/42] NFSv2/3 XDR encoder overhaul Chuck Lever
                   ` (35 preceding siblings ...)
  2021-03-01 15:18 ` [PATCH v1 36/42] NFSD: Update the NFSv2 SETACL " Chuck Lever
@ 2021-03-01 15:19 ` Chuck Lever
  2021-03-01 15:19 ` [PATCH v1 38/42] NFSD: Update the NFSv2 ACL ACCESS " Chuck Lever
                   ` (4 subsequent siblings)
  41 siblings, 0 replies; 58+ messages in thread
From: Chuck Lever @ 2021-03-01 15:19 UTC (permalink / raw)
  To: linux-nfs

Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
---
 fs/nfsd/nfs2acl.c |   24 ++----------------------
 1 file changed, 2 insertions(+), 22 deletions(-)

diff --git a/fs/nfsd/nfs2acl.c b/fs/nfsd/nfs2acl.c
index 9c572ffa5e7b..9270530a0c2f 100644
--- a/fs/nfsd/nfs2acl.c
+++ b/fs/nfsd/nfs2acl.c
@@ -279,19 +279,6 @@ static int nfsaclsvc_encode_getaclres(struct svc_rqst *rqstp, __be32 *p)
 	return 1;
 }
 
-static int nfsaclsvc_encode_attrstatres(struct svc_rqst *rqstp, __be32 *p)
-{
-	struct nfsd_attrstat *resp = rqstp->rq_resp;
-
-	*p++ = resp->status;
-	if (resp->status != nfs_ok)
-		goto out;
-
-	p = nfs2svc_encode_fattr(rqstp, p, &resp->fh, &resp->stat);
-out:
-	return xdr_ressize_check(rqstp, p);
-}
-
 /* ACCESS */
 static int nfsaclsvc_encode_accessres(struct svc_rqst *rqstp, __be32 *p)
 {
@@ -319,13 +306,6 @@ static void nfsaclsvc_release_getacl(struct svc_rqst *rqstp)
 	posix_acl_release(resp->acl_default);
 }
 
-static void nfsaclsvc_release_attrstat(struct svc_rqst *rqstp)
-{
-	struct nfsd_attrstat *resp = rqstp->rq_resp;
-
-	fh_put(&resp->fh);
-}
-
 static void nfsaclsvc_release_access(struct svc_rqst *rqstp)
 {
 	struct nfsd3_accessres *resp = rqstp->rq_resp;
@@ -376,8 +356,8 @@ static const struct svc_procedure nfsd_acl_procedures2[5] = {
 	[ACLPROC2_GETATTR] = {
 		.pc_func = nfsacld_proc_getattr,
 		.pc_decode = nfssvc_decode_fhandleargs,
-		.pc_encode = nfsaclsvc_encode_attrstatres,
-		.pc_release = nfsaclsvc_release_attrstat,
+		.pc_encode = nfssvc_encode_attrstatres,
+		.pc_release = nfssvc_release_attrstat,
 		.pc_argsize = sizeof(struct nfsd_fhandle),
 		.pc_ressize = sizeof(struct nfsd_attrstat),
 		.pc_cachetype = RC_NOCACHE,



^ permalink raw reply related	[flat|nested] 58+ messages in thread

* [PATCH v1 38/42] NFSD: Update the NFSv2 ACL ACCESS result encoder to use struct xdr_stream
  2021-03-01 15:15 [PATCH v1 00/42] NFSv2/3 XDR encoder overhaul Chuck Lever
                   ` (36 preceding siblings ...)
  2021-03-01 15:19 ` [PATCH v1 37/42] NFSD: Update the NFSv2 ACL GETATTR " Chuck Lever
@ 2021-03-01 15:19 ` Chuck Lever
  2021-03-01 15:19 ` [PATCH v1 39/42] NFSD: Clean up after updating NFSv2 ACL encoders Chuck Lever
                   ` (3 subsequent siblings)
  41 siblings, 0 replies; 58+ messages in thread
From: Chuck Lever @ 2021-03-01 15:19 UTC (permalink / raw)
  To: linux-nfs

Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
---
 fs/nfsd/nfs2acl.c |   19 ++++++++++++-------
 1 file changed, 12 insertions(+), 7 deletions(-)

diff --git a/fs/nfsd/nfs2acl.c b/fs/nfsd/nfs2acl.c
index 9270530a0c2f..4b43929c1f25 100644
--- a/fs/nfsd/nfs2acl.c
+++ b/fs/nfsd/nfs2acl.c
@@ -282,16 +282,21 @@ static int nfsaclsvc_encode_getaclres(struct svc_rqst *rqstp, __be32 *p)
 /* ACCESS */
 static int nfsaclsvc_encode_accessres(struct svc_rqst *rqstp, __be32 *p)
 {
+	struct xdr_stream *xdr = &rqstp->rq_res_stream;
 	struct nfsd3_accessres *resp = rqstp->rq_resp;
 
-	*p++ = resp->status;
-	if (resp->status != nfs_ok)
-		goto out;
+	if (!svcxdr_encode_stat(xdr, resp->status))
+		return 0;
+	switch (resp->status) {
+	case nfs_ok:
+		if (!svcxdr_encode_fattr(rqstp, xdr, &resp->fh, &resp->stat))
+			return 0;
+		if (xdr_stream_encode_u32(xdr, resp->access) < 0)
+			return 0;
+		break;
+	}
 
-	p = nfs2svc_encode_fattr(rqstp, p, &resp->fh, &resp->stat);
-	*p++ = htonl(resp->access);
-out:
-	return xdr_ressize_check(rqstp, p);
+	return 1;
 }
 
 /*



^ permalink raw reply related	[flat|nested] 58+ messages in thread

* [PATCH v1 39/42] NFSD: Clean up after updating NFSv2 ACL encoders
  2021-03-01 15:15 [PATCH v1 00/42] NFSv2/3 XDR encoder overhaul Chuck Lever
                   ` (37 preceding siblings ...)
  2021-03-01 15:19 ` [PATCH v1 38/42] NFSD: Update the NFSv2 ACL ACCESS " Chuck Lever
@ 2021-03-01 15:19 ` Chuck Lever
  2021-03-01 15:19 ` [PATCH v1 40/42] NFSD: Update the NFSv3 GETACL result encoder to use struct xdr_stream Chuck Lever
                   ` (2 subsequent siblings)
  41 siblings, 0 replies; 58+ messages in thread
From: Chuck Lever @ 2021-03-01 15:19 UTC (permalink / raw)
  To: linux-nfs

Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
---
 fs/nfsd/nfsxdr.c |   64 ------------------------------------------------------
 fs/nfsd/xdr.h    |    1 -
 2 files changed, 65 deletions(-)

diff --git a/fs/nfsd/nfsxdr.c b/fs/nfsd/nfsxdr.c
index 1fed3a8deb18..b800cfefcab7 100644
--- a/fs/nfsd/nfsxdr.c
+++ b/fs/nfsd/nfsxdr.c
@@ -201,64 +201,6 @@ svcxdr_decode_sattr(struct svc_rqst *rqstp, struct xdr_stream *xdr,
 	return true;
 }
 
-static __be32 *
-encode_fattr(struct svc_rqst *rqstp, __be32 *p, struct svc_fh *fhp,
-	     struct kstat *stat)
-{
-	struct user_namespace *userns = nfsd_user_namespace(rqstp);
-	struct dentry	*dentry = fhp->fh_dentry;
-	int type;
-	struct timespec64 time;
-	u32 f;
-
-	type = (stat->mode & S_IFMT);
-
-	*p++ = htonl(nfs_ftypes[type >> 12]);
-	*p++ = htonl((u32) stat->mode);
-	*p++ = htonl((u32) stat->nlink);
-	*p++ = htonl((u32) from_kuid_munged(userns, stat->uid));
-	*p++ = htonl((u32) from_kgid_munged(userns, stat->gid));
-
-	if (S_ISLNK(type) && stat->size > NFS_MAXPATHLEN) {
-		*p++ = htonl(NFS_MAXPATHLEN);
-	} else {
-		*p++ = htonl((u32) stat->size);
-	}
-	*p++ = htonl((u32) stat->blksize);
-	if (S_ISCHR(type) || S_ISBLK(type))
-		*p++ = htonl(new_encode_dev(stat->rdev));
-	else
-		*p++ = htonl(0xffffffff);
-	*p++ = htonl((u32) stat->blocks);
-	switch (fsid_source(fhp)) {
-	default:
-	case FSIDSOURCE_DEV:
-		*p++ = htonl(new_encode_dev(stat->dev));
-		break;
-	case FSIDSOURCE_FSID:
-		*p++ = htonl((u32) fhp->fh_export->ex_fsid);
-		break;
-	case FSIDSOURCE_UUID:
-		f = ((u32*)fhp->fh_export->ex_uuid)[0];
-		f ^= ((u32*)fhp->fh_export->ex_uuid)[1];
-		f ^= ((u32*)fhp->fh_export->ex_uuid)[2];
-		f ^= ((u32*)fhp->fh_export->ex_uuid)[3];
-		*p++ = htonl(f);
-		break;
-	}
-	*p++ = htonl((u32) stat->ino);
-	*p++ = htonl((u32) stat->atime.tv_sec);
-	*p++ = htonl(stat->atime.tv_nsec ? stat->atime.tv_nsec / 1000 : 0);
-	time = stat->mtime;
-	lease_get_mtime(d_inode(dentry), &time); 
-	*p++ = htonl((u32) time.tv_sec);
-	*p++ = htonl(time.tv_nsec ? time.tv_nsec / 1000 : 0); 
-	*p++ = htonl((u32) stat->ctime.tv_sec);
-	*p++ = htonl(stat->ctime.tv_nsec ? stat->ctime.tv_nsec / 1000 : 0);
-
-	return p;
-}
-
 /**
  * svcxdr_encode_fattr - Encode NFSv2 file attributes
  * @rqstp: Context of a completed RPC transaction
@@ -328,12 +270,6 @@ svcxdr_encode_fattr(struct svc_rqst *rqstp, struct xdr_stream *xdr,
 	return true;
 }
 
-/* Helper function for NFSv2 ACL code */
-__be32 *nfs2svc_encode_fattr(struct svc_rqst *rqstp, __be32 *p, struct svc_fh *fhp, struct kstat *stat)
-{
-	return encode_fattr(rqstp, p, fhp, stat);
-}
-
 /*
  * XDR decode functions
  */
diff --git a/fs/nfsd/xdr.h b/fs/nfsd/xdr.h
index ad7f7eabf41a..f45b4bc93f52 100644
--- a/fs/nfsd/xdr.h
+++ b/fs/nfsd/xdr.h
@@ -168,7 +168,6 @@ void nfssvc_release_diropres(struct svc_rqst *rqstp);
 void nfssvc_release_readres(struct svc_rqst *rqstp);
 
 /* Helper functions for NFSv2 ACL code */
-__be32 *nfs2svc_encode_fattr(struct svc_rqst *rqstp, __be32 *p, struct svc_fh *fhp, struct kstat *stat);
 bool svcxdr_decode_fhandle(struct xdr_stream *xdr, struct svc_fh *fhp);
 bool svcxdr_encode_stat(struct xdr_stream *xdr, __be32 status);
 bool svcxdr_encode_fattr(struct svc_rqst *rqstp, struct xdr_stream *xdr,



^ permalink raw reply related	[flat|nested] 58+ messages in thread

* [PATCH v1 40/42] NFSD: Update the NFSv3 GETACL result encoder to use struct xdr_stream
  2021-03-01 15:15 [PATCH v1 00/42] NFSv2/3 XDR encoder overhaul Chuck Lever
                   ` (38 preceding siblings ...)
  2021-03-01 15:19 ` [PATCH v1 39/42] NFSD: Clean up after updating NFSv2 ACL encoders Chuck Lever
@ 2021-03-01 15:19 ` Chuck Lever
  2021-03-01 15:19 ` [PATCH v1 41/42] NFSD: Update the NFSv3 SETACL " Chuck Lever
  2021-03-01 15:19 ` [PATCH v1 42/42] NFSD: Clean up after updating NFSv3 ACL encoders Chuck Lever
  41 siblings, 0 replies; 58+ messages in thread
From: Chuck Lever @ 2021-03-01 15:19 UTC (permalink / raw)
  To: linux-nfs

Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
---
 fs/nfsd/nfs3acl.c |   33 +++++++++++++++++++--------------
 fs/nfsd/nfs3xdr.c |   23 +++++++++++++++++++++--
 fs/nfsd/xdr3.h    |    3 +++
 3 files changed, 43 insertions(+), 16 deletions(-)

diff --git a/fs/nfsd/nfs3acl.c b/fs/nfsd/nfs3acl.c
index 9a6f18d74d14..11991026ab3a 100644
--- a/fs/nfsd/nfs3acl.c
+++ b/fs/nfsd/nfs3acl.c
@@ -168,22 +168,25 @@ static int nfs3svc_decode_setaclargs(struct svc_rqst *rqstp, __be32 *p)
 /* GETACL */
 static int nfs3svc_encode_getaclres(struct svc_rqst *rqstp, __be32 *p)
 {
+	struct xdr_stream *xdr = &rqstp->rq_res_stream;
 	struct nfsd3_getaclres *resp = rqstp->rq_resp;
 	struct dentry *dentry = resp->fh.fh_dentry;
+	struct kvec *head = rqstp->rq_res.head;
+	struct inode *inode = d_inode(dentry);
+	unsigned int base;
+	int n;
+	int w;
 
-	*p++ = resp->status;
-	p = nfs3svc_encode_post_op_attr(rqstp, p, &resp->fh);
-	if (resp->status == 0 && dentry && d_really_is_positive(dentry)) {
-		struct inode *inode = d_inode(dentry);
-		struct kvec *head = rqstp->rq_res.head;
-		unsigned int base;
-		int n;
-		int w;
-
-		*p++ = htonl(resp->mask);
-		if (!xdr_ressize_check(rqstp, p))
+	if (!svcxdr_encode_nfsstat3(xdr, resp->status))
+		return 0;
+	switch (resp->status) {
+	case nfs_ok:
+		if (!svcxdr_encode_post_op_attr(rqstp, xdr, &resp->fh))
 			return 0;
-		base = (char *)p - (char *)head->iov_base;
+		if (xdr_stream_encode_u32(xdr, resp->mask) < 0)
+			return 0;
+
+		base = (char *)xdr->p - (char *)head->iov_base;
 
 		rqstp->rq_res.page_len = w = nfsacl_size(
 			(resp->mask & NFS_ACL)   ? resp->acl_access  : NULL,
@@ -204,9 +207,11 @@ static int nfs3svc_encode_getaclres(struct svc_rqst *rqstp, __be32 *p)
 					  NFS_ACL_DEFAULT);
 		if (n <= 0)
 			return 0;
-	} else
-		if (!xdr_ressize_check(rqstp, p))
+		break;
+	default:
+		if (!svcxdr_encode_post_op_attr(rqstp, xdr, &resp->fh))
 			return 0;
+	}
 
 	return 1;
 }
diff --git a/fs/nfsd/nfs3xdr.c b/fs/nfsd/nfs3xdr.c
index a37ea9fb8214..b8f894e00b6d 100644
--- a/fs/nfsd/nfs3xdr.c
+++ b/fs/nfsd/nfs3xdr.c
@@ -107,7 +107,16 @@ svcxdr_decode_nfs_fh3(struct xdr_stream *xdr, struct svc_fh *fhp)
 	return true;
 }
 
-static bool
+/**
+ * svcxdr_encode_nfsstat3 - Encode an NFSv3 status code
+ * @xdr: XDR stream
+ * @status: status value to encode
+ *
+ * Return values:
+ *   %false: Send buffer space was exhausted
+ *   %true: Success
+ */
+bool
 svcxdr_encode_nfsstat3(struct xdr_stream *xdr, __be32 status)
 {
 	__be32 *p;
@@ -464,7 +473,17 @@ svcxdr_encode_pre_op_attr(struct xdr_stream *xdr, const struct svc_fh *fhp)
 	return svcxdr_encode_wcc_attr(xdr, fhp);
 }
 
-static bool
+/**
+ * svcxdr_encode_post_op_attr - Encode NFSv3 post-op attributes
+ * @rqstp: Context of a completed RPC transaction
+ * @xdr: XDR stream
+ * @fhp: File handle to encode
+ *
+ * Return values:
+ *   %false: Send buffer space was exhausted
+ *   %true: Success
+ */
+bool
 svcxdr_encode_post_op_attr(struct svc_rqst *rqstp, struct xdr_stream *xdr,
 			   const struct svc_fh *fhp)
 {
diff --git a/fs/nfsd/xdr3.h b/fs/nfsd/xdr3.h
index b851458373db..746c5f79964f 100644
--- a/fs/nfsd/xdr3.h
+++ b/fs/nfsd/xdr3.h
@@ -308,5 +308,8 @@ int nfs3svc_encode_entryplus3(void *data, const char *name, int namlen,
 __be32 *nfs3svc_encode_post_op_attr(struct svc_rqst *rqstp, __be32 *p,
 				struct svc_fh *fhp);
 bool svcxdr_decode_nfs_fh3(struct xdr_stream *xdr, struct svc_fh *fhp);
+bool svcxdr_encode_nfsstat3(struct xdr_stream *xdr, __be32 status);
+bool svcxdr_encode_post_op_attr(struct svc_rqst *rqstp, struct xdr_stream *xdr,
+				const struct svc_fh *fhp);
 
 #endif /* _LINUX_NFSD_XDR3_H */



^ permalink raw reply related	[flat|nested] 58+ messages in thread

* [PATCH v1 41/42] NFSD: Update the NFSv3 SETACL result encoder to use struct xdr_stream
  2021-03-01 15:15 [PATCH v1 00/42] NFSv2/3 XDR encoder overhaul Chuck Lever
                   ` (39 preceding siblings ...)
  2021-03-01 15:19 ` [PATCH v1 40/42] NFSD: Update the NFSv3 GETACL result encoder to use struct xdr_stream Chuck Lever
@ 2021-03-01 15:19 ` Chuck Lever
  2021-03-01 15:19 ` [PATCH v1 42/42] NFSD: Clean up after updating NFSv3 ACL encoders Chuck Lever
  41 siblings, 0 replies; 58+ messages in thread
From: Chuck Lever @ 2021-03-01 15:19 UTC (permalink / raw)
  To: linux-nfs

Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
---
 fs/nfsd/nfs3acl.c |    6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/fs/nfsd/nfs3acl.c b/fs/nfsd/nfs3acl.c
index 11991026ab3a..a1591feeea22 100644
--- a/fs/nfsd/nfs3acl.c
+++ b/fs/nfsd/nfs3acl.c
@@ -219,11 +219,11 @@ static int nfs3svc_encode_getaclres(struct svc_rqst *rqstp, __be32 *p)
 /* SETACL */
 static int nfs3svc_encode_setaclres(struct svc_rqst *rqstp, __be32 *p)
 {
+	struct xdr_stream *xdr = &rqstp->rq_res_stream;
 	struct nfsd3_attrstat *resp = rqstp->rq_resp;
 
-	*p++ = resp->status;
-	p = nfs3svc_encode_post_op_attr(rqstp, p, &resp->fh);
-	return xdr_ressize_check(rqstp, p);
+	return svcxdr_encode_nfsstat3(xdr, resp->status) &&
+		svcxdr_encode_post_op_attr(rqstp, xdr, &resp->fh);
 }
 
 /*



^ permalink raw reply related	[flat|nested] 58+ messages in thread

* [PATCH v1 42/42] NFSD: Clean up after updating NFSv3 ACL encoders
  2021-03-01 15:15 [PATCH v1 00/42] NFSv2/3 XDR encoder overhaul Chuck Lever
                   ` (40 preceding siblings ...)
  2021-03-01 15:19 ` [PATCH v1 41/42] NFSD: Update the NFSv3 SETACL " Chuck Lever
@ 2021-03-01 15:19 ` Chuck Lever
  41 siblings, 0 replies; 58+ messages in thread
From: Chuck Lever @ 2021-03-01 15:19 UTC (permalink / raw)
  To: linux-nfs

Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
---
 fs/nfsd/nfs3xdr.c |   86 -----------------------------------------------------
 fs/nfsd/xdr3.h    |    2 -
 2 files changed, 88 deletions(-)

diff --git a/fs/nfsd/nfs3xdr.c b/fs/nfsd/nfs3xdr.c
index b8f894e00b6d..6989a3c8452e 100644
--- a/fs/nfsd/nfs3xdr.c
+++ b/fs/nfsd/nfs3xdr.c
@@ -48,13 +48,6 @@ static const u32 nfs3_ftypes[] = {
  * Basic NFSv3 data types (RFC 1813 Sections 2.5 and 2.6)
  */
 
-static __be32 *
-encode_time3(__be32 *p, struct timespec64 *time)
-{
-	*p++ = htonl((u32) time->tv_sec); *p++ = htonl(time->tv_nsec);
-	return p;
-}
-
 static __be32 *
 encode_nfstime3(__be32 *p, const struct timespec64 *time)
 {
@@ -396,54 +389,6 @@ svcxdr_encode_fattr3(struct svc_rqst *rqstp, struct xdr_stream *xdr,
 	return true;
 }
 
-static __be32 *encode_fsid(__be32 *p, struct svc_fh *fhp)
-{
-	u64 f;
-	switch(fsid_source(fhp)) {
-	default:
-	case FSIDSOURCE_DEV:
-		p = xdr_encode_hyper(p, (u64)huge_encode_dev
-				     (fhp->fh_dentry->d_sb->s_dev));
-		break;
-	case FSIDSOURCE_FSID:
-		p = xdr_encode_hyper(p, (u64) fhp->fh_export->ex_fsid);
-		break;
-	case FSIDSOURCE_UUID:
-		f = ((u64*)fhp->fh_export->ex_uuid)[0];
-		f ^= ((u64*)fhp->fh_export->ex_uuid)[1];
-		p = xdr_encode_hyper(p, f);
-		break;
-	}
-	return p;
-}
-
-static __be32 *
-encode_fattr3(struct svc_rqst *rqstp, __be32 *p, struct svc_fh *fhp,
-	      struct kstat *stat)
-{
-	struct user_namespace *userns = nfsd_user_namespace(rqstp);
-	*p++ = htonl(nfs3_ftypes[(stat->mode & S_IFMT) >> 12]);
-	*p++ = htonl((u32) (stat->mode & S_IALLUGO));
-	*p++ = htonl((u32) stat->nlink);
-	*p++ = htonl((u32) from_kuid_munged(userns, stat->uid));
-	*p++ = htonl((u32) from_kgid_munged(userns, stat->gid));
-	if (S_ISLNK(stat->mode) && stat->size > NFS3_MAXPATHLEN) {
-		p = xdr_encode_hyper(p, (u64) NFS3_MAXPATHLEN);
-	} else {
-		p = xdr_encode_hyper(p, (u64) stat->size);
-	}
-	p = xdr_encode_hyper(p, ((u64)stat->blocks) << 9);
-	*p++ = htonl((u32) MAJOR(stat->rdev));
-	*p++ = htonl((u32) MINOR(stat->rdev));
-	p = encode_fsid(p, fhp);
-	p = xdr_encode_hyper(p, stat->ino);
-	p = encode_time3(p, &stat->atime);
-	p = encode_time3(p, &stat->mtime);
-	p = encode_time3(p, &stat->ctime);
-
-	return p;
-}
-
 static bool
 svcxdr_encode_wcc_attr(struct xdr_stream *xdr, const struct svc_fh *fhp)
 {
@@ -512,37 +457,6 @@ svcxdr_encode_post_op_attr(struct svc_rqst *rqstp, struct xdr_stream *xdr,
 	return xdr_stream_encode_item_absent(xdr) > 0;
 }
 
-/*
- * Encode post-operation attributes.
- * The inode may be NULL if the call failed because of a stale file
- * handle. In this case, no attributes are returned.
- */
-static __be32 *
-encode_post_op_attr(struct svc_rqst *rqstp, __be32 *p, struct svc_fh *fhp)
-{
-	struct dentry *dentry = fhp->fh_dentry;
-	if (!fhp->fh_no_wcc && dentry && d_really_is_positive(dentry)) {
-	        __be32 err;
-		struct kstat stat;
-
-		err = fh_getattr(fhp, &stat);
-		if (!err) {
-			*p++ = xdr_one;		/* attributes follow */
-			lease_get_mtime(d_inode(dentry), &stat.mtime);
-			return encode_fattr3(rqstp, p, fhp, &stat);
-		}
-	}
-	*p++ = xdr_zero;
-	return p;
-}
-
-/* Helper for NFSv3 ACLs */
-__be32 *
-nfs3svc_encode_post_op_attr(struct svc_rqst *rqstp, __be32 *p, struct svc_fh *fhp)
-{
-	return encode_post_op_attr(rqstp, p, fhp);
-}
-
 /*
  * Encode weak cache consistency data
  */
diff --git a/fs/nfsd/xdr3.h b/fs/nfsd/xdr3.h
index 746c5f79964f..933008382bbe 100644
--- a/fs/nfsd/xdr3.h
+++ b/fs/nfsd/xdr3.h
@@ -305,8 +305,6 @@ int nfs3svc_encode_entry3(void *data, const char *name, int namlen,
 int nfs3svc_encode_entryplus3(void *data, const char *name, int namlen,
 			      loff_t offset, u64 ino, unsigned int d_type);
 /* Helper functions for NFSv3 ACL code */
-__be32 *nfs3svc_encode_post_op_attr(struct svc_rqst *rqstp, __be32 *p,
-				struct svc_fh *fhp);
 bool svcxdr_decode_nfs_fh3(struct xdr_stream *xdr, struct svc_fh *fhp);
 bool svcxdr_encode_nfsstat3(struct xdr_stream *xdr, __be32 status);
 bool svcxdr_encode_post_op_attr(struct svc_rqst *rqstp, struct xdr_stream *xdr,



^ permalink raw reply related	[flat|nested] 58+ messages in thread

* Re: [PATCH v1 01/42] NFSD: Extract the svcxdr_init_encode() helper
  2021-03-01 15:15 ` [PATCH v1 01/42] NFSD: Extract the svcxdr_init_encode() helper Chuck Lever
@ 2021-03-02 16:47   ` J. Bruce Fields
  2021-03-02 16:57     ` Chuck Lever
  0 siblings, 1 reply; 58+ messages in thread
From: J. Bruce Fields @ 2021-03-02 16:47 UTC (permalink / raw)
  To: Chuck Lever; +Cc: linux-nfs

On Mon, Mar 01, 2021 at 10:15:24AM -0500, Chuck Lever wrote:
> NFSD initializes an encode xdr_stream only after the RPC layer has
> already inserted the RPC Reply header.

Out of curiosity: does it need to be this way?

--b.

> Thus it behaves differently
> than xdr_init_encode does, which assumes the passed-in xdr_buf is
> entirely devoid of content.
> 
> nfs4proc.c has this server-side stream initialization helper, but
> it is visible only to the NFSv4 code. Move this helper to a place
> that can be accessed by NFSv2 and NFSv3 server XDR functions.
> 
> Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
> ---
>  fs/nfsd/nfs4proc.c         |   31 +++---------
>  fs/nfsd/nfs4state.c        |    6 +-
>  fs/nfsd/nfs4xdr.c          |  110 ++++++++++++++++++++++----------------------
>  fs/nfsd/nfssvc.c           |    4 +-
>  fs/nfsd/xdr4.h             |    2 -
>  include/linux/sunrpc/svc.h |   25 ++++++++++
>  6 files changed, 94 insertions(+), 84 deletions(-)
> 
> diff --git a/fs/nfsd/nfs4proc.c b/fs/nfsd/nfs4proc.c
> index acdb3cd806a1..b749033e467f 100644
> --- a/fs/nfsd/nfs4proc.c
> +++ b/fs/nfsd/nfs4proc.c
> @@ -2262,25 +2262,6 @@ static bool need_wrongsec_check(struct svc_rqst *rqstp)
>  	return !(nextd->op_flags & OP_HANDLES_WRONGSEC);
>  }
>  
> -static void svcxdr_init_encode(struct svc_rqst *rqstp,
> -			       struct nfsd4_compoundres *resp)
> -{
> -	struct xdr_stream *xdr = &resp->xdr;
> -	struct xdr_buf *buf = &rqstp->rq_res;
> -	struct kvec *head = buf->head;
> -
> -	xdr->buf = buf;
> -	xdr->iov = head;
> -	xdr->p   = head->iov_base + head->iov_len;
> -	xdr->end = head->iov_base + PAGE_SIZE - rqstp->rq_auth_slack;
> -	/* Tail and page_len should be zero at this point: */
> -	buf->len = buf->head[0].iov_len;
> -	xdr_reset_scratch_buffer(xdr);
> -	xdr->page_ptr = buf->pages - 1;
> -	buf->buflen = PAGE_SIZE * (1 + rqstp->rq_page_end - buf->pages)
> -		- rqstp->rq_auth_slack;
> -}
> -
>  #ifdef CONFIG_NFSD_V4_2_INTER_SSC
>  static void
>  check_if_stalefh_allowed(struct nfsd4_compoundargs *args)
> @@ -2335,10 +2316,14 @@ nfsd4_proc_compound(struct svc_rqst *rqstp)
>  	struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id);
>  	__be32		status;
>  
> -	svcxdr_init_encode(rqstp, resp);
> -	resp->tagp = resp->xdr.p;
> +	resp->xdr = &rqstp->rq_res_stream;
> +
> +	/* reserve space for: NFS status code */
> +	xdr_reserve_space(resp->xdr, XDR_UNIT);
> +
> +	resp->tagp = resp->xdr->p;
>  	/* reserve space for: taglen, tag, and opcnt */
> -	xdr_reserve_space(&resp->xdr, 8 + args->taglen);
> +	xdr_reserve_space(resp->xdr, XDR_UNIT * 2 + args->taglen);
>  	resp->taglen = args->taglen;
>  	resp->tag = args->tag;
>  	resp->rqstp = rqstp;
> @@ -2444,7 +2429,7 @@ nfsd4_proc_compound(struct svc_rqst *rqstp)
>  encode_op:
>  		if (op->status == nfserr_replay_me) {
>  			op->replay = &cstate->replay_owner->so_replay;
> -			nfsd4_encode_replay(&resp->xdr, op);
> +			nfsd4_encode_replay(resp->xdr, op);
>  			status = op->status = op->replay->rp_status;
>  		} else {
>  			nfsd4_encode_operation(resp, op);
> diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c
> index 61552e89bd89..83a498ccab19 100644
> --- a/fs/nfsd/nfs4state.c
> +++ b/fs/nfsd/nfs4state.c
> @@ -2903,7 +2903,7 @@ gen_callback(struct nfs4_client *clp, struct nfsd4_setclientid *se, struct svc_r
>  static void
>  nfsd4_store_cache_entry(struct nfsd4_compoundres *resp)
>  {
> -	struct xdr_buf *buf = resp->xdr.buf;
> +	struct xdr_buf *buf = resp->xdr->buf;
>  	struct nfsd4_slot *slot = resp->cstate.slot;
>  	unsigned int base;
>  
> @@ -2973,7 +2973,7 @@ nfsd4_replay_cache_entry(struct nfsd4_compoundres *resp,
>  			 struct nfsd4_sequence *seq)
>  {
>  	struct nfsd4_slot *slot = resp->cstate.slot;
> -	struct xdr_stream *xdr = &resp->xdr;
> +	struct xdr_stream *xdr = resp->xdr;
>  	__be32 *p;
>  	__be32 status;
>  
> @@ -3708,7 +3708,7 @@ nfsd4_sequence(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
>  {
>  	struct nfsd4_sequence *seq = &u->sequence;
>  	struct nfsd4_compoundres *resp = rqstp->rq_resp;
> -	struct xdr_stream *xdr = &resp->xdr;
> +	struct xdr_stream *xdr = resp->xdr;
>  	struct nfsd4_session *session;
>  	struct nfs4_client *clp;
>  	struct nfsd4_slot *slot;
> diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c
> index eaaa1605b5b5..e0f06d3cbd44 100644
> --- a/fs/nfsd/nfs4xdr.c
> +++ b/fs/nfsd/nfs4xdr.c
> @@ -3581,7 +3581,7 @@ nfsd4_encode_stateid(struct xdr_stream *xdr, stateid_t *sid)
>  static __be32
>  nfsd4_encode_access(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_access *access)
>  {
> -	struct xdr_stream *xdr = &resp->xdr;
> +	struct xdr_stream *xdr = resp->xdr;
>  	__be32 *p;
>  
>  	p = xdr_reserve_space(xdr, 8);
> @@ -3594,7 +3594,7 @@ nfsd4_encode_access(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_
>  
>  static __be32 nfsd4_encode_bind_conn_to_session(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_bind_conn_to_session *bcts)
>  {
> -	struct xdr_stream *xdr = &resp->xdr;
> +	struct xdr_stream *xdr = resp->xdr;
>  	__be32 *p;
>  
>  	p = xdr_reserve_space(xdr, NFS4_MAX_SESSIONID_LEN + 8);
> @@ -3611,7 +3611,7 @@ static __be32 nfsd4_encode_bind_conn_to_session(struct nfsd4_compoundres *resp,
>  static __be32
>  nfsd4_encode_close(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_close *close)
>  {
> -	struct xdr_stream *xdr = &resp->xdr;
> +	struct xdr_stream *xdr = resp->xdr;
>  
>  	return nfsd4_encode_stateid(xdr, &close->cl_stateid);
>  }
> @@ -3620,7 +3620,7 @@ nfsd4_encode_close(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_c
>  static __be32
>  nfsd4_encode_commit(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_commit *commit)
>  {
> -	struct xdr_stream *xdr = &resp->xdr;
> +	struct xdr_stream *xdr = resp->xdr;
>  	__be32 *p;
>  
>  	p = xdr_reserve_space(xdr, NFS4_VERIFIER_SIZE);
> @@ -3634,7 +3634,7 @@ nfsd4_encode_commit(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_
>  static __be32
>  nfsd4_encode_create(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_create *create)
>  {
> -	struct xdr_stream *xdr = &resp->xdr;
> +	struct xdr_stream *xdr = resp->xdr;
>  	__be32 *p;
>  
>  	p = xdr_reserve_space(xdr, 20);
> @@ -3649,7 +3649,7 @@ static __be32
>  nfsd4_encode_getattr(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_getattr *getattr)
>  {
>  	struct svc_fh *fhp = getattr->ga_fhp;
> -	struct xdr_stream *xdr = &resp->xdr;
> +	struct xdr_stream *xdr = resp->xdr;
>  
>  	return nfsd4_encode_fattr(xdr, fhp, fhp->fh_export, fhp->fh_dentry,
>  				    getattr->ga_bmval, resp->rqstp, 0);
> @@ -3658,7 +3658,7 @@ nfsd4_encode_getattr(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4
>  static __be32
>  nfsd4_encode_getfh(struct nfsd4_compoundres *resp, __be32 nfserr, struct svc_fh **fhpp)
>  {
> -	struct xdr_stream *xdr = &resp->xdr;
> +	struct xdr_stream *xdr = resp->xdr;
>  	struct svc_fh *fhp = *fhpp;
>  	unsigned int len;
>  	__be32 *p;
> @@ -3713,7 +3713,7 @@ nfsd4_encode_lock_denied(struct xdr_stream *xdr, struct nfsd4_lock_denied *ld)
>  static __be32
>  nfsd4_encode_lock(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_lock *lock)
>  {
> -	struct xdr_stream *xdr = &resp->xdr;
> +	struct xdr_stream *xdr = resp->xdr;
>  
>  	if (!nfserr)
>  		nfserr = nfsd4_encode_stateid(xdr, &lock->lk_resp_stateid);
> @@ -3726,7 +3726,7 @@ nfsd4_encode_lock(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_lo
>  static __be32
>  nfsd4_encode_lockt(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_lockt *lockt)
>  {
> -	struct xdr_stream *xdr = &resp->xdr;
> +	struct xdr_stream *xdr = resp->xdr;
>  
>  	if (nfserr == nfserr_denied)
>  		nfsd4_encode_lock_denied(xdr, &lockt->lt_denied);
> @@ -3736,7 +3736,7 @@ nfsd4_encode_lockt(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_l
>  static __be32
>  nfsd4_encode_locku(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_locku *locku)
>  {
> -	struct xdr_stream *xdr = &resp->xdr;
> +	struct xdr_stream *xdr = resp->xdr;
>  
>  	return nfsd4_encode_stateid(xdr, &locku->lu_stateid);
>  }
> @@ -3745,7 +3745,7 @@ nfsd4_encode_locku(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_l
>  static __be32
>  nfsd4_encode_link(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_link *link)
>  {
> -	struct xdr_stream *xdr = &resp->xdr;
> +	struct xdr_stream *xdr = resp->xdr;
>  	__be32 *p;
>  
>  	p = xdr_reserve_space(xdr, 20);
> @@ -3759,7 +3759,7 @@ nfsd4_encode_link(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_li
>  static __be32
>  nfsd4_encode_open(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_open *open)
>  {
> -	struct xdr_stream *xdr = &resp->xdr;
> +	struct xdr_stream *xdr = resp->xdr;
>  	__be32 *p;
>  
>  	nfserr = nfsd4_encode_stateid(xdr, &open->op_stateid);
> @@ -3853,7 +3853,7 @@ nfsd4_encode_open(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_op
>  static __be32
>  nfsd4_encode_open_confirm(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_open_confirm *oc)
>  {
> -	struct xdr_stream *xdr = &resp->xdr;
> +	struct xdr_stream *xdr = resp->xdr;
>  
>  	return nfsd4_encode_stateid(xdr, &oc->oc_resp_stateid);
>  }
> @@ -3861,7 +3861,7 @@ nfsd4_encode_open_confirm(struct nfsd4_compoundres *resp, __be32 nfserr, struct
>  static __be32
>  nfsd4_encode_open_downgrade(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_open_downgrade *od)
>  {
> -	struct xdr_stream *xdr = &resp->xdr;
> +	struct xdr_stream *xdr = resp->xdr;
>  
>  	return nfsd4_encode_stateid(xdr, &od->od_stateid);
>  }
> @@ -3871,7 +3871,7 @@ static __be32 nfsd4_encode_splice_read(
>  				struct nfsd4_read *read,
>  				struct file *file, unsigned long maxcount)
>  {
> -	struct xdr_stream *xdr = &resp->xdr;
> +	struct xdr_stream *xdr = resp->xdr;
>  	struct xdr_buf *buf = xdr->buf;
>  	int status, space_left;
>  	u32 eof;
> @@ -3937,7 +3937,7 @@ static __be32 nfsd4_encode_readv(struct nfsd4_compoundres *resp,
>  				 struct nfsd4_read *read,
>  				 struct file *file, unsigned long maxcount)
>  {
> -	struct xdr_stream *xdr = &resp->xdr;
> +	struct xdr_stream *xdr = resp->xdr;
>  	u32 eof;
>  	int starting_len = xdr->buf->len - 8;
>  	__be32 nfserr;
> @@ -3976,7 +3976,7 @@ nfsd4_encode_read(struct nfsd4_compoundres *resp, __be32 nfserr,
>  		  struct nfsd4_read *read)
>  {
>  	unsigned long maxcount;
> -	struct xdr_stream *xdr = &resp->xdr;
> +	struct xdr_stream *xdr = resp->xdr;
>  	struct file *file;
>  	int starting_len = xdr->buf->len;
>  	__be32 *p;
> @@ -3990,7 +3990,7 @@ nfsd4_encode_read(struct nfsd4_compoundres *resp, __be32 nfserr,
>  		WARN_ON_ONCE(test_bit(RQ_SPLICE_OK, &resp->rqstp->rq_flags));
>  		return nfserr_resource;
>  	}
> -	if (resp->xdr.buf->page_len &&
> +	if (resp->xdr->buf->page_len &&
>  	    test_bit(RQ_SPLICE_OK, &resp->rqstp->rq_flags)) {
>  		WARN_ON_ONCE(1);
>  		return nfserr_resource;
> @@ -4020,7 +4020,7 @@ nfsd4_encode_readlink(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd
>  	int maxcount;
>  	__be32 wire_count;
>  	int zero = 0;
> -	struct xdr_stream *xdr = &resp->xdr;
> +	struct xdr_stream *xdr = resp->xdr;
>  	int length_offset = xdr->buf->len;
>  	int status;
>  	__be32 *p;
> @@ -4072,7 +4072,7 @@ nfsd4_encode_readdir(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4
>  	int bytes_left;
>  	loff_t offset;
>  	__be64 wire_offset;
> -	struct xdr_stream *xdr = &resp->xdr;
> +	struct xdr_stream *xdr = resp->xdr;
>  	int starting_len = xdr->buf->len;
>  	__be32 *p;
>  
> @@ -4083,8 +4083,8 @@ nfsd4_encode_readdir(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4
>  	/* XXX: Following NFSv3, we ignore the READDIR verifier for now. */
>  	*p++ = cpu_to_be32(0);
>  	*p++ = cpu_to_be32(0);
> -	resp->xdr.buf->head[0].iov_len = ((char *)resp->xdr.p)
> -				- (char *)resp->xdr.buf->head[0].iov_base;
> +	xdr->buf->head[0].iov_len = (char *)xdr->p -
> +				    (char *)xdr->buf->head[0].iov_base;
>  
>  	/*
>  	 * Number of bytes left for directory entries allowing for the
> @@ -4159,7 +4159,7 @@ nfsd4_encode_readdir(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4
>  static __be32
>  nfsd4_encode_remove(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_remove *remove)
>  {
> -	struct xdr_stream *xdr = &resp->xdr;
> +	struct xdr_stream *xdr = resp->xdr;
>  	__be32 *p;
>  
>  	p = xdr_reserve_space(xdr, 20);
> @@ -4172,7 +4172,7 @@ nfsd4_encode_remove(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_
>  static __be32
>  nfsd4_encode_rename(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_rename *rename)
>  {
> -	struct xdr_stream *xdr = &resp->xdr;
> +	struct xdr_stream *xdr = resp->xdr;
>  	__be32 *p;
>  
>  	p = xdr_reserve_space(xdr, 40);
> @@ -4255,7 +4255,7 @@ static __be32
>  nfsd4_encode_secinfo(struct nfsd4_compoundres *resp, __be32 nfserr,
>  		     struct nfsd4_secinfo *secinfo)
>  {
> -	struct xdr_stream *xdr = &resp->xdr;
> +	struct xdr_stream *xdr = resp->xdr;
>  
>  	return nfsd4_do_encode_secinfo(xdr, secinfo->si_exp);
>  }
> @@ -4264,7 +4264,7 @@ static __be32
>  nfsd4_encode_secinfo_no_name(struct nfsd4_compoundres *resp, __be32 nfserr,
>  		     struct nfsd4_secinfo_no_name *secinfo)
>  {
> -	struct xdr_stream *xdr = &resp->xdr;
> +	struct xdr_stream *xdr = resp->xdr;
>  
>  	return nfsd4_do_encode_secinfo(xdr, secinfo->sin_exp);
>  }
> @@ -4276,7 +4276,7 @@ nfsd4_encode_secinfo_no_name(struct nfsd4_compoundres *resp, __be32 nfserr,
>  static __be32
>  nfsd4_encode_setattr(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_setattr *setattr)
>  {
> -	struct xdr_stream *xdr = &resp->xdr;
> +	struct xdr_stream *xdr = resp->xdr;
>  	__be32 *p;
>  
>  	p = xdr_reserve_space(xdr, 16);
> @@ -4300,7 +4300,7 @@ nfsd4_encode_setattr(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4
>  static __be32
>  nfsd4_encode_setclientid(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_setclientid *scd)
>  {
> -	struct xdr_stream *xdr = &resp->xdr;
> +	struct xdr_stream *xdr = resp->xdr;
>  	__be32 *p;
>  
>  	if (!nfserr) {
> @@ -4324,7 +4324,7 @@ nfsd4_encode_setclientid(struct nfsd4_compoundres *resp, __be32 nfserr, struct n
>  static __be32
>  nfsd4_encode_write(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_write *write)
>  {
> -	struct xdr_stream *xdr = &resp->xdr;
> +	struct xdr_stream *xdr = resp->xdr;
>  	__be32 *p;
>  
>  	p = xdr_reserve_space(xdr, 16);
> @@ -4341,7 +4341,7 @@ static __be32
>  nfsd4_encode_exchange_id(struct nfsd4_compoundres *resp, __be32 nfserr,
>  			 struct nfsd4_exchange_id *exid)
>  {
> -	struct xdr_stream *xdr = &resp->xdr;
> +	struct xdr_stream *xdr = resp->xdr;
>  	__be32 *p;
>  	char *major_id;
>  	char *server_scope;
> @@ -4419,7 +4419,7 @@ static __be32
>  nfsd4_encode_create_session(struct nfsd4_compoundres *resp, __be32 nfserr,
>  			    struct nfsd4_create_session *sess)
>  {
> -	struct xdr_stream *xdr = &resp->xdr;
> +	struct xdr_stream *xdr = resp->xdr;
>  	__be32 *p;
>  
>  	p = xdr_reserve_space(xdr, 24);
> @@ -4472,7 +4472,7 @@ static __be32
>  nfsd4_encode_sequence(struct nfsd4_compoundres *resp, __be32 nfserr,
>  		      struct nfsd4_sequence *seq)
>  {
> -	struct xdr_stream *xdr = &resp->xdr;
> +	struct xdr_stream *xdr = resp->xdr;
>  	__be32 *p;
>  
>  	p = xdr_reserve_space(xdr, NFS4_MAX_SESSIONID_LEN + 20);
> @@ -4495,7 +4495,7 @@ static __be32
>  nfsd4_encode_test_stateid(struct nfsd4_compoundres *resp, __be32 nfserr,
>  			  struct nfsd4_test_stateid *test_stateid)
>  {
> -	struct xdr_stream *xdr = &resp->xdr;
> +	struct xdr_stream *xdr = resp->xdr;
>  	struct nfsd4_test_stateid_id *stateid, *next;
>  	__be32 *p;
>  
> @@ -4516,7 +4516,7 @@ static __be32
>  nfsd4_encode_getdeviceinfo(struct nfsd4_compoundres *resp, __be32 nfserr,
>  		struct nfsd4_getdeviceinfo *gdev)
>  {
> -	struct xdr_stream *xdr = &resp->xdr;
> +	struct xdr_stream *xdr = resp->xdr;
>  	const struct nfsd4_layout_ops *ops;
>  	u32 starting_len = xdr->buf->len, needed_len;
>  	__be32 *p;
> @@ -4572,7 +4572,7 @@ static __be32
>  nfsd4_encode_layoutget(struct nfsd4_compoundres *resp, __be32 nfserr,
>  		struct nfsd4_layoutget *lgp)
>  {
> -	struct xdr_stream *xdr = &resp->xdr;
> +	struct xdr_stream *xdr = resp->xdr;
>  	const struct nfsd4_layout_ops *ops;
>  	__be32 *p;
>  
> @@ -4599,7 +4599,7 @@ static __be32
>  nfsd4_encode_layoutcommit(struct nfsd4_compoundres *resp, __be32 nfserr,
>  			  struct nfsd4_layoutcommit *lcp)
>  {
> -	struct xdr_stream *xdr = &resp->xdr;
> +	struct xdr_stream *xdr = resp->xdr;
>  	__be32 *p;
>  
>  	p = xdr_reserve_space(xdr, 4);
> @@ -4620,7 +4620,7 @@ static __be32
>  nfsd4_encode_layoutreturn(struct nfsd4_compoundres *resp, __be32 nfserr,
>  		struct nfsd4_layoutreturn *lrp)
>  {
> -	struct xdr_stream *xdr = &resp->xdr;
> +	struct xdr_stream *xdr = resp->xdr;
>  	__be32 *p;
>  
>  	p = xdr_reserve_space(xdr, 4);
> @@ -4638,7 +4638,7 @@ nfsd42_encode_write_res(struct nfsd4_compoundres *resp,
>  		struct nfsd42_write_res *write, bool sync)
>  {
>  	__be32 *p;
> -	p = xdr_reserve_space(&resp->xdr, 4);
> +	p = xdr_reserve_space(resp->xdr, 4);
>  	if (!p)
>  		return nfserr_resource;
>  
> @@ -4647,11 +4647,11 @@ nfsd42_encode_write_res(struct nfsd4_compoundres *resp,
>  	else {
>  		__be32 nfserr;
>  		*p++ = cpu_to_be32(1);
> -		nfserr = nfsd4_encode_stateid(&resp->xdr, &write->cb_stateid);
> +		nfserr = nfsd4_encode_stateid(resp->xdr, &write->cb_stateid);
>  		if (nfserr)
>  			return nfserr;
>  	}
> -	p = xdr_reserve_space(&resp->xdr, 8 + 4 + NFS4_VERIFIER_SIZE);
> +	p = xdr_reserve_space(resp->xdr, 8 + 4 + NFS4_VERIFIER_SIZE);
>  	if (!p)
>  		return nfserr_resource;
>  
> @@ -4665,7 +4665,7 @@ nfsd42_encode_write_res(struct nfsd4_compoundres *resp,
>  static __be32
>  nfsd42_encode_nl4_server(struct nfsd4_compoundres *resp, struct nl4_server *ns)
>  {
> -	struct xdr_stream *xdr = &resp->xdr;
> +	struct xdr_stream *xdr = resp->xdr;
>  	struct nfs42_netaddr *addr;
>  	__be32 *p;
>  
> @@ -4713,7 +4713,7 @@ nfsd4_encode_copy(struct nfsd4_compoundres *resp, __be32 nfserr,
>  	if (nfserr)
>  		return nfserr;
>  
> -	p = xdr_reserve_space(&resp->xdr, 4 + 4);
> +	p = xdr_reserve_space(resp->xdr, 4 + 4);
>  	*p++ = xdr_one; /* cr_consecutive */
>  	*p++ = cpu_to_be32(copy->cp_synchronous);
>  	return 0;
> @@ -4723,7 +4723,7 @@ static __be32
>  nfsd4_encode_offload_status(struct nfsd4_compoundres *resp, __be32 nfserr,
>  			    struct nfsd4_offload_status *os)
>  {
> -	struct xdr_stream *xdr = &resp->xdr;
> +	struct xdr_stream *xdr = resp->xdr;
>  	__be32 *p;
>  
>  	p = xdr_reserve_space(xdr, 8 + 4);
> @@ -4740,7 +4740,7 @@ nfsd4_encode_read_plus_data(struct nfsd4_compoundres *resp,
>  			    unsigned long *maxcount, u32 *eof,
>  			    loff_t *pos)
>  {
> -	struct xdr_stream *xdr = &resp->xdr;
> +	struct xdr_stream *xdr = resp->xdr;
>  	struct file *file = read->rd_nf->nf_file;
>  	int starting_len = xdr->buf->len;
>  	loff_t hole_pos;
> @@ -4799,7 +4799,7 @@ nfsd4_encode_read_plus_hole(struct nfsd4_compoundres *resp,
>  	count = data_pos - read->rd_offset;
>  
>  	/* Content type, offset, byte count */
> -	p = xdr_reserve_space(&resp->xdr, 4 + 8 + 8);
> +	p = xdr_reserve_space(resp->xdr, 4 + 8 + 8);
>  	if (!p)
>  		return nfserr_resource;
>  
> @@ -4817,7 +4817,7 @@ nfsd4_encode_read_plus(struct nfsd4_compoundres *resp, __be32 nfserr,
>  		       struct nfsd4_read *read)
>  {
>  	unsigned long maxcount, count;
> -	struct xdr_stream *xdr = &resp->xdr;
> +	struct xdr_stream *xdr = resp->xdr;
>  	struct file *file;
>  	int starting_len = xdr->buf->len;
>  	int last_segment = xdr->buf->len;
> @@ -4888,7 +4888,7 @@ static __be32
>  nfsd4_encode_copy_notify(struct nfsd4_compoundres *resp, __be32 nfserr,
>  			 struct nfsd4_copy_notify *cn)
>  {
> -	struct xdr_stream *xdr = &resp->xdr;
> +	struct xdr_stream *xdr = resp->xdr;
>  	__be32 *p;
>  
>  	if (nfserr)
> @@ -4924,7 +4924,7 @@ nfsd4_encode_seek(struct nfsd4_compoundres *resp, __be32 nfserr,
>  {
>  	__be32 *p;
>  
> -	p = xdr_reserve_space(&resp->xdr, 4 + 8);
> +	p = xdr_reserve_space(resp->xdr, 4 + 8);
>  	*p++ = cpu_to_be32(seek->seek_eof);
>  	p = xdr_encode_hyper(p, seek->seek_pos);
>  
> @@ -4985,7 +4985,7 @@ static __be32
>  nfsd4_encode_getxattr(struct nfsd4_compoundres *resp, __be32 nfserr,
>  		      struct nfsd4_getxattr *getxattr)
>  {
> -	struct xdr_stream *xdr = &resp->xdr;
> +	struct xdr_stream *xdr = resp->xdr;
>  	__be32 *p, err;
>  
>  	p = xdr_reserve_space(xdr, 4);
> @@ -5009,7 +5009,7 @@ static __be32
>  nfsd4_encode_setxattr(struct nfsd4_compoundres *resp, __be32 nfserr,
>  		      struct nfsd4_setxattr *setxattr)
>  {
> -	struct xdr_stream *xdr = &resp->xdr;
> +	struct xdr_stream *xdr = resp->xdr;
>  	__be32 *p;
>  
>  	p = xdr_reserve_space(xdr, 20);
> @@ -5050,7 +5050,7 @@ static __be32
>  nfsd4_encode_listxattrs(struct nfsd4_compoundres *resp, __be32 nfserr,
>  			struct nfsd4_listxattrs *listxattrs)
>  {
> -	struct xdr_stream *xdr = &resp->xdr;
> +	struct xdr_stream *xdr = resp->xdr;
>  	u32 cookie_offset, count_offset, eof;
>  	u32 left, xdrleft, slen, count;
>  	u32 xdrlen, offset;
> @@ -5161,7 +5161,7 @@ static __be32
>  nfsd4_encode_removexattr(struct nfsd4_compoundres *resp, __be32 nfserr,
>  			 struct nfsd4_removexattr *removexattr)
>  {
> -	struct xdr_stream *xdr = &resp->xdr;
> +	struct xdr_stream *xdr = resp->xdr;
>  	__be32 *p;
>  
>  	p = xdr_reserve_space(xdr, 20);
> @@ -5301,7 +5301,7 @@ __be32 nfsd4_check_resp_size(struct nfsd4_compoundres *resp, u32 respsize)
>  void
>  nfsd4_encode_operation(struct nfsd4_compoundres *resp, struct nfsd4_op *op)
>  {
> -	struct xdr_stream *xdr = &resp->xdr;
> +	struct xdr_stream *xdr = resp->xdr;
>  	struct nfs4_stateowner *so = resp->cstate.replay_owner;
>  	struct svc_rqst *rqstp = resp->rqstp;
>  	const struct nfsd4_operation *opdesc = op->opdesc;
> @@ -5430,14 +5430,14 @@ int
>  nfs4svc_encode_compoundres(struct svc_rqst *rqstp, __be32 *p)
>  {
>  	struct nfsd4_compoundres *resp = rqstp->rq_resp;
> -	struct xdr_buf *buf = resp->xdr.buf;
> +	struct xdr_buf *buf = resp->xdr->buf;
>  
>  	WARN_ON_ONCE(buf->len != buf->head[0].iov_len + buf->page_len +
>  				 buf->tail[0].iov_len);
>  
>  	*p = resp->cstate.status;
>  
> -	rqstp->rq_next_page = resp->xdr.page_ptr + 1;
> +	rqstp->rq_next_page = resp->xdr->page_ptr + 1;
>  
>  	p = resp->tagp;
>  	*p++ = htonl(resp->taglen);
> diff --git a/fs/nfsd/nfssvc.c b/fs/nfsd/nfssvc.c
> index 6de406322106..d909e4956244 100644
> --- a/fs/nfsd/nfssvc.c
> +++ b/fs/nfsd/nfssvc.c
> @@ -997,7 +997,7 @@ int nfsd_dispatch(struct svc_rqst *rqstp, __be32 *statp)
>  	 * NFSv4 does some encoding while processing
>  	 */
>  	p = resv->iov_base + resv->iov_len;
> -	resv->iov_len += sizeof(__be32);
> +	svcxdr_init_encode(rqstp);
>  
>  	*statp = proc->pc_func(rqstp);
>  	if (*statp == rpc_drop_reply || test_bit(RQ_DROPME, &rqstp->rq_flags))
> @@ -1052,7 +1052,7 @@ int nfssvc_decode_voidarg(struct svc_rqst *rqstp, __be32 *p)
>   */
>  int nfssvc_encode_voidres(struct svc_rqst *rqstp, __be32 *p)
>  {
> -        return xdr_ressize_check(rqstp, p);
> +	return 1;
>  }
>  
>  int nfsd_pool_stats_open(struct inode *inode, struct file *file)
> diff --git a/fs/nfsd/xdr4.h b/fs/nfsd/xdr4.h
> index c300885ae75d..fe540a3415c6 100644
> --- a/fs/nfsd/xdr4.h
> +++ b/fs/nfsd/xdr4.h
> @@ -698,7 +698,7 @@ struct nfsd4_compoundargs {
>  
>  struct nfsd4_compoundres {
>  	/* scratch variables for XDR encode */
> -	struct xdr_stream		xdr;
> +	struct xdr_stream		*xdr;
>  	struct svc_rqst *		rqstp;
>  
>  	u32				taglen;
> diff --git a/include/linux/sunrpc/svc.h b/include/linux/sunrpc/svc.h
> index 31ee3b6047c3..e91d51ea028b 100644
> --- a/include/linux/sunrpc/svc.h
> +++ b/include/linux/sunrpc/svc.h
> @@ -248,6 +248,7 @@ struct svc_rqst {
>  	size_t			rq_xprt_hlen;	/* xprt header len */
>  	struct xdr_buf		rq_arg;
>  	struct xdr_stream	rq_arg_stream;
> +	struct xdr_stream	rq_res_stream;
>  	struct page		*rq_scratch_page;
>  	struct xdr_buf		rq_res;
>  	struct page		*rq_pages[RPCSVC_MAXPAGES + 1];
> @@ -574,4 +575,28 @@ static inline void svcxdr_init_decode(struct svc_rqst *rqstp)
>  	xdr_set_scratch_page(xdr, rqstp->rq_scratch_page);
>  }
>  
> +/**
> + * svcxdr_init_encode - Prepare an xdr_stream for svc Reply encoding
> + * @rqstp: controlling server RPC transaction context
> + *
> + */
> +static inline void svcxdr_init_encode(struct svc_rqst *rqstp)
> +{
> +	struct xdr_stream *xdr = &rqstp->rq_res_stream;
> +	struct xdr_buf *buf = &rqstp->rq_res;
> +	struct kvec *resv = buf->head;
> +
> +	xdr_reset_scratch_buffer(xdr);
> +
> +	xdr->buf = buf;
> +	xdr->iov = resv;
> +	xdr->p   = resv->iov_base + resv->iov_len;
> +	xdr->end = resv->iov_base + PAGE_SIZE - rqstp->rq_auth_slack;
> +	buf->len = resv->iov_len;
> +	xdr->page_ptr = buf->pages - 1;
> +	buf->buflen = PAGE_SIZE * (1 + rqstp->rq_page_end - buf->pages);
> +	buf->buflen -= rqstp->rq_auth_slack;
> +	xdr->rqst = NULL;
> +}
> +
>  #endif /* SUNRPC_SVC_H */
> 

^ permalink raw reply	[flat|nested] 58+ messages in thread

* Re: [PATCH v1 01/42] NFSD: Extract the svcxdr_init_encode() helper
  2021-03-02 16:47   ` J. Bruce Fields
@ 2021-03-02 16:57     ` Chuck Lever
  0 siblings, 0 replies; 58+ messages in thread
From: Chuck Lever @ 2021-03-02 16:57 UTC (permalink / raw)
  To: Bruce Fields; +Cc: Linux NFS Mailing List



> On Mar 2, 2021, at 11:47 AM, J. Bruce Fields <bfields@fieldses.org> wrote:
> 
> On Mon, Mar 01, 2021 at 10:15:24AM -0500, Chuck Lever wrote:
>> NFSD initializes an encode xdr_stream only after the RPC layer has
>> already inserted the RPC Reply header.
> 
> Out of curiosity: does it need to be this way?

The code in svc.c uses the old-school svc_putu32() and friends macros.
I don't think there's another reason.

IMHO they could be replaced, but I didn't have the stones to go that
far.


--
Chuck Lever




^ permalink raw reply	[flat|nested] 58+ messages in thread

* Re: [PATCH v1 12/42] NFSD: Update the NFSv3 FSSTAT3res encoder to use struct xdr_stream
  2021-03-01 15:16 ` [PATCH v1 12/42] NFSD: Update the NFSv3 FSSTAT3res " Chuck Lever
@ 2021-03-02 20:45   ` J. Bruce Fields
  2021-03-02 20:57     ` Chuck Lever
  0 siblings, 1 reply; 58+ messages in thread
From: J. Bruce Fields @ 2021-03-02 20:45 UTC (permalink / raw)
  To: Chuck Lever; +Cc: linux-nfs

On Mon, Mar 01, 2021 at 10:16:31AM -0500, Chuck Lever wrote:
> Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
> ---
>  fs/nfsd/nfs3xdr.c |   58 ++++++++++++++++++++++++++++++++++++++++-------------
>  1 file changed, 44 insertions(+), 14 deletions(-)
> 
> diff --git a/fs/nfsd/nfs3xdr.c b/fs/nfsd/nfs3xdr.c
> index e159e4557428..e4a569e7216d 100644
> --- a/fs/nfsd/nfs3xdr.c
> +++ b/fs/nfsd/nfs3xdr.c
> @@ -17,6 +17,13 @@
>  #define NFSDDBG_FACILITY		NFSDDBG_XDR
>  
>  
> +/*
> + * Force construction of an empty post-op attr
> + */
> +static const struct svc_fh nfs3svc_null_fh = {
> +	.fh_no_wcc	= true,
> +};
> +
>  /*
>   * Mapping of S_IF* types to NFS file types
>   */
> @@ -1392,27 +1399,50 @@ nfs3svc_encode_entry_plus(void *cd, const char *name,
>  	return encode_entry(cd, name, namlen, offset, ino, d_type, 1);
>  }
>  
> +static bool
> +svcxdr_encode_fsstat3resok(struct xdr_stream *xdr,
> +			   const struct nfsd3_fsstatres *resp)
> +{
> +	const struct kstatfs *s = &resp->stats;
> +	u64 bs = s->f_bsize;
> +	__be32 *p;
> +
> +	p = xdr_reserve_space(xdr, XDR_UNIT * 13);
> +	if (!p)
> +		return false;
> +	p = xdr_encode_hyper(p, bs * s->f_blocks);	/* total bytes */
> +	p = xdr_encode_hyper(p, bs * s->f_bfree);	/* free bytes */
> +	p = xdr_encode_hyper(p, bs * s->f_bavail);	/* user available bytes */
> +	p = xdr_encode_hyper(p, s->f_files);		/* total inodes */
> +	p = xdr_encode_hyper(p, s->f_ffree);		/* free inodes */
> +	p = xdr_encode_hyper(p, s->f_ffree);		/* user available inodes */
> +	*p = cpu_to_be32(resp->invarsec);		/* mean unchanged time */
> +
> +	return true;
> +}
> +
>  /* FSSTAT */
>  int
>  nfs3svc_encode_fsstatres(struct svc_rqst *rqstp, __be32 *p)
>  {
> +	struct xdr_stream *xdr = &rqstp->rq_res_stream;
>  	struct nfsd3_fsstatres *resp = rqstp->rq_resp;
> -	struct kstatfs	*s = &resp->stats;
> -	u64		bs = s->f_bsize;
>  
> -	*p++ = resp->status;
> -	*p++ = xdr_zero;	/* no post_op_attr */
> -
> -	if (resp->status == 0) {
> -		p = xdr_encode_hyper(p, bs * s->f_blocks);	/* total bytes */
> -		p = xdr_encode_hyper(p, bs * s->f_bfree);	/* free bytes */
> -		p = xdr_encode_hyper(p, bs * s->f_bavail);	/* user available bytes */
> -		p = xdr_encode_hyper(p, s->f_files);	/* total inodes */
> -		p = xdr_encode_hyper(p, s->f_ffree);	/* free inodes */
> -		p = xdr_encode_hyper(p, s->f_ffree);	/* user available inodes */
> -		*p++ = htonl(resp->invarsec);	/* mean unchanged time */
> +	if (!svcxdr_encode_nfsstat3(xdr, resp->status))
> +		return 0;
> +	switch (resp->status) {
> +	case nfs_ok:
> +		if (!svcxdr_encode_post_op_attr(rqstp, xdr, &nfs3svc_null_fh))
> +			return 0;
> +		if (!svcxdr_encode_fsstat3resok(xdr, resp))
> +			return 0;
> +		break;
> +	default:
> +		if (!svcxdr_encode_post_op_attr(rqstp, xdr, &nfs3svc_null_fh))
> +			return 0;

Dumb question: will this result in the same xdr on the wire as the above
that just hard-coded xdr_zero?

I feel like there's a lot of biolerplate error handling.  In the v4 case
I centralized some of it after a fuzzer found an oops in some of that
copy-pasted boilerplate:

	b7571e4cd39a nfsd4: skip encoder in trivial error cases
	bac966d60652 nfsd4: individual encoders no longer see error cases

I dunno, maybe that was overkill.

--b.

>  	}
> -	return xdr_ressize_check(rqstp, p);
> +
> +	return 1;
>  }
>  
>  /* FSINFO */
> 

^ permalink raw reply	[flat|nested] 58+ messages in thread

* Re: [PATCH v1 12/42] NFSD: Update the NFSv3 FSSTAT3res encoder to use struct xdr_stream
  2021-03-02 20:45   ` J. Bruce Fields
@ 2021-03-02 20:57     ` Chuck Lever
  0 siblings, 0 replies; 58+ messages in thread
From: Chuck Lever @ 2021-03-02 20:57 UTC (permalink / raw)
  To: Bruce Fields; +Cc: Linux NFS Mailing List


> On Mar 2, 2021, at 3:45 PM, J. Bruce Fields <bfields@fieldses.org> wrote:
> 
> On Mon, Mar 01, 2021 at 10:16:31AM -0500, Chuck Lever wrote:
>> Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
>> ---
>> fs/nfsd/nfs3xdr.c |   58 ++++++++++++++++++++++++++++++++++++++++-------------
>> 1 file changed, 44 insertions(+), 14 deletions(-)
>> 
>> diff --git a/fs/nfsd/nfs3xdr.c b/fs/nfsd/nfs3xdr.c
>> index e159e4557428..e4a569e7216d 100644
>> --- a/fs/nfsd/nfs3xdr.c
>> +++ b/fs/nfsd/nfs3xdr.c
>> @@ -17,6 +17,13 @@
>> #define NFSDDBG_FACILITY		NFSDDBG_XDR
>> 
>> 
>> +/*
>> + * Force construction of an empty post-op attr
>> + */
>> +static const struct svc_fh nfs3svc_null_fh = {
>> +	.fh_no_wcc	= true,
>> +};
>> +
>> /*
>>  * Mapping of S_IF* types to NFS file types
>>  */
>> @@ -1392,27 +1399,50 @@ nfs3svc_encode_entry_plus(void *cd, const char *name,
>> 	return encode_entry(cd, name, namlen, offset, ino, d_type, 1);
>> }
>> 
>> +static bool
>> +svcxdr_encode_fsstat3resok(struct xdr_stream *xdr,
>> +			   const struct nfsd3_fsstatres *resp)
>> +{
>> +	const struct kstatfs *s = &resp->stats;
>> +	u64 bs = s->f_bsize;
>> +	__be32 *p;
>> +
>> +	p = xdr_reserve_space(xdr, XDR_UNIT * 13);
>> +	if (!p)
>> +		return false;
>> +	p = xdr_encode_hyper(p, bs * s->f_blocks);	/* total bytes */
>> +	p = xdr_encode_hyper(p, bs * s->f_bfree);	/* free bytes */
>> +	p = xdr_encode_hyper(p, bs * s->f_bavail);	/* user available bytes */
>> +	p = xdr_encode_hyper(p, s->f_files);		/* total inodes */
>> +	p = xdr_encode_hyper(p, s->f_ffree);		/* free inodes */
>> +	p = xdr_encode_hyper(p, s->f_ffree);		/* user available inodes */
>> +	*p = cpu_to_be32(resp->invarsec);		/* mean unchanged time */
>> +
>> +	return true;
>> +}
>> +
>> /* FSSTAT */
>> int
>> nfs3svc_encode_fsstatres(struct svc_rqst *rqstp, __be32 *p)
>> {
>> +	struct xdr_stream *xdr = &rqstp->rq_res_stream;
>> 	struct nfsd3_fsstatres *resp = rqstp->rq_resp;
>> -	struct kstatfs	*s = &resp->stats;
>> -	u64		bs = s->f_bsize;
>> 
>> -	*p++ = resp->status;
>> -	*p++ = xdr_zero;	/* no post_op_attr */
>> -
>> -	if (resp->status == 0) {
>> -		p = xdr_encode_hyper(p, bs * s->f_blocks);	/* total bytes */
>> -		p = xdr_encode_hyper(p, bs * s->f_bfree);	/* free bytes */
>> -		p = xdr_encode_hyper(p, bs * s->f_bavail);	/* user available bytes */
>> -		p = xdr_encode_hyper(p, s->f_files);	/* total inodes */
>> -		p = xdr_encode_hyper(p, s->f_ffree);	/* free inodes */
>> -		p = xdr_encode_hyper(p, s->f_ffree);	/* user available inodes */
>> -		*p++ = htonl(resp->invarsec);	/* mean unchanged time */
>> +	if (!svcxdr_encode_nfsstat3(xdr, resp->status))
>> +		return 0;
>> +	switch (resp->status) {
>> +	case nfs_ok:
>> +		if (!svcxdr_encode_post_op_attr(rqstp, xdr, &nfs3svc_null_fh))
>> +			return 0;
>> +		if (!svcxdr_encode_fsstat3resok(xdr, resp))
>> +			return 0;
>> +		break;
>> +	default:
>> +		if (!svcxdr_encode_post_op_attr(rqstp, xdr, &nfs3svc_null_fh))
>> +			return 0;
> 
> Dumb question: will this result in the same xdr on the wire as the above
> that just hard-coded xdr_zero?

It should result in an xdr_zero. The point here is to document what that
xdr_zero means: basically that it is an absent post_op_attr.

The simpler form would be

     if (xdr_stream_encode_item_absent(xdr) < 0)
           return 0;

Which has the same amount of boilerplatiness but is less explanatory.


> I feel like there's a lot of biolerplate error handling.  In the v4 case
> I centralized some of it after a fuzzer found an oops in some of that
> copy-pasted boilerplate:
> 
> 	b7571e4cd39a nfsd4: skip encoder in trivial error cases
> 	bac966d60652 nfsd4: individual encoders no longer see error cases
> 
> I dunno, maybe that was overkill.

True, errors will be extremely rare and usually the result of a coding
error. The problem is that an encoder error can result in:

- A general protection fault that makes the server unusable, resulting
  in a temporary denial of service or at worst corruption of recently
  written data, or
- The server returning garbage or corrupted data along with an NFS_OK
  result.

So I think we need to take a little extra care here. If there's a more
efficient and easier way to do that checking, I'm all ears.


> --b.
> 
>> 	}
>> -	return xdr_ressize_check(rqstp, p);
>> +
>> +	return 1;
>> }
>> 
>> /* FSINFO */

--
Chuck Lever




^ permalink raw reply	[flat|nested] 58+ messages in thread

* Re: [PATCH v1 19/42] SUNRPC: Fix xdr_get_next_encode_buffer() page boundary handling
  2021-03-01 15:17 ` [PATCH v1 19/42] SUNRPC: Fix xdr_get_next_encode_buffer() page boundary handling Chuck Lever
@ 2021-03-02 22:11   ` J. Bruce Fields
  2021-03-03 15:43     ` Chuck Lever
  0 siblings, 1 reply; 58+ messages in thread
From: J. Bruce Fields @ 2021-03-02 22:11 UTC (permalink / raw)
  To: Chuck Lever; +Cc: linux-nfs

On Mon, Mar 01, 2021 at 10:17:13AM -0500, Chuck Lever wrote:
> The description of commit 2825a7f90753 ("nfsd4: allow encoding
> across page boundaries") states:
> 
> > Also we can't handle a new operation starting close to the end of
> > a page.
> 
> But does not detail why this is the case.

That wasn't every helpful of me, sorry.

> Subtracting the scratch buffer's "shift" value from the remaining
> stream space seems to make reserving space close to the end of the
> buf->pages array reliable.

So, why is that?

Thinking this through:

When somebody asks for a buffer that would straddle a page boundary,
with frag1bytes at the end of this page and frag2bytes at the start of
the next page, we instead give them a buffer starting at start of the
next page.  That gives them a nice contiguous buffer to write into.
When they're done using it, we fix things up by copying what they wrote
back to where it should be.

That means we're temporarily wasting frag1bytes of space.  So, I don't
know, maybe that's the logic behind subtracing frag1bytes from
space_left.

It means you may end up with xdr->end frag1bytes short of the next page.
I'm not sure that's right.

--b.


> 
> This change is needed to make entry encoding with struct xdr_stream,
> introduced in a subsequent patch, work correctly when it approaches
> the end of the dirlist buffer.
> 
> Fixes: 2825a7f90753 ("nfsd4: allow encoding across page boundaries")
> Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
> ---
>  net/sunrpc/xdr.c |    2 +-
>  1 file changed, 1 insertion(+), 1 deletion(-)
> 
> diff --git a/net/sunrpc/xdr.c b/net/sunrpc/xdr.c
> index 3964ff74ee51..043b67229792 100644
> --- a/net/sunrpc/xdr.c
> +++ b/net/sunrpc/xdr.c
> @@ -978,7 +978,7 @@ static __be32 *xdr_get_next_encode_buffer(struct xdr_stream *xdr,
>  	 * shifted this one back:
>  	 */
>  	xdr->p = (void *)p + frag2bytes;
> -	space_left = xdr->buf->buflen - xdr->buf->len;
> +	space_left = xdr->buf->buflen - xdr->buf->len - frag1bytes;
>  	xdr->end = (void *)p + min_t(int, space_left, PAGE_SIZE);
>  	xdr->buf->page_len += frag2bytes;
>  	xdr->buf->len += nbytes;
> 

^ permalink raw reply	[flat|nested] 58+ messages in thread

* Re: [PATCH v1 14/42] NFSD: Update the NFSv3 PATHCONF3res encoder to use struct xdr_stream
  2021-03-01 15:16 ` [PATCH v1 14/42] NFSD: Update the NFSv3 PATHCONF3res " Chuck Lever
@ 2021-03-03  7:13   ` Christoph Hellwig
  2021-03-03 15:34     ` Chuck Lever
  0 siblings, 1 reply; 58+ messages in thread
From: Christoph Hellwig @ 2021-03-03  7:13 UTC (permalink / raw)
  To: Chuck Lever; +Cc: linux-nfs

On Mon, Mar 01, 2021 at 10:16:43AM -0500, Chuck Lever wrote:
> +	*p++ = resp->p_no_trunc ? xdr_one : xdr_zero;
> +	*p++ = resp->p_chown_restricted ? xdr_one : xdr_zero;
> +	*p++ = resp->p_case_insensitive ? xdr_one : xdr_zero;
> +	*p = resp->p_case_preserving ? xdr_one : xdr_zero;

Wouldn't a little xdr_encode_bool helper for this common pattern be
nice?

^ permalink raw reply	[flat|nested] 58+ messages in thread

* Re: [PATCH v1 14/42] NFSD: Update the NFSv3 PATHCONF3res encoder to use struct xdr_stream
  2021-03-03  7:13   ` Christoph Hellwig
@ 2021-03-03 15:34     ` Chuck Lever
  0 siblings, 0 replies; 58+ messages in thread
From: Chuck Lever @ 2021-03-03 15:34 UTC (permalink / raw)
  To: Christoph Hellwig; +Cc: Linux NFS Mailing List



> On Mar 3, 2021, at 2:13 AM, Christoph Hellwig <hch@infradead.org> wrote:
> 
> On Mon, Mar 01, 2021 at 10:16:43AM -0500, Chuck Lever wrote:
>> +	*p++ = resp->p_no_trunc ? xdr_one : xdr_zero;
>> +	*p++ = resp->p_chown_restricted ? xdr_one : xdr_zero;
>> +	*p++ = resp->p_case_insensitive ? xdr_one : xdr_zero;
>> +	*p = resp->p_case_preserving ? xdr_one : xdr_zero;
> 
> Wouldn't a little xdr_encode_bool helper for this common pattern be
> nice?

Sure. In include/linux/sunrpc/xdr.h, I've now added:

/**
 * xdr_encode_bool - Encode a boolean item
 * @p: address in a buffer into which to encode
 * @n: boolean value to encode
 *
 * Return value:
 *   Address of item following the encoded boolean
 */
static inline __be32 *xdr_encode_bool(__be32 *p, u32 n)
{
       *p = n ? xdr_one : xdr_zero;
       return p++;
}

and xdr_stream_encode_bool() has been changed to use this helper.

In fs/nfsd/nfs3xdr.c, the PATHCONF result encoder now uses
xdr_encode_bool() to encode the four boolean fields in struct
PATHCONF3resok.

--
Chuck Lever




^ permalink raw reply	[flat|nested] 58+ messages in thread

* Re: [PATCH v1 19/42] SUNRPC: Fix xdr_get_next_encode_buffer() page boundary handling
  2021-03-02 22:11   ` J. Bruce Fields
@ 2021-03-03 15:43     ` Chuck Lever
  2021-03-03 16:52       ` Bruce Fields
  0 siblings, 1 reply; 58+ messages in thread
From: Chuck Lever @ 2021-03-03 15:43 UTC (permalink / raw)
  To: Bruce Fields; +Cc: Linux NFS Mailing List

Hi Bruce-

Thanks for your careful review of this series!


> On Mar 2, 2021, at 5:11 PM, J. Bruce Fields <bfields@fieldses.org> wrote:
> 
> On Mon, Mar 01, 2021 at 10:17:13AM -0500, Chuck Lever wrote:
>> The description of commit 2825a7f90753 ("nfsd4: allow encoding
>> across page boundaries") states:
>> 
>>> Also we can't handle a new operation starting close to the end of
>>> a page.
>> 
>> But does not detail why this is the case.
> 
> That wasn't every helpful of me, sorry.
> 
>> Subtracting the scratch buffer's "shift" value from the remaining
>> stream space seems to make reserving space close to the end of the
>> buf->pages array reliable.
> 
> So, why is that?
> 
> Thinking this through:
> 
> When somebody asks for a buffer that would straddle a page boundary,
> with frag1bytes at the end of this page and frag2bytes at the start of
> the next page, we instead give them a buffer starting at start of the
> next page.  That gives them a nice contiguous buffer to write into.
> When they're done using it, we fix things up by copying what they wrote
> back to where it should be.
> 
> That means we're temporarily wasting frag1bytes of space.  So, I don't
> know, maybe that's the logic behind subtracing frag1bytes from
> space_left.
> 
> It means you may end up with xdr->end frag1bytes short of the next page.
> I'm not sure that's right.

Why would that not be OK? the next call to xdr_get_next_encode_buffer()
should do the right thing and bounce the new encoded data from the
next page into this one again.

So far I have not encountered any problems. Would such a problem show
up with some frequency under normal use, or would it be especially
subtle?


> --b.
> 
> 
>> 
>> This change is needed to make entry encoding with struct xdr_stream,
>> introduced in a subsequent patch, work correctly when it approaches
>> the end of the dirlist buffer.
>> 
>> Fixes: 2825a7f90753 ("nfsd4: allow encoding across page boundaries")
>> Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
>> ---
>> net/sunrpc/xdr.c |    2 +-
>> 1 file changed, 1 insertion(+), 1 deletion(-)
>> 
>> diff --git a/net/sunrpc/xdr.c b/net/sunrpc/xdr.c
>> index 3964ff74ee51..043b67229792 100644
>> --- a/net/sunrpc/xdr.c
>> +++ b/net/sunrpc/xdr.c
>> @@ -978,7 +978,7 @@ static __be32 *xdr_get_next_encode_buffer(struct xdr_stream *xdr,
>> 	 * shifted this one back:
>> 	 */
>> 	xdr->p = (void *)p + frag2bytes;
>> -	space_left = xdr->buf->buflen - xdr->buf->len;
>> +	space_left = xdr->buf->buflen - xdr->buf->len - frag1bytes;
>> 	xdr->end = (void *)p + min_t(int, space_left, PAGE_SIZE);
>> 	xdr->buf->page_len += frag2bytes;
>> 	xdr->buf->len += nbytes;
>> 

--
Chuck Lever




^ permalink raw reply	[flat|nested] 58+ messages in thread

* Re: [PATCH v1 19/42] SUNRPC: Fix xdr_get_next_encode_buffer() page boundary handling
  2021-03-03 15:43     ` Chuck Lever
@ 2021-03-03 16:52       ` Bruce Fields
  2021-03-03 18:19         ` Chuck Lever
  0 siblings, 1 reply; 58+ messages in thread
From: Bruce Fields @ 2021-03-03 16:52 UTC (permalink / raw)
  To: Chuck Lever; +Cc: Linux NFS Mailing List

On Wed, Mar 03, 2021 at 03:43:28PM +0000, Chuck Lever wrote:
> Hi Bruce-
> 
> Thanks for your careful review of this series!
> 
> 
> > On Mar 2, 2021, at 5:11 PM, J. Bruce Fields <bfields@fieldses.org> wrote:
> > 
> > On Mon, Mar 01, 2021 at 10:17:13AM -0500, Chuck Lever wrote:
> >> The description of commit 2825a7f90753 ("nfsd4: allow encoding
> >> across page boundaries") states:
> >> 
> >>> Also we can't handle a new operation starting close to the end of
> >>> a page.
> >> 
> >> But does not detail why this is the case.
> > 
> > That wasn't every helpful of me, sorry.
> > 
> >> Subtracting the scratch buffer's "shift" value from the remaining
> >> stream space seems to make reserving space close to the end of the
> >> buf->pages array reliable.
> > 
> > So, why is that?
> > 
> > Thinking this through:
> > 
> > When somebody asks for a buffer that would straddle a page boundary,
> > with frag1bytes at the end of this page and frag2bytes at the start of
> > the next page, we instead give them a buffer starting at start of the
> > next page.  That gives them a nice contiguous buffer to write into.
> > When they're done using it, we fix things up by copying what they wrote
> > back to where it should be.
> > 
> > That means we're temporarily wasting frag1bytes of space.  So, I don't
> > know, maybe that's the logic behind subtracing frag1bytes from
> > space_left.
> > 
> > It means you may end up with xdr->end frag1bytes short of the next page.

Wait, let me try that again:

	p = page_address(*xdr->page_ptr);
	xdr->p = (void *)p + frag2bytes;
	space_left = xdr->buf->buflen - xdr->buf->len - frag1bytes;
        xdr->end = (void *)p + min_t(int, space_left, PAGE_SIZE);

If you've still got a lot of buffer space left, then that'll put
xdr->end frag2bytes past the end of a page, won't it?

> > I'm not sure that's right.
> 
> Why would that not be OK? the next call to xdr_get_next_encode_buffer()
> should do the right thing and bounce the new encoded data from the
> next page into this one again.
> 
> So far I have not encountered any problems. Would such a problem show
> up with some frequency under normal use, or would it be especially
> subtle?

I mainly just want to make sure we've got a coherent idea what this code
is doing....

For testing: large replies that aren't just read data are readdir and
getacl.  So reading large directories with lots of variably-named files
might be good. Also pynfs could easily send a single compound with lots
of variable-sized reads, that might be interesting.

Constructing a compound that will result in xdr_reserve_space calls that
exactly hit the various corner cases may be hard.  But maybe if we just
send a bunch of compounds that vary over some range we can still
guarantee hitting those cases.

--b.

^ permalink raw reply	[flat|nested] 58+ messages in thread

* Re: [PATCH v1 19/42] SUNRPC: Fix xdr_get_next_encode_buffer() page boundary handling
  2021-03-03 16:52       ` Bruce Fields
@ 2021-03-03 18:19         ` Chuck Lever
  2021-03-03 18:25           ` Bruce Fields
  0 siblings, 1 reply; 58+ messages in thread
From: Chuck Lever @ 2021-03-03 18:19 UTC (permalink / raw)
  To: Bruce Fields; +Cc: Linux NFS Mailing List



> On Mar 3, 2021, at 11:52 AM, Bruce Fields <bfields@fieldses.org> wrote:
> 
> On Wed, Mar 03, 2021 at 03:43:28PM +0000, Chuck Lever wrote:
>> Hi Bruce-
>> 
>> Thanks for your careful review of this series!
>> 
>> 
>>> On Mar 2, 2021, at 5:11 PM, J. Bruce Fields <bfields@fieldses.org> wrote:
>>> 
>>> On Mon, Mar 01, 2021 at 10:17:13AM -0500, Chuck Lever wrote:
>>>> The description of commit 2825a7f90753 ("nfsd4: allow encoding
>>>> across page boundaries") states:
>>>> 
>>>>> Also we can't handle a new operation starting close to the end of
>>>>> a page.
>>>> 
>>>> But does not detail why this is the case.
>>> 
>>> That wasn't every helpful of me, sorry.
>>> 
>>>> Subtracting the scratch buffer's "shift" value from the remaining
>>>> stream space seems to make reserving space close to the end of the
>>>> buf->pages array reliable.
>>> 
>>> So, why is that?
>>> 
>>> Thinking this through:
>>> 
>>> When somebody asks for a buffer that would straddle a page boundary,
>>> with frag1bytes at the end of this page and frag2bytes at the start of
>>> the next page, we instead give them a buffer starting at start of the
>>> next page.  That gives them a nice contiguous buffer to write into.
>>> When they're done using it, we fix things up by copying what they wrote
>>> back to where it should be.
>>> 
>>> That means we're temporarily wasting frag1bytes of space.  So, I don't
>>> know, maybe that's the logic behind subtracing frag1bytes from
>>> space_left.
>>> 
>>> It means you may end up with xdr->end frag1bytes short of the next page.
> 
> Wait, let me try that again:
> 
> 	p = page_address(*xdr->page_ptr);
> 	xdr->p = (void *)p + frag2bytes;
> 	space_left = xdr->buf->buflen - xdr->buf->len - frag1bytes;
>        xdr->end = (void *)p + min_t(int, space_left, PAGE_SIZE);
> 
> If you've still got a lot of buffer space left, then that'll put
> xdr->end frag2bytes past the end of a page, won't it?

So far I haven't heard any complaints from the kernel. I'll
instrument the code and see what comes up.


>>> I'm not sure that's right.
>> 
>> Why would that not be OK? the next call to xdr_get_next_encode_buffer()
>> should do the right thing and bounce the new encoded data from the
>> next page into this one again.
>> 
>> So far I have not encountered any problems. Would such a problem show
>> up with some frequency under normal use, or would it be especially
>> subtle?
> 
> I mainly just want to make sure we've got a coherent idea what this code
> is doing....

Agreed, that's a good thing.


> For testing: large replies that aren't just read data are readdir and
> getacl.  So reading large directories with lots of variably-named files
> might be good. Also pynfs could easily send a single compound with lots
> of variable-sized reads, that might be interesting.

I've run the full git regression suite over NFSv3 many many times with
this patch applied. That includes unpacking via tar, a full build from
scratch, and then running thousands of individual tests.

So that doesn't exercise a particular corner case, but it does reflect
a broad variety of directory operations.


> Constructing a compound that will result in xdr_reserve_space calls that
> exactly hit the various corner cases may be hard.  But maybe if we just
> send a bunch of compounds that vary over some range we can still
> guarantee hitting those cases.
> 
> --b.

--
Chuck Lever




^ permalink raw reply	[flat|nested] 58+ messages in thread

* Re: [PATCH v1 19/42] SUNRPC: Fix xdr_get_next_encode_buffer() page boundary handling
  2021-03-03 18:19         ` Chuck Lever
@ 2021-03-03 18:25           ` Bruce Fields
  2021-03-03 18:27             ` Chuck Lever
  0 siblings, 1 reply; 58+ messages in thread
From: Bruce Fields @ 2021-03-03 18:25 UTC (permalink / raw)
  To: Chuck Lever; +Cc: Linux NFS Mailing List

On Wed, Mar 03, 2021 at 06:19:33PM +0000, Chuck Lever wrote:
> 
> 
> > On Mar 3, 2021, at 11:52 AM, Bruce Fields <bfields@fieldses.org> wrote:
> > 
> > On Wed, Mar 03, 2021 at 03:43:28PM +0000, Chuck Lever wrote:
> >> Why would that not be OK? the next call to xdr_get_next_encode_buffer()
> >> should do the right thing and bounce the new encoded data from the
> >> next page into this one again.
> >> 
> >> So far I have not encountered any problems. Would such a problem show
> >> up with some frequency under normal use, or would it be especially
> >> subtle?
> > 
> > I mainly just want to make sure we've got a coherent idea what this code
> > is doing....
> 
> Agreed, that's a good thing.

I'm also a little vague on what exactly the problem is you're running
into.  (Probably because I haven't really looked at the v3 readdir
encoding.)

Is it approaching the end of a page, or is it running out of buflen?
How exactly does it fail?

--b.

> 
> 
> > For testing: large replies that aren't just read data are readdir and
> > getacl.  So reading large directories with lots of variably-named files
> > might be good. Also pynfs could easily send a single compound with lots
> > of variable-sized reads, that might be interesting.
> 
> I've run the full git regression suite over NFSv3 many many times with
> this patch applied. That includes unpacking via tar, a full build from
> scratch, and then running thousands of individual tests.
> 
> So that doesn't exercise a particular corner case, but it does reflect
> a broad variety of directory operations.
> 
> 
> > Constructing a compound that will result in xdr_reserve_space calls that
> > exactly hit the various corner cases may be hard.  But maybe if we just
> > send a bunch of compounds that vary over some range we can still
> > guarantee hitting those cases.
> > 
> > --b.
> 
> --
> Chuck Lever
> 
> 

^ permalink raw reply	[flat|nested] 58+ messages in thread

* Re: [PATCH v1 19/42] SUNRPC: Fix xdr_get_next_encode_buffer() page boundary handling
  2021-03-03 18:25           ` Bruce Fields
@ 2021-03-03 18:27             ` Chuck Lever
  2021-03-03 18:30               ` Chuck Lever
  0 siblings, 1 reply; 58+ messages in thread
From: Chuck Lever @ 2021-03-03 18:27 UTC (permalink / raw)
  To: Bruce Fields; +Cc: Linux NFS Mailing List



> On Mar 3, 2021, at 1:25 PM, Bruce Fields <bfields@fieldses.org> wrote:
> 
> On Wed, Mar 03, 2021 at 06:19:33PM +0000, Chuck Lever wrote:
>> 
>> 
>>> On Mar 3, 2021, at 11:52 AM, Bruce Fields <bfields@fieldses.org> wrote:
>>> 
>>> On Wed, Mar 03, 2021 at 03:43:28PM +0000, Chuck Lever wrote:
>>>> Why would that not be OK? the next call to xdr_get_next_encode_buffer()
>>>> should do the right thing and bounce the new encoded data from the
>>>> next page into this one again.
>>>> 
>>>> So far I have not encountered any problems. Would such a problem show
>>>> up with some frequency under normal use, or would it be especially
>>>> subtle?
>>> 
>>> I mainly just want to make sure we've got a coherent idea what this code
>>> is doing....
>> 
>> Agreed, that's a good thing.
> 
> I'm also a little vague on what exactly the problem is you're running
> into.  (Probably because I haven't really looked at the v3 readdir
> encoding.)
> 
> Is it approaching the end of a page, or is it running out of buflen?
> How exactly does it fail?

I don't recall exactly, it was a late last summer when I wrote all these.

Approaching the end of a page, IIRC, the unpatched code would leave
a gap in the directory entry stream.


> --b.
> 
>> 
>> 
>>> For testing: large replies that aren't just read data are readdir and
>>> getacl.  So reading large directories with lots of variably-named files
>>> might be good. Also pynfs could easily send a single compound with lots
>>> of variable-sized reads, that might be interesting.
>> 
>> I've run the full git regression suite over NFSv3 many many times with
>> this patch applied. That includes unpacking via tar, a full build from
>> scratch, and then running thousands of individual tests.
>> 
>> So that doesn't exercise a particular corner case, but it does reflect
>> a broad variety of directory operations.
>> 
>> 
>>> Constructing a compound that will result in xdr_reserve_space calls that
>>> exactly hit the various corner cases may be hard.  But maybe if we just
>>> send a bunch of compounds that vary over some range we can still
>>> guarantee hitting those cases.
>>> 
>>> --b.
>> 
>> --
>> Chuck Lever

--
Chuck Lever




^ permalink raw reply	[flat|nested] 58+ messages in thread

* Re: [PATCH v1 19/42] SUNRPC: Fix xdr_get_next_encode_buffer() page boundary handling
  2021-03-03 18:27             ` Chuck Lever
@ 2021-03-03 18:30               ` Chuck Lever
  2021-03-03 18:38                 ` Bruce Fields
  0 siblings, 1 reply; 58+ messages in thread
From: Chuck Lever @ 2021-03-03 18:30 UTC (permalink / raw)
  To: Bruce Fields; +Cc: Linux NFS Mailing List



> On Mar 3, 2021, at 1:27 PM, Chuck Lever <chuck.lever@oracle.com> wrote:
> 
> 
> 
>> On Mar 3, 2021, at 1:25 PM, Bruce Fields <bfields@fieldses.org> wrote:
>> 
>> On Wed, Mar 03, 2021 at 06:19:33PM +0000, Chuck Lever wrote:
>>> 
>>> 
>>>> On Mar 3, 2021, at 11:52 AM, Bruce Fields <bfields@fieldses.org> wrote:
>>>> 
>>>> On Wed, Mar 03, 2021 at 03:43:28PM +0000, Chuck Lever wrote:
>>>>> Why would that not be OK? the next call to xdr_get_next_encode_buffer()
>>>>> should do the right thing and bounce the new encoded data from the
>>>>> next page into this one again.
>>>>> 
>>>>> So far I have not encountered any problems. Would such a problem show
>>>>> up with some frequency under normal use, or would it be especially
>>>>> subtle?
>>>> 
>>>> I mainly just want to make sure we've got a coherent idea what this code
>>>> is doing....
>>> 
>>> Agreed, that's a good thing.
>> 
>> I'm also a little vague on what exactly the problem is you're running
>> into.  (Probably because I haven't really looked at the v3 readdir
>> encoding.)
>> 
>> Is it approaching the end of a page, or is it running out of buflen?
>> How exactly does it fail?
> 
> I don't recall exactly, it was a late last summer when I wrote all these.
> 
> Approaching the end of a page, IIRC, the unpatched code would leave
> a gap in the directory entry stream.

Well, when I converted the entry encoders to use xdr_stream, it would
have a problem around the end of a page. The existing encoders are
open-coded to deal with this case.


>> --b.
>> 
>>> 
>>> 
>>>> For testing: large replies that aren't just read data are readdir and
>>>> getacl.  So reading large directories with lots of variably-named files
>>>> might be good. Also pynfs could easily send a single compound with lots
>>>> of variable-sized reads, that might be interesting.
>>> 
>>> I've run the full git regression suite over NFSv3 many many times with
>>> this patch applied. That includes unpacking via tar, a full build from
>>> scratch, and then running thousands of individual tests.
>>> 
>>> So that doesn't exercise a particular corner case, but it does reflect
>>> a broad variety of directory operations.
>>> 
>>> 
>>>> Constructing a compound that will result in xdr_reserve_space calls that
>>>> exactly hit the various corner cases may be hard.  But maybe if we just
>>>> send a bunch of compounds that vary over some range we can still
>>>> guarantee hitting those cases.
>>>> 
>>>> --b.
>>> 
>>> --
>>> Chuck Lever
> 
> --
> Chuck Lever

--
Chuck Lever




^ permalink raw reply	[flat|nested] 58+ messages in thread

* Re: [PATCH v1 19/42] SUNRPC: Fix xdr_get_next_encode_buffer() page boundary handling
  2021-03-03 18:30               ` Chuck Lever
@ 2021-03-03 18:38                 ` Bruce Fields
  2021-03-03 18:42                   ` Chuck Lever
  0 siblings, 1 reply; 58+ messages in thread
From: Bruce Fields @ 2021-03-03 18:38 UTC (permalink / raw)
  To: Chuck Lever; +Cc: Linux NFS Mailing List

On Wed, Mar 03, 2021 at 06:30:40PM +0000, Chuck Lever wrote:
> 
> 
> > On Mar 3, 2021, at 1:27 PM, Chuck Lever <chuck.lever@oracle.com> wrote:
> > 
> > 
> > 
> >> On Mar 3, 2021, at 1:25 PM, Bruce Fields <bfields@fieldses.org> wrote:
> >> 
> >> On Wed, Mar 03, 2021 at 06:19:33PM +0000, Chuck Lever wrote:
> >>> 
> >>> 
> >>>> On Mar 3, 2021, at 11:52 AM, Bruce Fields <bfields@fieldses.org> wrote:
> >>>> 
> >>>> On Wed, Mar 03, 2021 at 03:43:28PM +0000, Chuck Lever wrote:
> >>>>> Why would that not be OK? the next call to xdr_get_next_encode_buffer()
> >>>>> should do the right thing and bounce the new encoded data from the
> >>>>> next page into this one again.
> >>>>> 
> >>>>> So far I have not encountered any problems. Would such a problem show
> >>>>> up with some frequency under normal use, or would it be especially
> >>>>> subtle?
> >>>> 
> >>>> I mainly just want to make sure we've got a coherent idea what this code
> >>>> is doing....
> >>> 
> >>> Agreed, that's a good thing.
> >> 
> >> I'm also a little vague on what exactly the problem is you're running
> >> into.  (Probably because I haven't really looked at the v3 readdir
> >> encoding.)
> >> 
> >> Is it approaching the end of a page, or is it running out of buflen?
> >> How exactly does it fail?
> > 
> > I don't recall exactly, it was a late last summer when I wrote all these.
> > 
> > Approaching the end of a page, IIRC, the unpatched code would leave
> > a gap in the directory entry stream.
> 
> Well, when I converted the entry encoders to use xdr_stream, it would
> have a problem around the end of a page. The existing encoders are
> open-coded to deal with this case.

We're not seeing v4 readdir bugs, though, I wonder what's different?

--b.

^ permalink raw reply	[flat|nested] 58+ messages in thread

* Re: [PATCH v1 19/42] SUNRPC: Fix xdr_get_next_encode_buffer() page boundary handling
  2021-03-03 18:38                 ` Bruce Fields
@ 2021-03-03 18:42                   ` Chuck Lever
  0 siblings, 0 replies; 58+ messages in thread
From: Chuck Lever @ 2021-03-03 18:42 UTC (permalink / raw)
  To: Bruce Fields; +Cc: Linux NFS Mailing List



> On Mar 3, 2021, at 1:38 PM, Bruce Fields <bfields@fieldses.org> wrote:
> 
> On Wed, Mar 03, 2021 at 06:30:40PM +0000, Chuck Lever wrote:
>> 
>> 
>>> On Mar 3, 2021, at 1:27 PM, Chuck Lever <chuck.lever@oracle.com> wrote:
>>> 
>>> 
>>> 
>>>> On Mar 3, 2021, at 1:25 PM, Bruce Fields <bfields@fieldses.org> wrote:
>>>> 
>>>> On Wed, Mar 03, 2021 at 06:19:33PM +0000, Chuck Lever wrote:
>>>>> 
>>>>> 
>>>>>> On Mar 3, 2021, at 11:52 AM, Bruce Fields <bfields@fieldses.org> wrote:
>>>>>> 
>>>>>> On Wed, Mar 03, 2021 at 03:43:28PM +0000, Chuck Lever wrote:
>>>>>>> Why would that not be OK? the next call to xdr_get_next_encode_buffer()
>>>>>>> should do the right thing and bounce the new encoded data from the
>>>>>>> next page into this one again.
>>>>>>> 
>>>>>>> So far I have not encountered any problems. Would such a problem show
>>>>>>> up with some frequency under normal use, or would it be especially
>>>>>>> subtle?
>>>>>> 
>>>>>> I mainly just want to make sure we've got a coherent idea what this code
>>>>>> is doing....
>>>>> 
>>>>> Agreed, that's a good thing.
>>>> 
>>>> I'm also a little vague on what exactly the problem is you're running
>>>> into.  (Probably because I haven't really looked at the v3 readdir
>>>> encoding.)
>>>> 
>>>> Is it approaching the end of a page, or is it running out of buflen?
>>>> How exactly does it fail?
>>> 
>>> I don't recall exactly, it was a late last summer when I wrote all these.
>>> 
>>> Approaching the end of a page, IIRC, the unpatched code would leave
>>> a gap in the directory entry stream.
>> 
>> Well, when I converted the entry encoders to use xdr_stream, it would
>> have a problem around the end of a page. The existing encoders are
>> open-coded to deal with this case.
> 
> We're not seeing v4 readdir bugs, though, I wonder what's different?

It's a small patch, easy to revert and find out with your own preferred
tests.


--
Chuck Lever




^ permalink raw reply	[flat|nested] 58+ messages in thread

end of thread, other threads:[~2021-03-04  0:31 UTC | newest]

Thread overview: 58+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2021-03-01 15:15 [PATCH v1 00/42] NFSv2/3 XDR encoder overhaul Chuck Lever
2021-03-01 15:15 ` [PATCH v1 01/42] NFSD: Extract the svcxdr_init_encode() helper Chuck Lever
2021-03-02 16:47   ` J. Bruce Fields
2021-03-02 16:57     ` Chuck Lever
2021-03-01 15:15 ` [PATCH v1 02/42] NFSD: Update the GETATTR3res encoder to use struct xdr_stream Chuck Lever
2021-03-01 15:15 ` [PATCH v1 03/42] NFSD: Update the NFSv3 ACCESS3res " Chuck Lever
2021-03-01 15:15 ` [PATCH v1 04/42] NFSD: Update the NFSv3 LOOKUP3res " Chuck Lever
2021-03-01 15:15 ` [PATCH v1 05/42] NFSD: Update the NFSv3 wccstat result " Chuck Lever
2021-03-01 15:15 ` [PATCH v1 06/42] NFSD: Update the NFSv3 READLINK3res " Chuck Lever
2021-03-01 15:16 ` [PATCH v1 07/42] NFSD: Update the NFSv3 READ3res encode " Chuck Lever
2021-03-01 15:16 ` [PATCH v1 08/42] NFSD: Update the NFSv3 WRITE3res encoder " Chuck Lever
2021-03-01 15:16 ` [PATCH v1 09/42] NFSD: Update the NFSv3 CREATE family of encoders " Chuck Lever
2021-03-01 15:16 ` [PATCH v1 10/42] NFSD: Update the NFSv3 RENAMEv3res encoder " Chuck Lever
2021-03-01 15:16 ` [PATCH v1 11/42] NFSD: Update the NFSv3 LINK3res " Chuck Lever
2021-03-01 15:16 ` [PATCH v1 12/42] NFSD: Update the NFSv3 FSSTAT3res " Chuck Lever
2021-03-02 20:45   ` J. Bruce Fields
2021-03-02 20:57     ` Chuck Lever
2021-03-01 15:16 ` [PATCH v1 13/42] NFSD: Update the NFSv3 FSINFO3res " Chuck Lever
2021-03-01 15:16 ` [PATCH v1 14/42] NFSD: Update the NFSv3 PATHCONF3res " Chuck Lever
2021-03-03  7:13   ` Christoph Hellwig
2021-03-03 15:34     ` Chuck Lever
2021-03-01 15:16 ` [PATCH v1 15/42] NFSD: Update the NFSv3 COMMIT3res " Chuck Lever
2021-03-01 15:16 ` [PATCH v1 16/42] NFSD: Add a helper that encodes NFSv3 directory offset cookies Chuck Lever
2021-03-01 15:17 ` [PATCH v1 17/42] NFSD: Count bytes instead of pages in the NFSv3 READDIR encoder Chuck Lever
2021-03-01 15:17 ` [PATCH v1 18/42] NFSD: Update the NFSv3 READDIR3res encoder to use struct xdr_stream Chuck Lever
2021-03-01 15:17 ` [PATCH v1 19/42] SUNRPC: Fix xdr_get_next_encode_buffer() page boundary handling Chuck Lever
2021-03-02 22:11   ` J. Bruce Fields
2021-03-03 15:43     ` Chuck Lever
2021-03-03 16:52       ` Bruce Fields
2021-03-03 18:19         ` Chuck Lever
2021-03-03 18:25           ` Bruce Fields
2021-03-03 18:27             ` Chuck Lever
2021-03-03 18:30               ` Chuck Lever
2021-03-03 18:38                 ` Bruce Fields
2021-03-03 18:42                   ` Chuck Lever
2021-03-01 15:17 ` [PATCH v1 20/42] NFSD: Update NFSv3 READDIR entry encoders to use struct xdr_stream Chuck Lever
2021-03-01 15:17 ` [PATCH v1 21/42] NFSD: Remove unused NFSv3 directory entry encoders Chuck Lever
2021-03-01 15:17 ` [PATCH v1 22/42] NFSD: Reduce svc_rqst::rq_pages churn during READDIR operations Chuck Lever
2021-03-01 15:17 ` [PATCH v1 23/42] NFSD: Update the NFSv2 stat encoder to use struct xdr_stream Chuck Lever
2021-03-01 15:17 ` [PATCH v1 24/42] NFSD: Update the NFSv2 attrstat " Chuck Lever
2021-03-01 15:17 ` [PATCH v1 25/42] NFSD: Update the NFSv2 diropres " Chuck Lever
2021-03-01 15:17 ` [PATCH v1 26/42] NFSD: Update the NFSv2 READLINK result " Chuck Lever
2021-03-01 15:18 ` [PATCH v1 27/42] NFSD: Update the NFSv2 READ " Chuck Lever
2021-03-01 15:18 ` [PATCH v1 28/42] NFSD: Update the NFSv2 STATFS " Chuck Lever
2021-03-01 15:18 ` [PATCH v1 29/42] NFSD: Add a helper that encodes NFSv3 directory offset cookies Chuck Lever
2021-03-01 15:18 ` [PATCH v1 30/42] NFSD: Count bytes instead of pages in the NFSv2 READDIR encoder Chuck Lever
2021-03-01 15:18 ` [PATCH v1 31/42] NFSD: Update the NFSv2 READDIR result encoder to use struct xdr_stream Chuck Lever
2021-03-01 15:18 ` [PATCH v1 32/42] NFSD: Update the NFSv2 READDIR entry " Chuck Lever
2021-03-01 15:18 ` [PATCH v1 33/42] NFSD: Remove unused NFSv2 directory entry encoders Chuck Lever
2021-03-01 15:18 ` [PATCH v1 34/42] NFSD: Add an xdr_stream-based encoder for NFSv2/3 ACLs Chuck Lever
2021-03-01 15:18 ` [PATCH v1 35/42] NFSD: Update the NFSv2 GETACL result encoder to use struct xdr_stream Chuck Lever
2021-03-01 15:18 ` [PATCH v1 36/42] NFSD: Update the NFSv2 SETACL " Chuck Lever
2021-03-01 15:19 ` [PATCH v1 37/42] NFSD: Update the NFSv2 ACL GETATTR " Chuck Lever
2021-03-01 15:19 ` [PATCH v1 38/42] NFSD: Update the NFSv2 ACL ACCESS " Chuck Lever
2021-03-01 15:19 ` [PATCH v1 39/42] NFSD: Clean up after updating NFSv2 ACL encoders Chuck Lever
2021-03-01 15:19 ` [PATCH v1 40/42] NFSD: Update the NFSv3 GETACL result encoder to use struct xdr_stream Chuck Lever
2021-03-01 15:19 ` [PATCH v1 41/42] NFSD: Update the NFSv3 SETACL " Chuck Lever
2021-03-01 15:19 ` [PATCH v1 42/42] NFSD: Clean up after updating NFSv3 ACL encoders Chuck Lever

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).