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