xref: /freebsd/sys/fs/nfsclient/nfs_clkdtrace.c (revision 397e83df75e0fcd0d3fcb95ae4d794cb7600fc89)
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
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
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
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
470 dtnfsclient_destroy(void *arg, dtrace_id_t id, void *parg)
471 {
472 }
473 
474 static void
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
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
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
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
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