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