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