Skip site navigation (1)Skip section navigation (2)
Date:      Thu, 9 Jan 2020 19:17:43 +0000 (UTC)
From:      Mark Johnston <markj@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org
Subject:   svn commit: r356563 - head/sys/vm
Message-ID:  <202001091917.009JHhtl011387@repo.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: markj
Date: Thu Jan  9 19:17:42 2020
New Revision: 356563
URL: https://svnweb.freebsd.org/changeset/base/356563

Log:
  UMA: Don't destroy zones after the system shutdown process starts.
  
  Some kernel subsystems, notably ZFS, will destroy UMA zones from a
  shutdown eventhandler.  This causes the zone to be drained.  For slabs
  that are mapped into KVA this can be very expensive and so it needlessly
  delays the shutdown process.
  
  Add a new state to the "booted" variable, BOOT_SHUTDOWN.  Once
  kern_reboot() starts invoking shutdown handlers, turn uma_zdestroy()
  into a no-op, provided that the zone does not have a custom finalization
  routine.
  
  PR:		242427
  Reviewed by:	jeff, kib, rlibby
  MFC after:	2 weeks
  Sponsored by:	The FreeBSD Foundation
  Differential Revision:	https://reviews.freebsd.org/D23066

Modified:
  head/sys/vm/uma_core.c

Modified: head/sys/vm/uma_core.c
==============================================================================
--- head/sys/vm/uma_core.c	Thu Jan  9 19:13:09 2020	(r356562)
+++ head/sys/vm/uma_core.c	Thu Jan  9 19:17:42 2020	(r356563)
@@ -158,8 +158,14 @@ SYSCTL_ULONG(_vm, OID_AUTO, uma_kmem_total, CTLFLAG_RD
     "UMA kernel memory usage");
 
 /* Is the VM done starting up? */
-static enum { BOOT_COLD = 0, BOOT_STRAPPED, BOOT_PAGEALLOC, BOOT_BUCKETS,
-    BOOT_RUNNING } booted = BOOT_COLD;
+static enum {
+	BOOT_COLD,
+	BOOT_STRAPPED,
+	BOOT_PAGEALLOC,
+	BOOT_BUCKETS,
+	BOOT_RUNNING,
+	BOOT_SHUTDOWN,
+} booted = BOOT_COLD;
 
 /*
  * This is the handle used to schedule events that need to happen
@@ -265,6 +271,7 @@ static int hash_expand(struct uma_hash *, struct uma_h
 static void hash_free(struct uma_hash *hash);
 static void uma_timeout(void *);
 static void uma_startup3(void);
+static void uma_shutdown(void);
 static void *zone_alloc_item(uma_zone_t, void *, int, int);
 static void zone_free_item(uma_zone_t, void *, void *, enum zfreeskip);
 static int zone_alloc_limit(uma_zone_t zone, int count, int flags);
@@ -1408,8 +1415,7 @@ startup_alloc(uma_zone_t zone, vm_size_t bytes, int do
 		case BOOT_PAGEALLOC:
 			if (keg->uk_ppera > 1)
 				break;
-		case BOOT_BUCKETS:
-		case BOOT_RUNNING:
+		default:
 #ifdef UMA_MD_SMALL_ALLOC
 			keg->uk_allocf = (keg->uk_ppera > 1) ?
 			    page_alloc : uma_small_alloc;
@@ -2337,7 +2343,7 @@ zone_ctor(void *mem, int size, void *udata, int flags)
 	    (UMA_ZONE_INHERIT | UMA_ZFLAG_INHERIT));
 
 out:
-	if (__predict_true(booted == BOOT_RUNNING)) {
+	if (__predict_true(booted >= BOOT_RUNNING)) {
 		zone_alloc_counters(zone, NULL);
 		zone_alloc_sysctl(zone, NULL);
 	} else {
@@ -2465,7 +2471,7 @@ zone_foreach(void (*zfunc)(uma_zone_t, void *arg), voi
 	 * threaded, so locking isn't needed. Startup functions
 	 * are allowed to use M_WAITOK.
 	 */
-	if (__predict_true(booted == BOOT_RUNNING))
+	if (__predict_true(booted >= BOOT_RUNNING))
 		rw_rlock(&uma_rwlock);
 	LIST_FOREACH(keg, &uma_kegs, uk_link) {
 		LIST_FOREACH(zone, &keg->uk_zones, uz_link)
@@ -2473,7 +2479,7 @@ zone_foreach(void (*zfunc)(uma_zone_t, void *arg), voi
 	}
 	LIST_FOREACH(zone, &uma_cachezones, uz_link)
 		zfunc(zone, arg);
-	if (__predict_true(booted == BOOT_RUNNING))
+	if (__predict_true(booted >= BOOT_RUNNING))
 		rw_runlock(&uma_rwlock);
 }
 
@@ -2635,10 +2641,6 @@ uma_startup2(void)
 	bucket_enable();
 }
 
-/*
- * Initialize our callout handle
- *
- */
 static void
 uma_startup3(void)
 {
@@ -2653,8 +2655,18 @@ uma_startup3(void)
 	callout_init(&uma_callout, 1);
 	callout_reset(&uma_callout, UMA_TIMEOUT * hz, uma_timeout, NULL);
 	booted = BOOT_RUNNING;
+
+	EVENTHANDLER_REGISTER(shutdown_post_sync, uma_shutdown, NULL,
+	    EVENTHANDLER_PRI_FIRST);
 }
 
+static void
+uma_shutdown(void)
+{
+
+	booted = BOOT_SHUTDOWN;
+}
+
 static uma_keg_t
 uma_kcreate(uma_zone_t zone, size_t size, uma_init uminit, uma_fini fini,
 		int align, uint32_t flags)
@@ -2796,6 +2808,13 @@ void
 uma_zdestroy(uma_zone_t zone)
 {
 
+	/*
+	 * Large slabs are expensive to reclaim, so don't bother doing
+	 * unnecessary work if we're shutting down.
+	 */
+	if (booted == BOOT_SHUTDOWN &&
+	    zone->uz_fini == NULL && zone->uz_release == zone_release)
+		return;
 	sx_slock(&uma_reclaim_lock);
 	zone_free_item(zones, zone, NULL, SKIP_NONE);
 	sx_sunlock(&uma_reclaim_lock);



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?202001091917.009JHhtl011387>