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