uma_dbg.c revision 132987
1/*
2 * Copyright (c) 2002, Jeffrey Roberson <jeff@freebsd.org>
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 *    notice unmodified, this list of conditions, and the following
10 *    disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 *    notice, this list of conditions and the following disclaimer in the
13 *    documentation and/or other materials provided with the distribution.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
16 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
17 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
18 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
19 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
20 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
21 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
22 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
24 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25 */
26
27/*
28 * uma_dbg.c	Debugging features for UMA users
29 *
30 */
31
32#include <sys/cdefs.h>
33__FBSDID("$FreeBSD: head/sys/vm/uma_dbg.c 132987 2004-08-02 00:18:36Z green $");
34
35#include <sys/param.h>
36#include <sys/systm.h>
37#include <sys/kernel.h>
38#include <sys/types.h>
39#include <sys/queue.h>
40#include <sys/lock.h>
41#include <sys/mutex.h>
42#include <sys/malloc.h>
43
44#include <vm/vm.h>
45#include <vm/vm_object.h>
46#include <vm/vm_page.h>
47#include <vm/uma.h>
48#include <vm/uma_int.h>
49#include <vm/uma_dbg.h>
50
51static const u_int32_t uma_junk = 0xdeadc0de;
52
53/*
54 * Checks an item to make sure it hasn't been overwritten since it was freed,
55 * prior to subsequent reallocation.
56 *
57 * Complies with standard ctor arg/return
58 *
59 */
60int
61trash_ctor(void *mem, int size, void *arg, int flags)
62{
63	int cnt;
64	u_int32_t *p;
65
66	cnt = size / sizeof(uma_junk);
67
68	for (p = mem; cnt > 0; cnt--, p++)
69		if (*p != uma_junk)
70			panic("Memory modified after free %p(%d) val=%x @ %p\n",
71			    mem, size, *p, p);
72	return (0);
73}
74
75/*
76 * Fills an item with predictable garbage
77 *
78 * Complies with standard dtor arg/return
79 *
80 */
81void
82trash_dtor(void *mem, int size, void *arg)
83{
84	int cnt;
85	u_int32_t *p;
86
87	cnt = size / sizeof(uma_junk);
88
89	for (p = mem; cnt > 0; cnt--, p++)
90		*p = uma_junk;
91}
92
93/*
94 * Fills an item with predictable garbage
95 *
96 * Complies with standard init arg/return
97 *
98 */
99int
100trash_init(void *mem, int size, int flags)
101{
102	trash_dtor(mem, size, NULL);
103	return (0);
104}
105
106/*
107 * Checks an item to make sure it hasn't been overwritten since it was freed.
108 *
109 * Complies with standard fini arg/return
110 *
111 */
112void
113trash_fini(void *mem, int size)
114{
115	(void)trash_ctor(mem, size, NULL, 0);
116}
117
118int
119mtrash_ctor(void *mem, int size, void *arg, int flags)
120{
121	struct malloc_type **ksp;
122	u_int32_t *p = mem;
123	int cnt;
124
125	size -= sizeof(struct malloc_type *);
126	ksp = (struct malloc_type **)mem;
127	ksp += size / sizeof(struct malloc_type *);
128	cnt = size / sizeof(uma_junk);
129
130	for (p = mem; cnt > 0; cnt--, p++)
131		if (*p != uma_junk) {
132			printf("Memory modified after free %p(%d) val=%x @ %p\n",
133			    mem, size, *p, p);
134			panic("Most recently used by %s\n", (*ksp == NULL)?
135			    "none" : (*ksp)->ks_shortdesc);
136		}
137	return (0);
138}
139
140/*
141 * Fills an item with predictable garbage
142 *
143 * Complies with standard dtor arg/return
144 *
145 */
146void
147mtrash_dtor(void *mem, int size, void *arg)
148{
149	int cnt;
150	u_int32_t *p;
151
152	size -= sizeof(struct malloc_type *);
153	cnt = size / sizeof(uma_junk);
154
155	for (p = mem; cnt > 0; cnt--, p++)
156		*p = uma_junk;
157}
158
159/*
160 * Fills an item with predictable garbage
161 *
162 * Complies with standard init arg/return
163 *
164 */
165int
166mtrash_init(void *mem, int size, int flags)
167{
168	struct malloc_type **ksp;
169
170	mtrash_dtor(mem, size, NULL);
171
172	ksp = (struct malloc_type **)mem;
173	ksp += (size / sizeof(struct malloc_type *)) - 1;
174	*ksp = NULL;
175	return (0);
176}
177
178/*
179 * Checks an item to make sure it hasn't been overwritten since it was freed,
180 * prior to freeing it back to available memory.
181 *
182 * Complies with standard fini arg/return
183 *
184 */
185void
186mtrash_fini(void *mem, int size)
187{
188	(void)mtrash_ctor(mem, size, NULL, 0);
189}
190
191static uma_slab_t
192uma_dbg_getslab(uma_zone_t zone, void *item)
193{
194	uma_slab_t slab;
195	uma_keg_t keg;
196	u_int8_t *mem;
197
198	keg = zone->uz_keg;
199	mem = (u_int8_t *)((unsigned long)item & (~UMA_SLAB_MASK));
200	if (keg->uk_flags & UMA_ZONE_MALLOC) {
201		slab = vtoslab((vm_offset_t)mem);
202	} else if (keg->uk_flags & UMA_ZONE_HASH) {
203		slab = hash_sfind(&keg->uk_hash, mem);
204	} else {
205		mem += keg->uk_pgoff;
206		slab = (uma_slab_t)mem;
207	}
208
209	return (slab);
210}
211
212/*
213 * Set up the slab's freei data such that uma_dbg_free can function.
214 *
215 */
216
217void
218uma_dbg_alloc(uma_zone_t zone, uma_slab_t slab, void *item)
219{
220	uma_keg_t keg;
221	int freei;
222
223	keg = zone->uz_keg;
224	if (slab == NULL) {
225		slab = uma_dbg_getslab(zone, item);
226		if (slab == NULL)
227			panic("uma: item %p did not belong to zone %s\n",
228			    item, zone->uz_name);
229	}
230
231	freei = ((unsigned long)item - (unsigned long)slab->us_data)
232	    / keg->uk_rsize;
233
234	slab->us_freelist[freei].us_item = 255;
235
236	return;
237}
238
239/*
240 * Verifies freed addresses.  Checks for alignment, valid slab membership
241 * and duplicate frees.
242 *
243 */
244
245void
246uma_dbg_free(uma_zone_t zone, uma_slab_t slab, void *item)
247{
248	uma_keg_t keg;
249	int freei;
250
251	keg = zone->uz_keg;
252	if (slab == NULL) {
253		slab = uma_dbg_getslab(zone, item);
254		if (slab == NULL)
255			panic("uma: Freed item %p did not belong to zone %s\n",
256			    item, zone->uz_name);
257	}
258
259	freei = ((unsigned long)item - (unsigned long)slab->us_data)
260	    / keg->uk_rsize;
261
262	if (freei >= keg->uk_ipers)
263		panic("zone: %s(%p) slab %p freelist %d out of range 0-%d\n",
264		    zone->uz_name, zone, slab, freei, keg->uk_ipers-1);
265
266	if (((freei * keg->uk_rsize) + slab->us_data) != item) {
267		printf("zone: %s(%p) slab %p freed address %p unaligned.\n",
268		    zone->uz_name, zone, slab, item);
269		panic("should be %p\n",
270		    (freei * keg->uk_rsize) + slab->us_data);
271	}
272
273	if (slab->us_freelist[freei].us_item != 255) {
274		printf("Slab at %p, freei %d = %d.\n",
275		    slab, freei, slab->us_freelist[freei].us_item);
276		panic("Duplicate free of item %p from zone %p(%s)\n",
277		    item, zone, zone->uz_name);
278	}
279
280	/*
281	 * When this is actually linked into the slab this will change.
282	 * Until then the count of valid slabs will make sure we don't
283	 * accidentally follow this and assume it's a valid index.
284	 */
285	slab->us_freelist[freei].us_item = 0;
286}
287