Skip to content
/ linux Public

Commit 243f71e

Browse files
Anthony IliopoulosSasha Levin
authored andcommitted
nfsd: never defer requests during idmap lookup
[ Upstream commit f9c206c ] During v4 request compound arg decoding, some ops (e.g. SETATTR) can trigger idmap lookup upcalls. When those upcall responses get delayed beyond the allowed time limit, cache_check() will mark the request for deferral and cause it to be dropped. This prevents nfs4svc_encode_compoundres from being executed, and thus the session slot flag NFSD4_SLOT_INUSE never gets cleared. Subsequent client requests will fail with NFSERR_JUKEBOX, given that the slot will be marked as in-use, making the SEQUENCE op fail. Fix this by making sure that the RQ_USEDEFERRAL flag is always clear during nfs4svc_decode_compoundargs(), since no v4 request should ever be deferred. Fixes: 2f42587 ("nfsd: don't use the deferral service, return NFS4ERR_DELAY") Signed-off-by: Anthony Iliopoulos <ailiop@suse.com> Reviewed-by: NeilBrown <neil@brown.name> Signed-off-by: Chuck Lever <chuck.lever@oracle.com> Signed-off-by: Sasha Levin <sashal@kernel.org>
1 parent 0114244 commit 243f71e

File tree

3 files changed

+58
-8
lines changed

3 files changed

+58
-8
lines changed

fs/nfsd/nfs4idmap.c

Lines changed: 42 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -643,13 +643,31 @@ static __be32 encode_name_from_id(struct xdr_stream *xdr,
643643
return idmap_id_to_name(xdr, rqstp, type, id);
644644
}
645645

646-
__be32
647-
nfsd_map_name_to_uid(struct svc_rqst *rqstp, const char *name, size_t namelen,
648-
kuid_t *uid)
646+
/**
647+
* nfsd_map_name_to_uid - Map user@domain to local UID
648+
* @rqstp: RPC execution context
649+
* @name: user@domain name to be mapped
650+
* @namelen: length of name, in bytes
651+
* @uid: OUT: mapped local UID value
652+
*
653+
* Returns nfs_ok on success or an NFSv4 status code on failure.
654+
*/
655+
__be32 nfsd_map_name_to_uid(struct svc_rqst *rqstp, const char *name,
656+
size_t namelen, kuid_t *uid)
649657
{
650658
__be32 status;
651659
u32 id = -1;
652660

661+
/*
662+
* The idmap lookup below triggers an upcall that invokes
663+
* cache_check(). RQ_USEDEFERRAL must be clear to prevent
664+
* cache_check() from setting RQ_DROPME via svc_defer().
665+
* NFSv4 servers are not permitted to drop requests. Also
666+
* RQ_DROPME will force NFSv4.1 session slot processing to
667+
* be skipped.
668+
*/
669+
WARN_ON_ONCE(test_bit(RQ_USEDEFERRAL, &rqstp->rq_flags));
670+
653671
if (name == NULL || namelen == 0)
654672
return nfserr_inval;
655673

@@ -660,13 +678,31 @@ nfsd_map_name_to_uid(struct svc_rqst *rqstp, const char *name, size_t namelen,
660678
return status;
661679
}
662680

663-
__be32
664-
nfsd_map_name_to_gid(struct svc_rqst *rqstp, const char *name, size_t namelen,
665-
kgid_t *gid)
681+
/**
682+
* nfsd_map_name_to_gid - Map user@domain to local GID
683+
* @rqstp: RPC execution context
684+
* @name: user@domain name to be mapped
685+
* @namelen: length of name, in bytes
686+
* @gid: OUT: mapped local GID value
687+
*
688+
* Returns nfs_ok on success or an NFSv4 status code on failure.
689+
*/
690+
__be32 nfsd_map_name_to_gid(struct svc_rqst *rqstp, const char *name,
691+
size_t namelen, kgid_t *gid)
666692
{
667693
__be32 status;
668694
u32 id = -1;
669695

696+
/*
697+
* The idmap lookup below triggers an upcall that invokes
698+
* cache_check(). RQ_USEDEFERRAL must be clear to prevent
699+
* cache_check() from setting RQ_DROPME via svc_defer().
700+
* NFSv4 servers are not permitted to drop requests. Also
701+
* RQ_DROPME will force NFSv4.1 session slot processing to
702+
* be skipped.
703+
*/
704+
WARN_ON_ONCE(test_bit(RQ_USEDEFERRAL, &rqstp->rq_flags));
705+
670706
if (name == NULL || namelen == 0)
671707
return nfserr_inval;
672708

fs/nfsd/nfs4proc.c

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2763,8 +2763,6 @@ nfsd4_proc_compound(struct svc_rqst *rqstp)
27632763
BUG_ON(cstate->replay_owner);
27642764
out:
27652765
cstate->status = status;
2766-
/* Reset deferral mechanism for RPC deferrals */
2767-
set_bit(RQ_USEDEFERRAL, &rqstp->rq_flags);
27682766
return rpc_success;
27692767
}
27702768

fs/nfsd/nfs4xdr.c

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5492,6 +5492,22 @@ nfs4svc_decode_compoundargs(struct svc_rqst *rqstp, struct xdr_stream *xdr)
54925492
args->ops = args->iops;
54935493
args->rqstp = rqstp;
54945494

5495+
/*
5496+
* NFSv4 operation decoders can invoke svc cache lookups
5497+
* that trigger svc_defer() when RQ_USEDEFERRAL is set,
5498+
* setting RQ_DROPME. This creates two problems:
5499+
*
5500+
* 1. Non-idempotency: Compounds make it too hard to avoid
5501+
* problems if a request is deferred and replayed.
5502+
*
5503+
* 2. Session slot leakage (NFSv4.1+): If RQ_DROPME is set
5504+
* during decode but SEQUENCE executes successfully, the
5505+
* session slot will be marked INUSE. The request is then
5506+
* dropped before encoding, so the slot is never released,
5507+
* rendering it permanently unusable by the client.
5508+
*/
5509+
clear_bit(RQ_USEDEFERRAL, &rqstp->rq_flags);
5510+
54955511
return nfsd4_decode_compound(args);
54965512
}
54975513

0 commit comments

Comments
 (0)