1 /*- 2 * Copyright (c) 2009 Robert N. M. Watson 3 * All rights reserved. 4 * 5 * This software was developed at the University of Cambridge Computer 6 * Laboratory with support from a grant from Google, Inc. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27 * SUCH DAMAGE. 28 */ 29 30 #include <sys/cdefs.h> 31 __FBSDID("$FreeBSD$"); 32 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 acess 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 dtnfsclient_provide, 166 NULL, 167 dtnfsclient_enable, 168 dtnfsclient_disable, 169 NULL, 170 NULL, 171 dtnfsclient_getargdesc, 172 NULL, 173 NULL, 174 dtnfsclient_destroy 175 }; 176 177 static dtrace_provider_id_t dtnfsclient_id; 178 179 /* 180 * Most probes are generated from the above RPC table, but for access and 181 * attribute caches, we have specific IDs we recognize and handle specially 182 * in various spots. 183 */ 184 extern uint32_t nfscl_accesscache_flush_done_id; 185 extern uint32_t nfscl_accesscache_get_hit_id; 186 extern uint32_t nfscl_accesscache_get_miss_id; 187 extern uint32_t nfscl_accesscache_load_done_id; 188 189 extern uint32_t nfscl_attrcache_flush_done_id; 190 extern uint32_t nfscl_attrcache_get_hit_id; 191 extern uint32_t nfscl_attrcache_get_miss_id; 192 extern uint32_t nfscl_attrcache_load_done_id; 193 194 /* 195 * When tracing on a procedure is enabled, the DTrace ID for an RPC event is 196 * stored in one of these two NFS client-allocated arrays; 0 indicates that 197 * the event is not being traced so probes should not be called. 198 * 199 * For simplicity, we allocate both v2, v3 and v4 arrays as NFSV41_NPROCS + 1, 200 * and the v2, v3 arrays are simply sparse. 201 */ 202 extern uint32_t nfscl_nfs2_start_probes[NFSV41_NPROCS + 1]; 203 extern uint32_t nfscl_nfs2_done_probes[NFSV41_NPROCS + 1]; 204 205 extern uint32_t nfscl_nfs3_start_probes[NFSV41_NPROCS + 1]; 206 extern uint32_t nfscl_nfs3_done_probes[NFSV41_NPROCS + 1]; 207 208 extern uint32_t nfscl_nfs4_start_probes[NFSV41_NPROCS + 1]; 209 extern uint32_t nfscl_nfs4_done_probes[NFSV41_NPROCS + 1]; 210 211 /* 212 * Look up a DTrace probe ID to see if it's associated with a "done" event -- 213 * if so, we will return a fourth argument type of "int". 214 */ 215 static int 216 dtnfs234_isdoneprobe(dtrace_id_t id) 217 { 218 int i; 219 220 for (i = 0; i < NFSV41_NPROCS + 1; i++) { 221 if (dtnfsclient_rpcs[i].nr_v4_id_done == id || 222 dtnfsclient_rpcs[i].nr_v3_id_done == id || 223 dtnfsclient_rpcs[i].nr_v2_id_done == id) 224 return (1); 225 } 226 return (0); 227 } 228 229 static void 230 dtnfsclient_getargdesc(void *arg, dtrace_id_t id, void *parg, 231 dtrace_argdesc_t *desc) 232 { 233 const char *p = NULL; 234 235 if (id == nfscl_accesscache_flush_done_id || 236 id == nfscl_attrcache_flush_done_id || 237 id == nfscl_attrcache_get_miss_id) { 238 switch (desc->dtargd_ndx) { 239 case 0: 240 p = "struct vnode *"; 241 break; 242 default: 243 desc->dtargd_ndx = DTRACE_ARGNONE; 244 break; 245 } 246 } else if (id == nfscl_accesscache_get_hit_id || 247 id == nfscl_accesscache_get_miss_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 default: 259 desc->dtargd_ndx = DTRACE_ARGNONE; 260 break; 261 } 262 } else if (id == nfscl_accesscache_load_done_id) { 263 switch (desc->dtargd_ndx) { 264 case 0: 265 p = "struct vnode *"; 266 break; 267 case 1: 268 p = "uid_t"; 269 break; 270 case 2: 271 p = "uint32_t"; 272 break; 273 case 3: 274 p = "int"; 275 break; 276 default: 277 desc->dtargd_ndx = DTRACE_ARGNONE; 278 break; 279 } 280 } else if (id == nfscl_attrcache_get_hit_id) { 281 switch (desc->dtargd_ndx) { 282 case 0: 283 p = "struct vnode *"; 284 break; 285 case 1: 286 p = "struct vattr *"; 287 break; 288 default: 289 desc->dtargd_ndx = DTRACE_ARGNONE; 290 break; 291 } 292 } else if (id == nfscl_attrcache_load_done_id) { 293 switch (desc->dtargd_ndx) { 294 case 0: 295 p = "struct vnode *"; 296 break; 297 case 1: 298 p = "struct vattr *"; 299 break; 300 case 2: 301 p = "int"; 302 break; 303 default: 304 desc->dtargd_ndx = DTRACE_ARGNONE; 305 break; 306 } 307 } else { 308 switch (desc->dtargd_ndx) { 309 case 0: 310 p = "struct vnode *"; 311 break; 312 case 1: 313 p = "struct mbuf *"; 314 break; 315 case 2: 316 p = "struct ucred *"; 317 break; 318 case 3: 319 p = "int"; 320 break; 321 case 4: 322 if (dtnfs234_isdoneprobe(id)) { 323 p = "int"; 324 break; 325 } 326 /* FALLSTHROUGH */ 327 default: 328 desc->dtargd_ndx = DTRACE_ARGNONE; 329 break; 330 } 331 } 332 if (p != NULL) 333 strlcpy(desc->dtargd_native, p, sizeof(desc->dtargd_native)); 334 } 335 336 static void 337 dtnfsclient_provide(void *arg, dtrace_probedesc_t *desc) 338 { 339 int i; 340 341 if (desc != NULL) 342 return; 343 344 /* 345 * Register access cache probes. 346 */ 347 if (dtrace_probe_lookup(dtnfsclient_id, dtnfsclient_accesscache_str, 348 dtnfsclient_flush_str, dtnfsclient_done_str) == 0) { 349 nfscl_accesscache_flush_done_id = dtrace_probe_create( 350 dtnfsclient_id, dtnfsclient_accesscache_str, 351 dtnfsclient_flush_str, dtnfsclient_done_str, 0, NULL); 352 } 353 if (dtrace_probe_lookup(dtnfsclient_id, dtnfsclient_accesscache_str, 354 dtnfsclient_get_str, dtnfsclient_hit_str) == 0) { 355 nfscl_accesscache_get_hit_id = dtrace_probe_create( 356 dtnfsclient_id, dtnfsclient_accesscache_str, 357 dtnfsclient_get_str, dtnfsclient_hit_str, 0, NULL); 358 } 359 if (dtrace_probe_lookup(dtnfsclient_id, dtnfsclient_accesscache_str, 360 dtnfsclient_get_str, dtnfsclient_miss_str) == 0) { 361 nfscl_accesscache_get_miss_id = dtrace_probe_create( 362 dtnfsclient_id, dtnfsclient_accesscache_str, 363 dtnfsclient_get_str, dtnfsclient_miss_str, 0, NULL); 364 } 365 if (dtrace_probe_lookup(dtnfsclient_id, dtnfsclient_accesscache_str, 366 dtnfsclient_load_str, dtnfsclient_done_str) == 0) { 367 nfscl_accesscache_load_done_id = dtrace_probe_create( 368 dtnfsclient_id, dtnfsclient_accesscache_str, 369 dtnfsclient_load_str, dtnfsclient_done_str, 0, NULL); 370 } 371 372 /* 373 * Register attribute cache probes. 374 */ 375 if (dtrace_probe_lookup(dtnfsclient_id, dtnfsclient_attrcache_str, 376 dtnfsclient_flush_str, dtnfsclient_done_str) == 0) { 377 nfscl_attrcache_flush_done_id = dtrace_probe_create( 378 dtnfsclient_id, dtnfsclient_attrcache_str, 379 dtnfsclient_flush_str, dtnfsclient_done_str, 0, NULL); 380 } 381 if (dtrace_probe_lookup(dtnfsclient_id, dtnfsclient_attrcache_str, 382 dtnfsclient_get_str, dtnfsclient_hit_str) == 0) { 383 nfscl_attrcache_get_hit_id = dtrace_probe_create( 384 dtnfsclient_id, dtnfsclient_attrcache_str, 385 dtnfsclient_get_str, dtnfsclient_hit_str, 0, NULL); 386 } 387 if (dtrace_probe_lookup(dtnfsclient_id, dtnfsclient_attrcache_str, 388 dtnfsclient_get_str, dtnfsclient_miss_str) == 0) { 389 nfscl_attrcache_get_miss_id = dtrace_probe_create( 390 dtnfsclient_id, dtnfsclient_attrcache_str, 391 dtnfsclient_get_str, dtnfsclient_miss_str, 0, NULL); 392 } 393 if (dtrace_probe_lookup(dtnfsclient_id, dtnfsclient_attrcache_str, 394 dtnfsclient_load_str, dtnfsclient_done_str) == 0) { 395 nfscl_attrcache_load_done_id = dtrace_probe_create( 396 dtnfsclient_id, dtnfsclient_attrcache_str, 397 dtnfsclient_load_str, dtnfsclient_done_str, 0, NULL); 398 } 399 400 /* 401 * Register NFSv2 RPC procedures; note sparseness check for each slot 402 * in the NFSv3, NFSv4 procnum-indexed array. 403 */ 404 for (i = 0; i < NFSV41_NPROCS + 1; i++) { 405 if (dtnfsclient_rpcs[i].nr_v2_name != NULL && 406 dtrace_probe_lookup(dtnfsclient_id, dtnfsclient_nfs2_str, 407 dtnfsclient_rpcs[i].nr_v2_name, dtnfsclient_start_str) == 408 0) { 409 dtnfsclient_rpcs[i].nr_v2_id_start = 410 dtrace_probe_create(dtnfsclient_id, 411 dtnfsclient_nfs2_str, 412 dtnfsclient_rpcs[i].nr_v2_name, 413 dtnfsclient_start_str, 0, 414 &nfscl_nfs2_start_probes[i]); 415 } 416 if (dtnfsclient_rpcs[i].nr_v2_name != NULL && 417 dtrace_probe_lookup(dtnfsclient_id, dtnfsclient_nfs2_str, 418 dtnfsclient_rpcs[i].nr_v2_name, dtnfsclient_done_str) == 419 0) { 420 dtnfsclient_rpcs[i].nr_v2_id_done = 421 dtrace_probe_create(dtnfsclient_id, 422 dtnfsclient_nfs2_str, 423 dtnfsclient_rpcs[i].nr_v2_name, 424 dtnfsclient_done_str, 0, 425 &nfscl_nfs2_done_probes[i]); 426 } 427 } 428 429 /* 430 * Register NFSv3 RPC procedures; note sparseness check for each slot 431 * in the NFSv4 procnum-indexed array. 432 */ 433 for (i = 0; i < NFSV41_NPROCS + 1; i++) { 434 if (dtnfsclient_rpcs[i].nr_v3_name != NULL && 435 dtrace_probe_lookup(dtnfsclient_id, dtnfsclient_nfs3_str, 436 dtnfsclient_rpcs[i].nr_v3_name, dtnfsclient_start_str) == 437 0) { 438 dtnfsclient_rpcs[i].nr_v3_id_start = 439 dtrace_probe_create(dtnfsclient_id, 440 dtnfsclient_nfs3_str, 441 dtnfsclient_rpcs[i].nr_v3_name, 442 dtnfsclient_start_str, 0, 443 &nfscl_nfs3_start_probes[i]); 444 } 445 if (dtnfsclient_rpcs[i].nr_v3_name != NULL && 446 dtrace_probe_lookup(dtnfsclient_id, dtnfsclient_nfs3_str, 447 dtnfsclient_rpcs[i].nr_v3_name, dtnfsclient_done_str) == 448 0) { 449 dtnfsclient_rpcs[i].nr_v3_id_done = 450 dtrace_probe_create(dtnfsclient_id, 451 dtnfsclient_nfs3_str, 452 dtnfsclient_rpcs[i].nr_v3_name, 453 dtnfsclient_done_str, 0, 454 &nfscl_nfs3_done_probes[i]); 455 } 456 } 457 458 /* 459 * Register NFSv4 RPC procedures. 460 */ 461 for (i = 0; i < NFSV41_NPROCS + 1; i++) { 462 if (dtrace_probe_lookup(dtnfsclient_id, dtnfsclient_nfs4_str, 463 dtnfsclient_rpcs[i].nr_v4_name, dtnfsclient_start_str) == 464 0) { 465 dtnfsclient_rpcs[i].nr_v4_id_start = 466 dtrace_probe_create(dtnfsclient_id, 467 dtnfsclient_nfs4_str, 468 dtnfsclient_rpcs[i].nr_v4_name, 469 dtnfsclient_start_str, 0, 470 &nfscl_nfs4_start_probes[i]); 471 } 472 if (dtrace_probe_lookup(dtnfsclient_id, dtnfsclient_nfs4_str, 473 dtnfsclient_rpcs[i].nr_v4_name, dtnfsclient_done_str) == 474 0) { 475 dtnfsclient_rpcs[i].nr_v4_id_done = 476 dtrace_probe_create(dtnfsclient_id, 477 dtnfsclient_nfs4_str, 478 dtnfsclient_rpcs[i].nr_v4_name, 479 dtnfsclient_done_str, 0, 480 &nfscl_nfs4_done_probes[i]); 481 } 482 } 483 } 484 485 static void 486 dtnfsclient_destroy(void *arg, dtrace_id_t id, void *parg) 487 { 488 } 489 490 static void 491 dtnfsclient_enable(void *arg, dtrace_id_t id, void *parg) 492 { 493 uint32_t *p = parg; 494 void *f = dtrace_probe; 495 496 if (id == nfscl_accesscache_flush_done_id) 497 dtrace_nfscl_accesscache_flush_done_probe = f; 498 else if (id == nfscl_accesscache_get_hit_id) 499 dtrace_nfscl_accesscache_get_hit_probe = f; 500 else if (id == nfscl_accesscache_get_miss_id) 501 dtrace_nfscl_accesscache_get_miss_probe = f; 502 else if (id == nfscl_accesscache_load_done_id) 503 dtrace_nfscl_accesscache_load_done_probe = f; 504 else if (id == nfscl_attrcache_flush_done_id) 505 dtrace_nfscl_attrcache_flush_done_probe = f; 506 else if (id == nfscl_attrcache_get_hit_id) 507 dtrace_nfscl_attrcache_get_hit_probe = f; 508 else if (id == nfscl_attrcache_get_miss_id) 509 dtrace_nfscl_attrcache_get_miss_probe = f; 510 else if (id == nfscl_attrcache_load_done_id) 511 dtrace_nfscl_attrcache_load_done_probe = f; 512 else 513 *p = id; 514 } 515 516 static void 517 dtnfsclient_disable(void *arg, dtrace_id_t id, void *parg) 518 { 519 uint32_t *p = parg; 520 521 if (id == nfscl_accesscache_flush_done_id) 522 dtrace_nfscl_accesscache_flush_done_probe = NULL; 523 else if (id == nfscl_accesscache_get_hit_id) 524 dtrace_nfscl_accesscache_get_hit_probe = NULL; 525 else if (id == nfscl_accesscache_get_miss_id) 526 dtrace_nfscl_accesscache_get_miss_probe = NULL; 527 else if (id == nfscl_accesscache_load_done_id) 528 dtrace_nfscl_accesscache_load_done_probe = NULL; 529 else if (id == nfscl_attrcache_flush_done_id) 530 dtrace_nfscl_attrcache_flush_done_probe = NULL; 531 else if (id == nfscl_attrcache_get_hit_id) 532 dtrace_nfscl_attrcache_get_hit_probe = NULL; 533 else if (id == nfscl_attrcache_get_miss_id) 534 dtrace_nfscl_attrcache_get_miss_probe = NULL; 535 else if (id == nfscl_attrcache_load_done_id) 536 dtrace_nfscl_attrcache_load_done_probe = NULL; 537 else 538 *p = 0; 539 } 540 541 static void 542 dtnfsclient_load(void *dummy) 543 { 544 545 if (dtrace_register("nfscl", &dtnfsclient_attr, 546 DTRACE_PRIV_USER, NULL, &dtnfsclient_pops, NULL, 547 &dtnfsclient_id) != 0) 548 return; 549 550 dtrace_nfscl_nfs234_start_probe = 551 (dtrace_nfsclient_nfs23_start_probe_func_t)dtrace_probe; 552 dtrace_nfscl_nfs234_done_probe = 553 (dtrace_nfsclient_nfs23_done_probe_func_t)dtrace_probe; 554 } 555 556 557 static int 558 dtnfsclient_unload() 559 { 560 561 dtrace_nfscl_nfs234_start_probe = NULL; 562 dtrace_nfscl_nfs234_done_probe = NULL; 563 564 return (dtrace_unregister(dtnfsclient_id)); 565 } 566 567 static int 568 dtnfsclient_modevent(module_t mod __unused, int type, void *data __unused) 569 { 570 int error = 0; 571 572 switch (type) { 573 case MOD_LOAD: 574 break; 575 576 case MOD_UNLOAD: 577 break; 578 579 case MOD_SHUTDOWN: 580 break; 581 582 default: 583 error = EOPNOTSUPP; 584 break; 585 } 586 587 return (error); 588 } 589 590 SYSINIT(dtnfsclient_load, SI_SUB_DTRACE_PROVIDER, SI_ORDER_ANY, 591 dtnfsclient_load, NULL); 592 SYSUNINIT(dtnfsclient_unload, SI_SUB_DTRACE_PROVIDER, SI_ORDER_ANY, 593 dtnfsclient_unload, NULL); 594 595 DEV_MODULE(dtnfscl, dtnfsclient_modevent, NULL); 596 MODULE_VERSION(dtnfscl, 1); 597 MODULE_DEPEND(dtnfscl, dtrace, 1, 1, 1); 598 MODULE_DEPEND(dtnfscl, opensolaris, 1, 1, 1); 599 MODULE_DEPEND(dtnfscl, nfscl, 1, 1, 1); 600 MODULE_DEPEND(dtnfscl, nfscommon, 1, 1, 1); 601