1*8a272653SPeter Holm#!/bin/sh 2*8a272653SPeter Holm 3*8a272653SPeter Holm# 4*8a272653SPeter Holm# Copyright (c) 2016 EMC Corp. 5*8a272653SPeter Holm# All rights reserved. 6*8a272653SPeter Holm# 7*8a272653SPeter Holm# Redistribution and use in source and binary forms, with or without 8*8a272653SPeter Holm# modification, are permitted provided that the following conditions 9*8a272653SPeter Holm# are met: 10*8a272653SPeter Holm# 1. Redistributions of source code must retain the above copyright 11*8a272653SPeter Holm# notice, this list of conditions and the following disclaimer. 12*8a272653SPeter Holm# 2. Redistributions in binary form must reproduce the above copyright 13*8a272653SPeter Holm# notice, this list of conditions and the following disclaimer in the 14*8a272653SPeter Holm# documentation and/or other materials provided with the distribution. 15*8a272653SPeter Holm# 16*8a272653SPeter Holm# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 17*8a272653SPeter Holm# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18*8a272653SPeter Holm# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19*8a272653SPeter Holm# ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 20*8a272653SPeter Holm# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21*8a272653SPeter Holm# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 22*8a272653SPeter Holm# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23*8a272653SPeter Holm# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 24*8a272653SPeter Holm# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 25*8a272653SPeter Holm# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26*8a272653SPeter Holm# SUCH DAMAGE. 27*8a272653SPeter Holm# 28*8a272653SPeter Holm 29*8a272653SPeter Holm# uma_zalloc_arc() fail point test scenario. 30*8a272653SPeter Holm# Test scenario by Ryan Libby <rlibby@gmail.com>. 31*8a272653SPeter Holm 32*8a272653SPeter Holm# "panic: backing_object 0xfffff8016dd74420 was somehow re-referenced during 33*8a272653SPeter Holm# collapse!" seen. 34*8a272653SPeter Holm# https://people.freebsd.org/~pho/stress/log/uma_zalloc_arg.txt 35*8a272653SPeter Holm 36*8a272653SPeter Holm# Hang seen: 37*8a272653SPeter Holm# https://people.freebsd.org/~pho/stress/log/kostik869.txt 38*8a272653SPeter Holm 39*8a272653SPeter Holm[ `id -u ` -ne 0 ] && echo "Must be root!" && exit 1 40*8a272653SPeter Holm 41*8a272653SPeter Holm. ../default.cfg 42*8a272653SPeter Holm 43*8a272653SPeter Holmsysctl debug.mnowait_failure.zalloc_whitelist > /dev/null 2>&1 || exit 0 44*8a272653SPeter Holm 45*8a272653SPeter Holms1=`sysctl -n debug.mnowait_failure.zalloc_whitelist` 46*8a272653SPeter Holms2=`sysctl -n debug.fail_point.uma_zalloc_arg` 47*8a272653SPeter Holmcleanup() { 48*8a272653SPeter Holm sysctl debug.mnowait_failure.zalloc_whitelist="$s1" > /dev/null 49*8a272653SPeter Holm sysctl debug.fail_point.uma_zalloc_arg="$s2" > /dev/null 50*8a272653SPeter Holm} 51*8a272653SPeter Holmtrap "cleanup" EXIT INT 52*8a272653SPeter Holmsysctl debug.mnowait_failure.zalloc_whitelist='RADIX NODE' 53*8a272653SPeter Holmsysctl debug.fail_point.uma_zalloc_arg='1%return' 54*8a272653SPeter Holm 55*8a272653SPeter Holmstart=`date '+%s'` 56*8a272653SPeter Holmwhile [ $((`date '+%s'` - start)) -lt 300 ]; do 57*8a272653SPeter Holm sh -c "echo | cat | cat > /dev/null" 58*8a272653SPeter Holmdone 59*8a272653SPeter Holmexit 0 60*8a272653SPeter Holm 61*8a272653SPeter HolmThe patch from 62*8a272653SPeter Holmhttps://github.com/freebsd/freebsd/compare/master...rlibby:mnowait-dbg 63*8a272653SPeter Holm 64*8a272653SPeter Holmdiff --git a/sys/kern/kern_malloc.c b/sys/kern/kern_malloc.c 65*8a272653SPeter Holmindex 01aff78..9d557a1 100644 66*8a272653SPeter Holm--- a/sys/kern/kern_malloc.c 67*8a272653SPeter Holm+++ b/sys/kern/kern_malloc.c 68*8a272653SPeter Holm@@ -50,6 +50,7 @@ __FBSDID("$FreeBSD$"); 69*8a272653SPeter Holm 70*8a272653SPeter Holm #include <sys/param.h> 71*8a272653SPeter Holm #include <sys/systm.h> 72*8a272653SPeter Holm+#include <sys/fail.h> 73*8a272653SPeter Holm #include <sys/kdb.h> 74*8a272653SPeter Holm #include <sys/kernel.h> 75*8a272653SPeter Holm #include <sys/lock.h> 76*8a272653SPeter Holm@@ -472,6 +473,19 @@ malloc(unsigned long size, struct malloc_type *mtp, int flags) 77*8a272653SPeter Holm } 78*8a272653SPeter Holm } 79*8a272653SPeter Holm #endif 80*8a272653SPeter Holm+ if (flags & M_NOWAIT) { 81*8a272653SPeter Holm+ KFAIL_POINT_CODE(DEBUG_FP, malloc, { 82*8a272653SPeter Holm+ if (uma_dbg_nowait_fail_enabled_malloc( 83*8a272653SPeter Holm+ mtp->ks_shortdesc)) { 84*8a272653SPeter Holm+ /* XXX record call stack */ 85*8a272653SPeter Holm+#ifdef MALLOC_MAKE_FAILURES 86*8a272653SPeter Holm+ atomic_add_int(&malloc_failure_count, 1); 87*8a272653SPeter Holm+ t_malloc_fail = time_uptime; 88*8a272653SPeter Holm+#endif 89*8a272653SPeter Holm+ return (NULL); 90*8a272653SPeter Holm+ } 91*8a272653SPeter Holm+ }); 92*8a272653SPeter Holm+ } 93*8a272653SPeter Holm if (flags & M_WAITOK) 94*8a272653SPeter Holm KASSERT(curthread->td_intr_nesting_level == 0, 95*8a272653SPeter Holm ("malloc(M_WAITOK) in interrupt context")); 96*8a272653SPeter Holmdiff --git a/sys/vm/uma_core.c b/sys/vm/uma_core.c 97*8a272653SPeter Holmindex 1f57dff..dfa18e6 100644 98*8a272653SPeter Holm--- a/sys/vm/uma_core.c 99*8a272653SPeter Holm+++ b/sys/vm/uma_core.c 100*8a272653SPeter Holm@@ -64,6 +64,7 @@ __FBSDID("$FreeBSD$"); 101*8a272653SPeter Holm #include <sys/param.h> 102*8a272653SPeter Holm #include <sys/systm.h> 103*8a272653SPeter Holm #include <sys/bitset.h> 104*8a272653SPeter Holm+#include <sys/fail.h> 105*8a272653SPeter Holm #include <sys/kernel.h> 106*8a272653SPeter Holm #include <sys/types.h> 107*8a272653SPeter Holm #include <sys/queue.h> 108*8a272653SPeter Holm@@ -2148,6 +2149,23 @@ uma_zalloc_arg(uma_zone_t zone, void *udata, int flags) 109*8a272653SPeter Holm if (flags & M_WAITOK) { 110*8a272653SPeter Holm WITNESS_WARN(WARN_GIANTOK | WARN_SLEEPOK, NULL, 111*8a272653SPeter Holm "uma_zalloc_arg: zone \"%s\"", zone->uz_name); 112*8a272653SPeter Holm+ } else { 113*8a272653SPeter Holm+ KFAIL_POINT_CODE(DEBUG_FP, uma_zalloc_arg, { 114*8a272653SPeter Holm+ /* 115*8a272653SPeter Holm+ * XXX hack. Setting the fail point to 0 (default) 116*8a272653SPeter Holm+ * causes it to ignore malloc zones, nonzero causes it 117*8a272653SPeter Holm+ * to inject failures for malloc zones regardless of 118*8a272653SPeter Holm+ * the malloc black/white lists. 119*8a272653SPeter Holm+ */ 120*8a272653SPeter Holm+ if (((zone->uz_flags & UMA_ZONE_MALLOC) == 0 || 121*8a272653SPeter Holm+ RETURN_VALUE != 0) && 122*8a272653SPeter Holm+ uma_dbg_nowait_fail_enabled_zalloc( 123*8a272653SPeter Holm+ zone->uz_name)) { 124*8a272653SPeter Holm+ /* XXX record call stack */ 125*8a272653SPeter Holm+ atomic_add_long(&zone->uz_fails, 1); 126*8a272653SPeter Holm+ return NULL; 127*8a272653SPeter Holm+ } 128*8a272653SPeter Holm+ }); 129*8a272653SPeter Holm } 130*8a272653SPeter Holm 131*8a272653SPeter Holm KASSERT(curthread->td_critnest == 0, 132*8a272653SPeter Holmdiff --git a/sys/vm/uma_dbg.c b/sys/vm/uma_dbg.c 133*8a272653SPeter Holmindex 3fbd29b..bed3130 100644 134*8a272653SPeter Holm--- a/sys/vm/uma_dbg.c 135*8a272653SPeter Holm+++ b/sys/vm/uma_dbg.c 136*8a272653SPeter Holm@@ -42,6 +42,8 @@ __FBSDID("$FreeBSD$"); 137*8a272653SPeter Holm #include <sys/lock.h> 138*8a272653SPeter Holm #include <sys/mutex.h> 139*8a272653SPeter Holm #include <sys/malloc.h> 140*8a272653SPeter Holm+#include <sys/rwlock.h> 141*8a272653SPeter Holm+#include <sys/sysctl.h> 142*8a272653SPeter Holm 143*8a272653SPeter Holm #include <vm/vm.h> 144*8a272653SPeter Holm #include <vm/vm_object.h> 145*8a272653SPeter Holm@@ -292,4 +294,143 @@ uma_dbg_free(uma_zone_t zone, uma_slab_t slab, void *item) 146*8a272653SPeter Holm BIT_CLR_ATOMIC(SLAB_SETSIZE, freei, &slab->us_debugfree); 147*8a272653SPeter Holm } 148*8a272653SPeter Holm 149*8a272653SPeter Holm+/* XXX explain */ 150*8a272653SPeter Holm+struct rwlock g_uma_dbg_nowait_lock; 151*8a272653SPeter Holm+RW_SYSINIT(uma_dbg_nowait, &g_uma_dbg_nowait_lock, "uma dbg nowait"); 152*8a272653SPeter Holm+ 153*8a272653SPeter Holm+#define NOWAIT_FAIL_LIST_BUFSIZE 4096 154*8a272653SPeter Holm+char malloc_fail_blacklist[NOWAIT_FAIL_LIST_BUFSIZE] = "kobj"; 155*8a272653SPeter Holm+char malloc_fail_whitelist[NOWAIT_FAIL_LIST_BUFSIZE] = ""; 156*8a272653SPeter Holm+char zalloc_fail_blacklist[NOWAIT_FAIL_LIST_BUFSIZE] = 157*8a272653SPeter Holm+ "BUF TRIE,ata_request,sackhole"; 158*8a272653SPeter Holm+char zalloc_fail_whitelist[NOWAIT_FAIL_LIST_BUFSIZE] = ""; 159*8a272653SPeter Holm+ 160*8a272653SPeter Holm+static bool 161*8a272653SPeter Holm+str_in_list(const char *list, char delim, const char *str) 162*8a272653SPeter Holm+{ 163*8a272653SPeter Holm+ const char *b, *e; 164*8a272653SPeter Holm+ size_t blen, slen; 165*8a272653SPeter Holm+ 166*8a272653SPeter Holm+ b = list; 167*8a272653SPeter Holm+ slen = strlen(str); 168*8a272653SPeter Holm+ for (;;) { 169*8a272653SPeter Holm+ e = strchr(b, delim); 170*8a272653SPeter Holm+ blen = e == NULL ? strlen(b) : e - b; 171*8a272653SPeter Holm+ if (blen == slen && strncmp(b, str, slen) == 0) 172*8a272653SPeter Holm+ return true; 173*8a272653SPeter Holm+ if (e == NULL) 174*8a272653SPeter Holm+ break; 175*8a272653SPeter Holm+ b = e + 1; 176*8a272653SPeter Holm+ } 177*8a272653SPeter Holm+ return false; 178*8a272653SPeter Holm+} 179*8a272653SPeter Holm+ 180*8a272653SPeter Holm+static bool 181*8a272653SPeter Holm+uma_dbg_nowait_fail_enabled_internal(const char *blacklist, 182*8a272653SPeter Holm+ const char *whitelist, const char *name) 183*8a272653SPeter Holm+{ 184*8a272653SPeter Holm+ bool fail; 185*8a272653SPeter Holm+ 186*8a272653SPeter Holm+ /* Protect ourselves from the sysctl handlers. */ 187*8a272653SPeter Holm+ rw_rlock(&g_uma_dbg_nowait_lock); 188*8a272653SPeter Holm+ if (whitelist[0] == '\0') 189*8a272653SPeter Holm+ fail = !str_in_list(blacklist, ',', name); 190*8a272653SPeter Holm+ else 191*8a272653SPeter Holm+ fail = str_in_list(whitelist, ',', name); 192*8a272653SPeter Holm+ rw_runlock(&g_uma_dbg_nowait_lock); 193*8a272653SPeter Holm+ 194*8a272653SPeter Holm+ return fail; 195*8a272653SPeter Holm+} 196*8a272653SPeter Holm+ 197*8a272653SPeter Holm+bool 198*8a272653SPeter Holm+uma_dbg_nowait_fail_enabled_malloc(const char *name) 199*8a272653SPeter Holm+{ 200*8a272653SPeter Holm+ return uma_dbg_nowait_fail_enabled_internal(malloc_fail_blacklist, 201*8a272653SPeter Holm+ malloc_fail_whitelist, name); 202*8a272653SPeter Holm+} 203*8a272653SPeter Holm+ 204*8a272653SPeter Holm+bool 205*8a272653SPeter Holm+uma_dbg_nowait_fail_enabled_zalloc(const char *name) 206*8a272653SPeter Holm+{ 207*8a272653SPeter Holm+ return uma_dbg_nowait_fail_enabled_internal(zalloc_fail_blacklist, 208*8a272653SPeter Holm+ zalloc_fail_whitelist, name); 209*8a272653SPeter Holm+} 210*8a272653SPeter Holm+ 211*8a272653SPeter Holm+/* 212*8a272653SPeter Holm+ * XXX provide SYSCTL_STRING_LOCKED / sysctl_string_locked_handler? 213*8a272653SPeter Holm+ * This is basically just a different sysctl_string_handler. This one wraps 214*8a272653SPeter Holm+ * the string manipulation in a lock and in a way that will not cause a sleep 215*8a272653SPeter Holm+ * under that lock. 216*8a272653SPeter Holm+ */ 217*8a272653SPeter Holm+static int 218*8a272653SPeter Holm+sysctl_debug_mnowait_failure_list(SYSCTL_HANDLER_ARGS) 219*8a272653SPeter Holm+{ 220*8a272653SPeter Holm+ char *newbuf = NULL; 221*8a272653SPeter Holm+ int error, newlen; 222*8a272653SPeter Holm+ bool have_lock = false; 223*8a272653SPeter Holm+ 224*8a272653SPeter Holm+ if (req->newptr != NULL) { 225*8a272653SPeter Holm+ newlen = req->newlen - req->newidx; 226*8a272653SPeter Holm+ if (newlen >= arg2) { 227*8a272653SPeter Holm+ error = EINVAL; 228*8a272653SPeter Holm+ goto out; 229*8a272653SPeter Holm+ } 230*8a272653SPeter Holm+ newbuf = malloc(newlen, M_TEMP, M_WAITOK); 231*8a272653SPeter Holm+ error = SYSCTL_IN(req, newbuf, newlen); 232*8a272653SPeter Holm+ if (error != 0) 233*8a272653SPeter Holm+ goto out; 234*8a272653SPeter Holm+ } 235*8a272653SPeter Holm+ 236*8a272653SPeter Holm+ error = sysctl_wire_old_buffer(req, arg2); 237*8a272653SPeter Holm+ if (error != 0) 238*8a272653SPeter Holm+ goto out; 239*8a272653SPeter Holm+ 240*8a272653SPeter Holm+ rw_wlock(&g_uma_dbg_nowait_lock); 241*8a272653SPeter Holm+ have_lock = true; 242*8a272653SPeter Holm+ 243*8a272653SPeter Holm+ error = SYSCTL_OUT(req, arg1, strnlen(arg1, arg2 - 1) + 1); 244*8a272653SPeter Holm+ if (error != 0) 245*8a272653SPeter Holm+ goto out; 246*8a272653SPeter Holm+ 247*8a272653SPeter Holm+ if (newbuf == NULL) 248*8a272653SPeter Holm+ goto out; 249*8a272653SPeter Holm+ 250*8a272653SPeter Holm+ bcopy(newbuf, arg1, newlen); 251*8a272653SPeter Holm+ ((char *)arg1)[newlen] = '\0'; 252*8a272653SPeter Holm+ out: 253*8a272653SPeter Holm+ if (have_lock) 254*8a272653SPeter Holm+ rw_wunlock(&g_uma_dbg_nowait_lock); 255*8a272653SPeter Holm+ free(newbuf, M_TEMP); 256*8a272653SPeter Holm+ return error; 257*8a272653SPeter Holm+} 258*8a272653SPeter Holm+ 259*8a272653SPeter Holm+SYSCTL_NODE(_debug, OID_AUTO, mnowait_failure, CTLFLAG_RW, 0, 260*8a272653SPeter Holm+ "Control of M_NOWAIT memory allocation failure injection."); 261*8a272653SPeter Holm+ 262*8a272653SPeter Holm+SYSCTL_PROC(_debug_mnowait_failure, OID_AUTO, malloc_blacklist, 263*8a272653SPeter Holm+ CTLTYPE_STRING | CTLFLAG_RW | CTLFLAG_MPSAFE, malloc_fail_blacklist, 264*8a272653SPeter Holm+ sizeof(malloc_fail_blacklist), sysctl_debug_mnowait_failure_list, "A", 265*8a272653SPeter Holm+ "With debug.fail_point.malloc and with an empty whitelist, CSV list of " 266*8a272653SPeter Holm+ "zones which remain unaffected."); 267*8a272653SPeter Holm+ 268*8a272653SPeter Holm+SYSCTL_PROC(_debug_mnowait_failure, OID_AUTO, malloc_whitelist, 269*8a272653SPeter Holm+ CTLTYPE_STRING | CTLFLAG_RW | CTLFLAG_MPSAFE, malloc_fail_whitelist, 270*8a272653SPeter Holm+ sizeof(malloc_fail_whitelist), sysctl_debug_mnowait_failure_list, "A", 271*8a272653SPeter Holm+ "With debug.fail_point.malloc, CSV list of zones exclusively affected. " 272*8a272653SPeter Holm+ "With an empty whitelist, all zones but those on the blacklist" 273*8a272653SPeter Holm+ "are affected."); 274*8a272653SPeter Holm+ 275*8a272653SPeter Holm+SYSCTL_PROC(_debug_mnowait_failure, OID_AUTO, zalloc_blacklist, 276*8a272653SPeter Holm+ CTLTYPE_STRING | CTLFLAG_RW | CTLFLAG_MPSAFE, zalloc_fail_blacklist, 277*8a272653SPeter Holm+ sizeof(zalloc_fail_blacklist), sysctl_debug_mnowait_failure_list, "A", 278*8a272653SPeter Holm+ "With debug.fail_point.uma_zalloc_arg and with an empty whitelist, CSV " 279*8a272653SPeter Holm+ "list of zones which remain unaffected."); 280*8a272653SPeter Holm+ 281*8a272653SPeter Holm+SYSCTL_PROC(_debug_mnowait_failure, OID_AUTO, zalloc_whitelist, 282*8a272653SPeter Holm+ CTLTYPE_STRING | CTLFLAG_RW | CTLFLAG_MPSAFE, zalloc_fail_whitelist, 283*8a272653SPeter Holm+ sizeof(zalloc_fail_whitelist), sysctl_debug_mnowait_failure_list, "A", 284*8a272653SPeter Holm+ "With debug.fail_point.uma_zalloc_arg, CSV list of zones exclusively " 285*8a272653SPeter Holm+ "affected. With an empty whitelist, all zones but those on the blacklist" 286*8a272653SPeter Holm+ "are affected."); 287*8a272653SPeter Holm+ 288*8a272653SPeter Holm #endif /* INVARIANTS */ 289*8a272653SPeter Holmdiff --git a/sys/vm/uma_int.h b/sys/vm/uma_int.h 290*8a272653SPeter Holmindex ad2a405..284747f 100644 291*8a272653SPeter Holm--- a/sys/vm/uma_int.h 292*8a272653SPeter Holm+++ b/sys/vm/uma_int.h 293*8a272653SPeter Holm@@ -427,6 +427,9 @@ vsetslab(vm_offset_t va, uma_slab_t slab) 294*8a272653SPeter Holm void *uma_small_alloc(uma_zone_t zone, vm_size_t bytes, uint8_t *pflag, 295*8a272653SPeter Holm int wait); 296*8a272653SPeter Holm void uma_small_free(void *mem, vm_size_t size, uint8_t flags); 297*8a272653SPeter Holm+ 298*8a272653SPeter Holm+bool uma_dbg_nowait_fail_enabled_malloc(const char *name); 299*8a272653SPeter Holm+bool uma_dbg_nowait_fail_enabled_zalloc(const char *name); 300*8a272653SPeter Holm #endif /* _KERNEL */ 301*8a272653SPeter Holm 302*8a272653SPeter Holm #endif /* VM_UMA_INT_H */ 303