> On Mar 2, 2021, at 3:45 PM, J. Bruce Fields <bfields@xxxxxxxxxxxx> wrote: > > 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? 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