[PATCH 2/2] nfsd: set op->status when an operation's header cannot be encoded
Chuck Lever <[email protected]>
| Newsgroups | gmane.linux.nfs |
|---|---|
| Message-ID | <[email protected]> |
nfsd4_encode_operation() leaves op->status alone when the reply buffer has no room for the operation's opcode and status word. nfsd4_proc_compound() reads the unchanged nfs_ok as success and goes on to the next operation, so the reply counts an operation whose result was never encoded. Report the failure through nfsd4_check_resp_size(), which the rest of the function already uses. It returns NFS4ERR_REP_TOO_BIG, or NFS4ERR_REP_TOO_BIG_TO_CACHE on a session, and the COMPOUND ends at that operation. Two paths narrow the reply buffer: nfsd4_sequence(), which rejects a SEQUENCE result that does not fit, and nfsd4_encode_splice_read(), which can leave a single XDR word in the head page. Whether a COMPOUND reaches that boundary is unproven, so this is a guard rather than a fix. Signed-off-by: Chuck Lever <[email protected]> --- fs/nfsd/nfs4xdr.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c index 7d1b2d6f57f2..a154b02d82b3 100644 --- a/fs/nfsd/nfs4xdr.c +++ b/fs/nfsd/nfs4xdr.c @@ -6723,11 +6723,20 @@ nfsd4_encode_operation(struct nfsd4_compoundres *resp, struct nfsd4_op *op) unsigned int op_status_offset; nfsd4_enc encoder; - if (xdr_stream_encode_u32(xdr, op->opnum) != XDR_UNIT) + /* + * nfsd4_proc_compound() stops the COMPOUND early only + * when op->status is set, so a header that cannot be + * encoded has to report the failure here. + */ + if (xdr_stream_encode_u32(xdr, op->opnum) != XDR_UNIT) { + op->status = nfsd4_check_resp_size(resp, XDR_UNIT * 2); goto release; + } op_status_offset = xdr->buf->len; - if (!xdr_reserve_space(xdr, XDR_UNIT)) + if (!xdr_reserve_space(xdr, XDR_UNIT)) { + op->status = nfsd4_check_resp_size(resp, XDR_UNIT); goto release; + } if (op->opnum == OP_ILLEGAL) goto status; -- 2.54.0