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
rfs4_db_dcmd(uintptr_t addr,uint_t flags,int argc,const mdb_arg_t * argv)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
rfs4_tbl_dcmd(uintptr_t addr,uint_t flags,int argc,const mdb_arg_t * argv)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
rfs4_tbl_help(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
rfs4_idx_dcmd(uintptr_t addr,uint_t flags,int argc,const mdb_arg_t * argv)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
rfs4_idx_help(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
rfs4_print_bkt_cb(uintptr_t addr,const void * data,void * cb_data)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
rfs4_bkt_dcmd(uintptr_t addr,uint_t flags,int argc,const mdb_arg_t * argv)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
rfs4_print_oo(uintptr_t addr,uintptr_t client)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
rfs4_print_oo_cb(uintptr_t addr,const void * data,void * cb_data)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
print_oo_hdr(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
rfs4_oo_dcmd(uintptr_t addr,uint_t flags,int argc,const mdb_arg_t * argv)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
print_stateid(const stateid_t * st)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
rfs4_print_osid(uintptr_t addr,uint_t opt_v)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
rfs4_print_osid_cb(uintptr_t addr,const void * data,void * cb_data)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
rfs4_osid_dcmd(uintptr_t addr,uint_t flags,int argc,const mdb_arg_t * argv)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
print_time(time_t t)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
rfs4_print_file(uintptr_t addr,uint_t opt_v)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
rfs4_print_file_cb(uintptr_t addr,const void * data,void * cb_data)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
rfs4_file_dcmd(uintptr_t addr,uint_t flags,int argc,const mdb_arg_t * argv)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
rfs4_print_deleg(uintptr_t addr,uint_t opt_v,uintptr_t client)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
rfs4_print_deleg_cb(uintptr_t addr,const void * data,void * cb_data)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
print_deleg_hdr(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
rfs4_deleg_dcmd(uintptr_t addr,uint_t flags,int argc,const mdb_arg_t * argv)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
rfs4_print_lo(uintptr_t addr,uintptr_t client)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
rfs4_print_lo_cb(uintptr_t addr,const void * data,void * cb_data)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
print_lo_hdr(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
rfs4_lo_dcmd(uintptr_t addr,uint_t flags,int argc,const mdb_arg_t * argv)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
rfs4_print_lsid(uintptr_t addr,uint_t opt_v)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
rfs4_print_lsid_cb(uintptr_t addr,const void * data,void * cb_data)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
rfs4_lsid_dcmd(uintptr_t addr,uint_t flags,int argc,const mdb_arg_t * argv)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
rfs4_print_client(uintptr_t addr)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
rfs4_client_deleg_cb(uintptr_t addr,const void * data,void * cb_data)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
rfs4_print_client_cb(uintptr_t addr,const void * data,void * cb_data)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
rfs4_client_dcmd(uintptr_t addr,uint_t flags,int argc,const mdb_arg_t * argv)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
rfs4_client_help(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
rfs4_db_tbl_walk_init(mdb_walk_state_t * wsp)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
rfs4_db_tbl_walk_step(mdb_walk_state_t * wsp)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
rfs4_db_idx_walk_init(mdb_walk_state_t * wsp)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
rfs4_db_idx_walk_step(mdb_walk_state_t * wsp)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
rfs4_db_bkt_walk_init(mdb_walk_state_t * wsp)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
rfs4_db_bkt_walk_step(mdb_walk_state_t * wsp)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
rfs4_db_bkt_walk_fini(mdb_walk_state_t * wsp)1183 rfs4_db_bkt_walk_fini(mdb_walk_state_t *wsp)
1184 {
1185 mdb_free(wsp->walk_data, sizeof (uint32_t));
1186 }
1187