smbsrv.c revision dc20a3024900c47dd2ee44b9707e6df38f7d62a5
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 * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
23 * Use is subject to license terms.
24 */
25
26#pragma ident	"%Z%%M%	%I%	%E% SMI"
27
28#include <sys/mdb_modapi.h>
29#include <smbsrv/smb_vops.h>
30#include <smbsrv/smb.h>
31#include <smbsrv/mlsvc.h>
32#include <smbsrv/smbvar.h>
33
34#define	SMB_DCMD_INDENT		4
35
36static void smb_lookup_svc_state_str(smb_svcstate_t state, char *dst_str,
37    int slen);
38
39/*
40 * Initialize the smb_session_t walker by reading the value of smb_info
41 * object in the kernel's symbol table. Only global walk supported.
42 */
43static int
44smb_session_walk_init(mdb_walk_state_t *wsp)
45{
46	GElf_Sym	sym;
47	uintptr_t	svcsm_addr;
48
49	if (wsp->walk_addr == NULL) {
50		if (mdb_lookup_by_name("smb_info", &sym) == -1) {
51			mdb_warn("failed to find 'smb_info'");
52			return (WALK_ERR);
53		}
54		svcsm_addr = (uintptr_t)(sym.st_value +
55		    offsetof(struct smb_info, si_svc_sm_ctx));
56		wsp->walk_addr = svcsm_addr +
57		    offsetof(smb_svc_sm_ctx_t, ssc_active_sessions);
58	} else {
59		mdb_printf("smb_session walk only supports global walks\n");
60		return (WALK_ERR);
61	}
62
63	if (mdb_layered_walk("list", wsp) == -1) {
64		mdb_warn("failed to walk 'list'");
65		return (WALK_ERR);
66	}
67
68	return (WALK_NEXT);
69}
70
71static int
72smb_session_walk_step(mdb_walk_state_t *wsp)
73{
74	return (wsp->walk_callback(wsp->walk_addr, wsp->walk_layer,
75	    wsp->walk_cbdata));
76}
77
78/*
79 * Initialize the smb_node_t walker by reading the value of smb_info
80 * object in the kernel's symbol table. Only global walk supported.
81 */
82static int
83smb_node_walk_init(mdb_walk_state_t *wsp)
84{
85	GElf_Sym	sym;
86	int		i;
87	uintptr_t	node_hash_table_addr;
88
89	if (wsp->walk_addr == NULL) {
90		if (mdb_lookup_by_name("smb_info", &sym) == -1) {
91			mdb_warn("failed to find 'smb_info'");
92			return (WALK_ERR);
93		}
94		node_hash_table_addr = (uintptr_t)(sym.st_value +
95		    offsetof(struct smb_info, node_hash_table));
96	} else {
97		mdb_printf("smb_node walk only supports global walks\n");
98		return (WALK_ERR);
99	}
100
101	for (i = 0; i < SMBND_HASH_MASK + 1; i++) {
102		wsp->walk_addr = node_hash_table_addr +
103		    (i * sizeof (smb_llist_t)) +
104		    offsetof(smb_llist_t, ll_list);
105		if (mdb_layered_walk("list", wsp) == -1) {
106			mdb_warn("failed to walk 'list'");
107			return (WALK_ERR);
108		}
109	}
110
111	return (WALK_NEXT);
112}
113
114static int
115smb_node_walk_step(mdb_walk_state_t *wsp)
116{
117	return (wsp->walk_callback(wsp->walk_addr, wsp->walk_layer,
118	    wsp->walk_cbdata));
119}
120
121/*
122 * ::smb_info
123 *
124 * smb_info dcmd - Print out the smb_info structure.
125 */
126/*ARGSUSED*/
127static int
128smb_information(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
129{
130	int print_config = FALSE;
131	struct smb_info	smb_info;
132	GElf_Sym smb_info_sym;
133	char state_name[40];
134	char last_state_name[40];
135
136	if (mdb_getopts(argc, argv,
137	    'c', MDB_OPT_SETBITS, TRUE, &print_config,
138	    NULL) != argc)
139		return (DCMD_USAGE);
140
141	if (flags & DCMD_ADDRSPEC)
142		return (DCMD_USAGE);
143
144	if (mdb_lookup_by_obj(MDB_OBJ_EVERY, "smb_info", &smb_info_sym)) {
145		mdb_warn("failed to find symbol smb_info");
146		return (DCMD_ERR);
147	}
148
149	if (mdb_readvar(&smb_info, "smb_info") == -1) {
150		mdb_warn("failed to read smb_info structure");
151		return (DCMD_ERR);
152	}
153
154	/* Lookup state string */
155	smb_lookup_svc_state_str(smb_info.si_svc_sm_ctx.ssc_state,
156	    state_name, 40);
157	smb_lookup_svc_state_str(smb_info.si_svc_sm_ctx.ssc_last_state,
158	    last_state_name, 40);
159
160	mdb_printf("SMB information:\n\n");
161	mdb_printf("        SMB state :\t%s (%d)\n", state_name,
162	    smb_info.si_svc_sm_ctx.ssc_state);
163	mdb_printf("   SMB last state :\t%s (%d)\n", last_state_name,
164	    smb_info.si_svc_sm_ctx.ssc_last_state);
165	mdb_printf("  Active Sessions :\t%d\n",
166	    smb_info.si_svc_sm_ctx.ssc_active_session_count);
167	mdb_printf("Deferred Sessions :\t%d\n",
168	    smb_info.si_svc_sm_ctx.ssc_deferred_session_count);
169	mdb_printf("   SMB Open Files :\t%d\n", smb_info.open_files);
170	mdb_printf("   SMB Open Trees :\t%d\n", smb_info.open_trees);
171	mdb_printf("   SMB Open Users :\t%d\n\n", smb_info.open_users);
172
173	if (print_config) {
174		mdb_printf("Configuration:\n\n");
175		(void) mdb_inc_indent(SMB_DCMD_INDENT);
176		mdb_printf("Max Buffer Size %d\n",
177		    smb_info.si.skc_maxbufsize);
178		mdb_printf("Max Worker Thread %d\n",
179		    smb_info.si.skc_maxworkers);
180		mdb_printf("Max Connections %d\n",
181		    smb_info.si.skc_maxconnections);
182		mdb_printf("Keep Alive Timeout %d\n",
183		    smb_info.si.skc_keepalive);
184		mdb_printf("%sRestrict Anonymous Access\n",
185		    (smb_info.si.skc_restrict_anon) ? "" : "Do Not ");
186		mdb_printf("Signing %s\n",
187		    (smb_info.si.skc_signing_enable) ? "Enabled" : "Disabled");
188		mdb_printf("Signing %sRequired\n",
189		    (smb_info.si.skc_signing_required) ? "" : "Not ");
190		mdb_printf("Signing Check %s\n",
191		    (smb_info.si.skc_signing_check) ? "Enabled" : "Disabled");
192		mdb_printf("Oplocks %s\n",
193		    (smb_info.si.skc_oplock_enable) ? "Enabled" : "Disabled");
194		mdb_printf("Oplock Timeout %d millisec\n",
195		    smb_info.si.skc_oplock_timeout);
196		mdb_printf("Flush %sRequired\n",
197		    (smb_info.si.skc_flush_required) ? "" : "Not ");
198		mdb_printf("Sync %s\n",
199		    (smb_info.si.skc_sync_enable) ? "Enabled" : "Disabled");
200		mdb_printf("Dir Symlink %s\n",
201		    (smb_info.si.skc_dirsymlink_enable) ?
202		    "Enabled" : "Disabled");
203		mdb_printf("%sAnnounce Quota\n",
204		    (smb_info.si.skc_announce_quota) ? "" : "Do Not ");
205		mdb_printf("Security Mode %d\n", smb_info.si.skc_secmode);
206		mdb_printf("Domain %s\n", smb_info.si.skc_resource_domain);
207		mdb_printf("Hostname %s\n", smb_info.si.skc_hostname);
208		mdb_printf("Comment %s\n", smb_info.si.skc_system_comment);
209		(void) mdb_dec_indent(SMB_DCMD_INDENT);
210		mdb_printf("\n");
211	}
212
213	return (DCMD_OK);
214}
215
216static void
217smb_lookup_svc_state_str(smb_svcstate_t state, char *dst_str, int slen)
218{
219	GElf_Sym	smb_statename_table_sym;
220	uintptr_t	statename_addr_addr, statename_addr;
221
222	if (mdb_lookup_by_name("smb_svcstate_state_name",
223	    &smb_statename_table_sym)) {
224		(void) mdb_snprintf(dst_str, slen, "UNKNOWN");
225		return;
226	}
227
228	/* Lookup state string */
229	statename_addr_addr = smb_statename_table_sym.st_value +
230	    (state * sizeof (uintptr_t));
231	if (mdb_vread(&statename_addr, sizeof (uintptr_t),
232	    statename_addr_addr) == -1) {
233		(void) mdb_snprintf(dst_str, slen, "UNKNOWN");
234		return;
235	} else {
236		if (mdb_readstr(dst_str, slen, statename_addr) == -1) {
237			(void) mdb_snprintf(dst_str, slen, "UNKNOWN");
238			return;
239		}
240	}
241}
242
243static void
244smb_node_help(void)
245{
246	mdb_printf(
247	    "Display the contents of smb_node_t, with optional filtering.\n\n");
248	mdb_dec_indent(2);
249	mdb_printf("%<b>OPTIONS%</b>\n");
250	mdb_inc_indent(2);
251	mdb_printf(
252	    "-v\tDisplay verbose smb_node information\n"
253	    "-p\tDisplay the full path of the vnode associated\n"
254	    "-s\tDisplay the stack of the last 16 calls that modified the "
255	    "reference\n\tcount\n");
256}
257
258/*
259 * ::smb_node
260 *
261 * smb_node dcmd - Print out smb_node structure.
262 */
263/*ARGSUSED*/
264static int
265smb_node(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
266{
267	smb_node_t	node;
268	int		verbose = FALSE;
269	int		print_full_path = FALSE;
270	int		stack_trace = FALSE;
271	vnode_t		vnode;
272	char		od_name[MAXNAMELEN];
273	char		path_name[1024];
274	uintptr_t	list_addr;
275
276	if (mdb_getopts(argc, argv,
277	    'v', MDB_OPT_SETBITS, TRUE, &verbose,
278	    'p', MDB_OPT_SETBITS, TRUE, &print_full_path,
279	    's', MDB_OPT_SETBITS, TRUE, &stack_trace,
280	    NULL) != argc)
281		return (DCMD_USAGE);
282
283	/*
284	 * If no smb_node address was specified on the command line, we can
285	 * print out all smb nodes by invoking the smb_node walker, using
286	 * this dcmd itself as the callback.
287	 */
288	if (!(flags & DCMD_ADDRSPEC)) {
289		if (mdb_walk_dcmd("smb_node", "smb_node",
290		    argc, argv) == -1) {
291			mdb_warn("failed to walk 'smb_node'");
292			return (DCMD_ERR);
293		}
294		return (DCMD_OK);
295	}
296
297	/*
298	 * If this is the first invocation of the command, print a nice
299	 * header line for the output that will follow.
300	 */
301	if (DCMD_HDRSPEC(flags)) {
302		if (verbose)
303			mdb_printf("SMB node information:\n\n");
304		else
305			mdb_printf("%<u>%?s %?s %18s %6s %5s %4s%</u>\n",
306			    "SMB Nodes:", "VP", "NODE NAME",
307			    "OFILES", "LOCKS", "REF");
308	}
309
310	/*
311	 * For each smb_node, we just need to read the smb_node_t struct,
312	 * read and then print out the following fields.
313	 */
314	if (mdb_vread(&node, sizeof (node), addr) == sizeof (node)) {
315		(void) mdb_snprintf(od_name, MAXNAMELEN, "%s", node.od_name);
316		if (print_full_path) {
317			if (mdb_vread(&vnode, sizeof (vnode_t),
318			    (uintptr_t)node.vp) ==
319			    sizeof (vnode_t)) {
320				if (mdb_readstr(path_name, 1024,
321				    (uintptr_t)vnode.v_path) != 0) {
322					(void) mdb_snprintf(od_name,
323					    MAXNAMELEN, "N/A");
324				}
325			}
326		}
327		if (verbose) {
328			mdb_printf("VP              :\t%p\n",
329			    node.vp);
330			mdb_printf("Name            :\t%s\n",
331			    od_name);
332			if (print_full_path) {
333				mdb_printf("V-node Path     :\t%s\n",
334				    path_name);
335			}
336			mdb_printf("Ofiles          :\t%u\n",
337			    node.n_ofile_list.ll_count);
338			mdb_printf("Range Locks     :\t%u\n",
339			    node.n_lock_list.ll_count);
340			if (node.n_lock_list.ll_count != 0) {
341				(void) mdb_inc_indent(SMB_DCMD_INDENT);
342				list_addr = addr +
343				    offsetof(smb_node_t, n_lock_list) +
344				    offsetof(smb_llist_t, ll_list);
345				if (mdb_pwalk_dcmd("list", "smb_lock",
346				    0, NULL, list_addr)) {
347					mdb_warn("failed to walk node's active"
348					    " locks");
349				}
350				(void) mdb_dec_indent(SMB_DCMD_INDENT);
351			}
352			mdb_printf("Reference Count :\t%u\n",
353			    node.n_refcnt);
354			mdb_printf("\n");
355		} else {
356			mdb_printf("%?p %?p %18s %5d %5d %4d\n",
357			    addr, node.vp, od_name, node.n_ofile_list.ll_count,
358			    node.n_lock_list.ll_count, node.n_refcnt);
359			if (print_full_path) {
360				if (mdb_vread(&vnode, sizeof (vnode_t),
361				    (uintptr_t)node.vp) ==
362				    sizeof (vnode_t)) {
363					if (mdb_readstr(path_name, 1024,
364					    (uintptr_t)vnode.v_path)) {
365						mdb_printf("\t%s\n",
366						    path_name);
367					}
368				}
369			}
370		}
371		if (stack_trace && node.n_audit_buf) {
372			int ctr;
373			smb_audit_buf_node_t *anb;
374
375			anb = mdb_alloc(sizeof (smb_audit_buf_node_t),
376			    UM_SLEEP);
377
378			if (mdb_vread(anb, sizeof (*anb),
379			    (uintptr_t)node.n_audit_buf) != sizeof (*anb)) {
380				mdb_free(anb, sizeof (smb_audit_buf_node_t));
381				mdb_warn("failed to read audit buffer");
382				return (DCMD_ERR);
383			}
384			ctr = anb->anb_max_index + 1;
385			anb->anb_index--;
386			anb->anb_index &= anb->anb_max_index;
387
388			while (ctr) {
389				smb_audit_record_node_t	*anr;
390
391				anr = anb->anb_records + anb->anb_index;
392
393				if (anr->anr_depth) {
394					char c[MDB_SYM_NAMLEN];
395					GElf_Sym sym;
396					int i;
397
398					mdb_printf("\nRefCnt: %u\t",
399					    anr->anr_refcnt);
400
401					for (i = 0;
402					    i < anr->anr_depth;
403					    i++) {
404						if (mdb_lookup_by_addr(
405						    anr->anr_stack[i],
406						    MDB_SYM_FUZZY,
407						    c, sizeof (c),
408						    &sym) == -1) {
409							continue;
410						}
411						mdb_printf("%s+0x%1x",
412						    c,
413						    anr->anr_stack[i] -
414						    (uintptr_t)sym.st_value);
415						++i;
416						break;
417					}
418
419					while (i < anr->anr_depth) {
420						if (mdb_lookup_by_addr(
421						    anr->anr_stack[i],
422						    MDB_SYM_FUZZY,
423						    c, sizeof (c),
424						    &sym) == -1) {
425							++i;
426							continue;
427						}
428						mdb_printf("\n\t\t%s+0x%1x",
429						    c,
430						    anr->anr_stack[i] -
431						    (uintptr_t)sym.st_value);
432						++i;
433					}
434					mdb_printf("\n");
435				}
436				anb->anb_index--;
437				anb->anb_index &= anb->anb_max_index;
438				ctr--;
439			}
440			mdb_free(anb, sizeof (smb_audit_buf_node_t));
441		}
442	} else {
443		mdb_warn("failed to read struct smb_node at %p", addr);
444		return (DCMD_ERR);
445	}
446
447	return (DCMD_OK);
448}
449
450static void
451smb_session_help(void)
452{
453	mdb_printf(
454	    "Display the contents of smb_session_t, with optional"
455	    " filtering.\n\n");
456	mdb_dec_indent(2);
457	mdb_printf("%<b>OPTIONS%</b>\n");
458	mdb_inc_indent(2);
459	mdb_printf(
460	    "-v\tDisplay verbose smb_session information\n"
461	    "-r\tDisplay the list of smb requests attached\n"
462	    "-u\tDisplay the list of users attached\n");
463}
464
465/*
466 * ::smb_session
467 *
468 * smb_session dcmd - Print out the smb_session structure.
469 */
470/*ARGSUSED*/
471static int
472smb_session(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
473{
474	smb_session_t	session;
475	int		print_requests = FALSE;
476	int		print_users = FALSE;
477	int		verbose = FALSE;
478	uintptr_t	list_addr;
479
480	if (mdb_getopts(argc, argv,
481	    'v', MDB_OPT_SETBITS, TRUE, &verbose,
482	    'r', MDB_OPT_SETBITS, TRUE, &print_requests,
483	    'u', MDB_OPT_SETBITS, TRUE, &print_users,
484	    NULL) != argc)
485		return (DCMD_USAGE);
486
487	/*
488	 * If no smb_session address was specified on the command line, we can
489	 * print out all smb sessions by invoking the smb_session walker, using
490	 * this dcmd itself as the callback.
491	 */
492	if (!(flags & DCMD_ADDRSPEC)) {
493		if (mdb_walk_dcmd("smb_session", "smb_session",
494		    argc, argv) == -1) {
495			mdb_warn("failed to walk 'smb_session'");
496			return (DCMD_ERR);
497		}
498		return (DCMD_OK);
499	}
500
501	/*
502	 * If this is the first invocation of the command, print a nice
503	 * header line for the output that will follow.
504	 */
505	if (DCMD_HDRSPEC(flags)) {
506		if (verbose)
507			mdb_printf("SMB session information:\n\n");
508		else
509			mdb_printf("%<u>%-?s %16s %16s %5s %10s%</u>\n",
510			    "Sessions:", "CLIENT_IP_ADDR", "LOCAL_IP_ADDR",
511			    "KID", "STATE");
512	}
513
514	/*
515	 * For each smb_session, we just need to read the smb_session_t struct,
516	 * read and then print out the following fields.
517	 */
518	if (mdb_vread(&session, sizeof (session), addr) == sizeof (session)) {
519		if (verbose) {
520			mdb_printf("IP address      :\t%I\n",
521			    session.ipaddr);
522			mdb_printf("Local IP Address:\t%I\n",
523			    session.local_ipaddr);
524			mdb_printf("Session KID     :\t%u\n",
525			    session.s_kid);
526			mdb_printf("Workstation Name:\t%s\n",
527			    session.workstation);
528			mdb_printf("Session state   :\t%u\n",
529			    session.s_state);
530			mdb_printf("users           :\t%u\n",
531			    session.s_user_list.ll_count);
532			mdb_printf("trees           :\t%u\n",
533			    session.s_tree_cnt);
534			mdb_printf("files           :\t%u\n",
535			    session.s_file_cnt);
536			mdb_printf("shares          :\t%u\n",
537			    session.s_dir_cnt);
538			mdb_printf("xa count        :\t%u\n\n",
539			    session.s_xa_list.ll_count);
540			mdb_printf("\n");
541		} else {
542			mdb_printf("%?p %16I %16I %5u %10u\n", addr,
543			    session.ipaddr, session.local_ipaddr,
544			    session.s_kid, session.s_state);
545		}
546	} else {
547		mdb_warn("failed to read struct smb_session at %p", &session);
548		return (DCMD_ERR);
549	}
550
551	if (print_requests) {
552		(void) mdb_inc_indent(SMB_DCMD_INDENT);
553		list_addr = addr + offsetof(smb_session_t, s_req_list) +
554		    offsetof(smb_slist_t, sl_list);
555		if (mdb_pwalk_dcmd("list", "smb_request", 0, NULL, list_addr)) {
556			mdb_warn("failed to walk request list\n");
557			(void) mdb_dec_indent(SMB_DCMD_INDENT);
558			return (DCMD_ERR);
559		}
560		(void) mdb_dec_indent(SMB_DCMD_INDENT);
561	}
562
563	if (print_users) {
564		(void) mdb_inc_indent(SMB_DCMD_INDENT);
565		list_addr = addr + offsetof(smb_session_t, s_user_list) +
566		    offsetof(smb_llist_t, ll_list);
567		if (mdb_pwalk_dcmd("list", "smb_user", 0, NULL, list_addr)) {
568			mdb_warn("failed to walk user list\n");
569			(void) mdb_dec_indent(SMB_DCMD_INDENT);
570			return (DCMD_ERR);
571		}
572		(void) mdb_dec_indent(SMB_DCMD_INDENT);
573	}
574
575	return (DCMD_OK);
576}
577
578static int
579smb_request(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
580{
581	smb_request_t	request;
582	int		verbose = FALSE;
583
584	if (mdb_getopts(argc, argv,
585	    'v', MDB_OPT_SETBITS, TRUE, &verbose,
586	    NULL) != argc)
587		return (DCMD_USAGE);
588
589	/*
590	 * An smb_requets_t address must be specified.
591	 */
592	if (!(flags & DCMD_ADDRSPEC))
593		return (DCMD_USAGE);
594
595	/*
596	 * If this is the first invocation of the command, print a nice
597	 * header line for the output that will follow.
598	 */
599	if (DCMD_HDRSPEC(flags)) {
600		if (verbose)
601			mdb_printf("SMB request information:\n\n");
602		else
603			mdb_printf("%<u>%-?s %4s %6s %4s %4s %4s %4s%</u>\n",
604			    "Requests: ", "COM", "STATE",
605			    "TID", "PID", "UID", "MID");
606	}
607
608	if (mdb_vread(&request, sizeof (request), addr) == sizeof (request)) {
609		if (verbose) {
610			mdb_printf("First SMB COM    :\t%I\n",
611			    request.first_smb_com);
612			mdb_printf("State            :\t%I\n",
613			    request.sr_state);
614			mdb_printf("Tree ID          :\t%u\n",
615			    request.smb_tid);
616			mdb_printf("Process ID       :\t%u\n",
617			    request.smb_pid);
618			mdb_printf("User ID          :\t%u\n",
619			    request.smb_uid);
620			mdb_printf("Multiplex ID     :\t%u\n",
621			    request.smb_mid);
622			mdb_printf("\n");
623		} else {
624			mdb_printf("%?p %04x %6x %04x %04x %04x"
625			    " %04x\n", addr,
626			    request.first_smb_com, request.sr_state,
627			    request.smb_tid, request.smb_pid,
628			    request.smb_uid, request.smb_mid);
629		}
630	} else {
631		mdb_warn("failed to read struct smb_request at %p", addr);
632		return (DCMD_ERR);
633	}
634
635	return (DCMD_OK);
636}
637
638static int
639smb_lock(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
640{
641	smb_lock_t	lock;
642	int		verbose = FALSE;
643	uintptr_t	list_addr;
644	char		*lock_type;
645
646	if (mdb_getopts(argc, argv,
647	    'v', MDB_OPT_SETBITS, TRUE, &verbose,
648	    NULL) != argc)
649		return (DCMD_USAGE);
650
651	/*
652	 * An smb_lock_t address must be specified.
653	 */
654	if (!(flags & DCMD_ADDRSPEC))
655		return (DCMD_USAGE);
656
657	/*
658	 * If this is the first invocation of the command, print a nice
659	 * header line for the output that will follow.
660	 */
661	if (DCMD_HDRSPEC(flags)) {
662		if (verbose)
663			mdb_printf("SMB lock information:\n\n");
664		else
665			mdb_printf("%<u>%-?s %4s %16s %8s %9s%</u>\n",
666			    "Locks: ", "TYPE", "START", "LENGTH",
667			    "CONFLICTS");
668	}
669
670	if (mdb_vread(&lock, sizeof (lock), addr) == sizeof (lock)) {
671		switch (lock.l_type) {
672		case SMB_LOCK_TYPE_READWRITE:
673			lock_type = "RW";
674			break;
675		case SMB_LOCK_TYPE_READONLY:
676			lock_type = "RO";
677			break;
678		default:
679			lock_type = "N/A";
680			break;
681		}
682		if (verbose) {
683			mdb_printf("Type             :\t%s (%u)\n",
684			    lock_type, lock.l_type);
685			mdb_printf("Start            :\t%llx\n",
686			    lock.l_start);
687			mdb_printf("Length           :\t%lx\n",
688			    lock.l_length);
689			mdb_printf("Session          :\t%p\n",
690			    lock.l_session);
691			mdb_printf("File             :\t%p\n",
692			    lock.l_file);
693			mdb_printf("User ID          :\t%u\n",
694			    lock.l_uid);
695			mdb_printf("Process ID       :\t%u\n",
696			    lock.l_pid);
697			mdb_printf("Conflicts        :\t%u\n",
698			    lock.l_conflict_list.sl_count);
699			if (lock.l_conflict_list.sl_count != 0) {
700				(void) mdb_inc_indent(SMB_DCMD_INDENT);
701				list_addr = addr +
702				    offsetof(smb_lock_t, l_conflict_list) +
703				    offsetof(smb_slist_t, sl_list);
704				if (mdb_pwalk_dcmd("list", "smb_lock",
705				    0, NULL, list_addr)) {
706					mdb_warn("failed to walk conflict "
707					    "locks ");
708				}
709				(void) mdb_dec_indent(SMB_DCMD_INDENT);
710			}
711			mdb_printf("Blocked by       :\t%p\n",
712			    lock.l_blocked_by);
713			mdb_printf("Flags            :\t0x%x\n",
714			    lock.l_flags);
715			mdb_printf("\n");
716		} else {
717			mdb_printf("%?p %4s %16llx %08lx %9x", addr,
718			    lock_type, lock.l_start, lock.l_length,
719			    lock.l_conflict_list.sl_count);
720		}
721	} else {
722		mdb_warn("failed to read struct smb_request at %p", addr);
723		return (DCMD_ERR);
724	}
725
726	return (DCMD_OK);
727}
728
729static void
730smb_user_help(void)
731{
732	mdb_printf(
733	    "Display the contents of smb_user_t, with optional filtering.\n\n");
734	mdb_dec_indent(2);
735	mdb_printf("%<b>OPTIONS%</b>\n");
736	mdb_inc_indent(2);
737	mdb_printf(
738	    "-v\tDisplay verbose smb_user information\n"
739	    "-q\tDon't Display the contents of the smb_user. This option "
740	    "should be\n\tused in conjunction with -d or -f\n"
741	    "-d\tDisplay the list of smb_odirs attached\n"
742	    "-f\tDisplay the list of smb_ofiles attached\n"
743	    "-t\tDisplay the list of smb_trees attached\n");
744}
745
746static int
747smb_user(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
748{
749	smb_user_t	user;
750	int		print_odir = FALSE;
751	int		print_ofile = FALSE;
752	int		print_tree = FALSE;
753	int		verbose = FALSE;
754	int		quiet = FALSE;
755	uintptr_t	list_addr;
756	int		new_argc;
757	mdb_arg_t	new_argv[3];
758
759	if (mdb_getopts(argc, argv,
760	    'v', MDB_OPT_SETBITS, TRUE, &verbose,
761	    'q', MDB_OPT_SETBITS, TRUE, &quiet,
762	    'd', MDB_OPT_SETBITS, TRUE, &print_odir,
763	    'f', MDB_OPT_SETBITS, TRUE, &print_ofile,
764	    't', MDB_OPT_SETBITS, TRUE, &print_tree,
765	    NULL) != argc)
766		return (DCMD_USAGE);
767
768	/*
769	 * An smb_user address must be specified on the command line.
770	 */
771	if (!(flags & DCMD_ADDRSPEC))
772		return (DCMD_USAGE);
773
774	/*
775	 * If this is the first invocation of the command, print a nice
776	 * header line for the output that will follow.
777	 */
778	if (DCMD_HDRSPEC(flags) && !quiet) {
779		if (verbose)
780			mdb_printf("SMB user information:\n\n");
781		else
782			mdb_printf("%<u>%-?s %4s %6s %8s %16s %8s   %s%</u>\n",
783			    "Users:", "UID", "STATE", "FLAGS", "CRED",
784			    "REFCNT", "ACCOUNT");
785	}
786
787	if (mdb_vread(&user, sizeof (user), addr) !=  sizeof (user)) {
788		mdb_warn("failed to read struct smb_user at %?p", addr);
789		return (DCMD_ERR);
790	}
791
792	if (!quiet) {
793		char domain[SMB_PI_MAX_DOMAIN];
794		char account[SMB_PI_MAX_USERNAME];
795		int valid_domain = 0, valid_account = 0;
796
797		if (mdb_vread(domain, user.u_domain_len,
798		    (uintptr_t)user.u_domain) == user.u_domain_len)
799			valid_domain = 1;
800		if (mdb_vread(account, user.u_name_len,
801		    (uintptr_t)user.u_name) == user.u_name_len)
802			valid_account = 1;
803
804		if (verbose) {
805			mdb_printf("User ID          :\t%04x\n",
806			    user.u_uid);
807			mdb_printf("State            :\t%d\n",
808			    user.u_state);
809			mdb_printf("Flags            :\t%08x\n",
810			    user.u_flags);
811			mdb_printf("Privileges       :\t%08x\n",
812			    user.u_privileges);
813			mdb_printf("Credential       :\t%llx\n",
814			    user.u_cred);
815			mdb_printf("Reference Count  :\t%d\n",
816			    user.u_refcnt);
817			if (valid_domain && valid_account)
818				mdb_printf("User Account     :\t%s\\%s\n",
819				    domain, account);
820			mdb_printf("\n");
821		} else {
822			mdb_printf("%?p %04x %6d %08x %?p %8d   %s\\%s\n",
823			    addr, user.u_uid, user.u_state, user.u_flags,
824			    user.u_cred, user.u_refcnt,
825			    valid_domain ? domain : "UNKNOWN",
826			    valid_account ? account : "UNKNOWN");
827		}
828	}
829
830	new_argc = 0;
831	if (!print_tree) {
832		new_argv[new_argc].a_type = MDB_TYPE_STRING;
833		new_argv[new_argc].a_un.a_str = "-q";
834		new_argc++;
835	}
836	if (print_ofile) {
837		new_argv[new_argc].a_type = MDB_TYPE_STRING;
838		new_argv[new_argc].a_un.a_str = "-f";
839		new_argc++;
840	}
841	if (print_odir) {
842		new_argv[new_argc].a_type = MDB_TYPE_STRING;
843		new_argv[new_argc].a_un.a_str = "-d";
844		new_argc++;
845	}
846
847	if (print_tree || print_ofile || print_odir) {
848		(void) mdb_inc_indent(SMB_DCMD_INDENT);
849		list_addr = addr + offsetof(smb_user_t, u_tree_list) +
850		    offsetof(smb_llist_t, ll_list);
851		if (mdb_pwalk_dcmd("list", "smb_tree", new_argc, new_argv,
852		    list_addr)) {
853			mdb_warn("failed to walk tree list\n");
854			(void) mdb_dec_indent(SMB_DCMD_INDENT);
855			return (DCMD_ERR);
856		}
857		(void) mdb_dec_indent(SMB_DCMD_INDENT);
858	}
859
860	return (DCMD_OK);
861}
862
863static void
864smb_tree_help(void)
865{
866	mdb_printf(
867	    "Display the contents of smb_tree_t, with optional filtering.\n\n");
868	mdb_dec_indent(2);
869	mdb_printf("%<b>OPTIONS%</b>\n");
870	mdb_inc_indent(2);
871	mdb_printf(
872	    "-v\tDisplay verbose smb_tree information\n"
873	    "-q\tDon't Display the contents of the smb_tree. This option "
874	    "should be\n\tused in conjunction with -d or -f\n"
875	    "-d\tDisplay the list of smb_odirs attached\n"
876	    "-f\tDisplay the list of smb_ofiles attached\n");
877}
878
879static int
880smb_tree(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
881{
882	smb_tree_t	tree;
883	int		print_odir = FALSE;
884	int		print_ofile = FALSE;
885	int		verbose = FALSE;
886	int		quiet = FALSE;
887	uintptr_t	list_addr;
888
889	if (mdb_getopts(argc, argv,
890	    'v', MDB_OPT_SETBITS, TRUE, &verbose,
891	    'd', MDB_OPT_SETBITS, TRUE, &print_odir,
892	    'f', MDB_OPT_SETBITS, TRUE, &print_ofile,
893	    'q', MDB_OPT_SETBITS, TRUE, &quiet,
894	    NULL) != argc)
895		return (DCMD_USAGE);
896
897	/*
898	 * If no smb_session address was specified on the command line, we can
899	 * print out all smb sessions by invoking the smb_session walker, using
900	 * this dcmd itself as the callback.
901	 */
902	if (!(flags & DCMD_ADDRSPEC))
903		return (DCMD_USAGE);
904
905	/*
906	 * If this is the first invocation of the command, print a nice
907	 * header line for the output that will follow.
908	 */
909	if (DCMD_HDRSPEC(flags)) {
910		if (verbose)
911			mdb_printf("SMB tree information:\n\n");
912		else
913			mdb_printf("%<u>%-?s %4s %6s %16s %10s%</u>\n",
914			    "Trees:", "TID", "STATE", "SMB NODE",
915			    "SHARE NAME");
916	}
917
918	/*
919	 * Read tree and print some of the fields
920	 */
921	if (mdb_vread(&tree, sizeof (tree), addr) != sizeof (tree)) {
922		mdb_warn("failed to read struct smb_tree at %p", addr);
923		return (DCMD_ERR);
924	}
925	if (!quiet) {
926		if (verbose) {
927			mdb_printf("Tree ID          :\t%04x\n",
928			    tree.t_tid);
929			mdb_printf("State            :\t%d\n",
930			    tree.t_state);
931			mdb_printf("Share name       :\t%s\n",
932			    tree.t_sharename);
933			mdb_printf("Resource         :\t%s\n",
934			    tree.t_resource);
935			mdb_printf("Umask            :\t%04x\n",
936			    tree.t_umask);
937			mdb_printf("Access           :\t%04x\n",
938			    tree.t_access);
939			mdb_printf("Flags            :\t%08x\n",
940			    tree.t_flags);
941			mdb_printf("SMB Node         :\t%llx\n",
942			    tree.t_snode);
943			mdb_printf("Reference Count  :\t%d\n",
944			    tree.t_refcnt);
945			mdb_printf("\n");
946		} else {
947			mdb_printf("%?p %04x %6d %16llx %s\n", addr,
948			    tree.t_tid, tree.t_state, tree.t_snode,
949			    tree.t_sharename);
950		}
951	}
952
953	if (print_odir) {
954		(void) mdb_inc_indent(SMB_DCMD_INDENT);
955		list_addr = addr + offsetof(smb_tree_t, t_odir_list) +
956		    offsetof(smb_llist_t, ll_list);
957		if (mdb_pwalk_dcmd("list", "smb_odir", 0, NULL, list_addr)) {
958			mdb_warn("failed to walk odir list\n");
959			(void) mdb_dec_indent(SMB_DCMD_INDENT);
960			return (DCMD_ERR);
961		}
962		(void) mdb_dec_indent(SMB_DCMD_INDENT);
963	}
964
965	if (print_ofile) {
966		(void) mdb_inc_indent(SMB_DCMD_INDENT);
967		list_addr = addr + offsetof(smb_tree_t, t_ofile_list) +
968		    offsetof(smb_llist_t, ll_list);
969		if (mdb_pwalk_dcmd("list", "smb_ofile", 0, NULL, list_addr)) {
970			mdb_warn("failed to walk ofile list\n");
971			(void) mdb_dec_indent(SMB_DCMD_INDENT);
972			return (DCMD_ERR);
973		}
974		(void) mdb_dec_indent(SMB_DCMD_INDENT);
975	}
976
977	return (DCMD_OK);
978}
979
980static int
981smb_odir(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
982{
983	smb_odir_t	odir;
984	int		verbose = FALSE;
985
986	if (mdb_getopts(argc, argv,
987	    'v', MDB_OPT_SETBITS, TRUE, &verbose,
988	    NULL) != argc)
989		return (DCMD_USAGE);
990
991	/*
992	 * If no smb_session address was specified on the command line, we can
993	 * print out all smb sessions by invoking the smb_session walker, using
994	 * this dcmd itself as the callback.
995	 */
996	if (!(flags & DCMD_ADDRSPEC))
997		return (DCMD_USAGE);
998
999	/*
1000	 * If this is the first invocation of the command, print a nice
1001	 * header line for the output that will follow.
1002	 */
1003	if (DCMD_HDRSPEC(flags)) {
1004		if (verbose)
1005			mdb_printf("SMB odir information:\n\n");
1006		else
1007			mdb_printf("%<u>%-?s %8s %?s %10s%</u>\n",
1008			    "odir:", "STATE", "SMB NODE", "PATTERN");
1009	}
1010
1011	/*
1012	 * For each smb_session, we just need to read the smb_session_t struct,
1013	 * read and then print out the following fields.
1014	 */
1015	if (mdb_vread(&odir, sizeof (odir), addr) == sizeof (odir)) {
1016		if (verbose) {
1017			mdb_printf("State            :\t%d\n",
1018			    odir.d_state);
1019			mdb_printf("Pattern          :\t%s\n",
1020			    odir.d_pattern);
1021			mdb_printf("SMB Node         :\t%s\n",
1022			    odir.d_dir_snode);
1023			mdb_printf("\n");
1024		} else {
1025			mdb_printf("%?p %8d %16llx %s\n", addr,
1026			    odir.d_state, odir.d_dir_snode, odir.d_pattern);
1027		}
1028	} else {
1029		mdb_warn("failed to read struct smb_odir at %p", addr);
1030		return (DCMD_ERR);
1031	}
1032
1033	return (DCMD_OK);
1034}
1035
1036static int
1037smb_ofile(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
1038{
1039	smb_ofile_t ofile;
1040	int verbose = FALSE;
1041
1042	if (mdb_getopts(argc, argv,
1043	    'v', MDB_OPT_SETBITS, TRUE, &verbose,
1044	    NULL) != argc)
1045		return (DCMD_USAGE);
1046
1047	/*
1048	 * If no smb_session address was specified on the command line, we can
1049	 * print out all smb sessions by invoking the smb_session walker, using
1050	 * this dcmd itself as the callback.
1051	 */
1052	if (!(flags & DCMD_ADDRSPEC))
1053		return (DCMD_USAGE);
1054
1055	/*
1056	 * If this is the first invocation of the command, print a nice
1057	 * header line for the output that will follow.
1058	 */
1059	if (DCMD_HDRSPEC(flags)) {
1060		if (verbose)
1061			mdb_printf("SMB ofile information:\n\n");
1062		else
1063			mdb_printf("%<u>%-?s %04s %8s %?s %8s %?s%</u>\n",
1064			    "ofiles:", "FID", "STATE", "SMB NODE", "FLAGS",
1065			    "CRED");
1066	}
1067
1068	/*
1069	 * For each smb_session, we just need to read the smb_session_t struct,
1070	 * read and then print out the following fields.
1071	 */
1072	if (mdb_vread(&ofile, sizeof (ofile), addr) == sizeof (ofile)) {
1073		if (verbose) {
1074			mdb_printf("Ofile ID         :\t%04x\n",
1075			    ofile.f_fid);
1076			mdb_printf("State            :\t%d\n",
1077			    ofile.f_state);
1078			mdb_printf("SMB Node         :\t%llx\n",
1079			    ofile.f_node);
1080			mdb_printf("LLF Offset       :\t%llx (%s)\n",
1081			    ofile.f_llf_pos,
1082			    ((ofile.f_flags & SMB_OFLAGS_LLF_POS_VALID) ?
1083			    "Valid" : "Invalid"));
1084			mdb_printf("FLAGS            :\t%08x\n",
1085			    ofile.f_flags);
1086			mdb_printf("Credential       :\t%llx\n",
1087			    ofile.f_cr);
1088			mdb_printf("\n");
1089		} else {
1090			mdb_printf("%?p %04x %8d %16llx %08x %?\n", addr,
1091			    ofile.f_fid, ofile.f_state, ofile.f_node,
1092			    ofile.f_flags, ofile.f_cr);
1093		}
1094	} else {
1095		mdb_warn("failed to read struct smb_odir at %p", addr);
1096		return (DCMD_ERR);
1097	}
1098
1099	return (DCMD_OK);
1100}
1101
1102
1103/*
1104 * ::smb_dispatch_stats
1105 *
1106 * smb_dispatch_stats dcmd - Prints all dispatched SMB requests statistics.
1107 */
1108/*ARGSUSED*/
1109static int
1110smb_stats(uintptr_t addr, uint_t flags, int argc,
1111    const mdb_arg_t *argv)
1112{
1113	smb_dispatch_table_t	*disp;
1114	GElf_Sym		sym;
1115	int			nstats = 0, i;
1116
1117	if ((flags & DCMD_ADDRSPEC) || argc != 0)
1118		return (DCMD_USAGE);
1119
1120	if (mdb_lookup_by_obj(MDB_OBJ_EVERY, "dispatch", &sym)) {
1121		mdb_warn("failed to find dispatch object");
1122		return (DCMD_ERR);
1123	}
1124
1125	disp = mdb_alloc(sym.st_size, UM_SLEEP | UM_GC);
1126	if (mdb_vread(disp, sym.st_size, sym.st_value) == -1) {
1127		mdb_warn("failed to read from dispatch object");
1128		return (DCMD_ERR);
1129	}
1130
1131	nstats = sym.st_size / sizeof (smb_dispatch_table_t);
1132
1133	mdb_printf("All dispatched SMB requests statistics:\n\n");
1134	for (i = 0; i < nstats; i++) {
1135		if (disp[i].sdt_function)
1136			mdb_printf("    %40s\t: %lld\n",
1137			    disp[i].sdt_dispatch_stats.name,
1138			    disp[i].sdt_dispatch_stats.value.ui64);
1139	}
1140	return (DCMD_OK);
1141}
1142
1143/*
1144 * MDB module linkage information:
1145 *
1146 * We declare a list of structures describing our dcmds, a list of structures
1147 * describing our walkers and a function named _mdb_init to return a pointer
1148 * to our module information.
1149 */
1150static const mdb_dcmd_t dcmds[] = {
1151	{   "smb_info", "[-c]",
1152	    "print smb_info information", smb_information },
1153	{   "smb_node", "?[-vps]",
1154	    "print smb_node_t information", smb_node, smb_node_help },
1155	{   "smb_session", "?[-vru]",
1156	    "print smb_session_t information", smb_session, smb_session_help},
1157	{   "smb_request", ":[-v]",
1158	    "print smb_request_t information", smb_request },
1159	{   "smb_lock", ":[-v]",
1160	    "print smb_lock_t information", smb_lock },
1161	{   "smb_user", ":[-vdftq]",
1162	    "print smb_user_t information", smb_user, smb_user_help },
1163	{   "smb_tree", ":[-vdfq]",
1164	    "print smb_tree_t information", smb_tree, smb_tree_help },
1165	{   "smb_odir", ":[-v]",
1166	    "print smb_odir_t information", smb_odir },
1167	{   "smb_ofile", "[-v]",
1168	    "print smb_odir_t information", smb_ofile },
1169	{   "smb_stats", NULL,
1170	    "print all smb dispatched requests statistics",
1171	    smb_stats },
1172	{ NULL }
1173};
1174
1175static const mdb_walker_t walkers[] = {
1176	{  "smb_session", "walk list of smb_session_t structures",
1177	    smb_session_walk_init, smb_session_walk_step,
1178	    NULL },
1179	{  "smb_node", "walk list of smb_node_t structures",
1180	    smb_node_walk_init, smb_node_walk_step,
1181	    NULL },
1182	{ NULL }
1183};
1184
1185static const mdb_modinfo_t modinfo = {
1186	MDB_API_VERSION, dcmds, walkers
1187};
1188
1189const mdb_modinfo_t *
1190_mdb_init(void)
1191{
1192	return (&modinfo);
1193}
1194