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 #include <sys/types.h>
28 #include <sys/vfs.h>
29 #include <sys/fs/lofs_node.h>
30 #include <sys/fs/lofs_info.h>
31
32 #include <mdb/mdb_modapi.h>
33
34 typedef struct lnode_walk {
35 struct lobucket *lw_table; /* Snapshot of hash table */
36 uint_t lw_tabsz; /* Size of hash table */
37 uint_t lw_tabi; /* Current table index */
38 lnode_t *lw_lnode; /* Current buffer */
39 } lnode_walk_t;
40
41 int
lnode_walk_init(mdb_walk_state_t * wsp)42 lnode_walk_init(mdb_walk_state_t *wsp)
43 {
44 lnode_walk_t *lwp;
45
46 int lofsfstype;
47 struct vfs vfs;
48 struct loinfo loinfo;
49
50 if (mdb_readvar(&lofsfstype, "lofsfstype") == -1) {
51 mdb_warn("failed to read 'lofsfstype' symbol\n");
52 return (WALK_ERR);
53 }
54
55 if (wsp->walk_addr == 0) {
56 uintptr_t rootvfsp, vfsp;
57 uint_t htsize;
58
59 lwp = mdb_alloc(sizeof (lnode_walk_t), UM_SLEEP);
60
61 retry:
62 lwp->lw_tabsz = 0;
63 if (mdb_readvar(&rootvfsp, "rootvfs") == -1) {
64 mdb_warn("failed to read 'rootvfs' symbol\n");
65 mdb_free(lwp, sizeof (lnode_walk_t));
66 return (WALK_ERR);
67 }
68
69 vfsp = rootvfsp;
70 do {
71 (void) mdb_vread(&vfs, sizeof (vfs), vfsp);
72 if (lofsfstype != vfs.vfs_fstype) {
73 vfsp = (uintptr_t)vfs.vfs_next;
74 continue;
75 }
76 (void) mdb_vread(&loinfo, sizeof (struct loinfo),
77 (uintptr_t)vfs.vfs_data);
78 lwp->lw_tabsz += loinfo.li_htsize;
79 vfsp = (uintptr_t)vfs.vfs_next;
80 } while (vfsp != rootvfsp);
81
82 if (lwp->lw_tabsz == 0) {
83 /*
84 * No lofs filesystems mounted.
85 */
86 mdb_free(lwp, sizeof (lnode_walk_t));
87 return (WALK_DONE);
88 }
89 lwp->lw_table = mdb_alloc(lwp->lw_tabsz *
90 sizeof (struct lobucket), UM_SLEEP);
91 htsize = 0;
92
93 vfsp = rootvfsp;
94 do {
95 (void) mdb_vread(&vfs, sizeof (vfs), vfsp);
96 if (lofsfstype != vfs.vfs_fstype) {
97 vfsp = (uintptr_t)vfs.vfs_next;
98 continue;
99 }
100 (void) mdb_vread(&loinfo, sizeof (struct loinfo),
101 (uintptr_t)vfs.vfs_data);
102 if (htsize + loinfo.li_htsize > lwp->lw_tabsz) {
103 /*
104 * Something must have resized.
105 */
106 mdb_free(lwp->lw_table,
107 lwp->lw_tabsz * sizeof (struct lobucket));
108 goto retry;
109 }
110 (void) mdb_vread(lwp->lw_table + htsize,
111 loinfo.li_htsize * sizeof (struct lobucket),
112 (uintptr_t)loinfo.li_hashtable);
113 htsize += loinfo.li_htsize;
114 vfsp = (uintptr_t)vfs.vfs_next;
115 } while (vfsp != rootvfsp);
116 } else {
117 if (mdb_vread(&vfs, sizeof (vfs_t), wsp->walk_addr) == -1) {
118 mdb_warn("failed to read from '%p'\n", wsp->walk_addr);
119 return (WALK_ERR);
120 }
121 if (lofsfstype != vfs.vfs_fstype) {
122 mdb_warn("%p does not point to a lofs mount vfs\n",
123 wsp->walk_addr);
124 return (WALK_ERR);
125 }
126 if (mdb_vread(&loinfo, sizeof (loinfo),
127 (uintptr_t)vfs.vfs_data) == -1) {
128 mdb_warn("failed to read struct loinfo from '%p'\n",
129 vfs.vfs_data);
130 return (WALK_ERR);
131 }
132
133 lwp = mdb_alloc(sizeof (lnode_walk_t), UM_SLEEP);
134 lwp->lw_tabsz = loinfo.li_htsize;
135 lwp->lw_table = mdb_alloc(lwp->lw_tabsz *
136 sizeof (struct lobucket), UM_SLEEP);
137 (void) mdb_vread(lwp->lw_table,
138 lwp->lw_tabsz * sizeof (struct lobucket),
139 (uintptr_t)loinfo.li_hashtable);
140 }
141 lwp->lw_tabi = 0;
142 lwp->lw_lnode = mdb_alloc(sizeof (lnode_t), UM_SLEEP);
143
144 wsp->walk_addr = (uintptr_t)lwp->lw_table[0].lh_chain;
145 wsp->walk_data = lwp;
146
147 return (WALK_NEXT);
148 }
149
150 int
lnode_walk_step(mdb_walk_state_t * wsp)151 lnode_walk_step(mdb_walk_state_t *wsp)
152 {
153 lnode_walk_t *lwp = wsp->walk_data;
154 uintptr_t addr;
155
156 /*
157 * If the next lnode_t address we want is NULL, advance to the next
158 * hash bucket. When we reach lw_tabsz, we're done.
159 */
160 while (wsp->walk_addr == 0) {
161 if (++lwp->lw_tabi < lwp->lw_tabsz)
162 wsp->walk_addr =
163 (uintptr_t)lwp->lw_table[lwp->lw_tabi].lh_chain;
164 else
165 return (WALK_DONE);
166 }
167
168 /*
169 * When we have an lnode_t address, read the lnode and invoke the
170 * walk callback. Keep the next lnode_t address in wsp->walk_addr.
171 */
172 addr = wsp->walk_addr;
173 (void) mdb_vread(lwp->lw_lnode, sizeof (lnode_t), addr);
174 wsp->walk_addr = (uintptr_t)lwp->lw_lnode->lo_next;
175
176 return (wsp->walk_callback(addr, lwp->lw_lnode, wsp->walk_cbdata));
177 }
178
179 void
lnode_walk_fini(mdb_walk_state_t * wsp)180 lnode_walk_fini(mdb_walk_state_t *wsp)
181 {
182 lnode_walk_t *lwp = wsp->walk_data;
183
184 mdb_free(lwp->lw_table, lwp->lw_tabsz * sizeof (struct lobucket));
185 mdb_free(lwp->lw_lnode, sizeof (lnode_t));
186 mdb_free(lwp, sizeof (lnode_walk_t));
187 }
188
189 /*ARGSUSED*/
190 static int
lnode_format(uintptr_t addr,const void * data,void * private)191 lnode_format(uintptr_t addr, const void *data, void *private)
192 {
193 const lnode_t *lop = data;
194
195 mdb_printf("%?p %?p %?p\n",
196 addr, lop->lo_vnode, lop->lo_vp);
197
198 return (DCMD_OK);
199 }
200
201 /*ARGSUSED*/
202 int
lnode(uintptr_t addr,uint_t flags,int argc,const mdb_arg_t * argv)203 lnode(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
204 {
205 if (argc != 0)
206 return (DCMD_USAGE);
207
208 if (DCMD_HDRSPEC(flags)) {
209 mdb_printf("%<u>%?s %?s %?s%</u>\n",
210 "LNODE", "VNODE", "REALVP");
211 }
212
213 if (flags & DCMD_ADDRSPEC) {
214 lnode_t lo;
215
216 (void) mdb_vread(&lo, sizeof (lo), addr);
217 return (lnode_format(addr, &lo, NULL));
218 }
219
220 if (mdb_walk("lnode", lnode_format, NULL) == -1)
221 return (DCMD_ERR);
222
223 return (DCMD_OK);
224 }
225
226 /*ARGSUSED*/
227 int
lnode2dev(uintptr_t addr,uint_t flags,int argc,const mdb_arg_t * argv)228 lnode2dev(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
229 {
230 lnode_t lo;
231 vnode_t vno;
232 vfs_t vfs;
233
234 if (argc != 0)
235 return (DCMD_ERR);
236
237 (void) mdb_vread(&lo, sizeof (lo), addr);
238 (void) mdb_vread(&vno, sizeof (vno), (uintptr_t)lo.lo_vnode);
239 (void) mdb_vread(&vfs, sizeof (vfs), (uintptr_t)vno.v_vfsp);
240
241 mdb_printf("lnode %p vfs_dev %0?lx\n", addr, vfs.vfs_dev);
242 return (DCMD_OK);
243 }
244
245 static const mdb_dcmd_t dcmds[] = {
246 { "lnode", NULL, "print lnode structure(s)", lnode },
247 { "lnode2dev", ":", "print vfs_dev given lnode", lnode2dev },
248 { NULL }
249 };
250
251 static const mdb_walker_t walkers[] = {
252 { "lnode", "hash of lnode structures",
253 lnode_walk_init, lnode_walk_step, lnode_walk_fini },
254 { NULL }
255 };
256
257 static const mdb_modinfo_t modinfo = {
258 MDB_API_VERSION, dcmds, walkers
259 };
260
261 const mdb_modinfo_t *
_mdb_init(void)262 _mdb_init(void)
263 {
264 return (&modinfo);
265 }
266