Home | History | Annotate | Line # | Download | only in client
      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