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