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 (the "License").
6 * You may not use this file except in compliance with the License.
7 *
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.
12 *
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]
18 *
19 * CDDL HEADER END
20 */
21
22 /*
23 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
25 */
26
27 #include <sys/mdb_modapi.h>
28 #include <sys/types.h>
29 #include <sys/refstr_impl.h>
30 #include <sys/vnode.h>
31 #include <sys/vfs.h>
32
33 #include "smbfs.h"
34 #include "smbfs_node.h"
35
36 #define OPT_VERBOSE 0x0001 /* Be [-v]erbose in dcmd's */
37
38 /*
39 * This macro lets us easily use both sizeof (typename)
40 * and the string-ified typename for the error message.
41 */
42 #define SMBFS_OBJ_FETCH(obj_addr, obj_type, dest, err) \
43 if (mdb_vread(dest, sizeof (obj_type), ((uintptr_t)obj_addr)) \
44 != sizeof (obj_type)) { \
45 mdb_warn("error reading "#obj_type" at %p", obj_addr); \
46 return (err); \
47 }
48
49 /*
50 * We need to read in a private copy
51 * of every string we want to print out.
52 */
53 void
print_str(uintptr_t addr)54 print_str(uintptr_t addr)
55 {
56 char buf[64];
57 int len, mx = sizeof (buf) - 4;
58
59 if ((len = mdb_readstr(buf, sizeof (buf), addr)) <= 0) {
60 mdb_printf(" (%p)", addr);
61 } else {
62 if (len > mx)
63 strcpy(&buf[mx], "...");
64 mdb_printf(" %s", buf);
65 }
66 }
67
68 /*
69 * Dcmd (and callback function) to print a summary of
70 * all "smbfs" entries in the VFS list.
71 */
72
73 typedef struct smbfs_vfs_cbdata {
74 int flags;
75 int printed_header;
76 uintptr_t vfsops; /* filter by vfs ops pointer */
77 smbmntinfo_t smi; /* scratch space for smbfs_vfs_cb */
78 } smbfs_vfs_cbdata_t;
79
80 int
smbfs_vfs_cb(uintptr_t addr,const void * data,void * arg)81 smbfs_vfs_cb(uintptr_t addr, const void *data, void *arg)
82 {
83 const vfs_t *vfs = data;
84 smbfs_vfs_cbdata_t *cbd = arg;
85 uintptr_t ta;
86
87 /* Filter by matching smbfs ops vector. */
88 if (cbd->vfsops && cbd->vfsops != (uintptr_t)vfs->vfs_op) {
89 return (WALK_NEXT);
90 }
91
92 if (cbd->printed_header == 0) {
93 cbd->printed_header = 1;
94 mdb_printf("// vfs_t smbmntinfo_t mnt_path\n");
95 }
96
97 mdb_printf(" %-p", addr); /* vfs_t */
98 mdb_printf(" %-p", (uintptr_t)vfs->vfs_data);
99 /*
100 * Note: vfs_mntpt is a refstr_t.
101 * Advance to string member.
102 */
103 ta = (uintptr_t)vfs->vfs_mntpt;
104 ta += OFFSETOF(struct refstr, rs_string);
105 print_str(ta);
106 mdb_printf("\n");
107
108 if (cbd->flags & OPT_VERBOSE) {
109 mdb_inc_indent(2);
110 /* Don't fail the walk if this fails. */
111 if (mdb_vread(&cbd->smi, sizeof (cbd->smi),
112 (uintptr_t)vfs->vfs_data) == -1) {
113 mdb_warn("error reading smbmntinfo_t at %p",
114 (uintptr_t)vfs->vfs_data);
115 } else {
116 /* Interesting parts of smbmntinfo_t */
117 mdb_printf("smi_share: %p, smi_root: %p\n",
118 cbd->smi.smi_share, cbd->smi.smi_root);
119 }
120 mdb_dec_indent(2);
121 }
122
123 return (WALK_NEXT);
124 }
125
126 int
smbfs_vfs_dcmd(uintptr_t addr,uint_t flags,int argc,const mdb_arg_t * argv)127 smbfs_vfs_dcmd(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
128 {
129 smbfs_vfs_cbdata_t *cbd;
130 vfs_t *vfs;
131
132 cbd = mdb_zalloc(sizeof (*cbd), UM_SLEEP | UM_GC);
133
134 /*
135 * Get the ops address here, so things work
136 * even if the smbfs module is loaded later
137 * than this mdb module.
138 */
139 if (mdb_readvar(&cbd->vfsops, "smbfs_vfsops") == -1) {
140 mdb_warn("failed to find 'smbfs_vfsops'\n");
141 return (DCMD_ERR);
142 }
143
144 if (mdb_getopts(argc, argv,
145 'v', MDB_OPT_SETBITS, OPT_VERBOSE, &cbd->flags,
146 NULL) != argc) {
147 return (DCMD_USAGE);
148 }
149
150 if (!(flags & DCMD_ADDRSPEC)) {
151 if (mdb_walk("genunix`vfs", smbfs_vfs_cb, cbd)
152 == -1) {
153 mdb_warn("can't walk smbfs vfs");
154 return (DCMD_ERR);
155 }
156 return (DCMD_OK);
157 }
158
159 vfs = mdb_alloc(sizeof (*vfs), UM_SLEEP | UM_GC);
160 SMBFS_OBJ_FETCH(addr, vfs_t, vfs, DCMD_ERR);
161 smbfs_vfs_cb(addr, vfs, cbd);
162 return (DCMD_OK);
163 }
164
165 void
smbfs_vfs_help(void)166 smbfs_vfs_help(void)
167 {
168 mdb_printf(
169 "Display addresses of the mounted smbfs structures\n"
170 "and the pathname of the mountpoint\n"
171 "\nOptions:\n"
172 " -v display details of the smbmntinfo\n");
173 }
174
175 /*
176 * Dcmd (and callback function) to print a summary of
177 * all smbnodes in the node "hash" (cache) AVL tree.
178 */
179
180 typedef struct smbfs_node_cbdata {
181 int flags;
182 int printed_header;
183 vnode_t vn;
184 } smbfs_node_cbdata_t;
185
186 int
smbfs_node_cb(uintptr_t addr,const void * data,void * arg)187 smbfs_node_cb(uintptr_t addr, const void *data, void *arg)
188 {
189 const smbnode_t *np = data;
190 smbfs_node_cbdata_t *cbd = arg;
191
192 if (cbd->printed_header == 0) {
193 cbd->printed_header = 1;
194 mdb_printf("// vnode smbnode rpath\n");
195 }
196
197 mdb_printf(" %-p", (uintptr_t)np->r_vnode);
198 mdb_printf(" %-p", addr); /* smbnode */
199 print_str((uintptr_t)np->n_rpath);
200 mdb_printf("\n");
201
202 if (cbd->flags & OPT_VERBOSE) {
203 mdb_inc_indent(2);
204 /* Don't fail the walk if this fails. */
205 if (mdb_vread(&cbd->vn, sizeof (cbd->vn),
206 (uintptr_t)np->r_vnode) == -1) {
207 mdb_warn("error reading vnode_t at %p",
208 (uintptr_t)np->r_vnode);
209 } else {
210 /* Interesting parts of vnode_t */
211 mdb_printf("v_type=%d v_count=%d",
212 cbd->vn.v_type, cbd->vn.v_count);
213 mdb_printf("\n");
214 }
215 mdb_dec_indent(2);
216 }
217
218 return (WALK_NEXT);
219 }
220
221 int
smbfs_node_dcmd(uintptr_t addr,uint_t flags,int argc,const mdb_arg_t * argv)222 smbfs_node_dcmd(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
223 {
224 smbfs_node_cbdata_t *cbd;
225
226 cbd = mdb_zalloc(sizeof (*cbd), UM_SLEEP | UM_GC);
227
228 if (mdb_getopts(argc, argv,
229 'v', MDB_OPT_SETBITS, OPT_VERBOSE, &cbd->flags,
230 NULL) != argc) {
231 return (DCMD_USAGE);
232 }
233
234 if (!(flags & DCMD_ADDRSPEC)) {
235 mdb_warn("expect an smbmntinfo_t addr");
236 return (DCMD_USAGE);
237 }
238 addr += OFFSETOF(smbmntinfo_t, smi_hash_avl);
239
240 if (mdb_pwalk("genunix`avl", smbfs_node_cb, cbd, addr) == -1) {
241 mdb_warn("cannot walk smbfs nodes");
242 return (DCMD_ERR);
243 }
244
245 return (DCMD_OK);
246 }
247
248 void
smbfs_node_help(void)249 smbfs_node_help(void)
250 {
251 mdb_printf("Options:\n"
252 " -v be verbose when displaying smbnodes\n");
253 }
254
255 static const mdb_dcmd_t dcmds[] = {
256 {
257 "smbfs_vfs", "?[-v]",
258 "show smbfs-mounted vfs structs",
259 smbfs_vfs_dcmd, smbfs_vfs_help
260 },
261 {
262 "smbfs_node", "?[-v]",
263 "given an smbmntinfo_t, list smbnodes",
264 smbfs_node_dcmd, smbfs_node_help
265 },
266 {NULL}
267 };
268
269 static const mdb_walker_t walkers[] = {
270 {NULL}
271 };
272
273 static const mdb_modinfo_t modinfo = {
274 MDB_API_VERSION,
275 dcmds,
276 walkers
277 };
278
279 const mdb_modinfo_t *
_mdb_init(void)280 _mdb_init(void)
281 {
282 return (&modinfo);
283 }
284