xref: /freebsd/tools/test/stress2/misc/uma_zalloc_arg.sh (revision 8a272653d9fbd9fc37691c9aad6a05089b4ecb4d)
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