svn commit: r366839 - head/sys/vm

Mark Johnston markj at FreeBSD.org
Mon Oct 19 16:55:04 UTC 2020


Author: markj
Date: Mon Oct 19 16:55:03 2020
New Revision: 366839
URL: https://svnweb.freebsd.org/changeset/base/366839

Log:
  uma: Avoid depleting keg reserves when filling a bucket
  
  zone_import() fetches a free or partially free slab from the keg and
  then uses its items to populate an array, typically filling a bucket.
  If a single allocation causes the keg to drop below its minimum reserve,
  the inner loop ends.  However, if the bucket is still not full and
  M_USE_RESERVE is specified, the outer loop will continue to fetch items
  from the keg.
  
  If M_USE_RESERVE is specified and the number of free items is below the
  reserved limit, we should return only a single item.  Otherwise, if the
  bucket size is larger than the reserve, all of the reserved items may
  end up in a single per-CPU bucket, invisible to other CPUs.
  
  Reviewed by:	rlibby
  MFC after:	2 weeks
  Sponsored by:	The FreeBSD Foundation
  Differential Revision:	https://reviews.freebsd.org/D26771

Modified:
  head/sys/vm/uma_core.c

Modified: head/sys/vm/uma_core.c
==============================================================================
--- head/sys/vm/uma_core.c	Mon Oct 19 16:54:06 2020	(r366838)
+++ head/sys/vm/uma_core.c	Mon Oct 19 16:55:03 2020	(r366839)
@@ -3734,10 +3734,17 @@ zone_import(void *arg, void **bucket, int max, int dom
 		stripe = howmany(max, vm_ndomains);
 #endif
 		dom = &keg->uk_domain[slab->us_domain];
-		while (slab->us_freecount && i < max) { 
+		do {
 			bucket[i++] = slab_alloc_item(keg, slab);
-			if (dom->ud_free_items <= keg->uk_reserve)
-				break;
+			if (dom->ud_free_items <= keg->uk_reserve) {
+				/*
+				 * Avoid depleting the reserve after a
+				 * successful item allocation, even if
+				 * M_USE_RESERVE is specified.
+				 */
+				KEG_UNLOCK(keg, slab->us_domain);
+				goto out;
+			}
 #ifdef NUMA
 			/*
 			 * If the zone is striped we pick a new slab for every
@@ -3751,13 +3758,14 @@ zone_import(void *arg, void **bucket, int max, int dom
 			    vm_ndomains > 1 && --stripe == 0)
 				break;
 #endif
-		}
+		} while (slab->us_freecount != 0 && i < max);
 		KEG_UNLOCK(keg, slab->us_domain);
+
 		/* Don't block if we allocated any successfully. */
 		flags &= ~M_WAITOK;
 		flags |= M_NOWAIT;
 	}
-
+out:
 	return i;
 }
 


More information about the svn-src-head mailing list