1 /*-
2 * SPDX-License-Identifier: BSD-2-Clause
3 *
4 * Copyright (c) 2009 Robert N. M. Watson
5 * All rights reserved.
6 *
7 * This software was developed at the University of Cambridge Computer
8 * Laboratory with support from a grant from Google, Inc.
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29 * SUCH DAMAGE.
30 */
31
32 #include <sys/param.h>
33 #include <sys/systm.h>
34 #include <sys/conf.h>
35 #include <sys/kernel.h>
36 #include <sys/malloc.h>
37 #include <sys/module.h>
38
39 #include <sys/dtrace.h>
40 #include <sys/dtrace_bsd.h>
41
42 #include <fs/nfs/nfsproto.h>
43
44 #include <fs/nfsclient/nfs_kdtrace.h>
45
46 /*
47 * dtnfscl is a DTrace provider that tracks the intent to perform RPCs
48 * in the NFS client, as well as access to and maintenance of the access and
49 * attribute caches. This is not quite the same as RPCs, because NFS may
50 * issue multiple RPC transactions in the event that authentication fails,
51 * there's a jukebox error, or none at all if the access or attribute cache
52 * hits. However, it cleanly represents the logical layer between RPC
53 * transmission and vnode/vfs operations, providing access to state linking
54 * the two.
55 */
56
57 static int dtnfsclient_unload(void);
58 static void dtnfsclient_getargdesc(void *, dtrace_id_t, void *,
59 dtrace_argdesc_t *);
60 static void dtnfsclient_provide(void *, dtrace_probedesc_t *);
61 static void dtnfsclient_destroy(void *, dtrace_id_t, void *);
62 static void dtnfsclient_enable(void *, dtrace_id_t, void *);
63 static void dtnfsclient_disable(void *, dtrace_id_t, void *);
64 static void dtnfsclient_load(void *);
65
66 static dtrace_pattr_t dtnfsclient_attr = {
67 { DTRACE_STABILITY_STABLE, DTRACE_STABILITY_STABLE, DTRACE_CLASS_COMMON },
68 { DTRACE_STABILITY_PRIVATE, DTRACE_STABILITY_PRIVATE, DTRACE_CLASS_UNKNOWN },
69 { DTRACE_STABILITY_PRIVATE, DTRACE_STABILITY_PRIVATE, DTRACE_CLASS_UNKNOWN },
70 { DTRACE_STABILITY_STABLE, DTRACE_STABILITY_STABLE, DTRACE_CLASS_COMMON },
71 { DTRACE_STABILITY_STABLE, DTRACE_STABILITY_STABLE, DTRACE_CLASS_COMMON },
72 };
73
74 /*
75 * Description of NFSv4, NFSv3 and (optional) NFSv2 probes for a procedure.
76 */
77 struct dtnfsclient_rpc {
78 char *nr_v4_name;
79 char *nr_v3_name; /* Or NULL if none. */
80 char *nr_v2_name; /* Or NULL if none. */
81
82 /*
83 * IDs for the start and done cases, for NFSv2, NFSv3 and NFSv4.
84 */
85 uint32_t nr_v2_id_start, nr_v2_id_done;
86 uint32_t nr_v3_id_start, nr_v3_id_done;
87 uint32_t nr_v4_id_start, nr_v4_id_done;
88 };
89
90 /*
91 * This table is indexed by NFSv3 procedure number, but also used for NFSv2
92 * procedure names and NFSv4 operations.
93 */
94 static struct dtnfsclient_rpc dtnfsclient_rpcs[NFSV41_NPROCS + 1] = {
95 { "null", "null", "null" },
96 { "getattr", "getattr", "getattr" },
97 { "setattr", "setattr", "setattr" },
98 { "lookup", "lookup", "lookup" },
99 { "access", "access", "noop" },
100 { "readlink", "readlink", "readlink" },
101 { "read", "read", "read" },
102 { "write", "write", "write" },
103 { "create", "create", "create" },
104 { "mkdir", "mkdir", "mkdir" },
105 { "symlink", "symlink", "symlink" },
106 { "mknod", "mknod" },
107 { "remove", "remove", "remove" },
108 { "rmdir", "rmdir", "rmdir" },
109 { "rename", "rename", "rename" },
110 { "link", "link", "link" },
111 { "readdir", "readdir", "readdir" },
112 { "readdirplus", "readdirplus" },
113 { "fsstat", "fsstat", "statfs" },
114 { "fsinfo", "fsinfo" },
115 { "pathconf", "pathconf" },
116 { "commit", "commit" },
117 { "lookupp" },
118 { "setclientid" },
119 { "setclientidcfrm" },
120 { "lock" },
121 { "locku" },
122 { "open" },
123 { "close" },
124 { "openconfirm" },
125 { "lockt" },
126 { "opendowngrade" },
127 { "renew" },
128 { "putrootfh" },
129 { "releaselckown" },
130 { "delegreturn" },
131 { "retdelegremove" },
132 { "retdelegrename1" },
133 { "retdelegrename2" },
134 { "getacl" },
135 { "setacl" },
136 { "noop", "noop", "noop" }
137 };
138
139 /*
140 * Module name strings.
141 */
142 static char *dtnfsclient_accesscache_str = "accesscache";
143 static char *dtnfsclient_attrcache_str = "attrcache";
144 static char *dtnfsclient_nfs2_str = "nfs2";
145 static char *dtnfsclient_nfs3_str = "nfs3";
146 static char *dtnfsclient_nfs4_str = "nfs4";
147
148 /*
149 * Function name strings.
150 */
151 static char *dtnfsclient_flush_str = "flush";
152 static char *dtnfsclient_load_str = "load";
153 static char *dtnfsclient_get_str = "get";
154
155 /*
156 * Name strings.
157 */
158 static char *dtnfsclient_done_str = "done";
159 static char *dtnfsclient_hit_str = "hit";
160 static char *dtnfsclient_miss_str = "miss";
161 static char *dtnfsclient_start_str = "start";
162
163 static dtrace_pops_t dtnfsclient_pops = {
164 .dtps_provide = dtnfsclient_provide,
165 .dtps_provide_module = NULL,
166 .dtps_enable = dtnfsclient_enable,
167 .dtps_disable = dtnfsclient_disable,
168 .dtps_suspend = NULL,
169 .dtps_resume = NULL,
170 .dtps_getargdesc = dtnfsclient_getargdesc,
171 .dtps_getargval = NULL,
172 .dtps_usermode = NULL,
173 .dtps_destroy = dtnfsclient_destroy
174 };
175
176 static dtrace_provider_id_t dtnfsclient_id;
177
178 /*
179 * When tracing on a procedure is enabled, the DTrace ID for an RPC event is
180 * stored in one of these two NFS client-allocated arrays; 0 indicates that
181 * the event is not being traced so probes should not be called.
182 *
183 * For simplicity, we allocate both v2, v3 and v4 arrays as NFSV41_NPROCS + 1,
184 * and the v2, v3 arrays are simply sparse.
185 */
186 extern uint32_t nfscl_nfs2_start_probes[NFSV41_NPROCS + 1];
187 extern uint32_t nfscl_nfs2_done_probes[NFSV41_NPROCS + 1];
188
189 extern uint32_t nfscl_nfs3_start_probes[NFSV41_NPROCS + 1];
190 extern uint32_t nfscl_nfs3_done_probes[NFSV41_NPROCS + 1];
191
192 extern uint32_t nfscl_nfs4_start_probes[NFSV41_NPROCS + 1];
193 extern uint32_t nfscl_nfs4_done_probes[NFSV41_NPROCS + 1];
194
195 /*
196 * Look up a DTrace probe ID to see if it's associated with a "done" event --
197 * if so, we will return a fourth argument type of "int".
198 */
199 static int
dtnfs234_isdoneprobe(dtrace_id_t id)200 dtnfs234_isdoneprobe(dtrace_id_t id)
201 {
202 int i;
203
204 for (i = 0; i < NFSV41_NPROCS + 1; i++) {
205 if (dtnfsclient_rpcs[i].nr_v4_id_done == id ||
206 dtnfsclient_rpcs[i].nr_v3_id_done == id ||
207 dtnfsclient_rpcs[i].nr_v2_id_done == id)
208 return (1);
209 }
210 return (0);
211 }
212
213 static void
dtnfsclient_getargdesc(void * arg,dtrace_id_t id,void * parg,dtrace_argdesc_t * desc)214 dtnfsclient_getargdesc(void *arg, dtrace_id_t id, void *parg,
215 dtrace_argdesc_t *desc)
216 {
217 const char *p = NULL;
218
219 if (id == nfscl_accesscache_flush_done_id ||
220 id == nfscl_attrcache_flush_done_id ||
221 id == nfscl_attrcache_get_miss_id) {
222 switch (desc->dtargd_ndx) {
223 case 0:
224 p = "struct vnode *";
225 break;
226 default:
227 desc->dtargd_ndx = DTRACE_ARGNONE;
228 break;
229 }
230 } else if (id == nfscl_accesscache_get_hit_id ||
231 id == nfscl_accesscache_get_miss_id) {
232 switch (desc->dtargd_ndx) {
233 case 0:
234 p = "struct vnode *";
235 break;
236 case 1:
237 p = "uid_t";
238 break;
239 case 2:
240 p = "uint32_t";
241 break;
242 default:
243 desc->dtargd_ndx = DTRACE_ARGNONE;
244 break;
245 }
246 } else if (id == nfscl_accesscache_load_done_id) {
247 switch (desc->dtargd_ndx) {
248 case 0:
249 p = "struct vnode *";
250 break;
251 case 1:
252 p = "uid_t";
253 break;
254 case 2:
255 p = "uint32_t";
256 break;
257 case 3:
258 p = "int";
259 break;
260 default:
261 desc->dtargd_ndx = DTRACE_ARGNONE;
262 break;
263 }
264 } else if (id == nfscl_attrcache_get_hit_id) {
265 switch (desc->dtargd_ndx) {
266 case 0:
267 p = "struct vnode *";
268 break;
269 case 1:
270 p = "struct vattr *";
271 break;
272 default:
273 desc->dtargd_ndx = DTRACE_ARGNONE;
274 break;
275 }
276 } else if (id == nfscl_attrcache_load_done_id) {
277 switch (desc->dtargd_ndx) {
278 case 0:
279 p = "struct vnode *";
280 break;
281 case 1:
282 p = "struct vattr *";
283 break;
284 case 2:
285 p = "int";
286 break;
287 default:
288 desc->dtargd_ndx = DTRACE_ARGNONE;
289 break;
290 }
291 } else {
292 switch (desc->dtargd_ndx) {
293 case 0:
294 p = "struct vnode *";
295 break;
296 case 1:
297 p = "struct mbuf *";
298 break;
299 case 2:
300 p = "struct ucred *";
301 break;
302 case 3:
303 p = "int";
304 break;
305 case 4:
306 if (dtnfs234_isdoneprobe(id)) {
307 p = "int";
308 break;
309 }
310 /* FALLSTHROUGH */
311 default:
312 desc->dtargd_ndx = DTRACE_ARGNONE;
313 break;
314 }
315 }
316 if (p != NULL)
317 strlcpy(desc->dtargd_native, p, sizeof(desc->dtargd_native));
318 }
319
320 static void
dtnfsclient_provide(void * arg,dtrace_probedesc_t * desc)321 dtnfsclient_provide(void *arg, dtrace_probedesc_t *desc)
322 {
323 int i;
324
325 if (desc != NULL)
326 return;
327
328 /*
329 * Register access cache probes.
330 */
331 if (dtrace_probe_lookup(dtnfsclient_id, dtnfsclient_accesscache_str,
332 dtnfsclient_flush_str, dtnfsclient_done_str) == 0) {
333 nfscl_accesscache_flush_done_id = dtrace_probe_create(
334 dtnfsclient_id, dtnfsclient_accesscache_str,
335 dtnfsclient_flush_str, dtnfsclient_done_str, 0, NULL);
336 }
337 if (dtrace_probe_lookup(dtnfsclient_id, dtnfsclient_accesscache_str,
338 dtnfsclient_get_str, dtnfsclient_hit_str) == 0) {
339 nfscl_accesscache_get_hit_id = dtrace_probe_create(
340 dtnfsclient_id, dtnfsclient_accesscache_str,
341 dtnfsclient_get_str, dtnfsclient_hit_str, 0, NULL);
342 }
343 if (dtrace_probe_lookup(dtnfsclient_id, dtnfsclient_accesscache_str,
344 dtnfsclient_get_str, dtnfsclient_miss_str) == 0) {
345 nfscl_accesscache_get_miss_id = dtrace_probe_create(
346 dtnfsclient_id, dtnfsclient_accesscache_str,
347 dtnfsclient_get_str, dtnfsclient_miss_str, 0, NULL);
348 }
349 if (dtrace_probe_lookup(dtnfsclient_id, dtnfsclient_accesscache_str,
350 dtnfsclient_load_str, dtnfsclient_done_str) == 0) {
351 nfscl_accesscache_load_done_id = dtrace_probe_create(
352 dtnfsclient_id, dtnfsclient_accesscache_str,
353 dtnfsclient_load_str, dtnfsclient_done_str, 0, NULL);
354 }
355
356 /*
357 * Register attribute cache probes.
358 */
359 if (dtrace_probe_lookup(dtnfsclient_id, dtnfsclient_attrcache_str,
360 dtnfsclient_flush_str, dtnfsclient_done_str) == 0) {
361 nfscl_attrcache_flush_done_id = dtrace_probe_create(
362 dtnfsclient_id, dtnfsclient_attrcache_str,
363 dtnfsclient_flush_str, dtnfsclient_done_str, 0, NULL);
364 }
365 if (dtrace_probe_lookup(dtnfsclient_id, dtnfsclient_attrcache_str,
366 dtnfsclient_get_str, dtnfsclient_hit_str) == 0) {
367 nfscl_attrcache_get_hit_id = dtrace_probe_create(
368 dtnfsclient_id, dtnfsclient_attrcache_str,
369 dtnfsclient_get_str, dtnfsclient_hit_str, 0, NULL);
370 }
371 if (dtrace_probe_lookup(dtnfsclient_id, dtnfsclient_attrcache_str,
372 dtnfsclient_get_str, dtnfsclient_miss_str) == 0) {
373 nfscl_attrcache_get_miss_id = dtrace_probe_create(
374 dtnfsclient_id, dtnfsclient_attrcache_str,
375 dtnfsclient_get_str, dtnfsclient_miss_str, 0, NULL);
376 }
377 if (dtrace_probe_lookup(dtnfsclient_id, dtnfsclient_attrcache_str,
378 dtnfsclient_load_str, dtnfsclient_done_str) == 0) {
379 nfscl_attrcache_load_done_id = dtrace_probe_create(
380 dtnfsclient_id, dtnfsclient_attrcache_str,
381 dtnfsclient_load_str, dtnfsclient_done_str, 0, NULL);
382 }
383
384 /*
385 * Register NFSv2 RPC procedures; note sparseness check for each slot
386 * in the NFSv3, NFSv4 procnum-indexed array.
387 */
388 for (i = 0; i < NFSV41_NPROCS + 1; i++) {
389 if (dtnfsclient_rpcs[i].nr_v2_name != NULL &&
390 dtrace_probe_lookup(dtnfsclient_id, dtnfsclient_nfs2_str,
391 dtnfsclient_rpcs[i].nr_v2_name, dtnfsclient_start_str) ==
392 0) {
393 dtnfsclient_rpcs[i].nr_v2_id_start =
394 dtrace_probe_create(dtnfsclient_id,
395 dtnfsclient_nfs2_str,
396 dtnfsclient_rpcs[i].nr_v2_name,
397 dtnfsclient_start_str, 0,
398 &nfscl_nfs2_start_probes[i]);
399 }
400 if (dtnfsclient_rpcs[i].nr_v2_name != NULL &&
401 dtrace_probe_lookup(dtnfsclient_id, dtnfsclient_nfs2_str,
402 dtnfsclient_rpcs[i].nr_v2_name, dtnfsclient_done_str) ==
403 0) {
404 dtnfsclient_rpcs[i].nr_v2_id_done =
405 dtrace_probe_create(dtnfsclient_id,
406 dtnfsclient_nfs2_str,
407 dtnfsclient_rpcs[i].nr_v2_name,
408 dtnfsclient_done_str, 0,
409 &nfscl_nfs2_done_probes[i]);
410 }
411 }
412
413 /*
414 * Register NFSv3 RPC procedures; note sparseness check for each slot
415 * in the NFSv4 procnum-indexed array.
416 */
417 for (i = 0; i < NFSV41_NPROCS + 1; i++) {
418 if (dtnfsclient_rpcs[i].nr_v3_name != NULL &&
419 dtrace_probe_lookup(dtnfsclient_id, dtnfsclient_nfs3_str,
420 dtnfsclient_rpcs[i].nr_v3_name, dtnfsclient_start_str) ==
421 0) {
422 dtnfsclient_rpcs[i].nr_v3_id_start =
423 dtrace_probe_create(dtnfsclient_id,
424 dtnfsclient_nfs3_str,
425 dtnfsclient_rpcs[i].nr_v3_name,
426 dtnfsclient_start_str, 0,
427 &nfscl_nfs3_start_probes[i]);
428 }
429 if (dtnfsclient_rpcs[i].nr_v3_name != NULL &&
430 dtrace_probe_lookup(dtnfsclient_id, dtnfsclient_nfs3_str,
431 dtnfsclient_rpcs[i].nr_v3_name, dtnfsclient_done_str) ==
432 0) {
433 dtnfsclient_rpcs[i].nr_v3_id_done =
434 dtrace_probe_create(dtnfsclient_id,
435 dtnfsclient_nfs3_str,
436 dtnfsclient_rpcs[i].nr_v3_name,
437 dtnfsclient_done_str, 0,
438 &nfscl_nfs3_done_probes[i]);
439 }
440 }
441
442 /*
443 * Register NFSv4 RPC procedures.
444 */
445 for (i = 0; i < NFSV41_NPROCS + 1; i++) {
446 if (dtrace_probe_lookup(dtnfsclient_id, dtnfsclient_nfs4_str,
447 dtnfsclient_rpcs[i].nr_v4_name, dtnfsclient_start_str) ==
448 0) {
449 dtnfsclient_rpcs[i].nr_v4_id_start =
450 dtrace_probe_create(dtnfsclient_id,
451 dtnfsclient_nfs4_str,
452 dtnfsclient_rpcs[i].nr_v4_name,
453 dtnfsclient_start_str, 0,
454 &nfscl_nfs4_start_probes[i]);
455 }
456 if (dtrace_probe_lookup(dtnfsclient_id, dtnfsclient_nfs4_str,
457 dtnfsclient_rpcs[i].nr_v4_name, dtnfsclient_done_str) ==
458 0) {
459 dtnfsclient_rpcs[i].nr_v4_id_done =
460 dtrace_probe_create(dtnfsclient_id,
461 dtnfsclient_nfs4_str,
462 dtnfsclient_rpcs[i].nr_v4_name,
463 dtnfsclient_done_str, 0,
464 &nfscl_nfs4_done_probes[i]);
465 }
466 }
467 }
468
469 static void
dtnfsclient_destroy(void * arg,dtrace_id_t id,void * parg)470 dtnfsclient_destroy(void *arg, dtrace_id_t id, void *parg)
471 {
472 }
473
474 static void
dtnfsclient_enable(void * arg,dtrace_id_t id,void * parg)475 dtnfsclient_enable(void *arg, dtrace_id_t id, void *parg)
476 {
477 uint32_t *p = parg;
478 void *f = dtrace_probe;
479
480 if (id == nfscl_accesscache_flush_done_id)
481 dtrace_nfscl_accesscache_flush_done_probe = f;
482 else if (id == nfscl_accesscache_get_hit_id)
483 dtrace_nfscl_accesscache_get_hit_probe = f;
484 else if (id == nfscl_accesscache_get_miss_id)
485 dtrace_nfscl_accesscache_get_miss_probe = f;
486 else if (id == nfscl_accesscache_load_done_id)
487 dtrace_nfscl_accesscache_load_done_probe = f;
488 else if (id == nfscl_attrcache_flush_done_id)
489 dtrace_nfscl_attrcache_flush_done_probe = f;
490 else if (id == nfscl_attrcache_get_hit_id)
491 dtrace_nfscl_attrcache_get_hit_probe = f;
492 else if (id == nfscl_attrcache_get_miss_id)
493 dtrace_nfscl_attrcache_get_miss_probe = f;
494 else if (id == nfscl_attrcache_load_done_id)
495 dtrace_nfscl_attrcache_load_done_probe = f;
496 else
497 *p = id;
498 }
499
500 static void
dtnfsclient_disable(void * arg,dtrace_id_t id,void * parg)501 dtnfsclient_disable(void *arg, dtrace_id_t id, void *parg)
502 {
503 uint32_t *p = parg;
504
505 if (id == nfscl_accesscache_flush_done_id)
506 dtrace_nfscl_accesscache_flush_done_probe = NULL;
507 else if (id == nfscl_accesscache_get_hit_id)
508 dtrace_nfscl_accesscache_get_hit_probe = NULL;
509 else if (id == nfscl_accesscache_get_miss_id)
510 dtrace_nfscl_accesscache_get_miss_probe = NULL;
511 else if (id == nfscl_accesscache_load_done_id)
512 dtrace_nfscl_accesscache_load_done_probe = NULL;
513 else if (id == nfscl_attrcache_flush_done_id)
514 dtrace_nfscl_attrcache_flush_done_probe = NULL;
515 else if (id == nfscl_attrcache_get_hit_id)
516 dtrace_nfscl_attrcache_get_hit_probe = NULL;
517 else if (id == nfscl_attrcache_get_miss_id)
518 dtrace_nfscl_attrcache_get_miss_probe = NULL;
519 else if (id == nfscl_attrcache_load_done_id)
520 dtrace_nfscl_attrcache_load_done_probe = NULL;
521 else
522 *p = 0;
523 }
524
525 static void
dtnfsclient_load(void * dummy)526 dtnfsclient_load(void *dummy)
527 {
528
529 if (dtrace_register("nfscl", &dtnfsclient_attr,
530 DTRACE_PRIV_USER, NULL, &dtnfsclient_pops, NULL,
531 &dtnfsclient_id) != 0)
532 return;
533
534 dtrace_nfscl_nfs234_start_probe =
535 (dtrace_nfsclient_nfs23_start_probe_func_t)dtrace_probe;
536 dtrace_nfscl_nfs234_done_probe =
537 (dtrace_nfsclient_nfs23_done_probe_func_t)dtrace_probe;
538 }
539
540 static int
dtnfsclient_unload(void)541 dtnfsclient_unload(void)
542 {
543
544 dtrace_nfscl_nfs234_start_probe = NULL;
545 dtrace_nfscl_nfs234_done_probe = NULL;
546
547 return (dtrace_unregister(dtnfsclient_id));
548 }
549
550 static int
dtnfsclient_modevent(module_t mod __unused,int type,void * data __unused)551 dtnfsclient_modevent(module_t mod __unused, int type, void *data __unused)
552 {
553 int error = 0;
554
555 switch (type) {
556 case MOD_LOAD:
557 break;
558
559 case MOD_UNLOAD:
560 break;
561
562 case MOD_SHUTDOWN:
563 break;
564
565 default:
566 error = EOPNOTSUPP;
567 break;
568 }
569
570 return (error);
571 }
572
573 SYSINIT(dtnfsclient_load, SI_SUB_DTRACE_PROVIDER, SI_ORDER_ANY,
574 dtnfsclient_load, NULL);
575 SYSUNINIT(dtnfsclient_unload, SI_SUB_DTRACE_PROVIDER, SI_ORDER_ANY,
576 dtnfsclient_unload, NULL);
577
578 DEV_MODULE(dtnfscl, dtnfsclient_modevent, NULL);
579 MODULE_VERSION(dtnfscl, 1);
580 MODULE_DEPEND(dtnfscl, dtrace, 1, 1, 1);
581 MODULE_DEPEND(dtnfscl, opensolaris, 1, 1, 1);
582 MODULE_DEPEND(dtnfscl, nfscl, 1, 1, 1);
583 MODULE_DEPEND(dtnfscl, nfscommon, 1, 1, 1);
584