17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate  * CDDL HEADER START
37c478bd9Sstevel@tonic-gate  *
47c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5789d94c2Sjwadams  * Common Development and Distribution License (the "License").
6789d94c2Sjwadams  * You may not use this file except in compliance with the License.
77c478bd9Sstevel@tonic-gate  *
87c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
107c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
117c478bd9Sstevel@tonic-gate  * and limitations under the License.
127c478bd9Sstevel@tonic-gate  *
137c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
147c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
167c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
177c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
187c478bd9Sstevel@tonic-gate  *
197c478bd9Sstevel@tonic-gate  * CDDL HEADER END
207c478bd9Sstevel@tonic-gate  */
217c478bd9Sstevel@tonic-gate /*
220c3b83b1SJonathan Adams  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
237c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
247c478bd9Sstevel@tonic-gate  */
257c478bd9Sstevel@tonic-gate 
26d7dba7e5SBryan Cantrill /*
273b442230SJordan Paige Hendricks  * Copyright 2019 Joyent, Inc.
28831abf2cSDan Kimmel  * Copyright (c) 2013, 2015 by Delphix. All rights reserved.
29d7dba7e5SBryan Cantrill  */
30d7dba7e5SBryan Cantrill 
317c478bd9Sstevel@tonic-gate #include "umem.h"
327c478bd9Sstevel@tonic-gate 
337c478bd9Sstevel@tonic-gate #include <sys/vmem_impl_user.h>
347c478bd9Sstevel@tonic-gate #include <umem_impl.h>
357c478bd9Sstevel@tonic-gate 
367c478bd9Sstevel@tonic-gate #include <alloca.h>
37789d94c2Sjwadams #include <limits.h>
384a1c2431SJonathan Adams #include <mdb/mdb_whatis.h>
394f364e7cSRobert Mustacchi #include <thr_uberdata.h>
407c478bd9Sstevel@tonic-gate 
417c478bd9Sstevel@tonic-gate #include "misc.h"
42789d94c2Sjwadams #include "leaky.h"
43087e1372Stomee #include "dist.h"
447c478bd9Sstevel@tonic-gate 
457c478bd9Sstevel@tonic-gate #include "umem_pagesize.h"
467c478bd9Sstevel@tonic-gate 
477c478bd9Sstevel@tonic-gate #define	UM_ALLOCATED		0x1
487c478bd9Sstevel@tonic-gate #define	UM_FREE			0x2
497c478bd9Sstevel@tonic-gate #define	UM_BUFCTL		0x4
507c478bd9Sstevel@tonic-gate #define	UM_HASH			0x8
517c478bd9Sstevel@tonic-gate 
52789d94c2Sjwadams int umem_ready;
537c478bd9Sstevel@tonic-gate 
54789d94c2Sjwadams static int umem_stack_depth_warned;
55789d94c2Sjwadams static uint32_t umem_max_ncpus;
567c478bd9Sstevel@tonic-gate uint32_t umem_stack_depth;
57789d94c2Sjwadams 
587c478bd9Sstevel@tonic-gate size_t umem_pagesize;
597c478bd9Sstevel@tonic-gate 
607c478bd9Sstevel@tonic-gate #define	UMEM_READVAR(var)				\
617c478bd9Sstevel@tonic-gate 	(umem_readvar(&(var), #var) == -1 &&		\
62789d94c2Sjwadams 	    (mdb_warn("failed to read "#var), 1))
637c478bd9Sstevel@tonic-gate 
647c478bd9Sstevel@tonic-gate int
umem_update_variables(void)65789d94c2Sjwadams umem_update_variables(void)
667c478bd9Sstevel@tonic-gate {
677c478bd9Sstevel@tonic-gate 	size_t pagesize;
687c478bd9Sstevel@tonic-gate 
697c478bd9Sstevel@tonic-gate 	/*
70789d94c2Sjwadams 	 * Figure out which type of umem is being used; if it's not there
71789d94c2Sjwadams 	 * yet, succeed quietly.
727c478bd9Sstevel@tonic-gate 	 */
73789d94c2Sjwadams 	if (umem_set_standalone() == -1) {
74789d94c2Sjwadams 		umem_ready = 0;
75789d94c2Sjwadams 		return (0);		/* umem not there yet */
76789d94c2Sjwadams 	}
777c478bd9Sstevel@tonic-gate 
78789d94c2Sjwadams 	/*
79789d94c2Sjwadams 	 * Solaris 9 used a different name for umem_max_ncpus.  It's
80789d94c2Sjwadams 	 * cheap backwards compatibility to check for both names.
81789d94c2Sjwadams 	 */
82789d94c2Sjwadams 	if (umem_readvar(&umem_max_ncpus, "umem_max_ncpus") == -1 &&
83789d94c2Sjwadams 	    umem_readvar(&umem_max_ncpus, "max_ncpus") == -1) {
84789d94c2Sjwadams 		mdb_warn("unable to read umem_max_ncpus or max_ncpus");
85789d94c2Sjwadams 		return (-1);
86789d94c2Sjwadams 	}
87789d94c2Sjwadams 	if (UMEM_READVAR(umem_ready))
887c478bd9Sstevel@tonic-gate 		return (-1);
897c478bd9Sstevel@tonic-gate 	if (UMEM_READVAR(umem_stack_depth))
907c478bd9Sstevel@tonic-gate 		return (-1);
917c478bd9Sstevel@tonic-gate 	if (UMEM_READVAR(pagesize))
927c478bd9Sstevel@tonic-gate 		return (-1);
937c478bd9Sstevel@tonic-gate 
947c478bd9Sstevel@tonic-gate 	if (umem_stack_depth > UMEM_MAX_STACK_DEPTH) {
95789d94c2Sjwadams 		if (umem_stack_depth_warned == 0) {
96789d94c2Sjwadams 			mdb_warn("umem_stack_depth corrupted (%d > %d)\n",
97789d94c2Sjwadams 			    umem_stack_depth, UMEM_MAX_STACK_DEPTH);
98789d94c2Sjwadams 			umem_stack_depth_warned = 1;
99789d94c2Sjwadams 		}
1007c478bd9Sstevel@tonic-gate 		umem_stack_depth = 0;
1017c478bd9Sstevel@tonic-gate 	}
102789d94c2Sjwadams 
103789d94c2Sjwadams 	umem_pagesize = pagesize;
104789d94c2Sjwadams 
1057c478bd9Sstevel@tonic-gate 	return (0);
1067c478bd9Sstevel@tonic-gate }
1077c478bd9Sstevel@tonic-gate 
1084f364e7cSRobert Mustacchi static int
umem_ptc_walk_init(mdb_walk_state_t * wsp)1094f364e7cSRobert Mustacchi umem_ptc_walk_init(mdb_walk_state_t *wsp)
1104f364e7cSRobert Mustacchi {
111892ad162SToomas Soome 	if (wsp->walk_addr == 0) {
1124f364e7cSRobert Mustacchi 		if (mdb_layered_walk("ulwp", wsp) == -1) {
1134f364e7cSRobert Mustacchi 			mdb_warn("couldn't walk 'ulwp'");
1144f364e7cSRobert Mustacchi 			return (WALK_ERR);
1154f364e7cSRobert Mustacchi 		}
1164f364e7cSRobert Mustacchi 	}
1174f364e7cSRobert Mustacchi 
1184f364e7cSRobert Mustacchi 	return (WALK_NEXT);
1194f364e7cSRobert Mustacchi }
1204f364e7cSRobert Mustacchi 
1214f364e7cSRobert Mustacchi static int
umem_ptc_walk_step(mdb_walk_state_t * wsp)1224f364e7cSRobert Mustacchi umem_ptc_walk_step(mdb_walk_state_t *wsp)
1234f364e7cSRobert Mustacchi {
1244f364e7cSRobert Mustacchi 	uintptr_t this;
1254f364e7cSRobert Mustacchi 	int rval;
1264f364e7cSRobert Mustacchi 
1274f364e7cSRobert Mustacchi 	if (wsp->walk_layer != NULL) {
1284f364e7cSRobert Mustacchi 		this = (uintptr_t)((ulwp_t *)wsp->walk_layer)->ul_self +
1294f364e7cSRobert Mustacchi 		    (uintptr_t)wsp->walk_arg;
1304f364e7cSRobert Mustacchi 	} else {
1314f364e7cSRobert Mustacchi 		this = wsp->walk_addr + (uintptr_t)wsp->walk_arg;
1324f364e7cSRobert Mustacchi 	}
1334f364e7cSRobert Mustacchi 
1344f364e7cSRobert Mustacchi 	for (;;) {
1354f364e7cSRobert Mustacchi 		if (mdb_vread(&this, sizeof (void *), this) == -1) {
1364f364e7cSRobert Mustacchi 			mdb_warn("couldn't read ptc buffer at %p", this);
1374f364e7cSRobert Mustacchi 			return (WALK_ERR);
1384f364e7cSRobert Mustacchi 		}
1394f364e7cSRobert Mustacchi 
140892ad162SToomas Soome 		if (this == 0)
1414f364e7cSRobert Mustacchi 			break;
1424f364e7cSRobert Mustacchi 
1434f364e7cSRobert Mustacchi 		rval = wsp->walk_callback(this, &this, wsp->walk_cbdata);
1444f364e7cSRobert Mustacchi 
1454f364e7cSRobert Mustacchi 		if (rval != WALK_NEXT)
1464f364e7cSRobert Mustacchi 			return (rval);
1474f364e7cSRobert Mustacchi 	}
1484f364e7cSRobert Mustacchi 
1494f364e7cSRobert Mustacchi 	return (wsp->walk_layer != NULL ? WALK_NEXT : WALK_DONE);
1504f364e7cSRobert Mustacchi }
1514f364e7cSRobert Mustacchi 
1527c478bd9Sstevel@tonic-gate /*ARGSUSED*/
153789d94c2Sjwadams static int
umem_init_walkers(uintptr_t addr,const umem_cache_t * c,int * sizes)1544f364e7cSRobert Mustacchi umem_init_walkers(uintptr_t addr, const umem_cache_t *c, int *sizes)
1557c478bd9Sstevel@tonic-gate {
1567c478bd9Sstevel@tonic-gate 	mdb_walker_t w;
1577c478bd9Sstevel@tonic-gate 	char descr[64];
1584f364e7cSRobert Mustacchi 	char name[64];
1594f364e7cSRobert Mustacchi 	int i;
1607c478bd9Sstevel@tonic-gate 
1617c478bd9Sstevel@tonic-gate 	(void) mdb_snprintf(descr, sizeof (descr),
1627c478bd9Sstevel@tonic-gate 	    "walk the %s cache", c->cache_name);
1637c478bd9Sstevel@tonic-gate 
1647c478bd9Sstevel@tonic-gate 	w.walk_name = c->cache_name;
1657c478bd9Sstevel@tonic-gate 	w.walk_descr = descr;
1667c478bd9Sstevel@tonic-gate 	w.walk_init = umem_walk_init;
1677c478bd9Sstevel@tonic-gate 	w.walk_step = umem_walk_step;
1687c478bd9Sstevel@tonic-gate 	w.walk_fini = umem_walk_fini;
1697c478bd9Sstevel@tonic-gate 	w.walk_init_arg = (void *)addr;
1707c478bd9Sstevel@tonic-gate 
1717c478bd9Sstevel@tonic-gate 	if (mdb_add_walker(&w) == -1)
1727c478bd9Sstevel@tonic-gate 		mdb_warn("failed to add %s walker", c->cache_name);
1737c478bd9Sstevel@tonic-gate 
1744f364e7cSRobert Mustacchi 	if (!(c->cache_flags & UMF_PTC))
1754f364e7cSRobert Mustacchi 		return (WALK_NEXT);
1764f364e7cSRobert Mustacchi 
1774f364e7cSRobert Mustacchi 	/*
1784f364e7cSRobert Mustacchi 	 * For the per-thread cache walker, the address is the offset in the
1794f364e7cSRobert Mustacchi 	 * tm_roots[] array of the ulwp_t.
1804f364e7cSRobert Mustacchi 	 */
1814f364e7cSRobert Mustacchi 	for (i = 0; sizes[i] != 0; i++) {
1824f364e7cSRobert Mustacchi 		if (sizes[i] == c->cache_bufsize)
1834f364e7cSRobert Mustacchi 			break;
1844f364e7cSRobert Mustacchi 	}
1854f364e7cSRobert Mustacchi 
1864f364e7cSRobert Mustacchi 	if (sizes[i] == 0) {
1874f364e7cSRobert Mustacchi 		mdb_warn("cache %s is cached per-thread, but could not find "
1884f364e7cSRobert Mustacchi 		    "size in umem_alloc_sizes\n", c->cache_name);
1894f364e7cSRobert Mustacchi 		return (WALK_NEXT);
1904f364e7cSRobert Mustacchi 	}
1914f364e7cSRobert Mustacchi 
1924f364e7cSRobert Mustacchi 	if (i >= NTMEMBASE) {
1934f364e7cSRobert Mustacchi 		mdb_warn("index for %s (%d) exceeds root slots (%d)\n",
1944f364e7cSRobert Mustacchi 		    c->cache_name, i, NTMEMBASE);
1954f364e7cSRobert Mustacchi 		return (WALK_NEXT);
1964f364e7cSRobert Mustacchi 	}
1974f364e7cSRobert Mustacchi 
1984f364e7cSRobert Mustacchi 	(void) mdb_snprintf(name, sizeof (name),
1994f364e7cSRobert Mustacchi 	    "umem_ptc_%d", c->cache_bufsize);
2004f364e7cSRobert Mustacchi 	(void) mdb_snprintf(descr, sizeof (descr),
2014f364e7cSRobert Mustacchi 	    "walk the per-thread cache for %s", c->cache_name);
2024f364e7cSRobert Mustacchi 
2034f364e7cSRobert Mustacchi 	w.walk_name = name;
2044f364e7cSRobert Mustacchi 	w.walk_descr = descr;
2054f364e7cSRobert Mustacchi 	w.walk_init = umem_ptc_walk_init;
2064f364e7cSRobert Mustacchi 	w.walk_step = umem_ptc_walk_step;
2074f364e7cSRobert Mustacchi 	w.walk_fini = NULL;
2084f364e7cSRobert Mustacchi 	w.walk_init_arg = (void *)offsetof(ulwp_t, ul_tmem.tm_roots[i]);
2094f364e7cSRobert Mustacchi 
2104f364e7cSRobert Mustacchi 	if (mdb_add_walker(&w) == -1)
2114f364e7cSRobert Mustacchi 		mdb_warn("failed to add %s walker", w.walk_name);
2124f364e7cSRobert Mustacchi 
2137c478bd9Sstevel@tonic-gate 	return (WALK_NEXT);
2147c478bd9Sstevel@tonic-gate }
2157c478bd9Sstevel@tonic-gate 
216789d94c2Sjwadams /*ARGSUSED*/
217789d94c2Sjwadams static void
umem_statechange_cb(void * arg)218789d94c2Sjwadams umem_statechange_cb(void *arg)
219789d94c2Sjwadams {
220789d94c2Sjwadams 	static int been_ready = 0;
2214f364e7cSRobert Mustacchi 	GElf_Sym sym;
2224f364e7cSRobert Mustacchi 	int *sizes;
223789d94c2Sjwadams 
224789d94c2Sjwadams #ifndef _KMDB
225789d94c2Sjwadams 	leaky_cleanup(1);	/* state changes invalidate leaky state */
226789d94c2Sjwadams #endif
227789d94c2Sjwadams 
228789d94c2Sjwadams 	if (umem_update_variables() == -1)
229789d94c2Sjwadams 		return;
230789d94c2Sjwadams 
231789d94c2Sjwadams 	if (been_ready)
232789d94c2Sjwadams 		return;
233789d94c2Sjwadams 
234789d94c2Sjwadams 	if (umem_ready != UMEM_READY)
235789d94c2Sjwadams 		return;
236789d94c2Sjwadams 
237789d94c2Sjwadams 	been_ready = 1;
2384f364e7cSRobert Mustacchi 
2394f364e7cSRobert Mustacchi 	/*
2404f364e7cSRobert Mustacchi 	 * In order to determine the tm_roots offset of any cache that is
2414f364e7cSRobert Mustacchi 	 * cached per-thread, we need to have the umem_alloc_sizes array.
2424f364e7cSRobert Mustacchi 	 * Read this, assuring that it is zero-terminated.
2434f364e7cSRobert Mustacchi 	 */
2444f364e7cSRobert Mustacchi 	if (umem_lookup_by_name("umem_alloc_sizes", &sym) == -1) {
2454f364e7cSRobert Mustacchi 		mdb_warn("unable to lookup 'umem_alloc_sizes'");
2464f364e7cSRobert Mustacchi 		return;
2474f364e7cSRobert Mustacchi 	}
2484f364e7cSRobert Mustacchi 
2494f364e7cSRobert Mustacchi 	sizes = mdb_zalloc(sym.st_size + sizeof (int), UM_SLEEP | UM_GC);
2504f364e7cSRobert Mustacchi 
2514f364e7cSRobert Mustacchi 	if (mdb_vread(sizes, sym.st_size, (uintptr_t)sym.st_value) == -1) {
2524f364e7cSRobert Mustacchi 		mdb_warn("couldn't read 'umem_alloc_sizes'");
2534f364e7cSRobert Mustacchi 		return;
2544f364e7cSRobert Mustacchi 	}
2554f364e7cSRobert Mustacchi 
2564f364e7cSRobert Mustacchi 	(void) mdb_walk("umem_cache", (mdb_walk_cb_t)umem_init_walkers, sizes);
257789d94c2Sjwadams }
258789d94c2Sjwadams 
2597c478bd9Sstevel@tonic-gate int
umem_abort_messages(void)2607c478bd9Sstevel@tonic-gate umem_abort_messages(void)
2617c478bd9Sstevel@tonic-gate {
2627c478bd9Sstevel@tonic-gate 	char *umem_error_buffer;
2637c478bd9Sstevel@tonic-gate 	uint_t umem_error_begin;
2647c478bd9Sstevel@tonic-gate 	GElf_Sym sym;
2657c478bd9Sstevel@tonic-gate 	size_t bufsize;
2667c478bd9Sstevel@tonic-gate 
2677c478bd9Sstevel@tonic-gate 	if (UMEM_READVAR(umem_error_begin))
2687c478bd9Sstevel@tonic-gate 		return (DCMD_ERR);
2697c478bd9Sstevel@tonic-gate 
2707c478bd9Sstevel@tonic-gate 	if (umem_lookup_by_name("umem_error_buffer", &sym) == -1) {
2717c478bd9Sstevel@tonic-gate 		mdb_warn("unable to look up umem_error_buffer");
2727c478bd9Sstevel@tonic-gate 		return (DCMD_ERR);
2737c478bd9Sstevel@tonic-gate 	}
2747c478bd9Sstevel@tonic-gate 
2757c478bd9Sstevel@tonic-gate 	bufsize = (size_t)sym.st_size;
2767c478bd9Sstevel@tonic-gate 
2777c478bd9Sstevel@tonic-gate 	umem_error_buffer = mdb_alloc(bufsize+1, UM_SLEEP | UM_GC);
2787c478bd9Sstevel@tonic-gate 
2797c478bd9Sstevel@tonic-gate 	if (mdb_vread(umem_error_buffer, bufsize, (uintptr_t)sym.st_value)
2807c478bd9Sstevel@tonic-gate 	    != bufsize) {
2817c478bd9Sstevel@tonic-gate 		mdb_warn("unable to read umem_error_buffer");
2827c478bd9Sstevel@tonic-gate 		return (DCMD_ERR);
2837c478bd9Sstevel@tonic-gate 	}
2847c478bd9Sstevel@tonic-gate 	/* put a zero after the end of the buffer to simplify printing */
2857c478bd9Sstevel@tonic-gate 	umem_error_buffer[bufsize] = 0;
2867c478bd9Sstevel@tonic-gate 
2877c478bd9Sstevel@tonic-gate 	if ((umem_error_begin % bufsize) == 0)
2887c478bd9Sstevel@tonic-gate 		mdb_printf("%s\n", umem_error_buffer);
2897c478bd9Sstevel@tonic-gate 	else {
2907c478bd9Sstevel@tonic-gate 		umem_error_buffer[(umem_error_begin % bufsize) - 1] = 0;
2917c478bd9Sstevel@tonic-gate 		mdb_printf("%s%s\n",
2927c478bd9Sstevel@tonic-gate 		    &umem_error_buffer[umem_error_begin % bufsize],
2937c478bd9Sstevel@tonic-gate 		    umem_error_buffer);
2947c478bd9Sstevel@tonic-gate 	}
2957c478bd9Sstevel@tonic-gate 
2967c478bd9Sstevel@tonic-gate 	return (DCMD_OK);
2977c478bd9Sstevel@tonic-gate }
2987c478bd9Sstevel@tonic-gate 
2997c478bd9Sstevel@tonic-gate static void
umem_log_status(const char * name,umem_log_header_t * val)3007c478bd9Sstevel@tonic-gate umem_log_status(const char *name, umem_log_header_t *val)
3017c478bd9Sstevel@tonic-gate {
3027c478bd9Sstevel@tonic-gate 	umem_log_header_t my_lh;
3037c478bd9Sstevel@tonic-gate 	uintptr_t pos = (uintptr_t)val;
3047c478bd9Sstevel@tonic-gate 	size_t size;
3057c478bd9Sstevel@tonic-gate 
306892ad162SToomas Soome 	if (pos == 0)
3077c478bd9Sstevel@tonic-gate 		return;
3087c478bd9Sstevel@tonic-gate 
3097c478bd9Sstevel@tonic-gate 	if (mdb_vread(&my_lh, sizeof (umem_log_header_t), pos) == -1) {
3107c478bd9Sstevel@tonic-gate 		mdb_warn("\nunable to read umem_%s_log pointer %p",
3117c478bd9Sstevel@tonic-gate 		    name, pos);
3127c478bd9Sstevel@tonic-gate 		return;
3137c478bd9Sstevel@tonic-gate 	}
3147c478bd9Sstevel@tonic-gate 
3157c478bd9Sstevel@tonic-gate 	size = my_lh.lh_chunksize * my_lh.lh_nchunks;
3167c478bd9Sstevel@tonic-gate 
3177c478bd9Sstevel@tonic-gate 	if (size % (1024 * 1024) == 0)
3187c478bd9Sstevel@tonic-gate 		mdb_printf("%s=%dm ", name, size / (1024 * 1024));
3197c478bd9Sstevel@tonic-gate 	else if (size % 1024 == 0)
3207c478bd9Sstevel@tonic-gate 		mdb_printf("%s=%dk ", name, size / 1024);
3217c478bd9Sstevel@tonic-gate 	else
3227c478bd9Sstevel@tonic-gate 		mdb_printf("%s=%d ", name, size);
3237c478bd9Sstevel@tonic-gate }
3247c478bd9Sstevel@tonic-gate 
3257c478bd9Sstevel@tonic-gate typedef struct umem_debug_flags {
3267c478bd9Sstevel@tonic-gate 	const char	*udf_name;
3277c478bd9Sstevel@tonic-gate 	uint_t		udf_flags;
3287c478bd9Sstevel@tonic-gate 	uint_t		udf_clear;	/* if 0, uses udf_flags */
3297c478bd9Sstevel@tonic-gate } umem_debug_flags_t;
3307c478bd9Sstevel@tonic-gate 
3317c478bd9Sstevel@tonic-gate umem_debug_flags_t umem_status_flags[] = {
3327c478bd9Sstevel@tonic-gate 	{ "random",	UMF_RANDOMIZE,	UMF_RANDOM },
3337c478bd9Sstevel@tonic-gate 	{ "default",	UMF_AUDIT | UMF_DEADBEEF | UMF_REDZONE | UMF_CONTENTS },
3347c478bd9Sstevel@tonic-gate 	{ "audit",	UMF_AUDIT },
3357c478bd9Sstevel@tonic-gate 	{ "guards",	UMF_DEADBEEF | UMF_REDZONE },
3367c478bd9Sstevel@tonic-gate 	{ "nosignal",	UMF_CHECKSIGNAL },
3377c478bd9Sstevel@tonic-gate 	{ "firewall",	UMF_FIREWALL },
3387c478bd9Sstevel@tonic-gate 	{ "lite",	UMF_LITE },
339831abf2cSDan Kimmel 	{ "checknull",	UMF_CHECKNULL },
3407c478bd9Sstevel@tonic-gate 	{ NULL }
3417c478bd9Sstevel@tonic-gate };
3427c478bd9Sstevel@tonic-gate 
3437c478bd9Sstevel@tonic-gate /*ARGSUSED*/
3447c478bd9Sstevel@tonic-gate int
umem_status(uintptr_t addr,uint_t flags,int ac,const mdb_arg_t * argv)3457c478bd9Sstevel@tonic-gate umem_status(uintptr_t addr, uint_t flags, int ac, const mdb_arg_t *argv)
3467c478bd9Sstevel@tonic-gate {
3477c478bd9Sstevel@tonic-gate 	int umem_logging;
3487c478bd9Sstevel@tonic-gate 
3497c478bd9Sstevel@tonic-gate 	umem_log_header_t *umem_transaction_log;
3507c478bd9Sstevel@tonic-gate 	umem_log_header_t *umem_content_log;
3517c478bd9Sstevel@tonic-gate 	umem_log_header_t *umem_failure_log;
3527c478bd9Sstevel@tonic-gate 	umem_log_header_t *umem_slab_log;
3537c478bd9Sstevel@tonic-gate 
3547c478bd9Sstevel@tonic-gate 	mdb_printf("Status:\t\t%s\n",
3557c478bd9Sstevel@tonic-gate 	    umem_ready == UMEM_READY_INIT_FAILED ? "initialization failed" :
3567c478bd9Sstevel@tonic-gate 	    umem_ready == UMEM_READY_STARTUP ? "uninitialized" :
3577c478bd9Sstevel@tonic-gate 	    umem_ready == UMEM_READY_INITING ? "initialization in process" :
3587c478bd9Sstevel@tonic-gate 	    umem_ready == UMEM_READY ? "ready and active" :
359789d94c2Sjwadams 	    umem_ready == 0 ? "not loaded into address space" :
3607c478bd9Sstevel@tonic-gate 	    "unknown (umem_ready invalid)");
3617c478bd9Sstevel@tonic-gate 
362789d94c2Sjwadams 	if (umem_ready == 0)
363789d94c2Sjwadams 		return (DCMD_OK);
364789d94c2Sjwadams 
3657c478bd9Sstevel@tonic-gate 	mdb_printf("Concurrency:\t%d\n", umem_max_ncpus);
3667c478bd9Sstevel@tonic-gate 
3677c478bd9Sstevel@tonic-gate 	if (UMEM_READVAR(umem_logging))
3687c478bd9Sstevel@tonic-gate 		goto err;
3697c478bd9Sstevel@tonic-gate 	if (UMEM_READVAR(umem_transaction_log))
3707c478bd9Sstevel@tonic-gate 		goto err;
3717c478bd9Sstevel@tonic-gate 	if (UMEM_READVAR(umem_content_log))
3727c478bd9Sstevel@tonic-gate 		goto err;
3737c478bd9Sstevel@tonic-gate 	if (UMEM_READVAR(umem_failure_log))
3747c478bd9Sstevel@tonic-gate 		goto err;
3757c478bd9Sstevel@tonic-gate 	if (UMEM_READVAR(umem_slab_log))
3767c478bd9Sstevel@tonic-gate 		goto err;
3777c478bd9Sstevel@tonic-gate 
3787c478bd9Sstevel@tonic-gate 	mdb_printf("Logs:\t\t");
3797c478bd9Sstevel@tonic-gate 	umem_log_status("transaction", umem_transaction_log);
3807c478bd9Sstevel@tonic-gate 	umem_log_status("content", umem_content_log);
3817c478bd9Sstevel@tonic-gate 	umem_log_status("fail", umem_failure_log);
3827c478bd9Sstevel@tonic-gate 	umem_log_status("slab", umem_slab_log);
3837c478bd9Sstevel@tonic-gate 	if (!umem_logging)
3847c478bd9Sstevel@tonic-gate 		mdb_printf("(inactive)");
3857c478bd9Sstevel@tonic-gate 	mdb_printf("\n");
3867c478bd9Sstevel@tonic-gate 
3877c478bd9Sstevel@tonic-gate 	mdb_printf("Message buffer:\n");
3887c478bd9Sstevel@tonic-gate 	return (umem_abort_messages());
3897c478bd9Sstevel@tonic-gate 
3907c478bd9Sstevel@tonic-gate err:
3917c478bd9Sstevel@tonic-gate 	mdb_printf("Message buffer:\n");
3927c478bd9Sstevel@tonic-gate 	(void) umem_abort_messages();
3937c478bd9Sstevel@tonic-gate 	return (DCMD_ERR);
3947c478bd9Sstevel@tonic-gate }
3957c478bd9Sstevel@tonic-gate 
3967c478bd9Sstevel@tonic-gate typedef struct {
3977c478bd9Sstevel@tonic-gate 	uintptr_t ucw_first;
3987c478bd9Sstevel@tonic-gate 	uintptr_t ucw_current;
3997c478bd9Sstevel@tonic-gate } umem_cache_walk_t;
4007c478bd9Sstevel@tonic-gate 
4017c478bd9Sstevel@tonic-gate int
umem_cache_walk_init(mdb_walk_state_t * wsp)4027c478bd9Sstevel@tonic-gate umem_cache_walk_init(mdb_walk_state_t *wsp)
4037c478bd9Sstevel@tonic-gate {
4047c478bd9Sstevel@tonic-gate 	umem_cache_walk_t *ucw;
4057c478bd9Sstevel@tonic-gate 	umem_cache_t c;
4067c478bd9Sstevel@tonic-gate 	uintptr_t cp;
4077c478bd9Sstevel@tonic-gate 	GElf_Sym sym;
4087c478bd9Sstevel@tonic-gate 
4097c478bd9Sstevel@tonic-gate 	if (umem_lookup_by_name("umem_null_cache", &sym) == -1) {
4107c478bd9Sstevel@tonic-gate 		mdb_warn("couldn't find umem_null_cache");
4117c478bd9Sstevel@tonic-gate 		return (WALK_ERR);
4127c478bd9Sstevel@tonic-gate 	}
4137c478bd9Sstevel@tonic-gate 
4147c478bd9Sstevel@tonic-gate 	cp = (uintptr_t)sym.st_value;
4157c478bd9Sstevel@tonic-gate 
4167c478bd9Sstevel@tonic-gate 	if (mdb_vread(&c, sizeof (umem_cache_t), cp) == -1) {
4177c478bd9Sstevel@tonic-gate 		mdb_warn("couldn't read cache at %p", cp);
4187c478bd9Sstevel@tonic-gate 		return (WALK_ERR);
4197c478bd9Sstevel@tonic-gate 	}
4207c478bd9Sstevel@tonic-gate 
4217c478bd9Sstevel@tonic-gate 	ucw = mdb_alloc(sizeof (umem_cache_walk_t), UM_SLEEP);
4227c478bd9Sstevel@tonic-gate 
4237c478bd9Sstevel@tonic-gate 	ucw->ucw_first = cp;
4247c478bd9Sstevel@tonic-gate 	ucw->ucw_current = (uintptr_t)c.cache_next;
4257c478bd9Sstevel@tonic-gate 	wsp->walk_data = ucw;
4267c478bd9Sstevel@tonic-gate 
4277c478bd9Sstevel@tonic-gate 	return (WALK_NEXT);
4287c478bd9Sstevel@tonic-gate }
4297c478bd9Sstevel@tonic-gate 
4307c478bd9Sstevel@tonic-gate int
umem_cache_walk_step(mdb_walk_state_t * wsp)4317c478bd9Sstevel@tonic-gate umem_cache_walk_step(mdb_walk_state_t *wsp)
4327c478bd9Sstevel@tonic-gate {
4337c478bd9Sstevel@tonic-gate 	umem_cache_walk_t *ucw = wsp->walk_data;
4347c478bd9Sstevel@tonic-gate 	umem_cache_t c;
4357c478bd9Sstevel@tonic-gate 	int status;
4367c478bd9Sstevel@tonic-gate 
4377c478bd9Sstevel@tonic-gate 	if (mdb_vread(&c, sizeof (umem_cache_t), ucw->ucw_current) == -1) {
4387c478bd9Sstevel@tonic-gate 		mdb_warn("couldn't read cache at %p", ucw->ucw_current);
4397c478bd9Sstevel@tonic-gate 		return (WALK_DONE);
4407c478bd9Sstevel@tonic-gate 	}
4417c478bd9Sstevel@tonic-gate 
4427c478bd9Sstevel@tonic-gate 	status = wsp->walk_callback(ucw->ucw_current, &c, wsp->walk_cbdata);
4437c478bd9Sstevel@tonic-gate 
4447c478bd9Sstevel@tonic-gate 	if ((ucw->ucw_current = (uintptr_t)c.cache_next) == ucw->ucw_first)
4457c478bd9Sstevel@tonic-gate 		return (WALK_DONE);
4467c478bd9Sstevel@tonic-gate 
4477c478bd9Sstevel@tonic-gate 	return (status);
4487c478bd9Sstevel@tonic-gate }
4497c478bd9Sstevel@tonic-gate 
4507c478bd9Sstevel@tonic-gate void
umem_cache_walk_fini(mdb_walk_state_t * wsp)4517c478bd9Sstevel@tonic-gate umem_cache_walk_fini(mdb_walk_state_t *wsp)
4527c478bd9Sstevel@tonic-gate {
4537c478bd9Sstevel@tonic-gate 	umem_cache_walk_t *ucw = wsp->walk_data;
4547c478bd9Sstevel@tonic-gate 	mdb_free(ucw, sizeof (umem_cache_walk_t));
4557c478bd9Sstevel@tonic-gate }
4567c478bd9Sstevel@tonic-gate 
4577c478bd9Sstevel@tonic-gate typedef struct {
4587c478bd9Sstevel@tonic-gate 	umem_cpu_t *ucw_cpus;
4597c478bd9Sstevel@tonic-gate 	uint32_t ucw_current;
4607c478bd9Sstevel@tonic-gate 	uint32_t ucw_max;
4617c478bd9Sstevel@tonic-gate } umem_cpu_walk_state_t;
4627c478bd9Sstevel@tonic-gate 
4637c478bd9Sstevel@tonic-gate int
umem_cpu_walk_init(mdb_walk_state_t * wsp)4647c478bd9Sstevel@tonic-gate umem_cpu_walk_init(mdb_walk_state_t *wsp)
4657c478bd9Sstevel@tonic-gate {
4667c478bd9Sstevel@tonic-gate 	umem_cpu_t *umem_cpus;
4677c478bd9Sstevel@tonic-gate 
4687c478bd9Sstevel@tonic-gate 	umem_cpu_walk_state_t *ucw;
4697c478bd9Sstevel@tonic-gate 
4707c478bd9Sstevel@tonic-gate 	if (umem_readvar(&umem_cpus, "umem_cpus") == -1) {
4717c478bd9Sstevel@tonic-gate 		mdb_warn("failed to read 'umem_cpus'");
4727c478bd9Sstevel@tonic-gate 		return (WALK_ERR);
4737c478bd9Sstevel@tonic-gate 	}
4747c478bd9Sstevel@tonic-gate 
4757c478bd9Sstevel@tonic-gate 	ucw = mdb_alloc(sizeof (*ucw), UM_SLEEP);
4767c478bd9Sstevel@tonic-gate 
4777c478bd9Sstevel@tonic-gate 	ucw->ucw_cpus = umem_cpus;
4787c478bd9Sstevel@tonic-gate 	ucw->ucw_current = 0;
4797c478bd9Sstevel@tonic-gate 	ucw->ucw_max = umem_max_ncpus;
4807c478bd9Sstevel@tonic-gate 
4817c478bd9Sstevel@tonic-gate 	wsp->walk_data = ucw;
4827c478bd9Sstevel@tonic-gate 	return (WALK_NEXT);
4837c478bd9Sstevel@tonic-gate }
4847c478bd9Sstevel@tonic-gate 
4857c478bd9Sstevel@tonic-gate int
umem_cpu_walk_step(mdb_walk_state_t * wsp)4867c478bd9Sstevel@tonic-gate umem_cpu_walk_step(mdb_walk_state_t *wsp)
4877c478bd9Sstevel@tonic-gate {
4887c478bd9Sstevel@tonic-gate 	umem_cpu_t cpu;
4897c478bd9Sstevel@tonic-gate 	umem_cpu_walk_state_t *ucw = wsp->walk_data;
4907c478bd9Sstevel@tonic-gate 
4917c478bd9Sstevel@tonic-gate 	uintptr_t caddr;
4927c478bd9Sstevel@tonic-gate 
4937c478bd9Sstevel@tonic-gate 	if (ucw->ucw_current >= ucw->ucw_max)
4947c478bd9Sstevel@tonic-gate 		return (WALK_DONE);
4957c478bd9Sstevel@tonic-gate 
4967c478bd9Sstevel@tonic-gate 	caddr = (uintptr_t)&(ucw->ucw_cpus[ucw->ucw_current]);
4977c478bd9Sstevel@tonic-gate 
4987c478bd9Sstevel@tonic-gate 	if (mdb_vread(&cpu, sizeof (umem_cpu_t), caddr) == -1) {
4997c478bd9Sstevel@tonic-gate 		mdb_warn("failed to read cpu %d", ucw->ucw_current);
5007c478bd9Sstevel@tonic-gate 		return (WALK_ERR);
5017c478bd9Sstevel@tonic-gate 	}
5027c478bd9Sstevel@tonic-gate 
5037c478bd9Sstevel@tonic-gate 	ucw->ucw_current++;
5047c478bd9Sstevel@tonic-gate 
5057c478bd9Sstevel@tonic-gate 	return (wsp->walk_callback(caddr, &cpu, wsp->walk_cbdata));
5067c478bd9Sstevel@tonic-gate }
5077c478bd9Sstevel@tonic-gate 
5087c478bd9Sstevel@tonic-gate void
umem_cpu_walk_fini(mdb_walk_state_t * wsp)5097c478bd9Sstevel@tonic-gate umem_cpu_walk_fini(mdb_walk_state_t *wsp)
5107c478bd9Sstevel@tonic-gate {
5117c478bd9Sstevel@tonic-gate 	umem_cpu_walk_state_t *ucw = wsp->walk_data;
5127c478bd9Sstevel@tonic-gate 
5137c478bd9Sstevel@tonic-gate 	mdb_free(ucw, sizeof (*ucw));
5147c478bd9Sstevel@tonic-gate }
5157c478bd9Sstevel@tonic-gate 
5167c478bd9Sstevel@tonic-gate int
umem_cpu_cache_walk_init(mdb_walk_state_t * wsp)5177c478bd9Sstevel@tonic-gate umem_cpu_cache_walk_init(mdb_walk_state_t *wsp)
5187c478bd9Sstevel@tonic-gate {
519892ad162SToomas Soome 	if (wsp->walk_addr == 0) {
5207c478bd9Sstevel@tonic-gate 		mdb_warn("umem_cpu_cache doesn't support global walks");
5217c478bd9Sstevel@tonic-gate 		return (WALK_ERR);
5227c478bd9Sstevel@tonic-gate 	}
5237c478bd9Sstevel@tonic-gate 
5247c478bd9Sstevel@tonic-gate 	if (mdb_layered_walk("umem_cpu", wsp) == -1) {
5257c478bd9Sstevel@tonic-gate 		mdb_warn("couldn't walk 'umem_cpu'");
5267c478bd9Sstevel@tonic-gate 		return (WALK_ERR);
5277c478bd9Sstevel@tonic-gate 	}
5287c478bd9Sstevel@tonic-gate 
5297c478bd9Sstevel@tonic-gate 	wsp->walk_data = (void *)wsp->walk_addr;
5307c478bd9Sstevel@tonic-gate 
5317c478bd9Sstevel@tonic-gate 	return (WALK_NEXT);
5327c478bd9Sstevel@tonic-gate }
5337c478bd9Sstevel@tonic-gate 
5347c478bd9Sstevel@tonic-gate int
umem_cpu_cache_walk_step(mdb_walk_state_t * wsp)5357c478bd9Sstevel@tonic-gate umem_cpu_cache_walk_step(mdb_walk_state_t *wsp)
5367c478bd9Sstevel@tonic-gate {
5377c478bd9Sstevel@tonic-gate 	uintptr_t caddr = (uintptr_t)wsp->walk_data;
5387c478bd9Sstevel@tonic-gate 	const umem_cpu_t *cpu = wsp->walk_layer;
5397c478bd9Sstevel@tonic-gate 	umem_cpu_cache_t cc;
5407c478bd9Sstevel@tonic-gate 
5417c478bd9Sstevel@tonic-gate 	caddr += cpu->cpu_cache_offset;
5427c478bd9Sstevel@tonic-gate 
5437c478bd9Sstevel@tonic-gate 	if (mdb_vread(&cc, sizeof (umem_cpu_cache_t), caddr) == -1) {
5447c478bd9Sstevel@tonic-gate 		mdb_warn("couldn't read umem_cpu_cache at %p", caddr);
5457c478bd9Sstevel@tonic-gate 		return (WALK_ERR);
5467c478bd9Sstevel@tonic-gate 	}
5477c478bd9Sstevel@tonic-gate 
5487c478bd9Sstevel@tonic-gate 	return (wsp->walk_callback(caddr, &cc, wsp->walk_cbdata));
5497c478bd9Sstevel@tonic-gate }
5507c478bd9Sstevel@tonic-gate 
5517c478bd9Sstevel@tonic-gate int
umem_slab_walk_init(mdb_walk_state_t * wsp)5527c478bd9Sstevel@tonic-gate umem_slab_walk_init(mdb_walk_state_t *wsp)
5537c478bd9Sstevel@tonic-gate {
5547c478bd9Sstevel@tonic-gate 	uintptr_t caddr = wsp->walk_addr;
5557c478bd9Sstevel@tonic-gate 	umem_cache_t c;
5567c478bd9Sstevel@tonic-gate 
557892ad162SToomas Soome 	if (caddr == 0) {
5587c478bd9Sstevel@tonic-gate 		mdb_warn("umem_slab doesn't support global walks\n");
5597c478bd9Sstevel@tonic-gate 		return (WALK_ERR);
5607c478bd9Sstevel@tonic-gate 	}
5617c478bd9Sstevel@tonic-gate 
5627c478bd9Sstevel@tonic-gate 	if (mdb_vread(&c, sizeof (c), caddr) == -1) {
5637c478bd9Sstevel@tonic-gate 		mdb_warn("couldn't read umem_cache at %p", caddr);
5647c478bd9Sstevel@tonic-gate 		return (WALK_ERR);
5657c478bd9Sstevel@tonic-gate 	}
5667c478bd9Sstevel@tonic-gate 
5677c478bd9Sstevel@tonic-gate 	wsp->walk_data =
5687c478bd9Sstevel@tonic-gate 	    (void *)(caddr + offsetof(umem_cache_t, cache_nullslab));
5697c478bd9Sstevel@tonic-gate 	wsp->walk_addr = (uintptr_t)c.cache_nullslab.slab_next;
5707c478bd9Sstevel@tonic-gate 
5717c478bd9Sstevel@tonic-gate 	return (WALK_NEXT);
5727c478bd9Sstevel@tonic-gate }
5737c478bd9Sstevel@tonic-gate 
5747c478bd9Sstevel@tonic-gate int
umem_slab_walk_partial_init(mdb_walk_state_t * wsp)5757c478bd9Sstevel@tonic-gate umem_slab_walk_partial_init(mdb_walk_state_t *wsp)
5767c478bd9Sstevel@tonic-gate {
5777c478bd9Sstevel@tonic-gate 	uintptr_t caddr = wsp->walk_addr;
5787c478bd9Sstevel@tonic-gate 	umem_cache_t c;
5797c478bd9Sstevel@tonic-gate 
580892ad162SToomas Soome 	if (caddr == 0) {
5817c478bd9Sstevel@tonic-gate 		mdb_warn("umem_slab_partial doesn't support global walks\n");
5827c478bd9Sstevel@tonic-gate 		return (WALK_ERR);
5837c478bd9Sstevel@tonic-gate 	}
5847c478bd9Sstevel@tonic-gate 
5857c478bd9Sstevel@tonic-gate 	if (mdb_vread(&c, sizeof (c), caddr) == -1) {
5867c478bd9Sstevel@tonic-gate 		mdb_warn("couldn't read umem_cache at %p", caddr);
5877c478bd9Sstevel@tonic-gate 		return (WALK_ERR);
5887c478bd9Sstevel@tonic-gate 	}
5897c478bd9Sstevel@tonic-gate 
5907c478bd9Sstevel@tonic-gate 	wsp->walk_data =
5917c478bd9Sstevel@tonic-gate 	    (void *)(caddr + offsetof(umem_cache_t, cache_nullslab));
5927c478bd9Sstevel@tonic-gate 	wsp->walk_addr = (uintptr_t)c.cache_freelist;
5937c478bd9Sstevel@tonic-gate 
5947c478bd9Sstevel@tonic-gate 	/*
5957c478bd9Sstevel@tonic-gate 	 * Some consumers (umem_walk_step(), in particular) require at
5967c478bd9Sstevel@tonic-gate 	 * least one callback if there are any buffers in the cache.  So
5977c478bd9Sstevel@tonic-gate 	 * if there are *no* partial slabs, report the last full slab, if
5987c478bd9Sstevel@tonic-gate 	 * any.
5997c478bd9Sstevel@tonic-gate 	 *
6007c478bd9Sstevel@tonic-gate 	 * Yes, this is ugly, but it's cleaner than the other possibilities.
6017c478bd9Sstevel@tonic-gate 	 */
6027c478bd9Sstevel@tonic-gate 	if ((uintptr_t)wsp->walk_data == wsp->walk_addr)
6037c478bd9Sstevel@tonic-gate 		wsp->walk_addr = (uintptr_t)c.cache_nullslab.slab_prev;
6047c478bd9Sstevel@tonic-gate 
6057c478bd9Sstevel@tonic-gate 	return (WALK_NEXT);
6067c478bd9Sstevel@tonic-gate }
6077c478bd9Sstevel@tonic-gate 
6087c478bd9Sstevel@tonic-gate int
umem_slab_walk_step(mdb_walk_state_t * wsp)6097c478bd9Sstevel@tonic-gate umem_slab_walk_step(mdb_walk_state_t *wsp)
6107c478bd9Sstevel@tonic-gate {
6117c478bd9Sstevel@tonic-gate 	umem_slab_t s;
6127c478bd9Sstevel@tonic-gate 	uintptr_t addr = wsp->walk_addr;
6137c478bd9Sstevel@tonic-gate 	uintptr_t saddr = (uintptr_t)wsp->walk_data;
6147c478bd9Sstevel@tonic-gate 	uintptr_t caddr = saddr - offsetof(umem_cache_t, cache_nullslab);
6157c478bd9Sstevel@tonic-gate 
6167c478bd9Sstevel@tonic-gate 	if (addr == saddr)
6177c478bd9Sstevel@tonic-gate 		return (WALK_DONE);
6187c478bd9Sstevel@tonic-gate 
6197c478bd9Sstevel@tonic-gate 	if (mdb_vread(&s, sizeof (s), addr) == -1) {
6207c478bd9Sstevel@tonic-gate 		mdb_warn("failed to read slab at %p", wsp->walk_addr);
6217c478bd9Sstevel@tonic-gate 		return (WALK_ERR);
6227c478bd9Sstevel@tonic-gate 	}
6237c478bd9Sstevel@tonic-gate 
6247c478bd9Sstevel@tonic-gate 	if ((uintptr_t)s.slab_cache != caddr) {
6257c478bd9Sstevel@tonic-gate 		mdb_warn("slab %p isn't in cache %p (in cache %p)\n",
6267c478bd9Sstevel@tonic-gate 		    addr, caddr, s.slab_cache);
6277c478bd9Sstevel@tonic-gate 		return (WALK_ERR);
6287c478bd9Sstevel@tonic-gate 	}
6297c478bd9Sstevel@tonic-gate 
6307c478bd9Sstevel@tonic-gate 	wsp->walk_addr = (uintptr_t)s.slab_next;
6317c478bd9Sstevel@tonic-gate 
6327c478bd9Sstevel@tonic-gate 	return (wsp->walk_callback(addr, &s, wsp->walk_cbdata));
6337c478bd9Sstevel@tonic-gate }
6347c478bd9Sstevel@tonic-gate 
6357c478bd9Sstevel@tonic-gate int
umem_cache(uintptr_t addr,uint_t flags,int ac,const mdb_arg_t * argv)6367c478bd9Sstevel@tonic-gate umem_cache(uintptr_t addr, uint_t flags, int ac, const mdb_arg_t *argv)
6377c478bd9Sstevel@tonic-gate {
6387c478bd9Sstevel@tonic-gate 	umem_cache_t c;
6397c478bd9Sstevel@tonic-gate 
6407c478bd9Sstevel@tonic-gate 	if (!(flags & DCMD_ADDRSPEC)) {
6417c478bd9Sstevel@tonic-gate 		if (mdb_walk_dcmd("umem_cache", "umem_cache", ac, argv) == -1) {
6427c478bd9Sstevel@tonic-gate 			mdb_warn("can't walk umem_cache");
6437c478bd9Sstevel@tonic-gate 			return (DCMD_ERR);
6447c478bd9Sstevel@tonic-gate 		}
6457c478bd9Sstevel@tonic-gate 		return (DCMD_OK);
6467c478bd9Sstevel@tonic-gate 	}
6477c478bd9Sstevel@tonic-gate 
6487c478bd9Sstevel@tonic-gate 	if (DCMD_HDRSPEC(flags))
6497c478bd9Sstevel@tonic-gate 		mdb_printf("%-?s %-25s %4s %8s %8s %8s\n", "ADDR", "NAME",
6507c478bd9Sstevel@tonic-gate 		    "FLAG", "CFLAG", "BUFSIZE", "BUFTOTL");
6517c478bd9Sstevel@tonic-gate 
6527c478bd9Sstevel@tonic-gate 	if (mdb_vread(&c, sizeof (c), addr) == -1) {
6537c478bd9Sstevel@tonic-gate 		mdb_warn("couldn't read umem_cache at %p", addr);
6547c478bd9Sstevel@tonic-gate 		return (DCMD_ERR);
6557c478bd9Sstevel@tonic-gate 	}
6567c478bd9Sstevel@tonic-gate 
6577c478bd9Sstevel@tonic-gate 	mdb_printf("%0?p %-25s %04x %08x %8ld %8lld\n", addr, c.cache_name,
6587c478bd9Sstevel@tonic-gate 	    c.cache_flags, c.cache_cflags, c.cache_bufsize, c.cache_buftotal);
6597c478bd9Sstevel@tonic-gate 
6607c478bd9Sstevel@tonic-gate 	return (DCMD_OK);
6617c478bd9Sstevel@tonic-gate }
6627c478bd9Sstevel@tonic-gate 
6637c478bd9Sstevel@tonic-gate static int
addrcmp(const void * lhs,const void * rhs)6647c478bd9Sstevel@tonic-gate addrcmp(const void *lhs, const void *rhs)
6657c478bd9Sstevel@tonic-gate {
6667c478bd9Sstevel@tonic-gate 	uintptr_t p1 = *((uintptr_t *)lhs);
6677c478bd9Sstevel@tonic-gate 	uintptr_t p2 = *((uintptr_t *)rhs);
6687c478bd9Sstevel@tonic-gate 
6697c478bd9Sstevel@tonic-gate 	if (p1 < p2)
6707c478bd9Sstevel@tonic-gate 		return (-1);
6717c478bd9Sstevel@tonic-gate 	if (p1 > p2)
6727c478bd9Sstevel@tonic-gate 		return (1);
6737c478bd9Sstevel@tonic-gate 	return (0);
6747c478bd9Sstevel@tonic-gate }
6757c478bd9Sstevel@tonic-gate 
6767c478bd9Sstevel@tonic-gate static int
bufctlcmp(const umem_bufctl_audit_t ** lhs,const umem_bufctl_audit_t ** rhs)6777c478bd9Sstevel@tonic-gate bufctlcmp(const umem_bufctl_audit_t **lhs, const umem_bufctl_audit_t **rhs)
6787c478bd9Sstevel@tonic-gate {
6797c478bd9Sstevel@tonic-gate 	const umem_bufctl_audit_t *bcp1 = *lhs;
6807c478bd9Sstevel@tonic-gate 	const umem_bufctl_audit_t *bcp2 = *rhs;
6817c478bd9Sstevel@tonic-gate 
6827c478bd9Sstevel@tonic-gate 	if (bcp1->bc_timestamp > bcp2->bc_timestamp)
6837c478bd9Sstevel@tonic-gate 		return (-1);
6847c478bd9Sstevel@tonic-gate 
6857c478bd9Sstevel@tonic-gate 	if (bcp1->bc_timestamp < bcp2->bc_timestamp)
6867c478bd9Sstevel@tonic-gate 		return (1);
6877c478bd9Sstevel@tonic-gate 
6887c478bd9Sstevel@tonic-gate 	return (0);
6897c478bd9Sstevel@tonic-gate }
6907c478bd9Sstevel@tonic-gate 
6917c478bd9Sstevel@tonic-gate typedef struct umem_hash_walk {
6927c478bd9Sstevel@tonic-gate 	uintptr_t *umhw_table;
6937c478bd9Sstevel@tonic-gate 	size_t umhw_nelems;
6947c478bd9Sstevel@tonic-gate 	size_t umhw_pos;
6957c478bd9Sstevel@tonic-gate 	umem_bufctl_t umhw_cur;
6967c478bd9Sstevel@tonic-gate } umem_hash_walk_t;
6977c478bd9Sstevel@tonic-gate 
6987c478bd9Sstevel@tonic-gate int
umem_hash_walk_init(mdb_walk_state_t * wsp)6997c478bd9Sstevel@tonic-gate umem_hash_walk_init(mdb_walk_state_t *wsp)
7007c478bd9Sstevel@tonic-gate {
7017c478bd9Sstevel@tonic-gate 	umem_hash_walk_t *umhw;
7027c478bd9Sstevel@tonic-gate 	uintptr_t *hash;
7037c478bd9Sstevel@tonic-gate 	umem_cache_t c;
7047c478bd9Sstevel@tonic-gate 	uintptr_t haddr, addr = wsp->walk_addr;
7057c478bd9Sstevel@tonic-gate 	size_t nelems;
7067c478bd9Sstevel@tonic-gate 	size_t hsize;
7077c478bd9Sstevel@tonic-gate 
708892ad162SToomas Soome 	if (addr == 0) {
7097c478bd9Sstevel@tonic-gate 		mdb_warn("umem_hash doesn't support global walks\n");
7107c478bd9Sstevel@tonic-gate 		return (WALK_ERR);
7117c478bd9Sstevel@tonic-gate 	}
7127c478bd9Sstevel@tonic-gate 
7137c478bd9Sstevel@tonic-gate 	if (mdb_vread(&c, sizeof (c), addr) == -1) {
7147c478bd9Sstevel@tonic-gate 		mdb_warn("couldn't read cache at addr %p", addr);
7157c478bd9Sstevel@tonic-gate 		return (WALK_ERR);
7167c478bd9Sstevel@tonic-gate 	}
7177c478bd9Sstevel@tonic-gate 
7187c478bd9Sstevel@tonic-gate 	if (!(c.cache_flags & UMF_HASH)) {
7197c478bd9Sstevel@tonic-gate 		mdb_warn("cache %p doesn't have a hash table\n", addr);
7207c478bd9Sstevel@tonic-gate 		return (WALK_DONE);		/* nothing to do */
7217c478bd9Sstevel@tonic-gate 	}
7227c478bd9Sstevel@tonic-gate 
7237c478bd9Sstevel@tonic-gate 	umhw = mdb_zalloc(sizeof (umem_hash_walk_t), UM_SLEEP);
7247c478bd9Sstevel@tonic-gate 	umhw->umhw_cur.bc_next = NULL;
7257c478bd9Sstevel@tonic-gate 	umhw->umhw_pos = 0;
7267c478bd9Sstevel@tonic-gate 
7277c478bd9Sstevel@tonic-gate 	umhw->umhw_nelems = nelems = c.cache_hash_mask + 1;
7287c478bd9Sstevel@tonic-gate 	hsize = nelems * sizeof (uintptr_t);
7297c478bd9Sstevel@tonic-gate 	haddr = (uintptr_t)c.cache_hash_table;
7307c478bd9Sstevel@tonic-gate 
7317c478bd9Sstevel@tonic-gate 	umhw->umhw_table = hash = mdb_alloc(hsize, UM_SLEEP);
7327c478bd9Sstevel@tonic-gate 	if (mdb_vread(hash, hsize, haddr) == -1) {
7337c478bd9Sstevel@tonic-gate 		mdb_warn("failed to read hash table at %p", haddr);
7347c478bd9Sstevel@tonic-gate 		mdb_free(hash, hsize);
7357c478bd9Sstevel@tonic-gate 		mdb_free(umhw, sizeof (umem_hash_walk_t));
7367c478bd9Sstevel@tonic-gate 		return (WALK_ERR);
7377c478bd9Sstevel@tonic-gate 	}
7387c478bd9Sstevel@tonic-gate 
7397c478bd9Sstevel@tonic-gate 	wsp->walk_data = umhw;
7407c478bd9Sstevel@tonic-gate 
7417c478bd9Sstevel@tonic-gate 	return (WALK_NEXT);
7427c478bd9Sstevel@tonic-gate }
7437c478bd9Sstevel@tonic-gate 
7447c478bd9Sstevel@tonic-gate int
umem_hash_walk_step(mdb_walk_state_t * wsp)7457c478bd9Sstevel@tonic-gate umem_hash_walk_step(mdb_walk_state_t *wsp)
7467c478bd9Sstevel@tonic-gate {
7477c478bd9Sstevel@tonic-gate 	umem_hash_walk_t *umhw = wsp->walk_data;
748892ad162SToomas Soome 	uintptr_t addr = 0;
7497c478bd9Sstevel@tonic-gate 
750892ad162SToomas Soome 	if ((addr = (uintptr_t)umhw->umhw_cur.bc_next) == 0) {
7517c478bd9Sstevel@tonic-gate 		while (umhw->umhw_pos < umhw->umhw_nelems) {
752892ad162SToomas Soome 			if ((addr = umhw->umhw_table[umhw->umhw_pos++]) != 0)
7537c478bd9Sstevel@tonic-gate 				break;
7547c478bd9Sstevel@tonic-gate 		}
7557c478bd9Sstevel@tonic-gate 	}
756892ad162SToomas Soome 	if (addr == 0)
7577c478bd9Sstevel@tonic-gate 		return (WALK_DONE);
7587c478bd9Sstevel@tonic-gate 
7597c478bd9Sstevel@tonic-gate 	if (mdb_vread(&umhw->umhw_cur, sizeof (umem_bufctl_t), addr) == -1) {
7607c478bd9Sstevel@tonic-gate 		mdb_warn("couldn't read umem_bufctl_t at addr %p", addr);
7617c478bd9Sstevel@tonic-gate 		return (WALK_ERR);
7627c478bd9Sstevel@tonic-gate 	}
7637c478bd9Sstevel@tonic-gate 
7647c478bd9Sstevel@tonic-gate 	return (wsp->walk_callback(addr, &umhw->umhw_cur, wsp->walk_cbdata));
7657c478bd9Sstevel@tonic-gate }
7667c478bd9Sstevel@tonic-gate 
7677c478bd9Sstevel@tonic-gate void
umem_hash_walk_fini(mdb_walk_state_t * wsp)7687c478bd9Sstevel@tonic-gate umem_hash_walk_fini(mdb_walk_state_t *wsp)
7697c478bd9Sstevel@tonic-gate {
7707c478bd9Sstevel@tonic-gate 	umem_hash_walk_t *umhw = wsp->walk_data;
7717c478bd9Sstevel@tonic-gate 
7727c478bd9Sstevel@tonic-gate 	if (umhw == NULL)
7737c478bd9Sstevel@tonic-gate 		return;
7747c478bd9Sstevel@tonic-gate 
7757c478bd9Sstevel@tonic-gate 	mdb_free(umhw->umhw_table, umhw->umhw_nelems * sizeof (uintptr_t));
7767c478bd9Sstevel@tonic-gate 	mdb_free(umhw, sizeof (umem_hash_walk_t));
7777c478bd9Sstevel@tonic-gate }
7787c478bd9Sstevel@tonic-gate 
7797c478bd9Sstevel@tonic-gate /*
7807c478bd9Sstevel@tonic-gate  * Find the address of the bufctl structure for the address 'buf' in cache
7817c478bd9Sstevel@tonic-gate  * 'cp', which is at address caddr, and place it in *out.
7827c478bd9Sstevel@tonic-gate  */
7837c478bd9Sstevel@tonic-gate static int
umem_hash_lookup(umem_cache_t * cp,uintptr_t caddr,void * buf,uintptr_t * out)7847c478bd9Sstevel@tonic-gate umem_hash_lookup(umem_cache_t *cp, uintptr_t caddr, void *buf, uintptr_t *out)
7857c478bd9Sstevel@tonic-gate {
7867c478bd9Sstevel@tonic-gate 	uintptr_t bucket = (uintptr_t)UMEM_HASH(cp, buf);
7877c478bd9Sstevel@tonic-gate 	umem_bufctl_t *bcp;
7887c478bd9Sstevel@tonic-gate 	umem_bufctl_t bc;
7897c478bd9Sstevel@tonic-gate 
7907c478bd9Sstevel@tonic-gate 	if (mdb_vread(&bcp, sizeof (umem_bufctl_t *), bucket) == -1) {
7917c478bd9Sstevel@tonic-gate 		mdb_warn("unable to read hash bucket for %p in cache %p",
7927c478bd9Sstevel@tonic-gate 		    buf, caddr);
7937c478bd9Sstevel@tonic-gate 		return (-1);
7947c478bd9Sstevel@tonic-gate 	}
7957c478bd9Sstevel@tonic-gate 
7967c478bd9Sstevel@tonic-gate 	while (bcp != NULL) {
7977c478bd9Sstevel@tonic-gate 		if (mdb_vread(&bc, sizeof (umem_bufctl_t),
7987c478bd9Sstevel@tonic-gate 		    (uintptr_t)bcp) == -1) {
7997c478bd9Sstevel@tonic-gate 			mdb_warn("unable to read bufctl at %p", bcp);
8007c478bd9Sstevel@tonic-gate 			return (-1);
8017c478bd9Sstevel@tonic-gate 		}
8027c478bd9Sstevel@tonic-gate 		if (bc.bc_addr == buf) {
8037c478bd9Sstevel@tonic-gate 			*out = (uintptr_t)bcp;
8047c478bd9Sstevel@tonic-gate 			return (0);
8057c478bd9Sstevel@tonic-gate 		}
8067c478bd9Sstevel@tonic-gate 		bcp = bc.bc_next;
8077c478bd9Sstevel@tonic-gate 	}
8087c478bd9Sstevel@tonic-gate 
8097c478bd9Sstevel@tonic-gate 	mdb_warn("unable to find bufctl for %p in cache %p\n", buf, caddr);
8107c478bd9Sstevel@tonic-gate 	return (-1);
8117c478bd9Sstevel@tonic-gate }
8127c478bd9Sstevel@tonic-gate 
8137c478bd9Sstevel@tonic-gate int
umem_get_magsize(const umem_cache_t * cp)8147c478bd9Sstevel@tonic-gate umem_get_magsize(const umem_cache_t *cp)
8157c478bd9Sstevel@tonic-gate {
8167c478bd9Sstevel@tonic-gate 	uintptr_t addr = (uintptr_t)cp->cache_magtype;
8177c478bd9Sstevel@tonic-gate 	GElf_Sym mt_sym;
8187c478bd9Sstevel@tonic-gate 	umem_magtype_t mt;
8197c478bd9Sstevel@tonic-gate 	int res;
8207c478bd9Sstevel@tonic-gate 
8217c478bd9Sstevel@tonic-gate 	/*
8227c478bd9Sstevel@tonic-gate 	 * if cpu 0 has a non-zero magsize, it must be correct.  caches
8237c478bd9Sstevel@tonic-gate 	 * with UMF_NOMAGAZINE have disabled their magazine layers, so
8247c478bd9Sstevel@tonic-gate 	 * it is okay to return 0 for them.
8257c478bd9Sstevel@tonic-gate 	 */
8267c478bd9Sstevel@tonic-gate 	if ((res = cp->cache_cpu[0].cc_magsize) != 0 ||
8277c478bd9Sstevel@tonic-gate 	    (cp->cache_flags & UMF_NOMAGAZINE))
8287c478bd9Sstevel@tonic-gate 		return (res);
8297c478bd9Sstevel@tonic-gate 
830789d94c2Sjwadams 	if (umem_lookup_by_name("umem_magtype", &mt_sym) == -1) {
8317c478bd9Sstevel@tonic-gate 		mdb_warn("unable to read 'umem_magtype'");
8327c478bd9Sstevel@tonic-gate 	} else if (addr < mt_sym.st_value ||
8337c478bd9Sstevel@tonic-gate 	    addr + sizeof (mt) - 1 > mt_sym.st_value + mt_sym.st_size - 1 ||
8347c478bd9Sstevel@tonic-gate 	    ((addr - mt_sym.st_value) % sizeof (mt)) != 0) {
8357c478bd9Sstevel@tonic-gate 		mdb_warn("cache '%s' has invalid magtype pointer (%p)\n",
8367c478bd9Sstevel@tonic-gate 		    cp->cache_name, addr);
8377c478bd9Sstevel@tonic-gate 		return (0);
8387c478bd9Sstevel@tonic-gate 	}
8397c478bd9Sstevel@tonic-gate 	if (mdb_vread(&mt, sizeof (mt), addr) == -1) {
8407c478bd9Sstevel@tonic-gate 		mdb_warn("unable to read magtype at %a", addr);
8417c478bd9Sstevel@tonic-gate 		return (0);
8427c478bd9Sstevel@tonic-gate 	}
8437c478bd9Sstevel@tonic-gate 	return (mt.mt_magsize);
8447c478bd9Sstevel@tonic-gate }
8457c478bd9Sstevel@tonic-gate 
8467c478bd9Sstevel@tonic-gate /*ARGSUSED*/
8477c478bd9Sstevel@tonic-gate static int
umem_estimate_slab(uintptr_t addr,const umem_slab_t * sp,size_t * est)8487c478bd9Sstevel@tonic-gate umem_estimate_slab(uintptr_t addr, const umem_slab_t *sp, size_t *est)
8497c478bd9Sstevel@tonic-gate {
8507c478bd9Sstevel@tonic-gate 	*est -= (sp->slab_chunks - sp->slab_refcnt);
8517c478bd9Sstevel@tonic-gate 
8527c478bd9Sstevel@tonic-gate 	return (WALK_NEXT);
8537c478bd9Sstevel@tonic-gate }
8547c478bd9Sstevel@tonic-gate 
8557c478bd9Sstevel@tonic-gate /*
8567c478bd9Sstevel@tonic-gate  * Returns an upper bound on the number of allocated buffers in a given
8577c478bd9Sstevel@tonic-gate  * cache.
8587c478bd9Sstevel@tonic-gate  */
8597c478bd9Sstevel@tonic-gate size_t
umem_estimate_allocated(uintptr_t addr,const umem_cache_t * cp)8607c478bd9Sstevel@tonic-gate umem_estimate_allocated(uintptr_t addr, const umem_cache_t *cp)
8617c478bd9Sstevel@tonic-gate {
8627c478bd9Sstevel@tonic-gate 	int magsize;
8637c478bd9Sstevel@tonic-gate 	size_t cache_est;
8647c478bd9Sstevel@tonic-gate 
8657c478bd9Sstevel@tonic-gate 	cache_est = cp->cache_buftotal;
8667c478bd9Sstevel@tonic-gate 
8677c478bd9Sstevel@tonic-gate 	(void) mdb_pwalk("umem_slab_partial",
8687c478bd9Sstevel@tonic-gate 	    (mdb_walk_cb_t)umem_estimate_slab, &cache_est, addr);
8697c478bd9Sstevel@tonic-gate 
8707c478bd9Sstevel@tonic-gate 	if ((magsize = umem_get_magsize(cp)) != 0) {
8717c478bd9Sstevel@tonic-gate 		size_t mag_est = cp->cache_full.ml_total * magsize;
8727c478bd9Sstevel@tonic-gate 
8737c478bd9Sstevel@tonic-gate 		if (cache_est >= mag_est) {
8747c478bd9Sstevel@tonic-gate 			cache_est -= mag_est;
8757c478bd9Sstevel@tonic-gate 		} else {
8767c478bd9Sstevel@tonic-gate 			mdb_warn("cache %p's magazine layer holds more buffers "
8777c478bd9Sstevel@tonic-gate 			    "than the slab layer.\n", addr);
8787c478bd9Sstevel@tonic-gate 		}
8797c478bd9Sstevel@tonic-gate 	}
8807c478bd9Sstevel@tonic-gate 	return (cache_est);
8817c478bd9Sstevel@tonic-gate }
8827c478bd9Sstevel@tonic-gate 
8837c478bd9Sstevel@tonic-gate #define	READMAG_ROUNDS(rounds) { \
8847c478bd9Sstevel@tonic-gate 	if (mdb_vread(mp, magbsize, (uintptr_t)ump) == -1) { \
8857c478bd9Sstevel@tonic-gate 		mdb_warn("couldn't read magazine at %p", ump); \
8867c478bd9Sstevel@tonic-gate 		goto fail; \
8877c478bd9Sstevel@tonic-gate 	} \
8887c478bd9Sstevel@tonic-gate 	for (i = 0; i < rounds; i++) { \
8897c478bd9Sstevel@tonic-gate 		maglist[magcnt++] = mp->mag_round[i]; \
8907c478bd9Sstevel@tonic-gate 		if (magcnt == magmax) { \
8917c478bd9Sstevel@tonic-gate 			mdb_warn("%d magazines exceeds fudge factor\n", \
8927c478bd9Sstevel@tonic-gate 			    magcnt); \
8937c478bd9Sstevel@tonic-gate 			goto fail; \
8947c478bd9Sstevel@tonic-gate 		} \
8957c478bd9Sstevel@tonic-gate 	} \
8967c478bd9Sstevel@tonic-gate }
8977c478bd9Sstevel@tonic-gate 
8984f364e7cSRobert Mustacchi static int
umem_read_magazines(umem_cache_t * cp,uintptr_t addr,void *** maglistp,size_t * magcntp,size_t * magmaxp)899789d94c2Sjwadams umem_read_magazines(umem_cache_t *cp, uintptr_t addr,
9004f364e7cSRobert Mustacchi     void ***maglistp, size_t *magcntp, size_t *magmaxp)
9017c478bd9Sstevel@tonic-gate {
9027c478bd9Sstevel@tonic-gate 	umem_magazine_t *ump, *mp;
9037c478bd9Sstevel@tonic-gate 	void **maglist = NULL;
9047c478bd9Sstevel@tonic-gate 	int i, cpu;
9057c478bd9Sstevel@tonic-gate 	size_t magsize, magmax, magbsize;
9067c478bd9Sstevel@tonic-gate 	size_t magcnt = 0;
9077c478bd9Sstevel@tonic-gate 
9087c478bd9Sstevel@tonic-gate 	/*
9097c478bd9Sstevel@tonic-gate 	 * Read the magtype out of the cache, after verifying the pointer's
9107c478bd9Sstevel@tonic-gate 	 * correctness.
9117c478bd9Sstevel@tonic-gate 	 */
9127c478bd9Sstevel@tonic-gate 	magsize = umem_get_magsize(cp);
913789d94c2Sjwadams 	if (magsize == 0) {
914789d94c2Sjwadams 		*maglistp = NULL;
915789d94c2Sjwadams 		*magcntp = 0;
916789d94c2Sjwadams 		*magmaxp = 0;
9174f364e7cSRobert Mustacchi 		return (0);
918789d94c2Sjwadams 	}
9197c478bd9Sstevel@tonic-gate 
9207c478bd9Sstevel@tonic-gate 	/*
9217c478bd9Sstevel@tonic-gate 	 * There are several places where we need to go buffer hunting:
9227c478bd9Sstevel@tonic-gate 	 * the per-CPU loaded magazine, the per-CPU spare full magazine,
9237c478bd9Sstevel@tonic-gate 	 * and the full magazine list in the depot.
9247c478bd9Sstevel@tonic-gate 	 *
9257c478bd9Sstevel@tonic-gate 	 * For an upper bound on the number of buffers in the magazine
9267c478bd9Sstevel@tonic-gate 	 * layer, we have the number of magazines on the cache_full
9277c478bd9Sstevel@tonic-gate 	 * list plus at most two magazines per CPU (the loaded and the
9287c478bd9Sstevel@tonic-gate 	 * spare).  Toss in 100 magazines as a fudge factor in case this
9297c478bd9Sstevel@tonic-gate 	 * is live (the number "100" comes from the same fudge factor in
9307c478bd9Sstevel@tonic-gate 	 * crash(1M)).
9317c478bd9Sstevel@tonic-gate 	 */
932789d94c2Sjwadams 	magmax = (cp->cache_full.ml_total + 2 * umem_max_ncpus + 100) * magsize;
9337c478bd9Sstevel@tonic-gate 	magbsize = offsetof(umem_magazine_t, mag_round[magsize]);
9347c478bd9Sstevel@tonic-gate 
9357c478bd9Sstevel@tonic-gate 	if (magbsize >= PAGESIZE / 2) {
9367c478bd9Sstevel@tonic-gate 		mdb_warn("magazine size for cache %p unreasonable (%x)\n",
9377c478bd9Sstevel@tonic-gate 		    addr, magbsize);
9384f364e7cSRobert Mustacchi 		return (-1);
9397c478bd9Sstevel@tonic-gate 	}
9407c478bd9Sstevel@tonic-gate 
9414f364e7cSRobert Mustacchi 	maglist = mdb_alloc(magmax * sizeof (void *), UM_SLEEP);
9424f364e7cSRobert Mustacchi 	mp = mdb_alloc(magbsize, UM_SLEEP);
9437c478bd9Sstevel@tonic-gate 	if (mp == NULL || maglist == NULL)
9447c478bd9Sstevel@tonic-gate 		goto fail;
9457c478bd9Sstevel@tonic-gate 
9467c478bd9Sstevel@tonic-gate 	/*
9477c478bd9Sstevel@tonic-gate 	 * First up: the magazines in the depot (i.e. on the cache_full list).
9487c478bd9Sstevel@tonic-gate 	 */
9497c478bd9Sstevel@tonic-gate 	for (ump = cp->cache_full.ml_list; ump != NULL; ) {
9507c478bd9Sstevel@tonic-gate 		READMAG_ROUNDS(magsize);
9517c478bd9Sstevel@tonic-gate 		ump = mp->mag_next;
9527c478bd9Sstevel@tonic-gate 
9537c478bd9Sstevel@tonic-gate 		if (ump == cp->cache_full.ml_list)
9547c478bd9Sstevel@tonic-gate 			break; /* cache_full list loop detected */
9557c478bd9Sstevel@tonic-gate 	}
9567c478bd9Sstevel@tonic-gate 
9577c478bd9Sstevel@tonic-gate 	dprintf(("cache_full list done\n"));
9587c478bd9Sstevel@tonic-gate 
9597c478bd9Sstevel@tonic-gate 	/*
9607c478bd9Sstevel@tonic-gate 	 * Now whip through the CPUs, snagging the loaded magazines
9617c478bd9Sstevel@tonic-gate 	 * and full spares.
9627c478bd9Sstevel@tonic-gate 	 */
963789d94c2Sjwadams 	for (cpu = 0; cpu < umem_max_ncpus; cpu++) {
9647c478bd9Sstevel@tonic-gate 		umem_cpu_cache_t *ccp = &cp->cache_cpu[cpu];
9657c478bd9Sstevel@tonic-gate 
9667c478bd9Sstevel@tonic-gate 		dprintf(("reading cpu cache %p\n",
9677c478bd9Sstevel@tonic-gate 		    (uintptr_t)ccp - (uintptr_t)cp + addr));
9687c478bd9Sstevel@tonic-gate 
9697c478bd9Sstevel@tonic-gate 		if (ccp->cc_rounds > 0 &&
9707c478bd9Sstevel@tonic-gate 		    (ump = ccp->cc_loaded) != NULL) {
9717c478bd9Sstevel@tonic-gate 			dprintf(("reading %d loaded rounds\n", ccp->cc_rounds));
9727c478bd9Sstevel@tonic-gate 			READMAG_ROUNDS(ccp->cc_rounds);
9737c478bd9Sstevel@tonic-gate 		}
9747c478bd9Sstevel@tonic-gate 
9757c478bd9Sstevel@tonic-gate 		if (ccp->cc_prounds > 0 &&
9767c478bd9Sstevel@tonic-gate 		    (ump = ccp->cc_ploaded) != NULL) {
9777c478bd9Sstevel@tonic-gate 			dprintf(("reading %d previously loaded rounds\n",
9787c478bd9Sstevel@tonic-gate 			    ccp->cc_prounds));
9797c478bd9Sstevel@tonic-gate 			READMAG_ROUNDS(ccp->cc_prounds);
9807c478bd9Sstevel@tonic-gate 		}
9817c478bd9Sstevel@tonic-gate 	}
9827c478bd9Sstevel@tonic-gate 
9837c478bd9Sstevel@tonic-gate 	dprintf(("magazine layer: %d buffers\n", magcnt));
9847c478bd9Sstevel@tonic-gate 
9854f364e7cSRobert Mustacchi 	mdb_free(mp, magbsize);
9867c478bd9Sstevel@tonic-gate 
9877c478bd9Sstevel@tonic-gate 	*maglistp = maglist;
9887c478bd9Sstevel@tonic-gate 	*magcntp = magcnt;
9897c478bd9Sstevel@tonic-gate 	*magmaxp = magmax;
9907c478bd9Sstevel@tonic-gate 
9914f364e7cSRobert Mustacchi 	return (0);
9927c478bd9Sstevel@tonic-gate 
9937c478bd9Sstevel@tonic-gate fail:
9944f364e7cSRobert Mustacchi 	if (mp)
9954f364e7cSRobert Mustacchi 		mdb_free(mp, magbsize);
9964f364e7cSRobert Mustacchi 	if (maglist)
9974f364e7cSRobert Mustacchi 		mdb_free(maglist, magmax * sizeof (void *));
9984f364e7cSRobert Mustacchi 
9994f364e7cSRobert Mustacchi 	return (-1);
10004f364e7cSRobert Mustacchi }
10014f364e7cSRobert Mustacchi 
10024f364e7cSRobert Mustacchi typedef struct umem_read_ptc_walk {
10034f364e7cSRobert Mustacchi 	void **urpw_buf;
10044f364e7cSRobert Mustacchi 	size_t urpw_cnt;
10054f364e7cSRobert Mustacchi 	size_t urpw_max;
10064f364e7cSRobert Mustacchi } umem_read_ptc_walk_t;
10074f364e7cSRobert Mustacchi 
10084f364e7cSRobert Mustacchi /*ARGSUSED*/
10094f364e7cSRobert Mustacchi static int
umem_read_ptc_walk_buf(uintptr_t addr,const void * ignored,umem_read_ptc_walk_t * urpw)10104f364e7cSRobert Mustacchi umem_read_ptc_walk_buf(uintptr_t addr,
10114f364e7cSRobert Mustacchi     const void *ignored, umem_read_ptc_walk_t *urpw)
10124f364e7cSRobert Mustacchi {
10134f364e7cSRobert Mustacchi 	if (urpw->urpw_cnt == urpw->urpw_max) {
10144f364e7cSRobert Mustacchi 		size_t nmax = urpw->urpw_max ? (urpw->urpw_max << 1) : 1;
10154f364e7cSRobert Mustacchi 		void **new = mdb_zalloc(nmax * sizeof (void *), UM_SLEEP);
10164f364e7cSRobert Mustacchi 
10174f364e7cSRobert Mustacchi 		if (nmax > 1) {
10184f364e7cSRobert Mustacchi 			size_t osize = urpw->urpw_max * sizeof (void *);
10194f364e7cSRobert Mustacchi 			bcopy(urpw->urpw_buf, new, osize);
10204f364e7cSRobert Mustacchi 			mdb_free(urpw->urpw_buf, osize);
1021