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