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