1223280Srmacklem/*-
2223280Srmacklem * Copyright (c) 2009 Robert N. M. Watson
3223280Srmacklem * All rights reserved.
4223280Srmacklem *
5223280Srmacklem * This software was developed at the University of Cambridge Computer
6223280Srmacklem * Laboratory with support from a grant from Google, Inc.
7223280Srmacklem *
8223280Srmacklem * Redistribution and use in source and binary forms, with or without
9223280Srmacklem * modification, are permitted provided that the following conditions
10223280Srmacklem * are met:
11223280Srmacklem * 1. Redistributions of source code must retain the above copyright
12223280Srmacklem *    notice, this list of conditions and the following disclaimer.
13223280Srmacklem * 2. Redistributions in binary form must reproduce the above copyright
14223280Srmacklem *    notice, this list of conditions and the following disclaimer in the
15223280Srmacklem *    documentation and/or other materials provided with the distribution.
16223280Srmacklem *
17223280Srmacklem * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18223280Srmacklem * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19223280Srmacklem * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20223280Srmacklem * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
21223280Srmacklem * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22223280Srmacklem * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23223280Srmacklem * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24223280Srmacklem * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25223280Srmacklem * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26223280Srmacklem * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27223280Srmacklem * SUCH DAMAGE.
28223280Srmacklem */
29223280Srmacklem
30223280Srmacklem#include <sys/cdefs.h>
31223280Srmacklem__FBSDID("$FreeBSD$");
32223280Srmacklem
33223280Srmacklem#include <sys/param.h>
34223280Srmacklem#include <sys/systm.h>
35223280Srmacklem#include <sys/conf.h>
36223280Srmacklem#include <sys/kernel.h>
37223280Srmacklem#include <sys/malloc.h>
38223280Srmacklem#include <sys/module.h>
39223280Srmacklem
40223280Srmacklem#include <sys/dtrace.h>
41223280Srmacklem#include <sys/dtrace_bsd.h>
42223280Srmacklem
43223280Srmacklem#include <fs/nfs/nfsproto.h>
44223280Srmacklem
45223280Srmacklem#include <fs/nfsclient/nfs_kdtrace.h>
46223280Srmacklem
47223280Srmacklem/*
48223280Srmacklem * dtnfscl is a DTrace provider that tracks the intent to perform RPCs
49223280Srmacklem * in the NFS client, as well as acess to and maintenance of the access and
50223280Srmacklem * attribute caches.  This is not quite the same as RPCs, because NFS may
51223280Srmacklem * issue multiple RPC transactions in the event that authentication fails,
52223280Srmacklem * there's a jukebox error, or none at all if the access or attribute cache
53223280Srmacklem * hits.  However, it cleanly represents the logical layer between RPC
54223280Srmacklem * transmission and vnode/vfs operations, providing access to state linking
55223280Srmacklem * the two.
56223280Srmacklem */
57223280Srmacklem
58223280Srmacklemstatic int	dtnfsclient_unload(void);
59223280Srmacklemstatic void	dtnfsclient_getargdesc(void *, dtrace_id_t, void *,
60223280Srmacklem		    dtrace_argdesc_t *);
61223280Srmacklemstatic void	dtnfsclient_provide(void *, dtrace_probedesc_t *);
62223280Srmacklemstatic void	dtnfsclient_destroy(void *, dtrace_id_t, void *);
63223280Srmacklemstatic void	dtnfsclient_enable(void *, dtrace_id_t, void *);
64223280Srmacklemstatic void	dtnfsclient_disable(void *, dtrace_id_t, void *);
65223280Srmacklemstatic void	dtnfsclient_load(void *);
66223280Srmacklem
67223280Srmacklemstatic dtrace_pattr_t dtnfsclient_attr = {
68223280Srmacklem{ DTRACE_STABILITY_STABLE, DTRACE_STABILITY_STABLE, DTRACE_CLASS_COMMON },
69223280Srmacklem{ DTRACE_STABILITY_PRIVATE, DTRACE_STABILITY_PRIVATE, DTRACE_CLASS_UNKNOWN },
70223280Srmacklem{ DTRACE_STABILITY_PRIVATE, DTRACE_STABILITY_PRIVATE, DTRACE_CLASS_UNKNOWN },
71223280Srmacklem{ DTRACE_STABILITY_STABLE, DTRACE_STABILITY_STABLE, DTRACE_CLASS_COMMON },
72223280Srmacklem{ DTRACE_STABILITY_STABLE, DTRACE_STABILITY_STABLE, DTRACE_CLASS_COMMON },
73223280Srmacklem};
74223280Srmacklem
75223280Srmacklem/*
76223280Srmacklem * Description of NFSv4, NFSv3 and (optional) NFSv2 probes for a procedure.
77223280Srmacklem */
78223280Srmacklemstruct dtnfsclient_rpc {
79223280Srmacklem	char		*nr_v4_name;
80223280Srmacklem	char		*nr_v3_name;	/* Or NULL if none. */
81223280Srmacklem	char		*nr_v2_name;	/* Or NULL if none. */
82223280Srmacklem
83223280Srmacklem	/*
84223280Srmacklem	 * IDs for the start and done cases, for NFSv2, NFSv3 and NFSv4.
85223280Srmacklem	 */
86223280Srmacklem	uint32_t	 nr_v2_id_start, nr_v2_id_done;
87223280Srmacklem	uint32_t	 nr_v3_id_start, nr_v3_id_done;
88223280Srmacklem	uint32_t	 nr_v4_id_start, nr_v4_id_done;
89223280Srmacklem};
90223280Srmacklem
91223280Srmacklem/*
92223280Srmacklem * This table is indexed by NFSv3 procedure number, but also used for NFSv2
93223280Srmacklem * procedure names and NFSv4 operations.
94223280Srmacklem */
95223280Srmacklemstatic struct dtnfsclient_rpc	dtnfsclient_rpcs[NFS_NPROCS + 1] = {
96223280Srmacklem	{ "null", "null", "null" },
97223280Srmacklem	{ "getattr", "getattr", "getattr" },
98223280Srmacklem	{ "setattr", "setattr", "setattr" },
99223280Srmacklem	{ "lookup", "lookup", "lookup" },
100223280Srmacklem	{ "access", "access", "noop" },
101223280Srmacklem	{ "readlink", "readlink", "readlink" },
102223280Srmacklem	{ "read", "read", "read" },
103223280Srmacklem	{ "write", "write", "write" },
104223280Srmacklem	{ "create", "create", "create" },
105223280Srmacklem	{ "mkdir", "mkdir", "mkdir" },
106223280Srmacklem	{ "symlink", "symlink", "symlink" },
107223280Srmacklem	{ "mknod", "mknod" },
108223280Srmacklem	{ "remove", "remove", "remove" },
109223280Srmacklem	{ "rmdir", "rmdir", "rmdir" },
110223280Srmacklem	{ "rename", "rename", "rename" },
111223280Srmacklem	{ "link", "link", "link" },
112223280Srmacklem	{ "readdir", "readdir", "readdir" },
113223280Srmacklem	{ "readdirplus", "readdirplus" },
114223280Srmacklem	{ "fsstat", "fsstat", "statfs" },
115223280Srmacklem	{ "fsinfo", "fsinfo" },
116223280Srmacklem	{ "pathconf", "pathconf" },
117223280Srmacklem	{ "commit", "commit" },
118223280Srmacklem	{ "lookupp" },
119223280Srmacklem	{ "setclientid" },
120223280Srmacklem	{ "setclientidcfrm" },
121223280Srmacklem	{ "lock" },
122223280Srmacklem	{ "locku" },
123223280Srmacklem	{ "open" },
124223280Srmacklem	{ "close" },
125223280Srmacklem	{ "openconfirm" },
126223280Srmacklem	{ "lockt" },
127223280Srmacklem	{ "opendowngrade" },
128223280Srmacklem	{ "renew" },
129223280Srmacklem	{ "putrootfh" },
130223280Srmacklem	{ "releaselckown" },
131223280Srmacklem	{ "delegreturn" },
132223280Srmacklem	{ "retdelegremove" },
133223280Srmacklem	{ "retdelegrename1" },
134223280Srmacklem	{ "retdelegrename2" },
135223280Srmacklem	{ "getacl" },
136223280Srmacklem	{ "setacl" },
137223280Srmacklem	{ "noop", "noop", "noop" }
138223280Srmacklem};
139223280Srmacklem
140223280Srmacklem/*
141223280Srmacklem * Module name strings.
142223280Srmacklem */
143223280Srmacklemstatic char	*dtnfsclient_accesscache_str = "accesscache";
144223280Srmacklemstatic char	*dtnfsclient_attrcache_str = "attrcache";
145223280Srmacklemstatic char	*dtnfsclient_nfs2_str = "nfs2";
146223280Srmacklemstatic char	*dtnfsclient_nfs3_str = "nfs3";
147223280Srmacklemstatic char	*dtnfsclient_nfs4_str = "nfs4";
148223280Srmacklem
149223280Srmacklem/*
150223280Srmacklem * Function name strings.
151223280Srmacklem */
152223280Srmacklemstatic char	*dtnfsclient_flush_str = "flush";
153223280Srmacklemstatic char	*dtnfsclient_load_str = "load";
154223280Srmacklemstatic char	*dtnfsclient_get_str = "get";
155223280Srmacklem
156223280Srmacklem/*
157223280Srmacklem * Name strings.
158223280Srmacklem */
159223280Srmacklemstatic char	*dtnfsclient_done_str = "done";
160223280Srmacklemstatic char	*dtnfsclient_hit_str = "hit";
161223280Srmacklemstatic char	*dtnfsclient_miss_str = "miss";
162223280Srmacklemstatic char	*dtnfsclient_start_str = "start";
163223280Srmacklem
164223280Srmacklemstatic dtrace_pops_t dtnfsclient_pops = {
165223280Srmacklem	dtnfsclient_provide,
166223280Srmacklem	NULL,
167223280Srmacklem	dtnfsclient_enable,
168223280Srmacklem	dtnfsclient_disable,
169223280Srmacklem	NULL,
170223280Srmacklem	NULL,
171223280Srmacklem	dtnfsclient_getargdesc,
172223280Srmacklem	NULL,
173223280Srmacklem	NULL,
174223280Srmacklem	dtnfsclient_destroy
175223280Srmacklem};
176223280Srmacklem
177223280Srmacklemstatic dtrace_provider_id_t	dtnfsclient_id;
178223280Srmacklem
179223280Srmacklem/*
180223280Srmacklem * Most probes are generated from the above RPC table, but for access and
181223280Srmacklem * attribute caches, we have specific IDs we recognize and handle specially
182223280Srmacklem * in various spots.
183223280Srmacklem */
184223280Srmacklemextern uint32_t	nfscl_accesscache_flush_done_id;
185223280Srmacklemextern uint32_t	nfscl_accesscache_get_hit_id;
186223280Srmacklemextern uint32_t	nfscl_accesscache_get_miss_id;
187223280Srmacklemextern uint32_t	nfscl_accesscache_load_done_id;
188223280Srmacklem
189223280Srmacklemextern uint32_t	nfscl_attrcache_flush_done_id;
190223280Srmacklemextern uint32_t	nfscl_attrcache_get_hit_id;
191223280Srmacklemextern uint32_t	nfscl_attrcache_get_miss_id;
192223280Srmacklemextern uint32_t	nfscl_attrcache_load_done_id;
193223280Srmacklem
194223280Srmacklem/*
195223280Srmacklem * When tracing on a procedure is enabled, the DTrace ID for an RPC event is
196223280Srmacklem * stored in one of these two NFS client-allocated arrays; 0 indicates that
197223280Srmacklem * the event is not being traced so probes should not be called.
198223280Srmacklem *
199223280Srmacklem * For simplicity, we allocate both v2, v3 and v4 arrays as NFS_NPROCS + 1, and
200223280Srmacklem * the v2, v3 arrays are simply sparse.
201223280Srmacklem */
202223280Srmacklemextern uint32_t			nfscl_nfs2_start_probes[NFS_NPROCS + 1];
203223280Srmacklemextern uint32_t			nfscl_nfs2_done_probes[NFS_NPROCS + 1];
204223280Srmacklem
205223280Srmacklemextern uint32_t			nfscl_nfs3_start_probes[NFS_NPROCS + 1];
206223280Srmacklemextern uint32_t			nfscl_nfs3_done_probes[NFS_NPROCS + 1];
207223280Srmacklem
208223280Srmacklemextern uint32_t			nfscl_nfs4_start_probes[NFS_NPROCS + 1];
209223280Srmacklemextern uint32_t			nfscl_nfs4_done_probes[NFS_NPROCS + 1];
210223280Srmacklem
211223280Srmacklem/*
212223280Srmacklem * Look up a DTrace probe ID to see if it's associated with a "done" event --
213223280Srmacklem * if so, we will return a fourth argument type of "int".
214223280Srmacklem */
215223280Srmacklemstatic int
216223280Srmacklemdtnfs234_isdoneprobe(dtrace_id_t id)
217223280Srmacklem{
218223280Srmacklem	int i;
219223280Srmacklem
220223280Srmacklem	for (i = 0; i < NFS_NPROCS + 1; i++) {
221223280Srmacklem		if (dtnfsclient_rpcs[i].nr_v4_id_done == id ||
222223280Srmacklem		    dtnfsclient_rpcs[i].nr_v3_id_done == id ||
223223280Srmacklem		    dtnfsclient_rpcs[i].nr_v2_id_done == id)
224223280Srmacklem			return (1);
225223280Srmacklem	}
226223280Srmacklem	return (0);
227223280Srmacklem}
228223280Srmacklem
229223280Srmacklemstatic void
230223280Srmacklemdtnfsclient_getargdesc(void *arg, dtrace_id_t id, void *parg,
231223280Srmacklem    dtrace_argdesc_t *desc)
232223280Srmacklem{
233223280Srmacklem	const char *p = NULL;
234223280Srmacklem
235223280Srmacklem	if (id == nfscl_accesscache_flush_done_id ||
236223280Srmacklem	    id == nfscl_attrcache_flush_done_id ||
237223280Srmacklem	    id == nfscl_attrcache_get_miss_id) {
238223280Srmacklem		switch (desc->dtargd_ndx) {
239223280Srmacklem		case 0:
240223280Srmacklem			p = "struct vnode *";
241223280Srmacklem			break;
242223280Srmacklem		default:
243223280Srmacklem			desc->dtargd_ndx = DTRACE_ARGNONE;
244223280Srmacklem			break;
245223280Srmacklem		}
246223280Srmacklem	} else if (id == nfscl_accesscache_get_hit_id ||
247223280Srmacklem	    id == nfscl_accesscache_get_miss_id) {
248223280Srmacklem		switch (desc->dtargd_ndx) {
249223280Srmacklem		case 0:
250223280Srmacklem			p = "struct vnode *";
251223280Srmacklem			break;
252223280Srmacklem		case 1:
253223280Srmacklem			p = "uid_t";
254223280Srmacklem			break;
255223280Srmacklem		case 2:
256223280Srmacklem			p = "uint32_t";
257223280Srmacklem			break;
258223280Srmacklem		default:
259223280Srmacklem			desc->dtargd_ndx = DTRACE_ARGNONE;
260223280Srmacklem			break;
261223280Srmacklem		}
262223280Srmacklem	} else if (id == nfscl_accesscache_load_done_id) {
263223280Srmacklem		switch (desc->dtargd_ndx) {
264223280Srmacklem		case 0:
265223280Srmacklem			p = "struct vnode *";
266223280Srmacklem			break;
267223280Srmacklem		case 1:
268223280Srmacklem			p = "uid_t";
269223280Srmacklem			break;
270223280Srmacklem		case 2:
271223280Srmacklem			p = "uint32_t";
272223280Srmacklem			break;
273223280Srmacklem		case 3:
274223280Srmacklem			p = "int";
275223280Srmacklem			break;
276223280Srmacklem		default:
277223280Srmacklem			desc->dtargd_ndx = DTRACE_ARGNONE;
278223280Srmacklem			break;
279223280Srmacklem		}
280223280Srmacklem	} else if (id == nfscl_attrcache_get_hit_id) {
281223280Srmacklem		switch (desc->dtargd_ndx) {
282223280Srmacklem		case 0:
283223280Srmacklem			p = "struct vnode *";
284223280Srmacklem			break;
285223280Srmacklem		case 1:
286223280Srmacklem			p = "struct vattr *";
287223280Srmacklem			break;
288223280Srmacklem		default:
289223280Srmacklem			desc->dtargd_ndx = DTRACE_ARGNONE;
290223280Srmacklem			break;
291223280Srmacklem		}
292223280Srmacklem	} else if (id == nfscl_attrcache_load_done_id) {
293223280Srmacklem		switch (desc->dtargd_ndx) {
294223280Srmacklem		case 0:
295223280Srmacklem			p = "struct vnode *";
296223280Srmacklem			break;
297223280Srmacklem		case 1:
298223280Srmacklem			p = "struct vattr *";
299223280Srmacklem			break;
300223280Srmacklem		case 2:
301223280Srmacklem			p = "int";
302223280Srmacklem			break;
303223280Srmacklem		default:
304223280Srmacklem			desc->dtargd_ndx = DTRACE_ARGNONE;
305223280Srmacklem			break;
306223280Srmacklem		}
307223280Srmacklem	} else {
308223280Srmacklem		switch (desc->dtargd_ndx) {
309223280Srmacklem		case 0:
310223280Srmacklem			p = "struct vnode *";
311223280Srmacklem			break;
312223280Srmacklem		case 1:
313223280Srmacklem			p = "struct mbuf *";
314223280Srmacklem			break;
315223280Srmacklem		case 2:
316223280Srmacklem			p = "struct ucred *";
317223280Srmacklem			break;
318223280Srmacklem		case 3:
319223280Srmacklem			p = "int";
320223280Srmacklem			break;
321223280Srmacklem		case 4:
322223280Srmacklem			if (dtnfs234_isdoneprobe(id)) {
323223280Srmacklem				p = "int";
324223280Srmacklem				break;
325223280Srmacklem			}
326223280Srmacklem			/* FALLSTHROUGH */
327223280Srmacklem		default:
328223280Srmacklem			desc->dtargd_ndx = DTRACE_ARGNONE;
329223280Srmacklem			break;
330223280Srmacklem		}
331223280Srmacklem	}
332223280Srmacklem	if (p != NULL)
333223280Srmacklem		strlcpy(desc->dtargd_native, p, sizeof(desc->dtargd_native));
334223280Srmacklem}
335223280Srmacklem
336223280Srmacklemstatic void
337223280Srmacklemdtnfsclient_provide(void *arg, dtrace_probedesc_t *desc)
338223280Srmacklem{
339223280Srmacklem	int i;
340223280Srmacklem
341223280Srmacklem	if (desc != NULL)
342223280Srmacklem		return;
343223280Srmacklem
344223280Srmacklem	/*
345223280Srmacklem	 * Register access cache probes.
346223280Srmacklem	 */
347223280Srmacklem	if (dtrace_probe_lookup(dtnfsclient_id, dtnfsclient_accesscache_str,
348223280Srmacklem	    dtnfsclient_flush_str, dtnfsclient_done_str) == 0) {
349223280Srmacklem		nfscl_accesscache_flush_done_id = dtrace_probe_create(
350223280Srmacklem		    dtnfsclient_id, dtnfsclient_accesscache_str,
351223280Srmacklem		    dtnfsclient_flush_str, dtnfsclient_done_str, 0, NULL);
352223280Srmacklem	}
353223280Srmacklem	if (dtrace_probe_lookup(dtnfsclient_id, dtnfsclient_accesscache_str,
354223280Srmacklem	    dtnfsclient_get_str, dtnfsclient_hit_str) == 0) {
355223280Srmacklem		nfscl_accesscache_get_hit_id = dtrace_probe_create(
356223280Srmacklem		    dtnfsclient_id, dtnfsclient_accesscache_str,
357223280Srmacklem		    dtnfsclient_get_str, dtnfsclient_hit_str, 0, NULL);
358223280Srmacklem	}
359223280Srmacklem	if (dtrace_probe_lookup(dtnfsclient_id, dtnfsclient_accesscache_str,
360223280Srmacklem	    dtnfsclient_get_str, dtnfsclient_miss_str) == 0) {
361223280Srmacklem		nfscl_accesscache_get_miss_id = dtrace_probe_create(
362223280Srmacklem		    dtnfsclient_id, dtnfsclient_accesscache_str,
363223280Srmacklem		    dtnfsclient_get_str, dtnfsclient_miss_str, 0, NULL);
364223280Srmacklem	}
365223280Srmacklem	if (dtrace_probe_lookup(dtnfsclient_id, dtnfsclient_accesscache_str,
366223280Srmacklem	    dtnfsclient_load_str, dtnfsclient_done_str) == 0) {
367223280Srmacklem		nfscl_accesscache_load_done_id = dtrace_probe_create(
368223280Srmacklem		    dtnfsclient_id, dtnfsclient_accesscache_str,
369223280Srmacklem		    dtnfsclient_load_str, dtnfsclient_done_str, 0, NULL);
370223280Srmacklem	}
371223280Srmacklem
372223280Srmacklem	/*
373223280Srmacklem	 * Register attribute cache probes.
374223280Srmacklem	 */
375223280Srmacklem	if (dtrace_probe_lookup(dtnfsclient_id, dtnfsclient_attrcache_str,
376223280Srmacklem	    dtnfsclient_flush_str, dtnfsclient_done_str) == 0) {
377223280Srmacklem		nfscl_attrcache_flush_done_id = dtrace_probe_create(
378223280Srmacklem		    dtnfsclient_id, dtnfsclient_attrcache_str,
379223280Srmacklem		    dtnfsclient_flush_str, dtnfsclient_done_str, 0, NULL);
380223280Srmacklem	}
381223280Srmacklem	if (dtrace_probe_lookup(dtnfsclient_id, dtnfsclient_attrcache_str,
382223280Srmacklem	    dtnfsclient_get_str, dtnfsclient_hit_str) == 0) {
383223280Srmacklem		nfscl_attrcache_get_hit_id = dtrace_probe_create(
384223280Srmacklem		    dtnfsclient_id, dtnfsclient_attrcache_str,
385223280Srmacklem		    dtnfsclient_get_str, dtnfsclient_hit_str, 0, NULL);
386223280Srmacklem	}
387223280Srmacklem	if (dtrace_probe_lookup(dtnfsclient_id, dtnfsclient_attrcache_str,
388223280Srmacklem	    dtnfsclient_get_str, dtnfsclient_miss_str) == 0) {
389223280Srmacklem		nfscl_attrcache_get_miss_id = dtrace_probe_create(
390223280Srmacklem		    dtnfsclient_id, dtnfsclient_attrcache_str,
391223280Srmacklem		    dtnfsclient_get_str, dtnfsclient_miss_str, 0, NULL);
392223280Srmacklem	}
393223280Srmacklem	if (dtrace_probe_lookup(dtnfsclient_id, dtnfsclient_attrcache_str,
394223280Srmacklem	    dtnfsclient_load_str, dtnfsclient_done_str) == 0) {
395223280Srmacklem		nfscl_attrcache_load_done_id = dtrace_probe_create(
396223280Srmacklem		    dtnfsclient_id, dtnfsclient_attrcache_str,
397223280Srmacklem		    dtnfsclient_load_str, dtnfsclient_done_str, 0, NULL);
398223280Srmacklem	}
399223280Srmacklem
400223280Srmacklem	/*
401223280Srmacklem	 * Register NFSv2 RPC procedures; note sparseness check for each slot
402223280Srmacklem	 * in the NFSv3, NFSv4 procnum-indexed array.
403223280Srmacklem	 */
404223280Srmacklem	for (i = 0; i < NFS_NPROCS + 1; i++) {
405223280Srmacklem		if (dtnfsclient_rpcs[i].nr_v2_name != NULL &&
406223280Srmacklem		    dtrace_probe_lookup(dtnfsclient_id, dtnfsclient_nfs2_str,
407223280Srmacklem		    dtnfsclient_rpcs[i].nr_v2_name, dtnfsclient_start_str) ==
408223280Srmacklem		    0) {
409223280Srmacklem			dtnfsclient_rpcs[i].nr_v2_id_start =
410223280Srmacklem			    dtrace_probe_create(dtnfsclient_id,
411223280Srmacklem			    dtnfsclient_nfs2_str,
412223280Srmacklem			    dtnfsclient_rpcs[i].nr_v2_name,
413223280Srmacklem			    dtnfsclient_start_str, 0,
414223280Srmacklem			    &nfscl_nfs2_start_probes[i]);
415223280Srmacklem		}
416223280Srmacklem		if (dtnfsclient_rpcs[i].nr_v2_name != NULL &&
417223280Srmacklem		    dtrace_probe_lookup(dtnfsclient_id, dtnfsclient_nfs2_str,
418223280Srmacklem		    dtnfsclient_rpcs[i].nr_v2_name, dtnfsclient_done_str) ==
419223280Srmacklem		    0) {
420223280Srmacklem			dtnfsclient_rpcs[i].nr_v2_id_done =
421223280Srmacklem			    dtrace_probe_create(dtnfsclient_id,
422223280Srmacklem			    dtnfsclient_nfs2_str,
423223280Srmacklem			    dtnfsclient_rpcs[i].nr_v2_name,
424223280Srmacklem			    dtnfsclient_done_str, 0,
425223280Srmacklem			    &nfscl_nfs2_done_probes[i]);
426223280Srmacklem		}
427223280Srmacklem	}
428223280Srmacklem
429223280Srmacklem	/*
430223280Srmacklem	 * Register NFSv3 RPC procedures; note sparseness check for each slot
431223280Srmacklem	 * in the NFSv4 procnum-indexed array.
432223280Srmacklem	 */
433223280Srmacklem	for (i = 0; i < NFS_NPROCS + 1; i++) {
434223280Srmacklem		if (dtnfsclient_rpcs[i].nr_v3_name != NULL &&
435223280Srmacklem		    dtrace_probe_lookup(dtnfsclient_id, dtnfsclient_nfs3_str,
436223280Srmacklem		    dtnfsclient_rpcs[i].nr_v3_name, dtnfsclient_start_str) ==
437223280Srmacklem		    0) {
438223280Srmacklem			dtnfsclient_rpcs[i].nr_v3_id_start =
439223280Srmacklem			    dtrace_probe_create(dtnfsclient_id,
440223280Srmacklem			    dtnfsclient_nfs3_str,
441223280Srmacklem			    dtnfsclient_rpcs[i].nr_v3_name,
442223280Srmacklem			    dtnfsclient_start_str, 0,
443223280Srmacklem			    &nfscl_nfs3_start_probes[i]);
444223280Srmacklem		}
445223280Srmacklem		if (dtnfsclient_rpcs[i].nr_v3_name != NULL &&
446223280Srmacklem		    dtrace_probe_lookup(dtnfsclient_id, dtnfsclient_nfs3_str,
447223280Srmacklem		    dtnfsclient_rpcs[i].nr_v3_name, dtnfsclient_done_str) ==
448223280Srmacklem		    0) {
449223280Srmacklem			dtnfsclient_rpcs[i].nr_v3_id_done =
450223280Srmacklem			    dtrace_probe_create(dtnfsclient_id,
451223280Srmacklem			    dtnfsclient_nfs3_str,
452223280Srmacklem			    dtnfsclient_rpcs[i].nr_v3_name,
453223280Srmacklem			    dtnfsclient_done_str, 0,
454223280Srmacklem			    &nfscl_nfs3_done_probes[i]);
455223280Srmacklem		}
456223280Srmacklem	}
457223280Srmacklem
458223280Srmacklem	/*
459223280Srmacklem	 * Register NFSv4 RPC procedures.
460223280Srmacklem	 */
461223280Srmacklem	for (i = 0; i < NFS_NPROCS + 1; i++) {
462223280Srmacklem		if (dtrace_probe_lookup(dtnfsclient_id, dtnfsclient_nfs4_str,
463223280Srmacklem		    dtnfsclient_rpcs[i].nr_v4_name, dtnfsclient_start_str) ==
464223280Srmacklem		    0) {
465223280Srmacklem			dtnfsclient_rpcs[i].nr_v4_id_start =
466223280Srmacklem			    dtrace_probe_create(dtnfsclient_id,
467223280Srmacklem			    dtnfsclient_nfs4_str,
468223280Srmacklem			    dtnfsclient_rpcs[i].nr_v4_name,
469223280Srmacklem			    dtnfsclient_start_str, 0,
470223280Srmacklem			    &nfscl_nfs4_start_probes[i]);
471223280Srmacklem		}
472223280Srmacklem		if (dtrace_probe_lookup(dtnfsclient_id, dtnfsclient_nfs4_str,
473223280Srmacklem		    dtnfsclient_rpcs[i].nr_v4_name, dtnfsclient_done_str) ==
474223280Srmacklem		    0) {
475223280Srmacklem			dtnfsclient_rpcs[i].nr_v4_id_done =
476223280Srmacklem			    dtrace_probe_create(dtnfsclient_id,
477223280Srmacklem			    dtnfsclient_nfs4_str,
478223280Srmacklem			    dtnfsclient_rpcs[i].nr_v4_name,
479223280Srmacklem			    dtnfsclient_done_str, 0,
480223280Srmacklem			    &nfscl_nfs4_done_probes[i]);
481223280Srmacklem		}
482223280Srmacklem	}
483223280Srmacklem}
484223280Srmacklem
485223280Srmacklemstatic void
486223280Srmacklemdtnfsclient_destroy(void *arg, dtrace_id_t id, void *parg)
487223280Srmacklem{
488223280Srmacklem}
489223280Srmacklem
490223280Srmacklemstatic void
491223280Srmacklemdtnfsclient_enable(void *arg, dtrace_id_t id, void *parg)
492223280Srmacklem{
493223280Srmacklem	uint32_t *p = parg;
494223280Srmacklem	void *f = dtrace_probe;
495223280Srmacklem
496223280Srmacklem	if (id == nfscl_accesscache_flush_done_id)
497223280Srmacklem		dtrace_nfscl_accesscache_flush_done_probe = f;
498223280Srmacklem	else if (id == nfscl_accesscache_get_hit_id)
499223280Srmacklem		dtrace_nfscl_accesscache_get_hit_probe = f;
500223280Srmacklem	else if (id == nfscl_accesscache_get_miss_id)
501223280Srmacklem		dtrace_nfscl_accesscache_get_miss_probe = f;
502223280Srmacklem	else if (id == nfscl_accesscache_load_done_id)
503223280Srmacklem		dtrace_nfscl_accesscache_load_done_probe = f;
504223280Srmacklem	else if (id == nfscl_attrcache_flush_done_id)
505223280Srmacklem		dtrace_nfscl_attrcache_flush_done_probe = f;
506223280Srmacklem	else if (id == nfscl_attrcache_get_hit_id)
507223280Srmacklem		dtrace_nfscl_attrcache_get_hit_probe = f;
508223280Srmacklem	else if (id == nfscl_attrcache_get_miss_id)
509223280Srmacklem		dtrace_nfscl_attrcache_get_miss_probe = f;
510223280Srmacklem	else if (id == nfscl_attrcache_load_done_id)
511223280Srmacklem		dtrace_nfscl_attrcache_load_done_probe = f;
512223280Srmacklem	else
513223280Srmacklem		*p = id;
514223280Srmacklem}
515223280Srmacklem
516223280Srmacklemstatic void
517223280Srmacklemdtnfsclient_disable(void *arg, dtrace_id_t id, void *parg)
518223280Srmacklem{
519223280Srmacklem	uint32_t *p = parg;
520223280Srmacklem
521223280Srmacklem	if (id == nfscl_accesscache_flush_done_id)
522223280Srmacklem		dtrace_nfscl_accesscache_flush_done_probe = NULL;
523223280Srmacklem	else if (id == nfscl_accesscache_get_hit_id)
524223280Srmacklem		dtrace_nfscl_accesscache_get_hit_probe = NULL;
525223280Srmacklem	else if (id == nfscl_accesscache_get_miss_id)
526223280Srmacklem		dtrace_nfscl_accesscache_get_miss_probe = NULL;
527223280Srmacklem	else if (id == nfscl_accesscache_load_done_id)
528223280Srmacklem		dtrace_nfscl_accesscache_load_done_probe = NULL;
529223280Srmacklem	else if (id == nfscl_attrcache_flush_done_id)
530223280Srmacklem		dtrace_nfscl_attrcache_flush_done_probe = NULL;
531223280Srmacklem	else if (id == nfscl_attrcache_get_hit_id)
532223280Srmacklem		dtrace_nfscl_attrcache_get_hit_probe = NULL;
533223280Srmacklem	else if (id == nfscl_attrcache_get_miss_id)
534223280Srmacklem		dtrace_nfscl_attrcache_get_miss_probe = NULL;
535223280Srmacklem	else if (id == nfscl_attrcache_load_done_id)
536223280Srmacklem		dtrace_nfscl_attrcache_load_done_probe = NULL;
537223280Srmacklem	else
538223280Srmacklem		*p = 0;
539223280Srmacklem}
540223280Srmacklem
541223280Srmacklemstatic void
542223280Srmacklemdtnfsclient_load(void *dummy)
543223280Srmacklem{
544223280Srmacklem
545223280Srmacklem	if (dtrace_register("nfscl", &dtnfsclient_attr,
546223280Srmacklem	    DTRACE_PRIV_USER, NULL, &dtnfsclient_pops, NULL,
547223280Srmacklem	    &dtnfsclient_id) != 0)
548223280Srmacklem		return;
549223280Srmacklem
550223280Srmacklem	dtrace_nfscl_nfs234_start_probe =
551223280Srmacklem	    (dtrace_nfsclient_nfs23_start_probe_func_t)dtrace_probe;
552223280Srmacklem	dtrace_nfscl_nfs234_done_probe =
553223280Srmacklem	    (dtrace_nfsclient_nfs23_done_probe_func_t)dtrace_probe;
554223280Srmacklem}
555223280Srmacklem
556223280Srmacklem
557223280Srmacklemstatic int
558223280Srmacklemdtnfsclient_unload()
559223280Srmacklem{
560223280Srmacklem
561223280Srmacklem	dtrace_nfscl_nfs234_start_probe = NULL;
562223280Srmacklem	dtrace_nfscl_nfs234_done_probe = NULL;
563223280Srmacklem
564223280Srmacklem	return (dtrace_unregister(dtnfsclient_id));
565223280Srmacklem}
566223280Srmacklem
567223280Srmacklemstatic int
568223280Srmacklemdtnfsclient_modevent(module_t mod __unused, int type, void *data __unused)
569223280Srmacklem{
570223280Srmacklem	int error = 0;
571223280Srmacklem
572223280Srmacklem	switch (type) {
573223280Srmacklem	case MOD_LOAD:
574223280Srmacklem		break;
575223280Srmacklem
576223280Srmacklem	case MOD_UNLOAD:
577223280Srmacklem		break;
578223280Srmacklem
579223280Srmacklem	case MOD_SHUTDOWN:
580223280Srmacklem		break;
581223280Srmacklem
582223280Srmacklem	default:
583223280Srmacklem		error = EOPNOTSUPP;
584223280Srmacklem		break;
585223280Srmacklem	}
586223280Srmacklem
587223280Srmacklem	return (error);
588223280Srmacklem}
589223280Srmacklem
590223280SrmacklemSYSINIT(dtnfsclient_load, SI_SUB_DTRACE_PROVIDER, SI_ORDER_ANY,
591223280Srmacklem    dtnfsclient_load, NULL);
592223280SrmacklemSYSUNINIT(dtnfsclient_unload, SI_SUB_DTRACE_PROVIDER, SI_ORDER_ANY,
593223280Srmacklem    dtnfsclient_unload, NULL);
594223280Srmacklem
595223280SrmacklemDEV_MODULE(dtnfscl, dtnfsclient_modevent, NULL);
596223280SrmacklemMODULE_VERSION(dtnfscl, 1);
597223280SrmacklemMODULE_DEPEND(dtnfscl, dtrace, 1, 1, 1);
598223280SrmacklemMODULE_DEPEND(dtnfscl, opensolaris, 1, 1, 1);
599223280SrmacklemMODULE_DEPEND(dtnfscl, nfscl, 1, 1, 1);
600223280SrmacklemMODULE_DEPEND(dtnfscl, nfscommon, 1, 1, 1);
601