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 #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>
36 typedef struct inode_walk_data
{
44 inode_walk_init(mdb_walk_state_t
*wsp
)
49 inode_walk_data_t
*iw
;
51 if (wsp
->walk_addr
!= (uintptr_t)NULL
) {
52 mdb_warn("inode_cache only supports global walks\n");
56 if (mdb_readvar(&inohsz
, "inohsz") == -1) {
57 mdb_warn("failed to read 'inohsz'");
64 if (mdb_readvar(&ihead
, "ihead") == -1) {
65 mdb_warn("failed to read 'ihead'");
69 if (mdb_vread(&ih
, sizeof (union ihead
), ihead
) == -1) {
70 mdb_warn("failed to read ihead at %p", ihead
);
74 iw
= mdb_alloc(sizeof (inode_walk_data_t
), UM_SLEEP
);
75 iw
->iw_inohsz
= inohsz
;
79 wsp
->walk_addr
= (uintptr_t)ih
.ih_chain
[0];
86 inode_walk_step(mdb_walk_state_t
*wsp
)
88 uintptr_t addr
= wsp
->walk_addr
;
89 inode_walk_data_t
*iw
= wsp
->walk_data
;
92 while (addr
== iw
->iw_ihead
) {
93 if (++iw
->iw_inohcnt
>= iw
->iw_inohsz
)
96 iw
->iw_ihead
+= sizeof (union ihead
);
98 if (mdb_vread(&ih
, sizeof (union ihead
), iw
->iw_ihead
) == -1) {
99 mdb_warn("failed to read ihead at %p", iw
->iw_ihead
);
102 addr
= (uintptr_t)ih
.ih_chain
[0];
105 if (mdb_vread(&iw
->iw_inode
, sizeof (inode_t
), addr
) == -1) {
106 mdb_warn("failed to read inode at %p", addr
);
110 wsp
->walk_addr
= (uintptr_t)iw
->iw_inode
.i_forw
;
112 return (wsp
->walk_callback(addr
, (void *)(uintptr_t)iw
->iw_inohcnt
,
117 inode_walk_fini(mdb_walk_state_t
*wsp
)
119 mdb_free(wsp
->walk_data
, sizeof (inode_walk_data_t
));
122 typedef struct inode_cbdata
{
130 inode_cache_cb(uintptr_t addr
, const int inohcnt
, inode_cbdata_t
*id
)
135 if (mdb_vread(&inode
, sizeof (inode
), addr
) == -1) {
136 mdb_warn("failed to read inode_t at %p", addr
);
140 if (id
->id_device
!= 0 && inode
.i_dev
!= id
->id_device
)
143 if (id
->id_inumber
!= 0 && inode
.i_number
!= id
->id_inumber
)
146 if (id
->id_flags
& DCMD_ADDRSPEC
&& addr
!= id
->id_addr
)
149 if (id
->id_flags
& DCMD_PIPE_OUT
) {
150 mdb_printf("%p\n", addr
);
154 mdb_printf("%0?p %10lld %15lx",
155 addr
, (u_longlong_t
)inode
.i_number
, inode
.i_dev
);
158 * INOHASH needs inohsz.
160 if (mdb_readvar(&inohsz
, "inohsz") == -1) {
161 mdb_warn("failed to read 'inohsz'");
166 * Is the inode in the hash chain it should be?
168 if (inohcnt
== INOHASH(inode
.i_number
)) {
169 mdb_printf(" %5d\n", inohcnt
);
171 mdb_printf(" %<b>%5d/%5d ??</b>\n",
172 inohcnt
, INOHASH(inode
.i_number
));
180 inode_cache(uintptr_t addr
, uint_t flags
, int argc
, const mdb_arg_t
*argv
)
189 if (mdb_getopts(argc
, argv
,
190 'i', MDB_OPT_UINT64
, &id
.id_inumber
,
191 'd', MDB_OPT_UINTPTR
, &id
.id_device
, NULL
) != argc
)
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");
199 if (mdb_walk("inode_cache", (mdb_walk_cb_t
)inode_cache_cb
, &id
) == -1) {
200 mdb_warn("can't walk inode cache");
209 inode(uintptr_t addr
, uint_t flags
, int argc
, const mdb_arg_t
*argv
)
211 uint_t verbose
= FALSE
;
214 char path
[MAXPATHLEN
];
216 static const mdb_bitmask_t i_flag_masks
[] = {
217 { "UPD", IUPD
, IUPD
},
218 { "ACC", IACC
, IACC
},
219 { "MOD", IMOD
, IMOD
},
220 { "CHG", ICHG
, ICHG
},
221 { "NOACC", INOACC
, INOACC
},
222 { "MODTIME", IMODTIME
, IMODTIME
},
223 { "REF", IREF
, IREF
},
224 { "SYNC", ISYNC
, ISYNC
},
225 { "FASTSYMLNK", IFASTSYMLNK
, IFASTSYMLNK
},
226 { "MODACC", IMODACC
, IMODACC
},
227 { "ATTCHG", IATTCHG
, IATTCHG
},
228 { "BDWRITE", IBDWRITE
, IBDWRITE
},
229 { "STALE", ISTALE
, ISTALE
},
230 { "DEL", IDEL
, IDEL
},
231 { "DIRECTIO", IDIRECTIO
, IDIRECTIO
},
232 { "JUNKIQ", IJUNKIQ
, IJUNKIQ
},
236 static const mdb_bitmask_t i_modetype_masks
[] = {
237 { "p", IFMT
, IFIFO
},
238 { "c", IFMT
, IFCHR
},
239 { "d", IFMT
, IFDIR
},
240 { "b", IFMT
, IFBLK
},
241 { "-", IFMT
, IFREG
},
242 { "l", IFMT
, IFLNK
},
243 { "S", IFMT
, IFSHAD
},
244 { "s", IFMT
, IFSOCK
},
245 { "A", IFMT
, IFATTRDIR
},
249 if (!(flags
& DCMD_ADDRSPEC
))
252 if (mdb_getopts(argc
, argv
,
253 'v', MDB_OPT_SETBITS
, TRUE
, &verbose
, NULL
) != argc
)
256 if (DCMD_HDRSPEC(flags
) && (flags
& DCMD_PIPE_OUT
) == 0) {
257 mdb_printf("%<u>%-?s %10s %1s %5s %8s",
258 "ADDR", "INUMBER", "T", "MODE", "SIZE");
261 mdb_printf(" %11s %-22s%</u>\n", "DEVICE", "FLAG");
263 mdb_printf(" %-12s %-21s%</u>\n", "MTIME", "NAME");
266 if (mdb_vread(&inode
, sizeof (inode
), addr
) == -1) {
267 mdb_warn("failed to read inode_t at %p", addr
);
271 mdb_printf("%0?p %10lld %b %5#o %8llx",
272 addr
, (u_longlong_t
)inode
.i_number
, inode
.i_mode
, i_modetype_masks
,
273 inode
.i_mode
& ~IFMT
, inode
.i_size
);
277 mdb_printf(" %11lx <%b>\n",
278 inode
.i_dev
, inode
.i_flag
, i_flag_masks
);
282 mdb_printf("%Y\n", inode
.i_mtime
.tv_sec
);
284 if (mdb_vnode2path((uintptr_t)inode
.i_vnode
, path
,
285 sizeof (path
)) == 0 && *path
!= '\0')
286 mdb_printf("%s\n", path
);
296 * Not verbose, everything must fit into one line.
298 mdb_snprintf(buf
, sizeof (buf
), "%Y", inode
.i_mtime
.tv_sec
);
299 buf
[17] = '\0'; /* drop seconds */
300 if (buf
[0] == '1' || buf
[0] == '2')
301 mdb_printf(" %12s", buf
+ 5); /* drop year */
303 mdb_printf(" %-12s", "?");
305 if (mdb_vnode2path((uintptr_t)inode
.i_vnode
, path
,
306 sizeof (path
)) == 0 && *path
!= '\0') {
307 if (strlen(path
) <= 21)
308 mdb_printf(" %-21s\n", path
);
310 mdb_printf(" ...%-18s\n", path
+ strlen(path
) - 18);
322 { offsetof(si_t
, aowner
), "USER_OBJ" },
323 { offsetof(si_t
, agroup
), "GROUP_OBJ" },
324 { offsetof(si_t
, aother
), "OTHER_OBJ" },
325 { offsetof(si_t
, ausers
), "USER" },
326 { offsetof(si_t
, agroups
), "GROUP" },
327 { offsetof(si_t
, downer
), "DEF_USER_OBJ" },
328 { offsetof(si_t
, dgroup
), "DEF_GROUP_OBJ" },
329 { offsetof(si_t
, dother
), "DEF_OTHER_OBJ" },
330 { offsetof(si_t
, dusers
), "DEF_USER" },
331 { offsetof(si_t
, dgroups
), "DEF_GROUP" },
336 acl_walk_init(mdb_walk_state_t
*wsp
)
338 uintptr_t addr
= wsp
->walk_addr
;
341 ufs_ic_acl_t
**aclpp
;
343 if (addr
== (uintptr_t)NULL
) {
344 mdb_warn("acl walk needs an inode address\n");
348 if (mdb_vread(&inode
, sizeof (inode
), addr
) == -1) {
349 mdb_warn("failed to read inode_t at %p", addr
);
353 if (inode
.i_ufs_acl
== NULL
)
356 si
= mdb_alloc(sizeof (si_t
), UM_SLEEP
);
358 if (mdb_vread(si
, sizeof (si_t
), (uintptr_t)inode
.i_ufs_acl
) == -1) {
359 mdb_warn("failed to read si_t at %p", inode
.i_ufs_acl
);
360 mdb_free(si
, sizeof (si_t
));
364 /* LINTED - alignment */
365 aclpp
= (ufs_ic_acl_t
**)((caddr_t
)si
+ acl_map
[0].am_offset
);
367 wsp
->walk_addr
= (uintptr_t)*aclpp
;
375 acl_walk_step(mdb_walk_state_t
*wsp
)
377 uintptr_t addr
= wsp
->walk_addr
;
378 si_t
*si
= wsp
->walk_data
;
379 uint_t i
= (uintptr_t)wsp
->walk_arg
;
380 ufs_ic_acl_t
**aclpp
;
383 while (addr
== (uintptr_t)NULL
) {
384 wsp
->walk_arg
= (void *)(uintptr_t)++i
;
386 if (acl_map
[i
].am_offset
== -1)
389 /* LINTED - alignment */
390 aclpp
= (ufs_ic_acl_t
**)((caddr_t
)si
+ acl_map
[i
].am_offset
);
392 addr
= (uintptr_t)*aclpp
;
395 if (mdb_vread(&acl
, sizeof (acl
), addr
) == -1) {
396 mdb_warn("failed to read acl at %p", addr
);
400 wsp
->walk_addr
= (uintptr_t)acl
.acl_ic_next
;
402 return (wsp
->walk_callback(addr
, &acl
, acl_map
[i
].am_tag
));
406 acl_walk_fini(mdb_walk_state_t
*wsp
)
408 mdb_free(wsp
->walk_data
, sizeof (si_t
));
412 acl_cb(uintptr_t addr
, const void *arg
, void *data
)
414 ufs_ic_acl_t
*aclp
= (ufs_ic_acl_t
*)arg
;
416 mdb_printf("%?p %-16s %7#o %10d\n",
417 addr
, (char *)data
, aclp
->acl_ic_perm
, aclp
->acl_ic_who
);
424 acl_dcmd(uintptr_t addr
, uint_t flags
, int argc
, const mdb_arg_t
*argv
)
426 if (!(flags
& DCMD_ADDRSPEC
))
432 if (DCMD_HDRSPEC(flags
)) {
433 mdb_printf("%<u>%?s %-16s %7s %10s%</u>\n",
434 "ADDR", "TAG", "PERM", "WHO");
437 if (mdb_pwalk("acl", (mdb_walk_cb_t
)acl_cb
, NULL
, addr
) == -1) {
438 mdb_warn("can't walk acls of inode %p", addr
);
447 cg_walk_init(mdb_walk_state_t
*wsp
)
449 if (mdb_layered_walk("buf", wsp
) == -1) {
450 mdb_warn("couldn't walk bio buf hash");
458 cg_walk_step(mdb_walk_state_t
*wsp
)
460 uintptr_t addr
= (uintptr_t)((const buf_t
*)wsp
->walk_layer
)->b_un
.b_cg
;
463 if (mdb_vread(&cg
, sizeof (cg
), addr
) == -1) {
464 mdb_warn("failed to read cg struct at %p", addr
);
468 if (cg
.cg_magic
!= CG_MAGIC
)
471 return (wsp
->walk_callback(addr
, &cg
, wsp
->walk_cbdata
));
475 pbits(const uchar_t
*cp
, const int max
, const int linelen
)
481 for (i
= 0; i
< max
; i
++) {
483 len
= mdb_snprintf(entry
, sizeof (entry
), "%d", i
);
485 while ((i
+ 1) < max
&& isset(cp
, i
+1))
488 len
+= mdb_snprintf(entry
+ len
,
489 sizeof (entry
) - len
, "-%d", i
);
493 mdb_printf("%s", entry
);
494 linecnt
= linelen
- len
;
495 } else if (linecnt
- (len
+ 3) > 0) {
496 /* subsequent entry on same line */
497 mdb_printf(", %s", entry
);
500 /* subsequent enty on new line */
501 mdb_printf(",\n%s", entry
);
502 linecnt
= linelen
- len
;
511 cg(uintptr_t addr
, uint_t flags
, int argc
, const mdb_arg_t
*argv
)
513 uint_t verbose
= FALSE
;
515 struct cg
*cgp
= &cg
;
521 if (!(flags
& DCMD_ADDRSPEC
)) {
522 if (mdb_walk_dcmd("cg", "cg", argc
, argv
) == -1) {
523 mdb_warn("can't walk cylinder group structs");
529 if (mdb_getopts(argc
, argv
,
530 'v', MDB_OPT_SETBITS
, TRUE
, &verbose
, NULL
) != argc
)
533 if (mdb_vread(cgp
, sizeof (cg
), addr
) == -1) {
534 mdb_warn("failed to read cg struct at %p", addr
);
539 if (DCMD_HDRSPEC(flags
))
540 mdb_printf("%<u>%4s %?s %10s %10s %10s %10s%</u>\n",
541 "CGX", "CG", "NDIR", "NBFREE", "NIFREE", "NFFREE");
543 mdb_printf("%4d %?p %10d %10d %10d %10d\n", cgp
->cg_cgx
,
544 addr
, cgp
->cg_cs
.cs_ndir
, cgp
->cg_cs
.cs_nbfree
,
545 cgp
->cg_cs
.cs_nifree
, cgp
->cg_cs
.cs_nffree
);
551 * Verbose: produce output similiar to "fstyp -v".
553 if (cgp
->cg_btotoff
>= cgp
->cg_nextfreeoff
||
554 cgp
->cg_boff
>= cgp
->cg_nextfreeoff
||
555 cgp
->cg_iusedoff
>= cgp
->cg_nextfreeoff
||
556 cgp
->cg_freeoff
>= cgp
->cg_nextfreeoff
) {
557 mdb_warn("struct cg at %p seems broken\n", addr
);
561 size
= cgp
->cg_nextfreeoff
;
562 cgp
= mdb_alloc(size
, UM_SLEEP
);
564 if (mdb_vread(cgp
, size
, addr
) == -1) {
565 mdb_warn("failed to read struct cg and maps at %p", addr
);
570 mdb_printf("%<b>cg %d (%0?p)%</b>\n", cgp
->cg_cgx
, addr
);
574 mdb_printf("time:\t%Y\n", cgp
->cg_time
);
575 mdb_printf("ndir:\t%d\n", cgp
->cg_cs
.cs_ndir
);
576 mdb_printf("nbfree:\t%d\n", cgp
->cg_cs
.cs_nbfree
);
577 mdb_printf("nifree:\t%d\n", cgp
->cg_cs
.cs_nifree
);
578 mdb_printf("nffree:\t%d\n", cgp
->cg_cs
.cs_nffree
);
580 mdb_printf("frsum:");
581 for (i
= 1; i
< MAXFRAG
; i
++)
582 mdb_printf("\t%d", cgp
->cg_frsum
[i
]);
585 off
= cgp
->cg_iusedoff
;
586 mdb_printf("used inode map (%0?p):\n", (char *)addr
+ off
);
588 pbits((uchar_t
*)cgp
+ off
, cgp
->cg_niblk
/ sizeof (char), 72);
591 off
= cgp
->cg_freeoff
;
592 mdb_printf("free block map (%0?p):\n", (char *)addr
+ off
);
594 pbits((uchar_t
*)cgp
+ off
, cgp
->cg_ndblk
/ sizeof (char), 72);
597 /* LINTED - alignment */
598 blktot
= (int32_t *)((char *)cgp
+ cgp
->cg_btotoff
);
599 /* LINTED - alignment */
600 blks
= (short *)((char *)cgp
+ cgp
->cg_boff
);
601 cnt
= (cgp
->cg_iusedoff
- cgp
->cg_boff
) / cgp
->cg_ncyl
/ sizeof (short);
602 mdb_printf("free block positions:\n");
605 for (i
= 0; i
< cgp
->cg_ncyl
; i
++) {
606 mdb_printf("c%d:\t(%d)\t", i
, blktot
[i
]);
607 for (j
= 0; j
< cnt
; j
++)
608 mdb_printf(" %d", blks
[i
*cnt
+ j
]);
622 inode_cache_help(void)
625 "Displays cached inode_t. If an address, an inode number and/or a\n"
626 "device is specified, searches inode cache for inodes which match\n"
627 "the specified criteria. Prints nothing but the address, if\n"
628 "output is a pipe.\n"
631 " -d device Filter out inodes, which reside on the specified"
633 " -i inumber Filter out inodes with the specified inode"
640 static const mdb_dcmd_t dcmds
[] = {
641 { "inode_cache", "?[-d device] [-i inumber]",
642 "search/display inodes from inode cache",
643 inode_cache
, inode_cache_help
},
644 { "inode", ":[-v]", "display summarized inode_t", inode
},
645 { "acl", ":", "given an inode, display its in core acl's", acl_dcmd
},
646 { "cg", "?[-v]", "display a summarized cylinder group structure", cg
},
647 { "mapentry", ":", "dumps ufslog mapentry", mapentry_dcmd
},
648 { "mapstats", ":", "dumps ufslog stats", mapstats_dcmd
},
652 static const mdb_walker_t walkers
[] = {
653 { "inode_cache", "walk inode cache",
654 inode_walk_init
, inode_walk_step
, inode_walk_fini
},
655 { "acl", "given an inode, walk chains of in core acl's",
656 acl_walk_init
, acl_walk_step
, acl_walk_fini
},
657 { "cg", "walk cg's in bio buffer cache",
658 cg_walk_init
, cg_walk_step
, NULL
},
659 { "ufslogmap", "walk map entries in a ufs_log mt_map",
660 ufslogmap_walk_init
, ufslogmap_walk_step
, NULL
},
664 static const mdb_modinfo_t modinfo
= { MDB_API_VERSION
, dcmds
, walkers
};
666 const mdb_modinfo_t
*