uma_dbg.c revision 129906
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 129906 2004-05-31 21:46:06Z bmilekic $");
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 freed.
55 *
56 * Complies with standard ctor arg/return
57 *
58 */
59void
60trash_ctor(void *mem, int size, void *arg)
61{
62	int cnt;
63	u_int32_t *p;
64
65	cnt = size / sizeof(uma_junk);
66
67	for (p = mem; cnt > 0; cnt--, p++)
68		if (*p != uma_junk)
69			panic("Memory modified after free %p(%d) val=%x @ %p\n",
70			    mem, size, *p, p);
71}
72
73/*
74 * Fills an item with predictable garbage
75 *
76 * Complies with standard dtor arg/return
77 *
78 */
79void
80trash_dtor(void *mem, int size, void *arg)
81{
82	int cnt;
83	u_int32_t *p;
84
85	cnt = size / sizeof(uma_junk);
86
87	for (p = mem; cnt > 0; cnt--, p++)
88		*p = uma_junk;
89}
90
91/*
92 * Fills an item with predictable garbage
93 *
94 * Complies with standard init arg/return
95 *
96 */
97void
98trash_init(void *mem, int size)
99{
100	trash_dtor(mem, size, NULL);
101}
102
103/*
104 * Checks an item to make sure it hasn't been overwritten since it was freed.
105 *
106 * Complies with standard fini arg/return
107 *
108 */
109void
110trash_fini(void *mem, int size)
111{
112	trash_ctor(mem, size, NULL);
113}
114
115/*
116 * Checks an item to make sure it hasn't been overwritten since freed.
117 *
118 * Complies with standard ctor arg/return
119 *
120 */
121void
122mtrash_ctor(void *mem, int size, void *arg)
123{
124	struct malloc_type **ksp;
125	u_int32_t *p = mem;
126	int cnt;
127
128	size -= sizeof(struct malloc_type *);
129	ksp = (struct malloc_type **)mem;
130	ksp += size / sizeof(struct malloc_type *);
131	cnt = size / sizeof(uma_junk);
132
133	for (p = mem; cnt > 0; cnt--, p++)
134		if (*p != uma_junk) {
135			printf("Memory modified after free %p(%d) val=%x @ %p\n",
136			    mem, size, *p, p);
137			panic("Most recently used by %s\n", (*ksp == NULL)?
138			    "none" : (*ksp)->ks_shortdesc);
139		}
140}
141
142/*
143 * Fills an item with predictable garbage
144 *
145 * Complies with standard dtor arg/return
146 *
147 */
148void
149mtrash_dtor(void *mem, int size, void *arg)
150{
151	int cnt;
152	u_int32_t *p;
153
154	size -= sizeof(struct malloc_type *);
155	cnt = size / sizeof(uma_junk);
156
157	for (p = mem; cnt > 0; cnt--, p++)
158		*p = uma_junk;
159}
160
161/*
162 * Fills an item with predictable garbage
163 *
164 * Complies with standard init arg/return
165 *
166 */
167void
168mtrash_init(void *mem, int size)
169{
170	struct malloc_type **ksp;
171
172	mtrash_dtor(mem, size, NULL);
173
174	ksp = (struct malloc_type **)mem;
175	ksp += (size / sizeof(struct malloc_type *)) - 1;
176	*ksp = NULL;
177}
178
179/*
180 * Checks an item to make sure it hasn't been overwritten since it was freed.
181 *
182 * Complies with standard fini arg/return
183 *
184 */
185void
186mtrash_fini(void *mem, int size)
187{
188	mtrash_ctor(mem, size, NULL);
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