1139825Simp/*-
2148078Srwatson * Copyright (c) 2002, 2003, 2004, 2005 Jeffrey Roberson <jeff@FreeBSD.org>
3148078Srwatson * Copyright (c) 2004, 2005 Bosko Milekic <bmilekic@FreeBSD.org>
4148078Srwatson * All rights reserved.
595771Sjeff *
695771Sjeff * Redistribution and use in source and binary forms, with or without
795771Sjeff * modification, are permitted provided that the following conditions
895771Sjeff * are met:
995771Sjeff * 1. Redistributions of source code must retain the above copyright
1095771Sjeff *    notice unmodified, this list of conditions, and the following
1195771Sjeff *    disclaimer.
1295771Sjeff * 2. Redistributions in binary form must reproduce the above copyright
1395771Sjeff *    notice, this list of conditions and the following disclaimer in the
1495771Sjeff *    documentation and/or other materials provided with the distribution.
1595771Sjeff *
1695771Sjeff * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
1795771Sjeff * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
1895771Sjeff * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
1995771Sjeff * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
2095771Sjeff * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
2195771Sjeff * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
2295771Sjeff * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
2395771Sjeff * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
2495771Sjeff * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
2595771Sjeff * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2695771Sjeff */
2795771Sjeff
2895771Sjeff/*
2995771Sjeff * uma_dbg.c	Debugging features for UMA users
3095771Sjeff *
3195771Sjeff */
3295771Sjeff
33116226Sobrien#include <sys/cdefs.h>
34116226Sobrien__FBSDID("$FreeBSD$");
3595771Sjeff
3695771Sjeff#include <sys/param.h>
3795771Sjeff#include <sys/systm.h>
38251709Sjeff#include <sys/bitset.h>
3995771Sjeff#include <sys/kernel.h>
4095771Sjeff#include <sys/types.h>
4195771Sjeff#include <sys/queue.h>
4295771Sjeff#include <sys/lock.h>
4395771Sjeff#include <sys/mutex.h>
4495931Sjeff#include <sys/malloc.h>
4595771Sjeff
46103531Sjeff#include <vm/vm.h>
47103531Sjeff#include <vm/vm_object.h>
48103531Sjeff#include <vm/vm_page.h>
4995771Sjeff#include <vm/uma.h>
5095771Sjeff#include <vm/uma_int.h>
5195771Sjeff#include <vm/uma_dbg.h>
5295771Sjeff
53249313Sglebiusstatic const uint32_t uma_junk = 0xdeadc0de;
5495771Sjeff
5595771Sjeff/*
56132987Sgreen * Checks an item to make sure it hasn't been overwritten since it was freed,
57132987Sgreen * prior to subsequent reallocation.
5895771Sjeff *
5995771Sjeff * Complies with standard ctor arg/return
6095771Sjeff *
6195771Sjeff */
62132987Sgreenint
63132987Sgreentrash_ctor(void *mem, int size, void *arg, int flags)
6495771Sjeff{
6595771Sjeff	int cnt;
66249313Sglebius	uint32_t *p;
6795771Sjeff
6895771Sjeff	cnt = size / sizeof(uma_junk);
6995771Sjeff
7095771Sjeff	for (p = mem; cnt > 0; cnt--, p++)
71147615Ssilby		if (*p != uma_junk) {
72147615Ssilby			printf("Memory modified after free %p(%d) val=%x @ %p\n",
73120526Sphk			    mem, size, *p, p);
74147615Ssilby			return (0);
75147615Ssilby		}
76132987Sgreen	return (0);
7795771Sjeff}
7895771Sjeff
7995771Sjeff/*
8095771Sjeff * Fills an item with predictable garbage
8195771Sjeff *
8295771Sjeff * Complies with standard dtor arg/return
8395771Sjeff *
8495771Sjeff */
8595771Sjeffvoid
8695771Sjefftrash_dtor(void *mem, int size, void *arg)
8795771Sjeff{
8895771Sjeff	int cnt;
89249313Sglebius	uint32_t *p;
9095771Sjeff
9195771Sjeff	cnt = size / sizeof(uma_junk);
9295771Sjeff
9395771Sjeff	for (p = mem; cnt > 0; cnt--, p++)
9495771Sjeff		*p = uma_junk;
9595771Sjeff}
9695771Sjeff
9795771Sjeff/*
9895771Sjeff * Fills an item with predictable garbage
9995771Sjeff *
10095771Sjeff * Complies with standard init arg/return
10195771Sjeff *
10295771Sjeff */
103132987Sgreenint
104132987Sgreentrash_init(void *mem, int size, int flags)
10595771Sjeff{
10695771Sjeff	trash_dtor(mem, size, NULL);
107132987Sgreen	return (0);
10895771Sjeff}
10995771Sjeff
11095771Sjeff/*
11195771Sjeff * Checks an item to make sure it hasn't been overwritten since it was freed.
11295771Sjeff *
11395771Sjeff * Complies with standard fini arg/return
11495771Sjeff *
11595771Sjeff */
11695771Sjeffvoid
11795771Sjefftrash_fini(void *mem, int size)
11895771Sjeff{
119132987Sgreen	(void)trash_ctor(mem, size, NULL, 0);
12095771Sjeff}
12195899Sjeff
122132987Sgreenint
123132987Sgreenmtrash_ctor(void *mem, int size, void *arg, int flags)
12495931Sjeff{
12595931Sjeff	struct malloc_type **ksp;
126249313Sglebius	uint32_t *p = mem;
12795931Sjeff	int cnt;
12895931Sjeff
12995931Sjeff	size -= sizeof(struct malloc_type *);
13095931Sjeff	ksp = (struct malloc_type **)mem;
13195931Sjeff	ksp += size / sizeof(struct malloc_type *);
13295931Sjeff	cnt = size / sizeof(uma_junk);
13395931Sjeff
13495931Sjeff	for (p = mem; cnt > 0; cnt--, p++)
13595931Sjeff		if (*p != uma_junk) {
136120526Sphk			printf("Memory modified after free %p(%d) val=%x @ %p\n",
137120526Sphk			    mem, size, *p, p);
13895931Sjeff			panic("Most recently used by %s\n", (*ksp == NULL)?
13995931Sjeff			    "none" : (*ksp)->ks_shortdesc);
14095931Sjeff		}
141132987Sgreen	return (0);
14295931Sjeff}
14395931Sjeff
14495931Sjeff/*
14595931Sjeff * Fills an item with predictable garbage
14695931Sjeff *
14795931Sjeff * Complies with standard dtor arg/return
14895931Sjeff *
14995931Sjeff */
15095931Sjeffvoid
15195931Sjeffmtrash_dtor(void *mem, int size, void *arg)
15295931Sjeff{
15395931Sjeff	int cnt;
154249313Sglebius	uint32_t *p;
15595931Sjeff
15695931Sjeff	size -= sizeof(struct malloc_type *);
15795931Sjeff	cnt = size / sizeof(uma_junk);
15895931Sjeff
15995931Sjeff	for (p = mem; cnt > 0; cnt--, p++)
16095931Sjeff		*p = uma_junk;
16195931Sjeff}
16295931Sjeff
16395931Sjeff/*
16495931Sjeff * Fills an item with predictable garbage
16595931Sjeff *
16695931Sjeff * Complies with standard init arg/return
16795931Sjeff *
16895931Sjeff */
169132987Sgreenint
170132987Sgreenmtrash_init(void *mem, int size, int flags)
17195931Sjeff{
17295931Sjeff	struct malloc_type **ksp;
17395931Sjeff
17495931Sjeff	mtrash_dtor(mem, size, NULL);
17595931Sjeff
17695931Sjeff	ksp = (struct malloc_type **)mem;
17795931Sjeff	ksp += (size / sizeof(struct malloc_type *)) - 1;
17895931Sjeff	*ksp = NULL;
179132987Sgreen	return (0);
18095931Sjeff}
18195931Sjeff
18295931Sjeff/*
183132987Sgreen * Checks an item to make sure it hasn't been overwritten since it was freed,
184132987Sgreen * prior to freeing it back to available memory.
18595931Sjeff *
18695931Sjeff * Complies with standard fini arg/return
18795931Sjeff *
18895931Sjeff */
18995931Sjeffvoid
19095931Sjeffmtrash_fini(void *mem, int size)
19195931Sjeff{
192132987Sgreen	(void)mtrash_ctor(mem, size, NULL, 0);
19395931Sjeff}
19495931Sjeff
195251709Sjeff#ifdef INVARIANTS
19695899Sjeffstatic uma_slab_t
19795899Sjeffuma_dbg_getslab(uma_zone_t zone, void *item)
19895899Sjeff{
19995899Sjeff	uma_slab_t slab;
200129906Sbmilekic	uma_keg_t keg;
201249313Sglebius	uint8_t *mem;
20295899Sjeff
203251709Sjeff	mem = (uint8_t *)((uintptr_t)item & (~UMA_SLAB_MASK));
204187681Sjeff	if (zone->uz_flags & UMA_ZONE_VTOSLAB) {
205103531Sjeff		slab = vtoslab((vm_offset_t)mem);
20695899Sjeff	} else {
207251709Sjeff		/*
208251709Sjeff		 * It is safe to return the slab here even though the
209251709Sjeff		 * zone is unlocked because the item's allocation state
210251709Sjeff		 * essentially holds a reference.
211251709Sjeff		 */
212251709Sjeff		ZONE_LOCK(zone);
213187681Sjeff		keg = LIST_FIRST(&zone->uz_kegs)->kl_keg;
214187681Sjeff		if (keg->uk_flags & UMA_ZONE_HASH)
215187681Sjeff			slab = hash_sfind(&keg->uk_hash, mem);
216187681Sjeff		else
217187681Sjeff			slab = (uma_slab_t)(mem + keg->uk_pgoff);
218251709Sjeff		ZONE_UNLOCK(zone);
21995899Sjeff	}
22095899Sjeff
22195899Sjeff	return (slab);
22295899Sjeff}
22395899Sjeff
22495899Sjeff/*
22595899Sjeff * Set up the slab's freei data such that uma_dbg_free can function.
22695899Sjeff *
22795899Sjeff */
22895899Sjeffvoid
22995899Sjeffuma_dbg_alloc(uma_zone_t zone, uma_slab_t slab, void *item)
23095899Sjeff{
231129906Sbmilekic	uma_keg_t keg;
23295899Sjeff	int freei;
23395899Sjeff
234252040Sjeff	if (zone_first_keg(zone) == NULL)
235252040Sjeff		return;
23695899Sjeff	if (slab == NULL) {
23795899Sjeff		slab = uma_dbg_getslab(zone, item);
23895899Sjeff		if (slab == NULL)
23995899Sjeff			panic("uma: item %p did not belong to zone %s\n",
24095899Sjeff			    item, zone->uz_name);
24195899Sjeff	}
242187681Sjeff	keg = slab->us_keg;
243251709Sjeff	freei = ((uintptr_t)item - (uintptr_t)slab->us_data) / keg->uk_rsize;
24495899Sjeff
245251709Sjeff	if (BIT_ISSET(SLAB_SETSIZE, freei, &slab->us_debugfree))
246251709Sjeff		panic("Duplicate alloc of %p from zone %p(%s) slab %p(%d)\n",
247251709Sjeff		    item, zone, zone->uz_name, slab, freei);
248251709Sjeff	BIT_SET_ATOMIC(SLAB_SETSIZE, freei, &slab->us_debugfree);
24995899Sjeff
25095899Sjeff	return;
25195899Sjeff}
25295899Sjeff
25395899Sjeff/*
25495899Sjeff * Verifies freed addresses.  Checks for alignment, valid slab membership
25595899Sjeff * and duplicate frees.
25695899Sjeff *
25795899Sjeff */
25895899Sjeffvoid
25995899Sjeffuma_dbg_free(uma_zone_t zone, uma_slab_t slab, void *item)
26095899Sjeff{
261129906Sbmilekic	uma_keg_t keg;
26295899Sjeff	int freei;
26395899Sjeff
264252040Sjeff	if (zone_first_keg(zone) == NULL)
265252040Sjeff		return;
26695899Sjeff	if (slab == NULL) {
26795899Sjeff		slab = uma_dbg_getslab(zone, item);
26895899Sjeff		if (slab == NULL)
26995899Sjeff			panic("uma: Freed item %p did not belong to zone %s\n",
27095899Sjeff			    item, zone->uz_name);
27195899Sjeff	}
272187681Sjeff	keg = slab->us_keg;
273251709Sjeff	freei = ((uintptr_t)item - (uintptr_t)slab->us_data) / keg->uk_rsize;
27495899Sjeff
275129906Sbmilekic	if (freei >= keg->uk_ipers)
276251709Sjeff		panic("Invalid free of %p from zone %p(%s) slab %p(%d)\n",
277251709Sjeff		    item, zone, zone->uz_name, slab, freei);
27895899Sjeff
279251709Sjeff	if (((freei * keg->uk_rsize) + slab->us_data) != item)
280251709Sjeff		panic("Unaligned free of %p from zone %p(%s) slab %p(%d)\n",
281251709Sjeff		    item, zone, zone->uz_name, slab, freei);
28295899Sjeff
283251709Sjeff	if (!BIT_ISSET(SLAB_SETSIZE, freei, &slab->us_debugfree))
284251709Sjeff		panic("Duplicate free of %p from zone %p(%s) slab %p(%d)\n",
285251709Sjeff		    item, zone, zone->uz_name, slab, freei);
286136276Sgreen
287251709Sjeff	BIT_CLR_ATOMIC(SLAB_SETSIZE, freei, &slab->us_debugfree);
288251709Sjeff}
289136276Sgreen
290251709Sjeff#endif /* INVARIANTS */
291