uma_dbg.c revision 103531
195771Sjeff/*
295771Sjeff * Copyright (c) 2002, Jeffrey Roberson <jroberson@chesapeake.net>
395771Sjeff * All rights reserved.
495771Sjeff *
595771Sjeff * Redistribution and use in source and binary forms, with or without
695771Sjeff * modification, are permitted provided that the following conditions
795771Sjeff * are met:
895771Sjeff * 1. Redistributions of source code must retain the above copyright
995771Sjeff *    notice unmodified, this list of conditions, and the following
1095771Sjeff *    disclaimer.
1195771Sjeff * 2. Redistributions in binary form must reproduce the above copyright
1295771Sjeff *    notice, this list of conditions and the following disclaimer in the
1395771Sjeff *    documentation and/or other materials provided with the distribution.
1495771Sjeff *
1595771Sjeff * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
1695771Sjeff * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
1795771Sjeff * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
1895771Sjeff * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
1995771Sjeff * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
2095771Sjeff * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
2195771Sjeff * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
2295771Sjeff * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
2395771Sjeff * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
2495771Sjeff * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2595771Sjeff *
2695771Sjeff * $FreeBSD: head/sys/vm/uma_dbg.c 103531 2002-09-18 08:26:30Z jeff $
2795771Sjeff *
2895771Sjeff */
2995771Sjeff
3095771Sjeff/*
3195771Sjeff * uma_dbg.c	Debugging features for UMA users
3295771Sjeff *
3395771Sjeff */
3495771Sjeff
3595771Sjeff
3695771Sjeff#include <sys/param.h>
3795771Sjeff#include <sys/systm.h>
3895771Sjeff#include <sys/kernel.h>
3995771Sjeff#include <sys/types.h>
4095771Sjeff#include <sys/queue.h>
4195771Sjeff#include <sys/lock.h>
4295771Sjeff#include <sys/mutex.h>
4395931Sjeff#include <sys/malloc.h>
4495771Sjeff
45103531Sjeff#include <vm/vm.h>
46103531Sjeff#include <vm/vm_object.h>
47103531Sjeff#include <vm/vm_page.h>
4895771Sjeff#include <vm/uma.h>
4995771Sjeff#include <vm/uma_int.h>
5095771Sjeff#include <vm/uma_dbg.h>
5195771Sjeff
5295771Sjeffstatic const u_int32_t uma_junk = 0xdeadc0de;
5395771Sjeff
5495771Sjeff/*
5595771Sjeff * Checks an item to make sure it hasn't been overwritten since freed.
5695771Sjeff *
5795771Sjeff * Complies with standard ctor arg/return
5895771Sjeff *
5995771Sjeff */
6095771Sjeffvoid
6195771Sjefftrash_ctor(void *mem, int size, void *arg)
6295771Sjeff{
6395771Sjeff	int cnt;
6495771Sjeff	u_int32_t *p;
6595771Sjeff
6695771Sjeff	cnt = size / sizeof(uma_junk);
6795771Sjeff
6895771Sjeff	for (p = mem; cnt > 0; cnt--, p++)
6995771Sjeff		if (*p != uma_junk)
7095771Sjeff			panic("Memory modified after free %p(%d)\n",
7195771Sjeff			    mem, size);
7295771Sjeff}
7395771Sjeff
7495771Sjeff/*
7595771Sjeff * Fills an item with predictable garbage
7695771Sjeff *
7795771Sjeff * Complies with standard dtor arg/return
7895771Sjeff *
7995771Sjeff */
8095771Sjeffvoid
8195771Sjefftrash_dtor(void *mem, int size, void *arg)
8295771Sjeff{
8395771Sjeff	int cnt;
8495771Sjeff	u_int32_t *p;
8595771Sjeff
8695771Sjeff	cnt = size / sizeof(uma_junk);
8795771Sjeff
8895771Sjeff	for (p = mem; cnt > 0; cnt--, p++)
8995771Sjeff		*p = uma_junk;
9095771Sjeff}
9195771Sjeff
9295771Sjeff/*
9395771Sjeff * Fills an item with predictable garbage
9495771Sjeff *
9595771Sjeff * Complies with standard init arg/return
9695771Sjeff *
9795771Sjeff */
9895771Sjeffvoid
9995771Sjefftrash_init(void *mem, int size)
10095771Sjeff{
10195771Sjeff	trash_dtor(mem, size, NULL);
10295771Sjeff}
10395771Sjeff
10495771Sjeff/*
10595771Sjeff * Checks an item to make sure it hasn't been overwritten since it was freed.
10695771Sjeff *
10795771Sjeff * Complies with standard fini arg/return
10895771Sjeff *
10995771Sjeff */
11095771Sjeffvoid
11195771Sjefftrash_fini(void *mem, int size)
11295771Sjeff{
11395771Sjeff	trash_ctor(mem, size, NULL);
11495771Sjeff}
11595899Sjeff
11695931Sjeff/*
11795931Sjeff * Checks an item to make sure it hasn't been overwritten since freed.
11895931Sjeff *
11995931Sjeff * Complies with standard ctor arg/return
12095931Sjeff *
12195931Sjeff */
12295931Sjeffvoid
12395931Sjeffmtrash_ctor(void *mem, int size, void *arg)
12495931Sjeff{
12595931Sjeff	struct malloc_type **ksp;
12695931Sjeff	u_int32_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) {
13695931Sjeff			printf("Memory modified after free %p(%d)\n",
13795931Sjeff			    mem, size);
13895931Sjeff			panic("Most recently used by %s\n", (*ksp == NULL)?
13995931Sjeff			    "none" : (*ksp)->ks_shortdesc);
14095931Sjeff		}
14195931Sjeff}
14295931Sjeff
14395931Sjeff/*
14495931Sjeff * Fills an item with predictable garbage
14595931Sjeff *
14695931Sjeff * Complies with standard dtor arg/return
14795931Sjeff *
14895931Sjeff */
14995931Sjeffvoid
15095931Sjeffmtrash_dtor(void *mem, int size, void *arg)
15195931Sjeff{
15295931Sjeff	int cnt;
15395931Sjeff	u_int32_t *p;
15495931Sjeff
15595931Sjeff	size -= sizeof(struct malloc_type *);
15695931Sjeff	cnt = size / sizeof(uma_junk);
15795931Sjeff
15895931Sjeff	for (p = mem; cnt > 0; cnt--, p++)
15995931Sjeff		*p = uma_junk;
16095931Sjeff}
16195931Sjeff
16295931Sjeff/*
16395931Sjeff * Fills an item with predictable garbage
16495931Sjeff *
16595931Sjeff * Complies with standard init arg/return
16695931Sjeff *
16795931Sjeff */
16895931Sjeffvoid
16995931Sjeffmtrash_init(void *mem, int size)
17095931Sjeff{
17195931Sjeff	struct malloc_type **ksp;
17295931Sjeff
17395931Sjeff	mtrash_dtor(mem, size, NULL);
17495931Sjeff
17595931Sjeff	ksp = (struct malloc_type **)mem;
17695931Sjeff	ksp += (size / sizeof(struct malloc_type *)) - 1;
17795931Sjeff	*ksp = NULL;
17895931Sjeff}
17995931Sjeff
18095931Sjeff/*
18195931Sjeff * Checks an item to make sure it hasn't been overwritten since it was freed.
18295931Sjeff *
18395931Sjeff * Complies with standard fini arg/return
18495931Sjeff *
18595931Sjeff */
18695931Sjeffvoid
18795931Sjeffmtrash_fini(void *mem, int size)
18895931Sjeff{
18995931Sjeff	mtrash_ctor(mem, size, NULL);
19095931Sjeff}
19195931Sjeff
19295899Sjeffstatic uma_slab_t
19395899Sjeffuma_dbg_getslab(uma_zone_t zone, void *item)
19495899Sjeff{
19595899Sjeff	uma_slab_t slab;
19695899Sjeff	u_int8_t *mem;
19795899Sjeff
19895899Sjeff	mem = (u_int8_t *)((unsigned long)item & (~UMA_SLAB_MASK));
19995899Sjeff	if (zone->uz_flags & UMA_ZFLAG_MALLOC) {
200103531Sjeff		slab = vtoslab((vm_offset_t)mem);
201103531Sjeff	} else if (zone->uz_flags & UMA_ZFLAG_HASH) {
20295899Sjeff		ZONE_LOCK(zone);
20395899Sjeff		slab = hash_sfind(&zone->uz_hash, mem);
20495899Sjeff		ZONE_UNLOCK(zone);
20595899Sjeff	} else {
20695899Sjeff		mem += zone->uz_pgoff;
20795899Sjeff		slab = (uma_slab_t)mem;
20895899Sjeff	}
20995899Sjeff
21095899Sjeff	return (slab);
21195899Sjeff}
21295899Sjeff
21395899Sjeff/*
21495899Sjeff * Set up the slab's freei data such that uma_dbg_free can function.
21595899Sjeff *
21695899Sjeff */
21795899Sjeff
21895899Sjeffvoid
21995899Sjeffuma_dbg_alloc(uma_zone_t zone, uma_slab_t slab, void *item)
22095899Sjeff{
22195899Sjeff	int freei;
22295899Sjeff
22395899Sjeff	if (slab == NULL) {
22495899Sjeff		slab = uma_dbg_getslab(zone, item);
22595899Sjeff		if (slab == NULL)
22695899Sjeff			panic("uma: item %p did not belong to zone %s\n",
22795899Sjeff			    item, zone->uz_name);
22895899Sjeff	}
22995899Sjeff
23095899Sjeff	freei = ((unsigned long)item - (unsigned long)slab->us_data)
23195899Sjeff	    / zone->uz_rsize;
23295899Sjeff
23395899Sjeff	slab->us_freelist[freei] = 255;
23495899Sjeff
23595899Sjeff	return;
23695899Sjeff}
23795899Sjeff
23895899Sjeff/*
23995899Sjeff * Verifies freed addresses.  Checks for alignment, valid slab membership
24095899Sjeff * and duplicate frees.
24195899Sjeff *
24295899Sjeff */
24395899Sjeff
24495899Sjeffvoid
24595899Sjeffuma_dbg_free(uma_zone_t zone, uma_slab_t slab, void *item)
24695899Sjeff{
24795899Sjeff	int freei;
24895899Sjeff
24995899Sjeff	if (slab == NULL) {
25095899Sjeff		slab = uma_dbg_getslab(zone, item);
25195899Sjeff		if (slab == NULL)
25295899Sjeff			panic("uma: Freed item %p did not belong to zone %s\n",
25395899Sjeff			    item, zone->uz_name);
25495899Sjeff	}
25595899Sjeff
25695899Sjeff	freei = ((unsigned long)item - (unsigned long)slab->us_data)
25795899Sjeff	    / zone->uz_rsize;
25895899Sjeff
25995899Sjeff	if (freei >= zone->uz_ipers)
26097453Speter		panic("zone: %s(%p) slab %p freelist %d out of range 0-%d\n",
26195899Sjeff		    zone->uz_name, zone, slab, freei, zone->uz_ipers-1);
26295899Sjeff
26395899Sjeff	if (((freei * zone->uz_rsize) + slab->us_data) != item) {
26495899Sjeff		printf("zone: %s(%p) slab %p freed address %p unaligned.\n",
26595899Sjeff		    zone->uz_name, zone, slab, item);
26695899Sjeff		panic("should be %p\n",
26795899Sjeff		    (freei * zone->uz_rsize) + slab->us_data);
26895899Sjeff	}
26995899Sjeff
27095899Sjeff	if (slab->us_freelist[freei] != 255) {
27195899Sjeff		printf("Slab at %p, freei %d = %d.\n",
27295899Sjeff		    slab, freei, slab->us_freelist[freei]);
27395899Sjeff		panic("Duplicate free of item %p from zone %p(%s)\n",
27495899Sjeff		    item, zone, zone->uz_name);
27595899Sjeff	}
27695899Sjeff
27795899Sjeff	/*
27895899Sjeff	 * When this is actually linked into the slab this will change.
27995899Sjeff	 * Until then the count of valid slabs will make sure we don't
28095899Sjeff	 * accidentally follow this and assume it's a valid index.
28195899Sjeff	 */
28295899Sjeff	slab->us_freelist[freei] = 0;
28395899Sjeff}
284