* [PATCH v1] Revert "NFSD: Remove the cap on number of operations per NFSv4 COMPOUND"
@ 2025-10-01 13:28 Chuck Lever
2025-10-01 14:00 ` Jeff Layton
0 siblings, 1 reply; 2+ messages in thread
From: Chuck Lever @ 2025-10-01 13:28 UTC (permalink / raw)
To: NeilBrown, Jeff Layton, Olga Kornievskaia, Dai Ngo, Tom Talpey
Cc: linux-nfs, Chuck Lever
From: Chuck Lever <chuck.lever@oracle.com>
I've found that pynfs COMP6 leaves the connection or lease in a
strange state, which causes CLOSE9 to hang indefinitely. I've dug
into it a little, but I haven't been able to root-cause it yet.
Let's restore a 200 operation-per-COMPOUND limit. NFSD CI will pass,
and I can continue debugging.
Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
---
fs/nfsd/nfs4proc.c | 14 ++++++++++++--
fs/nfsd/nfs4state.c | 1 +
fs/nfsd/nfs4xdr.c | 4 +++-
fs/nfsd/nfsd.h | 3 +++
fs/nfsd/xdr4.h | 1 +
5 files changed, 20 insertions(+), 3 deletions(-)
diff --git a/fs/nfsd/nfs4proc.c b/fs/nfsd/nfs4proc.c
index f9aeefc0da73..7f7e6bb23a90 100644
--- a/fs/nfsd/nfs4proc.c
+++ b/fs/nfsd/nfs4proc.c
@@ -2893,10 +2893,20 @@ nfsd4_proc_compound(struct svc_rqst *rqstp)
rqstp->rq_lease_breaker = (void **)&cstate->clp;
- trace_nfsd_compound(rqstp, args->tag, args->taglen, args->opcnt);
+ trace_nfsd_compound(rqstp, args->tag, args->taglen, args->client_opcnt);
while (!status && resp->opcnt < args->opcnt) {
op = &args->ops[resp->opcnt++];
+ if (unlikely(resp->opcnt == NFSD_MAX_OPS_PER_COMPOUND)) {
+ /* If there are still more operations to process,
+ * stop here and report NFS4ERR_RESOURCE. */
+ if (cstate->minorversion == 0 &&
+ args->client_opcnt > resp->opcnt) {
+ op->status = nfserr_resource;
+ goto encode_op;
+ }
+ }
+
/*
* The XDR decode routines may have pre-set op->status;
* for example, if there is a miscellaneous XDR error
@@ -2973,7 +2983,7 @@ nfsd4_proc_compound(struct svc_rqst *rqstp)
status = op->status;
}
- trace_nfsd_compound_status(args->opcnt, resp->opcnt,
+ trace_nfsd_compound_status(args->client_opcnt, resp->opcnt,
status, nfsd4_op_name(op->opnum));
nfsd4_cstate_clear_replay(cstate);
diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c
index 7c60d2ffe21c..0de9ee8df7ce 100644
--- a/fs/nfsd/nfs4state.c
+++ b/fs/nfsd/nfs4state.c
@@ -3907,6 +3907,7 @@ static __be32 check_forechannel_attrs(struct nfsd4_channel_attrs *ca, struct nfs
ca->headerpadsz = 0;
ca->maxreq_sz = min_t(u32, ca->maxreq_sz, maxrpc);
ca->maxresp_sz = min_t(u32, ca->maxresp_sz, maxrpc);
+ ca->maxops = min_t(u32, ca->maxops, NFSD_MAX_OPS_PER_COMPOUND);
ca->maxresp_cached = min_t(u32, ca->maxresp_cached,
NFSD_SLOT_CACHE_SIZE + NFSD_MIN_HDR_SEQ_SZ);
ca->maxreqs = min_t(u32, ca->maxreqs, NFSD_MAX_SLOTS_PER_SESSION);
diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c
index 6a56dca6fb04..230bf53e39f7 100644
--- a/fs/nfsd/nfs4xdr.c
+++ b/fs/nfsd/nfs4xdr.c
@@ -2488,8 +2488,10 @@ nfsd4_decode_compound(struct nfsd4_compoundargs *argp)
if (xdr_stream_decode_u32(argp->xdr, &argp->minorversion) < 0)
return false;
- if (xdr_stream_decode_u32(argp->xdr, &argp->opcnt) < 0)
+ if (xdr_stream_decode_u32(argp->xdr, &argp->client_opcnt) < 0)
return false;
+ argp->opcnt = min_t(u32, argp->client_opcnt,
+ NFSD_MAX_OPS_PER_COMPOUND);
if (argp->opcnt > ARRAY_SIZE(argp->iops)) {
argp->ops = vcalloc(argp->opcnt, sizeof(*argp->ops));
diff --git a/fs/nfsd/nfsd.h b/fs/nfsd/nfsd.h
index 6812cd231b1d..8ffed4f0b95f 100644
--- a/fs/nfsd/nfsd.h
+++ b/fs/nfsd/nfsd.h
@@ -57,6 +57,9 @@ struct readdir_cd {
__be32 err; /* 0, nfserr, or nfserr_eof */
};
+/* Maximum number of operations per session compound */
+#define NFSD_MAX_OPS_PER_COMPOUND 200
+
struct nfsd_genl_rqstp {
struct sockaddr rq_daddr;
struct sockaddr rq_saddr;
diff --git a/fs/nfsd/xdr4.h b/fs/nfsd/xdr4.h
index d4b48602b2b0..ee0570cbdd9e 100644
--- a/fs/nfsd/xdr4.h
+++ b/fs/nfsd/xdr4.h
@@ -903,6 +903,7 @@ struct nfsd4_compoundargs {
char * tag;
u32 taglen;
u32 minorversion;
+ u32 client_opcnt;
u32 opcnt;
bool splice_ok;
struct nfsd4_op *ops;
--
2.51.0
^ permalink raw reply related [flat|nested] 2+ messages in thread* Re: [PATCH v1] Revert "NFSD: Remove the cap on number of operations per NFSv4 COMPOUND"
2025-10-01 13:28 [PATCH v1] Revert "NFSD: Remove the cap on number of operations per NFSv4 COMPOUND" Chuck Lever
@ 2025-10-01 14:00 ` Jeff Layton
0 siblings, 0 replies; 2+ messages in thread
From: Jeff Layton @ 2025-10-01 14:00 UTC (permalink / raw)
To: Chuck Lever, NeilBrown, Olga Kornievskaia, Dai Ngo, Tom Talpey
Cc: linux-nfs, Chuck Lever
On Wed, 2025-10-01 at 09:28 -0400, Chuck Lever wrote:
> From: Chuck Lever <chuck.lever@oracle.com>
>
> I've found that pynfs COMP6 leaves the connection or lease in a
> strange state, which causes CLOSE9 to hang indefinitely. I've dug
> into it a little, but I haven't been able to root-cause it yet.
>
> Let's restore a 200 operation-per-COMPOUND limit. NFSD CI will pass,
> and I can continue debugging.
>
> Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
> ---
> fs/nfsd/nfs4proc.c | 14 ++++++++++++--
> fs/nfsd/nfs4state.c | 1 +
> fs/nfsd/nfs4xdr.c | 4 +++-
> fs/nfsd/nfsd.h | 3 +++
> fs/nfsd/xdr4.h | 1 +
> 5 files changed, 20 insertions(+), 3 deletions(-)
>
> diff --git a/fs/nfsd/nfs4proc.c b/fs/nfsd/nfs4proc.c
> index f9aeefc0da73..7f7e6bb23a90 100644
> --- a/fs/nfsd/nfs4proc.c
> +++ b/fs/nfsd/nfs4proc.c
> @@ -2893,10 +2893,20 @@ nfsd4_proc_compound(struct svc_rqst *rqstp)
>
> rqstp->rq_lease_breaker = (void **)&cstate->clp;
>
> - trace_nfsd_compound(rqstp, args->tag, args->taglen, args->opcnt);
> + trace_nfsd_compound(rqstp, args->tag, args->taglen, args->client_opcnt);
> while (!status && resp->opcnt < args->opcnt) {
> op = &args->ops[resp->opcnt++];
>
> + if (unlikely(resp->opcnt == NFSD_MAX_OPS_PER_COMPOUND)) {
> + /* If there are still more operations to process,
> + * stop here and report NFS4ERR_RESOURCE. */
> + if (cstate->minorversion == 0 &&
> + args->client_opcnt > resp->opcnt) {
> + op->status = nfserr_resource;
> + goto encode_op;
> + }
> + }
> +
> /*
> * The XDR decode routines may have pre-set op->status;
> * for example, if there is a miscellaneous XDR error
> @@ -2973,7 +2983,7 @@ nfsd4_proc_compound(struct svc_rqst *rqstp)
> status = op->status;
> }
>
> - trace_nfsd_compound_status(args->opcnt, resp->opcnt,
> + trace_nfsd_compound_status(args->client_opcnt, resp->opcnt,
> status, nfsd4_op_name(op->opnum));
>
> nfsd4_cstate_clear_replay(cstate);
> diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c
> index 7c60d2ffe21c..0de9ee8df7ce 100644
> --- a/fs/nfsd/nfs4state.c
> +++ b/fs/nfsd/nfs4state.c
> @@ -3907,6 +3907,7 @@ static __be32 check_forechannel_attrs(struct nfsd4_channel_attrs *ca, struct nfs
> ca->headerpadsz = 0;
> ca->maxreq_sz = min_t(u32, ca->maxreq_sz, maxrpc);
> ca->maxresp_sz = min_t(u32, ca->maxresp_sz, maxrpc);
> + ca->maxops = min_t(u32, ca->maxops, NFSD_MAX_OPS_PER_COMPOUND);
> ca->maxresp_cached = min_t(u32, ca->maxresp_cached,
> NFSD_SLOT_CACHE_SIZE + NFSD_MIN_HDR_SEQ_SZ);
> ca->maxreqs = min_t(u32, ca->maxreqs, NFSD_MAX_SLOTS_PER_SESSION);
> diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c
> index 6a56dca6fb04..230bf53e39f7 100644
> --- a/fs/nfsd/nfs4xdr.c
> +++ b/fs/nfsd/nfs4xdr.c
> @@ -2488,8 +2488,10 @@ nfsd4_decode_compound(struct nfsd4_compoundargs *argp)
>
> if (xdr_stream_decode_u32(argp->xdr, &argp->minorversion) < 0)
> return false;
> - if (xdr_stream_decode_u32(argp->xdr, &argp->opcnt) < 0)
> + if (xdr_stream_decode_u32(argp->xdr, &argp->client_opcnt) < 0)
> return false;
> + argp->opcnt = min_t(u32, argp->client_opcnt,
> + NFSD_MAX_OPS_PER_COMPOUND);
>
> if (argp->opcnt > ARRAY_SIZE(argp->iops)) {
> argp->ops = vcalloc(argp->opcnt, sizeof(*argp->ops));
> diff --git a/fs/nfsd/nfsd.h b/fs/nfsd/nfsd.h
> index 6812cd231b1d..8ffed4f0b95f 100644
> --- a/fs/nfsd/nfsd.h
> +++ b/fs/nfsd/nfsd.h
> @@ -57,6 +57,9 @@ struct readdir_cd {
> __be32 err; /* 0, nfserr, or nfserr_eof */
> };
>
> +/* Maximum number of operations per session compound */
> +#define NFSD_MAX_OPS_PER_COMPOUND 200
> +
> struct nfsd_genl_rqstp {
> struct sockaddr rq_daddr;
> struct sockaddr rq_saddr;
> diff --git a/fs/nfsd/xdr4.h b/fs/nfsd/xdr4.h
> index d4b48602b2b0..ee0570cbdd9e 100644
> --- a/fs/nfsd/xdr4.h
> +++ b/fs/nfsd/xdr4.h
> @@ -903,6 +903,7 @@ struct nfsd4_compoundargs {
> char * tag;
> u32 taglen;
> u32 minorversion;
> + u32 client_opcnt;
> u32 opcnt;
> bool splice_ok;
> struct nfsd4_op *ops;
Seems like a reasonable stopgap fix until we can figure out why it's
hanging in the first place.
Reviewed-by: Jeff Layton <jlayton@kernel.org>
^ permalink raw reply [flat|nested] 2+ messages in thread
end of thread, other threads:[~2025-10-01 14:00 UTC | newest]
Thread overview: 2+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2025-10-01 13:28 [PATCH v1] Revert "NFSD: Remove the cap on number of operations per NFSv4 COMPOUND" Chuck Lever
2025-10-01 14:00 ` Jeff Layton
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.