diff options
author | jtl <jtl@FreeBSD.org> | 2015-11-19 14:04:53 +0000 |
---|---|---|
committer | jtl <jtl@FreeBSD.org> | 2015-11-19 14:04:53 +0000 |
commit | f2aa140123cb6701c58f52302538181a623480c4 (patch) | |
tree | b9519811576c3140a10c27aaa98b1ae5987e9610 /sys | |
parent | 5ec1c28867cc831823aa9d848fa6fb9012148ff8 (diff) | |
download | FreeBSD-src-f2aa140123cb6701c58f52302538181a623480c4.zip FreeBSD-src-f2aa140123cb6701c58f52302538181a623480c4.tar.gz |
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
Diffstat (limited to 'sys')
-rw-r--r-- | sys/kern/kern_malloc.c | 9 | ||||
-rw-r--r-- | sys/vm/uma_core.c | 7 |
2 files changed, 16 insertions, 0 deletions
diff --git a/sys/kern/kern_malloc.c b/sys/kern/kern_malloc.c index ff5b106..01aff78 100644 --- a/sys/kern/kern_malloc.c +++ b/sys/kern/kern_malloc.c @@ -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)); diff --git a/sys/vm/uma_core.c b/sys/vm/uma_core.c index 8169256..1f57dff 100644 --- a/sys/vm/uma_core.c +++ b/sys/vm/uma_core.c @@ -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; |