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.
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.
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]
22 * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
26 #pragma ident "%Z%%M% %I% %E% SMI"
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>
38 typedef struct inode_walk_data
{
46 inode_walk_init(mdb_walk_state_t
*wsp
)
51 inode_walk_data_t
*iw
;
53 if (wsp
->walk_addr
!= NULL
) {
54 mdb_warn("inode_cache only supports global walks\n");
58 if (mdb_readvar(&inohsz
, "inohsz") == -1) {
59 mdb_warn("failed to read 'inohsz'");
66 if (mdb_readvar(&ihead
, "ihead") == -1) {
67 mdb_warn("failed to read 'ihead'");
71 if (mdb_vread(&ih
, sizeof (union ihead
), ihead
) == -1) {
72 mdb_warn("failed to read ihead at %p", ihead
);
76 iw
= mdb_alloc(sizeof (inode_walk_data_t
), UM_SLEEP
);
77 iw
->iw_inohsz
= inohsz
;
81 wsp
->walk_addr
= (uintptr_t)ih
.ih_chain
[0];
88 inode_walk_step(mdb_walk_state_t
*wsp
)
90 uintptr_t addr
= wsp
->walk_addr
;
91 inode_walk_data_t
*iw
= wsp
->walk_data
;
94 while (addr
== iw
->iw_ihead
) {
95 if (++iw
->iw_inohcnt
>= iw
->iw_inohsz
)
98 iw
->iw_ihead
+= sizeof (union ihead
);
100 if (mdb_vread(&ih
, sizeof (union ihead
), iw
->iw_ihead
) == -1) {
101 mdb_warn("failed to read ihead at %p", iw
->iw_ihead
);
104 addr
= (uintptr_t)ih
.ih_chain
[0];
107 if (mdb_vread(&iw
->iw_inode
, sizeof (inode_t
), addr
) == -1) {
108 mdb_warn("failed to read inode at %p", addr
);
112 wsp
->walk_addr
= (uintptr_t)iw
->iw_inode
.i_forw
;
114 return (wsp
->walk_callback(addr
, (void *)(uintptr_t)iw
->iw_inohcnt
,
119 inode_walk_fini(mdb_walk_state_t
*wsp
)
121 mdb_free(wsp
->walk_data
, sizeof (inode_walk_data_t
));
124 typedef struct inode_cbdata
{
132 inode_cache_cb(uintptr_t addr
, const int inohcnt
, inode_cbdata_t
*id
)
137 if (mdb_vread(&inode
, sizeof (inode
), addr
) == -1) {
138 mdb_warn("failed to read inode_t at %p", addr
);
142 if (id
->id_device
!= 0 && inode
.i_dev
!= id
->id_device
)
145 if (id
->id_inumber
!= 0 && inode
.i_number
!= id
->id_inumber
)
148 if (id
->id_flags
& DCMD_ADDRSPEC
&& addr
!= id
->id_addr
)
151 if (id
->id_flags
& DCMD_PIPE_OUT
) {
152 mdb_printf("%p\n", addr
);
156 mdb_printf("%0?p %10lld %15lx",
157 addr
, (u_longlong_t
)inode
.i_number
, inode
.i_dev
);
160 * INOHASH needs inohsz.
162 if (mdb_readvar(&inohsz
, "inohsz") == -1) {
163 mdb_warn("failed to read 'inohsz'");
168 * Is the inode in the hash chain it should be?
170 if (inohcnt
== INOHASH(inode
.i_number
)) {
171 mdb_printf(" %5d\n", inohcnt
);
173 mdb_printf(" %<b>%5d/%5d ??</b>\n",
174 inohcnt
, INOHASH(inode
.i_number
));
182 inode_cache(uintptr_t addr
, uint_t flags
, int argc
, const mdb_arg_t
*argv
)
191 if (mdb_getopts(argc
, argv
,
192 'i', MDB_OPT_UINT64
, &id
.id_inumber
,
193 'd', MDB_OPT_UINTPTR
, &id
.id_device
, NULL
) != argc
)
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");
201 if (mdb_walk("inode_cache", (mdb_walk_cb_t
)inode_cache_cb
, &id
) == -1) {
202 mdb_warn("can't walk inode cache");
211 inode(uintptr_t addr
, uint_t flags
, int argc
, const mdb_arg_t
*argv
)
213 uint_t verbose
= FALSE
;
216 char path
[MAXPATHLEN
];
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
},
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
},
251 if (!(flags
& DCMD_ADDRSPEC
))
254 if (mdb_getopts(argc
, argv
,
255 'v', MDB_OPT_SETBITS
, TRUE
, &verbose
, NULL
) != argc
)
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");
263 mdb_printf(" %11s %-22s%</u>\n", "DEVICE", "FLAG");
265 mdb_printf(" %-12s %-21s%</u>\n", "MTIME", "NAME");
268 if (mdb_vread(&inode
, sizeof (inode
), addr
) == -1) {
269 mdb_warn("failed to read inode_t at %p", addr
);
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
);
279 mdb_printf(" %11lx <%b>\n",
280 inode
.i_dev
, inode
.i_flag
, i_flag_masks
);
284 mdb_printf("%Y\n", inode
.i_mtime
.tv_sec
);
286 if (mdb_vnode2path((uintptr_t)inode
.i_vnode
, path
,
287 sizeof (path
)) == 0 && *path
!= '\0')
288 mdb_printf("%s\n", path
);
298 * Not verbose, everything must fit into one line.
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 */
305 mdb_printf(" %-12s", "?");
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
);
312 mdb_printf(" ...%-18s\n", path
+ strlen(path
) - 18);
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" },
338 acl_walk_init(mdb_walk_state_t
*wsp
)
340 uintptr_t addr
= wsp
->walk_addr
;
343 ufs_ic_acl_t
**aclpp
;
346 mdb_warn("acl walk needs an inode address\n");
350 if (mdb_vread(&inode
, sizeof (inode
), addr
) == -1) {
351 mdb_warn("failed to read inode_t at %p", addr
);
355 if (inode
.i_ufs_acl
== NULL
)
358 si
= mdb_alloc(sizeof (si_t
), UM_SLEEP
);
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
));
366 /* LINTED - alignment */
367 aclpp
= (ufs_ic_acl_t
**)((caddr_t
)si
+ acl_map
[0].am_offset
);
369 wsp
->walk_addr
= (uintptr_t)*aclpp
;
377 acl_walk_step(mdb_walk_state_t
*wsp
)
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
;
385 while (addr
== NULL
) {
386 wsp
->walk_arg
= (void *)(uintptr_t)++i
;
388 if (acl_map
[i
].am_offset
== -1)
391 /* LINTED - alignment */
392 aclpp
= (ufs_ic_acl_t
**)((caddr_t
)si
+ acl_map
[i
].am_offset
);
394 addr
= (uintptr_t)*aclpp
;
397 if (mdb_vread(&acl
, sizeof (acl
), addr
) == -1) {
398 mdb_warn("failed to read acl at %p", addr
);
402 wsp
->walk_addr
= (uintptr_t)acl
.acl_ic_next
;
404 return (wsp
->walk_callback(addr
, &acl
, acl_map
[i
].am_tag
));
408 acl_walk_fini(mdb_walk_state_t
*wsp
)
410 mdb_free(wsp
->walk_data
, sizeof (si_t
));
414 acl_cb(uintptr_t addr
, const void *arg
, void *data
)
416 ufs_ic_acl_t
*aclp
= (ufs_ic_acl_t
*)arg
;
418 mdb_printf("%?p %-16s %7#o %10d\n",
419 addr
, (char *)data
, aclp
->acl_ic_perm
, aclp
->acl_ic_who
);
426 acl_dcmd(uintptr_t addr
, uint_t flags
, int argc
, const mdb_arg_t
*argv
)
428 if (!(flags
& DCMD_ADDRSPEC
))
434 if (DCMD_HDRSPEC(flags
)) {
435 mdb_printf("%<u>%?s %-16s %7s %10s%</u>\n",
436 "ADDR", "TAG", "PERM", "WHO");
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
);
449 cg_walk_init(mdb_walk_state_t
*wsp
)
451 if (mdb_layered_walk("buf", wsp
) == -1) {
452 mdb_warn("couldn't walk bio buf hash");
460 cg_walk_step(mdb_walk_state_t
*wsp
)
462 uintptr_t addr
= (uintptr_t)((const buf_t
*)wsp
->walk_layer
)->b_un
.b_cg
;
465 if (mdb_vread(&cg
, sizeof (cg
), addr
) == -1) {
466 mdb_warn("failed to read cg struct at %p", addr
);
470 if (cg
.cg_magic
!= CG_MAGIC
)
473 return (wsp
->walk_callback(addr
, &cg
, wsp
->walk_cbdata
));
477 pbits(const uchar_t
*cp
, const int max
, const int linelen
)
483 for (i
= 0; i
< max
; i
++) {
485 len
= mdb_snprintf(entry
, sizeof (entry
), "%d", i
);
487 while ((i
+ 1) < max
&& isset(cp
, i
+1))
490 len
+= mdb_snprintf(entry
+ len
,
491 sizeof (entry
) - len
, "-%d", i
);
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
);
502 /* subsequent enty on new line */
503 mdb_printf(",\n%s", entry
);
504 linecnt
= linelen
- len
;
513 cg(uintptr_t addr
, uint_t flags
, int argc
, const mdb_arg_t
*argv
)
515 uint_t verbose
= FALSE
;
517 struct cg
*cgp
= &cg
;
523 if (!(flags
& DCMD_ADDRSPEC
)) {
524 if (mdb_walk_dcmd("cg", "cg", argc
, argv
) == -1) {
525 mdb_warn("can't walk cylinder group structs");
531 if (mdb_getopts(argc
, argv
,
532 'v', MDB_OPT_SETBITS
, TRUE
, &verbose
, NULL
) != argc
)
535 if (mdb_vread(cgp
, sizeof (cg
), addr
) == -1) {
536 mdb_warn("failed to read cg struct at %p", addr
);
541 if (DCMD_HDRSPEC(flags
))
542 mdb_printf("%<u>%4s %?s %10s %10s %10s %10s%</u>\n",
543 "CGX", "CG", "NDIR", "NBFREE", "NIFREE", "NFFREE");
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
);
553 * Verbose: produce output similiar to "fstyp -v".
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
);
563 size
= cgp
->cg_nextfreeoff
;
564 cgp
= mdb_alloc(size
, UM_SLEEP
);
566 if (mdb_vread(cgp
, size
, addr
) == -1) {
567 mdb_warn("failed to read struct cg and maps at %p", addr
);
572 mdb_printf("%<b>cg %d (%0?p)%</b>\n", cgp
->cg_cgx
, addr
);
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
);
582 mdb_printf("frsum:");
583 for (i
= 1; i
< MAXFRAG
; i
++)
584 mdb_printf("\t%d", cgp
->cg_frsum
[i
]);
587 off
= cgp
->cg_iusedoff
;
588 mdb_printf("used inode map (%0?p):\n", (char *)addr
+ off
);
590 pbits((uchar_t
*)cgp
+ off
, cgp
->cg_niblk
/ sizeof (char), 72);
593 off
= cgp
->cg_freeoff
;
594 mdb_printf("free block map (%0?p):\n", (char *)addr
+ off
);
596 pbits((uchar_t
*)cgp
+ off
, cgp
->cg_ndblk
/ sizeof (char), 72);
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");
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
]);
624 inode_cache_help(void)
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"
633 " -d device Filter out inodes, which reside on the specified"
635 " -i inumber Filter out inodes with the specified inode"
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
},
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
},
666 static const mdb_modinfo_t modinfo
= { MDB_API_VERSION
, dcmds
, walkers
};
668 const mdb_modinfo_t
*