[1/2] nfsd: handle drc over-allocation gracefully.
diff mbox series

Message ID 877e63a3yg.fsf@notabene.neil.brown.name
State New
Headers show
Series
  • [1/2] nfsd: handle drc over-allocation gracefully.
Related show

Commit Message

NeilBrown Sept. 20, 2019, 6:15 a.m. UTC
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@suse.de>
---
 fs/nfsd/nfs4state.c | 16 +++++++++++++---
 1 file changed, 13 insertions(+), 3 deletions(-)

Patch
diff mbox series

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;
 }