2 * Copyright (c) 2002, 2003, 2004, 2005 Jeffrey Roberson <jeff@FreeBSD.org>
3 * Copyright (c) 2004, 2005 Bosko Milekic <bmilekic@FreeBSD.org>
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
9 * 1. Redistributions of source code must retain the above copyright
10 * notice unmodified, this list of conditions, and the following
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
17 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
18 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
19 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
20 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
21 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
22 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
23 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
25 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 * uma_dbg.c Debugging features for UMA users
33 #include <sys/cdefs.h>
34 __FBSDID("$FreeBSD$");
36 #include <sys/param.h>
37 #include <sys/systm.h>
38 #include <sys/kernel.h>
39 #include <sys/types.h>
40 #include <sys/queue.h>
42 #include <sys/mutex.h>
43 #include <sys/malloc.h>
46 #include <vm/vm_object.h>
47 #include <vm/vm_page.h>
49 #include <vm/uma_int.h>
50 #include <vm/uma_dbg.h>
52 static const u_int32_t uma_junk
= 0xdeadc0de;
55 * Checks an item to make sure it hasn't been overwritten since it was freed,
56 * prior to subsequent reallocation.
58 * Complies with standard ctor arg/return
62 trash_ctor(void *mem
, int size
, void *arg
, int flags
)
67 cnt
= size
/ sizeof(uma_junk
);
69 for (p
= mem
; cnt
> 0; cnt
--, p
++)
71 printf("Memory modified after free %p(%d) val=%x @ %p\n",
79 * Fills an item with predictable garbage
81 * Complies with standard dtor arg/return
85 trash_dtor(void *mem
, int size
, void *arg
)
90 cnt
= size
/ sizeof(uma_junk
);
92 for (p
= mem
; cnt
> 0; cnt
--, p
++)
97 * Fills an item with predictable garbage
99 * Complies with standard init arg/return
103 trash_init(void *mem
, int size
, int flags
)
105 trash_dtor(mem
, size
, NULL
);
110 * Checks an item to make sure it hasn't been overwritten since it was freed.
112 * Complies with standard fini arg/return
116 trash_fini(void *mem
, int size
)
118 (void)trash_ctor(mem
, size
, NULL
, 0);
122 mtrash_ctor(void *mem
, int size
, void *arg
, int flags
)
124 struct malloc_type
**ksp
;
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
);
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",
137 panic("Most recently used by %s\n", (*ksp
== NULL
)?
138 "none" : (*ksp
)->ks_shortdesc
);
144 * Fills an item with predictable garbage
146 * Complies with standard dtor arg/return
150 mtrash_dtor(void *mem
, int size
, void *arg
)
155 size
-= sizeof(struct malloc_type
*);
156 cnt
= size
/ sizeof(uma_junk
);
158 for (p
= mem
; cnt
> 0; cnt
--, p
++)
163 * Fills an item with predictable garbage
165 * Complies with standard init arg/return
169 mtrash_init(void *mem
, int size
, int flags
)
171 struct malloc_type
**ksp
;
173 mtrash_dtor(mem
, size
, NULL
);
175 ksp
= (struct malloc_type
**)mem
;
176 ksp
+= (size
/ sizeof(struct malloc_type
*)) - 1;
182 * Checks an item to make sure it hasn't been overwritten since it was freed,
183 * prior to freeing it back to available memory.
185 * Complies with standard fini arg/return
189 mtrash_fini(void *mem
, int size
)
191 (void)mtrash_ctor(mem
, size
, NULL
, 0);
195 uma_dbg_getslab(uma_zone_t zone
, void *item
)
202 mem
= (u_int8_t
*)((unsigned long)item
& (~UMA_SLAB_MASK
));
203 if (keg
->uk_flags
& UMA_ZONE_MALLOC
) {
204 slab
= vtoslab((vm_offset_t
)mem
);
205 } else if (keg
->uk_flags
& UMA_ZONE_HASH
) {
206 slab
= hash_sfind(&keg
->uk_hash
, mem
);
208 mem
+= keg
->uk_pgoff
;
209 slab
= (uma_slab_t
)mem
;
216 * Set up the slab's freei data such that uma_dbg_free can function.
221 uma_dbg_alloc(uma_zone_t zone
, uma_slab_t slab
, void *item
)
224 uma_slabrefcnt_t slabref
;
229 slab
= uma_dbg_getslab(zone
, item
);
231 panic("uma: item %p did not belong to zone %s\n",
232 item
, zone
->uz_name
);
235 freei
= ((unsigned long)item
- (unsigned long)slab
->us_data
)
238 if (keg
->uk_flags
& UMA_ZONE_REFCNT
) {
239 slabref
= (uma_slabrefcnt_t
)slab
;
240 slabref
->us_freelist
[freei
].us_item
= 255;
242 slab
->us_freelist
[freei
].us_item
= 255;
249 * Verifies freed addresses. Checks for alignment, valid slab membership
250 * and duplicate frees.
255 uma_dbg_free(uma_zone_t zone
, uma_slab_t slab
, void *item
)
258 uma_slabrefcnt_t slabref
;
263 slab
= uma_dbg_getslab(zone
, item
);
265 panic("uma: Freed item %p did not belong to zone %s\n",
266 item
, zone
->uz_name
);
269 freei
= ((unsigned long)item
- (unsigned long)slab
->us_data
)
272 if (freei
>= keg
->uk_ipers
)
273 panic("zone: %s(%p) slab %p freelist %d out of range 0-%d\n",
274 zone
->uz_name
, zone
, slab
, freei
, keg
->uk_ipers
-1);
276 if (((freei
* keg
->uk_rsize
) + slab
->us_data
) != item
) {
277 printf("zone: %s(%p) slab %p freed address %p unaligned.\n",
278 zone
->uz_name
, zone
, slab
, item
);
279 panic("should be %p\n",
280 (freei
* keg
->uk_rsize
) + slab
->us_data
);
283 if (keg
->uk_flags
& UMA_ZONE_REFCNT
) {
284 slabref
= (uma_slabrefcnt_t
)slab
;
285 if (slabref
->us_freelist
[freei
].us_item
!= 255) {
286 printf("Slab at %p, freei %d = %d.\n",
287 slab
, freei
, slabref
->us_freelist
[freei
].us_item
);
288 panic("Duplicate free of item %p from zone %p(%s)\n",
289 item
, zone
, zone
->uz_name
);
293 * When this is actually linked into the slab this will change.
294 * Until then the count of valid slabs will make sure we don't
295 * accidentally follow this and assume it's a valid index.
297 slabref
->us_freelist
[freei
].us_item
= 0;
299 if (slab
->us_freelist
[freei
].us_item
!= 255) {
300 printf("Slab at %p, freei %d = %d.\n",
301 slab
, freei
, slab
->us_freelist
[freei
].us_item
);
302 panic("Duplicate free of item %p from zone %p(%s)\n",
303 item
, zone
, zone
->uz_name
);
307 * When this is actually linked into the slab this will change.
308 * Until then the count of valid slabs will make sure we don't
309 * accidentally follow this and assume it's a valid index.
311 slab
->us_freelist
[freei
].us_item
= 0;