xref: /illumos-gate/usr/src/cmd/mdb/common/modules/nfs/nfs.c (revision 7a6d80f1660abd4755c68cbd094d4a914681d26e)
1 /*
2  * This file and its contents are supplied under the terms of the
3  * Common Development and Distribution License ("CDDL"), version 1.0.
4  * You may only use this file in accordance with the terms of version
5  * 1.0 of the CDDL.
6  *
7  * A full copy of the text of the CDDL should have accompanied this
8  * source.  A copy of the CDDL is also available via the Internet at
9  * http://www.illumos.org/license/CDDL.
10  */
11 /*
12  * Copyright 2021 Tintri by DDN, Inc. All rights reserved.
13  */
14 
15 #include <sys/mdb_modapi.h>
16 #include <mdb/mdb_types.h>
17 #include <sys/refstr.h>
18 #include <sys/kstat.h>
19 #include <sys/refstr_impl.h>
20 #include <nfs/nfs4_clnt.h>
21 #include <nfs/nfs_clnt.h>
22 #include <nfs/nfs4_db_impl.h>
23 #include <nfs/nfs4.h>
24 #include <nfs/rnode.h>
25 #include <nfs/rnode4.h>
26 #include <rpc/clnt.h>
27 #include <nfs/nfs4_idmap_impl.h>
28 #include <mdb/mdb_ks.h>
29 
30 #include "svc.h"
31 #include "rfs4.h"
32 #include "nfssrv.h"
33 #include "idmap.h"
34 #include "nfs_clnt.h"
35 
36 typedef struct nfs_rnode_cbdata {
37 	int printed_hdr;
38 	uintptr_t vfs_addr;	/* for nfs_rnode4find */
39 } nfs_rnode_cbdata_t;
40 
41 static const mdb_bitmask_t vfs_flags[] = {
42 	{ "VFS_RDONLY",   VFS_RDONLY,   VFS_RDONLY },
43 	{ "VFS_NOMNTTAB", VFS_NOMNTTAB, VFS_NOMNTTAB },
44 	{ "VFS_NOSETUID", VFS_NOSETUID, VFS_NOSETUID },
45 	{ "VFS_REMOUNT",  VFS_REMOUNT,  VFS_REMOUNT },
46 	{ "VFS_NOTRUNC",  VFS_NOTRUNC,  VFS_NOTRUNC },
47 	{ "VFS_PXFS",	  VFS_PXFS,	VFS_PXFS },
48 	{ "VFS_NBMAND",   VFS_NBMAND,   VFS_NBMAND },
49 	{ "VFS_XATTR",    VFS_XATTR,    VFS_XATTR },
50 	{ "VFS_NOEXEC",   VFS_NOEXEC,   VFS_NOEXEC },
51 	{ "VFS_STATS",    VFS_STATS,    VFS_STATS },
52 	{ "VFS_XID",	  VFS_XID,	VFS_XID },
53 	{ "VFS_UNLINKABLE", VFS_UNLINKABLE, VFS_UNLINKABLE },
54 	{ "VFS_UNMOUNTED",  VFS_UNMOUNTED,  VFS_UNMOUNTED },
55 	{ NULL, 0, 0 }
56 };
57 
58 static const mdb_bitmask_t nfs_mi4_flags[] = {
59 	{ "MI4_HARD",	  MI4_HARD,	MI4_HARD },
60 	{ "MI4_PRINTED",  MI4_PRINTED,  MI4_PRINTED },
61 	{ "MI4_INT",	  MI4_INT,	MI4_INT },
62 	{ "MI4_DOWN",	  MI4_DOWN,	MI4_DOWN },
63 	{ "MI4_NOAC",	  MI4_NOAC,	MI4_NOAC },
64 	{ "MI4_NOCTO",    MI4_NOCTO,    MI4_NOCTO },
65 	{ "MI4_LLOCK",    MI4_LLOCK,    MI4_LLOCK },
66 	{ "MI4_GRPID",    MI4_GRPID,    MI4_GRPID },
67 	{ "MI4_SHUTDOWN", MI4_SHUTDOWN, MI4_SHUTDOWN },
68 	{ "MI4_LINK",	  MI4_LINK,	MI4_LINK },
69 	{ "MI4_SYMLINK",  MI4_SYMLINK,  MI4_SYMLINK },
70 	{ "MI4_ACL",	  MI4_ACL,	MI4_ACL },
71 	{ "MI4_REFERRAL", MI4_REFERRAL, MI4_REFERRAL },
72 	{ "MI4_NOPRINT",  MI4_NOPRINT,  MI4_NOPRINT },
73 	{ "MI4_DIRECTIO", MI4_DIRECTIO, MI4_DIRECTIO },
74 	{ "MI4_PUBLIC",   MI4_PUBLIC,   MI4_PUBLIC },
75 	{ "MI4_MOUNTING", MI4_MOUNTING, MI4_MOUNTING },
76 	{ "MI4_DEAD",	  MI4_DEAD,	MI4_DEAD },
77 	{ "MI4_TIMEDOUT", MI4_TIMEDOUT, MI4_TIMEDOUT },
78 	{ "MI4_MIRRORMOUNT",  MI4_MIRRORMOUNT, MI4_MIRRORMOUNT },
79 	{ "MI4_RECOV_ACTIV",  MI4_RECOV_ACTIV, MI4_RECOV_ACTIV },
80 	{ "MI4_RECOV_FAIL",   MI4_RECOV_FAIL,  MI4_RECOV_FAIL },
81 	{ "MI4_POSIX_LOCK",   MI4_POSIX_LOCK,  MI4_POSIX_LOCK },
82 	{ "MI4_LOCK_DEBUG",   MI4_LOCK_DEBUG,  MI4_LOCK_DEBUG },
83 	{ "MI4_INACTIVE_IDLE",  MI4_INACTIVE_IDLE,  MI4_INACTIVE_IDLE },
84 	{ "MI4_BADOWNER_DEBUG", MI4_BADOWNER_DEBUG, MI4_BADOWNER_DEBUG },
85 	{ "MI4_ASYNC_MGR_STOP", MI4_ASYNC_MGR_STOP, MI4_ASYNC_MGR_STOP },
86 	{ "MI4_EPHEMERAL",	MI4_EPHEMERAL,	    MI4_EPHEMERAL },
87 	{ "MI4_REMOVE_ON_LAST_CLOSE", MI4_REMOVE_ON_LAST_CLOSE,
88 	    MI4_REMOVE_ON_LAST_CLOSE },
89 	{ NULL, 0, 0 }
90 };
91 
92 static const mdb_bitmask_t nfs_mi4_recover[] = {
93 	{ "MI4R_NEED_CLIENTID", MI4R_NEED_CLIENTID, MI4R_NEED_CLIENTID },
94 	{ "MI4R_REOPEN_FILES",  MI4R_REOPEN_FILES,  MI4R_REOPEN_FILES },
95 	{ "MI4R_NEED_SECINFO",  MI4R_NEED_SECINFO,  MI4R_NEED_SECINFO },
96 	{ "MI4R_REOPEN_FILES",  MI4R_REOPEN_FILES,  MI4R_REOPEN_FILES },
97 	{ "MI4R_SRV_REBOOT",    MI4R_SRV_REBOOT,    MI4R_SRV_REBOOT },
98 	{ "MI4R_LOST_STATE",    MI4R_LOST_STATE,    MI4R_LOST_STATE },
99 	{ "MI4R_BAD_SEQID",	MI4R_BAD_SEQID,	    MI4R_BAD_SEQID },
100 	{ "MI4R_MOVED",		MI4R_MOVED,	    MI4R_MOVED },
101 	{ "MI4R_NEED_NEW_SERVER", MI4R_NEED_NEW_SERVER, MI4R_NEED_NEW_SERVER },
102 	{ NULL, 0, 0 }
103 };
104 
105 static const char *
106 nfs4_tag_str(int tag)
107 {
108 	switch (tag) {
109 	case TAG_NONE:
110 		return ("TAG_NONE");
111 	case TAG_ACCESS:
112 		return ("TAG_ACCESS");
113 	case TAG_CLOSE:
114 		return ("TAG_CLOSE");
115 	case TAG_CLOSE_LOST:
116 		return ("TAG_CLOSE_LOST");
117 	case TAG_CLOSE_UNDO:
118 		return ("TAG_CLOSE_UNDO");
119 	case TAG_COMMIT:
120 		return ("TAG_COMMIT");
121 	case TAG_DELEGRETURN:
122 		return ("TAG_DELEGRETURN");
123 	case TAG_FSINFO:
124 		return ("TAG_FSINFO");
125 	case TAG_GET_SYMLINK:
126 		return ("TAG_GET_SYMLINK");
127 	case TAG_GETATTR:
128 		return ("TAG_GETATTR");
129 	case TAG_GETATTR_FSLOCATION:
130 		return ("TAG_GETATTR_FSLOCATION");
131 	case TAG_INACTIVE:
132 		return ("TAG_INACTIVE");
133 	case TAG_LINK:
134 		return ("TAG_LINK");
135 	case TAG_LOCK:
136 		return ("TAG_LOCK");
137 	case TAG_LOCK_RECLAIM:
138 		return ("TAG_LOCK_RECLAIM");
139 	case TAG_LOCK_RESEND:
140 		return ("TAG_LOCK_RESEND");
141 	case TAG_LOCK_REINSTATE:
142 		return ("TAG_LOCK_REINSTATE");
143 	case TAG_LOCK_UNKNOWN:
144 		return ("TAG_LOCK_UNKNOWN");
145 	case TAG_LOCKT:
146 		return ("TAG_LOCKT");
147 	case TAG_LOCKU:
148 		return ("TAG_LOCKU");
149 	case TAG_LOCKU_RESEND:
150 		return ("TAG_LOCKU_RESEND");
151 	case TAG_LOCKU_REINSTATE:
152 		return ("TAG_LOCKU_REINSTATE");
153 	case TAG_LOOKUP:
154 		return ("TAG_LOOKUP");
155 	case TAG_LOOKUP_PARENT:
156 		return ("TAG_LOOKUP_PARENT");
157 	case TAG_LOOKUP_VALID:
158 		return ("TAG_LOOKUP_VALID");
159 	case TAG_LOOKUP_VPARENT:
160 		return ("TAG_LOOKUP_VPARENT");
161 	case TAG_MKDIR:
162 		return ("TAG_MKDIR");
163 	case TAG_MKNOD:
164 		return ("TAG_MKNOD");
165 	case TAG_MOUNT:
166 		return ("TAG_MOUNT");
167 	case TAG_OPEN:
168 		return ("TAG_OPEN");
169 	case TAG_OPEN_CONFIRM:
170 		return ("TAG_OPEN_CONFIRM");
171 	case TAG_OPEN_CONFIRM_LOST:
172 		return ("TAG_OPEN_CONFIRM_LOST");
173 	case TAG_OPEN_DG:
174 		return ("TAG_OPEN_DG");
175 	case TAG_OPEN_DG_LOST:
176 		return ("TAG_OPEN_DG_LOST");
177 	case TAG_OPEN_LOST:
178 		return ("TAG_OPEN_LOST");
179 	case TAG_OPENATTR:
180 		return ("TAG_OPENATTR");
181 	case TAG_PATHCONF:
182 		return ("TAG_PATHCONF");
183 	case TAG_PUTROOTFH:
184 		return ("TAG_PUTROOTFH");
185 	case TAG_READ:
186 		return ("TAG_READ");
187 	case TAG_READAHEAD:
188 		return ("TAG_READAHEAD");
189 	case TAG_READDIR:
190 		return ("TAG_READDIR");
191 	case TAG_READLINK:
192 		return ("TAG_READLINK");
193 	case TAG_RELOCK:
194 		return ("TAG_RELOCK");
195 	case TAG_REMAP_LOOKUP:
196 		return ("TAG_REMAP_LOOKUP");
197 	case TAG_REMAP_LOOKUP_AD:
198 		return ("TAG_REMAP_LOOKUP_AD");
199 	case TAG_REMAP_LOOKUP_NA:
200 		return ("TAG_REMAP_LOOKUP_NA");
201 	case TAG_REMAP_MOUNT:
202 		return ("TAG_REMAP_MOUNT");
203 	case TAG_RMDIR:
204 		return ("TAG_RMDIR");
205 	case TAG_REMOVE:
206 		return ("TAG_REMOVE");
207 	case TAG_RENAME:
208 		return ("TAG_RENAME");
209 	case TAG_RENAME_VFH:
210 		return ("TAG_RENAME_VFH");
211 	case TAG_RENEW:
212 		return ("TAG_RENEW");
213 	case TAG_REOPEN:
214 		return ("TAG_REOPEN");
215 	case TAG_REOPEN_LOST:
216 		return ("TAG_REOPEN_LOST");
217 	case TAG_SECINFO:
218 		return ("TAG_SECINFO");
219 	case TAG_SETATTR:
220 		return ("TAG_SETATTR");
221 	case TAG_SETCLIENTID:
222 		return ("TAG_SETCLIENTID");
223 	case TAG_SETCLIENTID_CF:
224 		return ("TAG_SETCLIENTID_CF");
225 	case TAG_SYMLINK:
226 		return ("TAG_SYMLINK");
227 	case TAG_WRITE:
228 		return ("TAG_WRITE");
229 	default:
230 		return ("Undefined");
231 	}
232 }
233 
234 /*
235  * Return stringified NFS4 error.
236  * Note, it may return pointer to static buffer (in case of unknown error)
237  */
238 static const char *
239 nfs4_stat_str(nfsstat4 err)
240 {
241 	static char str[64];
242 
243 	switch (err) {
244 	case NFS4_OK:
245 		return ("NFS4_OK");
246 	case NFS4ERR_PERM:
247 		return ("NFS4ERR_PERM");
248 	case NFS4ERR_NOENT:
249 		return ("NFS4ERR_NOENT");
250 	case NFS4ERR_IO:
251 		return ("NFS4ERR_IO");
252 	case NFS4ERR_NXIO:
253 		return ("NFS4ERR_NXIO");
254 	case NFS4ERR_ACCESS:
255 		return ("NFS4ERR_ACCESS");
256 	case NFS4ERR_EXIST:
257 		return ("NFS4ERR_EXIST");
258 	case NFS4ERR_XDEV:
259 		return ("NFS4ERR_XDEV");
260 	case NFS4ERR_NOTDIR:
261 		return ("NFS4ERR_NOTDIR");
262 	case NFS4ERR_ISDIR:
263 		return ("NFS4ERR_ISDIR");
264 	case NFS4ERR_INVAL:
265 		return ("NFS4ERR_INVAL");
266 	case NFS4ERR_FBIG:
267 		return ("NFS4ERR_FBIG");
268 	case NFS4ERR_NOSPC:
269 		return ("NFS4ERR_NOSPC");
270 	case NFS4ERR_ROFS:
271 		return ("NFS4ERR_ROFS");
272 	case NFS4ERR_MLINK:
273 		return ("NFS4ERR_MLINK");
274 	case NFS4ERR_NAMETOOLONG:
275 		return ("NFS4ERR_NAMETOOLONG");
276 	case NFS4ERR_NOTEMPTY:
277 		return ("NFS4ERR_NOTEMPTY");
278 	case NFS4ERR_DQUOT:
279 		return ("NFS4ERR_DQUOT");
280 	case NFS4ERR_STALE:
281 		return ("NFS4ERR_STALE");
282 	case NFS4ERR_BADHANDLE:
283 		return ("NFS4ERR_BADHANDLE");
284 	case NFS4ERR_BAD_COOKIE:
285 		return ("NFS4ERR_BAD_COOKIE");
286 	case NFS4ERR_NOTSUPP:
287 		return ("NFS4ERR_NOTSUPP");
288 	case NFS4ERR_TOOSMALL:
289 		return ("NFS4ERR_TOOSMALL");
290 	case NFS4ERR_SERVERFAULT:
291 		return ("NFS4ERR_SERVERFAULT");
292 	case NFS4ERR_BADTYPE:
293 		return ("NFS4ERR_BADTYPE");
294 	case NFS4ERR_DELAY:
295 		return ("NFS4ERR_DELAY");
296 	case NFS4ERR_SAME:
297 		return ("NFS4ERR_SAME");
298 	case NFS4ERR_DENIED:
299 		return ("NFS4ERR_DENIED");
300 	case NFS4ERR_EXPIRED:
301 		return ("NFS4ERR_EXPIRED");
302 	case NFS4ERR_LOCKED:
303 		return ("NFS4ERR_LOCKED");
304 	case NFS4ERR_GRACE:
305 		return ("NFS4ERR_GRACE");
306 	case NFS4ERR_FHEXPIRED:
307 		return ("NFS4ERR_FHEXPIRED");
308 	case NFS4ERR_SHARE_DENIED:
309 		return ("NFS4ERR_SHARE_DENIED");
310 	case NFS4ERR_WRONGSEC:
311 		return ("NFS4ERR_WRONGSEC");
312 	case NFS4ERR_CLID_INUSE:
313 		return ("NFS4ERR_CLID_INUSE");
314 	case NFS4ERR_RESOURCE:
315 		return ("NFS4ERR_RESOURCE");
316 	case NFS4ERR_MOVED:
317 		return ("NFS4ERR_MOVED");
318 	case NFS4ERR_NOFILEHANDLE:
319 		return ("NFS4ERR_NOFILEHANDLE");
320 	case NFS4ERR_MINOR_VERS_MISMATCH:
321 		return ("NFS4ERR_MINOR_VERS_MISMATCH");
322 	case NFS4ERR_STALE_CLIENTID:
323 		return ("NFS4ERR_STALE_CLIENTID");
324 	case NFS4ERR_STALE_STATEID:
325 		return ("NFS4ERR_STALE_STATEID");
326 	case NFS4ERR_OLD_STATEID:
327 		return ("NFS4ERR_OLD_STATEID");
328 	case NFS4ERR_BAD_STATEID:
329 		return ("NFS4ERR_BAD_STATEID");
330 	case NFS4ERR_BAD_SEQID:
331 		return ("NFS4ERR_BAD_SEQID");
332 	case NFS4ERR_NOT_SAME:
333 		return ("NFS4ERR_NOT_SAME");
334 	case NFS4ERR_LOCK_RANGE:
335 		return ("NFS4ERR_LOCK_RANGE");
336 	case NFS4ERR_SYMLINK:
337 		return ("NFS4ERR_SYMLINK");
338 	case NFS4ERR_RESTOREFH:
339 		return ("NFS4ERR_RESTOREFH");
340 	case NFS4ERR_LEASE_MOVED:
341 		return ("NFS4ERR_LEASE_MOVED");
342 	case NFS4ERR_ATTRNOTSUPP:
343 		return ("NFS4ERR_ATTRNOTSUPP");
344 	case NFS4ERR_NO_GRACE:
345 		return ("NFS4ERR_NO_GRACE");
346 	case NFS4ERR_RECLAIM_BAD:
347 		return ("NFS4ERR_RECLAIM_BAD");
348 	case NFS4ERR_RECLAIM_CONFLICT:
349 		return ("NFS4ERR_RECLAIM_CONFLICT");
350 	case NFS4ERR_BADXDR:
351 		return ("NFS4ERR_BADXDR");
352 	case NFS4ERR_LOCKS_HELD:
353 		return ("NFS4ERR_LOCKS_HELD");
354 	case NFS4ERR_OPENMODE:
355 		return ("NFS4ERR_OPENMODE");
356 	case NFS4ERR_BADOWNER:
357 		return ("NFS4ERR_BADOWNER");
358 	case NFS4ERR_BADCHAR:
359 		return ("NFS4ERR_BADCHAR");
360 	case NFS4ERR_BADNAME:
361 		return ("NFS4ERR_BADNAME");
362 	case NFS4ERR_BAD_RANGE:
363 		return ("NFS4ERR_BAD_RANGE");
364 	case NFS4ERR_LOCK_NOTSUPP:
365 		return ("NFS4ERR_LOCK_NOTSUPP");
366 	case NFS4ERR_OP_ILLEGAL:
367 		return ("NFS4ERR_OP_ILLEGAL");
368 	case NFS4ERR_DEADLOCK:
369 		return ("NFS4ERR_DEADLOCK");
370 	case NFS4ERR_FILE_OPEN:
371 		return ("NFS4ERR_FILE_OPEN");
372 	case NFS4ERR_ADMIN_REVOKED:
373 		return ("NFS4ERR_ADMIN_REVOKED");
374 	case NFS4ERR_CB_PATH_DOWN:
375 		return ("NFS4ERR_CB_PATH_DOWN");
376 	default:
377 		mdb_snprintf(str, sizeof (str), "Unknown %d", err);
378 		return (str);
379 	}
380 }
381 
382 static const char *
383 nfs4_op_str(uint_t op)
384 {
385 	switch (op) {
386 	case OP_ACCESS:
387 		return ("OP_ACCESS");
388 	case OP_CLOSE:
389 		return ("OP_CLOSE");
390 	case OP_COMMIT:
391 		return ("OP_COMMIT");
392 	case OP_CREATE:
393 		return ("OP_CREATE");
394 	case OP_DELEGPURGE:
395 		return ("OP_DELEGPURGE");
396 	case OP_DELEGRETURN:
397 		return ("OP_DELEGRETURN");
398 	case OP_GETATTR:
399 		return ("OP_GETATTR");
400 	case OP_GETFH:
401 		return ("OP_GETFH");
402 	case OP_LINK:
403 		return ("OP_LINK");
404 	case OP_LOCK:
405 		return ("OP_LOCK");
406 	case OP_LOCKT:
407 		return ("OP_LOCKT");
408 	case OP_LOCKU:
409 		return ("OP_LOCKU");
410 	case OP_LOOKUP:
411 		return ("OP_LOOKUP");
412 	case OP_LOOKUPP:
413 		return ("OP_LOOKUPP");
414 	case OP_NVERIFY:
415 		return ("OP_NVERIFY");
416 	case OP_OPEN:
417 		return ("OP_OPEN");
418 	case OP_OPENATTR:
419 		return ("OP_OPENATTR");
420 	case OP_OPEN_CONFIRM:
421 		return ("OP_OPEN_CONFIRM");
422 	case OP_OPEN_DOWNGRADE:
423 		return ("OP_OPEN_DOWNGRADE");
424 	case OP_PUTFH:
425 		return ("OP_PUTFH");
426 	case OP_PUTPUBFH:
427 		return ("OP_PUTPUBFH");
428 	case OP_PUTROOTFH:
429 		return ("OP_PUTROOTFH");
430 	case OP_READ:
431 		return ("OP_READ");
432 	case OP_READDIR:
433 		return ("OP_READDIR");
434 	case OP_READLINK:
435 		return ("OP_READLINK");
436 	case OP_REMOVE:
437 		return ("OP_REMOVE");
438 	case OP_RENAME:
439 		return ("OP_RENAME");
440 	case OP_RENEW:
441 		return ("OP_RENEW");
442 	case OP_RESTOREFH:
443 		return ("OP_RESTOREFH");
444 	case OP_SAVEFH:
445 		return ("OP_SAVEFH");
446 	case OP_SECINFO:
447 		return ("OP_SECINFO");
448 	case OP_SETATTR:
449 		return ("OP_SETATTR");
450 	case OP_SETCLIENTID:
451 		return ("OP_SETCLIENTID");
452 	case OP_SETCLIENTID_CONFIRM:
453 		return ("OP_SETCLIENTID_CONFIRM");
454 	case OP_VERIFY:
455 		return ("OP_VERIFY");
456 	case OP_WRITE:
457 		return ("OP_WRITE");
458 	case OP_RELEASE_LOCKOWNER:
459 		return ("OP_RELEASE_LOCKOWNER");
460 	case OP_ILLEGAL:
461 		return ("OP_ILLEGAL");
462 	default:
463 		return ("Unknown");
464 	}
465 }
466 
467 static const char *
468 nfs4_recov_str(uint_t act)
469 {
470 	switch (act) {
471 	case NR_UNUSED:
472 		return ("NR_UNUSED");
473 	case NR_STALE:
474 		return ("NR_STALE");
475 	case NR_FAILOVER:
476 		return ("NR_FAILOVER");
477 	case NR_CLIENTID:
478 		return ("NR_CLIENTID");
479 	case NR_OPENFILES:
480 		return ("NR_OPENFILES");
481 	case NR_WRONGSEC:
482 		return ("NR_WRONGSEC");
483 	case NR_EXPIRED:
484 		return ("NR_EXPIRED");
485 	case NR_BAD_STATEID:
486 		return ("NR_BAD_STATEID");
487 	case NR_FHEXPIRED:
488 		return ("NR_FHEXPIRED");
489 	case NR_BADHANDLE:
490 		return ("NR_BADHANDLE");
491 	case NR_BAD_SEQID:
492 		return ("NR_BAD_SEQID");
493 	case NR_OLDSTATEID:
494 		return ("NR_OLDSTATEID");
495 	case NR_GRACE:
496 		return ("NR_GRACE");
497 	case NR_DELAY:
498 		return ("NR_DELAY");
499 	case NR_LOST_LOCK:
500 		return ("NR_LOST_LOCK");
501 	case NR_LOST_STATE_RQST:
502 		return ("NR_LOST_STATE_RQST");
503 	case NR_MOVED:
504 		return ("NR_MOVED");
505 	default:
506 		return ("Unknown");
507 	}
508 }
509 
510 static void
511 nfs_addr_by_conf(uintptr_t knconf, struct netbuf *addr,
512     char *s, size_t nbytes)
513 {
514 	struct knetconfig conf;
515 	char buf[16];
516 
517 	if (mdb_vread(&conf, sizeof (conf), knconf) == -1) {
518 		mdb_warn("can't read sv_knconf");
519 		return;
520 	}
521 
522 	if (mdb_readstr(buf, sizeof (buf),
523 	    (uintptr_t)conf.knc_protofmly) == -1) {
524 		mdb_warn("can't read knc_protofmly");
525 		return;
526 	}
527 	/* Support only IPv4 addresses */
528 	if (strcmp(NC_INET, buf) == 0) {
529 		struct sockaddr_in *in;
530 
531 		in = mdb_alloc(addr->len + 1, UM_SLEEP | UM_GC);
532 		if (mdb_vread(in, addr->len, (uintptr_t)addr->buf) == -1)
533 			return;
534 
535 		mdb_nhconvert(&in->sin_port, &in->sin_port,
536 		    sizeof (in->sin_port));
537 
538 		(void) mdb_snprintf(s, nbytes, "%I:%d", in->sin_addr.s_addr,
539 		    in->sin_port);
540 	}
541 }
542 
543 /*
544  * Get IPv4 string address by servinfo4_t
545  *
546  * in case of error does not modify 's'
547  */
548 static void
549 nfs_addr_by_servinfo4(uintptr_t addr, char *s, size_t nbytes)
550 {
551 	struct servinfo4 *si;
552 
553 	si = mdb_alloc(sizeof (*si), UM_SLEEP | UM_GC);
554 	if (mdb_vread(si, sizeof (*si), addr) == -1) {
555 		mdb_warn("can't read servinfo4");
556 		return;
557 	}
558 
559 	nfs_addr_by_conf((uintptr_t)si->sv_knconf, &si->sv_addr,
560 	    s, nbytes);
561 }
562 
563 
564 /*
565  * Get IPv4 string address by servinfo_t
566  *
567  * in case of error does not modify 's'
568  */
569 static void
570 nfs_addr_by_servinfo(uintptr_t addr, char *s, size_t nbytes)
571 {
572 	struct servinfo *si;
573 
574 	si = mdb_alloc(sizeof (*si), UM_SLEEP | UM_GC);
575 	if (mdb_vread(si, sizeof (*si), addr) == -1) {
576 		mdb_warn("can't read servinfo");
577 		return;
578 	}
579 
580 	nfs_addr_by_conf((uintptr_t)si->sv_knconf, &si->sv_addr,
581 	    s, nbytes);
582 }
583 
584 static void
585 nfs_queue_show_event(const nfs4_debug_msg_t *msg)
586 {
587 	const nfs4_revent_t *re;
588 	time_t time;
589 	char *re_char1 = "<unknown>", *re_char2 = "<unknown>";
590 
591 	re = &msg->rmsg_u.msg_event;
592 	time = msg->msg_time.tv_sec;
593 
594 	if (re->re_char1 != NULL) {
595 		char *s;
596 
597 		s = mdb_alloc(MAXPATHLEN, UM_SLEEP | UM_GC);
598 		if (mdb_readstr(s, MAXPATHLEN, (uintptr_t)re->re_char1) != -1)
599 			re_char1 = s;
600 		else
601 			mdb_warn("can't read re_char1");
602 	}
603 
604 	if (re->re_char2 != NULL) {
605 		char *s;
606 
607 		s = mdb_alloc(MAXPATHLEN, UM_SLEEP | UM_GC);
608 
609 		if (mdb_readstr(s, MAXPATHLEN, (uintptr_t)re->re_char2) != -1)
610 			re_char2 = s;
611 		else
612 			mdb_warn("can't read re_char2");
613 	}
614 
615 	switch (re->re_type) {
616 	case RE_BAD_SEQID:
617 		mdb_printf("[NFS4]%Y: Op %s for file %s rnode_pt %p\n"
618 		    "pid %d using seqid %d got %s. Last good seqid was %d "
619 		    "for operation %s\n",
620 		    time, nfs4_tag_str(re->re_tag1), re->re_char1, re->re_rp1,
621 		    re->re_pid, re->re_seqid1, nfs4_stat_str(re->re_stat4),
622 		    re->re_seqid2, nfs4_tag_str(re->re_tag2));
623 		break;
624 	case RE_BADHANDLE:
625 		mdb_printf("[NFS4]%Y: server said filehandle was "
626 		    "invalid for file: %s rnode_pt 0x%p\n", time,
627 		    re_char1, re->re_rp1);
628 		break;
629 	case RE_CLIENTID:
630 		mdb_printf("[NFS4]%Y: Can't recover clientid on mountpoint %s\n"
631 		    "mi %p due to error %d (%s). Marking file system "
632 		    "as unusable\n", time, msg->msg_mntpt,
633 		    re->re_mi, re->re_uint, nfs4_stat_str(re->re_stat4));
634 		break;
635 	case RE_DEAD_FILE:
636 		mdb_printf("[NFS4]%Y: File: %s rnode_pt: %p was closed on NFS\n"
637 		    "recovery error [%s %s]\n", time, re_char1, re->re_rp1,
638 		    re_char2, nfs4_stat_str(re->re_stat4));
639 		break;
640 	case RE_END:
641 		mdb_printf("[NFS4]%Y: NFS Recovery done for mi %p "
642 		    "rnode_pt1 %s (%p), rnode_pt2 %s (%p)\n", time, re->re_mi,
643 		    re_char1, re->re_rp1, re_char2, re->re_rp2);
644 		break;
645 
646 	case RE_FAIL_RELOCK:
647 		mdb_printf("[NFS4]%Y: Couldn't reclaim lock for pid %d for\n"
648 		    "file %s (rnode_pt %p) error %d\n", time, re->re_pid,
649 		    re_char1, re->re_rp1,
650 		    re->re_uint ? re->re_uint : re->re_stat4);
651 		break;
652 	case RE_FAIL_REMAP_LEN:
653 		mdb_printf("[NFS4]%Y: remap_lookup: returned bad\n"
654 		    "fhandle length %d\n", time, re->re_uint);
655 		break;
656 	case RE_FAIL_REMAP_OP:
657 		mdb_printf("[NFS4]%Y: remap_lookup: didn't get expected "
658 		    " OP_GETFH\n", time);
659 		break;
660 	case RE_FAILOVER:
661 		mdb_printf("[NFS4]%Y: failing over to %s\n", time, re_char1);
662 		break;
663 
664 	case RE_FILE_DIFF:
665 		mdb_printf("[NFS4]%Y: File %s rnode_pt: %p was closed\n"
666 		    "and failed attempted failover since its is different\n"
667 		    "than the original file\n", time, re_char1, re->re_rp1);
668 		break;
669 
670 	case RE_LOST_STATE:
671 		mdb_printf("[NFS4]%Y: Lost %s request file %s\n"
672 		    "rnode_pt: %p, dir %s (%p)\n", time,
673 		    nfs4_op_str(re->re_uint), re_char1,
674 		    re->re_rp1, re_char2, re->re_rp2);
675 		break;
676 	case RE_OPENS_CHANGED:
677 		mdb_printf("[NFS4]%Y: The number of open files to reopen\n"
678 		    "changed for mount %s mi %p old %d, new %d\n", time,
679 		    msg->msg_mntpt, re->re_mi, re->re_uint, re->re_pid);
680 		break;
681 	case RE_SIGLOST:
682 	case RE_SIGLOST_NO_DUMP:
683 		mdb_printf("[NFS4]%Y: Process %d lost its locks on file %s\n"
684 		    "rnode_pt: %p due to NFS recovery error (%d:%s)\n",
685 		    time, re->re_pid, re_char1,
686 		    re->re_rp1, re->re_uint, nfs4_stat_str(re->re_stat4));
687 		break;
688 	case RE_START:
689 		mdb_printf("[NFS4]%Y: NFS Starting recovery for\n"
690 		    "mi %p mi_recovflags [0x%x] rnode_pt1 %s %p "
691 		    "rnode_pt2 %s %p\n", time,
692 		    re->re_mi, re->re_uint, re_char1, re->re_rp1,
693 		    re_char2, re->re_rp2);
694 		break;
695 	case RE_UNEXPECTED_ACTION:
696 		mdb_printf("[NFS4]%Y: NFS recovery: unexpected action %s\n",
697 		    time, nfs4_recov_str(re->re_uint));
698 		break;
699 	case RE_UNEXPECTED_ERRNO:
700 		mdb_printf("[NFS4]%Y: NFS recovery: unexpected errno %d\n",
701 		    time, re->re_uint);
702 		break;
703 	case RE_UNEXPECTED_STATUS:
704 		mdb_printf("[NFS4]%Y: NFS recovery: unexpected status"
705 		    "code (%s)\n", time, nfs4_stat_str(re->re_stat4));
706 		break;
707 	case RE_WRONGSEC:
708 		mdb_printf("[NFS4]%Y: NFS can't recover from NFS4ERR_WRONGSEC\n"
709 		    "error %d rnode_pt1 %s (%p) rnode_pt2 %s (0x%p)\n", time,
710 		    re->re_uint, re_char1, re->re_rp1, re_char2, re->re_rp2);
711 		break;
712 	case RE_LOST_STATE_BAD_OP:
713 		mdb_printf("[NFS4]%Y: NFS lost state with unrecognized op %d\n"
714 		    "fs %s, pid %d, file %s (rnode_pt: %p) dir %s (%p)\n",
715 		    time, re->re_uint, msg->msg_mntpt, re->re_pid, re_char1,
716 		    re->re_rp1, re_char2, re->re_rp2);
717 		break;
718 	case RE_REFERRAL:
719 		mdb_printf("[NFS4]%Y: being referred to %s\n",
720 		    time, re_char1);
721 		break;
722 	default:
723 		mdb_printf("illegal event %d\n", re->re_type);
724 		break;
725 	}
726 }
727 
728 static void
729 nfs_queue_show_fact(const nfs4_debug_msg_t *msg)
730 {
731 	time_t time;
732 	const nfs4_rfact_t *rf;
733 	char *rf_char1 = "<unknown>";
734 
735 	rf = &msg->rmsg_u.msg_fact;
736 	time = msg->msg_time.tv_sec;
737 
738 	if (rf->rf_char1 != NULL) {
739 		char *s;
740 
741 		s = mdb_alloc(MAXPATHLEN, UM_SLEEP | UM_GC);
742 		if (mdb_readstr(s, MAXPATHLEN, (uintptr_t)rf->rf_char1) != -1)
743 			rf_char1 = s;
744 		else
745 			mdb_warn("can't read rf_char1");
746 	}
747 
748 	switch (rf->rf_type) {
749 	case RF_ERR:
750 		mdb_printf("[NFS4]%Y: NFS op %s got "
751 		    "error %s:%d causing recovery action %s.%s\n",
752 		    time, nfs4_op_str(rf->rf_op),
753 		    rf->rf_error ? "" : nfs4_stat_str(rf->rf_stat4),
754 		    rf->rf_error,
755 		    nfs4_recov_str(rf->rf_action),
756 		    rf->rf_reboot ?
757 		    "  Client also suspects that the server rebooted,"
758 		    " or experienced a network partition." : "");
759 		break;
760 	case RF_RENEW_EXPIRED:
761 		mdb_printf("[NFS4]%Y: NFS4 renew thread detected client's "
762 		    "lease has expired. Current open files/locks/IO may fail\n",
763 		    time);
764 		break;
765 	case RF_SRV_NOT_RESPOND:
766 		mdb_printf("[NFS4]%Y: NFS server not responding;"
767 		    "still trying\n", time);
768 		break;
769 	case RF_SRV_OK:
770 		mdb_printf("[NFS4]%Y: NFS server ok\n", time);
771 		break;
772 	case RF_SRVS_NOT_RESPOND:
773 		mdb_printf("[NFS4]%Y: NFS servers not responding; "
774 		    "still trying\n", time);
775 		break;
776 	case RF_SRVS_OK:
777 		mdb_printf("[NFS4]%Y: NFS servers ok\n", time);
778 		break;
779 	case RF_DELMAP_CB_ERR:
780 		mdb_printf("[NFS4]%Y: NFS op %s got error %s when executing "
781 		    "delmap on file %s rnode_pt %p\n", time,
782 		    nfs4_op_str(rf->rf_op), nfs4_stat_str(rf->rf_stat4),
783 		    rf_char1, rf->rf_rp1);
784 		break;
785 	case RF_SENDQ_FULL:
786 		mdb_printf("[NFS4]%Y: sending queue to NFS server is full; "
787 		    "still trying\n", time);
788 		break;
789 
790 	default:
791 		mdb_printf("queue_print_fact: illegal fact %d\n", rf->rf_type);
792 	}
793 }
794 
795 static int
796 nfs4_show_message(uintptr_t addr, const void *arg, void *data)
797 {
798 	nfs4_debug_msg_t msg;
799 	if (mdb_vread(&msg, sizeof (msg), addr) == -1) {
800 		mdb_warn("failed to read nfs4_debug_msg_t at %p", addr);
801 		return (WALK_ERR);
802 	}
803 
804 	if (msg.msg_type == RM_EVENT)
805 		nfs_queue_show_event(&msg);
806 	else if (msg.msg_type == RM_FACT)
807 		nfs_queue_show_fact(&msg);
808 	else
809 		mdb_printf("Wrong msg_type %d\n", msg.msg_type);
810 	return (WALK_NEXT);
811 }
812 
813 static void
814 nfs4_print_messages(uintptr_t head)
815 {
816 	mdb_printf("-----------------------------\n");
817 	mdb_printf("Messages queued:\n");
818 	mdb_inc_indent(2);
819 	mdb_pwalk("list", nfs4_show_message, NULL, (uintptr_t)head);
820 	mdb_dec_indent(2);
821 	mdb_printf("-----------------------------\n");
822 }
823 
824 
825 static void
826 nfs_print_mi4(uintptr_t miaddr, int verbose)
827 {
828 	mntinfo4_t *mi;
829 	char str[INET6_ADDRSTRLEN] = "";
830 
831 	mi = mdb_alloc(sizeof (*mi), UM_SLEEP | UM_GC);
832 	if (mdb_vread(mi, sizeof (*mi), miaddr) == -1) {
833 		mdb_warn("can't read mntinfo");
834 		return;
835 	}
836 
837 	mdb_printf("mntinfo4_t:    %p\n", miaddr);
838 	mdb_printf("NFS Version:   4\n");
839 	mdb_printf("mi_flags:      %b\n", mi->mi_flags, nfs_mi4_flags);
840 	mdb_printf("mi_error:      %x\n", mi->mi_error);
841 	mdb_printf("mi_open_files: %d\n", mi->mi_open_files);
842 	mdb_printf("mi_msg_count:  %d\n", mi->mi_msg_count);
843 	mdb_printf("mi_recovflags: %b\n", mi->mi_recovflags,
844 	    nfs_mi4_recover);
845 	mdb_printf("mi_recovthread: %p\n", mi->mi_recovthread);
846 	mdb_printf("mi_in_recovery: %d\n", mi->mi_in_recovery);
847 
848 	if (verbose == 0)
849 		return;
850 
851 	mdb_printf("mi_zone:     %p\n", mi->mi_zone);
852 	mdb_printf("mi_curread:  %d\n", mi->mi_curread);
853 	mdb_printf("mi_curwrite: %d\n", mi->mi_curwrite);
854 	mdb_printf("mi_retrans:  %d\n", mi->mi_retrans);
855 	mdb_printf("mi_timeo:    %d\n", mi->mi_timeo);
856 	mdb_printf("mi_acregmin: %llu\n", mi->mi_acregmin);
857 	mdb_printf("mi_acregmax: %llu\n", mi->mi_acregmax);
858 	mdb_printf("mi_acdirmin: %llu\n", mi->mi_acdirmin);
859 	mdb_printf("mi_acdirmax: %llu\n", mi->mi_acdirmax);
860 	mdb_printf("mi_count:    %u\n", mi->mi_count);
861 	mdb_printf("\nServer list: %p\n", mi->mi_servers);
862 	nfs_addr_by_servinfo4((uintptr_t)mi->mi_curr_serv, str, sizeof (str));
863 	mdb_printf("Curr Server: %p %s\n", mi->mi_curr_serv, str);
864 	mdb_printf("Total:\n");
865 	mdb_inc_indent(2);
866 	mdb_printf("Server Non-responses: %u\n", mi->mi_noresponse);
867 	mdb_printf("Server Failovers:     %u\n\n", mi->mi_failover);
868 	mdb_dec_indent(2);
869 
870 	mdb_printf("\nAsync Request queue:\n");
871 	mdb_inc_indent(2);
872 	mdb_printf("max threads:     %u\n", mi->mi_max_threads);
873 	mdb_printf("active threads:  %u\n", mi->mi_threads[NFS_ASYNC_QUEUE]);
874 	mdb_dec_indent(2);
875 
876 	nfs4_print_messages(miaddr + OFFSETOF(mntinfo4_t, mi_msg_list));
877 }
878 
879 static void
880 nfs_print_mi(uintptr_t miaddr, uint_t vers)
881 {
882 	mntinfo_t *mi;
883 	char str[INET6_ADDRSTRLEN] = "";
884 
885 	mi = mdb_alloc(sizeof (*mi), UM_SLEEP | UM_GC);
886 	if (mdb_vread(mi, sizeof (*mi), miaddr) == -1) {
887 		mdb_warn("can't read mntinfo");
888 		return;
889 	}
890 
891 	mdb_printf("\nServer list: %p\n", mi->mi_servers);
892 	nfs_addr_by_servinfo((uintptr_t)mi->mi_curr_serv, str, sizeof (str));
893 	mdb_printf("Curr Server: %p %s\n", mi->mi_curr_serv, str);
894 	mdb_printf("Total:\n");
895 	mdb_inc_indent(2);
896 	mdb_printf("Server Non-responses: %u\n", mi->mi_noresponse);
897 	mdb_printf("Server Failovers:     %u\n\n", mi->mi_failover);
898 	mdb_dec_indent(2);
899 
900 	mdb_printf("\nAsync Request queue:\n");
901 	mdb_inc_indent(2);
902 	mdb_printf("max threads:     %u\n", mi->mi_max_threads);
903 	mdb_printf("active threads:  %u\n", mi->mi_threads[NFS_ASYNC_QUEUE]);
904 	mdb_dec_indent(2);
905 }
906 
907 static int
908 nfs_vfs_dcmd(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
909 {
910 	vfs_t *vfs;
911 	char buf[MAXNAMELEN];
912 	int verbose = 0;
913 
914 	if ((flags & DCMD_ADDRSPEC) == 0) {
915 		if (mdb_walk_dcmd("nfs_vfs", "nfs_vfs", argc, argv) == -1) {
916 			mdb_warn("failed to walk nfs_vfs");
917 			return (DCMD_ERR);
918 		}
919 		return (DCMD_OK);
920 	}
921 
922 	if (mdb_getopts(argc, argv,
923 	    'v', MDB_OPT_SETBITS, TRUE, &verbose, NULL) != argc)
924 		return (DCMD_USAGE);
925 
926 	vfs = mdb_alloc(sizeof (*vfs), UM_SLEEP | UM_GC);
927 
928 	if (mdb_vread(vfs, sizeof (*vfs), addr) == -1) {
929 		mdb_warn("failed to read vfs");
930 		return (DCMD_ERR);
931 	}
932 
933 	mdb_printf("vfs_t->%p, data = %p, ops = %p\n",
934 	    addr, vfs->vfs_data, vfs->vfs_op);
935 
936 	/* do not need do vread for vfs_mntpt because take address */
937 	if (mdb_readstr(buf, MAXNAMELEN,
938 	    (uintptr_t)&vfs->vfs_mntpt->rs_string) == -1)
939 		return (DCMD_ERR);
940 
941 	mdb_inc_indent(2);
942 
943 	mdb_printf("mount point: %s\n", buf);
944 	if (mdb_readstr(buf, MAXNAMELEN,
945 	    (uintptr_t)&vfs->vfs_resource->rs_string) == -1) {
946 		mdb_warn("can't read rs_string");
947 		goto err;
948 	}
949 	mdb_printf("mount  from: %s\n", buf);
950 
951 	if (verbose) {
952 		uintptr_t nfs4_ops;
953 		mntopt_t m;
954 		uint_t i;
955 
956 		mdb_printf("vfs_flags:  %b\n", vfs->vfs_flag, vfs_flags);
957 		mdb_printf("mount opts: ");
958 		for (i = 0; i < vfs->vfs_mntopts.mo_count; i++) {
959 			uintptr_t a = (uintptr_t)(vfs->vfs_mntopts.mo_list + i);
960 
961 			if (mdb_vread(&m, sizeof (m), a) == -1) {
962 				mdb_warn("can't read mntopt");
963 				continue;
964 			}
965 			if (m.mo_flags & MO_EMPTY)
966 				continue;
967 
968 			if (mdb_readstr(buf, sizeof (buf),
969 			    (uintptr_t)m.mo_name) == -1) {
970 				mdb_warn("can't read mo_name");
971 				continue;
972 			}
973 			if (m.mo_flags & MO_HASVALUE) {
974 				char val[64];
975 
976 				if (mdb_readstr(val, sizeof (val),
977 				    (uintptr_t)m.mo_arg) == -1) {
978 					mdb_warn("can't read mo_arg");
979 					continue;
980 				}
981 				mdb_printf("%s(%s), ", buf, val);
982 			} else
983 				mdb_printf("%s, ", buf);
984 		}
985 		mdb_printf("\n+--------------------------------------+\n");
986 
987 		if (mdb_readvar(&nfs4_ops, "nfs4_vfsops") == -1) {
988 			mdb_warn("failed read %s", "nfs4_vfsops");
989 			goto err;
990 		}
991 		if (nfs4_ops == (uintptr_t)vfs->vfs_op) {
992 			nfs_print_mi4((uintptr_t)VFTOMI4(vfs), 1);
993 		} else {
994 			int vers = 3;
995 			uintptr_t nfs3_ops;
996 
997 			if (mdb_readvar(&nfs3_ops, "nfs3_vfsops") == -1) {
998 				mdb_warn("failed read %s", "nfs3_vfsops");
999 				goto err;
1000 			}
1001 			if (nfs3_ops != (uintptr_t)vfs->vfs_op)
1002 				vers = 2;
1003 
1004 			nfs_print_mi((uintptr_t)VFTOMI(vfs), vers);
1005 		}
1006 	}
1007 	mdb_dec_indent(2);
1008 	mdb_printf("\n");
1009 	return (DCMD_OK);
1010 err:
1011 	mdb_dec_indent(2);
1012 	mdb_printf("\n");
1013 	return (DCMD_ERR);
1014 }
1015 
1016 
1017 static int
1018 nfs4_diag_dcmd(uintptr_t addr, uint_t flags, int argc,
1019     const mdb_arg_t *argv)
1020 {
1021 	mntinfo4_t *mi;
1022 	vfs_t *vfs;
1023 	char buf[MAXNAMELEN];
1024 
1025 	if ((flags & DCMD_ADDRSPEC) == 0) {
1026 		if (mdb_walk_dcmd("nfs4_mnt", "nfs4_diag", argc,
1027 		    argv) == -1) {
1028 			mdb_warn("failed to walk nfs4_mnt");
1029 			return (DCMD_ERR);
1030 		}
1031 		return (DCMD_OK);
1032 	}
1033 
1034 	mi = mdb_alloc(sizeof (*mi), UM_SLEEP | UM_GC);
1035 	if (mdb_vread(mi, sizeof (*mi), addr) == -1) {
1036 		mdb_warn("can't read mntinfo4");
1037 		return (WALK_ERR);
1038 	}
1039 
1040 	vfs = mdb_alloc(sizeof (*vfs), UM_SLEEP | UM_GC);
1041 	if (mdb_vread(vfs, sizeof (*vfs), (uintptr_t)mi->mi_vfsp) == -1) {
1042 		mdb_warn("failed to read vfs");
1043 		return (DCMD_ERR);
1044 	}
1045 
1046 	mdb_printf("****************************************\n");
1047 	mdb_printf("vfs: %-16p mi: %-16p\n", mi->mi_vfsp, addr);
1048 
1049 	if (mdb_readstr(buf, MAXNAMELEN,
1050 	    (uintptr_t)&vfs->vfs_mntpt->rs_string) == -1)
1051 		return (DCMD_ERR);
1052 
1053 	mdb_inc_indent(2);
1054 	mdb_printf("mount point:   %s\n", buf);
1055 	if (mdb_readstr(buf, MAXNAMELEN,
1056 	    (uintptr_t)&vfs->vfs_resource->rs_string) == -1) {
1057 		mdb_warn("can't read rs_string");
1058 		mdb_dec_indent(2);
1059 		return (DCMD_ERR);
1060 	}
1061 	mdb_printf("mount  from:   %s\n", buf);
1062 	nfs4_print_messages(addr + OFFSETOF(mntinfo4_t, mi_msg_list));
1063 	mdb_dec_indent(2);
1064 	mdb_printf("\n");
1065 	return (DCMD_OK);
1066 }
1067 
1068 static void
1069 nfs4_diag_help(void)
1070 {
1071 	mdb_printf(" <mntinfo4_t>::nfs4_diag <-s>\n"
1072 	    "      -> assumes client is an illumos NFSv4 client\n");
1073 }
1074 
1075 static int
1076 nfs_rnode4_cb(uintptr_t addr, const void *data, void *arg)
1077 {
1078 	const rnode4_t *rp = data;
1079 	nfs_rnode_cbdata_t *cbd = arg;
1080 	vnode_t *vp;
1081 
1082 	if (addr == 0)
1083 		return (WALK_DONE);
1084 
1085 	vp = mdb_alloc(sizeof (*vp), UM_SLEEP | UM_GC);
1086 	if (mdb_vread(vp, sizeof (*vp), (uintptr_t)rp->r_vnode) == -1) {
1087 		mdb_warn("can't read vnode_t %p", (uintptr_t)rp->r_vnode);
1088 		return (WALK_ERR);
1089 	}
1090 
1091 	if (cbd->vfs_addr != 0 &&
1092 	    cbd->vfs_addr != (uintptr_t)vp->v_vfsp)
1093 		return (WALK_NEXT);
1094 
1095 	if (cbd->printed_hdr == 0) {
1096 		mdb_printf("%-16s %-16s %-16s %-8s\n"
1097 		    "%-16s %-8s %-8s %s\n",
1098 		    "Address", "r_vnode", "vfsp", "r_fh",
1099 		    "r_server", "r_error", "r_flags", "r_count");
1100 		cbd->printed_hdr = 1;
1101 	}
1102 
1103 	mdb_printf("%-?p %-8p %-8p %-8p\n"
1104 	    "%-16p %-8u %-8x  %u\n",
1105 	    addr, rp->r_vnode, vp->v_vfsp, rp->r_fh,
1106 	    rp->r_server, (int)rp->r_error, rp->r_flags, rp->r_count);
1107 
1108 	return (WALK_NEXT);
1109 }
1110 
1111 static int
1112 nfs_rnode4_dcmd(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
1113 {
1114 	nfs_rnode_cbdata_t *cbd;
1115 	rnode4_t *rp;
1116 
1117 	cbd = mdb_zalloc(sizeof (*cbd),  UM_SLEEP | UM_GC);
1118 
1119 	if ((flags & DCMD_ADDRSPEC) == 0) {
1120 		if (mdb_walk("nfs_rtable4", nfs_rnode4_cb, cbd) == -1) {
1121 			mdb_warn("failed to walk nfs_rnode4");
1122 			return (DCMD_ERR);
1123 		}
1124 		return (DCMD_OK);
1125 	}
1126 
1127 	/* address was specified */
1128 	rp = mdb_alloc(sizeof (*rp), UM_SLEEP | UM_GC);
1129 	if (mdb_vread(rp, sizeof (*rp), addr) == -1) {
1130 		mdb_warn("can't read rnode4_t");
1131 		return (DCMD_ERR);
1132 	}
1133 
1134 	nfs_rnode4_cb(addr, rp, cbd);
1135 	return (DCMD_OK);
1136 }
1137 
1138 static void
1139 nfs_rnode4_help(void)
1140 {
1141 	mdb_printf("<rnode4 addr>::nfs_rnode4\n\n"
1142 	    "This prints NFSv4 rnode at address specified. If address\n"
1143 	    "is not specified, walks entire NFSv4 rnode table.\n");
1144 }
1145 
1146 static int
1147 nfs_rnode4find_dcmd(uintptr_t addr, uint_t flags, int argc,
1148     const mdb_arg_t *argv)
1149 {
1150 	nfs_rnode_cbdata_t *cbd;
1151 
1152 	cbd = mdb_zalloc(sizeof (*cbd),  UM_SLEEP | UM_GC);
1153 
1154 	if ((flags & DCMD_ADDRSPEC) == 0) {
1155 		mdb_printf("requires address of vfs_t\n");
1156 		return (DCMD_USAGE);
1157 	}
1158 
1159 	cbd->vfs_addr = addr;
1160 	if (mdb_walk("nfs_rtable4", nfs_rnode4_cb, cbd) == -1) {
1161 		mdb_warn("failed to walk nfs_rnode4");
1162 		return (DCMD_ERR);
1163 	}
1164 	return (DCMD_OK);
1165 }
1166 
1167 static void
1168 nfs_rnode4find_help(void)
1169 {
1170 	mdb_printf("<vfs addr>::nfs_rnode4find\n\n"
1171 	    "This prints all NFSv4 rnodes that belong to\n"
1172 	    "the VFS address specified\n");
1173 }
1174 
1175 static int nfs_help_dcmd(uintptr_t, uint_t, int, const mdb_arg_t *);
1176 
1177 extern int nfs_stat_dcmd(uintptr_t, uint_t, int, const mdb_arg_t *);
1178 
1179 static const mdb_dcmd_t dcmds[] = {
1180 	/* svc */
1181 	{
1182 		"svc_pool", "?[-v] [poolid ...]",
1183 		"display SVCPOOL information\n"
1184 		"\t\t\t(Optional address of SVCPOOL)",
1185 		svc_pool_dcmd, svc_pool_help
1186 	},
1187 	{
1188 		"svc_mxprt", ":[-w]",
1189 		"display master xprt info given SVCMASTERXPRT",
1190 		svc_mxprt_dcmd, svc_mxprt_help
1191 	},
1192 	/* rfs4 */
1193 	{
1194 		"rfs4_db", "?",
1195 		"dump NFSv4 server database\n"
1196 		"\t\t\t(Optional address of zone_t)",
1197 		rfs4_db_dcmd
1198 	},
1199 	{
1200 		"rfs4_tbl", ":[-vw]",
1201 		"dump NFSv4 server table given rfs4_table_t",
1202 		rfs4_tbl_dcmd, rfs4_tbl_help
1203 	},
1204 	{
1205 		"rfs4_idx", ":[-w]",
1206 		"dump NFSv4 server index given rfs4_index_t",
1207 		rfs4_idx_dcmd, rfs4_idx_help
1208 	},
1209 	{
1210 		"rfs4_bkt", ":",
1211 		"dump NFSv4 server index buckets given rfs4_index_t",
1212 		rfs4_bkt_dcmd
1213 	},
1214 	{
1215 		"rfs4_oo", "?",
1216 		"dump NFSv4 rfs4_openowner_t structures from bucket data\n"
1217 		"\t\t\t(Optional address of rfs4_openowner_t)",
1218 		rfs4_oo_dcmd
1219 	},
1220 	{
1221 		"rfs4_osid", "?[-v]",
1222 		"dump NFSv4 rfs4_state_t structures from bucket data\n"
1223 		"\t\t\t(Optional address of rfs4_state_t)",
1224 		rfs4_osid_dcmd
1225 	},
1226 	{
1227 		"rfs4_file", "?[-v]",
1228 		"dump NFSv4 rfs4_file_t structures from bucket data\n"
1229 		"\t\t\t(Optional address of rfs4_file_t)",
1230 		rfs4_file_dcmd
1231 	},
1232 	{
1233 		"rfs4_deleg", "?[-v]",
1234 		"dump NFSv4 rfs4_deleg_state_t structures from bucket data\n"
1235 		"\t\t\t(Optional address of rfs4_deleg_state_t)",
1236 		rfs4_deleg_dcmd
1237 	},
1238 	{
1239 		"rfs4_lo", "?",
1240 		"dump NFSv4 rfs4_lockowner_t structures from bucket data\n"
1241 		"\t\t\t(Optional address of rfs4_lockowner_t)",
1242 		rfs4_lo_dcmd
1243 	},
1244 	{
1245 		"rfs4_lsid", "?[-v]",
1246 		"dump NFSv4 rfs4_lo_state_t structures from bucket data\n"
1247 		"\t\t\t(Optional address of rfs4_lo_state_t)",
1248 		rfs4_lsid_dcmd
1249 	},
1250 	{
1251 		"rfs4_client", "?[-c <clientid>]",
1252 		"dump NFSv4 rfs4_client_t structures from bucket data\n"
1253 		"\t\t\t(Optional address of rfs4_client_t)",
1254 		rfs4_client_dcmd, rfs4_client_help
1255 	},
1256 	/* NFS server */
1257 	{
1258 		"nfs_expvis", ":",
1259 		"dump exp_visible_t structure",
1260 		nfs_expvis_dcmd
1261 	},
1262 	{
1263 		"nfs_expinfo", ":",
1264 		"dump struct exportinfo",
1265 		nfs_expinfo_dcmd
1266 	},
1267 	{
1268 		"nfs_exptable", "?",
1269 		"dump exportinfo structures for a zone\n"
1270 		"\t\t\t(Optional address of zone_t)",
1271 		nfs_exptable_dcmd
1272 	},
1273 	{
1274 		"nfs_exptable_path", "?",
1275 		"dump exportinfo structures for a zone\n"
1276 		"\t\t\t(Optional address of zone_t)",
1277 		nfs_exptable_path_dcmd
1278 	},
1279 	{
1280 		"nfs_nstree", "?[-v]",
1281 		"dump NFS server pseudo namespace tree for a zone\n"
1282 		"\t\t\t(Optional address of zone_t)",
1283 		nfs_nstree_dcmd, nfs_nstree_help
1284 	},
1285 	{
1286 		"nfs_fid_hashdist", ":[-v]",
1287 		"show fid hash distribution of the exportinfo table",
1288 		nfs_fid_hashdist_dcmd, nfs_hashdist_help
1289 	},
1290 	{
1291 		"nfs_path_hashdist", "[-v]",
1292 		"show path hash distribution of the exportinfo table",
1293 		nfs_path_hashdist_dcmd, nfs_hashdist_help
1294 	},
1295 	/* NFSv4 idmap */
1296 	{
1297 		"nfs4_idmap", ":",
1298 		"dump nfsidmap_t",
1299 		nfs4_idmap_dcmd
1300 	},
1301 	{
1302 		"nfs4_idmap_info", "?[u2s | g2s | s2u | s2g ...]",
1303 		"dump NFSv4 idmap information\n"
1304 		"\t\t\t(Optional address of zone_t)",
1305 		nfs4_idmap_info_dcmd, nfs4_idmap_info_help
1306 	},
1307 	/* NFS client */
1308 	{
1309 		"nfs_mntinfo", "?[-v]",
1310 		"print mntinfo_t information\n"
1311 		"\t\t\t(Optional address of mntinfo_t)",
1312 		nfs_mntinfo_dcmd, nfs_mntinfo_help
1313 	},
1314 	{
1315 		"nfs_servinfo", ":[-v]",
1316 		"print servinfo_t information",
1317 		nfs_servinfo_dcmd, nfs_servinfo_help
1318 	},
1319 	/* WIP */
1320 	{
1321 		"nfs4_mntinfo", "?[-mv]",
1322 		"print mntinfo4_t information\n"
1323 		"\t\t\t(Optional address of mntinfo4_t)",
1324 		nfs4_mntinfo_dcmd, nfs4_mntinfo_help
1325 	},
1326 	{
1327 		"nfs4_servinfo", ":[-v]",
1328 		"print servinfo4_t information",
1329 		nfs4_servinfo_dcmd, nfs4_servinfo_help
1330 	},
1331 	{
1332 		"nfs4_server_info", "?[-cs]",
1333 		"print nfs4_server_t information",
1334 		nfs4_server_info_dcmd, nfs4_server_info_help
1335 	},
1336 	/* WIP */
1337 	{
1338 		"nfs4_mimsg", ":[-s]",
1339 		"print queued messages for given address of mi_msg_list",
1340 		nfs4_mimsg_dcmd, nfs4_mimsg_help
1341 	},
1342 	{
1343 		"nfs4_fname", ":",
1344 		"print path name of nfs4_fname_t specified",
1345 		nfs4_fname_dcmd
1346 	},
1347 	{
1348 		"nfs4_svnode", ":",
1349 		"print svnode_t info at specified address",
1350 		nfs4_svnode_dcmd
1351 	},
1352 
1353 
1354 /* NFSv2/3/4 clnt */
1355 	{
1356 		"nfs_vfs", "?[-v]",
1357 		"print all nfs vfs struct (-v for mntinfo)\n"
1358 		"\t\t\t(Optional address of vfs_t)",
1359 		nfs_vfs_dcmd
1360 	},
1361 
1362 
1363 /* NFSv4 clnt */
1364 	{
1365 		"nfs_rnode4", "?",
1366 		"dump NFSv4 rnodes\n"
1367 		"\t\t\t(Optional address of rnode4_t)",
1368 		nfs_rnode4_dcmd, nfs_rnode4_help
1369 	},
1370 	{
1371 		"nfs4_diag", "?[-s]",
1372 		"print queued recovery messages for NFSv4 client\n"
1373 		"\t\t\t(Optional address of mntinfo4_t)",
1374 		nfs4_diag_dcmd, nfs4_diag_help
1375 	},
1376 	{
1377 		"nfs_rnode4find", ":",
1378 		"dump NFSv4 rnodes for given vfs_t",
1379 		nfs_rnode4find_dcmd, nfs_rnode4find_help
1380 	},
1381 	{
1382 		"nfs4_foo", ":[-v]",
1383 		"dump free open owners for NFSv4 client",
1384 		nfs4_foo_dcmd
1385 	},
1386 	{
1387 		"nfs4_oob", ":[-v]",
1388 		"dump open owners for NFSv4 client",
1389 		nfs4_oob_dcmd
1390 	},
1391 	{
1392 		"nfs4_os", "?[-v]",
1393 		"dump open streams for NFSv4 Client\n"
1394 		"\t\t\t(Optional address of rnode4_t)",
1395 		nfs4_os_dcmd
1396 	},
1397 
1398 /* generic commands */
1399 	{
1400 		"nfs_stat", "?[-csb][-234][-anr] | $[count]",
1401 		"Print NFS statistics for zone\n"
1402 		"\t\t\t(Optional address of zone_t)",
1403 		nfs_stat_dcmd
1404 	},
1405 	{
1406 		"nfs_help", "[-dw]",
1407 		"Show nfs commands",
1408 		nfs_help_dcmd
1409 	},
1410 
1411 	{NULL, NULL, NULL, NULL}
1412 };
1413 
1414 static const mdb_walker_t walkers[] = {
1415 	/* svc */
1416 	{
1417 		"svc_pool", "walk SVCPOOL structs for given zone",
1418 		svc_pool_walk_init, svc_pool_walk_step
1419 	},
1420 	{
1421 		"svc_mxprt", "walk master xprts",
1422 		svc_mxprt_walk_init, svc_mxprt_walk_step
1423 	},
1424 	/* rfs4 */
1425 	{
1426 		"rfs4_db_tbl", "walk NFSv4 server rfs4_table_t structs",
1427 		rfs4_db_tbl_walk_init, rfs4_db_tbl_walk_step
1428 	},
1429 	{
1430 		"rfs4_db_idx", "walk NFSv4 server rfs4_index_t structs",
1431 		rfs4_db_idx_walk_init, rfs4_db_idx_walk_step
1432 	},
1433 	{
1434 		"rfs4_db_bkt", "walk NFSv4 server buckets for given index",
1435 		rfs4_db_bkt_walk_init, rfs4_db_bkt_walk_step,
1436 		rfs4_db_bkt_walk_fini
1437 	},
1438 	/* NFS server */
1439 	{
1440 		"nfs_expinfo", "walk exportinfo structures from the exptable",
1441 		nfs_expinfo_walk_init, hash_table_walk_step,
1442 		nfs_expinfo_walk_fini, &nfs_expinfo_arg
1443 	},
1444 	{
1445 		"nfs_expinfo_path",
1446 		"walk exportinfo structures from the exptable_path_hash",
1447 		nfs_expinfo_walk_init, hash_table_walk_step,
1448 		nfs_expinfo_walk_fini, &nfs_expinfo_path_arg
1449 	},
1450 	{
1451 		"nfs_expvis", "walk list of exp_visible structs",
1452 		nfs_expvis_walk_init, nfs_expvis_walk_step
1453 	},
1454 	{
1455 		"nfssrv_globals", "walk list of zones NFS globals",
1456 		nfssrv_globals_walk_init, nfssrv_globals_walk_step
1457 	},
1458 	/* NFSv4 idmap */
1459 	{
1460 		"nfs4_u2s", "walk uid-to-string idmap cache for given zone",
1461 		nfs4_idmap_walk_init, hash_table_walk_step,
1462 		nfs4_idmap_walk_fini,
1463 		(void *)OFFSETOF(struct nfsidmap_globals, u2s_ci)
1464 	},
1465 	{
1466 		"nfs4_s2u", "walk string-to-uid idmap cache for given zone",
1467 		nfs4_idmap_walk_init, hash_table_walk_step,
1468 		nfs4_idmap_walk_fini,
1469 		(void *)OFFSETOF(struct nfsidmap_globals, s2u_ci)
1470 	},
1471 	{
1472 		"nfs4_g2s", "walk gid-to-string idmap cache for given zone",
1473 		nfs4_idmap_walk_init, hash_table_walk_step,
1474 		nfs4_idmap_walk_fini,
1475 		(void *)OFFSETOF(struct nfsidmap_globals, g2s_ci)
1476 	},
1477 	{
1478 		"nfs4_s2g", "walk string-to-gid idmap cache for given zone",
1479 		nfs4_idmap_walk_init, hash_table_walk_step,
1480 		nfs4_idmap_walk_fini,
1481 		(void *)OFFSETOF(struct nfsidmap_globals, s2g_ci)
1482 	},
1483 	/* NFS client */
1484 	{
1485 		"nfs_rtable", "walk rnodes in rtable cache",
1486 		nfs_rtable_walk_init, hash_table_walk_step,
1487 		hash_table_walk_fini, &nfs_rtable_arg
1488 	},
1489 	{
1490 		"nfs_rtable4", "walk rnode4s in rtable4 cache",
1491 		nfs_rtable4_walk_init, hash_table_walk_step,
1492 		hash_table_walk_fini, &nfs_rtable4_arg
1493 	},
1494 	{
1495 		"nfs_vfs", "walk NFS-mounted vfs structs",
1496 		nfs_vfs_walk_init, nfs_vfs_walk_step, nfs_vfs_walk_fini
1497 	},
1498 	{
1499 		"nfs_mnt", "walk NFSv2/3-mounted vfs structs, pass mntinfo",
1500 		nfs_mnt_walk_init, nfs_mnt_walk_step, nfs_mnt_walk_fini
1501 	},
1502 	{
1503 		"nfs4_mnt", "walk NFSv4-mounted vfs structs, pass mntinfo4",
1504 		nfs4_mnt_walk_init, nfs4_mnt_walk_step, nfs4_mnt_walk_fini
1505 	},
1506 	{
1507 		"nfs_serv", "walk linkedlist of servinfo structs",
1508 		nfs_serv_walk_init, nfs_serv_walk_step
1509 	},
1510 	{
1511 		"nfs4_serv", "walk linkedlist of servinfo4 structs",
1512 		nfs4_serv_walk_init, nfs4_serv_walk_step
1513 	},
1514 	{
1515 		"nfs4_svnode", "walk svnode list at given svnode address",
1516 		nfs4_svnode_walk_init, nfs4_svnode_walk_step
1517 	},
1518 	{
1519 		"nfs4_server", "walk nfs4_server_t structs",
1520 		nfs4_server_walk_init, nfs4_server_walk_step
1521 	},
1522 	{
1523 		"nfs_async", "walk list of async requests",
1524 		nfs_async_walk_init, nfs_async_walk_step
1525 	},
1526 	{
1527 		"nfs4_async", "walk list of NFSv4 async requests",
1528 		nfs4_async_walk_init, nfs4_async_walk_step
1529 	},
1530 	{
1531 		"nfs_acache_rnode", "walk acache entries for a given rnode",
1532 		nfs_acache_rnode_walk_init, nfs_acache_rnode_walk_step
1533 	},
1534 	{
1535 		"nfs_acache", "walk entire nfs_access_cache",
1536 		nfs_acache_walk_init, hash_table_walk_step, nfs_acache_walk_fini
1537 	},
1538 	{
1539 		"nfs_acache4_rnode",
1540 		"walk acache4 entries for a given NFSv4 rnode",
1541 		nfs_acache4_rnode_walk_init, nfs_acache4_rnode_walk_step
1542 	},
1543 	{
1544 		"nfs_acache4", "walk entire nfs4_access_cache",
1545 		nfs_acache4_walk_init, hash_table_walk_step,
1546 		nfs_acache4_walk_fini
1547 	},
1548 
1549 	{NULL, NULL, NULL, NULL}
1550 };
1551 
1552 
1553 static int
1554 nfs_help_dcmd(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
1555 {
1556 	int i = 0;
1557 	uint_t opt_d = FALSE;
1558 	uint_t opt_w = FALSE;
1559 
1560 	if ((flags & DCMD_ADDRSPEC) != 0)
1561 		return (DCMD_USAGE);
1562 
1563 	if (argc == 0) {
1564 		mdb_printf("::nfs_help -w -d\n");
1565 		mdb_printf("       -w     Will show nfs specific walkers\n");
1566 		mdb_printf("       -d     Will show nfs specific dcmds\n");
1567 		return (DCMD_ERR);
1568 	}
1569 
1570 	if (mdb_getopts(argc, argv,
1571 	    'd', MDB_OPT_SETBITS, TRUE, &opt_d,
1572 	    'w', MDB_OPT_SETBITS, TRUE, &opt_w, NULL) != argc)
1573 		return (DCMD_USAGE);
1574 
1575 	if (opt_d) {
1576 		for (i = 0; dcmds[i].dc_name != NULL; i++)
1577 			mdb_printf("%-20s %s\n", dcmds[i].dc_name,
1578 			    dcmds[i].dc_descr);
1579 	}
1580 	if (opt_w) {
1581 		for (i = 0; walkers[i].walk_name != NULL; i++)
1582 			mdb_printf("%-20s %s\n", walkers[i].walk_name,
1583 			    walkers[i].walk_descr);
1584 	}
1585 	return (DCMD_OK);
1586 
1587 }
1588 
1589 static const mdb_modinfo_t modinfo = {
1590 	MDB_API_VERSION,
1591 	dcmds,
1592 	walkers
1593 };
1594 
1595 const mdb_modinfo_t *
1596 _mdb_init(void)
1597 {
1598 	return (&modinfo);
1599 }
1600