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 /*
22346799e8SJonathan W 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 /*
27dfec2ecfSJohn Levon * Copyright 2018 Joyent, Inc. All rights reserved.
2828e4da25SMatthew Ahrens * Copyright (c) 2012 by Delphix. All rights reserved.
29d7dba7e5SBryan Cantrill */
30d7dba7e5SBryan Cantrill
317c478bd9Sstevel@tonic-gate #include <mdb/mdb_param.h>
327c478bd9Sstevel@tonic-gate #include <mdb/mdb_modapi.h>
337c478bd9Sstevel@tonic-gate #include <mdb/mdb_ctf.h>
344a1c2431SJonathan Adams #include <mdb/mdb_whatis.h>
357c478bd9Sstevel@tonic-gate #include <sys/cpuvar.h>
367c478bd9Sstevel@tonic-gate #include <sys/kmem_impl.h>
377c478bd9Sstevel@tonic-gate #include <sys/vmem_impl.h>
387c478bd9Sstevel@tonic-gate #include <sys/machelf.h>
397c478bd9Sstevel@tonic-gate #include <sys/modctl.h>
407c478bd9Sstevel@tonic-gate #include <sys/kobj.h>
417c478bd9Sstevel@tonic-gate #include <sys/panic.h>
427c478bd9Sstevel@tonic-gate #include <sys/stack.h>
437c478bd9Sstevel@tonic-gate #include <sys/sysmacros.h>
447c478bd9Sstevel@tonic-gate #include <vm/page.h>
457c478bd9Sstevel@tonic-gate
46b5fca8f8Stomee #include "avl.h"
47b5fca8f8Stomee #include "combined.h"
48087e1372Stomee #include "dist.h"
497c478bd9Sstevel@tonic-gate #include "kmem.h"
50b5fca8f8Stomee #include "list.h"
517c478bd9Sstevel@tonic-gate
527c478bd9Sstevel@tonic-gate #define dprintf(x) if (mdb_debug_level) { \
537c478bd9Sstevel@tonic-gate mdb_printf("kmem debug: "); \
547c478bd9Sstevel@tonic-gate /*CSTYLED*/\
557c478bd9Sstevel@tonic-gate mdb_printf x ;\
567c478bd9Sstevel@tonic-gate }
577c478bd9Sstevel@tonic-gate
587c478bd9Sstevel@tonic-gate #define KM_ALLOCATED 0x01
597c478bd9Sstevel@tonic-gate #define KM_FREE 0x02
607c478bd9Sstevel@tonic-gate #define KM_BUFCTL 0x04
617c478bd9Sstevel@tonic-gate #define KM_CONSTRUCTED 0x08 /* only constructed free buffers */
627c478bd9Sstevel@tonic-gate #define KM_HASH 0x10
637c478bd9Sstevel@tonic-gate
647c478bd9Sstevel@tonic-gate static int mdb_debug_level = 0;
657c478bd9Sstevel@tonic-gate
667c478bd9Sstevel@tonic-gate /*ARGSUSED*/
677c478bd9Sstevel@tonic-gate static int
kmem_init_walkers(uintptr_t addr,const kmem_cache_t * c,void * ignored)687c478bd9Sstevel@tonic-gate kmem_init_walkers(uintptr_t addr, const kmem_cache_t *c, void *ignored)
697c478bd9Sstevel@tonic-gate {
707c478bd9Sstevel@tonic-gate mdb_walker_t w;
717c478bd9Sstevel@tonic-gate char descr[64];
727c478bd9Sstevel@tonic-gate
737c478bd9Sstevel@tonic-gate (void) mdb_snprintf(descr, sizeof (descr),
747c478bd9Sstevel@tonic-gate "walk the %s cache", c->cache_name);
757c478bd9Sstevel@tonic-gate
767c478bd9Sstevel@tonic-gate w.walk_name = c->cache_name;
777c478bd9Sstevel@tonic-gate w.walk_descr = descr;
787c478bd9Sstevel@tonic-gate w.walk_init = kmem_walk_init;
797c478bd9Sstevel@tonic-gate w.walk_step = kmem_walk_step;
807c478bd9Sstevel@tonic-gate w.walk_fini = kmem_walk_fini;
817c478bd9Sstevel@tonic-gate w.walk_init_arg = (void *)addr;
827c478bd9Sstevel@tonic-gate
837c478bd9Sstevel@tonic-gate if (mdb_add_walker(&w) == -1)
847c478bd9Sstevel@tonic-gate mdb_warn("failed to add %s walker", c->cache_name);
857c478bd9Sstevel@tonic-gate
867c478bd9Sstevel@tonic-gate return (WALK_NEXT);
877c478bd9Sstevel@tonic-gate }
887c478bd9Sstevel@tonic-gate
897c478bd9Sstevel@tonic-gate /*ARGSUSED*/
907c478bd9Sstevel@tonic-gate int
kmem_debug(uintptr_t addr,uint_t flags,int argc,const mdb_arg_t * argv)917c478bd9Sstevel@tonic-gate kmem_debug(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
927c478bd9Sstevel@tonic-gate {
937c478bd9Sstevel@tonic-gate mdb_debug_level ^= 1;
947c478bd9Sstevel@tonic-gate
957c478bd9Sstevel@tonic-gate mdb_printf("kmem: debugging is now %s\n",
967c478bd9Sstevel@tonic-gate mdb_debug_level ? "on" : "off");
977c478bd9Sstevel@tonic-gate
987c478bd9Sstevel@tonic-gate return (DCMD_OK);
997c478bd9Sstevel@tonic-gate }
1007c478bd9Sstevel@tonic-gate
1017c478bd9Sstevel@tonic-gate int
kmem_cache_walk_init(mdb_walk_state_t * wsp)1027c478bd9Sstevel@tonic-gate kmem_cache_walk_init(mdb_walk_state_t *wsp)
1037c478bd9Sstevel@tonic-gate {
1047c478bd9Sstevel@tonic-gate GElf_Sym sym;
1057c478bd9Sstevel@tonic-gate
106b5fca8f8Stomee if (mdb_lookup_by_name("kmem_caches", &sym) == -1) {
107b5fca8f8Stomee mdb_warn("couldn't find kmem_caches");
1087c478bd9Sstevel@tonic-gate return (WALK_ERR);
1097c478bd9Sstevel@tonic-gate }
1107c478bd9Sstevel@tonic-gate
111b5fca8f8Stomee wsp->walk_addr = (uintptr_t)sym.st_value;
1127c478bd9Sstevel@tonic-gate
113b5fca8f8Stomee return (list_walk_init_named(wsp, "cache list", "cache"));
1147c478bd9Sstevel@tonic-gate }
1157c478bd9Sstevel@tonic-gate
1167c478bd9Sstevel@tonic-gate int
kmem_cpu_cache_walk_init(mdb_walk_state_t * wsp)1177c478bd9Sstevel@tonic-gate kmem_cpu_cache_walk_init(mdb_walk_state_t *wsp)
1187c478bd9Sstevel@tonic-gate {
119892ad162SToomas Soome if (wsp->walk_addr == 0) {
1207c478bd9Sstevel@tonic-gate mdb_warn("kmem_cpu_cache doesn't support global walks");
1217c478bd9Sstevel@tonic-gate return (WALK_ERR);
1227c478bd9Sstevel@tonic-gate }
1237c478bd9Sstevel@tonic-gate
1247c478bd9Sstevel@tonic-gate if (mdb_layered_walk("cpu", wsp) == -1) {
1257c478bd9Sstevel@tonic-gate mdb_warn("couldn't walk 'cpu'");
1267c478bd9Sstevel@tonic-gate return (WALK_ERR);
1277c478bd9Sstevel@tonic-gate }
1287c478bd9Sstevel@tonic-gate
1297c478bd9Sstevel@tonic-gate wsp->walk_data = (void *)wsp->walk_addr;
1307c478bd9Sstevel@tonic-gate
1317c478bd9Sstevel@tonic-gate return (WALK_NEXT);
1327c478bd9Sstevel@tonic-gate }
1337c478bd9Sstevel@tonic-gate
1347c478bd9Sstevel@tonic-gate int
kmem_cpu_cache_walk_step(mdb_walk_state_t * wsp)1357c478bd9Sstevel@tonic-gate kmem_cpu_cache_walk_step(mdb_walk_state_t *wsp)
1367c478bd9Sstevel@tonic-gate {
1377c478bd9Sstevel@tonic-gate uintptr_t caddr = (uintptr_t)wsp->walk_data;
1387c478bd9Sstevel@tonic-gate const cpu_t *cpu = wsp->walk_layer;
1397c478bd9Sstevel@tonic-gate kmem_cpu_cache_t cc;
1407c478bd9Sstevel@tonic-gate
1411db3a682SMichael Corcoran caddr += OFFSETOF(kmem_cache_t, cache_cpu[cpu->cpu_seqid]);
1427c478bd9Sstevel@tonic-gate
1437c478bd9Sstevel@tonic-gate if (mdb_vread(&cc, sizeof (kmem_cpu_cache_t), caddr) == -1) {
1447c478bd9Sstevel@tonic-gate mdb_warn("couldn't read kmem_cpu_cache at %p", caddr);
1457c478bd9Sstevel@tonic-gate return (WALK_ERR);
1467c478bd9Sstevel@tonic-gate }
1477c478bd9Sstevel@tonic-gate
1487c478bd9Sstevel@tonic-gate return (wsp->walk_callback(caddr, &cc, wsp->walk_cbdata));
1497c478bd9Sstevel@tonic-gate }
1507c478bd9Sstevel@tonic-gate
151b5fca8f8Stomee static int
kmem_slab_check(void * p,uintptr_t saddr,void * arg)152b5fca8f8Stomee kmem_slab_check(void *p, uintptr_t saddr, void *arg)
153b5fca8f8Stomee {
154b5fca8f8Stomee kmem_slab_t *sp = p;
155b5fca8f8Stomee uintptr_t caddr = (uintptr_t)arg;
156b5fca8f8Stomee if ((uintptr_t)sp->slab_cache != caddr) {
157b5fca8f8Stomee mdb_warn("slab %p isn't in cache %p (in cache %p)\n",
158b5fca8f8Stomee saddr, caddr, sp->slab_cache);
159b5fca8f8Stomee return (-1);
160b5fca8f8Stomee }
161b5fca8f8Stomee
162b5fca8f8Stomee return (0);
163b5fca8f8Stomee }
164b5fca8f8Stomee
165b5fca8f8Stomee static int
kmem_partial_slab_check(void * p,uintptr_t saddr,void * arg)166b5fca8f8Stomee kmem_partial_slab_check(void *p, uintptr_t saddr, void *arg)
167b5fca8f8Stomee {
168b5fca8f8Stomee kmem_slab_t *sp = p;
169b5fca8f8Stomee
170b5fca8f8Stomee int rc = kmem_slab_check(p, saddr, arg);
171b5fca8f8Stomee if (rc != 0) {
172b5fca8f8Stomee return (rc);
173b5fca8f8Stomee }
174b5fca8f8Stomee
175b5fca8f8Stomee if (!KMEM_SLAB_IS_PARTIAL(sp)) {
176b5fca8f8Stomee mdb_warn("slab %p is not a partial slab\n", saddr);
177b5fca8f8Stomee return (-1);
178b5fca8f8Stomee }
179b5fca8f8Stomee
180b5fca8f8Stomee return (0);
181b5fca8f8Stomee }
182b5fca8f8Stomee
183b5fca8f8Stomee static int
kmem_complete_slab_check(void * p,uintptr_t saddr,void * arg)184b5fca8f8Stomee kmem_complete_slab_check(void *p, uintptr_t saddr, void *arg)
185b5fca8f8Stomee {
186b5fca8f8Stomee kmem_slab_t *sp = p;
187b5fca8f8Stomee
188b5fca8f8Stomee int rc = kmem_slab_check(p, saddr, arg);
189b5fca8f8Stomee if (rc != 0) {
190b5fca8f8Stomee return (rc);
191b5fca8f8Stomee }
192b5fca8f8Stomee
193b5fca8f8Stomee if (!KMEM_SLAB_IS_ALL_USED(sp)) {
194b5fca8f8Stomee mdb_warn("slab %p is not completely allocated\n", saddr);
195b5fca8f8Stomee return (-1);
196b5fca8f8Stomee }
197b5fca8f8Stomee
198b5fca8f8Stomee return (0);
199b5fca8f8Stomee }
200b5fca8f8Stomee
201b5fca8f8Stomee typedef struct {
202b5fca8f8Stomee uintptr_t kns_cache_addr;
203b5fca8f8Stomee int kns_nslabs;
204b5fca8f8Stomee } kmem_nth_slab_t;
205b5fca8f8Stomee
206b5fca8f8Stomee static int
kmem_nth_slab_check(void * p,uintptr_t saddr,void * arg)207b5fca8f8Stomee kmem_nth_slab_check(void *p, uintptr_t saddr, void *arg)
208b5fca8f8Stomee {
209b5fca8f8Stomee kmem_nth_slab_t *chkp = arg;
210b5fca8f8Stomee
211b5fca8f8Stomee int rc = kmem_slab_check(p, saddr, (void *)chkp->kns_cache_addr);
212b5fca8f8Stomee if (rc != 0) {
213b5fca8f8Stomee return (rc);
214b5fca8f8Stomee }
215b5fca8f8Stomee
216b5fca8f8Stomee return (chkp->kns_nslabs-- == 0 ? 1 : 0);
217b5fca8f8Stomee }
218b5fca8f8Stomee
219b5fca8f8Stomee static int
kmem_complete_slab_walk_init(mdb_walk_state_t * wsp)220b5fca8f8Stomee kmem_complete_slab_walk_init(mdb_walk_state_t *wsp)
221b5fca8f8Stomee {
222b5fca8f8Stomee uintptr_t caddr = wsp->walk_addr;
223b5fca8f8Stomee
224b5fca8f8Stomee wsp->walk_addr = (uintptr_t)(caddr +
225b5fca8f8Stomee offsetof(kmem_cache_t, cache_complete_slabs));
226b5fca8f8Stomee
227b5fca8f8Stomee return (list_walk_init_checked(wsp, "slab list", "slab",
228b5fca8f8Stomee kmem_complete_slab_check, (void *)caddr));
229b5fca8f8Stomee }
230b5fca8f8Stomee
231b5fca8f8Stomee static int
kmem_partial_slab_walk_init(mdb_walk_state_t * wsp)232b5fca8f8Stomee kmem_partial_slab_walk_init(mdb_walk_state_t *wsp)
233b5fca8f8Stomee {
234b5fca8f8Stomee uintptr_t caddr = wsp->walk_addr;
235b5fca8f8Stomee
236b5fca8f8Stomee wsp->walk_addr = (uintptr_t)(caddr +
237b5fca8f8Stomee offsetof(kmem_cache_t, cache_partial_slabs));
238b5fca8f8Stomee
239b5fca8f8Stomee return (avl_walk_init_checked(wsp, "slab list", "slab",
240b5fca8f8Stomee kmem_partial_slab_check, (void *)caddr));
241b5fca8f8Stomee }
242b5fca8f8Stomee
2437c478bd9Sstevel@tonic-gate int
kmem_slab_walk_init(mdb_walk_state_t * wsp)2447c478bd9Sstevel@tonic-gate kmem_slab_walk_init(mdb_walk_state_t *wsp)
2457c478bd9Sstevel@tonic-gate {
2467c478bd9Sstevel@tonic-gate uintptr_t caddr = wsp->walk_addr;
2477c478bd9Sstevel@tonic-gate
248892ad162SToomas Soome if (caddr == 0) {
2497c478bd9Sstevel@tonic-gate mdb_warn("kmem_slab doesn't support global walks\n");
2507c478bd9Sstevel@tonic-gate return (WALK_ERR);
2517c478bd9Sstevel@tonic-gate }
2527c478bd9Sstevel@tonic-gate
253b5fca8f8Stomee combined_walk_init(wsp);
254b5fca8f8Stomee combined_walk_add(wsp,
255b5fca8f8Stomee kmem_complete_slab_walk_init, list_walk_step, list_walk_fini);
256b5fca8f8Stomee combined_walk_add(wsp,
257b5fca8f8Stomee kmem_partial_slab_walk_init, avl_walk_step, avl_walk_fini);
2587c478bd9Sstevel@tonic-gate
2597c478bd9Sstevel@tonic-gate return (WALK_NEXT);
2607c478bd9Sstevel@tonic-gate }
2617c478bd9Sstevel@tonic-gate
262b5fca8f8Stomee static int
kmem_first_complete_slab_walk_init(mdb_walk_state_t * wsp)263b5fca8f8Stomee kmem_first_complete_slab_walk_init(mdb_walk_state_t *wsp)
264b5fca8f8Stomee {
265b5fca8f8Stomee uintptr_t caddr = wsp->walk_addr;
266b5fca8f8Stomee kmem_nth_slab_t *chk;
267b5fca8f8Stomee
268b5fca8f8Stomee chk = mdb_alloc(sizeof (kmem_nth_slab_t),
269b5fca8f8Stomee UM_SLEEP | UM_GC);
270b5fca8f8Stomee chk->kns_cache_addr = caddr;
271b5fca8f8Stomee chk->kns_nslabs = 1;
272b5fca8f8Stomee wsp->walk_addr = (uintptr_t)(caddr +
273b5fca8f8Stomee offsetof(kmem_cache_t, cache_complete_slabs));
274b5fca8f8Stomee
275b5fca8f8Stomee return (list_walk_init_checked(wsp, "slab list", "slab",
276b5fca8f8Stomee kmem_nth_slab_check, chk));
277b5fca8f8Stomee }
278b5fca8f8Stomee
2797c478bd9Sstevel@tonic-gate int
kmem_slab_walk_partial_init(mdb_walk_state_t * wsp)2807c478bd9Sstevel@tonic-gate kmem_slab_walk_partial_init(mdb_walk_state_t *wsp)
2817c478bd9Sstevel@tonic-gate {
2827c478bd9Sstevel@tonic-gate uintptr_t caddr = wsp->walk_addr;
2837c478bd9Sstevel@tonic-gate kmem_cache_t c;
2847c478bd9Sstevel@tonic-gate
285892ad162SToomas Soome if (caddr == 0) {
2867c478bd9Sstevel@tonic-gate mdb_warn("kmem_slab_partial doesn't support global walks\n");
2877c478bd9Sstevel@tonic-gate return (WALK_ERR);
2887c478bd9Sstevel@tonic-gate }
2897c478bd9Sstevel@tonic-gate
2907c478bd9Sstevel@tonic-gate if (mdb_vread(&c, sizeof (c), caddr) == -1) {
2917c478bd9Sstevel@tonic-gate mdb_warn("couldn't read kmem_cache at %p", caddr);
2927c478bd9Sstevel@tonic-gate return (WALK_ERR);
2937c478bd9Sstevel@tonic-gate }
2947c478bd9Sstevel@tonic-gate
295b5fca8f8Stomee combined_walk_init(wsp);
2967c478bd9Sstevel@tonic-gate
2977c478bd9Sstevel@tonic-gate /*
2987c478bd9Sstevel@tonic-gate * Some consumers (umem_walk_step(), in particular) require at
2997c478bd9Sstevel@tonic-gate * least one callback if there are any buffers in the cache. So
300b5fca8f8Stomee * if there are *no* partial slabs, report the first full slab, if
3017c478bd9Sstevel@tonic-gate * any.
3027c478bd9Sstevel@tonic-gate *
3037c478bd9Sstevel@tonic-gate * Yes, this is ugly, but it's cleaner than the other possibilities.
3047c478bd9Sstevel@tonic-gate */
305b5fca8f8Stomee if (c.cache_partial_slabs.avl_numnodes == 0) {
306b5fca8f8Stomee combined_walk_add(wsp, kmem_first_complete_slab_walk_init,
307b5fca8f8Stomee list_walk_step, list_walk_fini);
308b5fca8f8Stomee } else {
309b5fca8f8Stomee combined_walk_add(wsp, kmem_partial_slab_walk_init,
310b5fca8f8Stomee avl_walk_step, avl_walk_fini);
3117c478bd9Sstevel@tonic-gate }
3127c478bd9Sstevel@tonic-gate
313b5fca8f8Stomee return (WALK_NEXT);
3147c478bd9Sstevel@tonic-gate }
3157c478bd9Sstevel@tonic-gate
3167c478bd9Sstevel@tonic-gate int
kmem_cache(uintptr_t addr,uint_t flags,int ac,const mdb_arg_t * argv)3177c478bd9Sstevel@tonic-gate kmem_cache(uintptr_t addr, uint_t flags, int ac, const mdb_arg_t *argv)
3187c478bd9Sstevel@tonic-gate {
3197c478bd9Sstevel@tonic-gate kmem_cache_t c;
320b5fca8f8Stomee const char *filter = NULL;
321b5fca8f8Stomee
322b5fca8f8Stomee if (mdb_getopts(ac, argv,
323b5fca8f8Stomee 'n', MDB_OPT_STR, &filter,
324b5fca8f8Stomee NULL) != ac) {
325b5fca8f8Stomee return (DCMD_USAGE);
326b5fca8f8Stomee }
3277c478bd9Sstevel@tonic-gate
3287c478bd9Sstevel@tonic-gate if (!(flags & DCMD_ADDRSPEC)) {
3297c478bd9Sstevel@tonic-gate if (mdb_walk_dcmd("kmem_cache", "kmem_cache", ac, argv) == -1) {
3307c478bd9Sstevel@tonic-gate mdb_warn("can't walk kmem_cache");
3317c478bd9Sstevel@tonic-gate return (DCMD_ERR);
3327c478bd9Sstevel@tonic-gate }
3337c478bd9Sstevel@tonic-gate return (DCMD_OK);
3347c478bd9Sstevel@tonic-gate }
3357c478bd9Sstevel@tonic-gate
3367c478bd9Sstevel@tonic-gate if (DCMD_HDRSPEC(flags))
3377c478bd9Sstevel@tonic-gate mdb_printf("%-?s %-25s %4s %6s %8s %8s\n", "ADDR", "NAME",
3387c478bd9Sstevel@tonic-gate "FLAG", "CFLAG", "BUFSIZE", "BUFTOTL");
3397c478bd9Sstevel@tonic-gate
3407c478bd9Sstevel@tonic-gate if (mdb_vread(&c, sizeof (c), addr) == -1) {
3417c478bd9Sstevel@tonic-gate mdb_warn("couldn't read kmem_cache at %p", addr);
3427c478bd9Sstevel@tonic-gate return (DCMD_ERR);
3437c478bd9Sstevel@tonic-gate }
3447c478bd9Sstevel@tonic-gate
345b5fca8f8Stomee if ((filter != NULL) && (strstr(c.cache_name, filter) == NULL))
346b5fca8f8Stomee return (DCMD_OK);
347b5fca8f8Stomee
3487c478bd9Sstevel@tonic-gate mdb_printf("%0?p %-25s %04x %06x %8ld %8lld\n", addr, c.cache_name,
3497c478bd9Sstevel@tonic-gate c.cache_flags, c.cache_cflags, c.cache_bufsize, c.cache_buftotal);
3507c478bd9Sstevel@tonic-gate
3517c478bd9Sstevel@tonic-gate return (DCMD_OK);
3527c478bd9Sstevel@tonic-gate }
3537c478bd9Sstevel@tonic-gate
354b5fca8f8Stomee void
kmem_cache_help(void)355b5fca8f8Stomee kmem_cache_help(void)
356b5fca8f8Stomee {
357b5fca8f8Stomee mdb_printf("%s", "Print kernel memory caches.\n\n");
358b5fca8f8Stomee mdb_dec_indent(2);
359b5fca8f8Stomee mdb_printf("%<b>OPTIONS%</b>\n");
360b5fca8f8Stomee mdb_inc_indent(2);
361b5fca8f8Stomee mdb_printf("%s",
362b5fca8f8Stomee " -n name\n"
363b5fca8f8Stomee " name of kmem cache (or matching partial name)\n"
364b5fca8f8Stomee "\n"
365b5fca8f8Stomee "Column\tDescription\n"
366b5fca8f8Stomee "\n"
367b5fca8f8Stomee "ADDR\t\taddress of kmem cache\n"
368b5fca8f8Stomee "NAME\t\tname of kmem cache\n"
369b5fca8f8Stomee "FLAG\t\tvarious cache state flags\n"
370b5fca8f8Stomee "CFLAG\t\tcache creation flags\n"
371b5fca8f8Stomee "BUFSIZE\tobject size in bytes\n"
372b5fca8f8Stomee "BUFTOTL\tcurrent total buffers in cache (allocated and free)\n");
373b5fca8f8Stomee }
3743893cb7fStomee
3753893cb7fStomee #define LABEL_WIDTH 11
3763893cb7fStomee static void
kmem_slabs_print_dist(uint_t * ks_bucket,size_t buffers_per_slab,size_t maxbuckets,size_t minbucketsize)3773893cb7fStomee kmem_slabs_print_dist(uint_t *ks_bucket, size_t buffers_per_slab,
3783893cb7fStomee size_t maxbuckets, size_t minbucketsize)
3793893cb7fStomee {
3803893cb7fStomee uint64_t total;
3813893cb7fStomee int buckets;
3823893cb7fStomee int i;
3833893cb7fStomee const int *distarray;
3843893cb7fStomee int complete[2];
3853893cb7fStomee
3863893cb7fStomee buckets = buffers_per_slab;
3873893cb7fStomee
3883893cb7fStomee total = 0;
3893893cb7fStomee for (i = 0; i <= buffers_per_slab; i++)
3903893cb7fStomee total += ks_bucket[i];
3913893cb7fStomee
3923893cb7fStomee if (maxbuckets > 1)
3933893cb7fStomee buckets = MIN(buckets, maxbuckets);
3943893cb7fStomee
3953893cb7fStomee if (minbucketsize > 1) {
3963893cb7fStomee /*
3973893cb7fStomee * minbucketsize does not apply to the first bucket reserved
3983893cb7fStomee * for completely allocated slabs
3993893cb7fStomee */
4003893cb7fStomee buckets = MIN(buckets, 1 + ((buffers_per_slab - 1) /
4013893cb7fStomee minbucketsize));
4023893cb7fStomee if ((buckets < 2) && (buffers_per_slab > 1)) {
4033893cb7fStomee buckets = 2;
4043893cb7fStomee minbucketsize = (buffers_per_slab - 1);
4053893cb7fStomee }
4063893cb7fStomee }
4073893cb7fStomee
4083893cb7fStomee /*
4093893cb7fStomee * The first printed bucket is reserved for completely allocated slabs.
4103893cb7fStomee * Passing (buckets - 1) excludes that bucket from the generated
4113893cb7fStomee * distribution, since we're handling it as a special case.
4123893cb7fStomee */
4133893cb7fStomee complete[0] = buffers_per_slab;
4143893cb7fStomee complete[1] = buffers_per_slab + 1;
415087e1372Stomee distarray = dist_linear(buckets - 1, 1, buffers_per_slab - 1);
4163893cb7fStomee
4173893cb7fStomee mdb_printf("%*s\n", LABEL_WIDTH, "Allocated");
418087e1372Stomee dist_print_header("Buffers", LABEL_WIDTH, "Slabs");
4193893cb7fStomee
420087e1372Stomee dist_print_bucket(complete, 0, ks_bucket, total, LABEL_WIDTH);
4213893cb7fStomee /*
4223893cb7fStomee * Print bucket ranges in descending order after the first bucket for
4233893cb7fStomee * completely allocated slabs, so a person can see immediately whether
4243893cb7fStomee * or not there is fragmentation without having to scan possibly
4253893cb7fStomee * multiple screens of output. Starting at (buckets - 2) excludes the
4263893cb7fStomee * extra terminating bucket.
4273893cb7fStomee */
4283893cb7fStomee for (i = buckets - 2; i >= 0; i--) {
429087e1372Stomee dist_print_bucket(distarray, i, ks_bucket, total, LABEL_WIDTH);
4303893cb7fStomee }
4313893cb7fStomee mdb_printf("\n");
4323893cb7fStomee }
4333893cb7fStomee #undef LABEL_WIDTH
4343893cb7fStomee
4353893cb7fStomee /*ARGSUSED*/
4363893cb7fStomee static int
kmem_first_slab(uintptr_t addr,const kmem_slab_t * sp,boolean_t * is_slab)4373893cb7fStomee kmem_first_slab(uintptr_t addr, const kmem_slab_t *sp, boolean_t *is_slab)
4383893cb7fStomee {
4393893cb7fStomee *is_slab = B_TRUE;
4403893cb7fStomee return (WALK_DONE);
4413893cb7fStomee }
4423893cb7fStomee
4433893cb7fStomee /*ARGSUSED*/
4443893cb7fStomee static int
kmem_first_partial_slab(uintptr_t addr,const kmem_slab_t * sp,boolean_t * is_slab)4453893cb7fStomee kmem_first_partial_slab(uintptr_t addr, const kmem_slab_t *sp,
4463893cb7fStomee boolean_t *is_slab)
4473893cb7fStomee {
4483893cb7fStomee /*
449b5fca8f8Stomee * The "kmem_partial_slab" walker reports the first full slab if there
4503893cb7fStomee * are no partial slabs (for the sake of consumers that require at least
4513893cb7fStomee * one callback if there are any buffers in the cache).
4523893cb7fStomee */
453b5fca8f8Stomee *is_slab = KMEM_SLAB_IS_PARTIAL(sp);
4543893cb7fStomee return (WALK_DONE);
4553893cb7fStomee }
4563893cb7fStomee
457b5fca8f8Stomee typedef struct kmem_slab_usage {
458b5fca8f8Stomee int ksu_refcnt; /* count of allocated buffers on slab */
459b5fca8f8Stomee boolean_t ksu_nomove; /* slab marked non-reclaimable */
460b5fca8f8Stomee } kmem_slab_usage_t;
461b5fca8f8Stomee
462b5fca8f8Stomee typedef struct kmem_slab_stats {
463b5fca8f8Stomee const kmem_cache_t *ks_cp;
464b5fca8f8Stomee int ks_slabs; /* slabs in cache */
465b5fca8f8Stomee int ks_partial_slabs; /* partially allocated slabs in cache */
466b5fca8f8Stomee uint64_t ks_unused_buffers; /* total unused buffers in cache */
467b5fca8f8Stomee int ks_max_buffers_per_slab; /* max buffers per slab */
468b5fca8f8Stomee int ks_usage_len; /* ks_usage array length */
469b5fca8f8Stomee kmem_slab_usage_t *ks_usage; /* partial slab usage */
470b5fca8f8Stomee uint_t *ks_bucket; /* slab usage distribution */
471b5fca8f8Stomee } kmem_slab_stats_t;
472b5fca8f8Stomee
4733893cb7fStomee /*ARGSUSED*/
4743893cb7fStomee static int
kmem_slablist_stat(uintptr_t addr,const kmem_slab_t * sp,kmem_slab_stats_t * ks)4753893cb7fStomee kmem_slablist_stat(uintptr_t addr, const kmem_slab_t *sp,
4763893cb7fStomee kmem_slab_stats_t *ks)
4773893cb7fStomee {
4783893cb7fStomee kmem_slab_usage_t *ksu;
4793893cb7fStomee long unused;
4803893cb7fStomee
4813893cb7fStomee ks->ks_slabs++;
4823893cb7fStomee ks->ks_bucket[sp->slab_refcnt]++;
4833893cb7fStomee
4843893cb7fStomee unused = (sp->slab_chunks - sp->slab_refcnt);
4853893cb7fStomee if (unused == 0) {
4863893cb7fStomee return (WALK_NEXT);
4873893cb7fStomee }
4883893cb7fStomee
4893893cb7fStomee ks->ks_partial_slabs++;
4903893cb7fStomee ks->ks_unused_buffers += unused;
4913893cb7fStomee
4923893cb7fStomee if (ks->ks_partial_slabs > ks->ks_usage_len) {
4933893cb7fStomee kmem_slab_usage_t *usage;
4943893cb7fStomee int len = ks->ks_usage_len;
4953893cb7fStomee
4963893cb7fStomee len = (len == 0 ? 16 : len * 2);
4973893cb7fStomee usage = mdb_zalloc(len * sizeof (kmem_slab_usage_t), UM_SLEEP);
4983893cb7fStomee if (ks->ks_usage != NULL) {
4993893cb7fStomee bcopy(ks->ks_usage, usage,
5003893cb7fStomee ks->ks_usage_len * sizeof (kmem_slab_usage_t));
5013893cb7fStomee mdb_free(ks->ks_usage,
5023893cb7fStomee ks->ks_usage_len * sizeof (kmem_slab_usage_t));
5033893cb7fStomee }
5043893cb7fStomee ks->ks_usage = usage;
5053893cb7fStomee ks->ks_usage_len = len;
5063893cb7fStomee }
5073893cb7fStomee
5083893cb7fStomee ksu = &ks->ks_usage[ks->ks_partial_slabs - 1];
5093893cb7fStomee ksu->ksu_refcnt = sp->slab_refcnt;
510b5fca8f8Stomee ksu->ksu_nomove = (sp->slab_flags & KMEM_SLAB_NOMOVE);
5113893cb7fStomee return (WALK_NEXT);
5123893cb7fStomee }
5133893cb7fStomee
5143893cb7fStomee static void
kmem_slabs_header()5153893cb7fStomee kmem_slabs_header()
5163893cb7fStomee {
5173893cb7fStomee mdb_printf("%-25s %8s %8s %9s %9s %6s\n",
5183893cb7fStomee "", "", "Partial", "", "Unused", "");
5193893cb7fStomee mdb_printf("%-25s %8s %8s %9s %9s %6s\n",
5203893cb7fStomee "Cache Name", "Slabs", "Slabs", "Buffers", "Buffers", "Waste");
5213893cb7fStomee mdb_printf("%-25s %8s %8s %9s %9s %6s\n",
5223893cb7fStomee "-------------------------", "--------", "--------", "---------",
5233893cb7fStomee "---------", "------");
5243893cb7fStomee }
5253893cb7fStomee
5263893cb7fStomee int
kmem_slabs(uintptr_t addr,uint_t flags,int argc,const mdb_arg_t * argv)5273893cb7fStomee kmem_slabs(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
5283893cb7fStomee {
5293893cb7fStomee kmem_cache_t c;
5303893cb7fStomee kmem_slab_stats_t stats;
5313893cb7fStomee mdb_walk_cb_t cb;
5323893cb7fStomee int pct;
5333893cb7fStomee int tenths_pct;
5343893cb7fStomee size_t maxbuckets = 1;
5353893cb7fStomee size_t minbucketsize = 0;
5363893cb7fStomee const char *filter = NULL;
537b5fca8f8Stomee const char *name = NULL;
5383893cb7fStomee uint_t opt_v = FALSE;
539b5fca8f8Stomee boolean_t buckets = B_FALSE;
5403893cb7fStomee boolean_t skip = B_FALSE;
5413893cb7fStomee
5423893cb7fStomee if (mdb_getopts(argc, argv,
5433893cb7fStomee 'B', MDB_OPT_UINTPTR, &minbucketsize,
5443893cb7fStomee 'b', MDB_OPT_UINTPTR, &maxbuckets,
5453893cb7fStomee 'n', MDB_OPT_STR, &filter,
546b5fca8f8Stomee 'N', MDB_OPT_STR, &name,
5473893cb7fStomee 'v', MDB_OPT_SETBITS, TRUE, &opt_v,
5483893cb7fStomee NULL) != argc) {
5493893cb7fStomee return (DCMD_USAGE);
5503893cb7fStomee }
5513893cb7fStomee
552b5fca8f8Stomee if ((maxbuckets != 1) || (minbucketsize != 0)) {
553b5fca8f8Stomee buckets = B_TRUE;
5543893cb7fStomee }
5553893cb7fStomee
5563893cb7fStomee if (!(flags & DCMD_ADDRSPEC)) {
5573893cb7fStomee if (mdb_walk_dcmd("kmem_cache", "kmem_slabs", argc,
5583893cb7fStomee argv) == -1) {
5593893cb7fStomee mdb_warn("can't walk kmem_cache");
5603893cb7fStomee return (DCMD_ERR);
5613893cb7fStomee }
5623893cb7fStomee return (DCMD_OK);
5633893cb7fStomee }
5643893cb7fStomee
5653893cb7fStomee if (mdb_vread(&c, sizeof (c), addr) == -1) {
5663893cb7fStomee mdb_warn("couldn't read kmem_cache at %p", addr);
5673893cb7fStomee return (DCMD_ERR);
5683893cb7fStomee }
5693893cb7fStomee
570b5fca8f8Stomee if (name == NULL) {
571b5fca8f8Stomee skip = ((filter != NULL) &&
572b5fca8f8Stomee (strstr(c.cache_name, filter) == NULL));
573b5fca8f8Stomee } else if (filter == NULL) {
574b5fca8f8Stomee skip = (strcmp(c.cache_name, name) != 0);
575b5fca8f8Stomee } else {
576b5fca8f8Stomee /* match either -n or -N */
577b5fca8f8Stomee skip = ((strcmp(c.cache_name, name) != 0) &&
578b5fca8f8Stomee (strstr(c.cache_name, filter) == NULL));
5793893cb7fStomee }
5803893cb7fStomee
581b5fca8f8Stomee if (!(opt_v || buckets) && DCMD_HDRSPEC(flags)) {
5823893cb7fStomee kmem_slabs_header();
583b5fca8f8Stomee } else if ((opt_v || buckets) && !skip) {
5843893cb7fStomee if (DCMD_HDRSPEC(flags)) {
5853893cb7fStomee kmem_slabs_header();
5863893cb7fStomee } else {
5873893cb7fStomee boolean_t is_slab = B_FALSE;
5883893cb7fStomee const char *walker_name;
5893893cb7fStomee if (opt_v) {
5903893cb7fStomee cb = (mdb_walk_cb_t)kmem_first_partial_slab;
5913893cb7fStomee walker_name = "kmem_slab_partial";
5923893cb7fStomee } else {
5933893cb7fStomee cb = (mdb_walk_cb_t)kmem_first_slab;
5943893cb7fStomee walker_name = "kmem_slab";
5953893cb7fStomee }
5963893cb7fStomee (void) mdb_pwalk(walker_name, cb, &is_slab, addr);
5973893cb7fStomee if (is_slab) {
5983893cb7fStomee kmem_slabs_header();
5993893cb7fStomee }
6003893cb7fStomee }
6013893cb7fStomee }
6023893cb7fStomee
6033893cb7fStomee if (skip) {
6043893cb7fStomee return (DCMD_OK);
6053893cb7fStomee }
6063893cb7fStomee
6073893cb7fStomee bzero(&stats, sizeof (kmem_slab_stats_t));
608b5fca8f8Stomee stats.ks_cp = &c;
609b5fca8f8Stomee stats.ks_max_buffers_per_slab = c.cache_maxchunks;
610b5fca8f8Stomee /* +1 to include a zero bucket */
611b5fca8f8Stomee stats.ks_bucket = mdb_zalloc((stats.ks_max_buffers_per_slab + 1) *
612b5fca8f8Stomee sizeof (*stats.ks_bucket), UM_SLEEP);
6133893cb7fStomee cb = (mdb_walk_cb_t)kmem_slablist_stat;
6143893cb7fStomee (void) mdb_pwalk("kmem_slab", cb, &stats, addr);
6153893cb7fStomee
6163893cb7fStomee if (c.cache_buftotal == 0) {
6173893cb7fStomee pct = 0;
6183893cb7fStomee tenths_pct = 0;
6193893cb7fStomee } else {
6203893cb7fStomee uint64_t n = stats.ks_unused_buffers * 10000;
6213893cb7fStomee pct = (int)(n / c.cache_buftotal);
6223893cb7fStomee tenths_pct = pct - ((pct / 100) * 100);
6233893cb7fStomee tenths_pct = (tenths_pct + 5) / 10; /* round nearest tenth */
6243893cb7fStomee if (tenths_pct == 10) {
6253893cb7fStomee pct += 100;
6263893cb7fStomee tenths_pct = 0;
6273893cb7fStomee }
6283893cb7fStomee }
6293893cb7fStomee
6303893cb7fStomee pct /= 100;
6313893cb7fStomee mdb_printf("%-25s %8d %8d %9lld %9lld %3d.%1d%%\n", c.cache_name,
6323893cb7fStomee stats.ks_slabs, stats.ks_partial_slabs, c.cache_buftotal,
6333893cb7fStomee stats.ks_unused_buffers, pct, tenths_pct);
6343893cb7fStomee
6353893cb7fStomee if (maxbuckets == 0) {
636b5fca8f8Stomee maxbuckets = stats.ks_max_buffers_per_slab;
6373893cb7fStomee }
6383893cb7fStomee
6393893cb7fStomee if (((maxbuckets > 1) || (minbucketsize > 0)) &&
6403893cb7fStomee (stats.ks_slabs > 0)) {
6413893cb7fStomee mdb_printf("\n");
6423893cb7fStomee kmem_slabs_print_dist(stats.ks_bucket,
643b5fca8f8Stomee stats.ks_max_buffers_per_slab, maxbuckets, minbucketsize);
644b5fca8f8Stomee }
645b5fca8f8Stomee
646b5fca8f8Stomee mdb_free(stats.ks_bucket, (stats.ks_max_buffers_per_slab + 1) *
647b5fca8f8Stomee sizeof (*stats.ks_bucket));
648b5fca8f8Stomee
649b5fca8f8Stomee if (!opt_v) {
650b5fca8f8Stomee return (DCMD_OK);
6513893cb7fStomee }
6523893cb7fStomee
6533893cb7fStomee if (opt_v && (stats.ks_partial_slabs > 0)) {
6543893cb7fStomee int i;
6553893cb7fStomee kmem_slab_usage_t *ksu;
6563893cb7fStomee
657686031edSTom Erickson mdb_printf(" %d complete (%d), %d partial:",
6583893cb7fStomee (stats.ks_slabs - stats.ks_partial_slabs),
659686031edSTom Erickson stats.ks_max_buffers_per_slab,
6603893cb7fStomee stats.ks_partial_slabs);
661686031edSTom Erickson
6623893cb7fStomee for (i = 0; i < stats.ks_partial_slabs; i++) {
6633893cb7fStomee ksu = &stats.ks_usage[i];
664686031edSTom Erickson mdb_printf(" %d%s", ksu->ksu_refcnt,
665686031edSTom Erickson (ksu->ksu_nomove ? "*" : ""));
6663893cb7fStomee }
6673893cb7fStomee mdb_printf("\n\n");
6683893cb7fStomee }
6693893cb7fStomee
6703893cb7fStomee if (stats.ks_usage_len > 0) {
6713893cb7fStomee mdb_free(stats.ks_usage,
6723893cb7fStomee stats.ks_usage_len * sizeof (kmem_slab_usage_t));
6733893cb7fStomee }
6743893cb7fStomee
6753893cb7fStomee return (DCMD_OK);
6763893cb7fStomee }
6773893cb7fStomee
6783893cb7fStomee void
kmem_slabs_help(void)6793893cb7fStomee kmem_slabs_help(void)
6803893cb7fStomee {
681b5fca8f8Stomee mdb_printf("%s",
682b5fca8f8Stomee "Display slab usage per kmem cache.\n\n");
6833893cb7fStomee mdb_dec_indent(2);
6843893cb7fStomee mdb_printf("%<b>OPTIONS%</b>\n");
6853893cb7fStomee mdb_inc_indent(2);
6863893cb7fStomee mdb_printf("%s",
6873893cb7fStomee " -n name\n"
6883893cb7fStomee " name of kmem cache (or matching partial name)\n"
689b5fca8f8Stomee " -N name\n"
690b5fca8f8Stomee " exact name of kmem cache\n"
6913893cb7fStomee " -b maxbins\n"
6923893cb7fStomee " Print a distribution of allocated buffers per slab using at\n"
6933893cb7fStomee " most maxbins bins. The first bin is reserved for completely\n"
6943893cb7fStomee " allocated slabs. Setting maxbins to zero (-b 0) has the same\n"
6953893cb7fStomee " effect as specifying the maximum allocated buffers per slab\n"
6963893cb7fStomee " or setting minbinsize to 1 (-B 1).\n"
6973893cb7fStomee " -B minbinsize\n"
6983893cb7fStomee " Print a distribution of allocated buffers per slab, making\n"
6993893cb7fStomee " all bins (except the first, reserved for completely allocated\n"
7003893cb7fStomee " slabs) at least minbinsize buffers apart.\n"
7013893cb7fStomee " -v verbose output: List the allocated buffer count of each partial\n"
7023893cb7fStomee " slab on the free list in order from front to back to show how\n"
7033893cb7fStomee " closely the slabs are ordered by usage. For example\n"
7043893cb7fStomee "\n"
7053893cb7fStomee " 10 complete, 3 partial (8): 7 3 1\n"
7063893cb7fStomee "\n"
7073893cb7fStomee " means there are thirteen slabs with eight buffers each, including\n"
7083893cb7fStomee " three partially allocated slabs with less than all eight buffers\n"
7093893cb7fStomee " allocated.\n"
7103893cb7fStomee "\n"
7113893cb7fStomee " Buffer allocations are always from the front of the partial slab\n"
7123893cb7fStomee " list. When a buffer is freed from a completely used slab, that\n"
7133893cb7fStomee " slab is added to the front of the partial slab list. Assuming\n"
7143893cb7fStomee " that all buffers are equally likely to be freed soon, the\n"
7153893cb7fStomee " desired order of partial slabs is most-used at the front of the\n"
7163893cb7fStomee " list and least-used at the back (as in the example above).\n"
7173893cb7fStomee " However, if a slab contains an allocated buffer that will not\n"
7183893cb7fStomee " soon be freed, it would be better for that slab to be at the\n"
719b5fca8f8Stomee " front where all of its buffers can be allocated. Taking a slab\n"
720b5fca8f8Stomee " off the partial slab list (either with all buffers freed or all\n"
721b5fca8f8Stomee " buffers allocated) reduces cache fragmentation.\n"
722b5fca8f8Stomee "\n"
723b5fca8f8Stomee " A slab's allocated buffer count representing a partial slab (9 in\n"
724b5fca8f8Stomee " the example below) may be marked as follows:\n"
725b5fca8f8Stomee "\n"
726b5fca8f8Stomee " 9* An asterisk indicates that kmem has marked the slab non-\n"
727b5fca8f8Stomee " reclaimable because the kmem client refused to move one of the\n"
728b5fca8f8Stomee " slab's buffers. Since kmem does not expect to completely free the\n"
729b5fca8f8Stomee " slab, it moves it to the front of the list in the hope of\n"
730b5fca8f8Stomee " completely allocating it instead. A slab marked with an asterisk\n"
731b5fca8f8Stomee " stays marked for as long as it remains on the partial slab list.\n"
7323893cb7fStomee "\n"
7333893cb7fStomee "Column\t\tDescription\n"
7343893cb7fStomee "\n"
7353893cb7fStomee "Cache Name\t\tname of kmem cache\n"
7363893cb7fStomee "Slabs\t\t\ttotal slab count\n"
7373893cb7fStomee "Partial Slabs\t\tcount of partially allocated slabs on the free list\n"
7383893cb7fStomee "Buffers\t\ttotal buffer count (Slabs * (buffers per slab))\n"
7393893cb7fStomee "Unused Buffers\tcount of unallocated buffers across all partial slabs\n"
7403893cb7fStomee "Waste\t\t\t(Unused Buffers / Buffers) does not include space\n"
7413893cb7fStomee "\t\t\t for accounting structures (debug mode), slab\n"
7423893cb7fStomee "\t\t\t coloring (incremental small offsets to stagger\n"
7433893cb7fStomee "\t\t\t buffer alignment), or the per-CPU magazine layer\n");
7443893cb7fStomee }
7453893cb7fStomee
7467c478bd9Sstevel@tonic-gate static int
addrcmp(const void * lhs,const void * rhs)7477c478bd9Sstevel@tonic-gate addrcmp(const void *lhs, const void *rhs)
7487c478bd9Sstevel@tonic-gate {
7497c478bd9Sstevel@tonic-gate uintptr_t p1 = *((uintptr_t *)lhs);
7507c478bd9Sstevel@tonic-gate uintptr_t p2 = *((uintptr_t *)rhs);
7517c478bd9Sstevel@tonic-gate
7527c478bd9Sstevel@tonic-gate if (p1 < p2)
7537c478bd9Sstevel@tonic-gate return (-1);
7547c478bd9Sstevel@tonic-gate if (p1 > p2)
7557c478bd9Sstevel@tonic-gate return (1);
7567c478bd9Sstevel@tonic-gate return (0);
7577c478bd9Sstevel@tonic-gate }
7587c478bd9Sstevel@tonic-gate
7597c478bd9Sstevel@tonic-gate static int
bufctlcmp(const kmem_bufctl_audit_t ** lhs,const kmem_bufctl_audit_t ** rhs)7607c478bd9Sstevel@tonic-gate bufctlcmp(const kmem_bufctl_audit_t **lhs, const kmem_bufctl_audit_t **rhs)
7617c478bd9Sstevel@tonic-gate {
7627c478bd9Sstevel@tonic-gate const kmem_bufctl_audit_t *bcp1 = *lhs;
7637c478bd9Sstevel@tonic-gate const kmem_bufctl_audit_t *bcp2 = *rhs;
7647c478bd9Sstevel@tonic-gate
7657c478bd9Sstevel@tonic-gate if (bcp1->bc_timestamp > bcp2->bc_timestamp)
7667c478bd9Sstevel@tonic-gate return (-1);
7677c478bd9Sstevel@tonic-gate
7687c478bd9Sstevel@tonic-gate if (bcp1->bc_timestamp < bcp2->bc_timestamp)
7697c478bd9Sstevel@tonic-gate return (1);
7707c478bd9Sstevel@tonic-gate
7717c478bd9Sstevel@tonic-gate return (0);
7727c478bd9Sstevel@tonic-gate }
7737c478bd9Sstevel@tonic-gate
7747c478bd9Sstevel@tonic-gate typedef struct kmem_hash_walk {
7757c478bd9Sstevel@tonic-gate uintptr_t *kmhw_table;
7767c478bd9Sstevel@tonic-gate size_t kmhw_nelems;
7777c478bd9Sstevel@tonic-gate size_t kmhw_pos;
7787c478bd9Sstevel@tonic-gate kmem_bufctl_t kmhw_cur;
7797c478bd9Sstevel@tonic-gate } kmem_hash_walk_t;
7807c478bd9Sstevel@tonic-gate
7817c478bd9Sstevel@tonic-gate int
kmem_hash_walk_init(mdb_walk_state_t * wsp)7827c478bd9Sstevel@tonic-gate kmem_hash_walk_init(mdb_walk_state_t *wsp)
7837c478bd9Sstevel@tonic-gate {
7847c478bd9Sstevel@tonic-gate kmem_hash_walk_t *kmhw;
7857c478bd9Sstevel@tonic-gate uintptr_t *hash;
7867c478bd9Sstevel@tonic-gate kmem_cache_t c;
7877c478bd9Sstevel@tonic-gate uintptr_t haddr, addr = wsp->walk_addr;
7887c478bd9Sstevel@tonic-gate size_t nelems;
7897c478bd9Sstevel@tonic-gate size_t hsize;
7907c478bd9Sstevel@tonic-gate
791892ad162SToomas Soome if (addr == 0) {
7927c478bd9Sstevel@tonic-gate mdb_warn("kmem_hash doesn't support global walks\n");
7937c478bd9Sstevel@tonic-gate return (WALK_ERR);
7947c478bd9Sstevel@tonic-gate }
7957c478bd9Sstevel@tonic-gate
7967c478bd9Sstevel@tonic-gate if (mdb_vread(&c, sizeof (c), addr) == -1) {
7977c478bd9Sstevel@tonic-gate mdb_warn("couldn't read cache at addr %p", addr);
7987c478bd9Sstevel@tonic-gate return (WALK_ERR);
7997c478bd9Sstevel@tonic-gate }
8007c478bd9Sstevel@tonic-gate
8017c478bd9Sstevel@tonic-gate if (!(c.cache_flags & KMF_HASH)) {
8027c478bd9Sstevel@tonic-gate mdb_warn("cache %p doesn't have a hash table\n", addr);
8037c478bd9Sstevel@tonic-gate return (WALK_DONE); /* nothing to do */
8047c478bd9Sstevel@tonic-gate }
8057c478bd9Sstevel@tonic-gate
8067c478bd9Sstevel@tonic-gate kmhw = mdb_zalloc(sizeof (kmem_hash_walk_t), UM_SLEEP);
8077c478bd9Sstevel@tonic-gate kmhw->kmhw_cur.bc_next = NULL;
8087c478bd9Sstevel@tonic-gate kmhw->kmhw_pos = 0;
8097c478bd9Sstevel@tonic-gate
8107c478bd9Sstevel@tonic-gate kmhw->kmhw_nelems = nelems = c.cache_hash_mask + 1;
8117c478bd9Sstevel@tonic-gate hsize = nelems * sizeof (uintptr_t);
8127c478bd9Sstevel@tonic-gate haddr = (uintptr_t)c.cache_hash_table;
8137c478bd9Sstevel@tonic-gate
8147c478bd9Sstevel@tonic-gate kmhw->kmhw_table = hash = mdb_alloc(hsize, UM_SLEEP);
8157c478bd9Sstevel@tonic-gate if (mdb_vread(hash, hsize, haddr) == -1) {
8167c478bd9Sstevel@tonic-gate mdb_warn("failed to read hash table at %p", haddr);
8177c478bd9Sstevel@tonic-gate mdb_free(hash, hsize);
8187c478bd9Sstevel@tonic-gate mdb_free(kmhw, sizeof (kmem_hash_walk_t));
8197c478bd9Sstevel@tonic-gate return (WALK_ERR);
8207c478bd9Sstevel@tonic-gate }
8217c478bd9Sstevel@tonic-gate
8227c478bd9Sstevel@tonic-gate wsp->walk_data = kmhw;
8237c478bd9Sstevel@tonic-gate
8247c478bd9Sstevel@tonic-gate return (WALK_NEXT);
8257c478bd9Sstevel@tonic-gate }
8267c478bd9Sstevel@tonic-gate
8277c478bd9Sstevel@tonic-gate int
kmem_hash_walk_step(mdb_walk_state_t * wsp)8287c478bd9Sstevel@tonic-gate kmem_hash_walk_step(mdb_walk_state_t *wsp)
8297c478bd9Sstevel@tonic-gate {
8307c478bd9Sstevel@tonic-gate kmem_hash_walk_t *kmhw = wsp->walk_data;
831892ad162SToomas Soome uintptr_t addr = 0;
8327c478bd9Sstevel@tonic-gate
833892ad162SToomas Soome if ((addr = (uintptr_t)kmhw->kmhw_cur.bc_next) == 0) {
8347c478bd9Sstevel@tonic-gate while (kmhw->kmhw_pos < kmhw->kmhw_nelems) {
835892ad162SToomas Soome if ((addr = kmhw->kmhw_table[kmhw->kmhw_pos++]) != 0)
8367c478bd9Sstevel@tonic-gate break;
8377c478bd9Sstevel@tonic-gate }
8387c478bd9Sstevel@tonic-gate }
839892ad162SToomas Soome if (addr == 0)
8407c478bd9Sstevel@tonic-gate return (WALK_DONE);
8417c478bd9Sstevel@tonic-gate
8427c478bd9Sstevel@tonic-gate if (mdb_vread(&kmhw->kmhw_cur, sizeof (kmem_bufctl_t), addr) == -1) {
8437c478bd9Sstevel@tonic-gate mdb_warn("couldn't read kmem_bufctl_t at addr %p", addr);
8447c478bd9Sstevel@tonic-gate return (WALK_ERR);
8457c478bd9Sstevel@tonic-gate }
8467c478bd9Sstevel@tonic-gate
8477c478bd9Sstevel@tonic-gate return (wsp->walk_callback(addr, &kmhw->kmhw_cur, wsp->walk_cbdata));
8487c478bd9Sstevel@tonic-gate }
8497c478bd9Sstevel@tonic-gate
8507c478bd9Sstevel@tonic-gate void
kmem_hash_walk_fini(mdb_walk_state_t * wsp)8517c478bd9Sstevel@tonic-gate kmem_hash_walk_fini(mdb_walk_state_t *wsp)
8527c478bd9Sstevel@tonic-gate {
8537c478bd9Sstevel@tonic-gate kmem_hash_walk_t *kmhw = wsp->walk_data;
8547c478bd9Sstevel@tonic-gate
8557c478bd9Sstevel@tonic-gate if (kmhw == NULL)
8567c478bd9Sstevel@tonic-gate return;
8577c478bd9Sstevel@tonic-gate
8587c478bd9Sstevel@tonic-gate mdb_free(kmhw->kmhw_table, kmhw->kmhw_nelems * sizeof (uintptr_t));
8597c478bd9Sstevel@tonic-gate mdb_free(kmhw, sizeof (kmem_hash_walk_t));
8607c478bd9Sstevel@tonic-gate }
8617c478bd9Sstevel@tonic-gate
8627c478bd9Sstevel@tonic-gate /*
8637c478bd9Sstevel@tonic-gate * Find the address of the bufctl structure for the address 'buf' in cache
8647c478bd9Sstevel@tonic-gate * 'cp', which is at address caddr, and place it in *out.
8657c478bd9Sstevel@tonic-gate */
8667c478bd9Sstevel@tonic-gate static int
kmem_hash_lookup(kmem_cache_t * cp,uintptr_t caddr,void * buf,uintptr_t * out)8677c478bd9Sstevel@tonic-gate kmem_hash_lookup(kmem_cache_t *cp, uintptr_t caddr, void *buf, uintptr_t *out)
8687c478bd9Sstevel@tonic-gate {
8697c478bd9Sstevel@tonic-gate uintptr_t bucket = (uintptr_t)KMEM_HASH(cp, buf);
8707c478bd9Sstevel@tonic-gate kmem_bufctl_t *bcp;
8717c478bd9Sstevel@tonic-gate kmem_bufctl_t bc;
8727c478bd9Sstevel@tonic-gate
8737c478bd9Sstevel@tonic-gate if (mdb_vread(&bcp, sizeof (kmem_bufctl_t *), bucket) == -1) {
8747c478bd9Sstevel@tonic-gate mdb_warn("unable to read hash bucket for %p in cache %p",
8757c478bd9Sstevel@tonic-gate buf, caddr);
8767c478bd9Sstevel@tonic-gate return (-1);
8777c478bd9Sstevel@tonic-gate }
8787c478bd9Sstevel@tonic-gate
8797c478bd9Sstevel@tonic-gate while (bcp != NULL) {
8807c478bd9Sstevel@tonic-gate if (mdb_vread(&bc, sizeof (kmem_bufctl_t),
8817c478bd9Sstevel@tonic-gate (uintptr_t)bcp) == -1) {
8827c478bd9Sstevel@tonic-gate mdb_warn("unable to read bufctl at %p", bcp);
8837c478bd9Sstevel@tonic-gate return (-1);
8847c478bd9Sstevel@tonic-gate }
8857c478bd9Sstevel@tonic-gate if (bc.bc_addr == buf) {
8867c478bd9Sstevel@tonic-gate *out = (uintptr_t)bcp;
8877c478bd9Sstevel@tonic-gate return (0);
8887c478bd9Sstevel@tonic-gate }
8897c478bd9Sstevel@tonic-gate bcp = bc.bc_next;
8907c478bd9Sstevel@tonic-gate }
8917c478bd9Sstevel@tonic-gate
8927c478bd9Sstevel@tonic-gate mdb_warn("unable to find bufctl for %p in cache %p\n", buf, caddr);
8937c478bd9Sstevel@tonic-gate return (-1);
8947c478bd9Sstevel@tonic-gate }
8957c478bd9Sstevel@tonic-gate
8967c478bd9Sstevel@tonic-gate int
kmem_get_magsize(const kmem_cache_t * cp)8977c478bd9Sstevel@tonic-gate kmem_get_magsize(const kmem_cache_t *cp)
8987c478bd9Sstevel@tonic-gate {
8997c478bd9Sstevel@tonic-gate uintptr_t addr = (uintptr_t)cp->cache_magtype;
9007c478bd9Sstevel@tonic-gate GElf_Sym mt_sym;
9017c478bd9Sstevel@tonic-gate kmem_magtype_t mt;
9027c478bd9Sstevel@tonic-gate int res;
9037c478bd9Sstevel@tonic-gate
9047c478bd9Sstevel@tonic-gate /*
9057c478bd9Sstevel@tonic-gate * if cpu 0 has a non-zero magsize, it must be correct. caches
9067c478bd9Sstevel@tonic-gate * with KMF_NOMAGAZINE have disabled their magazine layers, so
9077c478bd9Sstevel@tonic-gate * it is okay to return 0 for them.
9087c478bd9Sstevel@tonic-gate */
9097c478bd9Sstevel@tonic-gate if ((res = cp->cache_cpu[0].cc_magsize) != 0 ||
9107c478bd9Sstevel@tonic-gate (cp->cache_flags & KMF_NOMAGAZINE))
9117c478bd9Sstevel@tonic-gate return (res);
9127c478bd9Sstevel@tonic-gate
9137c478bd9Sstevel@tonic-gate if (mdb_lookup_by_name("kmem_magtype", &mt_sym) == -1) {
9147c478bd9Sstevel@tonic-gate mdb_warn("unable to read 'kmem_magtype'");
9157c478bd9Sstevel@tonic-gate } else if (addr < mt_sym.st_value ||
9167c478bd9Sstevel@tonic-gate addr + sizeof (mt) - 1 > mt_sym.st_value + mt_sym.st_size - 1 ||
9177c478bd9Sstevel@tonic-gate ((addr - mt_sym.st_value) % sizeof (mt)) != 0) {
9187c478bd9Sstevel@tonic-gate mdb_warn("cache '%s' has invalid magtype pointer (%p)\n",
9197c478bd9Sstevel@tonic-gate cp->cache_name, addr);
9207c478bd9Sstevel@tonic-gate return (0);
9217c478bd9Sstevel@tonic-gate }
9227c478bd9Sstevel@tonic-gate if (mdb_vread(&mt, sizeof (mt), addr) == -1) {
9237c478bd9Sstevel@tonic-gate mdb_warn("unable to read magtype at %a", addr);
9247c478bd9Sstevel@tonic-gate return (0);
9257c478bd9Sstevel@tonic-gate }
9267c478bd9Sstevel@tonic-gate return (mt.mt_magsize);
9277c478bd9Sstevel@tonic-gate }
9287c478bd9Sstevel@tonic-gate
9297c478bd9Sstevel@tonic-gate /*ARGSUSED*/
9307c478bd9Sstevel@tonic-gate static int
kmem_estimate_slab(uintptr_t addr,const kmem_slab_t * sp,size_t * est)9317c478bd9Sstevel@tonic-gate kmem_estimate_slab(uintptr_t addr, const kmem_slab_t *sp, size_t *est)
9327c478bd9Sstevel@tonic-gate {
9337c478bd9Sstevel@tonic-gate *est -= (sp->slab_chunks - sp->slab_refcnt);
9347c478bd9Sstevel@tonic-gate
9357c478bd9Sstevel@tonic-gate return (WALK_NEXT);
9367c478bd9Sstevel@tonic-gate }
9377c478bd9Sstevel@tonic-gate
9387c478bd9Sstevel@tonic-gate /*
9397c478bd9Sstevel@tonic-gate * Returns an upper bound on the number of allocated buffers in a given
9407c478bd9Sstevel@tonic-gate * cache.
9417c478bd9Sstevel@tonic-gate */
9427c478bd9Sstevel@tonic-gate size_t
kmem_estimate_allocated(uintptr_t addr,const kmem_cache_t * cp)9437c478bd9Sstevel@tonic-gate kmem_estimate_allocated(uintptr_t addr, const kmem_cache_t *cp)
9447c478bd9Sstevel@tonic-gate {
9457c478bd9Sstevel@tonic-gate int magsize;
9467c478bd9Sstevel@tonic-gate size_t cache_est;
9477c478bd9Sstevel@tonic-gate
9487c478bd9Sstevel@tonic-gate cache_est = cp->cache_buftotal;
9497c478bd9Sstevel@tonic-gate
9507c478bd9Sstevel@tonic-gate (void) mdb_pwalk("kmem_slab_partial",
9517c478bd9Sstevel@tonic-gate (mdb_walk_cb_t)kmem_estimate_slab, &cache_est, addr);
9527c478bd9Sstevel@tonic-gate
9537c478bd9Sstevel@tonic-gate if ((magsize = kmem_get_magsize(cp)) != 0) {
9547c478bd9Sstevel@tonic-gate size_t mag_est = cp->cache_full.ml_total * magsize;
9557c478bd9Sstevel@tonic-gate
9567c478bd9Sstevel@tonic-gate if (cache_est >= mag_est) {
9577c478bd9Sstevel@tonic-gate cache_est -= mag_est;
9587c478bd9Sstevel@tonic-gate } else {
9597c478bd9Sstevel@tonic-gate mdb_warn("cache %p's magazine layer holds more buffers "
9607c478bd9Sstevel@tonic-gate "than the slab layer.\n", addr);
9617c478bd9Sstevel@tonic-gate }
9627c478bd9Sstevel@tonic-gate }
9637c478bd9Sstevel@tonic-gate return (cache_est);
9647c478bd9Sstevel@tonic-gate }
9657c478bd9Sstevel@tonic-gate
9667c478bd9Sstevel@tonic-gate #define READMAG_ROUNDS(rounds) { \
9677c478bd9Sstevel@tonic-gate if (mdb_vread(mp, magbsize, (uintptr_t)kmp) == -1) { \
9687c478bd9Sstevel@tonic-gate mdb_warn("couldn't read magazine at %p", kmp); \
9697c478bd9Sstevel@tonic-gate goto fail; \
9707c478bd9Sstevel@tonic-gate } \
9717c478bd9Sstevel@tonic-gate for (i = 0; i < rounds; i++) { \
9727c478bd9Sstevel@tonic-gate maglist[magcnt++] = mp->mag_round[i]; \
9737c478bd9Sstevel@tonic-gate if (magcnt == magmax) { \
9747c478bd9Sstevel@tonic-gate mdb_warn("%d magazines exceeds fudge factor\n", \
9757c478bd9Sstevel@tonic-gate magcnt); \
9767c478bd9Sstevel@tonic-gate goto fail; \
9777c478bd9Sstevel@tonic-gate } \
9787c478bd9Sstevel@tonic-gate } \
9797c478bd9Sstevel@tonic-gate }
9807c478bd9Sstevel@tonic-gate
9817c478bd9Sstevel@tonic-gate int
kmem_read_magazines(kmem_cache_t * cp,uintptr_t addr,int ncpus,void *** maglistp,size_t * magcntp,size_t * magmaxp,int alloc_flags)9827c478bd9Sstevel@tonic-gate kmem_read_magazines(kmem_cache_t *cp, uintptr_t addr, int ncpus,
9837c478bd9Sstevel@tonic-gate void ***maglistp, size_t *magcntp, size_t *magmaxp, int alloc_flags)
9847c478bd9Sstevel@tonic-gate {
9857c478bd9Sstevel@tonic-gate kmem_magazine_t *kmp, *mp;
9867c478bd9Sstevel@tonic-gate void **maglist = NULL;
9877c478bd9Sstevel@tonic-gate int i, cpu;
9887c478bd9Sstevel@tonic-gate size_t magsize, magmax, magbsize;
9897c478bd9Sstevel@tonic-gate size_t magcnt = 0;
9907c478bd9Sstevel@tonic-gate
9917c478bd9Sstevel@tonic-gate /*
9927c478bd9Sstevel@tonic-gate * Read the magtype out of the cache, after verifying the pointer's
9937c478bd9Sstevel@tonic-gate * correctness.
9947c478bd9Sstevel@tonic-gate */
9957c478bd9Sstevel@tonic-gate magsize = kmem_get_magsize(cp);
996789d94c2Sjwadams if (magsize == 0) {
997789d94c2Sjwadams *maglistp = NULL;
998789d94c2Sjwadams *magcntp = 0;
999789d94c2Sjwadams *magmaxp = 0;
1000789d94c2Sjwadams return (WALK_NEXT);
1001789d94c2Sjwadams }
10027c478bd9Sstevel@tonic-gate
10037c478bd9Sstevel@tonic-gate /*
10047c478bd9Sstevel@tonic-gate * There are several places where we need to go buffer hunting:
10057c478bd9Sstevel@tonic-gate * the per-CPU loaded magazine, the per-CPU spare full magazine,
10067c478bd9Sstevel@tonic-gate * and the full magazine list in the depot.
10077c478bd9Sstevel@tonic-gate *
10087c478bd9Sstevel@tonic-gate * For an upper bound on the number of buffers in the magazine
10097c478bd9Sstevel@tonic-gate * layer, we have the number of magazines on the cache_full
10107c478bd9Sstevel@tonic-gate * list plus at most two magazines per CPU (the loaded and the
10117c478bd9Sstevel@tonic-gate * spare). Toss in 100 magazines as a fudge factor in case this
10127c478bd9Sstevel@tonic-gate * is live (the number "100" comes from the same fudge factor in
10137c478bd9Sstevel@tonic-gate * crash(1M)).
10147c478bd9Sstevel@tonic-gate */
10157c478bd9Sstevel@tonic-gate magmax = (cp->cache_full.ml_total + 2 * ncpus + 100) * magsize;
10167c478bd9Sstevel@tonic-gate magbsize = offsetof(kmem_magazine_t, mag_round[magsize]);
10177c478bd9Sstevel@tonic-gate
10187c478bd9Sstevel@tonic-gate if (magbsize >= PAGESIZE / 2) {
10197c478bd9Sstevel@tonic-gate mdb_warn("magazine size for cache %p unreasonable (%x)\n",
10207c478bd9Sstevel@tonic-gate addr, magbsize);
1021789d94c2Sjwadams return (WALK_ERR);
10227c478bd9Sstevel@tonic-gate }
10237c478bd9Sstevel@tonic-gate
10247c478bd9Sstevel@tonic-gate maglist = mdb_alloc(magmax * sizeof (void *), alloc_flags);
10257c478bd9Sstevel@tonic-gate mp = mdb_alloc(magbsize, alloc_flags);
10267c478bd9Sstevel@tonic-gate if (mp == NULL || maglist == NULL)
10277c478bd9Sstevel@tonic-gate goto fail;
10287c478bd9Sstevel@tonic-gate
10297c478bd9Sstevel@tonic-gate /*
10307c478bd9Sstevel@tonic-gate * First up: the magazines in the depot (i.e. on the cache_full list).
10317c478bd9Sstevel@tonic-gate */
10327c478bd9Sstevel@tonic-gate for (kmp = cp->cache_full.ml_list; kmp != NULL; ) {
10337c478bd9Sstevel@tonic-gate READMAG_ROUNDS(magsize);
10347c478bd9Sstevel@tonic-gate kmp = mp->mag_next;
10357c478bd9Sstevel@tonic-gate
10367c478bd9Sstevel@tonic-gate if (kmp == cp->cache_full.ml_list)
10377c478bd9Sstevel@tonic-gate break; /* cache_full list loop detected */
10387c478bd9Sstevel@tonic-gate }
10397c478bd9Sstevel@tonic-gate
10407c478bd9Sstevel@tonic-gate dprintf(("cache_full list done\n"));
10417c478bd9Sstevel@tonic-gate
10427c478bd9Sstevel@tonic-gate /*
10437c478bd9Sstevel@tonic-gate * Now whip through the CPUs, snagging the loaded magazines
10447c478bd9Sstevel@tonic-gate * and full spares.
10459dd77bc8SDave Plauger *
10469dd77bc8SDave Plauger * In order to prevent inconsistent dumps, rounds and prounds
10479dd77bc8SDave Plauger * are copied aside before dumping begins.
10487c478bd9Sstevel@tonic-gate */
10497c478bd9Sstevel@tonic-gate for (cpu = 0; cpu < ncpus; cpu++) {
10507c478bd9Sstevel@tonic-gate kmem_cpu_cache_t *ccp = &cp->cache_cpu[cpu];
10519dd77bc8SDave Plauger short rounds, prounds;
10529dd77bc8SDave Plauger
10539dd77bc8SDave Plauger if (KMEM_DUMPCC(ccp)) {
10549dd77bc8SDave Plauger rounds = ccp->cc_dump_rounds;
10559dd77bc8SDave Plauger prounds = ccp->cc_dump_prounds;
10569dd77bc8SDave Plauger } else {
10579dd77bc8SDave Plauger rounds = ccp->cc_rounds;
10589dd77bc8SDave Plauger prounds = ccp->cc_prounds;
10599dd77bc8SDave Plauger }
10607c478bd9Sstevel@tonic-gate
10617c478bd9Sstevel@tonic-gate dprintf(("reading cpu cache %p\n",
10627c478bd9Sstevel@tonic-gate (uintptr_t)ccp - (uintptr_t)cp + addr));
10637c478bd9Sstevel@tonic-gate
10649dd77bc8SDave Plauger if (rounds > 0 &&
10657c478bd9Sstevel@tonic-gate (kmp = ccp->cc_loaded) != NULL) {
10669dd77bc8SDave Plauger dprintf(("reading %d loaded rounds\n", rounds));
10679dd77bc8SDave Plauger READMAG_ROUNDS(rounds);
10687c478bd9Sstevel@tonic-gate }
10697c478bd9Sstevel@tonic-gate
10709dd77bc8SDave Plauger if (prounds > 0 &&
10717c478bd9Sstevel@tonic-gate (kmp = ccp->cc_ploaded) != NULL) {
10727c478bd9Sstevel@tonic-gate dprintf(("reading %d previously loaded rounds\n",
10739dd77bc8SDave Plauger prounds));
10749dd77bc8SDave Plauger READMAG_ROUNDS(prounds);
10757c478bd9Sstevel@tonic-gate }
10767c478bd9Sstevel@tonic-gate }
10777c478bd9Sstevel@tonic-gate
10787c478bd9Sstevel@tonic-gate dprintf(("magazine layer: %d buffers\n", magcnt));
10797c478bd9Sstevel@tonic-gate
10807c478bd9Sstevel@tonic-gate if (!(alloc_flags & UM_GC))
10817c478bd9Sstevel@tonic-gate mdb_free(mp, magbsize);
10827c478bd9Sstevel@tonic-gate
10837c478bd9Sstevel@tonic-gate *maglistp = maglist;
10847c478bd9Sstevel@tonic-gate *magcntp = magcnt;
10857c478bd9Sstevel@tonic-gate *magmaxp = magmax;
10867c478bd9Sstevel@tonic-gate
10877c478bd9Sstevel@tonic-gate return (WALK_NEXT);
10887c478bd9Sstevel@tonic-gate
10897c478bd9Sstevel@tonic-gate fail:
10907c478bd9Sstevel@tonic-gate if (!(alloc_flags & UM_GC)) {
10917c478bd9Sstevel@tonic-gate if (mp)
10927c478bd9Sstevel@tonic-gate mdb_free(mp, magbsize);
10937c478bd9Sstevel@tonic-gate if (maglist)
10947c478bd9Sstevel@tonic-gate mdb_free(maglist, magmax * sizeof (void *));
1095