1a8d61afdSLawrence Stewart /*-
24d846d26SWarner Losh * SPDX-License-Identifier: BSD-2-Clause
38a36da99SPedro F. Giffuni *
4b1f53277SLawrence Stewart * Copyright (c) 2010,2013 Lawrence Stewart <lstewart@freebsd.org>
5a8d61afdSLawrence Stewart * Copyright (c) 2010 The FreeBSD Foundation
6a8d61afdSLawrence Stewart * All rights reserved.
7a8d61afdSLawrence Stewart *
8a8d61afdSLawrence Stewart * This software was developed by Lawrence Stewart while studying at the Centre
9891b8ed4SLawrence Stewart * for Advanced Internet Architectures, Swinburne University of Technology,
10891b8ed4SLawrence Stewart * made possible in part by grants from the FreeBSD Foundation and Cisco
11891b8ed4SLawrence Stewart * University Research Program Fund at Community Foundation Silicon Valley.
12a8d61afdSLawrence Stewart *
13a8d61afdSLawrence Stewart * Portions of this software were developed at the Centre for Advanced
14a8d61afdSLawrence Stewart * Internet Architectures, Swinburne University of Technology, Melbourne,
15a8d61afdSLawrence Stewart * Australia by Lawrence Stewart under sponsorship from the FreeBSD Foundation.
16a8d61afdSLawrence Stewart *
17a8d61afdSLawrence Stewart * Redistribution and use in source and binary forms, with or without
18a8d61afdSLawrence Stewart * modification, are permitted provided that the following conditions
19a8d61afdSLawrence Stewart * are met:
20a8d61afdSLawrence Stewart * 1. Redistributions of source code must retain the above copyright
21a8d61afdSLawrence Stewart * notice, this list of conditions and the following disclaimer.
22a8d61afdSLawrence Stewart * 2. Redistributions in binary form must reproduce the above copyright
23a8d61afdSLawrence Stewart * notice, this list of conditions and the following disclaimer in the
24a8d61afdSLawrence Stewart * documentation and/or other materials provided with the distribution.
25a8d61afdSLawrence Stewart *
26a8d61afdSLawrence Stewart * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
27a8d61afdSLawrence Stewart * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
28a8d61afdSLawrence Stewart * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
29a8d61afdSLawrence Stewart * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
30a8d61afdSLawrence Stewart * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
31a8d61afdSLawrence Stewart * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
32a8d61afdSLawrence Stewart * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
33a8d61afdSLawrence Stewart * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
34a8d61afdSLawrence Stewart * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
35a8d61afdSLawrence Stewart * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
36a8d61afdSLawrence Stewart * SUCH DAMAGE.
37a8d61afdSLawrence Stewart */
38a8d61afdSLawrence Stewart
39a8d61afdSLawrence Stewart #include <sys/param.h>
40a8d61afdSLawrence Stewart #include <sys/kernel.h>
41a8d61afdSLawrence Stewart #include <sys/hhook.h>
42a8d61afdSLawrence Stewart #include <sys/khelp.h>
43a8d61afdSLawrence Stewart #include <sys/lock.h>
44a8d61afdSLawrence Stewart #include <sys/malloc.h>
45a8d61afdSLawrence Stewart #include <sys/module.h>
46a8d61afdSLawrence Stewart #include <sys/module_khelp.h>
47a8d61afdSLawrence Stewart #include <sys/osd.h>
48a8d61afdSLawrence Stewart #include <sys/queue.h>
49a8d61afdSLawrence Stewart #include <sys/refcount.h>
50a8d61afdSLawrence Stewart #include <sys/rwlock.h>
51a8d61afdSLawrence Stewart #include <sys/systm.h>
52a8d61afdSLawrence Stewart
53a8d61afdSLawrence Stewart static struct rwlock khelp_list_lock;
54a8d61afdSLawrence Stewart RW_SYSINIT(khelplistlock, &khelp_list_lock, "helper list lock");
55a8d61afdSLawrence Stewart
56a8d61afdSLawrence Stewart static TAILQ_HEAD(helper_head, helper) helpers = TAILQ_HEAD_INITIALIZER(helpers);
57a8d61afdSLawrence Stewart
58a8d61afdSLawrence Stewart /* Private function prototypes. */
59a8d61afdSLawrence Stewart static inline void khelp_remove_osd(struct helper *h, struct osd *hosd);
6058261d30SLawrence Stewart void khelp_new_hhook_registered(struct hhook_head *hhh, uint32_t flags);
61a8d61afdSLawrence Stewart
62a8d61afdSLawrence Stewart #define KHELP_LIST_WLOCK() rw_wlock(&khelp_list_lock)
63a8d61afdSLawrence Stewart #define KHELP_LIST_WUNLOCK() rw_wunlock(&khelp_list_lock)
64a8d61afdSLawrence Stewart #define KHELP_LIST_RLOCK() rw_rlock(&khelp_list_lock)
65a8d61afdSLawrence Stewart #define KHELP_LIST_RUNLOCK() rw_runlock(&khelp_list_lock)
66a8d61afdSLawrence Stewart #define KHELP_LIST_LOCK_ASSERT() rw_assert(&khelp_list_lock, RA_LOCKED)
67a8d61afdSLawrence Stewart
68a8d61afdSLawrence Stewart int
khelp_register_helper(struct helper * h)69a8d61afdSLawrence Stewart khelp_register_helper(struct helper *h)
70a8d61afdSLawrence Stewart {
71a8d61afdSLawrence Stewart struct helper *tmph;
72a8d61afdSLawrence Stewart int error, i, inserted;
73a8d61afdSLawrence Stewart
74933a8bffSLawrence Stewart error = inserted = 0;
75a8d61afdSLawrence Stewart refcount_init(&h->h_refcount, 0);
76a8d61afdSLawrence Stewart h->h_id = osd_register(OSD_KHELP, NULL, NULL);
77a8d61afdSLawrence Stewart
78a8d61afdSLawrence Stewart /* It's only safe to add the hooks after osd_register(). */
79a8d61afdSLawrence Stewart for (i = 0; i < h->h_nhooks && !error; i++) {
80a8d61afdSLawrence Stewart /* We don't require the module to assign hook_helper. */
81a8d61afdSLawrence Stewart h->h_hooks[i].hook_helper = h;
82933a8bffSLawrence Stewart error = hhook_add_hook_lookup(&h->h_hooks[i], HHOOK_WAITOK);
83933a8bffSLawrence Stewart if (error)
84933a8bffSLawrence Stewart printf("%s: \"%s\" khelp module unable to "
85933a8bffSLawrence Stewart "hook type %d id %d due to error %d\n", __func__,
86933a8bffSLawrence Stewart h->h_name, h->h_hooks[i].hook_type,
87933a8bffSLawrence Stewart h->h_hooks[i].hook_id, error);
88a8d61afdSLawrence Stewart }
89a8d61afdSLawrence Stewart
90a8d61afdSLawrence Stewart if (error) {
91a8d61afdSLawrence Stewart for (i--; i >= 0; i--)
92b1f53277SLawrence Stewart hhook_remove_hook_lookup(&h->h_hooks[i]);
93a8d61afdSLawrence Stewart osd_deregister(OSD_KHELP, h->h_id);
94933a8bffSLawrence Stewart } else {
95a8d61afdSLawrence Stewart KHELP_LIST_WLOCK();
96a8d61afdSLawrence Stewart /*
97a8d61afdSLawrence Stewart * Keep list of helpers sorted in descending h_id order. Due to
98a8d61afdSLawrence Stewart * the way osd_set() works, a sorted list ensures
99933a8bffSLawrence Stewart * khelp_init_osd() will operate with improved efficiency.
100a8d61afdSLawrence Stewart */
101a8d61afdSLawrence Stewart TAILQ_FOREACH(tmph, &helpers, h_next) {
102a8d61afdSLawrence Stewart if (tmph->h_id < h->h_id) {
103a8d61afdSLawrence Stewart TAILQ_INSERT_BEFORE(tmph, h, h_next);
104a8d61afdSLawrence Stewart inserted = 1;
105a8d61afdSLawrence Stewart break;
106a8d61afdSLawrence Stewart }
107a8d61afdSLawrence Stewart }
108a8d61afdSLawrence Stewart
109a8d61afdSLawrence Stewart if (!inserted)
110a8d61afdSLawrence Stewart TAILQ_INSERT_TAIL(&helpers, h, h_next);
111a8d61afdSLawrence Stewart KHELP_LIST_WUNLOCK();
112a8d61afdSLawrence Stewart }
113a8d61afdSLawrence Stewart
114a8d61afdSLawrence Stewart return (error);
115a8d61afdSLawrence Stewart }
116a8d61afdSLawrence Stewart
117a8d61afdSLawrence Stewart int
khelp_deregister_helper(struct helper * h)118a8d61afdSLawrence Stewart khelp_deregister_helper(struct helper *h)
119a8d61afdSLawrence Stewart {
120a8d61afdSLawrence Stewart struct helper *tmph;
121a8d61afdSLawrence Stewart int error, i;
122a8d61afdSLawrence Stewart
123a8d61afdSLawrence Stewart KHELP_LIST_WLOCK();
124a8d61afdSLawrence Stewart if (h->h_refcount > 0)
125a8d61afdSLawrence Stewart error = EBUSY;
126a8d61afdSLawrence Stewart else {
127a8d61afdSLawrence Stewart error = ENOENT;
128a8d61afdSLawrence Stewart TAILQ_FOREACH(tmph, &helpers, h_next) {
129a8d61afdSLawrence Stewart if (tmph == h) {
130a8d61afdSLawrence Stewart TAILQ_REMOVE(&helpers, h, h_next);
131a8d61afdSLawrence Stewart error = 0;
132a8d61afdSLawrence Stewart break;
133a8d61afdSLawrence Stewart }
134a8d61afdSLawrence Stewart }
135a8d61afdSLawrence Stewart }
136a8d61afdSLawrence Stewart KHELP_LIST_WUNLOCK();
137a8d61afdSLawrence Stewart
138a8d61afdSLawrence Stewart if (!error) {
139a8d61afdSLawrence Stewart for (i = 0; i < h->h_nhooks; i++)
140b1f53277SLawrence Stewart hhook_remove_hook_lookup(&h->h_hooks[i]);
141a8d61afdSLawrence Stewart osd_deregister(OSD_KHELP, h->h_id);
142a8d61afdSLawrence Stewart }
143a8d61afdSLawrence Stewart
144a8d61afdSLawrence Stewart return (error);
145a8d61afdSLawrence Stewart }
146a8d61afdSLawrence Stewart
147a8d61afdSLawrence Stewart int
khelp_init_osd(uint32_t classes,struct osd * hosd)148a8d61afdSLawrence Stewart khelp_init_osd(uint32_t classes, struct osd *hosd)
149a8d61afdSLawrence Stewart {
150a8d61afdSLawrence Stewart struct helper *h;
151a8d61afdSLawrence Stewart void *hdata;
152a8d61afdSLawrence Stewart int error;
153a8d61afdSLawrence Stewart
154a8d61afdSLawrence Stewart KASSERT(hosd != NULL, ("struct osd not initialised!"));
155a8d61afdSLawrence Stewart
156a8d61afdSLawrence Stewart error = 0;
157a8d61afdSLawrence Stewart
158a8d61afdSLawrence Stewart KHELP_LIST_RLOCK();
159a8d61afdSLawrence Stewart TAILQ_FOREACH(h, &helpers, h_next) {
160a8d61afdSLawrence Stewart /* If helper is correct class and needs to store OSD... */
161a8d61afdSLawrence Stewart if (h->h_classes & classes && h->h_flags & HELPER_NEEDS_OSD) {
162a8d61afdSLawrence Stewart hdata = uma_zalloc(h->h_zone, M_NOWAIT);
163a8d61afdSLawrence Stewart if (hdata == NULL) {
164a8d61afdSLawrence Stewart error = ENOMEM;
165a8d61afdSLawrence Stewart break;
166a8d61afdSLawrence Stewart }
167a8d61afdSLawrence Stewart osd_set(OSD_KHELP, hosd, h->h_id, hdata);
168a8d61afdSLawrence Stewart refcount_acquire(&h->h_refcount);
169a8d61afdSLawrence Stewart }
170a8d61afdSLawrence Stewart }
171a8d61afdSLawrence Stewart
172a8d61afdSLawrence Stewart if (error) {
173a8d61afdSLawrence Stewart /* Delete OSD that was assigned prior to the error. */
174a8d61afdSLawrence Stewart TAILQ_FOREACH(h, &helpers, h_next) {
175a8d61afdSLawrence Stewart if (h->h_classes & classes)
176a8d61afdSLawrence Stewart khelp_remove_osd(h, hosd);
177a8d61afdSLawrence Stewart }
178a8d61afdSLawrence Stewart }
179a8d61afdSLawrence Stewart KHELP_LIST_RUNLOCK();
180a8d61afdSLawrence Stewart
181a8d61afdSLawrence Stewart return (error);
182a8d61afdSLawrence Stewart }
183a8d61afdSLawrence Stewart
184a8d61afdSLawrence Stewart int
khelp_destroy_osd(struct osd * hosd)185a8d61afdSLawrence Stewart khelp_destroy_osd(struct osd *hosd)
186a8d61afdSLawrence Stewart {
187a8d61afdSLawrence Stewart struct helper *h;
188a8d61afdSLawrence Stewart int error;
189a8d61afdSLawrence Stewart
190a8d61afdSLawrence Stewart KASSERT(hosd != NULL, ("struct osd not initialised!"));
191a8d61afdSLawrence Stewart
192a8d61afdSLawrence Stewart error = 0;
193a8d61afdSLawrence Stewart
194a8d61afdSLawrence Stewart KHELP_LIST_RLOCK();
195a8d61afdSLawrence Stewart /*
196a8d61afdSLawrence Stewart * Clean up all khelp related OSD.
197a8d61afdSLawrence Stewart *
198a8d61afdSLawrence Stewart * XXXLAS: Would be nice to use something like osd_exit() here but it
199a8d61afdSLawrence Stewart * doesn't have the right semantics for this purpose.
200a8d61afdSLawrence Stewart */
201a8d61afdSLawrence Stewart TAILQ_FOREACH(h, &helpers, h_next)
202a8d61afdSLawrence Stewart khelp_remove_osd(h, hosd);
203a8d61afdSLawrence Stewart KHELP_LIST_RUNLOCK();
204a8d61afdSLawrence Stewart
205a8d61afdSLawrence Stewart return (error);
206a8d61afdSLawrence Stewart }
207a8d61afdSLawrence Stewart
208a8d61afdSLawrence Stewart static inline void
khelp_remove_osd(struct helper * h,struct osd * hosd)209a8d61afdSLawrence Stewart khelp_remove_osd(struct helper *h, struct osd *hosd)
210a8d61afdSLawrence Stewart {
211a8d61afdSLawrence Stewart void *hdata;
212a8d61afdSLawrence Stewart
213a8d61afdSLawrence Stewart if (h->h_flags & HELPER_NEEDS_OSD) {
214a8d61afdSLawrence Stewart /*
215a8d61afdSLawrence Stewart * If the current helper uses OSD and calling osd_get()
216a8d61afdSLawrence Stewart * on the helper's h_id returns non-NULL, the helper has
217a8d61afdSLawrence Stewart * OSD attached to 'hosd' which needs to be cleaned up.
218a8d61afdSLawrence Stewart */
219a8d61afdSLawrence Stewart hdata = osd_get(OSD_KHELP, hosd, h->h_id);
220a8d61afdSLawrence Stewart if (hdata != NULL) {
221a8d61afdSLawrence Stewart uma_zfree(h->h_zone, hdata);
222a8d61afdSLawrence Stewart osd_del(OSD_KHELP, hosd, h->h_id);
223a8d61afdSLawrence Stewart refcount_release(&h->h_refcount);
224a8d61afdSLawrence Stewart }
225a8d61afdSLawrence Stewart }
226a8d61afdSLawrence Stewart }
227a8d61afdSLawrence Stewart
228a8d61afdSLawrence Stewart void *
khelp_get_osd(struct osd * hosd,int32_t id)229a8d61afdSLawrence Stewart khelp_get_osd(struct osd *hosd, int32_t id)
230a8d61afdSLawrence Stewart {
231a8d61afdSLawrence Stewart
232a8d61afdSLawrence Stewart return (osd_get(OSD_KHELP, hosd, id));
233a8d61afdSLawrence Stewart }
234a8d61afdSLawrence Stewart
235a8d61afdSLawrence Stewart int32_t
khelp_get_id(char * hname)236a8d61afdSLawrence Stewart khelp_get_id(char *hname)
237a8d61afdSLawrence Stewart {
238a8d61afdSLawrence Stewart struct helper *h;
239a8d61afdSLawrence Stewart int32_t id;
240a8d61afdSLawrence Stewart
241a8d61afdSLawrence Stewart id = -1;
242a8d61afdSLawrence Stewart
243a8d61afdSLawrence Stewart KHELP_LIST_RLOCK();
244a8d61afdSLawrence Stewart TAILQ_FOREACH(h, &helpers, h_next) {
245a8d61afdSLawrence Stewart if (strncmp(h->h_name, hname, HELPER_NAME_MAXLEN) == 0) {
246a8d61afdSLawrence Stewart id = h->h_id;
247a8d61afdSLawrence Stewart break;
248a8d61afdSLawrence Stewart }
249a8d61afdSLawrence Stewart }
250a8d61afdSLawrence Stewart KHELP_LIST_RUNLOCK();
251a8d61afdSLawrence Stewart
252a8d61afdSLawrence Stewart return (id);
253a8d61afdSLawrence Stewart }
254a8d61afdSLawrence Stewart
255a8d61afdSLawrence Stewart int
khelp_add_hhook(const struct hookinfo * hki,uint32_t flags)256*89937323SZhenlei Huang khelp_add_hhook(const struct hookinfo *hki, uint32_t flags)
257a8d61afdSLawrence Stewart {
258a8d61afdSLawrence Stewart int error;
259a8d61afdSLawrence Stewart
260a8d61afdSLawrence Stewart /*
261b1f53277SLawrence Stewart * XXXLAS: Should probably include the functionality to update the
262b1f53277SLawrence Stewart * helper's h_hooks struct member.
263a8d61afdSLawrence Stewart */
264a8d61afdSLawrence Stewart error = hhook_add_hook_lookup(hki, flags);
265a8d61afdSLawrence Stewart
266a8d61afdSLawrence Stewart return (error);
267a8d61afdSLawrence Stewart }
268a8d61afdSLawrence Stewart
269a8d61afdSLawrence Stewart int
khelp_remove_hhook(const struct hookinfo * hki)270*89937323SZhenlei Huang khelp_remove_hhook(const struct hookinfo *hki)
271a8d61afdSLawrence Stewart {
272a8d61afdSLawrence Stewart int error;
273a8d61afdSLawrence Stewart
274a8d61afdSLawrence Stewart /*
275b1f53277SLawrence Stewart * XXXLAS: Should probably include the functionality to update the
276b1f53277SLawrence Stewart * helper's h_hooks struct member.
277a8d61afdSLawrence Stewart */
278a8d61afdSLawrence Stewart error = hhook_remove_hook_lookup(hki);
279a8d61afdSLawrence Stewart
280a8d61afdSLawrence Stewart return (error);
281a8d61afdSLawrence Stewart }
282a8d61afdSLawrence Stewart
28358261d30SLawrence Stewart /*
28458261d30SLawrence Stewart * Private KPI between hhook and khelp that allows khelp modules to insert hook
28558261d30SLawrence Stewart * functions into hhook points which register after the modules were loaded.
28658261d30SLawrence Stewart */
28758261d30SLawrence Stewart void
khelp_new_hhook_registered(struct hhook_head * hhh,uint32_t flags)28858261d30SLawrence Stewart khelp_new_hhook_registered(struct hhook_head *hhh, uint32_t flags)
28958261d30SLawrence Stewart {
29058261d30SLawrence Stewart struct helper *h;
29158261d30SLawrence Stewart int error, i;
29258261d30SLawrence Stewart
29358261d30SLawrence Stewart KHELP_LIST_RLOCK();
29458261d30SLawrence Stewart TAILQ_FOREACH(h, &helpers, h_next) {
29558261d30SLawrence Stewart for (i = 0; i < h->h_nhooks; i++) {
29658261d30SLawrence Stewart if (hhh->hhh_type != h->h_hooks[i].hook_type ||
29758261d30SLawrence Stewart hhh->hhh_id != h->h_hooks[i].hook_id)
29858261d30SLawrence Stewart continue;
29958261d30SLawrence Stewart error = hhook_add_hook(hhh, &h->h_hooks[i], flags);
30058261d30SLawrence Stewart if (error) {
30158261d30SLawrence Stewart printf("%s: \"%s\" khelp module unable to "
30258261d30SLawrence Stewart "hook type %d id %d due to error %d\n",
30358261d30SLawrence Stewart __func__, h->h_name,
30458261d30SLawrence Stewart h->h_hooks[i].hook_type,
30558261d30SLawrence Stewart h->h_hooks[i].hook_id, error);
30658261d30SLawrence Stewart error = 0;
30758261d30SLawrence Stewart }
30858261d30SLawrence Stewart }
30958261d30SLawrence Stewart }
31058261d30SLawrence Stewart KHELP_LIST_RUNLOCK();
31158261d30SLawrence Stewart }
31258261d30SLawrence Stewart
313a8d61afdSLawrence Stewart int
khelp_modevent(module_t mod,int event_type,void * data)314a8d61afdSLawrence Stewart khelp_modevent(module_t mod, int event_type, void *data)
315a8d61afdSLawrence Stewart {
316a8d61afdSLawrence Stewart struct khelp_modevent_data *kmd;
317a8d61afdSLawrence Stewart int error;
318a8d61afdSLawrence Stewart
319a8d61afdSLawrence Stewart kmd = (struct khelp_modevent_data *)data;
320a8d61afdSLawrence Stewart error = 0;
321a8d61afdSLawrence Stewart
322a8d61afdSLawrence Stewart switch(event_type) {
323a8d61afdSLawrence Stewart case MOD_LOAD:
324a8d61afdSLawrence Stewart if (kmd->helper->h_flags & HELPER_NEEDS_OSD) {
325a8d61afdSLawrence Stewart if (kmd->uma_zsize <= 0) {
326a8d61afdSLawrence Stewart printf("Use KHELP_DECLARE_MOD_UMA() instead!\n");
327a8d61afdSLawrence Stewart error = EDOOFUS;
328a8d61afdSLawrence Stewart break;
329a8d61afdSLawrence Stewart }
330a8d61afdSLawrence Stewart kmd->helper->h_zone = uma_zcreate(kmd->name,
331a8d61afdSLawrence Stewart kmd->uma_zsize, kmd->umactor, kmd->umadtor, NULL,
332a8d61afdSLawrence Stewart NULL, 0, 0);
333a8d61afdSLawrence Stewart }
334a8d61afdSLawrence Stewart strlcpy(kmd->helper->h_name, kmd->name, HELPER_NAME_MAXLEN);
335a8d61afdSLawrence Stewart kmd->helper->h_hooks = kmd->hooks;
336a8d61afdSLawrence Stewart kmd->helper->h_nhooks = kmd->nhooks;
337a8d61afdSLawrence Stewart if (kmd->helper->mod_init != NULL)
338a8d61afdSLawrence Stewart error = kmd->helper->mod_init();
339a8d61afdSLawrence Stewart if (!error)
340a8d61afdSLawrence Stewart error = khelp_register_helper(kmd->helper);
341a8d61afdSLawrence Stewart break;
342a8d61afdSLawrence Stewart
343a8d61afdSLawrence Stewart case MOD_QUIESCE:
344a8d61afdSLawrence Stewart case MOD_SHUTDOWN:
345a8d61afdSLawrence Stewart case MOD_UNLOAD:
346a8d61afdSLawrence Stewart error = khelp_deregister_helper(kmd->helper);
347a8d61afdSLawrence Stewart if (!error) {
348a8d61afdSLawrence Stewart if (kmd->helper->h_flags & HELPER_NEEDS_OSD)
349a8d61afdSLawrence Stewart uma_zdestroy(kmd->helper->h_zone);
350a8d61afdSLawrence Stewart if (kmd->helper->mod_destroy != NULL)
351a8d61afdSLawrence Stewart kmd->helper->mod_destroy();
352a8d61afdSLawrence Stewart } else if (error == ENOENT)
353a8d61afdSLawrence Stewart /* Do nothing and allow unload if helper not in list. */
354a8d61afdSLawrence Stewart error = 0;
355415c1c74SMike Karels else if (error == EBUSY && event_type != MOD_SHUTDOWN)
356a8d61afdSLawrence Stewart printf("Khelp module \"%s\" can't unload until its "
357a8d61afdSLawrence Stewart "refcount drops from %d to 0.\n", kmd->name,
358a8d61afdSLawrence Stewart kmd->helper->h_refcount);
359a8d61afdSLawrence Stewart break;
360a8d61afdSLawrence Stewart
361a8d61afdSLawrence Stewart default:
362a8d61afdSLawrence Stewart error = EINVAL;
363a8d61afdSLawrence Stewart break;
364a8d61afdSLawrence Stewart }
365a8d61afdSLawrence Stewart
366a8d61afdSLawrence Stewart return (error);
367a8d61afdSLawrence Stewart }
368