1190293Srwatson/*-
2190293Srwatson * Copyright (c) 2009 Robert N. M. Watson
3190293Srwatson * All rights reserved.
4190293Srwatson *
5190293Srwatson * This software was developed at the University of Cambridge Computer
6190293Srwatson * Laboratory with support from a grant from Google, Inc.
7190293Srwatson *
8190293Srwatson * Redistribution and use in source and binary forms, with or without
9190293Srwatson * modification, are permitted provided that the following conditions
10190293Srwatson * are met:
11190293Srwatson * 1. Redistributions of source code must retain the above copyright
12190293Srwatson *    notice, this list of conditions and the following disclaimer.
13190293Srwatson * 2. Redistributions in binary form must reproduce the above copyright
14190293Srwatson *    notice, this list of conditions and the following disclaimer in the
15190293Srwatson *    documentation and/or other materials provided with the distribution.
16190293Srwatson *
17190293Srwatson * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18190293Srwatson * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19190293Srwatson * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20190293Srwatson * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
21190293Srwatson * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22190293Srwatson * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23190293Srwatson * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24190293Srwatson * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25190293Srwatson * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26190293Srwatson * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27190293Srwatson * SUCH DAMAGE.
28190293Srwatson */
29190293Srwatson
30190293Srwatson#include <sys/cdefs.h>
31190293Srwatson__FBSDID("$FreeBSD$");
32190293Srwatson
33190293Srwatson#include <sys/param.h>
34190293Srwatson#include <sys/systm.h>
35190293Srwatson#include <sys/conf.h>
36190293Srwatson#include <sys/kernel.h>
37190293Srwatson#include <sys/malloc.h>
38190293Srwatson#include <sys/module.h>
39190293Srwatson
40190293Srwatson#include <sys/dtrace.h>
41190293Srwatson#include <sys/dtrace_bsd.h>
42190293Srwatson
43190293Srwatson#include <nfs/nfsproto.h>
44190293Srwatson
45190293Srwatson/*
46190293Srwatson * dtnfsclient is a DTrace provider that tracks the intent to perform RPCs
47190380Srwatson * in the NFS client, as well as acess to and maintenance of the access and
48190380Srwatson * attribute caches.  This is not quite the same as RPCs, because NFS may
49190293Srwatson * issue multiple RPC transactions in the event that authentication fails,
50190380Srwatson * there's a jukebox error, or none at all if the access or attribute cache
51190380Srwatson * hits.  However, it cleanly represents the logical layer between RPC
52190380Srwatson * transmission and vnode/vfs operations, providing access to state linking
53190380Srwatson * the two.
54190293Srwatson */
55190293Srwatson
56190293Srwatsonstatic int	dtnfsclient_unload(void);
57190293Srwatsonstatic void	dtnfsclient_getargdesc(void *, dtrace_id_t, void *,
58190293Srwatson		    dtrace_argdesc_t *);
59190293Srwatsonstatic void	dtnfsclient_provide(void *, dtrace_probedesc_t *);
60190293Srwatsonstatic void	dtnfsclient_destroy(void *, dtrace_id_t, void *);
61190293Srwatsonstatic void	dtnfsclient_enable(void *, dtrace_id_t, void *);
62190293Srwatsonstatic void	dtnfsclient_disable(void *, dtrace_id_t, void *);
63190293Srwatsonstatic void	dtnfsclient_load(void *);
64190293Srwatson
65190293Srwatsonstatic dtrace_pattr_t dtnfsclient_attr = {
66190293Srwatson{ DTRACE_STABILITY_STABLE, DTRACE_STABILITY_STABLE, DTRACE_CLASS_COMMON },
67190293Srwatson{ DTRACE_STABILITY_PRIVATE, DTRACE_STABILITY_PRIVATE, DTRACE_CLASS_UNKNOWN },
68190293Srwatson{ DTRACE_STABILITY_PRIVATE, DTRACE_STABILITY_PRIVATE, DTRACE_CLASS_UNKNOWN },
69190293Srwatson{ DTRACE_STABILITY_STABLE, DTRACE_STABILITY_STABLE, DTRACE_CLASS_COMMON },
70190293Srwatson{ DTRACE_STABILITY_STABLE, DTRACE_STABILITY_STABLE, DTRACE_CLASS_COMMON },
71190293Srwatson};
72190293Srwatson
73190380Srwatson/*
74191776Srwatson * Description of NFSv3 and (optional) NFSv2 probes for a procedure.
75190380Srwatson */
76190293Srwatsonstruct dtnfsclient_rpc {
77190293Srwatson	char		*nr_v3_name;
78190293Srwatson	char		*nr_v2_name;	/* Or NULL if none. */
79190293Srwatson
80190293Srwatson	/*
81190293Srwatson	 * IDs for the start and done cases, for both NFSv2 and NFSv3.
82190293Srwatson	 */
83190293Srwatson	uint32_t	 nr_v2_id_start, nr_v2_id_done;
84190293Srwatson	uint32_t	 nr_v3_id_start, nr_v3_id_done;
85190293Srwatson};
86190293Srwatson
87190293Srwatson/*
88190293Srwatson * This table is indexed by NFSv3 procedure number, but also used for NFSv2
89190293Srwatson * procedure names.
90190293Srwatson */
91190293Srwatsonstatic struct dtnfsclient_rpc	dtnfsclient_rpcs[NFS_NPROCS] = {
92190293Srwatson	{ "null", "null" },
93190293Srwatson	{ "getattr", "getattr" },
94190293Srwatson	{ "setattr", "setattr" },
95190293Srwatson	{ "lookup", "lookup" },
96190293Srwatson	{ "access" },
97190293Srwatson	{ "readlink", "readlink" },
98190293Srwatson	{ "read", "read" },
99190293Srwatson	{ "write", "write" },
100190293Srwatson	{ "create", "create" },
101190293Srwatson	{ "mkdir", "mkdir" },
102190293Srwatson	{ "symlink", "symlink" },
103190293Srwatson	{ "mknod" },
104190293Srwatson	{ "remove", "remove" },
105190293Srwatson	{ "rmdir", "rmdir" },
106190293Srwatson	{ "rename", "rename" },
107190293Srwatson	{ "link", "link" },
108190293Srwatson	{ "readdir", "readdir" },
109190293Srwatson	{ "readdirplus" },
110190293Srwatson	{ "fsstat", "statfs" },
111190293Srwatson	{ "fsinfo" },
112190293Srwatson	{ "pathconf" },
113190293Srwatson	{ "commit" },
114190293Srwatson	{ "noop" },
115190293Srwatson};
116190293Srwatson
117190380Srwatson/*
118190380Srwatson * Module name strings.
119190380Srwatson */
120190380Srwatsonstatic char	*dtnfsclient_accesscache_str = "accesscache";
121190380Srwatsonstatic char	*dtnfsclient_attrcache_str = "attrcache";
122190380Srwatsonstatic char	*dtnfsclient_nfs2_str = "nfs2";
123190380Srwatsonstatic char	*dtnfsclient_nfs3_str = "nfs3";
124190293Srwatson
125190380Srwatson/*
126190380Srwatson * Function name strings.
127190380Srwatson */
128190380Srwatsonstatic char	*dtnfsclient_flush_str = "flush";
129190380Srwatsonstatic char	*dtnfsclient_load_str = "load";
130190380Srwatsonstatic char	*dtnfsclient_get_str = "get";
131190293Srwatson
132190380Srwatson/*
133190380Srwatson * Name strings.
134190380Srwatson */
135190380Srwatsonstatic char	*dtnfsclient_done_str = "done";
136190380Srwatsonstatic char	*dtnfsclient_hit_str = "hit";
137190380Srwatsonstatic char	*dtnfsclient_miss_str = "miss";
138190380Srwatsonstatic char	*dtnfsclient_start_str = "start";
139190380Srwatson
140190293Srwatsonstatic dtrace_pops_t dtnfsclient_pops = {
141190293Srwatson	dtnfsclient_provide,
142190293Srwatson	NULL,
143190293Srwatson	dtnfsclient_enable,
144190293Srwatson	dtnfsclient_disable,
145190293Srwatson	NULL,
146190293Srwatson	NULL,
147190293Srwatson	dtnfsclient_getargdesc,
148190293Srwatson	NULL,
149190293Srwatson	NULL,
150190293Srwatson	dtnfsclient_destroy
151190293Srwatson};
152190293Srwatson
153190293Srwatsonstatic dtrace_provider_id_t	dtnfsclient_id;
154190293Srwatson
155190293Srwatson/*
156190380Srwatson * Most probes are generated from the above RPC table, but for access and
157190380Srwatson * attribute caches, we have specific IDs we recognize and handle specially
158190380Srwatson * in various spots.
159190380Srwatson */
160190380Srwatsonextern uint32_t	nfsclient_accesscache_flush_done_id;
161190380Srwatsonextern uint32_t	nfsclient_accesscache_get_hit_id;
162190380Srwatsonextern uint32_t	nfsclient_accesscache_get_miss_id;
163190380Srwatsonextern uint32_t	nfsclient_accesscache_load_done_id;
164190380Srwatson
165190380Srwatsonextern uint32_t	nfsclient_attrcache_flush_done_id;
166190380Srwatsonextern uint32_t	nfsclient_attrcache_get_hit_id;
167190380Srwatsonextern uint32_t	nfsclient_attrcache_get_miss_id;
168190380Srwatsonextern uint32_t	nfsclient_attrcache_load_done_id;
169190380Srwatson
170190380Srwatson/*
171190380Srwatson * When tracing on a procedure is enabled, the DTrace ID for an RPC event is
172190293Srwatson * stored in one of these two NFS client-allocated arrays; 0 indicates that
173190293Srwatson * the event is not being traced so probes should not be called.
174190293Srwatson *
175190293Srwatson * For simplicity, we allocate both v2 and v3 arrays as NFS_NPROCS, and the
176190293Srwatson * v2 array is simply sparse.
177190293Srwatson */
178190293Srwatsonextern uint32_t			nfsclient_nfs2_start_probes[NFS_NPROCS];
179190293Srwatsonextern uint32_t			nfsclient_nfs2_done_probes[NFS_NPROCS];
180190293Srwatson
181190293Srwatsonextern uint32_t			nfsclient_nfs3_start_probes[NFS_NPROCS];
182190293Srwatsonextern uint32_t			nfsclient_nfs3_done_probes[NFS_NPROCS];
183190293Srwatson
184190293Srwatson/*
185190293Srwatson * Look up a DTrace probe ID to see if it's associated with a "done" event --
186190293Srwatson * if so, we will return a fourth argument type of "int".
187190293Srwatson */
188190293Srwatsonstatic int
189190293Srwatsondtnfs23_isdoneprobe(dtrace_id_t id)
190190293Srwatson{
191190293Srwatson	int i;
192190293Srwatson
193190293Srwatson	for (i = 0; i < NFS_NPROCS; i++) {
194190293Srwatson		if (dtnfsclient_rpcs[i].nr_v3_id_done == id ||
195190293Srwatson		    dtnfsclient_rpcs[i].nr_v2_id_done == id)
196190293Srwatson			return (1);
197190293Srwatson	}
198190293Srwatson	return (0);
199190293Srwatson}
200190293Srwatson
201190293Srwatsonstatic void
202190293Srwatsondtnfsclient_getargdesc(void *arg, dtrace_id_t id, void *parg,
203190293Srwatson    dtrace_argdesc_t *desc)
204190293Srwatson{
205190293Srwatson	const char *p = NULL;
206190293Srwatson
207190380Srwatson	if (id == nfsclient_accesscache_flush_done_id ||
208190380Srwatson	    id == nfsclient_attrcache_flush_done_id ||
209190380Srwatson	    id == nfsclient_attrcache_get_miss_id) {
210190380Srwatson		switch (desc->dtargd_ndx) {
211190380Srwatson		case 0:
212190380Srwatson			p = "struct vnode *";
213190380Srwatson			break;
214190380Srwatson		default:
215190380Srwatson			desc->dtargd_ndx = DTRACE_ARGNONE;
216190380Srwatson			break;
217190380Srwatson		}
218190380Srwatson	} else if (id == nfsclient_accesscache_get_hit_id ||
219190380Srwatson	    id == nfsclient_accesscache_get_miss_id) {
220190380Srwatson		switch (desc->dtargd_ndx) {
221190380Srwatson		case 0:
222190380Srwatson			p = "struct vnode *";
223190380Srwatson			break;
224190380Srwatson		case 1:
225190380Srwatson			p = "uid_t";
226190380Srwatson			break;
227190380Srwatson		case 2:
228190380Srwatson			p = "uint32_t";
229190380Srwatson			break;
230190380Srwatson		default:
231190380Srwatson			desc->dtargd_ndx = DTRACE_ARGNONE;
232190380Srwatson			break;
233190380Srwatson		}
234190380Srwatson	} else if (id == nfsclient_accesscache_load_done_id) {
235190380Srwatson		switch (desc->dtargd_ndx) {
236190380Srwatson		case 0:
237190380Srwatson			p = "struct vnode *";
238190380Srwatson			break;
239190380Srwatson		case 1:
240190380Srwatson			p = "uid_t";
241190380Srwatson			break;
242190380Srwatson		case 2:
243190380Srwatson			p = "uint32_t";
244190380Srwatson			break;
245190380Srwatson		case 3:
246190293Srwatson			p = "int";
247190293Srwatson			break;
248190380Srwatson		default:
249190380Srwatson			desc->dtargd_ndx = DTRACE_ARGNONE;
250190380Srwatson			break;
251190293Srwatson		}
252190380Srwatson	} else if (id == nfsclient_attrcache_get_hit_id) {
253190380Srwatson		switch (desc->dtargd_ndx) {
254190380Srwatson		case 0:
255190380Srwatson			p = "struct vnode *";
256190380Srwatson			break;
257190380Srwatson		case 1:
258190380Srwatson			p = "struct vattr *";
259190380Srwatson			break;
260190380Srwatson		default:
261190380Srwatson			desc->dtargd_ndx = DTRACE_ARGNONE;
262190380Srwatson			break;
263190380Srwatson		}
264190380Srwatson	} else if (id == nfsclient_attrcache_load_done_id) {
265190380Srwatson		switch (desc->dtargd_ndx) {
266190380Srwatson		case 0:
267190380Srwatson			p = "struct vnode *";
268190380Srwatson			break;
269190380Srwatson		case 1:
270190380Srwatson			p = "struct vattr *";
271190380Srwatson			break;
272190380Srwatson		case 2:
273190380Srwatson			p = "int";
274190380Srwatson			break;
275190380Srwatson		default:
276190380Srwatson			desc->dtargd_ndx = DTRACE_ARGNONE;
277190380Srwatson			break;
278190380Srwatson		}
279190380Srwatson	} else {
280190380Srwatson		switch (desc->dtargd_ndx) {
281190380Srwatson		case 0:
282190380Srwatson			p = "struct vnode *";
283190380Srwatson			break;
284190380Srwatson		case 1:
285190380Srwatson			p = "struct mbuf *";
286190380Srwatson			break;
287190380Srwatson		case 2:
288190380Srwatson			p = "struct ucred *";
289190380Srwatson			break;
290190380Srwatson		case 3:
291190380Srwatson			p = "int";
292190380Srwatson			break;
293190380Srwatson		case 4:
294190380Srwatson			if (dtnfs23_isdoneprobe(id)) {
295190380Srwatson				p = "int";
296190380Srwatson				break;
297190380Srwatson			}
298190380Srwatson			/* FALLSTHROUGH */
299190380Srwatson		default:
300190380Srwatson			desc->dtargd_ndx = DTRACE_ARGNONE;
301190380Srwatson			break;
302190380Srwatson		}
303190293Srwatson	}
304190293Srwatson	if (p != NULL)
305190293Srwatson		strlcpy(desc->dtargd_native, p, sizeof(desc->dtargd_native));
306190293Srwatson}
307190293Srwatson
308190293Srwatsonstatic void
309190293Srwatsondtnfsclient_provide(void *arg, dtrace_probedesc_t *desc)
310190293Srwatson{
311190293Srwatson	int i;
312190293Srwatson
313190293Srwatson	if (desc != NULL)
314190293Srwatson		return;
315190293Srwatson
316190293Srwatson	/*
317190380Srwatson	 * Register access cache probes.
318190293Srwatson	 */
319190380Srwatson	if (dtrace_probe_lookup(dtnfsclient_id, dtnfsclient_accesscache_str,
320190380Srwatson	    dtnfsclient_flush_str, dtnfsclient_done_str) == 0) {
321190380Srwatson		nfsclient_accesscache_flush_done_id = dtrace_probe_create(
322190380Srwatson		    dtnfsclient_id, dtnfsclient_accesscache_str,
323190380Srwatson		    dtnfsclient_flush_str, dtnfsclient_done_str, 0, NULL);
324190380Srwatson	}
325190380Srwatson	if (dtrace_probe_lookup(dtnfsclient_id, dtnfsclient_accesscache_str,
326190380Srwatson	    dtnfsclient_get_str, dtnfsclient_hit_str) == 0) {
327190380Srwatson		nfsclient_accesscache_get_hit_id = dtrace_probe_create(
328190380Srwatson		    dtnfsclient_id, dtnfsclient_accesscache_str,
329190380Srwatson		    dtnfsclient_get_str, dtnfsclient_hit_str, 0, NULL);
330190380Srwatson	}
331190380Srwatson	if (dtrace_probe_lookup(dtnfsclient_id, dtnfsclient_accesscache_str,
332190380Srwatson	    dtnfsclient_get_str, dtnfsclient_miss_str) == 0) {
333190380Srwatson		nfsclient_accesscache_get_miss_id = dtrace_probe_create(
334190380Srwatson		    dtnfsclient_id, dtnfsclient_accesscache_str,
335190380Srwatson		    dtnfsclient_get_str, dtnfsclient_miss_str, 0, NULL);
336190380Srwatson	}
337190380Srwatson	if (dtrace_probe_lookup(dtnfsclient_id, dtnfsclient_accesscache_str,
338190380Srwatson	    dtnfsclient_load_str, dtnfsclient_done_str) == 0) {
339190380Srwatson		nfsclient_accesscache_load_done_id = dtrace_probe_create(
340190380Srwatson		    dtnfsclient_id, dtnfsclient_accesscache_str,
341190380Srwatson		    dtnfsclient_load_str, dtnfsclient_done_str, 0, NULL);
342190380Srwatson	}
343190380Srwatson
344190380Srwatson	/*
345190380Srwatson	 * Register attribute cache probes.
346190380Srwatson	 */
347190380Srwatson	if (dtrace_probe_lookup(dtnfsclient_id, dtnfsclient_attrcache_str,
348190380Srwatson	    dtnfsclient_flush_str, dtnfsclient_done_str) == 0) {
349190380Srwatson		nfsclient_attrcache_flush_done_id = dtrace_probe_create(
350190380Srwatson		    dtnfsclient_id, dtnfsclient_attrcache_str,
351190380Srwatson		    dtnfsclient_flush_str, dtnfsclient_done_str, 0, NULL);
352190380Srwatson	}
353190380Srwatson	if (dtrace_probe_lookup(dtnfsclient_id, dtnfsclient_attrcache_str,
354190380Srwatson	    dtnfsclient_get_str, dtnfsclient_hit_str) == 0) {
355190380Srwatson		nfsclient_attrcache_get_hit_id = dtrace_probe_create(
356190380Srwatson		    dtnfsclient_id, dtnfsclient_attrcache_str,
357190380Srwatson		    dtnfsclient_get_str, dtnfsclient_hit_str, 0, NULL);
358190380Srwatson	}
359190380Srwatson	if (dtrace_probe_lookup(dtnfsclient_id, dtnfsclient_attrcache_str,
360190380Srwatson	    dtnfsclient_get_str, dtnfsclient_miss_str) == 0) {
361190380Srwatson		nfsclient_attrcache_get_miss_id = dtrace_probe_create(
362190380Srwatson		    dtnfsclient_id, dtnfsclient_attrcache_str,
363190380Srwatson		    dtnfsclient_get_str, dtnfsclient_miss_str, 0, NULL);
364190380Srwatson	}
365190380Srwatson	if (dtrace_probe_lookup(dtnfsclient_id, dtnfsclient_attrcache_str,
366190380Srwatson	    dtnfsclient_load_str, dtnfsclient_done_str) == 0) {
367190380Srwatson		nfsclient_attrcache_load_done_id = dtrace_probe_create(
368190380Srwatson		    dtnfsclient_id, dtnfsclient_attrcache_str,
369190380Srwatson		    dtnfsclient_load_str, dtnfsclient_done_str, 0, NULL);
370190380Srwatson	}
371190380Srwatson
372190380Srwatson	/*
373190380Srwatson	 * Register NFSv2 RPC procedures; note sparseness check for each slot
374190380Srwatson	 * in the NFSv3 procnum-indexed array.
375190380Srwatson	 */
376190293Srwatson	for (i = 0; i < NFS_NPROCS; i++) {
377190293Srwatson		if (dtnfsclient_rpcs[i].nr_v2_name != NULL &&
378190380Srwatson		    dtrace_probe_lookup(dtnfsclient_id, dtnfsclient_nfs2_str,
379190380Srwatson		    dtnfsclient_rpcs[i].nr_v2_name, dtnfsclient_start_str) ==
380190380Srwatson		    0) {
381190293Srwatson			dtnfsclient_rpcs[i].nr_v2_id_start =
382190293Srwatson			    dtrace_probe_create(dtnfsclient_id,
383190380Srwatson			    dtnfsclient_nfs2_str,
384190293Srwatson			    dtnfsclient_rpcs[i].nr_v2_name,
385190380Srwatson			    dtnfsclient_start_str, 0,
386190293Srwatson			    &nfsclient_nfs2_start_probes[i]);
387190293Srwatson		}
388190293Srwatson		if (dtnfsclient_rpcs[i].nr_v2_name != NULL &&
389190380Srwatson		    dtrace_probe_lookup(dtnfsclient_id, dtnfsclient_nfs2_str,
390190380Srwatson		    dtnfsclient_rpcs[i].nr_v2_name, dtnfsclient_done_str) ==
391190380Srwatson		    0) {
392190293Srwatson			dtnfsclient_rpcs[i].nr_v2_id_done =
393190293Srwatson			    dtrace_probe_create(dtnfsclient_id,
394190380Srwatson			    dtnfsclient_nfs2_str,
395190293Srwatson			    dtnfsclient_rpcs[i].nr_v2_name,
396190380Srwatson			    dtnfsclient_done_str, 0,
397190293Srwatson			    &nfsclient_nfs2_done_probes[i]);
398190293Srwatson		}
399190293Srwatson	}
400190293Srwatson
401190293Srwatson	/*
402190380Srwatson	 * Register NFSv3 RPC procedures.
403190293Srwatson	 */
404190293Srwatson	for (i = 0; i < NFS_NPROCS; i++) {
405190380Srwatson		if (dtrace_probe_lookup(dtnfsclient_id, dtnfsclient_nfs3_str,
406190380Srwatson		    dtnfsclient_rpcs[i].nr_v3_name, dtnfsclient_start_str) ==
407190380Srwatson		    0) {
408190293Srwatson			dtnfsclient_rpcs[i].nr_v3_id_start =
409190293Srwatson			    dtrace_probe_create(dtnfsclient_id,
410190380Srwatson			    dtnfsclient_nfs3_str,
411190293Srwatson			    dtnfsclient_rpcs[i].nr_v3_name,
412190380Srwatson			    dtnfsclient_start_str, 0,
413190293Srwatson			    &nfsclient_nfs3_start_probes[i]);
414190293Srwatson		}
415190380Srwatson		if (dtrace_probe_lookup(dtnfsclient_id, dtnfsclient_nfs3_str,
416190380Srwatson		    dtnfsclient_rpcs[i].nr_v3_name, dtnfsclient_done_str) ==
417190380Srwatson		    0) {
418190293Srwatson			dtnfsclient_rpcs[i].nr_v3_id_done =
419190293Srwatson			    dtrace_probe_create(dtnfsclient_id,
420190380Srwatson			    dtnfsclient_nfs3_str,
421190293Srwatson			    dtnfsclient_rpcs[i].nr_v3_name,
422190380Srwatson			    dtnfsclient_done_str, 0,
423190293Srwatson			    &nfsclient_nfs3_done_probes[i]);
424190293Srwatson		}
425190293Srwatson	}
426190293Srwatson}
427190293Srwatson
428190293Srwatsonstatic void
429190293Srwatsondtnfsclient_destroy(void *arg, dtrace_id_t id, void *parg)
430190293Srwatson{
431190293Srwatson}
432190293Srwatson
433190293Srwatsonstatic void
434190293Srwatsondtnfsclient_enable(void *arg, dtrace_id_t id, void *parg)
435190293Srwatson{
436190293Srwatson	uint32_t *p = parg;
437190380Srwatson	void *f = dtrace_probe;
438190293Srwatson
439190380Srwatson	if (id == nfsclient_accesscache_flush_done_id)
440190380Srwatson		dtrace_nfsclient_accesscache_flush_done_probe = f;
441190380Srwatson	else if (id == nfsclient_accesscache_get_hit_id)
442190380Srwatson		dtrace_nfsclient_accesscache_get_hit_probe = f;
443190380Srwatson	else if (id == nfsclient_accesscache_get_miss_id)
444190380Srwatson		dtrace_nfsclient_accesscache_get_miss_probe = f;
445190380Srwatson	else if (id == nfsclient_accesscache_load_done_id)
446190380Srwatson		dtrace_nfsclient_accesscache_load_done_probe = f;
447190380Srwatson	else if (id == nfsclient_attrcache_flush_done_id)
448190380Srwatson		dtrace_nfsclient_attrcache_flush_done_probe = f;
449190380Srwatson	else if (id == nfsclient_attrcache_get_hit_id)
450190380Srwatson		dtrace_nfsclient_attrcache_get_hit_probe = f;
451190380Srwatson	else if (id == nfsclient_attrcache_get_miss_id)
452190380Srwatson		dtrace_nfsclient_attrcache_get_miss_probe = f;
453190380Srwatson	else if (id == nfsclient_attrcache_load_done_id)
454190380Srwatson		dtrace_nfsclient_attrcache_load_done_probe = f;
455190380Srwatson	else
456190380Srwatson		*p = id;
457190293Srwatson}
458190293Srwatson
459190293Srwatsonstatic void
460190293Srwatsondtnfsclient_disable(void *arg, dtrace_id_t id, void *parg)
461190293Srwatson{
462190293Srwatson	uint32_t *p = parg;
463190293Srwatson
464190380Srwatson	if (id == nfsclient_accesscache_flush_done_id)
465190380Srwatson		dtrace_nfsclient_accesscache_flush_done_probe = NULL;
466190380Srwatson	else if (id == nfsclient_accesscache_get_hit_id)
467190380Srwatson		dtrace_nfsclient_accesscache_get_hit_probe = NULL;
468190380Srwatson	else if (id == nfsclient_accesscache_get_miss_id)
469190380Srwatson		dtrace_nfsclient_accesscache_get_miss_probe = NULL;
470190380Srwatson	else if (id == nfsclient_accesscache_load_done_id)
471190380Srwatson		dtrace_nfsclient_accesscache_load_done_probe = NULL;
472190380Srwatson	else if (id == nfsclient_attrcache_flush_done_id)
473190380Srwatson		dtrace_nfsclient_attrcache_flush_done_probe = NULL;
474190380Srwatson	else if (id == nfsclient_attrcache_get_hit_id)
475190380Srwatson		dtrace_nfsclient_attrcache_get_hit_probe = NULL;
476190380Srwatson	else if (id == nfsclient_attrcache_get_miss_id)
477190380Srwatson		dtrace_nfsclient_attrcache_get_miss_probe = NULL;
478190380Srwatson	else if (id == nfsclient_attrcache_load_done_id)
479190380Srwatson		dtrace_nfsclient_attrcache_load_done_probe = NULL;
480190380Srwatson	else
481190380Srwatson		*p = 0;
482190293Srwatson}
483190293Srwatson
484190293Srwatsonstatic void
485190293Srwatsondtnfsclient_load(void *dummy)
486190293Srwatson{
487190293Srwatson
488190293Srwatson	if (dtrace_register("nfsclient", &dtnfsclient_attr,
489190293Srwatson	    DTRACE_PRIV_USER, NULL, &dtnfsclient_pops, NULL,
490190293Srwatson	    &dtnfsclient_id) != 0)
491190293Srwatson		return;
492190293Srwatson
493190293Srwatson	dtrace_nfsclient_nfs23_start_probe =
494190293Srwatson	    (dtrace_nfsclient_nfs23_start_probe_func_t)dtrace_probe;
495190293Srwatson	dtrace_nfsclient_nfs23_done_probe =
496190293Srwatson	    (dtrace_nfsclient_nfs23_done_probe_func_t)dtrace_probe;
497190293Srwatson}
498190293Srwatson
499190293Srwatson
500190293Srwatsonstatic int
501190293Srwatsondtnfsclient_unload()
502190293Srwatson{
503190293Srwatson
504190293Srwatson	dtrace_nfsclient_nfs23_start_probe = NULL;
505190293Srwatson	dtrace_nfsclient_nfs23_done_probe = NULL;
506190293Srwatson
507204063Spjd	return (dtrace_unregister(dtnfsclient_id));
508190293Srwatson}
509190293Srwatson
510190293Srwatsonstatic int
511190293Srwatsondtnfsclient_modevent(module_t mod __unused, int type, void *data __unused)
512190293Srwatson{
513190293Srwatson	int error = 0;
514190293Srwatson
515190293Srwatson	switch (type) {
516190293Srwatson	case MOD_LOAD:
517190293Srwatson		break;
518190293Srwatson
519190293Srwatson	case MOD_UNLOAD:
520190293Srwatson		break;
521190293Srwatson
522190293Srwatson	case MOD_SHUTDOWN:
523190293Srwatson		break;
524190293Srwatson
525190293Srwatson	default:
526190293Srwatson		error = EOPNOTSUPP;
527190293Srwatson		break;
528190293Srwatson	}
529190293Srwatson
530190293Srwatson	return (error);
531190293Srwatson}
532190293Srwatson
533190293SrwatsonSYSINIT(dtnfsclient_load, SI_SUB_DTRACE_PROVIDER, SI_ORDER_ANY,
534190293Srwatson    dtnfsclient_load, NULL);
535190293SrwatsonSYSUNINIT(dtnfsclient_unload, SI_SUB_DTRACE_PROVIDER, SI_ORDER_ANY,
536190293Srwatson    dtnfsclient_unload, NULL);
537190293Srwatson
538190293SrwatsonDEV_MODULE(dtnfsclient, dtnfsclient_modevent, NULL);
539190293SrwatsonMODULE_VERSION(dtnfsclient, 1);
540190293SrwatsonMODULE_DEPEND(dtnfsclient, dtrace, 1, 1, 1);
541190293SrwatsonMODULE_DEPEND(dtnfsclient, opensolaris, 1, 1, 1);
542221542SrmacklemMODULE_DEPEND(dtnfsclient, oldnfs, 1, 1, 1);
543