xref: /illumos-gate/usr/src/cmd/mdb/common/modules/nfs/rfs4.c (revision ddb365bfc9e868ad24ccdcb0dc91af18b10df082)
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 <nfs/nfs4.h>
17 #include <nfs/nfs4_db_impl.h>
18 #include <limits.h>
19 
20 #include "rfs4.h"
21 #include "common.h"
22 
23 /*
24  * rfs4_db dcmd implementation
25  */
26 
27 int
28 rfs4_db_dcmd(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
29 {
30 	uintptr_t	glbls;
31 	uintptr_t	zonep;
32 	rfs4_database_t	rfs4_db;
33 	nfs_globals_t	nfsglbls;
34 	struct nfs4_srv	nfs4srv;
35 
36 	if (argc > 0)
37 		return (DCMD_USAGE);
38 
39 
40 	if ((flags & DCMD_ADDRSPEC) != 0) {
41 		zonep = addr;
42 	} else {
43 		if (mdb_readsym(&zonep, sizeof (uintptr_t),
44 		    "global_zone") == -1) {
45 			mdb_warn("Failed to find global_zone");
46 			return (DCMD_ERR);
47 		}
48 	}
49 
50 	if (zoned_get_nfs_globals(zonep, &glbls) != DCMD_OK) {
51 		mdb_warn("failed to get zoned specific NFS globals");
52 		return (DCMD_ERR);
53 	}
54 
55 	if (mdb_vread(&nfsglbls, sizeof (nfs_globals_t), glbls) == -1) {
56 		mdb_warn("can't read zone globals");
57 		return (DCMD_ERR);
58 	}
59 
60 	if (mdb_vread(&nfs4srv, sizeof (struct nfs4_srv),
61 	    (uintptr_t)nfsglbls.nfs4_srv) == -1) {
62 		mdb_warn("can't read NFS4 server structure");
63 		return (DCMD_ERR);
64 	}
65 
66 	if (mdb_vread(&rfs4_db, sizeof (rfs4_database_t),
67 	    (uintptr_t)nfs4srv.nfs4_server_state) == -1) {
68 		mdb_warn("can't read NFS4 server state");
69 		return (DCMD_ERR);
70 	}
71 
72 	if (mdb_pwalk_dcmd("rfs4_db_tbl", "rfs4_tbl", 0, NULL,
73 	    (uintptr_t)rfs4_db.db_tables) == -1) {
74 		mdb_warn("failed to walk tables");
75 		return (DCMD_ERR);
76 	}
77 
78 	return (DCMD_OK);
79 }
80 
81 /*
82  * rfs4_tbl dcmd implementation
83  */
84 
85 int
86 rfs4_tbl_dcmd(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
87 {
88 	rfs4_table_t tbl;
89 	char name[14];
90 	uint_t opt_v = FALSE;
91 	uint_t opt_w = FALSE;
92 
93 	if ((flags & DCMD_ADDRSPEC) == 0) {
94 		mdb_printf("requires address of rfs4_table_t\n");
95 		return (DCMD_USAGE);
96 	}
97 
98 	if (mdb_getopts(argc, argv,
99 	    'v', MDB_OPT_SETBITS, TRUE, &opt_v,
100 	    'w', MDB_OPT_SETBITS, TRUE, &opt_w, NULL) != argc)
101 		return (DCMD_USAGE);
102 
103 	if (opt_w) {
104 		mdb_arg_t arg;
105 		mdb_arg_t *argp = NULL;
106 		int n = 0;
107 
108 		if (opt_v) {
109 			arg.a_type = MDB_TYPE_STRING;
110 			arg.a_un.a_str = "-v";
111 			argp = &arg;
112 			n = 1;
113 		}
114 
115 		/* Walk through all tables */
116 		if (mdb_pwalk_dcmd("rfs4_db_tbl", "rfs4_tbl", n, argp, addr)
117 		    == -1) {
118 			mdb_warn("failed to walk tables\n");
119 			return (DCMD_ERR);
120 		}
121 		return (DCMD_OK);
122 	}
123 
124 	if (mdb_vread(&tbl, sizeof (tbl), addr) == -1) {
125 		mdb_warn("can't read rfs4_table_t");
126 		return (DCMD_ERR);
127 	}
128 
129 	if (!opt_v && DCMD_HDRSPEC(flags)) {
130 		const size_t ptrsize = mdb_snprintf(NULL, 0, "%?p");
131 		size_t sz = ptrsize + 1 + sizeof (name) + 8 + 5 - 7;
132 		size_t i;
133 
134 		mdb_printf("%<b>");
135 		for (i = 0; i < (sz + 1) / 2; i++)
136 			mdb_printf("-");
137 		mdb_printf(" Table ");
138 		for (i = 0; i < sz - (sz + 1) / 2; i++)
139 			mdb_printf("-");
140 
141 		mdb_printf(" Bkt  ");
142 
143 		sz = ptrsize + 5 + 5 - 9;
144 
145 		for (i = 0; i < (sz + 1) / 2; i++)
146 			mdb_printf("-");
147 		mdb_printf(" Indices ");
148 		for (i = 0; i < sz - (sz + 1) / 2; i++)
149 			mdb_printf("-");
150 		mdb_printf("%</b>\n");
151 
152 		mdb_printf("%<b>%<u>%-?s %-*s%-8s Cnt %</u> %<u>Cnt %</u> "
153 		    "%<u>%-?s Cnt  Max %</u>%</b>\n", "Address", sizeof (name),
154 		    "Name", "Flags", "Pointer");
155 	}
156 
157 	if (mdb_readstr(name, sizeof (name), (uintptr_t)tbl.dbt_name) == -1) {
158 		mdb_warn("can't read dbt_name");
159 		return (DCMD_ERR);
160 	}
161 	mdb_printf("%?p %-*s%08x %04u %04u %?p %04u %04u\n", addr,
162 	    sizeof (name), name, tbl.dbt_debug, tbl.dbt_count, tbl.dbt_len,
163 	    tbl.dbt_indices, tbl.dbt_idxcnt, tbl.dbt_maxcnt);
164 
165 	if (opt_v) {
166 		mdb_inc_indent(8);
167 		mdb_printf("db              = %p\n", tbl.dbt_db);
168 		mdb_printf("t_lock          = %s\n",
169 		    common_rwlock(tbl.dbt_t_lock));
170 		mdb_printf("lock            = %s\n",
171 		    common_mutex(tbl.dbt_lock));
172 		mdb_printf("id_space        = %p\n", tbl.dbt_id_space);
173 		mdb_printf("min_cache_time  = %lu\n", tbl.dbt_min_cache_time);
174 		mdb_printf("max_cache_time  = %lu\n", tbl.dbt_max_cache_time);
175 		mdb_printf("usize           = %u\n", tbl.dbt_usize);
176 		mdb_printf("maxentries      = %u\n", tbl.dbt_maxentries);
177 		mdb_printf("len             = %u\n", tbl.dbt_len);
178 		mdb_printf("count           = %u\n", tbl.dbt_count);
179 		mdb_printf("idxcnt          = %u\n", tbl.dbt_idxcnt);
180 		mdb_printf("maxcnt          = %u\n", tbl.dbt_maxcnt);
181 		mdb_printf("ccnt            = %u\n", tbl.dbt_ccnt);
182 		mdb_printf("indices         = %p\n", tbl.dbt_indices);
183 		mdb_printf("create          = %a\n", tbl.dbt_create);
184 		mdb_printf("destroy         = %a\n", tbl.dbt_destroy);
185 		mdb_printf("expiry          = %a\n", tbl.dbt_expiry);
186 		mdb_printf("mem_cache       = %p\n", tbl.dbt_mem_cache);
187 		mdb_printf("debug           = %08x\n", tbl.dbt_debug);
188 		mdb_printf("reaper_shutdown = %s\n\n",
189 		    tbl.dbt_reaper_shutdown ? "TRUE" : "FALSE");
190 		mdb_dec_indent(8);
191 	}
192 
193 	return (DCMD_OK);
194 }
195 
196 void
197 rfs4_tbl_help(void)
198 {
199 	mdb_printf(
200 	    "-v       display more details about the table\n"
201 	    "-w       walks along all tables in the list\n"
202 	    "\n"
203 	    "The following two commands are equivalent:\n"
204 	    "  ::rfs4_tbl -w\n"
205 	    "  ::walk rfs4_db_tbl|::rfs4_tbl\n");
206 }
207 
208 /*
209  * rfs4_tbl dcmd implementation
210  */
211 
212 int
213 rfs4_idx_dcmd(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
214 {
215 	rfs4_index_t idx;
216 	char name[19];
217 	uint_t opt_w = FALSE;
218 
219 	if ((flags & DCMD_ADDRSPEC) == 0) {
220 		mdb_printf("requires address of rfs4_index_t\n");
221 		return (DCMD_USAGE);
222 	}
223 
224 	if (mdb_getopts(argc, argv,
225 	    'w', MDB_OPT_SETBITS, TRUE, &opt_w, NULL) != argc)
226 		return (DCMD_USAGE);
227 
228 	if (opt_w) {
229 		/* Walk through all tables */
230 		if (mdb_pwalk_dcmd("rfs4_db_idx", "rfs4_idx", 0, NULL, addr)
231 		    == -1) {
232 			mdb_warn("failed to walk indices");
233 			return (DCMD_ERR);
234 		}
235 		return (DCMD_OK);
236 	}
237 
238 	if (mdb_vread(&idx, sizeof (idx), addr) == -1) {
239 		mdb_warn("can't read rfs4_index_t");
240 		return (DCMD_ERR);
241 	}
242 
243 	if (DCMD_HDRSPEC(flags))
244 		mdb_printf("%<b>%<u>%-?s %-*sCreat Tndx %-?s%</u>%</b>\n",
245 		    "Address", sizeof (name), "Name", "Buckets");
246 
247 	if (mdb_readstr(name, sizeof (name), (uintptr_t)idx.dbi_keyname)
248 	    == -1) {
249 		mdb_warn("can't read dbi_keyname");
250 		return (DCMD_ERR);
251 	}
252 
253 	mdb_printf("%?p %-*s%-5s %04u %?p\n", addr, sizeof (name), name,
254 	    idx.dbi_createable ? "TRUE" : "FALSE", idx.dbi_tblidx,
255 	    idx.dbi_buckets);
256 
257 	return (DCMD_OK);
258 }
259 
260 void
261 rfs4_idx_help(void)
262 {
263 	mdb_printf(
264 	    "-w       walks along all indices in the list\n"
265 	    "\n"
266 	    "The following two commands are equivalent:\n"
267 	    "  ::rfs4_idx -w\n"
268 	    "  ::walk rfs4_db_idx|::rfs4_idx\n");
269 }
270 
271 /*
272  * rfs4_bkt dcmd implementation
273  */
274 
275 static int
276 rfs4_print_bkt_cb(uintptr_t addr, const void *data, void *cb_data)
277 {
278 	const rfs4_bucket_t *bkt = data;
279 	rfs4_link_t *lp;
280 	rfs4_link_t rl;
281 
282 	for (lp = bkt->dbk_head; lp; lp = rl.next) {
283 		rfs4_dbe_t dbe;
284 
285 		if (mdb_vread(&rl, sizeof (rl), (uintptr_t)lp) == -1) {
286 			mdb_warn("can't read rfs4_link_t");
287 			return (WALK_ERR);
288 		}
289 
290 		if (mdb_vread(&dbe, sizeof (dbe), (uintptr_t)rl.entry) == -1) {
291 			mdb_warn("can't read rfs4_dbe_t");
292 			return (WALK_ERR);
293 		}
294 
295 		mdb_inc_indent(4);
296 		mdb_printf(
297 		    "DBE {  Address=%p data->%p refcnt=%u skipsearch=%u\n"
298 		    "    invalid=%u time_rele=%Y\n}\n", rl.entry, dbe.dbe_data,
299 		    dbe.dbe_refcnt, dbe.dbe_skipsearch, dbe.dbe_invalid,
300 		    dbe.dbe_time_rele);
301 		mdb_dec_indent(4);
302 	}
303 
304 	return (WALK_NEXT);
305 }
306 
307 int
308 rfs4_bkt_dcmd(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
309 {
310 	if (argc > 0)
311 		return (DCMD_USAGE);
312 
313 	if ((flags & DCMD_ADDRSPEC) == 0) {
314 		mdb_printf("requires address of rfs4_index_t\n");
315 		return (DCMD_USAGE);
316 	}
317 
318 	if (mdb_pwalk("rfs4_db_bkt", rfs4_print_bkt_cb, NULL, addr) == -1) {
319 		mdb_warn("bucket walking failed");
320 		return (DCMD_ERR);
321 	}
322 
323 	return (DCMD_OK);
324 }
325 
326 /*
327  * rfs4_oo dcmd implementation
328  */
329 
330 static int
331 rfs4_print_oo(uintptr_t addr, uintptr_t client)
332 {
333 	rfs4_openowner_t oo;
334 	uint8_t *owner_val;
335 	uint_t i;
336 
337 	if (mdb_vread(&oo, sizeof (oo), addr) == -1) {
338 		mdb_warn("can't read rfs4_openowner_t");
339 		return (DCMD_ERR);
340 	}
341 
342 	if (client && (client != (uintptr_t)oo.ro_client))
343 		return (DCMD_OK);
344 
345 	owner_val = mdb_alloc(oo.ro_owner.owner_len, UM_SLEEP | UM_GC);
346 	if (mdb_vread(owner_val, oo.ro_owner.owner_len,
347 	    (uintptr_t)oo.ro_owner.owner_val) == -1) {
348 		mdb_warn("can't read owner_val");
349 		return (DCMD_ERR);
350 	}
351 
352 	mdb_printf("%?p %?p %?p %10u %16llx ", addr, oo.ro_dbe, oo.ro_client,
353 	    oo.ro_open_seqid, oo.ro_owner.clientid);
354 	for (i = 0; i < oo.ro_owner.owner_len; i++)
355 		mdb_printf("%02x", owner_val[i]);
356 	mdb_printf("\n");
357 
358 	return (DCMD_OK);
359 }
360 
361 static int
362 rfs4_print_oo_cb(uintptr_t addr, const void *data, void *cb_data)
363 {
364 	if (mdb_vread(&addr, sizeof (addr), addr + OFFSETOF(rfs4_dbe_t,
365 	    dbe_data)) == -1) {
366 		mdb_warn("failed to read dbe_data");
367 		return (WALK_ERR);
368 	}
369 
370 	return (rfs4_print_oo(addr, (uintptr_t)cb_data) == DCMD_OK
371 	    ? WALK_NEXT : WALK_ERR);
372 }
373 
374 static void
375 print_oo_hdr(void)
376 {
377 	mdb_printf("%<b>%<u>%-?s %-?s %-?s %10s %16s %-16s%</u>%</b>\n",
378 	    "Address", "Dbe", "Client", "OpenSeqID", "clientid",
379 	    "owner");
380 }
381 
382 int
383 rfs4_oo_dcmd(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
384 {
385 	if (argc > 0)
386 		return (DCMD_USAGE);
387 
388 	if (DCMD_HDRSPEC(flags))
389 		print_oo_hdr();
390 
391 	if (flags & DCMD_ADDRSPEC)
392 		return (rfs4_print_oo(addr, 0));
393 
394 	if (mdb_walk("OpenOwner_entry_cache", rfs4_print_oo_cb, NULL) == -1) {
395 		mdb_warn("walking of %s failed", "OpenOwner_entry_cache");
396 		return (DCMD_ERR);
397 	}
398 
399 	return (DCMD_OK);
400 }
401 
402 /*
403  * rfs4_osid dcmd implementation
404  */
405 
406 static void
407 print_stateid(const stateid_t *st)
408 {
409 	const char *s;
410 
411 	mdb_printf("chgseq=%u boottime=%x pid=%i\n", st->bits.chgseq,
412 	    st->bits.boottime, st->bits.pid);
413 
414 	switch ((stateid_type_t)st->bits.type) {
415 	case OPENID:
416 		s = "OpenID";
417 		break;
418 	case LOCKID:
419 		s = "LockID";
420 		break;
421 	case DELEGID:
422 		s = "DelegID";
423 		break;
424 	default:
425 		s = "<undefined>";
426 		break;
427 	}
428 	mdb_printf("type=%s ident=%x\n", s, st->bits.ident);
429 }
430 
431 static int
432 rfs4_print_osid(uintptr_t addr, uint_t opt_v)
433 {
434 	rfs4_state_t osid;
435 	size_t i;
436 	const char *s;
437 
438 	if (mdb_vread(&osid, sizeof (osid), addr) == -1) {
439 		mdb_warn("can't read rfs4_state_t");
440 		return (DCMD_ERR);
441 	}
442 
443 	mdb_printf("%?p %?p %?p %?p ", addr, osid.rs_dbe, osid.rs_owner,
444 	    osid.rs_finfo);
445 	for (i = 0; i < sizeof (stateid4); i++)
446 		mdb_printf("%02x", ((uint8_t *)&osid.rs_stateid)[i]);
447 	mdb_printf("\n");
448 
449 	if (!opt_v)
450 		return (DCMD_OK);
451 
452 	mdb_inc_indent(8);
453 
454 	print_stateid(&osid.rs_stateid);
455 
456 	switch (osid.rs_share_access) {
457 	case 0:
458 		s = "none";
459 		break;
460 	case OPEN4_SHARE_ACCESS_READ:
461 		s = "read";
462 		break;
463 	case OPEN4_SHARE_ACCESS_WRITE:
464 		s = "write";
465 		break;
466 	case OPEN4_SHARE_ACCESS_BOTH:
467 		s = "read-write";
468 		break;
469 	default:
470 		s = "<invalid>";
471 		break;
472 	}
473 	mdb_printf("share_access: %s", s);
474 
475 	switch (osid.rs_share_deny) {
476 	case OPEN4_SHARE_DENY_NONE:
477 		s = "none";
478 		break;
479 	case OPEN4_SHARE_DENY_READ:
480 		s = "read";
481 		break;
482 	case OPEN4_SHARE_DENY_WRITE:
483 		s = "write";
484 		break;
485 	case OPEN4_SHARE_DENY_BOTH:
486 		s = "read-write";
487 		break;
488 	default:
489 		s = "<invalid>";
490 		break;
491 	}
492 	mdb_printf(" share_deny: %s file is: %s\n", s,
493 	    osid.rs_closed ? "CLOSED" : "OPEN");
494 
495 	mdb_dec_indent(8);
496 
497 	return (DCMD_OK);
498 }
499 
500 static int
501 rfs4_print_osid_cb(uintptr_t addr, const void *data, void *cb_data)
502 {
503 	/* addr = ((rfs4_dbe_t *)addr)->dbe_data */
504 	if (mdb_vread(&addr, sizeof (addr), addr + OFFSETOF(rfs4_dbe_t,
505 	    dbe_data)) == -1) {
506 		mdb_warn("failed to read dbe_data");
507 		return (WALK_ERR);
508 	}
509 
510 	return (rfs4_print_osid(addr, *(uint_t *)cb_data) == DCMD_OK
511 	    ? WALK_NEXT : WALK_ERR);
512 }
513 
514 int
515 rfs4_osid_dcmd(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
516 {
517 	uint_t opt_v = FALSE;
518 
519 	if (mdb_getopts(argc, argv,
520 	    'v', MDB_OPT_SETBITS, TRUE, &opt_v, NULL) != argc)
521 		return (DCMD_USAGE);
522 
523 	if (DCMD_HDRSPEC(flags))
524 		mdb_printf("%<b>%<u>%-?s %-?s %-?s %-?s %-*s%</u>%</b>\n",
525 		    "Address", "Dbe", "Owner", "finfo", 2 * sizeof (stateid4),
526 		    "StateID");
527 
528 	if (flags & DCMD_ADDRSPEC)
529 		return (rfs4_print_osid(addr, opt_v));
530 
531 	if (mdb_walk("OpenStateID_entry_cache", rfs4_print_osid_cb, &opt_v)
532 	    == -1) {
533 		mdb_warn("walking of %s failed", "OpenStateID_entry_cache");
534 		return (DCMD_ERR);
535 	}
536 
537 	return (DCMD_OK);
538 }
539 
540 /*
541  * rfs4_file dcmd implementation
542  */
543 
544 static void
545 print_time(time_t t)
546 {
547 	if (t == 0)
548 		mdb_printf("0");
549 	else
550 		mdb_printf("%Y", t);
551 }
552 
553 static int
554 rfs4_print_file(uintptr_t addr, uint_t opt_v)
555 {
556 	rfs4_file_t f;
557 	uint8_t *nfs_fh4_val;
558 	uint_t i;
559 	uintptr_t vp;
560 	char *s;
561 	const rfs4_dinfo_t *di;
562 
563 	if (mdb_vread(&f, sizeof (f), addr) == -1) {
564 		mdb_warn("can't read rfs4_file_t");
565 		return (DCMD_ERR);
566 	}
567 
568 	nfs_fh4_val = mdb_alloc(f.rf_filehandle.nfs_fh4_len, UM_SLEEP | UM_GC);
569 	if (mdb_vread(nfs_fh4_val, f.rf_filehandle.nfs_fh4_len,
570 	    (uintptr_t)f.rf_filehandle.nfs_fh4_val) == -1) {
571 		mdb_warn("can't read nfs_fh4_val");
572 		return (DCMD_ERR);
573 	}
574 
575 	mdb_printf("%?p %?p %?p ", addr, f.rf_dbe, f.rf_vp);
576 	for (i = 0; i < f.rf_filehandle.nfs_fh4_len; i++)
577 		mdb_printf("%02x", nfs_fh4_val[i]);
578 	mdb_printf("\n");
579 
580 	if (!opt_v)
581 		return (DCMD_OK);
582 
583 	/* vp = f.rf_vp->v_path */
584 	if (mdb_vread(&vp, sizeof (vp), (uintptr_t)f.rf_vp
585 	    + OFFSETOF(vnode_t, v_path)) == -1) {
586 		mdb_warn("can't read vnode_t");
587 		return (DCMD_ERR);
588 	}
589 
590 	s = mdb_alloc(PATH_MAX, UM_SLEEP | UM_GC);
591 	if (mdb_readstr(s, PATH_MAX, vp) == -1) {
592 		mdb_warn("can't read v_path");
593 		return (DCMD_ERR);
594 	}
595 
596 	mdb_inc_indent(8);
597 
598 	mdb_printf("path=%s\n", s);
599 
600 	di = &f.rf_dinfo;
601 	switch (di->rd_dtype) {
602 	case OPEN_DELEGATE_NONE:
603 		s = "None";
604 		break;
605 	case OPEN_DELEGATE_READ:
606 		s = "Read";
607 		break;
608 	case OPEN_DELEGATE_WRITE:
609 		s = "Write";
610 		break;
611 	default:
612 		s = "?????";
613 		break;
614 	}
615 	mdb_printf("dtype=%-5s rdgrants=%u wrgrants=%u recall_cnt=%i "
616 	    "ever_recalled=%s\n", s, di->rd_rdgrants, di->rd_wrgrants,
617 	    di->rd_recall_count, (di->rd_ever_recalled == TRUE) ? "True"
618 	    : "False");
619 
620 	mdb_printf("Time: ");
621 	mdb_inc_indent(6);
622 
623 	mdb_printf("returned=");
624 	print_time(di->rd_time_returned);
625 	mdb_printf(" recalled=");
626 	print_time(di->rd_time_recalled);
627 	mdb_printf("\nlastgrant=");
628 	print_time(di->rd_time_lastgrant);
629 	mdb_printf(" lastwrite=");
630 	print_time(di->rd_time_lastwrite);
631 	mdb_printf("\nrm_delayed=");
632 	print_time(di->rd_time_rm_delayed);
633 	mdb_printf("\n");
634 
635 	mdb_dec_indent(14);
636 
637 	return (DCMD_OK);
638 }
639 
640 static int
641 rfs4_print_file_cb(uintptr_t addr, const void *data, void *cb_data)
642 {
643 	/* addr = ((rfs4_dbe_t *)addr)->dbe_data */
644 	if (mdb_vread(&addr, sizeof (addr), addr + OFFSETOF(rfs4_dbe_t,
645 	    dbe_data)) == -1) {
646 		mdb_warn("failed to read dbe_data");
647 		return (WALK_ERR);
648 	}
649 
650 	return (rfs4_print_file(addr, *(uint_t *)cb_data) == DCMD_OK
651 	    ? WALK_NEXT : WALK_ERR);
652 }
653 
654 int
655 rfs4_file_dcmd(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
656 {
657 	uint_t opt_v = FALSE;
658 
659 	if (mdb_getopts(argc, argv,
660 	    'v', MDB_OPT_SETBITS, TRUE, &opt_v, NULL) != argc)
661 		return (DCMD_USAGE);
662 
663 	if (DCMD_HDRSPEC(flags))
664 		mdb_printf("%<b>%<u>%-?s %-?s %-?s %-32s%</u>%</b>\n",
665 		    "Address", "Dbe", "Vnode", "Filehandle");
666 
667 	if (flags & DCMD_ADDRSPEC)
668 		return (rfs4_print_file(addr, opt_v));
669 
670 	if (mdb_walk("File_entry_cache", rfs4_print_file_cb, &opt_v) == -1) {
671 		mdb_warn("walking of %s failed", "File_entry_cache");
672 		return (DCMD_ERR);
673 	}
674 
675 	return (DCMD_OK);
676 }
677 
678 /*
679  * rfs4_deleg dcmd implementation
680  */
681 
682 static int
683 rfs4_print_deleg(uintptr_t addr, uint_t opt_v, uintptr_t client)
684 {
685 	rfs4_deleg_state_t ds;
686 	size_t i;
687 	uintptr_t pa;
688 	char *s;
689 
690 	if (mdb_vread(&ds, sizeof (ds), addr) == -1) {
691 		mdb_warn("can't read rfs4_deleg_state_t");
692 		return (DCMD_ERR);
693 	}
694 
695 	if (client && (client != (uintptr_t)ds.rds_client))
696 		return (DCMD_OK);
697 
698 	mdb_printf("%?p %?p ", addr, ds.rds_dbe);
699 	for (i = 0; i < sizeof (stateid4); i++)
700 		mdb_printf("%02x", ((uint8_t *)&ds.rds_delegid)[i]);
701 	mdb_printf(" %?p %?p\n", ds.rds_finfo, ds.rds_client);
702 
703 	if (!opt_v)
704 		return (DCMD_OK);
705 
706 	/* pa = ds.rds_finfo->rf_vp */
707 	if (mdb_vread(&pa, sizeof (pa), (uintptr_t)ds.rds_finfo
708 	    + OFFSETOF(rfs4_file_t, rf_vp)) == -1) {
709 		mdb_warn("can't read rf_vp");
710 		return (DCMD_ERR);
711 	}
712 	/* pa = ((vnode_t *)pa)->v_path */
713 	if (mdb_vread(&pa, sizeof (pa), pa + OFFSETOF(vnode_t, v_path)) == -1) {
714 		mdb_warn("can't read rf_vp");
715 		return (DCMD_ERR);
716 	}
717 
718 	s = mdb_alloc(PATH_MAX, UM_SLEEP | UM_GC);
719 	if (mdb_readstr(s, PATH_MAX, pa) == -1) {
720 		mdb_warn("can't read v_path");
721 		return (DCMD_ERR);
722 	}
723 
724 	mdb_inc_indent(8);
725 	mdb_printf("Time: ");
726 	mdb_inc_indent(6);
727 
728 	mdb_printf("granted=");
729 	print_time(ds.rds_time_granted);
730 	mdb_printf(" recalled=");
731 	print_time(ds.rds_time_recalled);
732 	mdb_printf(" revoked=");
733 	print_time(ds.rds_time_revoked);
734 
735 	mdb_dec_indent(6);
736 	mdb_printf("\npath=%s\n", s);
737 	mdb_dec_indent(8);
738 
739 	return (DCMD_OK);
740 }
741 
742 static int
743 rfs4_print_deleg_cb(uintptr_t addr, const void *data, void *cb_data)
744 {
745 	/* addr = ((rfs4_dbe_t *)addr)->dbe_data */
746 	if (mdb_vread(&addr, sizeof (addr), addr + OFFSETOF(rfs4_dbe_t,
747 	    dbe_data)) == -1) {
748 		mdb_warn("failed to read dbe_data");
749 		return (WALK_ERR);
750 	}
751 
752 	return (rfs4_print_deleg(addr, *(uint_t *)cb_data,
753 	    0) == DCMD_OK ? WALK_NEXT : WALK_ERR);
754 }
755 
756 static void
757 print_deleg_hdr(void)
758 {
759 	mdb_printf("%<b>%<u>%-?s %-?s %-*s %-?s %-?s%</u>%</b>\n",
760 	    "Address", "Dbe", 2 * sizeof (stateid4), "StateID",
761 	    "File Info", "Client");
762 }
763 
764 int
765 rfs4_deleg_dcmd(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
766 {
767 	uint_t opt_v = FALSE;
768 
769 	if (mdb_getopts(argc, argv,
770 	    'v', MDB_OPT_SETBITS, TRUE, &opt_v, NULL) != argc)
771 		return (DCMD_USAGE);
772 
773 	if (DCMD_HDRSPEC(flags))
774 		print_deleg_hdr();
775 
776 	if (flags & DCMD_ADDRSPEC)
777 		return (rfs4_print_deleg(addr, opt_v, 0));
778 
779 	if (mdb_walk("DelegStateID_entry_cache", rfs4_print_deleg_cb, &opt_v)
780 	    == -1) {
781 		mdb_warn("walking of %s failed", "DelegStateID_entry_cache");
782 		return (DCMD_ERR);
783 	}
784 
785 	return (DCMD_OK);
786 }
787 
788 /*
789  * rfs4_lo dcmd implementation
790  */
791 
792 static int
793 rfs4_print_lo(uintptr_t addr, uintptr_t client)
794 {
795 	rfs4_lockowner_t lo;
796 	uint8_t *owner_val;
797 	uint_t i;
798 
799 	if (mdb_vread(&lo, sizeof (lo), addr) == -1) {
800 		mdb_warn("can't read rfs4_lockowner_t");
801 		return (DCMD_ERR);
802 	}
803 
804 	if (client && (client != (uintptr_t)lo.rl_client))
805 		return (DCMD_OK);
806 
807 	owner_val = mdb_alloc(lo.rl_owner.owner_len, UM_SLEEP | UM_GC);
808 	if (mdb_vread(owner_val, lo.rl_owner.owner_len,
809 	    (uintptr_t)lo.rl_owner.owner_val) == -1) {
810 		mdb_warn("can't read owner_val");
811 		return (DCMD_ERR);
812 	}
813 
814 	mdb_printf("%?p %?p %?p %10i %16llx ", addr, lo.rl_dbe, lo.rl_client,
815 	    lo.rl_pid, lo.rl_owner.clientid);
816 	for (i = 0; i < lo.rl_owner.owner_len; i++)
817 		mdb_printf("%02x", owner_val[i]);
818 	mdb_printf("\n");
819 
820 	return (DCMD_OK);
821 }
822 
823 static int
824 rfs4_print_lo_cb(uintptr_t addr, const void *data, void *cb_data)
825 {
826 	if (mdb_vread(&addr, sizeof (addr), addr + OFFSETOF(rfs4_dbe_t,
827 	    dbe_data)) == -1) {
828 		mdb_warn("failed to read dbe_data");
829 		return (WALK_ERR);
830 	}
831 
832 	return (rfs4_print_lo(addr, (uintptr_t)cb_data) == DCMD_OK
833 	    ? WALK_NEXT : WALK_ERR);
834 }
835 
836 static void
837 print_lo_hdr(void)
838 {
839 	mdb_printf("%<b>%<u>%-?s %-?s %-?s %10s %16s %-16s%</u>%</b>\n",
840 	    "Address", "Dbe", "Client", "Pid", "clientid", "owner");
841 }
842 
843 int
844 rfs4_lo_dcmd(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
845 {
846 	if (argc > 0)
847 		return (DCMD_USAGE);
848 
849 	if (DCMD_HDRSPEC(flags))
850 		print_lo_hdr();
851 
852 	if (flags & DCMD_ADDRSPEC)
853 		return (rfs4_print_lo(addr, 0));
854 
855 	if (mdb_walk("Lockowner_entry_cache", rfs4_print_lo_cb, NULL) == -1) {
856 		mdb_warn("walking of %s failed", "Lockowner_entry_cache");
857 		return (DCMD_ERR);
858 	}
859 
860 	return (DCMD_OK);
861 }
862 
863 /*
864  * rfs4_lsid dcmd implementation
865  */
866 
867 static int
868 rfs4_print_lsid(uintptr_t addr, uint_t opt_v)
869 {
870 	rfs4_lo_state_t lsid;
871 	size_t i;
872 
873 	if (mdb_vread(&lsid, sizeof (lsid), addr) == -1) {
874 		mdb_warn("can't read rfs4_lo_state_t");
875 		return (DCMD_ERR);
876 	}
877 
878 	mdb_printf("%?p %?p %?p %10u ", addr, lsid.rls_dbe, lsid.rls_locker,
879 	    lsid.rls_seqid);
880 	for (i = 0; i < sizeof (stateid4); i++)
881 		mdb_printf("%02x", ((uint8_t *)&lsid.rls_lockid)[i]);
882 	mdb_printf("\n");
883 
884 	if (!opt_v)
885 		return (DCMD_OK);
886 
887 	mdb_inc_indent(8);
888 	print_stateid(&lsid.rls_lockid);
889 	mdb_dec_indent(8);
890 
891 	return (DCMD_OK);
892 }
893 
894 static int
895 rfs4_print_lsid_cb(uintptr_t addr, const void *data, void *cb_data)
896 {
897 	if (mdb_vread(&addr, sizeof (addr), addr + OFFSETOF(rfs4_dbe_t,
898 	    dbe_data)) == -1) {
899 		mdb_warn("failed to read dbe_data");
900 		return (WALK_ERR);
901 	}
902 
903 	return (rfs4_print_lsid(addr, *(uint_t *)cb_data) == DCMD_OK
904 	    ? WALK_NEXT : WALK_ERR);
905 }
906 
907 int
908 rfs4_lsid_dcmd(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
909 {
910 	uint_t opt_v = FALSE;
911 
912 	if (mdb_getopts(argc, argv,
913 	    'v', MDB_OPT_SETBITS, TRUE, &opt_v, NULL) != argc)
914 		return (DCMD_USAGE);
915 
916 	if (DCMD_HDRSPEC(flags))
917 		mdb_printf("%<b>%<u>%-?s %-?s %-?s %10s %-*s%</u>%</b>\n",
918 		    "Address", "Dbe", "Locker", "SeqID", 2 * sizeof (stateid4),
919 		    "Lockid");
920 
921 	if (flags & DCMD_ADDRSPEC)
922 		return (rfs4_print_lsid(addr, opt_v));
923 
924 	if (mdb_walk("LockStateID_entry_cache", rfs4_print_lsid_cb, &opt_v)
925 	    == -1) {
926 		mdb_warn("walking of %s failed", "LockStateID_entry_cache");
927 		return (DCMD_ERR);
928 	}
929 
930 	return (DCMD_OK);
931 }
932 
933 /*
934  * rfs4_client dcmd implementation
935  */
936 
937 static int
938 rfs4_print_client(uintptr_t addr)
939 {
940 	rfs4_client_t cl;
941 
942 	if (mdb_vread(&cl, sizeof (cl), addr) == -1) {
943 		mdb_warn("can't read rfs4_client_t");
944 		return (DCMD_ERR);
945 	}
946 
947 	mdb_printf("%?p %?p %-16llx %-16llx %-5s %-5s %?p %-20Y\n", addr,
948 	    cl.rc_dbe, cl.rc_clientid, cl.rc_confirm_verf,
949 	    cl.rc_need_confirm ? "True" : "False",
950 	    cl.rc_unlksys_completed ? "True" : "False", cl.rc_cp_confirmed,
951 	    cl.rc_last_access);
952 
953 	return (DCMD_OK);
954 }
955 
956 static int
957 rfs4_client_deleg_cb(uintptr_t addr, const void *data, void *cb_data)
958 {
959 	/* addr = ((rfs4_dbe_t *)addr)->dbe_data */
960 	if (mdb_vread(&addr, sizeof (addr), addr + OFFSETOF(rfs4_dbe_t,
961 	    dbe_data)) == -1) {
962 		mdb_warn("failed to read dbe_data");
963 		return (WALK_ERR);
964 	}
965 
966 	return (rfs4_print_deleg(addr, FALSE, (uintptr_t)cb_data) == DCMD_OK
967 	    ? WALK_NEXT : WALK_ERR);
968 }
969 
970 static int
971 rfs4_print_client_cb(uintptr_t addr, const void *data, void *cb_data)
972 {
973 	clientid4 clid;
974 
975 	/* addr = ((rfs4_dbe_t *)addr)->dbe_data */
976 	if (mdb_vread(&addr, sizeof (addr), addr + OFFSETOF(rfs4_dbe_t,
977 	    dbe_data)) == -1) {
978 		mdb_warn("failed to read dbe_data");
979 		return (WALK_ERR);
980 	}
981 
982 	/* if no clid specified then print all clients */
983 	if (!cb_data)
984 		return (rfs4_print_client(addr) == DCMD_OK ? WALK_NEXT
985 		    : WALK_ERR);
986 
987 	/* clid = ((rfs4_client_t *)addr)->rc_clientid */
988 	if (mdb_vread(&clid, sizeof (clid), addr + OFFSETOF(rfs4_client_t,
989 	    rc_clientid)) == -1) {
990 		mdb_warn("can't read rc_clientid");
991 		return (WALK_ERR);
992 	}
993 
994 	/* clid does not match, do not print the client */
995 	if (clid != *(clientid4 *)cb_data)
996 		return (WALK_NEXT);
997 
998 	if (rfs4_print_client(addr) != DCMD_OK)
999 		return (WALK_ERR);
1000 
1001 	mdb_printf("\n");
1002 	print_oo_hdr();
1003 	if (mdb_walk("OpenOwner_entry_cache", rfs4_print_oo_cb, (void *)addr)
1004 	    == -1) {
1005 		mdb_warn("walking of %s failed", "OpenOwner_entry_cache");
1006 		return (WALK_ERR);
1007 	}
1008 
1009 	mdb_printf("\n");
1010 	print_lo_hdr();
1011 	if (mdb_walk("Lockowner_entry_cache", rfs4_print_lo_cb, (void *)addr)
1012 	    == -1) {
1013 		mdb_warn("walking of %s failed", "Lockowner_entry_cache");
1014 		return (WALK_ERR);
1015 	}
1016 
1017 	mdb_printf("\n");
1018 	print_deleg_hdr();
1019 	if (mdb_walk("DelegStateID_entry_cache", rfs4_client_deleg_cb,
1020 	    (void *)addr) == -1) {
1021 		mdb_warn("walking of %s failed", "DelegStateID_entry_cache");
1022 		return (WALK_ERR);
1023 	}
1024 
1025 	return (WALK_DONE);
1026 }
1027 
1028 int
1029 rfs4_client_dcmd(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
1030 {
1031 	clientid4 clid;
1032 
1033 	if (mdb_getopts(argc, argv,
1034 	    'c', MDB_OPT_UINT64, &clid, NULL) != argc)
1035 		return (DCMD_USAGE);
1036 
1037 	if (DCMD_HDRSPEC(flags))
1038 		mdb_printf("%<b>%<u>%-?s %-?s %-16s %-16s NCnfm unlnk %-?s "
1039 		    "%-20s%</u>%</b>\n", "Address", "dbe", "clientid",
1040 		    "confirm_verf", "cp_confirmed", "Last Access");
1041 
1042 	if ((argc == 0) && (flags & DCMD_ADDRSPEC))
1043 		return (rfs4_print_client(addr));
1044 
1045 	if (mdb_walk("Client_entry_cache", rfs4_print_client_cb, (argc > 0)
1046 	    ? &clid : NULL) == -1) {
1047 		mdb_warn("walking of %s failed", "Client_entry_cache");
1048 		return (DCMD_ERR);
1049 	}
1050 
1051 	return (DCMD_OK);
1052 }
1053 
1054 void
1055 rfs4_client_help(void)
1056 {
1057 	mdb_printf(
1058 	    "-c       print all NFSv4 server state entries referencing\n"
1059 	    "         the <clientid> client. In this case the supplied\n"
1060 	    "         address is ignored\n");
1061 }
1062 
1063 /*
1064  * rfs4_db_tbl walker implementation
1065  */
1066 
1067 int
1068 rfs4_db_tbl_walk_init(mdb_walk_state_t *wsp)
1069 {
1070 	if (wsp->walk_addr == 0) {
1071 		mdb_warn("db tbl global walk not supported");
1072 		return (WALK_ERR);
1073 	}
1074 
1075 	return (WALK_NEXT);
1076 }
1077 
1078 int
1079 rfs4_db_tbl_walk_step(mdb_walk_state_t *wsp)
1080 {
1081 	rfs4_table_t tbl;
1082 	uintptr_t addr = wsp->walk_addr;
1083 
1084 	if (addr == 0)
1085 		return (WALK_DONE);
1086 
1087 	if (mdb_vread(&tbl, sizeof (tbl), addr) == -1) {
1088 		mdb_warn("can't read rfs4_table_t");
1089 		return (WALK_ERR);
1090 	}
1091 
1092 	wsp->walk_addr = (uintptr_t)tbl.dbt_tnext;
1093 	return (wsp->walk_callback(addr, &tbl, wsp->walk_cbdata));
1094 }
1095 
1096 /*
1097  * rfs4_db_idx walker implementation
1098  */
1099 
1100 int
1101 rfs4_db_idx_walk_init(mdb_walk_state_t *wsp)
1102 {
1103 	if (wsp->walk_addr == 0) {
1104 		mdb_warn("db idx global walk not supported");
1105 		return (WALK_ERR);
1106 	}
1107 
1108 	return (WALK_NEXT);
1109 }
1110 
1111 int
1112 rfs4_db_idx_walk_step(mdb_walk_state_t *wsp)
1113 {
1114 	rfs4_index_t idx;
1115 	uintptr_t addr = wsp->walk_addr;
1116 
1117 	if (addr == 0)
1118 		return (WALK_DONE);
1119 
1120 	if (mdb_vread(&idx, sizeof (idx), addr) == -1) {
1121 		mdb_warn("can't read rfs4_index_t");
1122 		return (WALK_ERR);
1123 	}
1124 
1125 	wsp->walk_addr = (uintptr_t)idx.dbi_inext;
1126 	return (wsp->walk_callback(addr, &idx, wsp->walk_cbdata));
1127 }
1128 /*
1129  * rfs4_db_bkt walker implementation
1130  */
1131 
1132 int
1133 rfs4_db_bkt_walk_init(mdb_walk_state_t *wsp)
1134 {
1135 	rfs4_index_t idx;
1136 	uint32_t dbt_len;
1137 
1138 	if (wsp->walk_addr == 0) {
1139 		mdb_warn("db bkt global walk not supported");
1140 		return (WALK_ERR);
1141 	}
1142 
1143 	if (mdb_vread(&idx, sizeof (idx), wsp->walk_addr) == -1) {
1144 		mdb_warn("can't read rfs4_index_t");
1145 		return (WALK_ERR);
1146 	}
1147 
1148 	/* dbt_len = idx.dbi_table->dbt_len */
1149 	if (mdb_vread(&dbt_len, sizeof (dbt_len), (uintptr_t)idx.dbi_table
1150 	    + OFFSETOF(rfs4_table_t, dbt_len)) == -1) {
1151 		mdb_warn("can't read dbt_len");
1152 		return (WALK_ERR);
1153 	}
1154 
1155 	wsp->walk_data = mdb_alloc(sizeof (dbt_len), UM_SLEEP);
1156 	*(uint32_t *)wsp->walk_data = dbt_len;
1157 	wsp->walk_addr = (uintptr_t)idx.dbi_buckets;
1158 
1159 	return (WALK_NEXT);
1160 }
1161 
1162 int
1163 rfs4_db_bkt_walk_step(mdb_walk_state_t *wsp)
1164 {
1165 	rfs4_bucket_t bkt;
1166 	uintptr_t addr = wsp->walk_addr;
1167 
1168 	if (*(uint32_t *)wsp->walk_data == 0)
1169 		return (WALK_DONE);
1170 
1171 	if (mdb_vread(&bkt, sizeof (bkt), addr) == -1) {
1172 		mdb_warn("can't read rfs4_bucket_t");
1173 		return (WALK_ERR);
1174 	}
1175 
1176 	(*(uint32_t *)wsp->walk_data)--;
1177 	wsp->walk_addr = (uintptr_t)((rfs4_bucket_t *)addr + 1);
1178 
1179 	return (wsp->walk_callback(addr, &bkt, wsp->walk_cbdata));
1180 }
1181 
1182 void
1183 rfs4_db_bkt_walk_fini(mdb_walk_state_t *wsp)
1184 {
1185 	mdb_free(wsp->walk_data, sizeof (uint32_t));
1186 }
1187