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