Commit 8eefed8f authored by Linus Torvalds's avatar Linus Torvalds
Browse files
Pull nfsd fixes from Chuck Lever:
 "Regression fixes:

   - Revert the patch that removed the cap on MAX_OPS_PER_COMPOUND

   - Address a kernel build issue

  Stable fixes:

   - Fix crash when a client queries new attributes on forechannel

   - Fix rare NFSD crash when tracing is enabled"

* tag 'nfsd-6.18-2' of git://git.kernel.org/pub/scm/linux/kernel/git/cel/linux:
  Revert "NFSD: Remove the cap on number of operations per NFSv4 COMPOUND"
  nfsd: Avoid strlen conflict in nfsd4_encode_components_esc()
  NFSD: Fix crash in nfsd4_read_release()
  NFSD: Define actions for the new time_deleg FATTR4 attributes
parents fd575722 3e7f011c
Loading
Loading
Loading
Loading
+16 −5
Original line number Diff line number Diff line
@@ -988,10 +988,11 @@ nfsd4_read(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
static void
nfsd4_read_release(union nfsd4_op_u *u)
{
	if (u->read.rd_nf)
		nfsd_file_put(u->read.rd_nf);
	if (u->read.rd_nf) {
		trace_nfsd_read_done(u->read.rd_rqstp, u->read.rd_fhp,
				     u->read.rd_offset, u->read.rd_length);
		nfsd_file_put(u->read.rd_nf);
	}
}

static __be32
@@ -2892,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
@@ -2972,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);
+1 −0
Original line number Diff line number Diff line
@@ -3902,6 +3902,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);
+14 −7
Original line number Diff line number Diff line
@@ -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));
@@ -2628,10 +2630,8 @@ static __be32 nfsd4_encode_components_esc(struct xdr_stream *xdr, char sep,
	__be32 *p;
	__be32 pathlen;
	int pathlen_offset;
	int strlen, count=0;
	char *str, *end, *next;

	dprintk("nfsd4_encode_components(%s)\n", components);
	int count = 0;

	pathlen_offset = xdr->buf->len;
	p = xdr_reserve_space(xdr, 4);
@@ -2658,9 +2658,8 @@ static __be32 nfsd4_encode_components_esc(struct xdr_stream *xdr, char sep,
			for (; *end && (*end != sep); end++)
				/* find sep or end of string */;

		strlen = end - str;
		if (strlen) {
			if (xdr_stream_encode_opaque(xdr, str, strlen) < 0)
		if (end > str) {
			if (xdr_stream_encode_opaque(xdr, str, end - str) < 0)
				return nfserr_resource;
			count++;
		} else
@@ -2939,6 +2938,12 @@ struct nfsd4_fattr_args {
typedef __be32(*nfsd4_enc_attr)(struct xdr_stream *xdr,
				const struct nfsd4_fattr_args *args);

static __be32 nfsd4_encode_fattr4__inval(struct xdr_stream *xdr,
					 const struct nfsd4_fattr_args *args)
{
	return nfserr_inval;
}

static __be32 nfsd4_encode_fattr4__noop(struct xdr_stream *xdr,
					const struct nfsd4_fattr_args *args)
{
@@ -3560,6 +3565,8 @@ static const nfsd4_enc_attr nfsd4_enc_fattr4_encode_ops[] = {

	[FATTR4_MODE_UMASK]		= nfsd4_encode_fattr4__noop,
	[FATTR4_XATTR_SUPPORT]		= nfsd4_encode_fattr4_xattr_support,
	[FATTR4_TIME_DELEG_ACCESS]	= nfsd4_encode_fattr4__inval,
	[FATTR4_TIME_DELEG_MODIFY]	= nfsd4_encode_fattr4__inval,
	[FATTR4_OPEN_ARGUMENTS]		= nfsd4_encode_fattr4_open_arguments,
};

+3 −0
Original line number Diff line number Diff line
@@ -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;
+1 −0
Original line number Diff line number Diff line
@@ -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;