On Mon, Mar 01, 2021 at 10:16:31AM -0500, Chuck Lever wrote: > Signed-off-by: Chuck Lever <chuck.lever@xxxxxxxxxx> > --- > 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 */ >