xref: /illumos-gate/usr/src/cmd/mdb/common/modules/smbsrv/smbsrv.c (revision 2850d85b7b93f31e578520dc3b3feb24db609c62)
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 
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("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 
216 static void
217 smb_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 
243 static void
244 smb_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*/
264 static int
265 smb_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 
450 static void
451 smb_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*/
471 static int
472 smb_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 
578 static int
579 smb_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 
638 static int
639 smb_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 
729 static void
730 smb_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 
746 static int
747 smb_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 
863 static void
864 smb_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 
879 static int
880 smb_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 
980 static int
981 smb_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 
1036 static int
1037 smb_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*/
1109 static int
1110 smb_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  */
1150 static 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 
1175 static 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 
1185 static const mdb_modinfo_t modinfo = {
1186 	MDB_API_VERSION, dcmds, walkers
1187 };
1188 
1189 const mdb_modinfo_t *
1190 _mdb_init(void)
1191 {
1192 	return (&modinfo);
1193 }
1194