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/export.h>
17 #include <sys/pkp_hash.h>
18 #include <limits.h>
19
20 #include "nfssrv.h"
21 #include "common.h"
22
23 /*
24 * nfs_expvis dcmd implementation
25 */
26
27 static const mdb_bitmask_t sec_flag_bits[] = {
28 {"M_RO", M_RO, M_RO},
29 {"M_ROL", M_ROL, M_ROL},
30 {"M_RW", M_RW, M_RW},
31 {"M_RWL", M_RWL, M_RWL},
32 {"M_ROOT", M_ROOT, M_ROOT},
33 {"M_EXP", M_4SEC_EXPORTED, M_4SEC_EXPORTED},
34 {NULL, 0, 0}
35 };
36
37 static int
print_sec(int cnt,uintptr_t addr)38 print_sec(int cnt, uintptr_t addr)
39 {
40 int i;
41
42 if (cnt == 0)
43 return (DCMD_OK);
44
45 mdb_printf("Security Flavors :\n");
46 mdb_inc_indent(4);
47
48 for (i = 0; i < cnt; i++) {
49 struct secinfo si;
50 const char *s;
51
52 if (mdb_vread(&si, sizeof (si), addr) == -1) {
53 mdb_warn("can't read struct secinfo");
54 return (DCMD_ERR);
55 }
56
57 switch (si.s_secinfo.sc_nfsnum) {
58 case AUTH_NONE:
59 s = "none";
60 break;
61 case AUTH_SYS:
62 s = "sys";
63 break;
64 case AUTH_DH:
65 s = "dh";
66 break;
67 case 390003:
68 s = "krb5";
69 break;
70 case 390004:
71 s = "krb5i";
72 break;
73 case 390005:
74 s = "krb5p";
75 break;
76 default:
77 s = "???";
78 break;
79 }
80
81 mdb_printf("%-8s ref: %-8i flag: %#x (%b)\n", s, si.s_refcnt,
82 si.s_flags, si.s_flags, sec_flag_bits);
83
84 addr = (uintptr_t)((struct secinfo *)addr + 1);
85 }
86
87 mdb_dec_indent(4);
88
89 return (DCMD_OK);
90 }
91
92 int
nfs_expvis_dcmd(uintptr_t addr,uint_t flags,int argc,const mdb_arg_t * argv)93 nfs_expvis_dcmd(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
94 {
95 exp_visible_t expvis;
96 uintptr_t vp;
97 char *s;
98 int status;
99
100 if (argc > 0)
101 return (DCMD_USAGE);
102
103 if ((flags & DCMD_ADDRSPEC) == 0) {
104 mdb_printf("requires address of exp_visible_t\n");
105 return (DCMD_USAGE);
106 }
107
108 if (mdb_vread(&expvis, sizeof (expvis), addr) == -1) {
109 mdb_warn("can't read exp_visible_t");
110 return (DCMD_ERR);
111 }
112
113 /* vp = expvis.vis_vp->v_path */
114 if (mdb_vread(&vp, sizeof (vp), (uintptr_t)expvis.vis_vp
115 + OFFSETOF(vnode_t, v_path)) == -1) {
116 mdb_warn("can't read vnode_t");
117 return (DCMD_ERR);
118 }
119
120 s = mdb_alloc(PATH_MAX, UM_SLEEP | UM_GC);
121 if (mdb_readstr(s, PATH_MAX, vp) == -1) {
122 mdb_warn("can't read v_path");
123 return (DCMD_ERR);
124 }
125
126 mdb_printf("%s\n", s);
127
128 mdb_inc_indent(4);
129
130 mdb_printf("addr: %?p exp : %i ref: %i\n", addr,
131 expvis.vis_exported, expvis.vis_count);
132 mdb_printf("vp : %?p ino : %llu (%#llx)\n", expvis.vis_vp,
133 expvis.vis_ino, expvis.vis_ino);
134 mdb_printf("seci: %?p nsec: %i\n", expvis.vis_secinfo,
135 expvis.vis_seccnt);
136
137 status = print_sec(expvis.vis_seccnt, (uintptr_t)expvis.vis_secinfo);
138
139 mdb_dec_indent(4);
140
141 return (status);
142 }
143
144
145 /*
146 * nfs_expinfo dcmd implementation
147 */
148
149 static const mdb_bitmask_t exp_flag_bits[] = {
150 {"EX_NOSUID", EX_NOSUID, EX_NOSUID},
151 {"EX_ACLOK", EX_ACLOK, EX_ACLOK},
152 {"EX_PUBLIC", EX_PUBLIC, EX_PUBLIC},
153 {"EX_NOSUB", EX_NOSUB, EX_NOSUB},
154 {"EX_INDEX", EX_INDEX, EX_INDEX},
155 {"EX_LOG", EX_LOG, EX_LOG},
156 {"EX_LOG_ALLOPS", EX_LOG_ALLOPS, EX_LOG_ALLOPS},
157 {"EX_PSEUDO", EX_PSEUDO, EX_PSEUDO},
158 {NULL, 0, 0}
159 };
160
161 int
nfs_expinfo_dcmd(uintptr_t addr,uint_t flags,int argc,const mdb_arg_t * argv)162 nfs_expinfo_dcmd(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
163 {
164 struct exportinfo exi;
165 char *path;
166 int status;
167 uint_t v_flag;
168
169 if (argc > 0)
170 return (DCMD_USAGE);
171
172 if ((flags & DCMD_ADDRSPEC) == 0) {
173 mdb_printf("requires address of struct exporinfo\n");
174 return (DCMD_USAGE);
175 }
176
177 if (mdb_vread(&exi, sizeof (exi), addr) == -1) {
178 mdb_warn("can't read struct exportinfo");
179 return (DCMD_ERR);
180 }
181
182 if (mdb_vread(&v_flag, sizeof (v_flag), (uintptr_t)exi.exi_vp
183 + OFFSETOF(vnode_t, v_flag)) == -1) {
184 mdb_warn("can't read v_flag");
185 return (DCMD_ERR);
186 }
187
188 path = mdb_alloc(exi.exi_export.ex_pathlen + 1, UM_SLEEP | UM_GC);
189 if (mdb_readstr(path, exi.exi_export.ex_pathlen + 1,
190 (uintptr_t)exi.exi_export.ex_path) == -1) {
191 mdb_warn("can't read ex_path");
192 return (DCMD_ERR);
193 }
194
195 mdb_printf("\n%s %p\n", path, addr);
196
197 mdb_inc_indent(4);
198
199 mdb_printf("rtvp: %?p ref : %-8u flag: %#x (%b)%s\n", exi.exi_vp,
200 exi.exi_count, exi.exi_export.ex_flags, exi.exi_export.ex_flags,
201 exp_flag_bits, v_flag & VROOT ? " VROOT" : "");
202
203 mdb_printf("dvp : %?p anon: %-8u logb: %p\n", exi.exi_dvp,
204 exi.exi_export.ex_anon, exi.exi_logbuffer);
205 mdb_printf("seci: %?p nsec: %-8i fsid: (%#x %#x)\n",
206 exi.exi_export.ex_secinfo, exi.exi_export.ex_seccnt,
207 exi.exi_fsid.val[0], exi.exi_fsid.val[1]);
208
209 status = print_sec(exi.exi_export.ex_seccnt,
210 (uintptr_t)exi.exi_export.ex_secinfo);
211 if (status != DCMD_OK)
212 return (status);
213
214 if (exi.exi_visible) {
215 mdb_printf("PseudoFS Nodes:\n");
216 mdb_inc_indent(4);
217
218 if (mdb_pwalk_dcmd("nfs_expvis", "nfs_expvis", 0, NULL,
219 (uintptr_t)exi.exi_visible) == -1) {
220 mdb_warn("walk through exi_visible failed");
221 return (DCMD_ERR);
222 }
223
224 mdb_dec_indent(4);
225 }
226
227 mdb_dec_indent(4);
228
229 return (DCMD_OK);
230 }
231
232 /*
233 * nfs_exptable dcmd implementation
234 */
235
236 int
nfs_exptable_dcmd(uintptr_t addr,uint_t flags,int argc,const mdb_arg_t * argv)237 nfs_exptable_dcmd(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
238 {
239 uintptr_t glbls;
240 uintptr_t zonep;
241 nfs_globals_t nfsglbls;
242
243 if (argc > 0)
244 return (DCMD_USAGE);
245
246 if ((flags & DCMD_ADDRSPEC) != 0) {
247 zonep = addr;
248 } else {
249 if (mdb_readsym(
250 &zonep, sizeof (uintptr_t), "global_zone") == -1) {
251 mdb_warn("Failed to find global_zone");
252 return (DCMD_ERR);
253 }
254 }
255 mdb_printf("The zone is %p\n", zonep);
256
257 if (zoned_get_nfs_globals(zonep, &glbls) != DCMD_OK) {
258 mdb_warn("failed to get zoned specific NFS globals");
259 return (DCMD_ERR);
260 }
261
262 mdb_printf("The nfs zone globals are %p\n", glbls);
263
264 if (mdb_vread(&nfsglbls, sizeof (nfs_globals_t), glbls) == -1) {
265 mdb_warn("can't read zone globals");
266 return (DCMD_ERR);
267 }
268 mdb_printf("The nfs globals are %p\n", nfsglbls);
269 mdb_printf("The address of nfsglbls.nfs_export is %p\n",
270 nfsglbls.nfs_export);
271 mdb_printf("The exptable address is %p\n",
272 nfsglbls.nfs_export->exptable);
273
274 if (mdb_pwalk_dcmd("nfs_expinfo", "nfs_expinfo", 0, NULL,
275 (uintptr_t)nfsglbls.nfs_export->exptable) == -1) {
276 mdb_warn("exptable walk failed");
277 return (DCMD_ERR);
278 }
279
280 return (DCMD_OK);
281 }
282
283 /*
284 * nfs_exptable_path dcmd implementation
285 */
286
287 int
nfs_exptable_path_dcmd(uintptr_t addr,uint_t flags,int argc,const mdb_arg_t * argv)288 nfs_exptable_path_dcmd(uintptr_t addr, uint_t flags, int argc,
289 const mdb_arg_t *argv)
290 {
291 uintptr_t glbls;
292 uintptr_t zonep;
293 nfs_globals_t nfsglbls;
294
295 if (argc > 0)
296 return (DCMD_USAGE);
297
298 if ((flags & DCMD_ADDRSPEC) != 0) {
299 zonep = addr;
300 } else {
301 if (mdb_readsym(&zonep, sizeof (uintptr_t),
302 "global_zone") == -1) {
303 mdb_warn("Failed to find global_zone");
304 return (DCMD_ERR);
305 }
306 }
307
308 if (zoned_get_nfs_globals(zonep, &glbls) != DCMD_OK) {
309 mdb_warn("failed to get zoned specific NFS globals");
310 return (DCMD_ERR);
311 }
312
313 if (mdb_vread(&nfsglbls, sizeof (nfs_globals_t), glbls) == -1) {
314 mdb_warn("can't read zone globals");
315 return (DCMD_ERR);
316 }
317
318 if (mdb_pwalk_dcmd("nfs_expinfo_path", "nfs_expinfo", 0, NULL,
319 (uintptr_t)nfsglbls.nfs_export->exptable) == -1) {
320 mdb_warn("exptable walk failed");
321 return (DCMD_ERR);
322 }
323
324 return (DCMD_OK);
325 }
326
327 /*
328 * nfs_nstree dcmd implementation
329 */
330
331 static int
print_tree(uintptr_t addr,uint_t opt_v,treenode_t * tn,char * s)332 print_tree(uintptr_t addr, uint_t opt_v, treenode_t *tn, char *s)
333 {
334 while (addr != 0) {
335 uintptr_t a;
336
337 if (mdb_vread(tn, sizeof (*tn), addr) == -1) {
338 mdb_warn("can't read treenode");
339 return (DCMD_ERR);
340 }
341
342 /* a = tn->tree_exi->exi_vp */
343 if (mdb_vread(&a, sizeof (a), (uintptr_t)tn->tree_exi
344 + OFFSETOF(struct exportinfo, exi_vp)) == -1) {
345 mdb_warn("can't read exi_vp");
346 return (DCMD_ERR);
347 }
348 /* a = ((vnode_t *)a)->v_path */
349 if (mdb_vread(&a, sizeof (a),
350 a + OFFSETOF(vnode_t, v_path)) == -1) {
351 mdb_warn("can't read v_path");
352 return (DCMD_ERR);
353 }
354 if (mdb_readstr(s, PATH_MAX, a) == -1) {
355 mdb_warn("can't read v_path string");
356 return (DCMD_ERR);
357 }
358
359 mdb_printf("\n\nTREENODE:\n%s\n", s);
360
361 mdb_inc_indent(2);
362
363 if (opt_v)
364 mdb_printf("\nDump treenode:\n\n");
365
366 mdb_printf("addr: %p\n", addr);
367 mdb_printf("tree_parent: %p\n", tn->tree_parent);
368 mdb_printf("tree_child_first: %p\n", tn->tree_child_first);
369 mdb_printf("tree_sibling: %p\n", tn->tree_sibling);
370 mdb_printf("tree_exi: %p\n", tn->tree_exi);
371 mdb_printf("tree_vis: %p\n", tn->tree_vis);
372
373 if (opt_v) {
374 mdb_printf("\nDump exportinfo:\n");
375 if (mdb_call_dcmd("nfs_expinfo",
376 (uintptr_t)tn->tree_exi, DCMD_ADDRSPEC, 0, NULL)
377 == -1)
378 return (DCMD_ERR);
379
380 if (tn->tree_vis) {
381 mdb_printf("\nDump exp_visible:\n\n");
382 if (mdb_call_dcmd("nfs_expvis",
383 (uintptr_t)tn->tree_vis, DCMD_ADDRSPEC, 0,
384 NULL) == -1)
385 return (DCMD_ERR);
386 }
387 }
388
389 addr = (uintptr_t)tn->tree_sibling;
390
391 if (tn->tree_child_first != NULL) {
392 int status;
393
394 mdb_inc_indent(2);
395 status = print_tree((uintptr_t)tn->tree_child_first,
396 opt_v, tn, s);
397 if (status != DCMD_OK)
398 return (status);
399 mdb_dec_indent(2);
400 }
401
402 mdb_dec_indent(2);
403 }
404
405 return (DCMD_OK);
406 }
407
408 int
nfs_nstree_dcmd(uintptr_t addr,uint_t flags,int argc,const mdb_arg_t * argv)409 nfs_nstree_dcmd(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
410 {
411 uintptr_t glbls;
412 uintptr_t zonep;
413 nfs_globals_t nfsglbls;
414 nfs_export_t exp;
415
416 uint_t opt_v = FALSE;
417 treenode_t tn;
418 char *s;
419
420 if (mdb_getopts(argc, argv,
421 'v', MDB_OPT_SETBITS, TRUE, &opt_v, NULL) != argc)
422 return (DCMD_USAGE);
423
424 if ((flags & DCMD_ADDRSPEC) != 0) {
425 zonep = addr;
426 } else {
427 if (mdb_readsym(&zonep, sizeof (uintptr_t),
428 "global_zone") == -1) {
429 mdb_warn("Failed to find global_zone");
430 return (DCMD_ERR);
431 }
432 }
433
434 if (zoned_get_nfs_globals(zonep, &glbls) != DCMD_OK) {
435 mdb_warn("failed to get zoned specific NFS globals");
436 return (DCMD_ERR);
437 }
438
439 if (mdb_vread(&nfsglbls, sizeof (nfs_globals_t), glbls) == -1) {
440 mdb_warn("can't read zone globals");
441 return (DCMD_ERR);
442 }
443
444 if (mdb_vread(&exp, sizeof (nfs_export_t),
445 (uintptr_t)nfsglbls.nfs_export) == -1) {
446 mdb_warn("can't read nfs_export");
447 return (DCMD_ERR);
448 }
449
450 s = mdb_alloc(PATH_MAX, UM_SLEEP | UM_GC);
451
452 return (print_tree((uintptr_t)exp.ns_root, opt_v, &tn, s));
453 }
454
455 void
nfs_nstree_help(void)456 nfs_nstree_help(void)
457 {
458 mdb_printf(
459 "-v dump also exportinfo and exp_visible structures\n");
460 }
461
462 /*
463 * nfs_fid_hashdist dcmd implementation
464 */
465
466 static int
calc_hashdist(struct exp_walk_arg * arg,uint_t opt_v,uintptr_t tbladdr)467 calc_hashdist(struct exp_walk_arg *arg, uint_t opt_v, uintptr_t tbladdr)
468 {
469 struct exportinfo **table;
470 int i;
471 u_longlong_t min = 0;
472 u_longlong_t max = 0;
473 u_longlong_t sum = 0;
474 u_longlong_t sum_sqr = 0;
475
476 table = mdb_alloc(arg->size * sizeof (struct exportinfo *),
477 UM_SLEEP | UM_GC);
478 if (mdb_vread(table, arg->size * sizeof (struct exportinfo *),
479 tbladdr) == -1) {
480 mdb_warn("can't vreadsym exptable");
481 return (DCMD_ERR);
482 }
483
484
485 for (i = 0; i < arg->size; i++) {
486 u_longlong_t len;
487 uintptr_t addr;
488
489 for (addr = (uintptr_t)table[i], len = 0; addr; len++)
490 if (mdb_vread(&addr, sizeof (addr), addr + arg->offset)
491 == -1) {
492 mdb_warn("unable to read pointer to next "
493 "exportinfo struct");
494 return (DCMD_ERR);
495 }
496
497 if (i == 0 || len < min)
498 min = len;
499 if (len > max)
500 max = len;
501 sum += len;
502 sum_sqr += len * len;
503
504 if (opt_v)
505 mdb_printf("%u\n", len);
506 }
507
508 mdb_printf("TABLE: %s\n", arg->name);
509 mdb_printf("items/size = %u/%u\n", sum, arg->size);
510 mdb_printf("min/avg/max/variance = %u/%u/%u/%u\n", min, sum / arg->size,
511 max, (sum_sqr - (sum * sum) / arg->size) / arg->size);
512
513 return (DCMD_OK);
514 }
515
516 int
nfs_fid_hashdist_dcmd(uintptr_t addr,uint_t flags,int argc,const mdb_arg_t * argv)517 nfs_fid_hashdist_dcmd(uintptr_t addr, uint_t flags, int argc,
518 const mdb_arg_t *argv)
519 {
520 uint_t opt_v = FALSE;
521
522 if (mdb_getopts(argc, argv,
523 'v', MDB_OPT_SETBITS, TRUE, &opt_v, NULL) != argc)
524 return (DCMD_USAGE);
525
526 if ((flags & DCMD_ADDRSPEC) == 0) {
527 mdb_printf("requires address of export table\n");
528 return (DCMD_USAGE);
529 }
530
531 return (calc_hashdist(&nfs_expinfo_arg, opt_v, addr));
532 }
533
534 void
nfs_hashdist_help(void)535 nfs_hashdist_help(void)
536 {
537 mdb_printf(
538 "-v displays individual bucket lengths\n");
539 }
540
541 /*
542 * nfs_path_hashdist dcmd implementation
543 */
544
545 int
nfs_path_hashdist_dcmd(uintptr_t addr,uint_t flags,int argc,const mdb_arg_t * argv)546 nfs_path_hashdist_dcmd(uintptr_t addr, uint_t flags, int argc,
547 const mdb_arg_t *argv)
548 {
549 uint_t opt_v = FALSE;
550
551 if (mdb_getopts(argc, argv,
552 'v', MDB_OPT_SETBITS, TRUE, &opt_v, NULL) != argc)
553 return (DCMD_USAGE);
554
555 if ((flags & DCMD_ADDRSPEC) == 0) {
556 mdb_printf("requires address of export table\n");
557 return (DCMD_USAGE);
558 }
559
560 return (calc_hashdist(&nfs_expinfo_path_arg, opt_v, addr));
561 }
562
563 /*
564 * nfs_expinfo/nfs_expinfo_path walkers implementation
565 */
566
567 struct exp_walk_arg nfs_expinfo_arg = {
568 "exptable", EXPTABLESIZE,
569 OFFSETOF(struct exportinfo, fid_hash) + OFFSETOF(struct exp_hash, next)
570 };
571
572 struct exp_walk_arg nfs_expinfo_path_arg = {
573 "exptable_path_hash", PKP_HASH_SIZE,
574 OFFSETOF(struct exportinfo, path_hash) + OFFSETOF(struct exp_hash, next)
575 };
576
577 int
nfs_expinfo_walk_init(mdb_walk_state_t * wsp)578 nfs_expinfo_walk_init(mdb_walk_state_t *wsp)
579 {
580 struct exp_walk_arg *exp_arg = wsp->walk_arg;
581 hash_table_walk_arg_t *arg;
582 int status;
583
584 if (wsp->walk_addr == 0) {
585 mdb_warn("global walk not supported");
586 return (WALK_ERR);
587 }
588
589 arg = mdb_alloc(sizeof (hash_table_walk_arg_t), UM_SLEEP);
590 arg->array_addr = wsp->walk_addr;
591 arg->array_len = exp_arg->size;
592 arg->head_size = sizeof (struct exportinfo *);
593 arg->first_name = "exportinfo pointer";
594 arg->first_offset = 0;
595 arg->member_type_name = "struct exportinfo";
596 arg->member_size = sizeof (struct exportinfo);
597 arg->next_offset = exp_arg->offset;
598
599 wsp->walk_arg = arg;
600
601 status = hash_table_walk_init(wsp);
602 if (status != WALK_NEXT)
603 mdb_free(wsp->walk_arg, sizeof (hash_table_walk_arg_t));
604 return (status);
605 }
606
607 void
nfs_expinfo_walk_fini(mdb_walk_state_t * wsp)608 nfs_expinfo_walk_fini(mdb_walk_state_t *wsp)
609 {
610 hash_table_walk_fini(wsp);
611 mdb_free(wsp->walk_arg, sizeof (hash_table_walk_arg_t));
612 }
613
614 /*
615 * nfs_expvis walker implementation
616 */
617
618 int
nfs_expvis_walk_init(mdb_walk_state_t * wsp)619 nfs_expvis_walk_init(mdb_walk_state_t *wsp)
620 {
621 if (wsp->walk_addr == 0) {
622 mdb_warn("global walk not supported");
623 return (WALK_ERR);
624 }
625
626 return (WALK_NEXT);
627 }
628
629 int
nfs_expvis_walk_step(mdb_walk_state_t * wsp)630 nfs_expvis_walk_step(mdb_walk_state_t *wsp)
631 {
632 exp_visible_t vis;
633 uintptr_t addr = wsp->walk_addr;
634
635 if (addr == 0)
636 return (WALK_DONE);
637
638 if (mdb_vread(&vis, sizeof (vis), addr) == -1) {
639 mdb_warn("failed to read exp_visible_t at %p", addr);
640 return (WALK_ERR);
641 }
642
643 wsp->walk_addr = (uintptr_t)vis.vis_next;
644 return (wsp->walk_callback(addr, &vis, wsp->walk_cbdata));
645 }
646
647 /*
648 * nfssrv_globals walker, gets the nfs globals for each zone
649 *
650 * Note: Most of the NFS dcmds take a zone pointer, at some point we may
651 * want to change that to take the nfs globals address and aviod the zone
652 * key lookup. This walker could be helpful in that change.
653 */
654 int
nfssrv_globals_walk_init(mdb_walk_state_t * wsp)655 nfssrv_globals_walk_init(mdb_walk_state_t *wsp)
656 {
657 GElf_Sym sym;
658
659 if (wsp->walk_addr == 0) {
660 if (mdb_lookup_by_name("nfssrv_globals_list", &sym) == -1) {
661 mdb_warn("failed to find 'nfssrv_globals_list'");
662 return (WALK_ERR);
663 }
664 wsp->walk_addr = (uintptr_t)sym.st_value;
665 } else {
666 mdb_printf("nfssrv_globals walk only supports global walks\n");
667 return (WALK_ERR);
668 }
669
670 if (mdb_layered_walk("list", wsp) == -1) {
671 mdb_warn("couldn't walk 'list'");
672 return (WALK_ERR);
673 }
674
675 wsp->walk_data = (void *)wsp->walk_addr;
676 return (WALK_NEXT);
677 }
678
679 int
nfssrv_globals_walk_step(mdb_walk_state_t * wsp)680 nfssrv_globals_walk_step(mdb_walk_state_t *wsp)
681 {
682 return (wsp->walk_callback(wsp->walk_addr, wsp->walk_layer,
683 wsp->walk_cbdata));
684 }
685