Consistently enforce the restriction against calling malloc/free when in a
critical section. uma_zalloc_arg()/uma_zalloc_free() may acquire a sleepable lock on the zone. The malloc() family of functions may call uma_zalloc_arg() or uma_zalloc_free(). The malloc(9) man page currently claims that free() will never sleep. It also implies that the malloc() family of functions will not sleep when called with M_NOWAIT. However, it is more correct to say that these functions will not sleep indefinitely. Indeed, they may acquire a sleepable lock. However, a developer may overlook this restriction because the WITNESS check that catches attempts to call the malloc() family of functions within a critical section is inconsistenly applied. This change clarifies the language of the malloc(9) man page to clarify the restriction against calling the malloc() family of functions while in a critical section or holding a spin lock. It also adds KASSERTs at appropriate points to make the enforcement of this restriction more consistent. PR: 204633 Differential Revision: https://reviews.freebsd.org/D4197 Reviewed by: markj Approved by: gnn (mentor) Sponsored by: Juniper Networks
This commit is contained in:
parent
c1dfca84c6
commit
1067a2ba68
@ -29,7 +29,7 @@
|
||||
.\" $NetBSD: malloc.9,v 1.3 1996/11/11 00:05:11 lukem Exp $
|
||||
.\" $FreeBSD$
|
||||
.\"
|
||||
.Dd January 16, 2014
|
||||
.Dd November 19, 2015
|
||||
.Dt MALLOC 9
|
||||
.Os
|
||||
.Sh NAME
|
||||
@ -227,6 +227,13 @@ may sleep when called with
|
||||
.Dv M_WAITOK .
|
||||
.Fn free
|
||||
never sleeps.
|
||||
However,
|
||||
.Fn malloc ,
|
||||
.Fn realloc,
|
||||
.Fn reallocf
|
||||
and
|
||||
.Fn free
|
||||
may not be called in a critical section or while holding a spin lock.
|
||||
.Pp
|
||||
Any calls to
|
||||
.Fn malloc
|
||||
|
@ -476,6 +476,9 @@ malloc(unsigned long size, struct malloc_type *mtp, int flags)
|
||||
KASSERT(curthread->td_intr_nesting_level == 0,
|
||||
("malloc(M_WAITOK) in interrupt context"));
|
||||
|
||||
KASSERT(curthread->td_critnest == 0,
|
||||
("malloc: called with spinlock or critical section held"));
|
||||
|
||||
#ifdef DEBUG_MEMGUARD
|
||||
if (memguard_cmp_mtp(mtp, size)) {
|
||||
va = memguard_alloc(size, flags);
|
||||
@ -542,6 +545,9 @@ free(void *addr, struct malloc_type *mtp)
|
||||
|
||||
KASSERT(mtp->ks_magic == M_MAGIC, ("free: bad malloc type magic"));
|
||||
|
||||
KASSERT(curthread->td_critnest == 0,
|
||||
("free: called with spinlock or critical section held"));
|
||||
|
||||
/* free(NULL, ...) does nothing */
|
||||
if (addr == NULL)
|
||||
return;
|
||||
@ -605,6 +611,9 @@ realloc(void *addr, unsigned long size, struct malloc_type *mtp, int flags)
|
||||
KASSERT(mtp->ks_magic == M_MAGIC,
|
||||
("realloc: bad malloc type magic"));
|
||||
|
||||
KASSERT(curthread->td_critnest == 0,
|
||||
("realloc: called with spinlock or critical section held"));
|
||||
|
||||
/* realloc(NULL, ...) is equivalent to malloc(...) */
|
||||
if (addr == NULL)
|
||||
return (malloc(size, mtp, flags));
|
||||
|
@ -2149,6 +2149,10 @@ uma_zalloc_arg(uma_zone_t zone, void *udata, int flags)
|
||||
WITNESS_WARN(WARN_GIANTOK | WARN_SLEEPOK, NULL,
|
||||
"uma_zalloc_arg: zone \"%s\"", zone->uz_name);
|
||||
}
|
||||
|
||||
KASSERT(curthread->td_critnest == 0,
|
||||
("uma_zalloc_arg: called with spinlock or critical section held"));
|
||||
|
||||
#ifdef DEBUG_MEMGUARD
|
||||
if (memguard_cmp_zone(zone)) {
|
||||
item = memguard_alloc(zone->uz_size, flags);
|
||||
@ -2686,6 +2690,9 @@ uma_zfree_arg(uma_zone_t zone, void *item, void *udata)
|
||||
CTR2(KTR_UMA, "uma_zfree_arg thread %x zone %s", curthread,
|
||||
zone->uz_name);
|
||||
|
||||
KASSERT(curthread->td_critnest == 0,
|
||||
("uma_zfree_arg: called with spinlock or critical section held"));
|
||||
|
||||
/* uma_zfree(..., NULL) does nothing, to match free(9). */
|
||||
if (item == NULL)
|
||||
return;
|
||||
|
Loading…
Reference in New Issue
Block a user