xref: /illumos-gate/usr/src/cmd/mdb/common/modules/smbfs/smbfs.c (revision 581cede61ac9c14d8d4ea452562a567189eead78)
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 2008 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 
28 #pragma ident	"%Z%%M%	%I%	%E% SMI"
29 
30 #include <sys/mdb_modapi.h>
31 #include <sys/types.h>
32 #include <sys/refstr_impl.h>
33 #include <sys/vnode.h>
34 #include <sys/vfs.h>
35 
36 #include "smbfs.h"
37 #include "smbfs_node.h"
38 
39 #define	OPT_VERBOSE	0x0001	/* Be [-v]erbose in dcmd's */
40 
41 /*
42  * This macro lets us easily use both sizeof (typename)
43  * and the string-ified typename for the error message.
44  */
45 #define	SMBFS_OBJ_FETCH(obj_addr, obj_type, dest, err) \
46 	if (mdb_vread(dest, sizeof (obj_type), ((uintptr_t)obj_addr)) \
47 	!= sizeof (obj_type)) { \
48 		mdb_warn("error reading "#obj_type" at %p", obj_addr); \
49 		return (err); \
50 	}
51 
52 /*
53  * We need to read in a private copy
54  * of every string we want to print out.
55  */
56 void
57 print_str(uintptr_t addr)
58 {
59 	char buf[64];
60 	int len, mx = sizeof (buf) - 4;
61 
62 	if ((len = mdb_readstr(buf, sizeof (buf), addr)) <= 0) {
63 		mdb_printf(" (%p)", addr);
64 	} else {
65 		if (len > mx)
66 			strcpy(&buf[mx], "...");
67 		mdb_printf(" %s", buf);
68 	}
69 }
70 
71 /*
72  * Dcmd (and callback function) to print a summary of
73  * all "smbfs" entries in the VFS list.
74  */
75 
76 typedef struct smbfs_vfs_cbdata {
77 	int flags;
78 	int printed_header;
79 	uintptr_t vfsops;	/* filter by vfs ops pointer */
80 	smbmntinfo_t smi;	/* scratch space for smbfs_vfs_cb */
81 } smbfs_vfs_cbdata_t;
82 
83 int
84 smbfs_vfs_cb(uintptr_t addr, const void *data, void *arg)
85 {
86 	const vfs_t *vfs = data;
87 	smbfs_vfs_cbdata_t *cbd = arg;
88 	uintptr_t ta;
89 
90 	/* Filter by matching smbfs ops vector. */
91 	if (cbd->vfsops && cbd->vfsops != (uintptr_t)vfs->vfs_op) {
92 		return (WALK_NEXT);
93 	}
94 
95 	if (cbd->printed_header == 0) {
96 		cbd->printed_header = 1;
97 		mdb_printf("// vfs_t smbmntinfo_t mnt_path\n");
98 	}
99 
100 	mdb_printf(" %-p", addr);	/* vfs_t */
101 	mdb_printf(" %-p", (uintptr_t)vfs->vfs_data);
102 	/*
103 	 * Note: vfs_mntpt is a refstr_t.
104 	 * Advance to string member.
105 	 */
106 	ta = (uintptr_t)vfs->vfs_mntpt;
107 	ta += OFFSETOF(struct refstr, rs_string);
108 	print_str(ta);
109 	mdb_printf("\n");
110 
111 	if (cbd->flags & OPT_VERBOSE) {
112 		mdb_inc_indent(2);
113 		/* Don't fail the walk if this fails. */
114 		if (mdb_vread(&cbd->smi, sizeof (cbd->smi),
115 		    (uintptr_t)vfs->vfs_data) == -1) {
116 			mdb_warn("error reading smbmntinfo_t at %p",
117 			    (uintptr_t)vfs->vfs_data);
118 		} else {
119 			/* Interesting parts of smbmntinfo_t */
120 			mdb_printf("smi_share: %p, smi_root: %p\n",
121 			    cbd->smi.smi_share, cbd->smi.smi_root);
122 		}
123 		mdb_dec_indent(2);
124 	}
125 
126 	return (WALK_NEXT);
127 }
128 
129 int
130 smbfs_vfs_dcmd(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
131 {
132 	smbfs_vfs_cbdata_t *cbd;
133 	vfs_t *vfs;
134 
135 	cbd = mdb_zalloc(sizeof (*cbd),  UM_SLEEP | UM_GC);
136 
137 	/*
138 	 * Get the ops address here, so things work
139 	 * even if the smbfs module is loaded later
140 	 * than this mdb module.
141 	 */
142 	if (mdb_readvar(&cbd->vfsops, "smbfs_vfsops") == -1) {
143 		mdb_warn("failed to find 'smbfs_vfsops'\n");
144 		return (DCMD_ERR);
145 	}
146 
147 	if (mdb_getopts(argc, argv,
148 	    'v', MDB_OPT_SETBITS, OPT_VERBOSE, &cbd->flags,
149 	    NULL) != argc) {
150 		return (DCMD_USAGE);
151 	}
152 
153 	if (!(flags & DCMD_ADDRSPEC)) {
154 		if (mdb_walk("genunix`vfs", smbfs_vfs_cb, cbd)
155 		    == -1) {
156 			mdb_warn("can't walk smbfs vfs");
157 			return (DCMD_ERR);
158 		}
159 		return (DCMD_OK);
160 	}
161 
162 	vfs = mdb_alloc(sizeof (*vfs),  UM_SLEEP | UM_GC);
163 	SMBFS_OBJ_FETCH(addr, vfs_t, vfs, DCMD_ERR);
164 	smbfs_vfs_cb(addr, vfs, cbd);
165 	return (DCMD_OK);
166 }
167 
168 void
169 smbfs_vfs_help(void)
170 {
171 	mdb_printf(
172 	    "Display addresses of the mounted smbfs structures\n"
173 	    "and the pathname of the mountpoint\n"
174 	    "\nOptions:\n"
175 	    "  -v    display details of the smbmntinfo\n");
176 }
177 
178 /*
179  * Walker for the smbnode hash table.
180  */
181 
182 typedef struct smbnode_walk_data {
183 	rhashq_t *smbtab;	/* (our copy of) the smbtable */
184 	int tabsize;		/* size of table */
185 	int nextidx;		/* next bucket index */
186 	uintptr_t buckptr;	/* target addr of current bucket */
187 	uintptr_t nodeptr;	/* target addr of current smbnode */
188 	smbnode_t node; 	/* scratch space for _step */
189 } smbnode_walk_data_t;
190 
191 int
192 smbnode_walk_init(mdb_walk_state_t *wsp)
193 {
194 	size_t tabsz_bytes;
195 	int tabsize;
196 	uintptr_t smbtab;
197 	smbnode_walk_data_t *smbw;
198 
199 	if (wsp->walk_addr != NULL) {
200 		mdb_warn("smbnode only supports global walks\n");
201 		return (WALK_ERR);
202 	}
203 
204 	if (mdb_readvar(&tabsize, "smbtablesize") == -1) {
205 		mdb_warn("failed to read `smbtablesize'\n");
206 		return (WALK_ERR);
207 	}
208 
209 	if (tabsize == 0) {
210 		return (WALK_DONE);
211 	}
212 
213 	if (mdb_readvar(&smbtab, "smbtable") == -1) {
214 		mdb_warn("failed to read `smbtable'\n");
215 		return (WALK_ERR);
216 	}
217 
218 	smbw = mdb_alloc(sizeof (*smbw), UM_SLEEP | UM_GC);
219 
220 	tabsz_bytes = tabsize * sizeof (rhashq_t);
221 	smbw->smbtab  = mdb_alloc(tabsz_bytes, UM_SLEEP | UM_GC);
222 	if (mdb_vread(smbw->smbtab, tabsz_bytes, smbtab) != tabsz_bytes) {
223 		mdb_warn("failed to read in smbtable from %p", smbtab);
224 		return (WALK_ERR);
225 	}
226 	smbw->tabsize = tabsize;
227 	smbw->nextidx = 1;
228 	smbw->buckptr = smbtab;
229 	smbw->nodeptr = (uintptr_t)smbw->smbtab[0].r_hashf;
230 	wsp->walk_data = smbw;
231 
232 	return (WALK_NEXT);
233 }
234 
235 int
236 smbnode_walk_step(mdb_walk_state_t *wsp)
237 {
238 	smbnode_walk_data_t *smbw = wsp->walk_data;
239 	int status;
240 
241 next_bucket:
242 	while (smbw->nodeptr == smbw->buckptr &&
243 	    smbw->nextidx < smbw->tabsize) {
244 
245 		/* Skip an empty bucket */
246 		rhashq_t *h = &smbw->smbtab[smbw->nextidx];
247 		smbw->nodeptr = (uintptr_t)h->r_hashf;
248 		smbw->nextidx++;
249 		smbw->buckptr += sizeof (rhashq_t);
250 	}
251 
252 	if (smbw->nodeptr == smbw->buckptr)
253 		return (WALK_DONE);
254 
255 	if (mdb_vread(&smbw->node, sizeof (smbw->node),
256 	    smbw->nodeptr) != sizeof (smbw->node)) {
257 		mdb_warn("failed to read smbnode at %p in bucket %p\n",
258 		    smbw->nodeptr, smbw->buckptr);
259 		/* Proceed with next bucket. */
260 		smbw->nodeptr = smbw->buckptr;
261 		goto next_bucket;
262 	}
263 
264 	status = wsp->walk_callback(smbw->nodeptr,
265 	    &smbw->node, wsp->walk_cbdata);
266 
267 	/* Move to next node in this bucket */
268 	smbw->nodeptr = (uintptr_t)smbw->node.r_hashf;
269 
270 	return (status);
271 }
272 
273 /*ARGSUSED*/
274 void
275 smbnode_walk_fini(mdb_walk_state_t *wsp)
276 {
277 	/* UM_GC takes care of it all. */
278 }
279 
280 /*
281  * Dcmd (and callback function) to print a summary of
282  * all smbnodes in the node hash table.
283  */
284 
285 typedef struct smbnode_cbdata {
286 	int flags;
287 	int printed_header;
288 	uintptr_t smi;		/* optional filtering by VFS */
289 				/* TODO: only nodes with a given [-h]ash */
290 	vnode_t vn;			/* scratch space for smbnode_cb */
291 } smbnode_cbdata_t;
292 
293 int
294 smbnode_cb(uintptr_t addr, const void *data, void *arg)
295 {
296 	const smbnode_t *np = data;
297 	smbnode_cbdata_t *cbd = arg;
298 
299 	/* Optional filtering by mount point. */
300 	if (cbd->smi && cbd->smi != (uintptr_t)np->n_mount) {
301 		return (WALK_NEXT);
302 	}
303 
304 	if (cbd->printed_header == 0) {
305 		cbd->printed_header = 1;
306 		mdb_printf("// smbnode vnode rpath\n");
307 	}
308 
309 	mdb_printf(" %-p", addr);	/* smbnode */
310 	mdb_printf(" %-p", (uintptr_t)np->r_vnode);
311 	print_str((uintptr_t)np->n_rpath);
312 	mdb_printf("\n");
313 
314 	if (cbd->flags & OPT_VERBOSE) {
315 		mdb_inc_indent(2);
316 		/* Don't fail the walk if this fails. */
317 		if (mdb_vread(&cbd->vn, sizeof (cbd->vn),
318 		    (uintptr_t)np->r_vnode) == -1) {
319 			mdb_warn("error reading vnode_t at %p",
320 			    (uintptr_t)np->r_vnode);
321 		} else {
322 			/* Interesting parts of vnode_t */
323 			mdb_printf("v_type: %d v_path:",
324 			    cbd->vn.v_type);
325 			print_str((uintptr_t)cbd->vn.v_path);
326 			mdb_printf("\n");
327 		}
328 		mdb_dec_indent(2);
329 	}
330 
331 	return (WALK_NEXT);
332 }
333 
334 int
335 smbnode_dcmd(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
336 {
337 	smbnode_cbdata_t *cbd;
338 	smbnode_t *np;
339 
340 	cbd = mdb_zalloc(sizeof (*cbd), UM_SLEEP | UM_GC);
341 
342 	if (mdb_getopts(argc, argv,
343 	    'v', MDB_OPT_SETBITS, OPT_VERBOSE, &cbd->flags,
344 	    'm', MDB_OPT_UINTPTR, &cbd->smi, NULL) != argc) {
345 		return (DCMD_USAGE);
346 	}
347 
348 	if (!(flags & DCMD_ADDRSPEC)) {
349 		if (mdb_walk("smbnode", smbnode_cb, cbd)
350 		    == -1) {
351 			mdb_warn("cannot walk smbnodes");
352 			return (DCMD_ERR);
353 		}
354 		return (DCMD_OK);
355 	}
356 
357 	np = mdb_alloc(sizeof (*np), UM_SLEEP | UM_GC);
358 	SMBFS_OBJ_FETCH(addr, smbnode_t, np, DCMD_ERR);
359 	smbnode_cb(addr, np, cbd);
360 
361 	return (DCMD_OK);
362 }
363 
364 void
365 smbnode_help(void)
366 {
367 	mdb_printf("Options:\n"
368 	    "  -m mntinfo   only show smbnodes belonging to mntinfo\n"
369 	    "  -v           be verbose when displaying smbnodes\n");
370 }
371 
372 static const mdb_dcmd_t dcmds[] = {
373 	{ "smbfs_vfs", "?[-v]",
374 		"show smbfs-mounted vfs structs",
375 		smbfs_vfs_dcmd, smbfs_vfs_help },
376 	{ "smbnode", "?[-v] [-m mntinfo]",
377 		"show smbnodes", smbnode_dcmd, smbnode_help },
378 	{NULL}
379 };
380 
381 static const mdb_walker_t walkers[] = {
382 	{ "smbnode", "walk smbnode hash table",
383 		smbnode_walk_init, smbnode_walk_step, smbnode_walk_fini },
384 	{NULL}
385 };
386 
387 static const mdb_modinfo_t modinfo = {
388 	MDB_API_VERSION,
389 	dcmds,
390 	walkers
391 };
392 
393 const mdb_modinfo_t *
394 _mdb_init(void)
395 {
396 	return (&modinfo);
397 }
398