Since commit de766e570413 ("nfsd: give out fewer session slots as limit approaches") nfsd4_get_drc_mem() ensures 'avail' is always at least 'slotsize', so the return value 'num' is always at least 1. This means that: 1/ nfsd_drc_mem_used could exceed nfsd_drc_max_mem, which becomes a problem when we later perform an unsigned subtraction of the larger from the smaller to calculate 'total_avail'. 2/ Check the return value of nfsd4_get_drc_mem() against zero is pointless - the error code (which isn't actually correct according to RFC-5661) is never returned. So avoid the integer overflow, and discard the check. Signed-off-by: NeilBrown <neilb@xxxxxxx> --- fs/nfsd/nfs4state.c | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c index 7857942c5ca6..8c09ac49fff2 100644 --- a/fs/nfsd/nfs4state.c +++ b/fs/nfsd/nfs4state.c @@ -1570,11 +1570,21 @@ static u32 nfsd4_get_drc_mem(struct nfsd4_channel_attrs *ca) unsigned long avail, total_avail; spin_lock(&nfsd_drc_lock); - total_avail = nfsd_drc_max_mem - nfsd_drc_mem_used; + if (nfsd_drc_max_mem > nfsd_drc_mem_used) + total_avail = nfsd_drc_max_mem - nfsd_drc_mem_used; + else + /* We have handed out more space than we chose in + * set_max_drc() to allow. That isn't really a + * problem as long as that doesn't make us thing we + * have lots more due to integer overflow. + */ + total_avail = 0; avail = min((unsigned long)NFSD_MAX_MEM_PER_SESSION, total_avail); /* * Never use more than a third of the remaining memory, * unless it's the only way to give this client a slot: + * Note that we always return at least 1 here, even if + * we have exceeded nfsd_drc_max_mem. */ avail = clamp_t(unsigned long, avail, slotsize, total_avail/3); num = min_t(int, num, avail / slotsize); @@ -3169,10 +3179,10 @@ static __be32 check_forechannel_attrs(struct nfsd4_channel_attrs *ca, struct nfs * performance. When short on memory we therefore prefer to * decrease number of slots instead of their size. Clients that * request larger slots than they need will get poor results: + * Note that we always allow at least one slot, because our + * accounting is soft and provides no guarantees either way. */ ca->maxreqs = nfsd4_get_drc_mem(ca); - if (!ca->maxreqs) - return nfserr_jukebox; return nfs_ok; } -- 2.23.0
Attachment:
signature.asc
Description: PGP signature