xref: /illumos-gate/usr/src/cmd/mdb/common/modules/lofs/lofs.c (revision 2f172c55ef76964744bc62b4500ece87f3089b4d)
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, Version 1.0 only
6  * (the "License").  You may not use this file except in compliance
7  * with the License.
8  *
9  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10  * or http://www.opensolaris.org/os/licensing.
11  * See the License for the specific language governing permissions
12  * and limitations under the License.
13  *
14  * When distributing Covered Code, include this CDDL HEADER in each
15  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16  * If applicable, add the following below this CDDL HEADER, with the
17  * fields enclosed by brackets "[]" replaced with your own identifying
18  * information: Portions Copyright [yyyy] [name of copyright owner]
19  *
20  * CDDL HEADER END
21  */
22 /*
23  * Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 #pragma ident	"%Z%%M%	%I%	%E% SMI"
28 
29 #include <sys/types.h>
30 #include <sys/vfs.h>
31 #include <sys/fs/lofs_node.h>
32 #include <sys/fs/lofs_info.h>
33 
34 #include <mdb/mdb_modapi.h>
35 
36 typedef struct lnode_walk {
37 	struct lobucket *lw_table;	/* Snapshot of hash table */
38 	uint_t lw_tabsz;		/* Size of hash table */
39 	uint_t lw_tabi;			/* Current table index */
40 	lnode_t *lw_lnode;		/* Current buffer */
41 } lnode_walk_t;
42 
43 int
44 lnode_walk_init(mdb_walk_state_t *wsp)
45 {
46 	lnode_walk_t *lwp;
47 
48 	int lofsfstype;
49 	struct vfs vfs;
50 	struct loinfo loinfo;
51 
52 	if (mdb_readvar(&lofsfstype, "lofsfstype") == -1) {
53 		mdb_warn("failed to read 'lofsfstype' symbol\n");
54 		return (WALK_ERR);
55 	}
56 
57 	if (wsp->walk_addr == NULL) {
58 		uintptr_t rootvfsp, vfsp;
59 		uint_t htsize;
60 
61 		lwp = mdb_alloc(sizeof (lnode_walk_t), UM_SLEEP);
62 
63 retry:
64 		lwp->lw_tabsz = 0;
65 		if (mdb_readvar(&rootvfsp, "rootvfs") == -1) {
66 			mdb_warn("failed to read 'rootvfs' symbol\n");
67 			mdb_free(lwp, sizeof (lnode_walk_t));
68 			return (WALK_ERR);
69 		}
70 
71 		vfsp = rootvfsp;
72 		do {
73 			(void) mdb_vread(&vfs, sizeof (vfs), vfsp);
74 			if (lofsfstype != vfs.vfs_fstype) {
75 				vfsp = (uintptr_t)vfs.vfs_next;
76 				continue;
77 			}
78 			(void) mdb_vread(&loinfo, sizeof (struct loinfo),
79 			    (uintptr_t)vfs.vfs_data);
80 			lwp->lw_tabsz += loinfo.li_htsize;
81 			vfsp = (uintptr_t)vfs.vfs_next;
82 		} while (vfsp != rootvfsp);
83 
84 		if (lwp->lw_tabsz == 0) {
85 			/*
86 			 * No lofs filesystems mounted.
87 			 */
88 			mdb_free(lwp, sizeof (lnode_walk_t));
89 			return (WALK_DONE);
90 		}
91 		lwp->lw_table = mdb_alloc(lwp->lw_tabsz *
92 		    sizeof (struct lobucket), UM_SLEEP);
93 		htsize = 0;
94 
95 		vfsp = rootvfsp;
96 		do {
97 			(void) mdb_vread(&vfs, sizeof (vfs), vfsp);
98 			if (lofsfstype != vfs.vfs_fstype) {
99 				vfsp = (uintptr_t)vfs.vfs_next;
100 				continue;
101 			}
102 			(void) mdb_vread(&loinfo, sizeof (struct loinfo),
103 			    (uintptr_t)vfs.vfs_data);
104 			if (htsize + loinfo.li_htsize > lwp->lw_tabsz) {
105 				/*
106 				 * Something must have resized.
107 				 */
108 				mdb_free(lwp->lw_table,
109 				    lwp->lw_tabsz * sizeof (struct lobucket));
110 				goto retry;
111 			}
112 			(void) mdb_vread(lwp->lw_table + htsize,
113 			    loinfo.li_htsize * sizeof (struct lobucket),
114 			    (uintptr_t)loinfo.li_hashtable);
115 			htsize += loinfo.li_htsize;
116 			vfsp = (uintptr_t)vfs.vfs_next;
117 		} while (vfsp != rootvfsp);
118 	} else {
119 		if (mdb_vread(&vfs, sizeof (vfs_t), wsp->walk_addr) == -1) {
120 			mdb_warn("failed to read from '%p'\n", wsp->walk_addr);
121 			return (WALK_ERR);
122 		}
123 		if (lofsfstype != vfs.vfs_fstype) {
124 			mdb_warn("%p does not point to a lofs mount vfs\n",
125 			    wsp->walk_addr);
126 			return (WALK_ERR);
127 		}
128 		if (mdb_vread(&loinfo, sizeof (loinfo),
129 		    (uintptr_t)vfs.vfs_data) == -1) {
130 			mdb_warn("failed to read struct loinfo from '%p'\n",
131 			    vfs.vfs_data);
132 			return (WALK_ERR);
133 		}
134 
135 		lwp = mdb_alloc(sizeof (lnode_walk_t), UM_SLEEP);
136 		lwp->lw_tabsz = loinfo.li_htsize;
137 		lwp->lw_table = mdb_alloc(lwp->lw_tabsz *
138 		    sizeof (struct lobucket), UM_SLEEP);
139 		(void) mdb_vread(lwp->lw_table,
140 		    lwp->lw_tabsz * sizeof (struct lobucket),
141 		    (uintptr_t)loinfo.li_hashtable);
142 	}
143 	lwp->lw_tabi = 0;
144 	lwp->lw_lnode = mdb_alloc(sizeof (lnode_t), UM_SLEEP);
145 
146 	wsp->walk_addr = (uintptr_t)lwp->lw_table[0].lh_chain;
147 	wsp->walk_data = lwp;
148 
149 	return (WALK_NEXT);
150 }
151 
152 int
153 lnode_walk_step(mdb_walk_state_t *wsp)
154 {
155 	lnode_walk_t *lwp = wsp->walk_data;
156 	uintptr_t addr;
157 
158 	/*
159 	 * If the next lnode_t address we want is NULL, advance to the next
160 	 * hash bucket.  When we reach lw_tabsz, we're done.
161 	 */
162 	while (wsp->walk_addr == NULL) {
163 		if (++lwp->lw_tabi < lwp->lw_tabsz)
164 			wsp->walk_addr =
165 			    (uintptr_t)lwp->lw_table[lwp->lw_tabi].lh_chain;
166 		else
167 			return (WALK_DONE);
168 	}
169 
170 	/*
171 	 * When we have an lnode_t address, read the lnode and invoke the
172 	 * walk callback.  Keep the next lnode_t address in wsp->walk_addr.
173 	 */
174 	addr = wsp->walk_addr;
175 	(void) mdb_vread(lwp->lw_lnode, sizeof (lnode_t), addr);
176 	wsp->walk_addr = (uintptr_t)lwp->lw_lnode->lo_next;
177 
178 	return (wsp->walk_callback(addr, lwp->lw_lnode, wsp->walk_cbdata));
179 }
180 
181 void
182 lnode_walk_fini(mdb_walk_state_t *wsp)
183 {
184 	lnode_walk_t *lwp = wsp->walk_data;
185 
186 	mdb_free(lwp->lw_table, lwp->lw_tabsz * sizeof (struct lobucket));
187 	mdb_free(lwp->lw_lnode, sizeof (lnode_t));
188 	mdb_free(lwp, sizeof (lnode_walk_t));
189 }
190 
191 /*ARGSUSED*/
192 static int
193 lnode_format(uintptr_t addr, const void *data, void *private)
194 {
195 	const lnode_t *lop = data;
196 
197 	mdb_printf("%?p %?p %?p\n",
198 	    addr, lop->lo_vnode, lop->lo_vp);
199 
200 	return (DCMD_OK);
201 }
202 
203 /*ARGSUSED*/
204 int
205 lnode(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
206 {
207 	if (argc != 0)
208 		return (DCMD_USAGE);
209 
210 	if (DCMD_HDRSPEC(flags)) {
211 		mdb_printf("%<u>%?s %?s %?s%</u>\n",
212 		    "LNODE", "VNODE", "REALVP");
213 	}
214 
215 	if (flags & DCMD_ADDRSPEC) {
216 		lnode_t lo;
217 
218 		(void) mdb_vread(&lo, sizeof (lo), addr);
219 		return (lnode_format(addr, &lo, NULL));
220 	}
221 
222 	if (mdb_walk("lnode", lnode_format, NULL) == -1)
223 		return (DCMD_ERR);
224 
225 	return (DCMD_OK);
226 }
227 
228 /*ARGSUSED*/
229 int
230 lnode2dev(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
231 {
232 	lnode_t lo;
233 	vnode_t	vno;
234 	vfs_t vfs;
235 
236 	if (argc != 0)
237 		return (DCMD_ERR);
238 
239 	(void) mdb_vread(&lo, sizeof (lo), addr);
240 	(void) mdb_vread(&vno, sizeof (vno), (uintptr_t)lo.lo_vnode);
241 	(void) mdb_vread(&vfs, sizeof (vfs), (uintptr_t)vno.v_vfsp);
242 
243 	mdb_printf("lnode %p vfs_dev %0?lx\n", addr, vfs.vfs_dev);
244 	return (DCMD_OK);
245 }
246 
247 static const mdb_dcmd_t dcmds[] = {
248 	{ "lnode", NULL, "print lnode structure(s)", lnode },
249 	{ "lnode2dev", ":", "print vfs_dev given lnode", lnode2dev },
250 	{ NULL }
251 };
252 
253 static const mdb_walker_t walkers[] = {
254 	{ "lnode", "hash of lnode structures",
255 		lnode_walk_init, lnode_walk_step, lnode_walk_fini },
256 	{ NULL }
257 };
258 
259 static const mdb_modinfo_t modinfo = {
260 	MDB_API_VERSION, dcmds, walkers
261 };
262 
263 const mdb_modinfo_t *
264 _mdb_init(void)
265 {
266 	return (&modinfo);
267 }
268