1179237Sjb/*
2179237Sjb * CDDL HEADER START
3179237Sjb *
4179237Sjb * The contents of this file are subject to the terms of the
5179237Sjb * Common Development and Distribution License (the "License").
6179237Sjb * You may not use this file except in compliance with the License.
7179237Sjb *
8179237Sjb * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9179237Sjb * or http://www.opensolaris.org/os/licensing.
10179237Sjb * See the License for the specific language governing permissions
11179237Sjb * and limitations under the License.
12179237Sjb *
13179237Sjb * When distributing Covered Code, include this CDDL HEADER in each
14179237Sjb * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15179237Sjb * If applicable, add the following below this CDDL HEADER, with the
16179237Sjb * fields enclosed by brackets "[]" replaced with your own identifying
17179237Sjb * information: Portions Copyright [yyyy] [name of copyright owner]
18179237Sjb *
19179237Sjb * CDDL HEADER END
20179237Sjb *
21179237Sjb * $FreeBSD$
22179237Sjb *
23179237Sjb */
24179237Sjb
25179237Sjbstatic int
26179237Sjbdtrace_unload()
27179237Sjb{
28179237Sjb	dtrace_state_t *state;
29179237Sjb	int error = 0;
30179237Sjb
31184698Srodrigc#if __FreeBSD_version < 800039
32179237Sjb	/*
33179237Sjb	 * Check if there is still an event handler callback
34179237Sjb	 * registered.
35179237Sjb	 */
36179237Sjb	if (eh_tag != 0) {
37179237Sjb		/* De-register the device cloning event handler. */
38179237Sjb		EVENTHANDLER_DEREGISTER(dev_clone, eh_tag);
39179237Sjb		eh_tag = 0;
40179237Sjb
41179237Sjb		/* Stop device cloning. */
42179237Sjb		clone_cleanup(&dtrace_clones);
43179237Sjb	}
44184698Srodrigc#else
45184698Srodrigc	destroy_dev(dtrace_dev);
46211611Srpaulo	destroy_dev(helper_dev);
47184698Srodrigc#endif
48179237Sjb
49179237Sjb	mutex_enter(&dtrace_provider_lock);
50179237Sjb	mutex_enter(&dtrace_lock);
51179237Sjb	mutex_enter(&cpu_lock);
52179237Sjb
53179237Sjb	ASSERT(dtrace_opens == 0);
54179237Sjb
55179237Sjb	if (dtrace_helpers > 0) {
56179237Sjb		mutex_exit(&cpu_lock);
57179237Sjb		mutex_exit(&dtrace_lock);
58179237Sjb		mutex_exit(&dtrace_provider_lock);
59179237Sjb		return (EBUSY);
60179237Sjb	}
61179237Sjb
62179237Sjb	if (dtrace_unregister((dtrace_provider_id_t)dtrace_provider) != 0) {
63179237Sjb		mutex_exit(&cpu_lock);
64179237Sjb		mutex_exit(&dtrace_lock);
65179237Sjb		mutex_exit(&dtrace_provider_lock);
66179237Sjb		return (EBUSY);
67179237Sjb	}
68179237Sjb
69179237Sjb	dtrace_provider = NULL;
70254309Smarkj	EVENTHANDLER_DEREGISTER(kld_load, dtrace_kld_load_tag);
71254813Smarkj	EVENTHANDLER_DEREGISTER(kld_unload_try, dtrace_kld_unload_try_tag);
72179237Sjb
73179237Sjb	if ((state = dtrace_anon_grab()) != NULL) {
74179237Sjb		/*
75179237Sjb		 * If there were ECBs on this state, the provider should
76179237Sjb		 * have not been allowed to detach; assert that there is
77179237Sjb		 * none.
78179237Sjb		 */
79179237Sjb		ASSERT(state->dts_necbs == 0);
80179237Sjb		dtrace_state_destroy(state);
81179237Sjb	}
82179237Sjb
83179237Sjb	bzero(&dtrace_anon, sizeof (dtrace_anon_t));
84179237Sjb
85179237Sjb	mutex_exit(&cpu_lock);
86179237Sjb
87179237Sjb	if (dtrace_helptrace_enabled) {
88179237Sjb		kmem_free(dtrace_helptrace_buffer, 0);
89179237Sjb		dtrace_helptrace_buffer = NULL;
90179237Sjb	}
91179237Sjb
92179237Sjb	if (dtrace_probes != NULL) {
93179237Sjb		kmem_free(dtrace_probes, 0);
94179237Sjb		dtrace_probes = NULL;
95179237Sjb		dtrace_nprobes = 0;
96179237Sjb	}
97179237Sjb
98179237Sjb	dtrace_hash_destroy(dtrace_bymod);
99179237Sjb	dtrace_hash_destroy(dtrace_byfunc);
100179237Sjb	dtrace_hash_destroy(dtrace_byname);
101179237Sjb	dtrace_bymod = NULL;
102179237Sjb	dtrace_byfunc = NULL;
103179237Sjb	dtrace_byname = NULL;
104179237Sjb
105179237Sjb	kmem_cache_destroy(dtrace_state_cache);
106179237Sjb
107179237Sjb	delete_unrhdr(dtrace_arena);
108179237Sjb
109179237Sjb	if (dtrace_toxrange != NULL) {
110179237Sjb		kmem_free(dtrace_toxrange, 0);
111179237Sjb		dtrace_toxrange = NULL;
112179237Sjb		dtrace_toxranges = 0;
113179237Sjb		dtrace_toxranges_max = 0;
114179237Sjb	}
115179237Sjb
116179237Sjb	ASSERT(dtrace_vtime_references == 0);
117179237Sjb	ASSERT(dtrace_opens == 0);
118179237Sjb	ASSERT(dtrace_retained == NULL);
119179237Sjb
120179237Sjb	mutex_exit(&dtrace_lock);
121179237Sjb	mutex_exit(&dtrace_provider_lock);
122179237Sjb
123179237Sjb	mutex_destroy(&dtrace_meta_lock);
124179237Sjb	mutex_destroy(&dtrace_provider_lock);
125179237Sjb	mutex_destroy(&dtrace_lock);
126253996Savg#ifdef DEBUG
127179237Sjb	mutex_destroy(&dtrace_errlock);
128253996Savg#endif
129179237Sjb
130256148Smarkj	taskq_destroy(dtrace_taskq);
131256148Smarkj
132179237Sjb	/* Reset our hook for exceptions. */
133179237Sjb	dtrace_invop_uninit();
134179237Sjb
135179237Sjb	/*
136179237Sjb	 * Reset our hook for thread switches, but ensure that vtime isn't
137179237Sjb	 * active first.
138179237Sjb	 */
139179237Sjb	dtrace_vtime_active = 0;
140179237Sjb	dtrace_vtime_switch_func = NULL;
141179237Sjb
142179237Sjb	/* Unhook from the trap handler. */
143179237Sjb	dtrace_trap_func = NULL;
144179237Sjb
145179237Sjb	return (error);
146179237Sjb}
147