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