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