smbsrv.c revision cb174861876aea6950a7ab4ce944aff84b1914cd
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 (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
23 */
24
25#include <mdb/mdb_modapi.h>
26#include <mdb/mdb_ks.h>
27#include <sys/thread.h>
28#include <sys/taskq_impl.h>
29#include <smbsrv/smb_vops.h>
30#include <smbsrv/smb.h>
31#include <smbsrv/smb_ktypes.h>
32
33#define	SMB_DCMD_INDENT		2
34#define	ACE_TYPE_TABLEN		(ACE_ALL_TYPES + 1)
35#define	ACE_TYPE_ENTRY(_v_)	{_v_, #_v_}
36#define	SMB_COM_ENTRY(_v_, _x_)	{#_v_, _x_}
37
38#define	SMB_MDB_MAX_OPTS	9
39
40#define	SMB_OPT_SERVER		0x00000001
41#define	SMB_OPT_SESSION		0x00000002
42#define	SMB_OPT_REQUEST		0x00000004
43#define	SMB_OPT_USER		0x00000008
44#define	SMB_OPT_TREE		0x00000010
45#define	SMB_OPT_OFILE		0x00000020
46#define	SMB_OPT_ODIR		0x00000040
47#define	SMB_OPT_WALK		0x00000100
48#define	SMB_OPT_VERBOSE		0x00000200
49#define	SMB_OPT_ALL_OBJ		0x000000FF
50
51/*
52 * Structure associating an ACE type to a string.
53 */
54typedef struct {
55	uint8_t		ace_type_value;
56	const char	*ace_type_sting;
57} ace_type_entry_t;
58
59/*
60 * Structure containing strings describing an SMB command.
61 */
62typedef struct {
63	const char	*smb_com;
64	const char	*smb_andx;
65} smb_com_entry_t;
66
67/*
68 * Structure describing an object to be expanded (displayed).
69 */
70typedef struct {
71	uint_t		ex_mask;
72	size_t		ex_offset;
73	const char	*ex_dcmd;
74	const char	*ex_name;
75} smb_exp_t;
76
77/*
78 * List of supported options. Ther order has the match the bits SMB_OPT_xxx.
79 */
80typedef struct smb_mdb_opts {
81	char		*o_name;
82	uint32_t	o_value;
83} smb_mdb_opts_t;
84
85static smb_mdb_opts_t smb_opts[SMB_MDB_MAX_OPTS] =
86{
87	{ "-s", SMB_OPT_SERVER	},
88	{ "-e", SMB_OPT_SESSION	},
89	{ "-r", SMB_OPT_REQUEST	},
90	{ "-u", SMB_OPT_USER	},
91	{ "-t", SMB_OPT_TREE	},
92	{ "-f", SMB_OPT_OFILE	},
93	{ "-d", SMB_OPT_ODIR	},
94	{ "-w", SMB_OPT_WALK	},
95	{ "-v", SMB_OPT_VERBOSE	}
96};
97
98static smb_com_entry_t	smb_com[256] =
99{
100	SMB_COM_ENTRY(SMB_COM_CREATE_DIRECTORY, "No"),
101	SMB_COM_ENTRY(SMB_COM_DELETE_DIRECTORY, "No"),
102	SMB_COM_ENTRY(SMB_COM_OPEN, "No"),
103	SMB_COM_ENTRY(SMB_COM_CREATE, "No"),
104	SMB_COM_ENTRY(SMB_COM_CLOSE, "No"),
105	SMB_COM_ENTRY(SMB_COM_FLUSH, "No"),
106	SMB_COM_ENTRY(SMB_COM_DELETE, "No"),
107	SMB_COM_ENTRY(SMB_COM_RENAME, "No"),
108	SMB_COM_ENTRY(SMB_COM_QUERY_INFORMATION, "No"),
109	SMB_COM_ENTRY(SMB_COM_SET_INFORMATION, "No"),
110	SMB_COM_ENTRY(SMB_COM_READ, "No"),
111	SMB_COM_ENTRY(SMB_COM_WRITE, "No"),
112	SMB_COM_ENTRY(SMB_COM_LOCK_BYTE_RANGE, "No"),
113	SMB_COM_ENTRY(SMB_COM_UNLOCK_BYTE_RANGE, "No"),
114	SMB_COM_ENTRY(SMB_COM_CREATE_TEMPORARY, "No"),
115	SMB_COM_ENTRY(SMB_COM_CREATE_NEW, "No"),
116	SMB_COM_ENTRY(SMB_COM_CHECK_DIRECTORY, "No"),
117	SMB_COM_ENTRY(SMB_COM_PROCESS_EXIT, "No"),
118	SMB_COM_ENTRY(SMB_COM_SEEK, "No"),
119	SMB_COM_ENTRY(SMB_COM_LOCK_AND_READ, "No"),
120	SMB_COM_ENTRY(SMB_COM_WRITE_AND_UNLOCK, "No"),
121	SMB_COM_ENTRY(0x15, "?"),
122	SMB_COM_ENTRY(0x16, "?"),
123	SMB_COM_ENTRY(0x17, "?"),
124	SMB_COM_ENTRY(0x18, "?"),
125	SMB_COM_ENTRY(0x19, "?"),
126	SMB_COM_ENTRY(SMB_COM_READ_RAW, "No"),
127	SMB_COM_ENTRY(SMB_COM_READ_MPX, "No"),
128	SMB_COM_ENTRY(SMB_COM_READ_MPX_SECONDARY, "No"),
129	SMB_COM_ENTRY(SMB_COM_WRITE_RAW, "No"),
130	SMB_COM_ENTRY(SMB_COM_WRITE_MPX, "No"),
131	SMB_COM_ENTRY(SMB_COM_WRITE_MPX_SECONDARY, "No"),
132	SMB_COM_ENTRY(SMB_COM_WRITE_COMPLETE, "No"),
133	SMB_COM_ENTRY(SMB_COM_QUERY_SERVER, "No"),
134	SMB_COM_ENTRY(SMB_COM_SET_INFORMATION2, "No"),
135	SMB_COM_ENTRY(SMB_COM_QUERY_INFORMATION2, "No"),
136	SMB_COM_ENTRY(SMB_COM_LOCKING_ANDX, "No"),
137	SMB_COM_ENTRY(SMB_COM_TRANSACTION, "No"),
138	SMB_COM_ENTRY(SMB_COM_TRANSACTION_SECONDARY, "No"),
139	SMB_COM_ENTRY(SMB_COM_IOCTL, "No"),
140	SMB_COM_ENTRY(SMB_COM_IOCTL_SECONDARY, "No"),
141	SMB_COM_ENTRY(SMB_COM_COPY, "No"),
142	SMB_COM_ENTRY(SMB_COM_MOVE, "No"),
143	SMB_COM_ENTRY(SMB_COM_ECHO, "No"),
144	SMB_COM_ENTRY(SMB_COM_WRITE_AND_CLOSE, "No"),
145	SMB_COM_ENTRY(SMB_COM_OPEN_ANDX, "No"),
146	SMB_COM_ENTRY(SMB_COM_READ_ANDX, "No"),
147	SMB_COM_ENTRY(SMB_COM_WRITE_ANDX, "No"),
148	SMB_COM_ENTRY(SMB_COM_NEW_FILE_SIZE, "No"),
149	SMB_COM_ENTRY(SMB_COM_CLOSE_AND_TREE_DISC, "No"),
150	SMB_COM_ENTRY(SMB_COM_TRANSACTION2, "No"),
151	SMB_COM_ENTRY(SMB_COM_TRANSACTION2_SECONDARY, "No"),
152	SMB_COM_ENTRY(SMB_COM_FIND_CLOSE2, "No"),
153	SMB_COM_ENTRY(SMB_COM_FIND_NOTIFY_CLOSE, "No"),
154	SMB_COM_ENTRY(0x36, "?"),
155	SMB_COM_ENTRY(0x37, "?"),
156	SMB_COM_ENTRY(0x38, "?"),
157	SMB_COM_ENTRY(0x39, "?"),
158	SMB_COM_ENTRY(0x3A, "?"),
159	SMB_COM_ENTRY(0x3B, "?"),
160	SMB_COM_ENTRY(0x3C, "?"),
161	SMB_COM_ENTRY(0x3D, "?"),
162	SMB_COM_ENTRY(0x3E, "?"),
163	SMB_COM_ENTRY(0x3F, "?"),
164	SMB_COM_ENTRY(0x40, "?"),
165	SMB_COM_ENTRY(0x41, "?"),
166	SMB_COM_ENTRY(0x42, "?"),
167	SMB_COM_ENTRY(0x43, "?"),
168	SMB_COM_ENTRY(0x44, "?"),
169	SMB_COM_ENTRY(0x45, "?"),
170	SMB_COM_ENTRY(0x46, "?"),
171	SMB_COM_ENTRY(0x47, "?"),
172	SMB_COM_ENTRY(0x48, "?"),
173	SMB_COM_ENTRY(0x49, "?"),
174	SMB_COM_ENTRY(0x4A, "?"),
175	SMB_COM_ENTRY(0x4B, "?"),
176	SMB_COM_ENTRY(0x4C, "?"),
177	SMB_COM_ENTRY(0x4D, "?"),
178	SMB_COM_ENTRY(0x4E, "?"),
179	SMB_COM_ENTRY(0x4F, "?"),
180	SMB_COM_ENTRY(0x50, "?"),
181	SMB_COM_ENTRY(0x51, "?"),
182	SMB_COM_ENTRY(0x52, "?"),
183	SMB_COM_ENTRY(0x53, "?"),
184	SMB_COM_ENTRY(0x54, "?"),
185	SMB_COM_ENTRY(0x55, "?"),
186	SMB_COM_ENTRY(0x56, "?"),
187	SMB_COM_ENTRY(0x57, "?"),
188	SMB_COM_ENTRY(0x58, "?"),
189	SMB_COM_ENTRY(0x59, "?"),
190	SMB_COM_ENTRY(0x5A, "?"),
191	SMB_COM_ENTRY(0x5B, "?"),
192	SMB_COM_ENTRY(0x5C, "?"),
193	SMB_COM_ENTRY(0x5D, "?"),
194	SMB_COM_ENTRY(0x5E, "?"),
195	SMB_COM_ENTRY(0x5F, "?"),
196	SMB_COM_ENTRY(0x60, "?"),
197	SMB_COM_ENTRY(0x61, "?"),
198	SMB_COM_ENTRY(0x62, "?"),
199	SMB_COM_ENTRY(0x63, "?"),
200	SMB_COM_ENTRY(0x64, "?"),
201	SMB_COM_ENTRY(0x65, "?"),
202	SMB_COM_ENTRY(0x66, "?"),
203	SMB_COM_ENTRY(0x67, "?"),
204	SMB_COM_ENTRY(0x68, "?"),
205	SMB_COM_ENTRY(0x69, "?"),
206	SMB_COM_ENTRY(0x6A, "?"),
207	SMB_COM_ENTRY(0x6B, "?"),
208	SMB_COM_ENTRY(0x6C, "?"),
209	SMB_COM_ENTRY(0x6D, "?"),
210	SMB_COM_ENTRY(0x6E, "?"),
211	SMB_COM_ENTRY(0x6F, "?"),
212	SMB_COM_ENTRY(SMB_COM_TREE_CONNECT, "No"),
213	SMB_COM_ENTRY(SMB_COM_TREE_DISCONNECT, "No"),
214	SMB_COM_ENTRY(SMB_COM_NEGOTIATE, "No"),
215	SMB_COM_ENTRY(SMB_COM_SESSION_SETUP_ANDX, "No"),
216	SMB_COM_ENTRY(SMB_COM_LOGOFF_ANDX, "No"),
217	SMB_COM_ENTRY(SMB_COM_TREE_CONNECT_ANDX, "No"),
218	SMB_COM_ENTRY(0x76, "?"),
219	SMB_COM_ENTRY(0x77, "?"),
220	SMB_COM_ENTRY(0x78, "?"),
221	SMB_COM_ENTRY(0x79, "?"),
222	SMB_COM_ENTRY(0x7A, "?"),
223	SMB_COM_ENTRY(0x7B, "?"),
224	SMB_COM_ENTRY(0x7C, "?"),
225	SMB_COM_ENTRY(0x7D, "?"),
226	SMB_COM_ENTRY(0x7E, "?"),
227	SMB_COM_ENTRY(0x7F, "?"),
228	SMB_COM_ENTRY(SMB_COM_QUERY_INFORMATION_DISK, "No"),
229	SMB_COM_ENTRY(SMB_COM_SEARCH, "No"),
230	SMB_COM_ENTRY(SMB_COM_FIND, "No"),
231	SMB_COM_ENTRY(SMB_COM_FIND_UNIQUE, "No"),
232	SMB_COM_ENTRY(SMB_COM_FIND_CLOSE, "No"),
233	SMB_COM_ENTRY(0x85, "?"),
234	SMB_COM_ENTRY(0x86, "?"),
235	SMB_COM_ENTRY(0x87, "?"),
236	SMB_COM_ENTRY(0x88, "?"),
237	SMB_COM_ENTRY(0x89, "?"),
238	SMB_COM_ENTRY(0x8A, "?"),
239	SMB_COM_ENTRY(0x8B, "?"),
240	SMB_COM_ENTRY(0x8C, "?"),
241	SMB_COM_ENTRY(0x8D, "?"),
242	SMB_COM_ENTRY(0x8E, "?"),
243	SMB_COM_ENTRY(0x8F, "?"),
244	SMB_COM_ENTRY(0x90, "?"),
245	SMB_COM_ENTRY(0x91, "?"),
246	SMB_COM_ENTRY(0x92, "?"),
247	SMB_COM_ENTRY(0x93, "?"),
248	SMB_COM_ENTRY(0x94, "?"),
249	SMB_COM_ENTRY(0x95, "?"),
250	SMB_COM_ENTRY(0x96, "?"),
251	SMB_COM_ENTRY(0x97, "?"),
252	SMB_COM_ENTRY(0x98, "?"),
253	SMB_COM_ENTRY(0x99, "?"),
254	SMB_COM_ENTRY(0x9A, "?"),
255	SMB_COM_ENTRY(0x9B, "?"),
256	SMB_COM_ENTRY(0x9C, "?"),
257	SMB_COM_ENTRY(0x9D, "?"),
258	SMB_COM_ENTRY(0x9E, "?"),
259	SMB_COM_ENTRY(0x9F, "?"),
260	SMB_COM_ENTRY(SMB_COM_NT_TRANSACT, "No"),
261	SMB_COM_ENTRY(SMB_COM_NT_TRANSACT_SECONDARY, "No"),
262	SMB_COM_ENTRY(SMB_COM_NT_CREATE_ANDX, "No"),
263	SMB_COM_ENTRY(0xA3, "?"),
264	SMB_COM_ENTRY(SMB_COM_NT_CANCEL, "No"),
265	SMB_COM_ENTRY(SMB_COM_NT_RENAME, "No"),
266	SMB_COM_ENTRY(0xA6, "?"),
267	SMB_COM_ENTRY(0xA7, "?"),
268	SMB_COM_ENTRY(0xA8, "?"),
269	SMB_COM_ENTRY(0xA9, "?"),
270	SMB_COM_ENTRY(0xAA, "?"),
271	SMB_COM_ENTRY(0xAB, "?"),
272	SMB_COM_ENTRY(0xAC, "?"),
273	SMB_COM_ENTRY(0xAD, "?"),
274	SMB_COM_ENTRY(0xAE, "?"),
275	SMB_COM_ENTRY(0xAF, "?"),
276	SMB_COM_ENTRY(0xB0, "?"),
277	SMB_COM_ENTRY(0xB1, "?"),
278	SMB_COM_ENTRY(0xB2, "?"),
279	SMB_COM_ENTRY(0xB3, "?"),
280	SMB_COM_ENTRY(0xB4, "?"),
281	SMB_COM_ENTRY(0xB5, "?"),
282	SMB_COM_ENTRY(0xB6, "?"),
283	SMB_COM_ENTRY(0xB7, "?"),
284	SMB_COM_ENTRY(0xB8, "?"),
285	SMB_COM_ENTRY(0xB9, "?"),
286	SMB_COM_ENTRY(0xBA, "?"),
287	SMB_COM_ENTRY(0xBB, "?"),
288	SMB_COM_ENTRY(0xBC, "?"),
289	SMB_COM_ENTRY(0xBD, "?"),
290	SMB_COM_ENTRY(0xBE, "?"),
291	SMB_COM_ENTRY(0xBF, "?"),
292	SMB_COM_ENTRY(SMB_COM_OPEN_PRINT_FILE, "No"),
293	SMB_COM_ENTRY(SMB_COM_WRITE_PRINT_FILE, "No"),
294	SMB_COM_ENTRY(SMB_COM_CLOSE_PRINT_FILE, "No"),
295	SMB_COM_ENTRY(SMB_COM_GET_PRINT_QUEUE, "No"),
296	SMB_COM_ENTRY(0xC4, "?"),
297	SMB_COM_ENTRY(0xC5, "?"),
298	SMB_COM_ENTRY(0xC6, "?"),
299	SMB_COM_ENTRY(0xC7, "?"),
300	SMB_COM_ENTRY(0xC8, "?"),
301	SMB_COM_ENTRY(0xC9, "?"),
302	SMB_COM_ENTRY(0xCA, "?"),
303	SMB_COM_ENTRY(0xCB, "?"),
304	SMB_COM_ENTRY(0xCC, "?"),
305	SMB_COM_ENTRY(0xCD, "?"),
306	SMB_COM_ENTRY(0xCE, "?"),
307	SMB_COM_ENTRY(0xCF, "?"),
308	SMB_COM_ENTRY(0xD0, "?"),
309	SMB_COM_ENTRY(0xD1, "?"),
310	SMB_COM_ENTRY(0xD2, "?"),
311	SMB_COM_ENTRY(0xD3, "?"),
312	SMB_COM_ENTRY(0xD4, "?"),
313	SMB_COM_ENTRY(0xD5, "?"),
314	SMB_COM_ENTRY(0xD6, "?"),
315	SMB_COM_ENTRY(0xD7, "?"),
316	SMB_COM_ENTRY(SMB_COM_READ_BULK, "No"),
317	SMB_COM_ENTRY(SMB_COM_WRITE_BULK, "No"),
318	SMB_COM_ENTRY(SMB_COM_WRITE_BULK_DATA, "No"),
319	SMB_COM_ENTRY(0xDB, "?"),
320	SMB_COM_ENTRY(0xDC, "?"),
321	SMB_COM_ENTRY(0xDD, "?"),
322	SMB_COM_ENTRY(0xDE, "?"),
323	SMB_COM_ENTRY(0xDF, "?"),
324	SMB_COM_ENTRY(0xE0, "?"),
325	SMB_COM_ENTRY(0xE1, "?"),
326	SMB_COM_ENTRY(0xE2, "?"),
327	SMB_COM_ENTRY(0xE3, "?"),
328	SMB_COM_ENTRY(0xE4, "?"),
329	SMB_COM_ENTRY(0xE5, "?"),
330	SMB_COM_ENTRY(0xE6, "?"),
331	SMB_COM_ENTRY(0xE7, "?"),
332	SMB_COM_ENTRY(0xE8, "?"),
333	SMB_COM_ENTRY(0xE9, "?"),
334	SMB_COM_ENTRY(0xEA, "?"),
335	SMB_COM_ENTRY(0xEB, "?"),
336	SMB_COM_ENTRY(0xEC, "?"),
337	SMB_COM_ENTRY(0xED, "?"),
338	SMB_COM_ENTRY(0xEE, "?"),
339	SMB_COM_ENTRY(0xEF, "?"),
340	SMB_COM_ENTRY(0xF0, "?"),
341	SMB_COM_ENTRY(0xF1, "?"),
342	SMB_COM_ENTRY(0xF2, "?"),
343	SMB_COM_ENTRY(0xF3, "?"),
344	SMB_COM_ENTRY(0xF4, "?"),
345	SMB_COM_ENTRY(0xF5, "?"),
346	SMB_COM_ENTRY(0xF6, "?"),
347	SMB_COM_ENTRY(0xF7, "?"),
348	SMB_COM_ENTRY(0xF8, "?"),
349	SMB_COM_ENTRY(0xF9, "?"),
350	SMB_COM_ENTRY(0xFA, "?"),
351	SMB_COM_ENTRY(0xFB, "?"),
352	SMB_COM_ENTRY(0xFC, "?"),
353	SMB_COM_ENTRY(0xFD, "?"),
354	SMB_COM_ENTRY(0xFE, "?"),
355	SMB_COM_ENTRY(0xFF, "?")
356};
357
358static int smb_dcmd_list(uintptr_t, uint_t, int, const mdb_arg_t *);
359static void smb_dcmd_list_help(void);
360static int smb_dcmd_server(uintptr_t, uint_t, int, const mdb_arg_t *);
361static void smb_dcmd_session_help(void);
362static int smb_dcmd_session(uintptr_t, uint_t, int, const mdb_arg_t *);
363static int smb_dcmd_request(uintptr_t, uint_t, int, const mdb_arg_t *);
364static void smb_dcmd_user_help(void);
365static int smb_dcmd_user(uintptr_t, uint_t, int, const mdb_arg_t *);
366static void smb_dcmd_tree_help(void);
367static int smb_dcmd_tree(uintptr_t, uint_t, int, const mdb_arg_t *);
368static int smb_dcmd_odir(uintptr_t, uint_t, int, const mdb_arg_t *);
369static int smb_dcmd_ofile(uintptr_t, uint_t, int, const mdb_arg_t *);
370static int smb_vfs(uintptr_t, uint_t, int, const mdb_arg_t *);
371static int smb_vfs_walk_init(mdb_walk_state_t *);
372static int smb_vfs_walk_step(mdb_walk_state_t *);
373static void smb_node_help(void);
374static int smb_node(uintptr_t, uint_t, int, const mdb_arg_t *);
375static int smb_node_walk_init(mdb_walk_state_t *);
376static int smb_node_walk_step(mdb_walk_state_t *);
377static int smb_lock(uintptr_t, uint_t, int, const mdb_arg_t *);
378static int smb_oplock(uintptr_t, uint_t, int, const mdb_arg_t *);
379static int smb_oplock_grant(uintptr_t, uint_t, int, const mdb_arg_t *);
380static int smb_ace(uintptr_t, uint_t, int, const mdb_arg_t *);
381static int smb_ace_walk_init(mdb_walk_state_t *);
382static int smb_ace_walk_step(mdb_walk_state_t *);
383static int smb_acl(uintptr_t, uint_t, int, const mdb_arg_t *);
384static int smb_sd(uintptr_t, uint_t, int, const mdb_arg_t *);
385static int smb_sid(uintptr_t, uint_t, int, const mdb_arg_t *);
386static int smb_sid_print(uintptr_t);
387static int smb_fssd(uintptr_t, uint_t, int, const mdb_arg_t *);
388static int smb_dcmd_getopt(uint_t *, int, const mdb_arg_t *);
389static int smb_dcmd_setopt(uint_t, int, mdb_arg_t *);
390static int smb_obj_expand(uintptr_t, uint_t, const smb_exp_t *, ulong_t);
391static int smb_obj_list(const char *, uint_t, uint_t);
392static int smb_worker_findstack(uintptr_t);
393static int smb_stats(uintptr_t, uint_t, int, const mdb_arg_t *);
394
395/*
396 * MDB module linkage information:
397 *
398 * We declare a list of structures describing our dcmds, a list of structures
399 * describing our walkers and a function named _mdb_init to return a pointer
400 * to our module information.
401 */
402static const mdb_dcmd_t dcmds[] = {
403	{   "smblist",
404	    "[-seutfdwv]",
405	    "print tree of SMB objects",
406	    smb_dcmd_list,
407	    smb_dcmd_list_help },
408	{   "smbsrv",
409	    "[-seutfdwv]",
410	    "print smb_server information",
411	    smb_dcmd_server },
412	{   "smbvfs",
413	    "[-v]",
414	    "print smb_vfs information",
415	    smb_vfs },
416	{   "smbnode",
417	    "?[-vps]",
418	    "print smb_node_t information",
419	    smb_node,
420	    smb_node_help },
421	{   "smbsess",
422	    "[-utfdwv]",
423	    "print smb_session_t information",
424	    smb_dcmd_session,
425	    smb_dcmd_session_help},
426	{   "smbreq",
427	    ":[-v]",
428	    "print smb_request_t information",
429	    smb_dcmd_request },
430	{   "smblock", ":[-v]",
431	    "print smb_lock_t information", smb_lock },
432	{   "smbuser",
433	    ":[-vdftq]",
434	    "print smb_user_t information",
435	    smb_dcmd_user,
436	    smb_dcmd_user_help },
437	{   "smbtree",
438	    ":[-vdf]",
439	    "print smb_tree_t information",
440	    smb_dcmd_tree,
441	    smb_dcmd_tree_help },
442	{   "smbodir",
443	    ":[-v]",
444	    "print smb_odir_t information",
445	    smb_dcmd_odir },
446	{   "smbofile",
447	    "[-v]",
448	    "print smb_file_t information",
449	    smb_dcmd_ofile },
450	{   "smboplock", NULL,
451	    "print smb_oplock_t information", smb_oplock },
452	{   "smboplockgrant", NULL,
453	    "print smb_oplock_grant_t information", smb_oplock_grant },
454	{   "smbstat", NULL,
455	    "print all smb dispatched requests statistics",
456	    smb_stats },
457	{   "smbace", "[-v]",
458	    "print smb_ace_t information", smb_ace },
459	{   "smbacl", "[-v]",
460	    "print smb_acl_t information", smb_acl },
461	{   "smbsid", "[-v]",
462	    "print smb_sid_t information", smb_sid },
463	{   "smbsd", "[-v]",
464	    "print smb_sd_t information", smb_sd },
465	{   "smbfssd", "[-v]",
466	    "print smb_fssd_t information", smb_fssd },
467	{ NULL }
468};
469
470static const mdb_walker_t walkers[] = {
471	{   "smbnode_walker",
472	    "walk list of smb_node_t structures",
473	    smb_node_walk_init,
474	    smb_node_walk_step,
475	    NULL,
476	    NULL },
477	{   "smbvfs_walker",
478	    "walk list of smb_vfs_t structures",
479	    smb_vfs_walk_init,
480	    smb_vfs_walk_step,
481	    NULL,
482	    NULL },
483	{   "smbace_walker",
484	    "walk list of smb_ace_t structures",
485	    smb_ace_walk_init,
486	    smb_ace_walk_step,
487	    NULL,
488	    NULL },
489	{ NULL }
490};
491
492static const mdb_modinfo_t modinfo = {
493	MDB_API_VERSION, dcmds, walkers
494};
495
496const mdb_modinfo_t *
497_mdb_init(void)
498{
499	return (&modinfo);
500}
501
502/*
503 * *****************************************************************************
504 * ****************************** Top level DCMD *******************************
505 * *****************************************************************************
506 */
507
508static void
509smb_dcmd_list_help(void)
510{
511	mdb_printf(
512	    "Displays the list of objects using an indented tree format.\n"
513	    "If no option is specified the entire tree is displayed\n\n");
514	(void) mdb_dec_indent(2);
515	mdb_printf("%<b>OPTIONS%</b>\n");
516	(void) mdb_inc_indent(2);
517	mdb_printf(
518	    "-v\tDisplay verbose information\n"
519	    "-s\tDisplay the list of servers\n"
520	    "-e\tDisplay the list of sessions\n"
521	    "-r\tDisplay the list of smb requests\n"
522	    "-u\tDisplay the list of users\n"
523	    "-t\tDisplay the list of trees\n"
524	    "-f\tDisplay the list of open files\n"
525	    "-d\tDisplay the list of open searches\n");
526}
527
528/*
529 * ::smblist
530 *
531 * This function lists the objects specified on the command line. If no object
532 * is specified the entire tree (server through ofile and odir) is displayed.
533 *
534 */
535/*ARGSUSED*/
536static int
537smb_dcmd_list(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
538{
539	GElf_Sym	sym;
540	uint_t		opts = 0;
541	int		new_argc;
542	mdb_arg_t	new_argv[SMB_MDB_MAX_OPTS];
543
544	if (smb_dcmd_getopt(&opts, argc, argv))
545		return (DCMD_USAGE);
546
547	if (!(opts & ~(SMB_OPT_WALK | SMB_OPT_VERBOSE)))
548		opts |= SMB_OPT_ALL_OBJ;
549
550	opts |= SMB_OPT_WALK;
551
552	new_argc = smb_dcmd_setopt(opts, SMB_MDB_MAX_OPTS, new_argv);
553
554	if (mdb_lookup_by_name("smb_servers", &sym) == -1) {
555		mdb_warn("failed to find symbol smb_servers");
556		return (DCMD_ERR);
557	}
558
559	addr = (uintptr_t)sym.st_value + offsetof(smb_llist_t, ll_list);
560
561	if (mdb_pwalk_dcmd("list", "smbsrv", new_argc, new_argv, addr))
562		return (DCMD_ERR);
563	return (DCMD_OK);
564}
565
566/*
567 * *****************************************************************************
568 * ***************************** smb_server_t **********************************
569 * *****************************************************************************
570 */
571
572static const char *smb_server_state[SMB_SERVER_STATE_SENTINEL] =
573{
574	"CREATED",
575	"CONFIGURED",
576	"RUNNING",
577	"STOPPING",
578	"DELETING"
579};
580
581/*
582 * List of objects that can be expanded under a server structure.
583 */
584static const smb_exp_t smb_server_exp[] =
585{
586	{ SMB_OPT_ALL_OBJ,
587	    offsetof(smb_server_t, sv_nbt_daemon.ld_session_list.se_rdy.lst),
588	    "smbsess", "smb_session"},
589	{ SMB_OPT_ALL_OBJ,
590	    offsetof(smb_server_t, sv_nbt_daemon.ld_session_list.se_act.lst),
591	    "smbsess", "smb_session"},
592	{ SMB_OPT_ALL_OBJ,
593	    offsetof(smb_server_t, sv_tcp_daemon.ld_session_list.se_rdy.lst),
594	    "smbsess", "smb_session"},
595	{ SMB_OPT_ALL_OBJ,
596	    offsetof(smb_server_t, sv_tcp_daemon.ld_session_list.se_act.lst),
597	    "smbsess", "smb_session"},
598	{ 0, 0, NULL, NULL }
599};
600
601/*
602 * ::smbsrv
603 *
604 * smbsrv dcmd - Print out smb_server structures.
605 */
606/*ARGSUSED*/
607static int
608smb_dcmd_server(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
609{
610	uint_t		opts;
611	ulong_t		indent = 0;
612
613	if (smb_dcmd_getopt(&opts, argc, argv))
614		return (DCMD_USAGE);
615
616	if (!(flags & DCMD_ADDRSPEC))
617		return (smb_obj_list("smb_server", opts | SMB_OPT_SERVER,
618		    flags));
619
620	if (((opts & SMB_OPT_WALK) && (opts & SMB_OPT_SERVER)) ||
621	    !(opts & SMB_OPT_WALK)) {
622		smb_server_t	*sv;
623		const char	*state;
624
625		sv = mdb_alloc(sizeof (smb_server_t), UM_SLEEP | UM_GC);
626		if (mdb_vread(sv, sizeof (smb_server_t), addr) == -1) {
627			mdb_warn("failed to read smb_server at %p", addr);
628			return (DCMD_ERR);
629		}
630
631		indent = SMB_DCMD_INDENT;
632
633		if (opts & SMB_OPT_VERBOSE) {
634			mdb_arg_t	argv;
635
636			argv.a_type = MDB_TYPE_STRING;
637			argv.a_un.a_str = "smb_server_t";
638			if (mdb_call_dcmd("print", addr, flags, 1, &argv))
639				return (DCMD_ERR);
640		} else {
641			if (DCMD_HDRSPEC(flags))
642				mdb_printf(
643				    "%<b>%<u>%-?s% "
644				    "%-4s% "
645				    "%-32s% "
646				    "%</u>%</b>\n",
647				    "SERVER", "ZONE", "STATE");
648
649			if (sv->sv_state >= SMB_SERVER_STATE_SENTINEL)
650				state = "UNKNOWN";
651			else
652				state = smb_server_state[sv->sv_state];
653
654			mdb_printf("%-?p %-4d %-32s \n",
655			    addr, sv->sv_zid, state);
656		}
657	}
658	if (smb_obj_expand(addr, opts, smb_server_exp, indent))
659		return (DCMD_ERR);
660	return (DCMD_OK);
661}
662
663/*
664 * *****************************************************************************
665 * ***************************** smb_session_t *********************************
666 * *****************************************************************************
667 */
668
669static const char *smb_session_state[SMB_SESSION_STATE_SENTINEL] =
670{
671	"INITIALIZED",
672	"DISCONNECTED",
673	"CONNECTED",
674	"ESTABLISHED",
675	"NEGOTIATED",
676	"OPLOCK_BREAKING",
677	"WRITE_RAW_ACTIVE",
678	"READ_RAW_ACTIVE",
679	"TERMINATED"
680};
681
682/*
683 * List of objects that can be expanded under a session structure.
684 */
685static const smb_exp_t smb_session_exp[] =
686{
687	{ SMB_OPT_REQUEST,
688	    offsetof(smb_session_t, s_req_list.sl_list),
689	    "smbreq", "smb_request"},
690	{ SMB_OPT_USER | SMB_OPT_TREE | SMB_OPT_OFILE | SMB_OPT_ODIR,
691	    offsetof(smb_session_t, s_user_list.ll_list),
692	    "smbuser", "smb_user"},
693	{ 0, 0, NULL, NULL}
694};
695
696static void
697smb_dcmd_session_help(void)
698{
699	mdb_printf(
700	    "Display the contents of smb_session_t, with optional"
701	    " filtering.\n\n");
702	(void) mdb_dec_indent(2);
703	mdb_printf("%<b>OPTIONS%</b>\n");
704	(void) mdb_inc_indent(2);
705	mdb_printf(
706	    "-v\tDisplay verbose smb_session information\n"
707	    "-r\tDisplay the list of smb requests attached\n"
708	    "-u\tDisplay the list of users attached\n");
709}
710
711/*
712 * ::smbsess
713 *
714 * smbsess dcmd - Print out the smb_session structure.
715 */
716/*ARGSUSED*/
717static int
718smb_dcmd_session(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
719{
720	uint_t		opts;
721	ulong_t		indent = 0;
722
723	if (smb_dcmd_getopt(&opts, argc, argv))
724		return (DCMD_USAGE);
725
726	if (!(flags & DCMD_ADDRSPEC)) {
727		opts |= SMB_OPT_SESSION;
728		opts &= ~SMB_OPT_SERVER;
729		return (smb_obj_list("smb_session", opts, flags));
730	}
731
732	if (((opts & SMB_OPT_WALK) && (opts & SMB_OPT_SESSION)) ||
733	    !(opts & SMB_OPT_WALK)) {
734		smb_session_t	*se;
735		const char	*state;
736
737		indent = SMB_DCMD_INDENT;
738
739		se = mdb_alloc(sizeof (*se), UM_SLEEP | UM_GC);
740		if (mdb_vread(se, sizeof (*se), addr) == -1) {
741			mdb_warn("failed to read smb_session at %p", addr);
742			return (DCMD_ERR);
743		}
744		if (se->s_state >= SMB_SESSION_STATE_SENTINEL)
745			state = "INVALID";
746		else
747			state = smb_session_state[se->s_state];
748
749		if (opts & SMB_OPT_VERBOSE) {
750			mdb_printf("%<b>%<u>SMB session information "
751			    "(%p): %</u>%</b>\n", addr);
752			mdb_printf("Client IP address: %I\n", se->ipaddr);
753			mdb_printf("Local IP Address: %I\n", se->local_ipaddr);
754			mdb_printf("Session KID: %u\n", se->s_kid);
755			mdb_printf("Workstation Name: %s\n",
756			    se->workstation);
757			mdb_printf("Session state: %u (%s)\n", se->s_state,
758			    state);
759			mdb_printf("Number of Users: %u\n",
760			    se->s_user_list.ll_count);
761			mdb_printf("Number of Trees: %u\n", se->s_tree_cnt);
762			mdb_printf("Number of Files: %u\n", se->s_file_cnt);
763			mdb_printf("Number of Shares: %u\n", se->s_dir_cnt);
764			mdb_printf("Number of active Transact.: %u\n\n",
765			    se->s_xa_list.ll_count);
766		} else {
767			if (DCMD_HDRSPEC(flags))
768				mdb_printf(
769				    "%<b>%<u>%-?s "
770				    "%-16s "
771				    "%-16s %-16s%</u>%</b>\n",
772				    "SESSION", "CLIENT_IP_ADDR",
773				    "LOCAL_IP_ADDR", "STATE");
774
775			mdb_printf(
776			    "%-?p %-16I %-16I %s\n", addr, se->ipaddr.a_ipv4,
777			    se->local_ipaddr.a_ipv4, state);
778		}
779	}
780	if (smb_obj_expand(addr, opts, smb_session_exp, indent))
781		return (DCMD_ERR);
782	return (DCMD_OK);
783}
784
785/*
786 * *****************************************************************************
787 * **************************** smb_request_t **********************************
788 * *****************************************************************************
789 */
790
791static const char *smb_request_state[SMB_REQ_STATE_SENTINEL] =
792{
793	"FREE",
794	"INITIALIZING",
795	"SUBMITTED",
796	"ACTIVE",
797	"WAITING_EVENT",
798	"EVENT_OCCURRED",
799	"WAITING_LOCK",
800	"COMPLETED",
801	"CANCELED",
802	"CLEANED_UP"
803};
804
805#define	SMB_REQUEST_BANNER	\
806	"%<b>%<u>%-?s %-?s %-14s %-14s %-16s %-32s%</u>%</b>\n"
807#define	SMB_REQUEST_FORMAT	\
808	"%-?p %-?p %-14lld %-14lld %-16s %s\n"
809
810static int
811smb_dcmd_request(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
812{
813	uint_t		opts;
814
815	if (smb_dcmd_getopt(&opts, argc, argv))
816		return (DCMD_USAGE);
817
818	if (!(flags & DCMD_ADDRSPEC)) {
819		opts |= SMB_OPT_REQUEST;
820		opts &= ~(SMB_OPT_SERVER | SMB_OPT_SESSION | SMB_OPT_USER);
821		return (smb_obj_list("smb_request", opts, flags));
822	}
823
824	if (((opts & SMB_OPT_WALK) && (opts & SMB_OPT_REQUEST)) ||
825	    !(opts & SMB_OPT_WALK)) {
826		smb_request_t	*sr;
827		const char	*state;
828		uint64_t	waiting;
829		uint64_t	running;
830
831		sr = mdb_alloc(sizeof (*sr), UM_SLEEP | UM_GC);
832		if (mdb_vread(sr, sizeof (*sr), addr) == -1) {
833			mdb_warn("failed to read smb_request at %p", addr);
834			return (DCMD_ERR);
835		}
836		if (sr->sr_magic != SMB_REQ_MAGIC) {
837			mdb_warn("not an smb_request_t (%p)>", addr);
838			return (DCMD_ERR);
839		}
840		waiting = 0;
841		running = 0;
842		if (sr->sr_time_submitted != 0) {
843			if (sr->sr_time_active != 0) {
844				waiting = sr->sr_time_active -
845				    sr->sr_time_submitted;
846				running = mdb_gethrtime() -
847				    sr->sr_time_active;
848			} else {
849				waiting = mdb_gethrtime() -
850				    sr->sr_time_submitted;
851			}
852		}
853		waiting /= NANOSEC;
854		running /= NANOSEC;
855
856		if (sr->sr_state >= SMB_REQ_STATE_SENTINEL)
857			state = "INVALID";
858		else
859			state = smb_request_state[sr->sr_state];
860
861		if (opts & SMB_OPT_VERBOSE) {
862			mdb_printf(
863			    "%</b>%</u>SMB request information (%p):"
864			    "%</u>%</b>\n\n", addr);
865
866			mdb_printf(
867			    "first SMB COM: %u (%s)\n"
868			    "current SMB COM: %u (%s)\n"
869			    "state: %u (%s)\n"
870			    "TID(tree): %u (%p)\n"
871			    "UID(user): %u (%p)\n"
872			    "FID(file): %u (%p)\n"
873			    "PID: %u\n"
874			    "MID: %u\n\n"
875			    "waiting time: %lld\n"
876			    "running time: %lld\n",
877			    sr->first_smb_com,
878			    smb_com[sr->first_smb_com].smb_com,
879			    sr->smb_com,
880			    smb_com[sr->smb_com].smb_com,
881			    sr->sr_state, state,
882			    sr->smb_tid, sr->tid_tree,
883			    sr->smb_uid, sr->uid_user,
884			    sr->smb_fid, sr->fid_ofile,
885			    sr->smb_pid,
886			    sr->smb_mid,
887			    waiting,
888			    running);
889
890			smb_worker_findstack((uintptr_t)sr->sr_worker);
891		} else {
892			if (DCMD_HDRSPEC(flags))
893				mdb_printf(
894				    SMB_REQUEST_BANNER,
895				    "ADDR",
896				    "WORKER",
897				    "WAITING(s)",
898				    "RUNNING(s)",
899				    "STATE",
900				    "COMMAND");
901
902			mdb_printf(SMB_REQUEST_FORMAT,
903			    addr,
904			    sr->sr_worker,
905			    waiting,
906			    running,
907			    state,
908			    smb_com[sr->smb_com].smb_com);
909		}
910	}
911	return (DCMD_OK);
912}
913
914/*
915 * *****************************************************************************
916 * ****************************** smb_user_t ***********************************
917 * *****************************************************************************
918 */
919
920static const char *smb_user_state[SMB_USER_STATE_SENTINEL] =
921{
922	"LOGGED_IN",
923	"LOGGING_OFF",
924	"LOGGED_OFF"
925};
926
927/*
928 * List of objects that can be expanded under a user structure.
929 */
930static const smb_exp_t smb_user_exp[] =
931{
932	{ SMB_OPT_TREE | SMB_OPT_OFILE | SMB_OPT_ODIR,
933	    offsetof(smb_user_t, u_tree_list.ll_list),
934	    "smbtree", "smb_tree"},
935	{ 0, 0, NULL, NULL}
936};
937
938static void
939smb_dcmd_user_help(void)
940{
941	mdb_printf(
942	    "Display the contents of smb_user_t, with optional filtering.\n\n");
943	(void) mdb_dec_indent(2);
944	mdb_printf("%<b>OPTIONS%</b>\n");
945	(void) mdb_inc_indent(2);
946	mdb_printf(
947	    "-v\tDisplay verbose smb_user information\n"
948	    "-d\tDisplay the list of smb_odirs attached\n"
949	    "-f\tDisplay the list of smb_ofiles attached\n"
950	    "-t\tDisplay the list of smb_trees attached\n");
951}
952
953static int
954smb_dcmd_user(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
955{
956	uint_t		opts;
957	ulong_t		indent = 0;
958
959	if (smb_dcmd_getopt(&opts, argc, argv))
960		return (DCMD_USAGE);
961
962	if (!(flags & DCMD_ADDRSPEC)) {
963		opts |= SMB_OPT_USER;
964		opts &= ~(SMB_OPT_SERVER | SMB_OPT_SESSION | SMB_OPT_REQUEST);
965		return (smb_obj_list("smb_user", opts, flags));
966	}
967
968	if (((opts & SMB_OPT_WALK) && (opts & SMB_OPT_USER)) ||
969	    !(opts & SMB_OPT_WALK)) {
970		smb_user_t	*user;
971		char		*account;
972
973		indent = SMB_DCMD_INDENT;
974
975		user = mdb_alloc(sizeof (*user), UM_SLEEP | UM_GC);
976		if (mdb_vread(user, sizeof (*user), addr) == -1) {
977			mdb_warn("failed to read smb_user at %p", addr);
978			return (DCMD_ERR);
979		}
980		account = mdb_zalloc(user->u_domain_len + user->u_name_len + 2,
981		    UM_SLEEP | UM_GC);
982
983		if (user->u_domain_len)
984			(void) mdb_vread(account, user->u_domain_len,
985			    (uintptr_t)user->u_domain);
986
987		strcat(account, "\\");
988
989		if (user->u_name_len)
990			(void) mdb_vread(account + strlen(account),
991			    user->u_name_len, (uintptr_t)user->u_name);
992
993		if (opts & SMB_OPT_VERBOSE) {
994			const char	*state;
995
996			if (user->u_state >= SMB_USER_STATE_SENTINEL)
997				state = "INVALID";
998			else
999				state = smb_user_state[user->u_state];
1000
1001			mdb_printf("%<b>%<u>SMB user information (%p):"
1002			    "%</u>%</b>\n", addr);
1003			mdb_printf("UID: %u\n", user->u_uid);
1004			mdb_printf("State: %d (%s)\n", user->u_state, state);
1005			mdb_printf("Flags: 0x%08x\n", user->u_flags);
1006			mdb_printf("Privileges: 0x%08x\n", user->u_privileges);
1007			mdb_printf("Credential: %p\n", user->u_cred);
1008			mdb_printf("Reference Count: %d\n", user->u_refcnt);
1009			mdb_printf("User Account: %s\n\n", account);
1010		} else {
1011			if (DCMD_HDRSPEC(flags))
1012				mdb_printf(
1013				    "%<b>%<u>%?-s "
1014				    "%-5s "
1015				    "%-32s%</u>%</b>\n",
1016				    "USER", "UID", "ACCOUNT");
1017
1018			mdb_printf("%-?p %-5u %-32s\n", addr, user->u_uid,
1019			    account);
1020		}
1021	}
1022	if (smb_obj_expand(addr, opts, smb_user_exp, indent))
1023		return (DCMD_ERR);
1024	return (DCMD_OK);
1025}
1026
1027/*
1028 * *****************************************************************************
1029 * ****************************** smb_tree_t ***********************************
1030 * *****************************************************************************
1031 */
1032
1033static const char *smb_tree_state[SMB_TREE_STATE_SENTINEL] =
1034{
1035	"CONNECTED",
1036	"DISCONNECTING",
1037	"DISCONNECTED"
1038};
1039
1040/*
1041 * List of objects that can be expanded under a tree structure.
1042 */
1043static const smb_exp_t smb_tree_exp[] =
1044{
1045	{ SMB_OPT_OFILE,
1046	    offsetof(smb_tree_t, t_ofile_list.ll_list),
1047	    "smbofile", "smb_ofile"},
1048	{ SMB_OPT_ODIR,
1049	    offsetof(smb_tree_t, t_odir_list.ll_list),
1050	    "smbodir", "smb_odir"},
1051	{ 0, 0, NULL, NULL}
1052};
1053
1054static void
1055smb_dcmd_tree_help(void)
1056{
1057	mdb_printf(
1058	    "Display the contents of smb_tree_t, with optional filtering.\n\n");
1059	(void) mdb_dec_indent(2);
1060	mdb_printf("%<b>OPTIONS%</b>\n");
1061	(void) mdb_inc_indent(2);
1062	mdb_printf(
1063	    "-v\tDisplay verbose smb_tree information\n"
1064	    "-d\tDisplay the list of smb_odirs attached\n"
1065	    "-f\tDisplay the list of smb_ofiles attached\n");
1066}
1067
1068static int
1069smb_dcmd_tree(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
1070{
1071	uint_t		opts;
1072	ulong_t		indent = 0;
1073
1074	if (smb_dcmd_getopt(&opts, argc, argv))
1075		return (DCMD_USAGE);
1076
1077	if (!(flags & DCMD_ADDRSPEC)) {
1078		opts |= SMB_OPT_TREE;
1079		opts &= ~(SMB_OPT_SERVER | SMB_OPT_SESSION | SMB_OPT_REQUEST |
1080		    SMB_OPT_USER);
1081		return (smb_obj_list("smb_tree", opts, flags));
1082	}
1083
1084	if (((opts & SMB_OPT_WALK) && (opts & SMB_OPT_TREE)) ||
1085	    !(opts & SMB_OPT_WALK)) {
1086		smb_tree_t	*tree;
1087
1088		indent = SMB_DCMD_INDENT;
1089
1090		tree = mdb_alloc(sizeof (*tree), UM_SLEEP | UM_GC);
1091		if (mdb_vread(tree, sizeof (*tree), addr) == -1) {
1092			mdb_warn("failed to read smb_tree at %p", addr);
1093			return (DCMD_ERR);
1094		}
1095		if (opts & SMB_OPT_VERBOSE) {
1096			const char	*state;
1097
1098			if (tree->t_state >= SMB_TREE_STATE_SENTINEL)
1099				state = "INVALID";
1100			else
1101				state = smb_tree_state[tree->t_state];
1102
1103			mdb_printf("%<b>%<u>SMB tree information (%p):"
1104			    "%</u>%</b>\n\n", addr);
1105			mdb_printf("TID: %04x\n", tree->t_tid);
1106			mdb_printf("State: %d (%s)\n", tree->t_state, state);
1107			mdb_printf("Share: %s\n", tree->t_sharename);
1108			mdb_printf("Resource: %s\n", tree->t_resource);
1109			mdb_printf("Type: %s\n", tree->t_typename);
1110			mdb_printf("Volume: %s\n", tree->t_volume);
1111			mdb_printf("Umask: %04x\n", tree->t_umask);
1112			mdb_printf("Flags: %08x\n", tree->t_flags);
1113			mdb_printf("SMB Node: %llx\n", tree->t_snode);
1114			mdb_printf("Reference Count: %d\n\n", tree->t_refcnt);
1115		} else {
1116			if (DCMD_HDRSPEC(flags))
1117				mdb_printf(
1118				    "%<b>%<u>%-?s %-5s %-16s %-32s%</u>%</b>\n",
1119				    "TREE", "TID", "SHARE NAME", "RESOURCE");
1120
1121			mdb_printf("%-?p %-5u %-16s %-32s\n", addr,
1122			    tree->t_tid, tree->t_sharename, tree->t_resource);
1123		}
1124	}
1125	if (smb_obj_expand(addr, opts, smb_tree_exp, indent))
1126		return (DCMD_ERR);
1127	return (DCMD_OK);
1128}
1129
1130/*
1131 * *****************************************************************************
1132 * ****************************** smb_odir_t ***********************************
1133 * *****************************************************************************
1134 */
1135
1136static const char *smb_odir_state[SMB_ODIR_STATE_SENTINEL] =
1137{
1138	"OPEN",
1139	"IN_USE",
1140	"CLOSING",
1141	"CLOSED"
1142};
1143
1144static int
1145smb_dcmd_odir(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
1146{
1147	uint_t		opts;
1148
1149	if (smb_dcmd_getopt(&opts, argc, argv))
1150		return (DCMD_USAGE);
1151
1152	if (!(flags & DCMD_ADDRSPEC)) {
1153		opts |= SMB_OPT_ODIR;
1154		opts &= ~(SMB_OPT_SERVER | SMB_OPT_SESSION | SMB_OPT_REQUEST |
1155		    SMB_OPT_USER | SMB_OPT_TREE | SMB_OPT_OFILE);
1156		return (smb_obj_list("smb_odir", opts, flags));
1157	}
1158
1159	if (((opts & SMB_OPT_WALK) && (opts & SMB_OPT_ODIR)) ||
1160	    !(opts & SMB_OPT_WALK)) {
1161		smb_odir_t	*od;
1162
1163		od = mdb_alloc(sizeof (*od), UM_SLEEP | UM_GC);
1164		if (mdb_vread(od, sizeof (*od), addr) == -1) {
1165			mdb_warn("failed to read smb_odir at %p", addr);
1166			return (DCMD_ERR);
1167		}
1168		if (opts & SMB_OPT_VERBOSE) {
1169			const char	*state;
1170
1171			if (od->d_state >= SMB_ODIR_STATE_SENTINEL)
1172				state = "INVALID";
1173			else
1174				state = smb_odir_state[od->d_state];
1175
1176			mdb_printf(
1177			    "%<b>%<u>SMB odir information (%p):%</u>%</b>\n\n",
1178			    addr);
1179			mdb_printf("State: %d (%s)\n", od->d_state, state);
1180			mdb_printf("SID: %u\n", od->d_odid);
1181			mdb_printf("Reference Count: %d\n", od->d_refcnt);
1182			mdb_printf("Pattern: %s\n", od->d_pattern);
1183			mdb_printf("SMB Node: %p\n\n", od->d_dnode);
1184		} else {
1185			if (DCMD_HDRSPEC(flags))
1186				mdb_printf(
1187				    "%<b>%<u>%-?s "
1188				    "%-5s "
1189				    "%-?s "
1190				    "%-16s%</u>%</b>\n",
1191				    "ODIR", "SID", "VNODE", "PATTERN");
1192
1193			mdb_printf("%?p %-5u %-16p %s\n",
1194			    addr, od->d_odid, od->d_dnode, od->d_pattern);
1195		}
1196	}
1197	return (DCMD_OK);
1198}
1199
1200/*
1201 * *****************************************************************************
1202 * ****************************** smb_ofile_t **********************************
1203 * *****************************************************************************
1204 */
1205
1206static const char *smb_ofile_state[SMB_OFILE_STATE_SENTINEL] =
1207{
1208	"OPEN",
1209	"CLOSING",
1210	"CLOSED"
1211};
1212
1213static int
1214smb_dcmd_ofile(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
1215{
1216	uint_t		opts;
1217
1218	if (smb_dcmd_getopt(&opts, argc, argv))
1219		return (DCMD_USAGE);
1220
1221	if (!(flags & DCMD_ADDRSPEC)) {
1222		opts |= SMB_OPT_OFILE;
1223		opts &= ~(SMB_OPT_SERVER | SMB_OPT_SESSION | SMB_OPT_REQUEST |
1224		    SMB_OPT_USER | SMB_OPT_TREE | SMB_OPT_ODIR);
1225		return (smb_obj_list("smb_ofile", opts, flags));
1226	}
1227
1228	if (((opts & SMB_OPT_WALK) && (opts & SMB_OPT_OFILE)) ||
1229	    !(opts & SMB_OPT_WALK)) {
1230		smb_ofile_t	*of;
1231
1232		of = mdb_alloc(sizeof (*of), UM_SLEEP | UM_GC);
1233		if (mdb_vread(of, sizeof (*of), addr) == -1) {
1234			mdb_warn("failed to read smb_ofile at %p", addr);
1235			return (DCMD_ERR);
1236		}
1237		if (opts & SMB_OPT_VERBOSE) {
1238			const char	*state;
1239
1240			if (of->f_state >= SMB_ODIR_STATE_SENTINEL)
1241				state = "INVALID";
1242			else
1243				state = smb_ofile_state[of->f_state];
1244
1245			mdb_printf(
1246			    "%<b>%<u>SMB ofile information (%p):%</u>%</b>\n\n",
1247			    addr);
1248			mdb_printf("FID: %u\n", of->f_fid);
1249			mdb_printf("State: %d (%s)\n", of->f_state, state);
1250			mdb_printf("SMB Node: %p\n", of->f_node);
1251			mdb_printf("LLF Offset: 0x%llx (%s)\n",
1252			    of->f_llf_pos,
1253			    ((of->f_flags & SMB_OFLAGS_LLF_POS_VALID) ?
1254			    "Valid" : "Invalid"));
1255			mdb_printf("Flags: 0x%08x\n", of->f_flags);
1256			mdb_printf("Credential: %p\n\n", of->f_cr);
1257		} else {
1258			if (DCMD_HDRSPEC(flags))
1259				mdb_printf(
1260				    "%<b>%<u>%-?s "
1261				    "%-5s "
1262				    "%-?s "
1263				    "%-?s%</u>%</b>\n",
1264				    "OFILE", "FID", "SMB NODE", "CRED");
1265
1266			mdb_printf("%?p %-5u %-p %p\n", addr,
1267			    of->f_fid, of->f_node, of->f_cr);
1268		}
1269	}
1270	return (DCMD_OK);
1271}
1272
1273/*
1274 * *****************************************************************************
1275 * ******************************** smb_vfs_t **********************************
1276 * *****************************************************************************
1277 */
1278
1279/*
1280 * ::smbvfs
1281 *
1282 * smbvfs dcmd - Prints out smb_vfs structures.
1283 */
1284/*ARGSUSED*/
1285static int
1286smb_vfs(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
1287{
1288	int		verbose = FALSE;
1289	smb_vfs_t	*sf;
1290	vnode_t		*vn;
1291	char		*path;
1292
1293	if (mdb_getopts(argc, argv,
1294	    'v', MDB_OPT_SETBITS, TRUE, &verbose,
1295	    NULL) != argc)
1296		return (DCMD_USAGE);
1297
1298	/*
1299	 * If no smb_vfs address was specified on the command line, we can
1300	 * print out all smb_vfs by invoking the smb_vfs walker, using
1301	 * this dcmd itself as the callback.
1302	 */
1303	if (!(flags & DCMD_ADDRSPEC)) {
1304		if (mdb_walk_dcmd("smbvfs_walker", "smbvfs",
1305		    argc, argv) == -1) {
1306			mdb_warn("failed to walk 'smb_vfs'");
1307			return (DCMD_ERR);
1308		}
1309		return (DCMD_OK);
1310	}
1311
1312	if (DCMD_HDRSPEC(flags)) {
1313		mdb_printf(
1314		    "%<b>%<u>"
1315		    "%-?s "
1316		    "%-10s "
1317		    "%-16s "
1318		    "%-16s"
1319		    "%-s"
1320		    "%</u>%</b>\n",
1321		    "SMB_VFS", "REFCNT", "VFS", "VNODE", "ROOT");
1322	}
1323
1324	sf = mdb_alloc(sizeof (*sf), UM_SLEEP | UM_GC);
1325	if (mdb_vread(sf, sizeof (*sf), addr) == -1) {
1326		mdb_warn("failed to read smb_vfs at %p", addr);
1327		return (DCMD_ERR);
1328	}
1329
1330	vn = mdb_alloc(sizeof (*vn), UM_SLEEP | UM_GC);
1331	if (mdb_vread(vn, sizeof (*vn),
1332	    (uintptr_t)sf->sv_rootvp) == -1) {
1333		mdb_warn("failed to read vnode at %p", sf->sv_rootvp);
1334		return (DCMD_ERR);
1335	}
1336
1337	path = mdb_zalloc(MAXPATHLEN, UM_SLEEP | UM_GC);
1338	(void) mdb_vread(path, MAXPATHLEN, (uintptr_t)vn->v_path);
1339
1340	mdb_printf(
1341	    "%-?p %-10d %-?p %-?p %-s\n", addr, sf->sv_refcnt,
1342	    sf->sv_vfsp, sf->sv_rootvp, path);
1343
1344	return (DCMD_OK);
1345}
1346
1347/*
1348 * Initialize the smb_vfs_t walker by reading the value of smb_export
1349 * in the kernel's symbol table. Only global walk supported.
1350 */
1351static int
1352smb_vfs_walk_init(mdb_walk_state_t *wsp)
1353{
1354	GElf_Sym	sym;
1355
1356	if (wsp->walk_addr != NULL) {
1357		mdb_printf("smb_vfs walk only supports global walks\n");
1358		return (WALK_ERR);
1359	}
1360
1361	if (mdb_lookup_by_name("smb_export", &sym) == -1) {
1362		mdb_warn("failed to find 'smb_export'");
1363		return (WALK_ERR);
1364	}
1365
1366	wsp->walk_addr = (uintptr_t)sym.st_value +
1367	    offsetof(smb_export_t, e_vfs_list) + offsetof(smb_llist_t, ll_list);
1368
1369	if (mdb_layered_walk("list", wsp) == -1) {
1370		mdb_warn("failed to walk list of VFS");
1371		return (WALK_ERR);
1372	}
1373
1374	return (WALK_NEXT);
1375}
1376
1377static int
1378smb_vfs_walk_step(mdb_walk_state_t *wsp)
1379{
1380	return (wsp->walk_callback(wsp->walk_addr, wsp->walk_layer,
1381	    wsp->walk_cbdata));
1382}
1383
1384/*
1385 * *****************************************************************************
1386 * ******************************* smb_node_t **********************************
1387 * *****************************************************************************
1388 */
1389
1390static void
1391smb_node_help(void)
1392{
1393	mdb_printf(
1394	    "Display the contents of smb_node_t, with optional filtering.\n\n");
1395	(void) mdb_dec_indent(2);
1396	mdb_printf("%<b>OPTIONS%</b>\n");
1397	(void) mdb_inc_indent(2);
1398	mdb_printf(
1399	    "-v\tDisplay verbose smb_node information\n"
1400	    "-p\tDisplay the full path of the vnode associated\n"
1401	    "-s\tDisplay the stack of the last 16 calls that modified the "
1402	    "reference\n\tcount\n");
1403}
1404
1405/*
1406 * ::smbnode
1407 *
1408 * smb_node dcmd - Print out smb_node structure.
1409 */
1410static int
1411smb_node(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
1412{
1413	smb_node_t	node;
1414	int		rc;
1415	int		verbose = FALSE;
1416	int		print_full_path = FALSE;
1417	int		stack_trace = FALSE;
1418	vnode_t		vnode;
1419	char		od_name[MAXNAMELEN];
1420	char		path_name[1024];
1421	uintptr_t	list_addr, oplock_addr;
1422
1423	if (mdb_getopts(argc, argv,
1424	    'v', MDB_OPT_SETBITS, TRUE, &verbose,
1425	    'p', MDB_OPT_SETBITS, TRUE, &print_full_path,
1426	    's', MDB_OPT_SETBITS, TRUE, &stack_trace,
1427	    NULL) != argc)
1428		return (DCMD_USAGE);
1429
1430	/*
1431	 * If no smb_node address was specified on the command line, we can
1432	 * print out all smb nodes by invoking the smb_node walker, using
1433	 * this dcmd itself as the callback.
1434	 */
1435	if (!(flags & DCMD_ADDRSPEC)) {
1436		if (mdb_walk_dcmd("smbnode_walker", "smbnode",
1437		    argc, argv) == -1) {
1438			mdb_warn("failed to walk 'smb_node'");
1439			return (DCMD_ERR);
1440		}
1441		return (DCMD_OK);
1442	}
1443
1444	/*
1445	 * If this is the first invocation of the command, print a nice
1446	 * header line for the output that will follow.
1447	 */
1448	if (DCMD_HDRSPEC(flags)) {
1449		if (verbose) {
1450			mdb_printf("%<b>%<u>SMB node information:%</u>%</b>\n");
1451		} else {
1452			mdb_printf(
1453			    "%<b>%<u>%-?s "
1454			    "%-?s "
1455			    "%-18s "
1456			    "%-6s "
1457			    "%-6s "
1458			    "%-8s "
1459			    "%-6s%</u>%</b>\n",
1460			    "ADDR", "VP", "NODE-NAME", "OFILES", "LOCKS",
1461			    "OPLOCK", "REF");
1462		}
1463	}
1464
1465	/*
1466	 * For each smb_node, we just need to read the smb_node_t struct, read
1467	 * and then print out the following fields.
1468	 */
1469	if (mdb_vread(&node, sizeof (node), addr) == sizeof (node)) {
1470		(void) mdb_snprintf(od_name, sizeof (od_name), "%s",
1471		    node.od_name);
1472		if (print_full_path) {
1473			if (mdb_vread(&vnode, sizeof (vnode_t),
1474			    (uintptr_t)node.vp) == sizeof (vnode_t)) {
1475				if (mdb_readstr(path_name, sizeof (path_name),
1476				    (uintptr_t)vnode.v_path) != 0) {
1477					(void) mdb_snprintf(od_name,
1478					    sizeof (od_name), "N/A");
1479				}
1480			}
1481		}
1482		if (verbose) {
1483			mdb_printf("VP: %p\n", node.vp);
1484			mdb_printf("Name: %s\n", od_name);
1485			if (print_full_path)
1486				mdb_printf("V-node Path: %s\n", path_name);
1487			mdb_printf("Ofiles: %u\n", node.n_ofile_list.ll_count);
1488			mdb_printf("Range Locks: %u\n",
1489			    node.n_lock_list.ll_count);
1490			if (node.n_lock_list.ll_count != 0) {
1491				(void) mdb_inc_indent(SMB_DCMD_INDENT);
1492				list_addr = addr +
1493				    offsetof(smb_node_t, n_lock_list) +
1494				    offsetof(smb_llist_t, ll_list);
1495				if (mdb_pwalk_dcmd("list", "smblock", 0,
1496				    NULL, list_addr)) {
1497					mdb_warn("failed to walk node's active"
1498					    " locks");
1499				}
1500				(void) mdb_dec_indent(SMB_DCMD_INDENT);
1501			}
1502			if (node.n_oplock.ol_count == 0) {
1503				mdb_printf("Opportunistic Locks: 0\n");
1504			} else {
1505				oplock_addr =
1506				    addr + offsetof(smb_node_t, n_oplock);
1507				mdb_printf("Opportunistic Lock: %p\n",
1508				    oplock_addr);
1509				rc = mdb_call_dcmd("smboplock", oplock_addr,
1510				    flags, argc, argv);
1511				if (rc != DCMD_OK)
1512					return (rc);
1513			}
1514			mdb_printf("Reference Count: %u\n\n", node.n_refcnt);
1515		} else {
1516			mdb_printf("%-?p %-?p %-18s %-6d %-6d %-8d %-6d ",
1517			    addr, node.vp, od_name, node.n_ofile_list.ll_count,
1518			    node.n_lock_list.ll_count,
1519			    node.n_oplock.ol_count, node.n_refcnt);
1520
1521			if (print_full_path)
1522				mdb_printf("\t%s\n", path_name);
1523		}
1524		if (stack_trace && node.n_audit_buf) {
1525			int ctr;
1526			smb_audit_buf_node_t *anb;
1527
1528			anb = mdb_alloc(sizeof (smb_audit_buf_node_t),
1529			    UM_SLEEP | UM_GC);
1530
1531			if (mdb_vread(anb, sizeof (*anb),
1532			    (uintptr_t)node.n_audit_buf) != sizeof (*anb)) {
1533				mdb_warn("failed to read audit buffer");
1534				return (DCMD_ERR);
1535			}
1536			ctr = anb->anb_max_index + 1;
1537			anb->anb_index--;
1538			anb->anb_index &= anb->anb_max_index;
1539
1540			while (ctr) {
1541				smb_audit_record_node_t	*anr;
1542
1543				anr = anb->anb_records + anb->anb_index;
1544
1545				if (anr->anr_depth) {
1546					char c[MDB_SYM_NAMLEN];
1547					GElf_Sym sym;
1548					int i;
1549
1550					mdb_printf("\nRefCnt: %u\t",
1551					    anr->anr_refcnt);
1552
1553					for (i = 0;
1554					    i < anr->anr_depth;
1555					    i++) {
1556						if (mdb_lookup_by_addr(
1557						    anr->anr_stack[i],
1558						    MDB_SYM_FUZZY,
1559						    c, sizeof (c),
1560						    &sym) == -1) {
1561							continue;
1562						}
1563						mdb_printf("%s+0x%1x",
1564						    c,
1565						    anr->anr_stack[i] -
1566						    (uintptr_t)sym.st_value);
1567						++i;
1568						break;
1569					}
1570
1571					while (i < anr->anr_depth) {
1572						if (mdb_lookup_by_addr(
1573						    anr->anr_stack[i],
1574						    MDB_SYM_FUZZY,
1575						    c, sizeof (c),
1576						    &sym) == -1) {
1577							++i;
1578							continue;
1579						}
1580						mdb_printf("\n\t\t%s+0x%1x",
1581						    c,
1582						    anr->anr_stack[i] -
1583						    (uintptr_t)sym.st_value);
1584						++i;
1585					}
1586					mdb_printf("\n");
1587				}
1588				anb->anb_index--;
1589				anb->anb_index &= anb->anb_max_index;
1590				ctr--;
1591			}
1592		}
1593	} else {
1594		mdb_warn("failed to read struct smb_node at %p", addr);
1595		return (DCMD_ERR);
1596	}
1597
1598	return (DCMD_OK);
1599}
1600
1601/*
1602 * Initialize the smb_node_t walker by reading the value of smb_node_hash_table
1603 * in the kernel's symbol table. Only global walk supported.
1604 */
1605static int
1606smb_node_walk_init(mdb_walk_state_t *wsp)
1607{
1608	GElf_Sym	sym;
1609	int		i;
1610	uintptr_t	node_hash_table_addr;
1611
1612	if (wsp->walk_addr == NULL) {
1613		if (mdb_lookup_by_name("smb_node_hash_table", &sym) == -1) {
1614			mdb_warn("failed to find 'smb_node_hash_table'");
1615			return (WALK_ERR);
1616		}
1617		node_hash_table_addr = (uintptr_t)sym.st_value;
1618	} else {
1619		mdb_printf("smb_node walk only supports global walks\n");
1620		return (WALK_ERR);
1621	}
1622
1623	for (i = 0; i < SMBND_HASH_MASK + 1; i++) {
1624		wsp->walk_addr = node_hash_table_addr +
1625		    (i * sizeof (smb_llist_t)) + offsetof(smb_llist_t, ll_list);
1626		if (mdb_layered_walk("list", wsp) == -1) {
1627			mdb_warn("failed to walk 'list'");
1628			return (WALK_ERR);
1629		}
1630	}
1631
1632	return (WALK_NEXT);
1633}
1634
1635static int
1636smb_node_walk_step(mdb_walk_state_t *wsp)
1637{
1638	return (wsp->walk_callback(wsp->walk_addr, wsp->walk_layer,
1639	    wsp->walk_cbdata));
1640}
1641
1642/*
1643 * *****************************************************************************
1644 * ****************************** smb_lock_t ***********************************
1645 * *****************************************************************************
1646 */
1647
1648static int
1649smb_lock(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
1650{
1651	smb_lock_t	lock;
1652	int		verbose = FALSE;
1653	uintptr_t	list_addr;
1654	char		*lock_type;
1655
1656	if (mdb_getopts(argc, argv,
1657	    'v', MDB_OPT_SETBITS, TRUE, &verbose,
1658	    NULL) != argc)
1659		return (DCMD_USAGE);
1660
1661	/*
1662	 * An smb_lock_t address must be specified.
1663	 */
1664	if (!(flags & DCMD_ADDRSPEC))
1665		return (DCMD_USAGE);
1666
1667	/*
1668	 * If this is the first invocation of the command, print a nice
1669	 * header line for the output that will follow.
1670	 */
1671	if (DCMD_HDRSPEC(flags)) {
1672		if (verbose)
1673			mdb_printf("SMB lock information:\n\n");
1674		else
1675			mdb_printf("%<u>%-?s %4s %16s %8s %9s%</u>\n",
1676			    "Locks: ", "TYPE", "START", "LENGTH",
1677			    "CONFLICTS");
1678	}
1679
1680	if (mdb_vread(&lock, sizeof (lock), addr) == sizeof (lock)) {
1681		switch (lock.l_type) {
1682		case SMB_LOCK_TYPE_READWRITE:
1683			lock_type = "RW";
1684			break;
1685		case SMB_LOCK_TYPE_READONLY:
1686			lock_type = "RO";
1687			break;
1688		default:
1689			lock_type = "N/A";
1690			break;
1691		}
1692		if (verbose) {
1693			mdb_printf("Type             :\t%s (%u)\n",
1694			    lock_type, lock.l_type);
1695			mdb_printf("Start            :\t%llx\n",
1696			    lock.l_start);
1697			mdb_printf("Length           :\t%lx\n",
1698			    lock.l_length);
1699			mdb_printf("Session          :\t%p\n",
1700			    lock.l_session);
1701			mdb_printf("File             :\t%p\n",
1702			    lock.l_file);
1703			mdb_printf("User ID          :\t%u\n",
1704			    lock.l_uid);
1705			mdb_printf("Process ID       :\t%u\n",
1706			    lock.l_pid);
1707			mdb_printf("Conflicts        :\t%u\n",
1708			    lock.l_conflict_list.sl_count);
1709			if (lock.l_conflict_list.sl_count != 0) {
1710				(void) mdb_inc_indent(SMB_DCMD_INDENT);
1711				list_addr = addr +
1712				    offsetof(smb_lock_t, l_conflict_list) +
1713				    offsetof(smb_slist_t, sl_list);
1714				if (mdb_pwalk_dcmd("list", "smb_lock",
1715				    0, NULL, list_addr)) {
1716					mdb_warn("failed to walk conflict "
1717					    "locks ");
1718				}
1719				(void) mdb_dec_indent(SMB_DCMD_INDENT);
1720			}
1721			mdb_printf("Blocked by       :\t%p\n",
1722			    lock.l_blocked_by);
1723			mdb_printf("Flags            :\t0x%x\n",
1724			    lock.l_flags);
1725			mdb_printf("\n");
1726		} else {
1727			mdb_printf("%?p %4s %16llx %08lx %9x", addr,
1728			    lock_type, lock.l_start, lock.l_length,
1729			    lock.l_conflict_list.sl_count);
1730		}
1731	} else {
1732		mdb_warn("failed to read struct smb_request at %p", addr);
1733		return (DCMD_ERR);
1734	}
1735
1736	return (DCMD_OK);
1737}
1738
1739/*
1740 * *****************************************************************************
1741 * ************************** smb_oplock_grant_t *******************************
1742 * *****************************************************************************
1743 */
1744/*ARGSUSED*/
1745static int
1746smb_oplock_grant(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
1747{
1748	smb_oplock_grant_t	grant;
1749	char			 *level;
1750
1751	if (!(flags & DCMD_ADDRSPEC))
1752		return (DCMD_USAGE);
1753
1754	/*
1755	 * If this is the first invocation of the command, print a nice
1756	 * header line for the output that will follow.
1757	 */
1758	if (DCMD_HDRSPEC(flags)) {
1759		mdb_printf("%<u>%-16s %-10s %-16s%</u>\n",
1760		    "Grants:", "LEVEL", "OFILE");
1761	}
1762
1763	if (mdb_vread(&grant, sizeof (grant), addr) == sizeof (grant)) {
1764		switch (grant.og_level) {
1765		case SMB_OPLOCK_EXCLUSIVE:
1766			level = "EXCLUSIVE";
1767			break;
1768		case SMB_OPLOCK_BATCH:
1769			level = "BATCH";
1770			break;
1771		case SMB_OPLOCK_LEVEL_II:
1772			level = "LEVEL_II";
1773			break;
1774		default:
1775			level = "UNKNOWN";
1776			break;
1777		}
1778
1779		mdb_printf("%-16p %-10s %-16p", addr, level, grant.og_ofile);
1780	}
1781	return (DCMD_OK);
1782}
1783
1784/*
1785 * *****************************************************************************
1786 * ***************************** smb_oplock_t **********************************
1787 * *****************************************************************************
1788 */
1789/*ARGSUSED*/
1790static int
1791smb_oplock(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
1792{
1793	smb_oplock_t	oplock;
1794	uintptr_t	list_addr;
1795
1796	if (!(flags & DCMD_ADDRSPEC))
1797		return (DCMD_USAGE);
1798
1799	if (mdb_vread(&oplock, sizeof (oplock), addr) != sizeof (oplock)) {
1800		mdb_warn("failed to read struct smb_oplock at %p", addr);
1801		return (DCMD_ERR);
1802	}
1803
1804	if (oplock.ol_count == 0)
1805		return (DCMD_OK);
1806
1807	(void) mdb_inc_indent(SMB_DCMD_INDENT);
1808	switch (oplock.ol_break) {
1809	case SMB_OPLOCK_BREAK_TO_NONE:
1810		mdb_printf("Break Pending: BREAK_TO_NONE\n");
1811		break;
1812	case SMB_OPLOCK_BREAK_TO_LEVEL_II:
1813		mdb_printf(
1814		    "Break Pending: BREAK_TO_LEVEL_II\n");
1815		break;
1816	default:
1817		break;
1818	}
1819
1820	list_addr = addr + offsetof(smb_oplock_t, ol_grants);
1821
1822	if (mdb_pwalk_dcmd("list", "smboplockgrant",
1823	    argc, argv, list_addr)) {
1824		mdb_warn("failed to walk oplock grants");
1825	}
1826
1827	(void) mdb_dec_indent(SMB_DCMD_INDENT);
1828
1829	return (DCMD_OK);
1830}
1831
1832/*
1833 * ::smbstat
1834 *
1835 * Prints SMB requests statistics.
1836 */
1837/*ARGSUSED*/
1838static int
1839smb_stats(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
1840{
1841	smb_server_t	*sv;
1842
1843	if (!(flags & DCMD_ADDRSPEC))
1844		return (DCMD_USAGE);
1845
1846	sv = mdb_alloc(sizeof (*sv), UM_SLEEP | UM_GC);
1847	if (mdb_vread(sv, sizeof (*sv), addr) == -1) {
1848		mdb_warn("failed to read server object at %p", addr);
1849		return (DCMD_ERR);
1850	}
1851	if (sv->sv_magic != SMB_SERVER_MAGIC) {
1852		mdb_warn("not an smb_server_t (%p)>", addr);
1853		return (DCMD_ERR);
1854	}
1855	mdb_printf(
1856	    "\n%<b>  nbt   tcp users trees files pipes%</b>\n"
1857	    "%5d %5d %5d %5d %5d %5d\n",
1858	    sv->sv_nbt_sess,
1859	    sv->sv_tcp_sess,
1860	    sv->sv_users,
1861	    sv->sv_trees,
1862	    sv->sv_files,
1863	    sv->sv_pipes);
1864
1865	return (DCMD_OK);
1866}
1867
1868/*
1869 * *****************************************************************************
1870 * ******************************** smb_ace_t **********************************
1871 * *****************************************************************************
1872 */
1873static const ace_type_entry_t	ace_types[ACE_TYPE_TABLEN] =
1874{
1875	ACE_TYPE_ENTRY(ACE_ACCESS_ALLOWED_ACE_TYPE),
1876	ACE_TYPE_ENTRY(ACE_ACCESS_DENIED_ACE_TYPE),
1877	ACE_TYPE_ENTRY(ACE_SYSTEM_AUDIT_ACE_TYPE),
1878	ACE_TYPE_ENTRY(ACE_SYSTEM_ALARM_ACE_TYPE),
1879	ACE_TYPE_ENTRY(ACE_ACCESS_ALLOWED_COMPOUND_ACE_TYPE),
1880	ACE_TYPE_ENTRY(ACE_ACCESS_ALLOWED_OBJECT_ACE_TYPE),
1881	ACE_TYPE_ENTRY(ACE_ACCESS_DENIED_OBJECT_ACE_TYPE),
1882	ACE_TYPE_ENTRY(ACE_SYSTEM_AUDIT_OBJECT_ACE_TYPE),
1883	ACE_TYPE_ENTRY(ACE_SYSTEM_ALARM_OBJECT_ACE_TYPE),
1884	ACE_TYPE_ENTRY(ACE_ACCESS_ALLOWED_CALLBACK_ACE_TYPE),
1885	ACE_TYPE_ENTRY(ACE_ACCESS_DENIED_CALLBACK_ACE_TYPE),
1886	ACE_TYPE_ENTRY(ACE_ACCESS_ALLOWED_CALLBACK_OBJECT_ACE_TYPE),
1887	ACE_TYPE_ENTRY(ACE_ACCESS_DENIED_CALLBACK_OBJECT_ACE_TYPE),
1888	ACE_TYPE_ENTRY(ACE_SYSTEM_AUDIT_CALLBACK_ACE_TYPE),
1889	ACE_TYPE_ENTRY(ACE_SYSTEM_ALARM_CALLBACK_ACE_TYPE),
1890	ACE_TYPE_ENTRY(ACE_SYSTEM_AUDIT_CALLBACK_OBJECT_ACE_TYPE),
1891	ACE_TYPE_ENTRY(ACE_SYSTEM_ALARM_CALLBACK_OBJECT_ACE_TYPE),
1892	ACE_TYPE_ENTRY(0x11),
1893	ACE_TYPE_ENTRY(0x12),
1894	ACE_TYPE_ENTRY(0x13),
1895	ACE_TYPE_ENTRY(0x14),
1896	ACE_TYPE_ENTRY(0x15),
1897	ACE_TYPE_ENTRY(0x16),
1898	ACE_TYPE_ENTRY(0x17),
1899	ACE_TYPE_ENTRY(0x18),
1900	ACE_TYPE_ENTRY(0x19),
1901	ACE_TYPE_ENTRY(0x1A),
1902	ACE_TYPE_ENTRY(0x1B),
1903	ACE_TYPE_ENTRY(0x1C),
1904	ACE_TYPE_ENTRY(0x1D),
1905	ACE_TYPE_ENTRY(0x1E),
1906	ACE_TYPE_ENTRY(0x1F)
1907};
1908
1909static const mdb_bitmask_t ace_flag_bits[] = {
1910	{ "OBJECT_INHERIT_ACE", OBJECT_INHERIT_ACE, OBJECT_INHERIT_ACE },
1911	{ "CONTAINER_INHERIT_ACE", CONTAINER_INHERIT_ACE,
1912	    CONTAINER_INHERIT_ACE },
1913	{ "NO_PROPOGATE_INHERIT_ACE", NO_PROPOGATE_INHERIT_ACE,
1914	    NO_PROPOGATE_INHERIT_ACE },
1915	{ "INHERIT_ONLY_ACE", INHERIT_ONLY_ACE, INHERIT_ONLY_ACE },
1916	{ "INHERITED_ACE", INHERITED_ACE, INHERITED_ACE },
1917	{ "SUCCESSFUL_ACCESS_ACE_FLAG", SUCCESSFUL_ACCESS_ACE_FLAG,
1918	    SUCCESSFUL_ACCESS_ACE_FLAG },
1919	{ "FAILED_ACCESS_ACE_FLAG", FAILED_ACCESS_ACE_FLAG,
1920	    FAILED_ACCESS_ACE_FLAG },
1921	{ NULL, 0, 0 }
1922};
1923
1924/*
1925 * ::smbace
1926 */
1927static int
1928smb_ace(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
1929{
1930	smb_ace_t	ace;
1931	int		verbose = FALSE;
1932	const char	*ptr;
1933	int		rc;
1934
1935	if (mdb_getopts(argc, argv, 'v', MDB_OPT_SETBITS, TRUE, &verbose,
1936	    NULL) != argc)
1937		return (DCMD_USAGE);
1938
1939	/*
1940	 * An smb_ace address is required.
1941	 */
1942	if (!(flags & DCMD_ADDRSPEC))
1943		return (DCMD_USAGE);
1944
1945	if (mdb_vread(&ace, sizeof (ace), addr) != sizeof (ace)) {
1946		mdb_warn("failed to read struct smb_ace at %p", addr);
1947		return (DCMD_ERR);
1948	}
1949
1950	if (verbose) {
1951		if (ace.se_hdr.se_type < ACE_TYPE_TABLEN)
1952			ptr = ace_types[ace.se_hdr.se_type].ace_type_sting;
1953		else
1954			ptr = "Unknown";
1955
1956		mdb_printf("ACE Type: 0x%02x (%s)\n", ace.se_hdr.se_type, ptr);
1957		mdb_printf("ACE Flags: %b\n", (int)ace.se_hdr.se_flags,
1958		    ace_flag_bits);
1959		mdb_printf("ACE Wire Size: 0x%04x\n", ace.se_hdr.se_bsize);
1960		mdb_printf("ACE Mask: 0x%08x\n", ace.se_mask);
1961		mdb_printf("ACE SID: ");
1962	} else {
1963		if (DCMD_HDRSPEC(flags))
1964			mdb_printf(
1965			    "%<b>%<u>%?-s %-4s %-4s %-8s %s%</u>%</b>\n",
1966			    "ACE", "TYPE", "FLAGS", "MASK", "SID");
1967		mdb_printf("%?p 0x%02x 0x%02x 0x%08x ", addr,
1968		    ace.se_hdr.se_type, ace.se_hdr.se_flags, ace.se_mask);
1969	}
1970	rc = smb_sid_print((uintptr_t)ace.se_sid);
1971	mdb_printf("\n");
1972	return (rc);
1973}
1974
1975static int
1976smb_ace_walk_init(mdb_walk_state_t *wsp)
1977{
1978	if (wsp->walk_addr == 0) {
1979		mdb_printf("smb_ace walk only supports local walks\n");
1980		return (WALK_ERR);
1981	}
1982
1983	wsp->walk_addr += offsetof(smb_acl_t, sl_sorted);
1984
1985	if (mdb_layered_walk("list", wsp) == -1) {
1986		mdb_warn("failed to walk list of ACEs");
1987		return (WALK_ERR);
1988	}
1989
1990	return (WALK_NEXT);
1991}
1992
1993static int
1994smb_ace_walk_step(mdb_walk_state_t *wsp)
1995{
1996	return (wsp->walk_callback(wsp->walk_addr, wsp->walk_layer,
1997	    wsp->walk_cbdata));
1998}
1999
2000/*
2001 * *****************************************************************************
2002 * ******************************** smb_acl_t **********************************
2003 * *****************************************************************************
2004 */
2005
2006/*
2007 * ::smbacl
2008 */
2009static int
2010smb_acl(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
2011{
2012	smb_acl_t	acl;
2013
2014	/* An smb_acl address is required. */
2015	if (!(flags & DCMD_ADDRSPEC))
2016		return (DCMD_USAGE);
2017
2018	if (mdb_vread(&acl, sizeof (acl), addr) != sizeof (acl)) {
2019		mdb_warn("failed to read struct smb_acl at %p", addr);
2020		return (DCMD_ERR);
2021	}
2022
2023	mdb_printf("ACL Revision: %d\n", acl.sl_revision);
2024	mdb_printf("ACL Size on Wire: %d\n", acl.sl_bsize);
2025	mdb_printf("ACL Number of ACEs: %d\n", acl.sl_acecnt);
2026
2027	(void) mdb_inc_indent(SMB_DCMD_INDENT);
2028	if (mdb_pwalk_dcmd("smbace_walker", "smbace", argc, argv, addr)) {
2029		(void) mdb_dec_indent(SMB_DCMD_INDENT);
2030		mdb_warn("failed to walk list of ACEs for ACL %p", addr);
2031		return (DCMD_ERR);
2032	}
2033	(void) mdb_dec_indent(SMB_DCMD_INDENT);
2034	return (DCMD_OK);
2035}
2036
2037/*
2038 * *****************************************************************************
2039 * ********************************* smb_sd_t **********************************
2040 * *****************************************************************************
2041 */
2042
2043/*
2044 * ::smbsd
2045 */
2046static int
2047smb_sd(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
2048{
2049	smb_sd_t	sd;
2050	int		rc;
2051
2052	/*
2053	 * An smb_sid address is required.
2054	 */
2055	if (!(flags & DCMD_ADDRSPEC))
2056		return (DCMD_USAGE);
2057
2058	if (mdb_vread(&sd, sizeof (sd), addr) != sizeof (sd)) {
2059		mdb_warn("failed to read struct smb_sd at %p", addr);
2060		return (DCMD_ERR);
2061	}
2062
2063	mdb_printf("SD Revision: %d\n", sd.sd_revision);
2064	mdb_printf("SD Control: %04x\n", sd.sd_control);
2065	if (sd.sd_control & SE_OWNER_DEFAULTED)
2066		mdb_printf("\t    SE_OWNER_DEFAULTED\n");
2067	if (sd.sd_control & SE_GROUP_DEFAULTED)
2068		mdb_printf("\t    SE_GROUP_DEFAULTED\n");
2069	if (sd.sd_control & SE_DACL_PRESENT)
2070		mdb_printf("\t    SE_DACL_PRESENT\n");
2071	if (sd.sd_control & SE_DACL_DEFAULTED)
2072		mdb_printf("\t    SE_DACL_DEFAULTED\n");
2073	if (sd.sd_control & SE_SACL_PRESENT)
2074		mdb_printf("\t    SE_SACL_PRESENT\n");
2075	if (sd.sd_control & SE_SACL_DEFAULTED)
2076		mdb_printf("\t    SE_SACL_DEFAULTED\n");
2077	if (sd.sd_control & SE_DACL_AUTO_INHERIT_REQ)
2078		mdb_printf("\t    SE_DACL_AUTO_INHERIT_REQ\n");
2079	if (sd.sd_control & SE_SACL_AUTO_INHERIT_REQ)
2080		mdb_printf("\t    SE_SACL_AUTO_INHERIT_REQ\n");
2081	if (sd.sd_control & SE_DACL_AUTO_INHERITED)
2082		mdb_printf("\t    SE_DACL_AUTO_INHERITED\n");
2083	if (sd.sd_control & SE_SACL_AUTO_INHERITED)
2084		mdb_printf("\t    SE_SACL_AUTO_INHERITED\n");
2085	if (sd.sd_control & SE_DACL_PROTECTED)
2086		mdb_printf("\t    SE_DACL_PROTECTED\n");
2087	if (sd.sd_control & SE_SACL_PROTECTED)
2088		mdb_printf("\t    SE_SACL_PROTECTED\n");
2089	if (sd.sd_control & SE_SELF_RELATIVE)
2090		mdb_printf("\t    SE_SELF_RELATIVE\n");
2091
2092	mdb_printf("SID of Owner: ");
2093	rc = smb_sid_print((uintptr_t)sd.sd_owner);
2094	if (rc != DCMD_OK)
2095		return (rc);
2096	mdb_printf("\nSID of Group: ");
2097	rc = smb_sid_print((uintptr_t)sd.sd_group);
2098	if (rc != DCMD_OK)
2099		return (rc);
2100	mdb_printf("\n");
2101
2102	if (sd.sd_control & SE_SACL_PRESENT && sd.sd_sacl) {
2103		mdb_printf("%<b>%<u>System ACL%</u>%</b>\n");
2104		(void) mdb_inc_indent(SMB_DCMD_INDENT);
2105		rc = mdb_call_dcmd("smbacl", (uintptr_t)sd.sd_sacl, flags,
2106		    argc, argv);
2107		(void) mdb_dec_indent(SMB_DCMD_INDENT);
2108		if (rc != DCMD_OK)
2109			return (rc);
2110	}
2111	if (sd.sd_control & SE_DACL_PRESENT && sd.sd_dacl) {
2112		mdb_printf("%<b>%<u>Discretionary ACL%</u>%</b>\n");
2113		(void) mdb_inc_indent(SMB_DCMD_INDENT);
2114		rc = mdb_call_dcmd("smbacl", (uintptr_t)sd.sd_dacl, flags,
2115		    argc, argv);
2116		(void) mdb_dec_indent(SMB_DCMD_INDENT);
2117		if (rc != DCMD_OK)
2118			return (rc);
2119	}
2120
2121	return (DCMD_OK);
2122}
2123
2124/*
2125 * *****************************************************************************
2126 * ********************************* smb_sid_t *********************************
2127 * *****************************************************************************
2128 */
2129
2130/*
2131 * ::smbsid
2132 */
2133/*ARGSUSED*/
2134static int
2135smb_sid(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
2136{
2137	/*
2138	 * An smb_sid address is required.
2139	 */
2140	if (!(flags & DCMD_ADDRSPEC))
2141		return (DCMD_USAGE);
2142
2143	return (smb_sid_print(addr));
2144}
2145
2146/*
2147 * smb_sid_print
2148 */
2149static int
2150smb_sid_print(uintptr_t addr)
2151{
2152	smb_sid_t	sid;
2153	smb_sid_t	*psid;
2154	size_t		sid_size;
2155	int		i;
2156	uint64_t	authority;
2157
2158	sid_size = offsetof(smb_sid_t, sid_subauth);
2159
2160	if (mdb_vread(&sid, sid_size, addr) != sid_size) {
2161		mdb_warn("failed to read struct smb_sid at %p", addr);
2162		return (DCMD_ERR);
2163	}
2164
2165	sid_size += sid.sid_subauthcnt * sizeof (sid.sid_subauth[0]);
2166
2167	psid = mdb_zalloc(sid_size, UM_SLEEP | UM_GC);
2168	if (mdb_vread(psid, sid_size, addr) != sid_size) {
2169		mdb_warn("failed to read struct smb_sid at %p", addr);
2170		return (DCMD_ERR);
2171	}
2172
2173	mdb_printf("S-%d", psid->sid_revision);
2174	authority = 0;
2175	for (i = 0; i < NT_SID_AUTH_MAX; i++) {
2176		authority += ((uint64_t)psid->sid_authority[i]) <<
2177		    (8 * (NT_SID_AUTH_MAX - 1) - i);
2178	}
2179	mdb_printf("-%ll", authority);
2180
2181	for (i = 0; i < psid->sid_subauthcnt; i++)
2182		mdb_printf("-%d", psid->sid_subauth[i]);
2183
2184	return (DCMD_OK);
2185}
2186
2187/*
2188 * *****************************************************************************
2189 * ********************************* smb_fssd_t ********************************
2190 * *****************************************************************************
2191 */
2192
2193/*
2194 * ::smbfssd
2195 */
2196static int
2197smb_fssd(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
2198{
2199	smb_fssd_t	fssd;
2200	int		rc;
2201
2202	/*
2203	 * An smb_fssd address is required.
2204	 */
2205	if (!(flags & DCMD_ADDRSPEC))
2206		return (DCMD_USAGE);
2207
2208	if (mdb_vread(&fssd, sizeof (fssd), addr) != sizeof (fssd)) {
2209		mdb_warn("failed to read struct smb_fssd at %p", addr);
2210		return (DCMD_ERR);
2211	}
2212
2213	mdb_printf("FSSD secinfo: 0x%x\n", fssd.sd_secinfo);
2214	if (fssd.sd_secinfo & SMB_OWNER_SECINFO)
2215		mdb_printf("FSSD uid: %d\n", fssd.sd_uid);
2216	if (fssd.sd_secinfo & SMB_GROUP_SECINFO)
2217		mdb_printf("FSSD gid: %d\n", fssd.sd_gid);
2218	if (fssd.sd_secinfo & SMB_SACL_SECINFO && fssd.sd_zsacl) {
2219		mdb_printf("%<b>%<u>System ACL%</u>%</b>\n");
2220		(void) mdb_inc_indent(SMB_DCMD_INDENT);
2221		rc = mdb_call_dcmd("smbacl", (uintptr_t)fssd.sd_zsacl, flags,
2222		    argc, argv);
2223		(void) mdb_dec_indent(SMB_DCMD_INDENT);
2224		if (rc != DCMD_OK)
2225			return (rc);
2226	}
2227	if (fssd.sd_secinfo & SMB_DACL_SECINFO && fssd.sd_zdacl) {
2228		mdb_printf("%<b>%<u>Discretionary ACL%</u>%</b>\n");
2229		(void) mdb_inc_indent(SMB_DCMD_INDENT);
2230		rc = mdb_call_dcmd("smbacl", (uintptr_t)fssd.sd_zdacl, flags,
2231		    argc, argv);
2232		(void) mdb_dec_indent(SMB_DCMD_INDENT);
2233		if (rc != DCMD_OK)
2234			return (rc);
2235	}
2236
2237	return (DCMD_OK);
2238}
2239
2240/*
2241 * *****************************************************************************
2242 * **************************** Utility Funcions *******************************
2243 * *****************************************************************************
2244 */
2245
2246/*
2247 * smb_dcmd_getopt
2248 *
2249 * This function analyzes the arguments passed in and sets the bit corresponding
2250 * to the options found in the opts variable.
2251 *
2252 * Return Value
2253 *
2254 *	-1	An error occured during the decoding
2255 *	0	The decoding was successful
2256 */
2257static int
2258smb_dcmd_getopt(uint_t *opts, int argc, const mdb_arg_t *argv)
2259{
2260	*opts = 0;
2261
2262	if (mdb_getopts(argc, argv,
2263	    's', MDB_OPT_SETBITS, SMB_OPT_SERVER, opts,
2264	    'e', MDB_OPT_SETBITS, SMB_OPT_SESSION, opts,
2265	    'r', MDB_OPT_SETBITS, SMB_OPT_REQUEST, opts,
2266	    'u', MDB_OPT_SETBITS, SMB_OPT_USER, opts,
2267	    't', MDB_OPT_SETBITS, SMB_OPT_TREE, opts,
2268	    'f', MDB_OPT_SETBITS, SMB_OPT_OFILE, opts,
2269	    'd', MDB_OPT_SETBITS, SMB_OPT_ODIR, opts,
2270	    'w', MDB_OPT_SETBITS, SMB_OPT_WALK, opts,
2271	    'v', MDB_OPT_SETBITS, SMB_OPT_VERBOSE, opts,
2272	    NULL) != argc)
2273		return (-1);
2274
2275	return (0);
2276}
2277
2278/*
2279 * smb_dcmd_setopt
2280 *
2281 * This function set the arguments corresponding to the bits set in opts.
2282 *
2283 * Return Value
2284 *
2285 *	Number of arguments set.
2286 */
2287static int
2288smb_dcmd_setopt(uint_t opts, int max_argc, mdb_arg_t *argv)
2289{
2290	int	i;
2291	int	argc = 0;
2292
2293	for (i = 0; i < SMB_MDB_MAX_OPTS; i++) {
2294		if ((opts & smb_opts[i].o_value) && (argc < max_argc)) {
2295			argv->a_type = MDB_TYPE_STRING;
2296			argv->a_un.a_str = smb_opts[i].o_name;
2297			argc++;
2298			argv++;
2299		}
2300	}
2301	return (argc);
2302}
2303
2304/*
2305 * smb_obj_expand
2306 */
2307static int
2308smb_obj_expand(uintptr_t addr, uint_t opts, const smb_exp_t *x, ulong_t indent)
2309{
2310	int		rc = 0;
2311	int		argc;
2312	mdb_arg_t	argv[SMB_MDB_MAX_OPTS];
2313
2314	argc = smb_dcmd_setopt(opts | SMB_OPT_WALK, SMB_MDB_MAX_OPTS, argv);
2315
2316	(void) mdb_inc_indent(indent);
2317	while (x->ex_dcmd) {
2318		if (x->ex_mask & opts) {
2319			rc = mdb_pwalk_dcmd("list", x->ex_dcmd, argc, argv,
2320			    addr + x->ex_offset);
2321
2322			if (rc) {
2323				mdb_warn("failed to walk the list of %s in %p",
2324				    x->ex_name, addr + x->ex_offset);
2325				break;
2326			}
2327		}
2328		x++;
2329	}
2330	(void) mdb_dec_indent(indent);
2331	return (rc);
2332}
2333
2334/*
2335 * smb_obj_list
2336 *
2337 * Function called by the DCMDs when no address is provided. It expands the
2338 * tree under the object type associated with the calling DCMD (based on the
2339 * flags passed in).
2340 *
2341 * Return Value
2342 *
2343 *	DCMD_OK
2344 *	DCMD_ERR
2345 */
2346static int
2347smb_obj_list(const char *name, uint_t opts, uint_t flags)
2348{
2349	int		argc;
2350	mdb_arg_t	argv[SMB_MDB_MAX_OPTS];
2351
2352	argc = smb_dcmd_setopt(opts, SMB_MDB_MAX_OPTS, argv);
2353
2354	if (mdb_call_dcmd("smblist", 0, flags, argc, argv)) {
2355		mdb_warn("failed to list %s", name);
2356		return (DCMD_ERR);
2357	}
2358	return (DCMD_OK);
2359}
2360
2361static int
2362smb_worker_findstack(uintptr_t addr)
2363{
2364	kthread_t	t;
2365	taskq_t		tq;
2366	char		cmd[80];
2367	mdb_arg_t	cmdarg;
2368
2369	if (mdb_vread(&t, sizeof (kthread_t), addr) == -1) {
2370		mdb_warn("failed to read kthread_t at %p", addr);
2371		return (DCMD_ERR);
2372	}
2373
2374	if (mdb_vread(&tq, sizeof (taskq_t), (uintptr_t)t.t_taskq) == -1)
2375		tq.tq_name[0] = '\0';
2376
2377	mdb_inc_indent(2);
2378
2379	mdb_printf("PC: %a", t.t_pc);
2380	if (t.t_tid == 0) {
2381		if (tq.tq_name[0] != '\0')
2382			mdb_printf("    TASKQ: %s\n", tq.tq_name);
2383		else
2384			mdb_printf("    THREAD: %a()\n", t.t_startpc);
2385	}
2386
2387	mdb_snprintf(cmd, sizeof (cmd), "<.$c%d", 16);
2388	cmdarg.a_type = MDB_TYPE_STRING;
2389	cmdarg.a_un.a_str = cmd;
2390	(void) mdb_call_dcmd("findstack", addr, DCMD_ADDRSPEC, 1, &cmdarg);
2391	mdb_dec_indent(2);
2392	mdb_printf("\n");
2393	return (DCMD_OK);
2394}
2395