xref: /titanic_52/usr/src/cmd/mdb/common/modules/ufs/ufs.c (revision c7158ae983f5a04c4a998f468ecefba6d23ba721)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 /*
22  * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
23  * Use is subject to license terms.
24  */
25 
26 #pragma ident	"%Z%%M%	%I%	%E% SMI"
27 
28 #include <mdb/mdb_modapi.h>
29 #include <mdb/mdb_ks.h>
30 #include <sys/types.h>
31 #include <sys/sysmacros.h>
32 #include <sys/fs/ufs_inode.h>
33 #include <sys/fs/ufs_acl.h>
34 #include <sys/fs/ufs_fs.h>
35 
36 #include "ufs_cmds.h"
37 
38 typedef struct inode_walk_data {
39 	int iw_inohsz;
40 	int iw_inohcnt;
41 	uintptr_t iw_ihead;
42 	inode_t iw_inode;
43 } inode_walk_data_t;
44 
45 static int
46 inode_walk_init(mdb_walk_state_t *wsp)
47 {
48 	int inohsz;
49 	uintptr_t ihead;
50 	union ihead ih;
51 	inode_walk_data_t *iw;
52 
53 	if (wsp->walk_addr != NULL) {
54 		mdb_warn("inode_cache only supports global walks\n");
55 		return (WALK_ERR);
56 	}
57 
58 	if (mdb_readvar(&inohsz, "inohsz") == -1) {
59 		mdb_warn("failed to read 'inohsz'");
60 		return (WALK_ERR);
61 	}
62 
63 	if (inohsz == 0)
64 		return (WALK_DONE);
65 
66 	if (mdb_readvar(&ihead, "ihead") == -1) {
67 		mdb_warn("failed to read 'ihead'");
68 		return (WALK_ERR);
69 	}
70 
71 	if (mdb_vread(&ih, sizeof (union ihead), ihead) == -1) {
72 		mdb_warn("failed to read ihead at %p", ihead);
73 		return (WALK_DONE);
74 	}
75 
76 	iw = mdb_alloc(sizeof (inode_walk_data_t), UM_SLEEP);
77 	iw->iw_inohsz = inohsz;
78 	iw->iw_inohcnt = 0;
79 	iw->iw_ihead = ihead;
80 
81 	wsp->walk_addr = (uintptr_t)ih.ih_chain[0];
82 	wsp->walk_data = iw;
83 
84 	return (WALK_NEXT);
85 }
86 
87 static int
88 inode_walk_step(mdb_walk_state_t *wsp)
89 {
90 	uintptr_t addr = wsp->walk_addr;
91 	inode_walk_data_t *iw = wsp->walk_data;
92 	union ihead ih;
93 
94 	while (addr == iw->iw_ihead) {
95 		if (++iw->iw_inohcnt >= iw->iw_inohsz)
96 			return (WALK_DONE);
97 
98 		iw->iw_ihead += sizeof (union ihead);
99 
100 		if (mdb_vread(&ih, sizeof (union ihead), iw->iw_ihead) == -1) {
101 			mdb_warn("failed to read ihead at %p", iw->iw_ihead);
102 			return (WALK_DONE);
103 		}
104 		addr = (uintptr_t)ih.ih_chain[0];
105 	}
106 
107 	if (mdb_vread(&iw->iw_inode, sizeof (inode_t), addr) == -1) {
108 		mdb_warn("failed to read inode at %p", addr);
109 		return (WALK_DONE);
110 	}
111 
112 	wsp->walk_addr = (uintptr_t)iw->iw_inode.i_forw;
113 
114 	return (wsp->walk_callback(addr, (void *)(uintptr_t)iw->iw_inohcnt,
115 	    wsp->walk_cbdata));
116 }
117 
118 static void
119 inode_walk_fini(mdb_walk_state_t *wsp)
120 {
121 	mdb_free(wsp->walk_data, sizeof (inode_walk_data_t));
122 }
123 
124 typedef struct inode_cbdata {
125 	ino_t id_inumber;
126 	dev_t id_device;
127 	uintptr_t id_addr;
128 	uint_t id_flags;
129 } inode_cbdata_t;
130 
131 static int
132 inode_cache_cb(uintptr_t addr, const int inohcnt, inode_cbdata_t *id)
133 {
134 	inode_t inode;
135 	int inohsz;
136 
137 	if (mdb_vread(&inode, sizeof (inode), addr) == -1) {
138 		mdb_warn("failed to read inode_t at %p", addr);
139 		return (WALK_ERR);
140 	}
141 
142 	if (id->id_device != 0 && inode.i_dev != id->id_device)
143 		return (WALK_NEXT);
144 
145 	if (id->id_inumber != 0 && inode.i_number != id->id_inumber)
146 		return (WALK_NEXT);
147 
148 	if (id->id_flags & DCMD_ADDRSPEC && addr != id->id_addr)
149 		return (WALK_NEXT);
150 
151 	if (id->id_flags & DCMD_PIPE_OUT) {
152 		mdb_printf("%p\n", addr);
153 		return (WALK_NEXT);
154 	}
155 
156 	mdb_printf("%0?p %10lld %15lx",
157 	    addr, (u_longlong_t)inode.i_number, inode.i_dev);
158 
159 	/*
160 	 * INOHASH needs inohsz.
161 	 */
162 	if (mdb_readvar(&inohsz, "inohsz") == -1) {
163 		mdb_warn("failed to read 'inohsz'");
164 		return (WALK_ERR);
165 	}
166 
167 	/*
168 	 * Is the inode in the hash chain it should be?
169 	 */
170 	if (inohcnt == INOHASH(inode.i_number)) {
171 		mdb_printf(" %5d\n", inohcnt);
172 	} else {
173 		mdb_printf(" %<b>%5d/%5d ??</b>\n",
174 		    inohcnt, INOHASH(inode.i_number));
175 	}
176 
177 	return (WALK_NEXT);
178 }
179 
180 /*ARGSUSED*/
181 static int
182 inode_cache(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
183 {
184 	inode_cbdata_t id;
185 
186 	id.id_inumber = 0;
187 	id.id_device = 0;
188 	id.id_addr = addr;
189 	id.id_flags = flags;
190 
191 	if (mdb_getopts(argc, argv,
192 	    'i', MDB_OPT_UINT64, &id.id_inumber,
193 	    'd', MDB_OPT_UINTPTR, &id.id_device, NULL) != argc)
194 		return (DCMD_USAGE);
195 
196 	if (DCMD_HDRSPEC(flags) && (flags & DCMD_PIPE_OUT) == 0) {
197 		mdb_printf("%<u>%-?s %10s %15s %5s%</u>\n",
198 		    "ADDR", "INUMBER", "DEVICE", "CHAIN");
199 	}
200 
201 	if (mdb_walk("inode_cache", (mdb_walk_cb_t)inode_cache_cb, &id) == -1) {
202 		mdb_warn("can't walk inode cache");
203 		return (DCMD_ERR);
204 	}
205 
206 	return (DCMD_OK);
207 }
208 
209 /*ARGSUSED*/
210 static int
211 inode(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
212 {
213 	uint_t verbose = FALSE;
214 	inode_t inode;
215 	char buf[64];
216 	char path[MAXPATHLEN];
217 
218 	static const mdb_bitmask_t i_flag_masks[] = {
219 		{ "UPD",		IUPD,		IUPD		},
220 		{ "ACC",		IACC,		IACC		},
221 		{ "MOD",		IMOD,		IMOD		},
222 		{ "CHG",		ICHG,		ICHG		},
223 		{ "NOACC",		INOACC,		INOACC		},
224 		{ "MODTIME",		IMODTIME,	IMODTIME	},
225 		{ "REF",		IREF,		IREF		},
226 		{ "SYNC",		ISYNC,		ISYNC		},
227 		{ "FASTSYMLNK",		IFASTSYMLNK,	IFASTSYMLNK	},
228 		{ "MODACC",		IMODACC,	IMODACC		},
229 		{ "ATTCHG",		IATTCHG,	IATTCHG		},
230 		{ "BDWRITE",		IBDWRITE,	IBDWRITE	},
231 		{ "STALE",		ISTALE,		ISTALE		},
232 		{ "DEL",		IDEL,		IDEL		},
233 		{ "DIRECTIO",		IDIRECTIO,	IDIRECTIO	},
234 		{ "JUNKIQ",		IJUNKIQ,	IJUNKIQ		},
235 		{ NULL,			0,		0		}
236 	};
237 
238 	static const mdb_bitmask_t i_modetype_masks[] = {
239 		{ "p",	IFMT,	IFIFO		},
240 		{ "c",	IFMT,	IFCHR		},
241 		{ "d",	IFMT,	IFDIR		},
242 		{ "b",	IFMT,	IFBLK		},
243 		{ "-",	IFMT,	IFREG		},
244 		{ "l",	IFMT,	IFLNK		},
245 		{ "S",	IFMT,	IFSHAD		},
246 		{ "s",	IFMT,	IFSOCK		},
247 		{ "A",	IFMT,	IFATTRDIR	},
248 		{ NULL,	0,	0		}
249 	};
250 
251 	if (!(flags & DCMD_ADDRSPEC))
252 		return (DCMD_USAGE);
253 
254 	if (mdb_getopts(argc, argv,
255 	    'v', MDB_OPT_SETBITS, TRUE, &verbose, NULL) != argc)
256 		return (DCMD_USAGE);
257 
258 	if (DCMD_HDRSPEC(flags) && (flags & DCMD_PIPE_OUT) == 0) {
259 		mdb_printf("%<u>%-?s %10s %1s %5s %8s",
260 		    "ADDR", "INUMBER", "T", "MODE", "SIZE");
261 
262 		if (verbose)
263 			mdb_printf(" %11s %-22s%</u>\n", "DEVICE", "FLAG");
264 		else
265 			mdb_printf(" %-12s %-21s%</u>\n", "MTIME", "NAME");
266 	}
267 
268 	if (mdb_vread(&inode, sizeof (inode), addr) == -1) {
269 		mdb_warn("failed to read inode_t at %p", addr);
270 		return (DCMD_ERR);
271 	}
272 
273 	mdb_printf("%0?p %10lld %b %5#o %8llx",
274 	    addr, (u_longlong_t)inode.i_number, inode.i_mode, i_modetype_masks,
275 	    inode.i_mode & ~IFMT, inode.i_size);
276 
277 	if (verbose) {
278 
279 		mdb_printf(" %11lx <%b>\n",
280 		    inode.i_dev, inode.i_flag, i_flag_masks);
281 
282 		mdb_inc_indent(2);
283 
284 		mdb_printf("%Y\n", inode.i_mtime.tv_sec);
285 
286 		if (mdb_vnode2path((uintptr_t)inode.i_vnode, path,
287 		    sizeof (path)) == 0 && *path != '\0')
288 			mdb_printf("%s\n", path);
289 		else
290 			mdb_printf("??\n");
291 
292 		mdb_dec_indent(2);
293 
294 		return (DCMD_OK);
295 	}
296 
297 	/*
298 	 * Not verbose, everything must fit into one line.
299 	 */
300 	mdb_snprintf(buf, sizeof (buf), "%Y", inode.i_mtime.tv_sec);
301 	buf[17] = '\0'; /* drop seconds */
302 	if (buf[0] == '1' || buf[0] == '2')
303 		mdb_printf(" %12s", buf + 5); /* drop year */
304 	else
305 		mdb_printf(" %-12s", "?");
306 
307 	if (mdb_vnode2path((uintptr_t)inode.i_vnode, path,
308 	    sizeof (path)) == 0 && *path != '\0') {
309 		if (strlen(path) <= 21)
310 			mdb_printf(" %-21s\n", path);
311 		else
312 			mdb_printf(" ...%-18s\n", path + strlen(path) - 18);
313 	} else {
314 		mdb_printf(" ??\n");
315 	}
316 
317 	return (DCMD_OK);
318 }
319 
320 static struct {
321 	int am_offset;
322 	char *am_tag;
323 } acl_map[] = {
324 	{ offsetof(si_t, aowner), "USER_OBJ" },
325 	{ offsetof(si_t, agroup), "GROUP_OBJ" },
326 	{ offsetof(si_t, aother), "OTHER_OBJ" },
327 	{ offsetof(si_t, ausers), "USER" },
328 	{ offsetof(si_t, agroups), "GROUP" },
329 	{ offsetof(si_t, downer), "DEF_USER_OBJ" },
330 	{ offsetof(si_t, dgroup), "DEF_GROUP_OBJ" },
331 	{ offsetof(si_t, dother), "DEF_OTHER_OBJ" },
332 	{ offsetof(si_t, dusers), "DEF_USER" },
333 	{ offsetof(si_t, dgroups), "DEF_GROUP" },
334 	{ -1, NULL }
335 };
336 
337 static int
338 acl_walk_init(mdb_walk_state_t *wsp)
339 {
340 	uintptr_t addr = wsp->walk_addr;
341 	inode_t inode;
342 	si_t *si;
343 	ufs_ic_acl_t **aclpp;
344 
345 	if (addr == NULL) {
346 		mdb_warn("acl walk needs an inode address\n");
347 		return (WALK_ERR);
348 	}
349 
350 	if (mdb_vread(&inode, sizeof (inode), addr) == -1) {
351 		mdb_warn("failed to read inode_t at %p", addr);
352 		return (WALK_ERR);
353 	}
354 
355 	if (inode.i_ufs_acl == NULL)
356 		return (WALK_DONE);
357 
358 	si = mdb_alloc(sizeof (si_t), UM_SLEEP);
359 
360 	if (mdb_vread(si, sizeof (si_t), (uintptr_t)inode.i_ufs_acl) == -1) {
361 		mdb_warn("failed to read si_t at %p", inode.i_ufs_acl);
362 		mdb_free(si, sizeof (si_t));
363 		return (WALK_ERR);
364 	}
365 
366 	/* LINTED - alignment */
367 	aclpp = (ufs_ic_acl_t **)((caddr_t)si + acl_map[0].am_offset);
368 
369 	wsp->walk_addr = (uintptr_t)*aclpp;
370 	wsp->walk_data = si;
371 	wsp->walk_arg = 0;
372 
373 	return (WALK_NEXT);
374 }
375 
376 static int
377 acl_walk_step(mdb_walk_state_t *wsp)
378 {
379 	uintptr_t addr = wsp->walk_addr;
380 	si_t *si = wsp->walk_data;
381 	uint_t i = (uintptr_t)wsp->walk_arg;
382 	ufs_ic_acl_t **aclpp;
383 	ufs_ic_acl_t acl;
384 
385 	while (addr == NULL) {
386 		wsp->walk_arg = (void *)(uintptr_t)++i;
387 
388 		if (acl_map[i].am_offset == -1)
389 			return (WALK_DONE);
390 
391 		/* LINTED - alignment */
392 		aclpp = (ufs_ic_acl_t **)((caddr_t)si + acl_map[i].am_offset);
393 
394 		addr = (uintptr_t)*aclpp;
395 	}
396 
397 	if (mdb_vread(&acl, sizeof (acl), addr) == -1) {
398 		mdb_warn("failed to read acl at %p", addr);
399 		return (WALK_DONE);
400 	}
401 
402 	wsp->walk_addr = (uintptr_t)acl.acl_ic_next;
403 
404 	return (wsp->walk_callback(addr, &acl, acl_map[i].am_tag));
405 }
406 
407 static void
408 acl_walk_fini(mdb_walk_state_t *wsp)
409 {
410 	mdb_free(wsp->walk_data, sizeof (si_t));
411 }
412 
413 static int
414 acl_cb(uintptr_t addr, const void *arg, void *data)
415 {
416 	ufs_ic_acl_t *aclp = (ufs_ic_acl_t *)arg;
417 
418 	mdb_printf("%?p %-16s %7#o %10d\n",
419 	    addr, (char *)data, aclp->acl_ic_perm, aclp->acl_ic_who);
420 
421 	return (WALK_NEXT);
422 }
423 
424 /*ARGSUSED*/
425 static int
426 acl_dcmd(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
427 {
428 	if (!(flags & DCMD_ADDRSPEC))
429 		return (DCMD_USAGE);
430 
431 	if (argc != 0)
432 		return (DCMD_USAGE);
433 
434 	if (DCMD_HDRSPEC(flags)) {
435 		mdb_printf("%<u>%?s %-16s %7s %10s%</u>\n",
436 		    "ADDR", "TAG", "PERM", "WHO");
437 	}
438 
439 	if (mdb_pwalk("acl", (mdb_walk_cb_t)acl_cb, NULL, addr) == -1) {
440 		mdb_warn("can't walk acls of inode %p", addr);
441 		return (DCMD_ERR);
442 	}
443 
444 	return (DCMD_OK);
445 }
446 
447 
448 static int
449 cg_walk_init(mdb_walk_state_t *wsp)
450 {
451 	if (mdb_layered_walk("buf", wsp) == -1) {
452 		mdb_warn("couldn't walk bio buf hash");
453 		return (WALK_ERR);
454 	}
455 
456 	return (WALK_NEXT);
457 }
458 
459 static int
460 cg_walk_step(mdb_walk_state_t *wsp)
461 {
462 	uintptr_t addr = (uintptr_t)((const buf_t *)wsp->walk_layer)->b_un.b_cg;
463 	struct cg cg;
464 
465 	if (mdb_vread(&cg, sizeof (cg), addr) == -1) {
466 		mdb_warn("failed to read cg struct at %p", addr);
467 		return (WALK_ERR);
468 	}
469 
470 	if (cg.cg_magic != CG_MAGIC)
471 		return (WALK_NEXT);
472 
473 	return (wsp->walk_callback(addr, &cg, wsp->walk_cbdata));
474 }
475 
476 static void
477 pbits(const uchar_t *cp, const int max, const int linelen)
478 {
479 	int i, j, len;
480 	char entry[40];
481 	int linecnt = -1;
482 
483 	for (i = 0; i < max; i++) {
484 		if (isset(cp, i)) {
485 			len = mdb_snprintf(entry, sizeof (entry), "%d", i);
486 			j = i;
487 			while ((i + 1) < max && isset(cp, i+1))
488 				i++;
489 			if (i != j)
490 				len += mdb_snprintf(entry + len,
491 				    sizeof (entry) - len, "-%d", i);
492 
493 			if (linecnt == -1) {
494 				/* first entry */
495 				mdb_printf("%s", entry);
496 				linecnt = linelen - len;
497 			} else if (linecnt - (len + 3) > 0) {
498 				/* subsequent entry on same line */
499 				mdb_printf(", %s", entry);
500 				linecnt -= len + 2;
501 			} else {
502 				/* subsequent enty on new line */
503 				mdb_printf(",\n%s", entry);
504 				linecnt = linelen - len;
505 			}
506 		}
507 	}
508 	mdb_printf("\n");
509 }
510 
511 /*ARGSUSED*/
512 static int
513 cg(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
514 {
515 	uint_t verbose = FALSE;
516 	struct cg cg;
517 	struct cg *cgp = &cg;
518 	size_t size;
519 	int i, j, cnt, off;
520 	int32_t *blktot;
521 	short *blks;
522 
523 	if (!(flags & DCMD_ADDRSPEC)) {
524 		if (mdb_walk_dcmd("cg", "cg", argc, argv) == -1) {
525 			mdb_warn("can't walk cylinder group structs");
526 			return (DCMD_ERR);
527 		}
528 		return (DCMD_OK);
529 	}
530 
531 	if (mdb_getopts(argc, argv,
532 	    'v', MDB_OPT_SETBITS, TRUE, &verbose, NULL) != argc)
533 		return (DCMD_USAGE);
534 
535 	if (mdb_vread(cgp, sizeof (cg), addr) == -1) {
536 		mdb_warn("failed to read cg struct at %p", addr);
537 		return (DCMD_ERR);
538 	}
539 
540 	if (!verbose) {
541 		if (DCMD_HDRSPEC(flags))
542 			mdb_printf("%<u>%4s %?s %10s %10s %10s %10s%</u>\n",
543 			    "CGX", "CG", "NDIR", "NBFREE", "NIFREE", "NFFREE");
544 
545 		mdb_printf("%4d %?p %10d %10d %10d %10d\n", cgp->cg_cgx,
546 		    addr, cgp->cg_cs.cs_ndir, cgp->cg_cs.cs_nbfree,
547 		    cgp->cg_cs.cs_nifree, cgp->cg_cs.cs_nffree);
548 
549 		return (DCMD_OK);
550 	}
551 
552 	/*
553 	 * Verbose: produce output similiar to "fstyp -v".
554 	 */
555 	if (cgp->cg_btotoff >= cgp->cg_nextfreeoff ||
556 	    cgp->cg_boff >= cgp->cg_nextfreeoff ||
557 	    cgp->cg_iusedoff >= cgp->cg_nextfreeoff ||
558 	    cgp->cg_freeoff >= cgp->cg_nextfreeoff) {
559 		mdb_warn("struct cg at %p seems broken\n", addr);
560 		return (DCMD_ERR);
561 	}
562 
563 	size = cgp->cg_nextfreeoff;
564 	cgp = mdb_alloc(size, UM_SLEEP);
565 
566 	if (mdb_vread(cgp, size, addr) == -1) {
567 		mdb_warn("failed to read struct cg and maps at %p", addr);
568 		mdb_free(cgp, size);
569 		return (DCMD_ERR);
570 	}
571 
572 	mdb_printf("%<b>cg %d (%0?p)%</b>\n", cgp->cg_cgx, addr);
573 
574 	mdb_inc_indent(4);
575 
576 	mdb_printf("time:\t%Y\n", cgp->cg_time);
577 	mdb_printf("ndir:\t%d\n", cgp->cg_cs.cs_ndir);
578 	mdb_printf("nbfree:\t%d\n", cgp->cg_cs.cs_nbfree);
579 	mdb_printf("nifree:\t%d\n", cgp->cg_cs.cs_nifree);
580 	mdb_printf("nffree:\t%d\n", cgp->cg_cs.cs_nffree);
581 
582 	mdb_printf("frsum:");
583 	for (i = 1; i < MAXFRAG; i++)
584 		mdb_printf("\t%d", cgp->cg_frsum[i]);
585 	mdb_printf("\n");
586 
587 	off = cgp->cg_iusedoff;
588 	mdb_printf("used inode map (%0?p):\n", (char *)addr + off);
589 	mdb_inc_indent(4);
590 	pbits((uchar_t *)cgp + off, cgp->cg_niblk / sizeof (char), 72);
591 	mdb_dec_indent(4);
592 
593 	off = cgp->cg_freeoff;
594 	mdb_printf("free block map (%0?p):\n", (char *)addr + off);
595 	mdb_inc_indent(4);
596 	pbits((uchar_t *)cgp + off, cgp->cg_ndblk / sizeof (char), 72);
597 	mdb_dec_indent(4);
598 
599 	/* LINTED - alignment */
600 	blktot = (int32_t *)((char *)cgp + cgp->cg_btotoff);
601 	/* LINTED - alignment */
602 	blks = (short *)((char *)cgp + cgp->cg_boff);
603 	cnt = (cgp->cg_iusedoff - cgp->cg_boff) / cgp->cg_ncyl / sizeof (short);
604 	mdb_printf("free block positions:\n");
605 	mdb_inc_indent(4);
606 
607 	for (i = 0; i < cgp->cg_ncyl; i++) {
608 		mdb_printf("c%d:\t(%d)\t", i, blktot[i]);
609 		for (j = 0; j < cnt; j++)
610 			mdb_printf(" %d", blks[i*cnt + j]);
611 		mdb_printf("\n");
612 	}
613 	mdb_dec_indent(4);
614 
615 	mdb_printf("\n");
616 	mdb_dec_indent(4);
617 
618 	mdb_free(cgp, size);
619 
620 	return (DCMD_OK);
621 }
622 
623 void
624 inode_cache_help(void)
625 {
626 	mdb_printf(
627 	    "Displays cached inode_t. If an address, an inode number and/or a\n"
628 	    "device is specified, searches inode cache for inodes which match\n"
629 	    "the specified criteria. Prints nothing but the address, if\n"
630 	    "output is a pipe.\n"
631 	    "\n"
632 	    "Options:\n"
633 	    "  -d device    Filter out inodes, which reside on the specified"
634 	    " device.\n"
635 	    "  -i inumber   Filter out inodes with the specified inode"
636 	    " number.\n");
637 }
638 
639 /*
640  * MDB module linkage
641  */
642 static const mdb_dcmd_t dcmds[] = {
643 	{ "inode_cache", "?[-d device] [-i inumber]",
644 		"search/display inodes from inode cache",
645 		inode_cache, inode_cache_help },
646 	{ "inode", ":[-v]", "display summarized inode_t", inode },
647 	{ "acl", ":", "given an inode, display its in core acl's", acl_dcmd },
648 	{ "cg", "?[-v]", "display a summarized cylinder group structure", cg },
649 	{ "mapentry", ":", "dumps ufslog mapentry", mapentry_dcmd },
650 	{ "mapstats", ":", "dumps ufslog stats", mapstats_dcmd },
651 	{ NULL }
652 };
653 
654 static const mdb_walker_t walkers[] = {
655 	{ "inode_cache", "walk inode cache",
656 		inode_walk_init, inode_walk_step, inode_walk_fini },
657 	{ "acl", "given an inode, walk chains of in core acl's",
658 		acl_walk_init, acl_walk_step, acl_walk_fini },
659 	{ "cg", "walk cg's in bio buffer cache",
660 		cg_walk_init, cg_walk_step, NULL },
661 	{ "ufslogmap", "walk map entries in a ufs_log mt_map",
662 		ufslogmap_walk_init, ufslogmap_walk_step, NULL },
663 	{ NULL }
664 };
665 
666 static const mdb_modinfo_t modinfo = { MDB_API_VERSION, dcmds, walkers };
667 
668 const mdb_modinfo_t *
669 _mdb_init(void)
670 {
671 	return (&modinfo);
672 }
673