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