Module Name:    src
Committed By:   thorpej
Date:           Wed Dec 22 16:57:29 UTC 2021

Modified Files:
        src/sys/external/bsd/common/include/linux: slab.h
        src/sys/kern: kern_lwp.c subr_pool.c
        src/sys/sys: pool.h

Log Message:
Do the last change differently:

Instead of having a pre-destruct hook, put knowledge of passive
serialization into the pool allocator directly, enabled by PR_PSERIALIZE
when the pool / pool_cache is initialized.  This will guarantee that
a passive serialization barrier will be performed before the object's
destructor is called, or before the page containing the object is freed
back to the system (in the case of no destructor).  Note that the internal
allocator overhead is different when PR_PSERIALIZE is used (it implies
PR_NOTOUCH, because the objects must remain in a valid state).

In the DRM Linux API shim, this allows us to remove the custom page
allocator for SLAB_TYPESAFE_BY_RCU.


To generate a diff of this commit:
cvs rdiff -u -r1.11 -r1.12 src/sys/external/bsd/common/include/linux/slab.h
cvs rdiff -u -r1.245 -r1.246 src/sys/kern/kern_lwp.c
cvs rdiff -u -r1.278 -r1.279 src/sys/kern/subr_pool.c
cvs rdiff -u -r1.95 -r1.96 src/sys/sys/pool.h

Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.

Modified files:

Index: src/sys/external/bsd/common/include/linux/slab.h
diff -u src/sys/external/bsd/common/include/linux/slab.h:1.11 src/sys/external/bsd/common/include/linux/slab.h:1.12
--- src/sys/external/bsd/common/include/linux/slab.h:1.11	Tue Dec 21 19:07:09 2021
+++ src/sys/external/bsd/common/include/linux/slab.h	Wed Dec 22 16:57:29 2021
@@ -1,4 +1,4 @@
-/*	$NetBSD: slab.h,v 1.11 2021/12/21 19:07:09 thorpej Exp $	*/
+/*	$NetBSD: slab.h,v 1.12 2021/12/22 16:57:29 thorpej Exp $	*/
 
 /*-
  * Copyright (c) 2013 The NetBSD Foundation, Inc.
@@ -174,24 +174,6 @@ struct kmem_cache {
 	void		(*kc_dtor)(void *);
 };
 
-/* XXX These should be in <sys/pool.h>.  */
-void *	pool_page_alloc(struct pool *, int);
-void	pool_page_free(struct pool *, void *);
-
-static void
-pool_page_free_rcu(struct pool *pp, void *v)
-{
-
-	synchronize_rcu();
-	pool_page_free(pp, v);
-}
-
-static struct pool_allocator pool_allocator_kmem_rcu = {
-	.pa_alloc = pool_page_alloc,
-	.pa_free = pool_page_free_rcu,
-	.pa_pagesz = 0,
-};
-
 static int
 kmem_cache_ctor(void *cookie, void *ptr, int flags __unused)
 {
@@ -212,26 +194,20 @@ kmem_cache_dtor(void *cookie, void *ptr)
 		(*kc->kc_dtor)(ptr);
 }
 
-static void
-kmem_cache_pre_dtor(void *cookie)
-{
-	synchronize_rcu();
-}
-
 static inline struct kmem_cache *
 kmem_cache_create(const char *name, size_t size, size_t align,
     unsigned long flags, void (*ctor)(void *))
 {
-	struct pool_allocator *palloc = NULL;
 	struct kmem_cache *kc;
+	int pcflags = 0;
 
 	if (ISSET(flags, SLAB_HWCACHE_ALIGN))
 		align = roundup(MAX(1, align), CACHE_LINE_SIZE);
 	if (ISSET(flags, SLAB_TYPESAFE_BY_RCU))
-		palloc = &pool_allocator_kmem_rcu;
+		pcflags |= PR_PSERIALIZE;
 
 	kc = kmem_alloc(sizeof(*kc), KM_SLEEP);
-	kc->kc_pool_cache = pool_cache_init(size, align, 0, 0, name, palloc,
+	kc->kc_pool_cache = pool_cache_init(size, align, 0, pcflags, name, NULL,
 	    IPL_VM, &kmem_cache_ctor, NULL, kc);
 	kc->kc_size = size;
 	kc->kc_ctor = ctor;
@@ -244,26 +220,20 @@ static inline struct kmem_cache *
 kmem_cache_create_dtor(const char *name, size_t size, size_t align,
     unsigned long flags, void (*ctor)(void *), void (*dtor)(void *))
 {
-	struct pool_allocator *palloc = NULL;
 	struct kmem_cache *kc;
+	int pcflags = 0;
 
 	if (ISSET(flags, SLAB_HWCACHE_ALIGN))
 		align = roundup(MAX(1, align), CACHE_LINE_SIZE);
-	/*
-	 * No need to use pool_allocator_kmem_rcu here; RCU synchronization
-	 * will be handled by the pre-destructor hook.
-	 */
+	if (ISSET(flags, SLAB_TYPESAFE_BY_RCU))
+		pcflags |= PR_PSERIALIZE;
 
 	kc = kmem_alloc(sizeof(*kc), KM_SLEEP);
-	kc->kc_pool_cache = pool_cache_init(size, align, 0, 0, name, palloc,
+	kc->kc_pool_cache = pool_cache_init(size, align, 0, pcflags, name, NULL,
 	    IPL_VM, &kmem_cache_ctor, &kmem_cache_dtor, kc);
 	kc->kc_size = size;
 	kc->kc_ctor = ctor;
 	kc->kc_dtor = dtor;
-	if (ISSET(flags, SLAB_TYPESAFE_BY_RCU)) {
-		pool_cache_setpredestruct(kc->kc_pool_cache,
-		    kmem_cache_pre_dtor);
-	}
 
 	return kc;
 }

Index: src/sys/kern/kern_lwp.c
diff -u src/sys/kern/kern_lwp.c:1.245 src/sys/kern/kern_lwp.c:1.246
--- src/sys/kern/kern_lwp.c:1.245	Tue Dec 21 19:00:37 2021
+++ src/sys/kern/kern_lwp.c	Wed Dec 22 16:57:28 2021
@@ -1,4 +1,4 @@
-/*	$NetBSD: kern_lwp.c,v 1.245 2021/12/21 19:00:37 thorpej Exp $	*/
+/*	$NetBSD: kern_lwp.c,v 1.246 2021/12/22 16:57:28 thorpej Exp $	*/
 
 /*-
  * Copyright (c) 2001, 2006, 2007, 2008, 2009, 2019, 2020
@@ -217,7 +217,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: kern_lwp.c,v 1.245 2021/12/21 19:00:37 thorpej Exp $");
+__KERNEL_RCSID(0, "$NetBSD: kern_lwp.c,v 1.246 2021/12/22 16:57:28 thorpej Exp $");
 
 #include "opt_ddb.h"
 #include "opt_lockdebug.h"
@@ -262,7 +262,6 @@ struct lwplist		alllwp		__cacheline_alig
 
 static int		lwp_ctor(void *, void *, int);
 static void		lwp_dtor(void *, void *);
-static void		lwp_pre_dtor(void *);
 
 /* DTrace proc provider probes */
 SDT_PROVIDER_DEFINE(proc);
@@ -340,9 +339,16 @@ lwpinit(void)
 
 	LIST_INIT(&alllwp);
 	lwpinit_specificdata();
-	lwp_cache = pool_cache_init(sizeof(lwp_t), MIN_LWP_ALIGNMENT, 0, 0,
-	    "lwppl", NULL, IPL_NONE, lwp_ctor, lwp_dtor, NULL);
-	pool_cache_setpredestruct(lwp_cache, lwp_pre_dtor);
+	/*
+	 * Provide a barrier to ensure that all mutex_oncpu() and rw_oncpu()
+	 * calls will exit before memory of LWPs is returned to the pool, where
+	 * KVA of LWP structure might be freed and re-used for other purposes.
+	 * Kernel preemption is disabled around mutex_oncpu() and rw_oncpu()
+	 * callers, therefore a regular passive serialization barrier will
+	 * do the job.
+	 */
+	lwp_cache = pool_cache_init(sizeof(lwp_t), MIN_LWP_ALIGNMENT, 0,
+	    PR_PSERIALIZE, "lwppl", NULL, IPL_NONE, lwp_ctor, lwp_dtor, NULL);
 
 	maxlwp = cpu_maxlwp();
 	sysctl_kern_lwp_setup();
@@ -393,21 +399,6 @@ lwp_ctor(void *arg, void *obj, int flags
 }
 
 static void
-lwp_pre_dtor(void *arg __unused)
-{
-	/*
-	 * Provide a barrier to ensure that all mutex_oncpu() and rw_oncpu()
-	 * calls will exit before memory of LWPs is returned to the pool, where
-	 * KVA of LWP structure might be freed and re-used for other purposes.
-	 * Kernel preemption is disabled around mutex_oncpu() and rw_oncpu()
-	 * callers, therefore cross-call to all CPUs will do the job.
-	 *
-	 * XXX should use epoch based reclamation.
-	 */
-	xc_barrier(0);
-}
-
-static void
 lwp_dtor(void *arg, void *obj)
 {
 	lwp_t *l = obj;

Index: src/sys/kern/subr_pool.c
diff -u src/sys/kern/subr_pool.c:1.278 src/sys/kern/subr_pool.c:1.279
--- src/sys/kern/subr_pool.c:1.278	Tue Dec 21 18:59:22 2021
+++ src/sys/kern/subr_pool.c	Wed Dec 22 16:57:28 2021
@@ -1,8 +1,8 @@
-/*	$NetBSD: subr_pool.c,v 1.278 2021/12/21 18:59:22 thorpej Exp $	*/
+/*	$NetBSD: subr_pool.c,v 1.279 2021/12/22 16:57:28 thorpej Exp $	*/
 
 /*
  * Copyright (c) 1997, 1999, 2000, 2002, 2007, 2008, 2010, 2014, 2015, 2018,
- *     2020 The NetBSD Foundation, Inc.
+ *     2020, 2021 The NetBSD Foundation, Inc.
  * All rights reserved.
  *
  * This code is derived from software contributed to The NetBSD Foundation
@@ -33,7 +33,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: subr_pool.c,v 1.278 2021/12/21 18:59:22 thorpej Exp $");
+__KERNEL_RCSID(0, "$NetBSD: subr_pool.c,v 1.279 2021/12/22 16:57:28 thorpej Exp $");
 
 #ifdef _KERNEL_OPT
 #include "opt_ddb.h"
@@ -142,9 +142,14 @@ static bool pool_cache_put_nocache(pool_
 #define NO_CTOR	__FPTRCAST(int (*)(void *, void *, int), nullop)
 #define NO_DTOR	__FPTRCAST(void (*)(void *, void *), nullop)
 
+#define pc_has_pser(pc) (((pc)->pc_roflags & PR_PSERIALIZE) != 0)
 #define pc_has_ctor(pc) ((pc)->pc_ctor != NO_CTOR)
 #define pc_has_dtor(pc) ((pc)->pc_dtor != NO_DTOR)
 
+#define pp_has_pser(pp) (((pp)->pr_roflags & PR_PSERIALIZE) != 0)
+
+#define pool_barrier()	xc_barrier(0)
+
 /*
  * Pool backend allocators.
  *
@@ -479,6 +484,8 @@ pr_item_linkedlist_put(const struct pool
 {
 	struct pool_item *pi = obj;
 
+	KASSERT(!pp_has_pser(pp));
+
 #ifdef POOL_CHECK_MAGIC
 	pi->pi_magic = PI_MAGIC;
 #endif
@@ -841,6 +848,14 @@ pool_init(struct pool *pp, size_t size, 
 	if (!cold)
 		mutex_exit(&pool_allocator_lock);
 
+	/*
+	 * PR_PSERIALIZE implies PR_NOTOUCH; freed objects must remain
+	 * valid until the the backing page is returned to the system.
+	 */
+	if (flags & PR_PSERIALIZE) {
+		flags |= PR_NOTOUCH;
+	}
+
 	if (align == 0)
 		align = ALIGN(1);
 
@@ -2095,6 +2110,7 @@ pool_cache_bootstrap(pool_cache_t pc, si
 	pool_cache_t pc1;
 	struct cpu_info *ci;
 	struct pool *pp;
+	unsigned int ppflags = flags;
 
 	pp = &pc->pc_pool;
 	if (palloc == NULL && ipl == IPL_NONE) {
@@ -2106,22 +2122,29 @@ pool_cache_bootstrap(pool_cache_t pc, si
 		} else
 			palloc = &pool_allocator_nointr;
 	}
-	pool_init(pp, size, align, align_offset, flags, wchan, palloc, ipl);
 
 	if (ctor == NULL) {
 		ctor = NO_CTOR;
 	}
 	if (dtor == NULL) {
 		dtor = NO_DTOR;
+	} else {
+		/*
+		 * If we have a destructor, then the pool layer does not
+		 * need to worry about PR_PSERIALIZE.
+		 */
+		ppflags &= ~PR_PSERIALIZE;
 	}
 
+	pool_init(pp, size, align, align_offset, ppflags, wchan, palloc, ipl);
+
 	pc->pc_fullgroups = NULL;
 	pc->pc_partgroups = NULL;
 	pc->pc_ctor = ctor;
 	pc->pc_dtor = dtor;
-	pc->pc_pre_dtor = NULL;
 	pc->pc_arg  = arg;
 	pc->pc_refcnt = 0;
+	pc->pc_roflags = flags;
 	pc->pc_freecheck = NULL;
 
 	if ((flags & PR_LARGECACHE) != 0) {
@@ -2165,19 +2188,6 @@ pool_cache_bootstrap(pool_cache_t pc, si
 }
 
 /*
- * pool_cache_setpredestruct:
- *
- *	Set a pre-destructor hook for the specified pool cache.
- */
-void
-pool_cache_setpredestruct(pool_cache_t pc, void (*fn)(void *))
-{
-	KASSERT(pc->pc_pre_dtor == NULL);
-	pc->pc_pre_dtor = fn;
-	membar_sync();
-}
-
-/*
  * pool_cache_destroy:
  *
  *	Destroy a pool cache.
@@ -2308,13 +2318,11 @@ static inline void
 pool_cache_pre_destruct(pool_cache_t pc)
 {
 	/*
-	 * Call the pre-destruct hook before destructing a batch
-	 * of objects.  Users of this hook can perform passive
-	 * serialization other other activities that need to be
-	 * performed once-per-batch (rather than once-per-object).
+	 * Perform a passive serialization barrier before destructing
+	 * a batch of one or more objects.
 	 */
-	if (__predict_false(pc->pc_pre_dtor != NULL)) {
-		(*pc->pc_pre_dtor)(pc->pc_arg);
+	if (__predict_false(pc_has_pser(pc))) {
+		pool_barrier();
 	}
 }
 
@@ -2974,7 +2982,14 @@ pool_allocator_free(struct pool *pp, voi
 	struct pool_allocator *pa = pp->pr_alloc;
 
 	if (pp->pr_redzone) {
+		KASSERT(!pp_has_pser(pp));
 		kasan_mark(v, pa->pa_pagesz, pa->pa_pagesz, 0);
+	} else if (__predict_false(pp_has_pser(pp))) {
+		/*
+		 * Perform a passive serialization barrier before freeing
+		 * the pool page back to the system.
+		 */
+		pool_barrier();
 	}
 	(*pa->pa_free)(pp, v);
 }
@@ -3183,6 +3198,7 @@ pool_redzone_fill(struct pool *pp, void 
 {
 	if (!pp->pr_redzone)
 		return;
+	KASSERT(!pp_has_pser(pp));
 #ifdef KASAN
 	kasan_mark(p, pp->pr_reqsize, pp->pr_reqsize_with_redzone,
 	    KASAN_POOL_REDZONE);
@@ -3213,6 +3229,7 @@ pool_redzone_check(struct pool *pp, void
 {
 	if (!pp->pr_redzone)
 		return;
+	KASSERT(!pp_has_pser(pp));
 #ifdef KASAN
 	kasan_mark(p, 0, pp->pr_reqsize_with_redzone, KASAN_POOL_FREED);
 #else
@@ -3245,8 +3262,12 @@ static void
 pool_cache_redzone_check(pool_cache_t pc, void *p)
 {
 #ifdef KASAN
-	/* If there is a ctor/dtor, leave the data as valid. */
-	if (__predict_false(pc_has_ctor(pc) || pc_has_dtor(pc))) {
+	/*
+	 * If there is a ctor/dtor, or if the cache objects use
+	 * passive serialization, leave the data as valid.
+	 */
+	if (__predict_false(pc_has_ctor(pc) || pc_has_dtor(pc) ||
+	    pc_has_pser(pc))) {
 		return;
 	}
 #endif

Index: src/sys/sys/pool.h
diff -u src/sys/sys/pool.h:1.95 src/sys/sys/pool.h:1.96
--- src/sys/sys/pool.h:1.95	Tue Dec 21 18:59:22 2021
+++ src/sys/sys/pool.h	Wed Dec 22 16:57:28 2021
@@ -1,4 +1,4 @@
-/*	$NetBSD: pool.h,v 1.95 2021/12/21 18:59:22 thorpej Exp $	*/
+/*	$NetBSD: pool.h,v 1.96 2021/12/22 16:57:28 thorpej Exp $	*/
 
 /*-
  * Copyright (c) 1997, 1998, 1999, 2000, 2007, 2020
@@ -162,6 +162,7 @@ struct pool {
 #define PR_GROWINGNOWAIT 0x4000	/* pool_grow in progress by PR_NOWAIT alloc */
 #define PR_ZERO		0x8000	/* zero data before returning */
 #define PR_USEBMAP	0x10000	/* use a bitmap to manage freed items */
+#define PR_PSERIALIZE	0x20000	/* needs pserialize sync point before free */
 
 	/*
 	 * `pr_lock' protects the pool's data structures when removing
@@ -265,9 +266,9 @@ struct pool_cache {
 	int		pc_ncpu;	/* number cpus set up */
 	int		(*pc_ctor)(void *, void *, int);
 	void		(*pc_dtor)(void *, void *);
-	void		(*pc_pre_dtor)(void *);
-	void		*pc_arg;	/* for ctor/dtor/pre_dtor */
+	void		*pc_arg;	/* for ctor/dtor */
 	unsigned int	pc_refcnt;	/* ref count for pagedaemon, etc */
+	unsigned int	pc_roflags;	/* r/o cache flags */
 	void		*pc_cpus[MAXCPUS];
 
 	/* Diagnostic aides. */
@@ -342,7 +343,6 @@ void		pool_cache_bootstrap(pool_cache_t,
 		    const char *, struct pool_allocator *, int,
 		    int (*)(void *, void *, int), void (*)(void *, void *),
 		    void *);
-void		pool_cache_setpredestruct(pool_cache_t, void (*)(void *));
 void		pool_cache_destroy(pool_cache_t);
 void		pool_cache_bootstrap_destroy(pool_cache_t);
 void		*pool_cache_get_paddr(pool_cache_t, int, paddr_t *);

Reply via email to