diff -r 622908642a20 sys/conf/files --- a/sys/conf/files Mon Dec 06 17:57:58 2010 +1100 +++ b/sys/conf/files Sun Dec 12 00:59:58 2010 +1100 @@ -2140,6 +2140,7 @@ kern/kern_idle.c standard kern/kern_intr.c standard kern/kern_jail.c standard +kern/kern_khelp.c standard kern/kern_kthread.c standard kern/kern_ktr.c optional ktr kern/kern_ktrace.c standard diff -r 622908642a20 sys/kern/kern_khelp.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/sys/kern/kern_khelp.c Sun Dec 12 00:59:58 2010 +1100 @@ -0,0 +1,366 @@ +/*- + * Copyright (c) 2010 Lawrence Stewart + * Copyright (c) 2010 The FreeBSD Foundation + * All rights reserved. + * + * This software was developed by Lawrence Stewart while studying at the Centre + * for Advanced Internet Architectures, Swinburne University, made possible in + * part by grants from the FreeBSD Foundation and Cisco University Research + * Program Fund at Community Foundation Silicon Valley. + * + * Portions of this software were developed at the Centre for Advanced + * Internet Architectures, Swinburne University of Technology, Melbourne, + * Australia by Lawrence Stewart under sponsorship from the FreeBSD Foundation. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +__FBSDID("$FreeBSD$"); + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +static struct rwlock khelp_list_lock; +RW_SYSINIT(khelplistlock, &khelp_list_lock, "helper list lock"); + +static TAILQ_HEAD(helper_head, helper) helpers = TAILQ_HEAD_INITIALIZER(helpers); + +/* Private function prototypes. */ +static inline void khelp_remove_osd(struct helper *h, struct osd *hosd); + +#define KHELP_LIST_WLOCK() rw_wlock(&khelp_list_lock) +#define KHELP_LIST_WUNLOCK() rw_wunlock(&khelp_list_lock) +#define KHELP_LIST_RLOCK() rw_rlock(&khelp_list_lock) +#define KHELP_LIST_RUNLOCK() rw_runlock(&khelp_list_lock) +#define KHELP_LIST_LOCK_ASSERT() rw_assert(&khelp_list_lock, RA_LOCKED) + +int +khelp_add_hhook(int hhook_type, int hhook_id, struct helper *helper, + hhook_func_t hook, void *udata, uint32_t flags) +{ + VNET_ITERATOR_DECL(vnet_iter); + int error; + + error = 0; + + VNET_LIST_RLOCK_NOSLEEP(); + VNET_FOREACH(vnet_iter) { + CURVNET_SET(vnet_iter); + error = hhook_add_hook_lookup(hhook_type, hhook_id, helper, + hook, udata, flags); + CURVNET_RESTORE(); + if (error) + break; + } + VNET_LIST_RUNLOCK_NOSLEEP(); + + return (error); +} + +int +khelp_deregister_helper(struct helper *h) +{ + struct helper *tmph; + int error, i; + + error = 0; + + KHELP_LIST_WLOCK(); + if (h->h_refcount > 0) + error = EBUSY; + else { + error = ENOENT; + TAILQ_FOREACH(tmph, &helpers, h_next) { + if (tmph == h) { + TAILQ_REMOVE(&helpers, h, h_next); + error = 0; + break; + } + } + } + KHELP_LIST_WUNLOCK(); + + if (!error) { + if (h->h_nhooks > 0) { + for (i = 0; i < h->h_nhooks; i++) + khelp_remove_hhook(h->h_hooks[i].hook_type, + h->h_hooks[i].hook_id, h->h_hooks[i].hook_func, + h->h_hooks[i].hook_udata); + } + osd_deregister(OSD_KHELP, h->h_id); + } + + return (error); +} + +int +khelp_destroy_osd(struct osd *hosd) +{ + struct helper *h; + int error; + + KASSERT(hosd != NULL, ("struct osd not initialised!")); + + error = 0; + + KHELP_LIST_RLOCK(); + /* + * Clean up all khelp related OSD. + * + * XXXLAS: Would be nice to use something like osd_exit() here but it + * doesn't have the right semantics for this purpose. + */ + TAILQ_FOREACH(h, &helpers, h_next) + khelp_remove_osd(h, hosd); + KHELP_LIST_RUNLOCK(); + + return (error); +} + +int32_t +khelp_get_id(char *hname) +{ + struct helper *h; + int32_t id; + + id = -1; + + KHELP_LIST_RLOCK(); + TAILQ_FOREACH(h, &helpers, h_next) { + if (strncmp(h->h_name, hname, HELPER_NAME_MAXLEN) == 0) { + id = h->h_id; + break; + } + } + KHELP_LIST_RUNLOCK(); + + return (id); +} + +void * +khelp_get_osd(struct osd *hosd, int32_t id) +{ + + return (osd_get(OSD_KHELP, hosd, id)); +} + +int +khelp_modevent(module_t mod, int event_type, void *data) +{ + struct khelp_modevent_data *kmd; + int error; + + kmd = (struct khelp_modevent_data *)data; + error = 0; + + switch(event_type) { + case MOD_LOAD: + if (kmd->helper->h_flags & HELPER_NEEDS_OSD) { + if (kmd->uma_zsize <= 0) { + printf("Use DECLARE_HELPER_UMA() instead!\n"); + error = EDOOFUS; + break; + } + kmd->helper->h_zone = uma_zcreate(kmd->name, + kmd->uma_zsize, kmd->umactor, kmd->umadtor, NULL, + NULL, 0, 0); + if (kmd->helper->h_zone == NULL) { + error = ENOMEM; + break; + } + } + strlcpy(kmd->helper->h_name, kmd->name, HELPER_NAME_MAXLEN); + if (kmd->helper->mod_init != NULL) + error = kmd->helper->mod_init(); + if (!error) + error = khelp_register_helper(kmd->helper); + break; + + case MOD_QUIESCE: + case MOD_SHUTDOWN: + case MOD_UNLOAD: + error = khelp_deregister_helper(kmd->helper); + if (!error) { + if (kmd->helper->h_flags & HELPER_NEEDS_OSD) + uma_zdestroy(kmd->helper->h_zone); + if (kmd->helper->mod_destroy != NULL) + kmd->helper->mod_destroy(); + } else if (error == ENOENT) + /* Do nothing and allow unload if helper not in list. */ + error = 0; + else if (error == EBUSY) + printf("Khelp module \"%s\" can't unload until its " + "refcount drops from %d to 0.\n", kmd->name, + kmd->helper->h_refcount); + break; + + default: + error = EINVAL; + break; + } + + return (error); +} + +int +khelp_init_osd(uint32_t classes, struct osd *hosd) +{ + struct helper *h; + void *hdata; + int error; + + KASSERT(hosd != NULL, ("struct osd not initialised!")); + + error = 0; + + KHELP_LIST_RLOCK(); + TAILQ_FOREACH(h, &helpers, h_next) { + /* If helper is correct class and needs to store OSD... */ + if (h->h_classes & classes && h->h_flags & HELPER_NEEDS_OSD) { + hdata = uma_zalloc(h->h_zone, M_NOWAIT); + if (hdata == NULL) { + error = ENOMEM; + break; + } + osd_set(OSD_KHELP, hosd, h->h_id, hdata); + refcount_acquire(&h->h_refcount); + } + } + + if (error) { + /* Delete OSD that was assigned prior to the error. */ + TAILQ_FOREACH(h, &helpers, h_next) { + if (h->h_classes & classes) + khelp_remove_osd(h, hosd); + } + } + KHELP_LIST_RUNLOCK(); + + return (error); +} + +int +khelp_register_helper(struct helper *h) +{ + struct helper *tmph; + int error, i, inserted; + + error = 0; + inserted = 0; + refcount_init(&h->h_refcount, 0); + h->h_id = osd_register(OSD_KHELP, NULL, NULL); + + if (h->h_nhooks > 0) { + for (i = 0; i < h->h_nhooks && !error; i++) + error = khelp_add_hhook(h->h_hooks[i].hook_type, + h->h_hooks[i].hook_id, h, h->h_hooks[i].hook_func, + h->h_hooks[i].hook_udata, HHOOK_NOWAIT); + + if (error) { + for (i--; i >= 0; i--) + khelp_remove_hhook(h->h_hooks[i].hook_type, + h->h_hooks[i].hook_id, + h->h_hooks[i].hook_func, + h->h_hooks[i].hook_udata); + + osd_deregister(OSD_KHELP, h->h_id); + } + } + + if (!error) { + KHELP_LIST_WLOCK(); + /* + * Keep list of helpers sorted in descending h_id order. Due to + * the way osd_set() works, a sorted list ensures + * init_helper_osd() will operate with improved efficiency. + */ + TAILQ_FOREACH(tmph, &helpers, h_next) { + if (tmph->h_id < h->h_id) { + TAILQ_INSERT_BEFORE(tmph, h, h_next); + inserted = 1; + break; + } + } + + if (!inserted) + TAILQ_INSERT_TAIL(&helpers, h, h_next); + KHELP_LIST_WUNLOCK(); + } + + return (error); +} + +int +khelp_remove_hhook(int hhook_type, int hhook_id, hhook_func_t hook, void *udata) +{ + VNET_ITERATOR_DECL(vnet_iter); + int error; + + error = 0; + + VNET_LIST_RLOCK_NOSLEEP(); + VNET_FOREACH(vnet_iter) { + CURVNET_SET(vnet_iter); + error = hhook_remove_hook_lookup(hhook_type, hhook_id, hook, udata); + CURVNET_RESTORE(); + + if (error) + break; + } + VNET_LIST_RUNLOCK_NOSLEEP(); + + return (error); +} + +static inline void +khelp_remove_osd(struct helper *h, struct osd *hosd) +{ + void *hdata; + + if (h->h_flags & HELPER_NEEDS_OSD) { + /* + * If the current helper uses OSD and calling osd_get() + * on the helper's h_id returns non-NULL, the helper has + * OSD attached to 'hosd' which needs to be cleaned up. + */ + hdata = osd_get(OSD_KHELP, hosd, h->h_id); + if (hdata != NULL) { + uma_zfree(h->h_zone, hdata); + osd_del(OSD_KHELP, hosd, h->h_id); + refcount_release(&h->h_refcount); + } + } +} diff -r 622908642a20 sys/sys/khelp.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/sys/sys/khelp.h Sun Dec 12 00:59:58 2010 +1100 @@ -0,0 +1,70 @@ +/*- + * Copyright (c) 2010 Lawrence Stewart + * Copyright (c) 2010 The FreeBSD Foundation + * All rights reserved. + * + * This software was developed by Lawrence Stewart while studying at the Centre + * for Advanced Internet Architectures, Swinburne University, made possible in + * part by grants from the FreeBSD Foundation and Cisco University Research + * Program Fund at Community Foundation Silicon Valley. + * + * Portions of this software were developed at the Centre for Advanced + * Internet Architectures, Swinburne University of Technology, Melbourne, + * Australia by Lawrence Stewart under sponsorship from the FreeBSD Foundation. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD$ + */ + +/* + * A KPI for managing kernel helper modules which perform useful functionality + * within the kernel. Originally released as part of the NewTCP research + * project at Swinburne University's Centre for Advanced Internet Architectures, + * Melbourne, Australia, which was made possible in part by a grant from the + * Cisco University Research Program Fund at Community Foundation Silicon + * Valley. More details are available at: + * http://caia.swin.edu.au/urp/newtcp/ + */ + +#ifndef _SYS_KHELP_H_ +#define _SYS_KHELP_H_ + +struct helper; +struct osd; + +/* Helper classes. */ +#define HELPER_CLASS_TCP 0x00000001 + +/* Public KPI functions. */ +int khelp_add_hhook(int hhook_type, int hhook_id, struct helper *helper, + hhook_func_t hook, void *udata, uint32_t flags); +int khelp_deregister_helper(struct helper *h); +int khelp_destroy_osd(struct osd *hosd); +int32_t khelp_get_id(char *hname); +void * khelp_get_osd(struct osd *hosd, int32_t id); +int khelp_init_osd(uint32_t classes, struct osd *hosd); +int khelp_register_helper(struct helper *h); +int khelp_remove_hhook(int hhook_type, int hhook_id, hhook_func_t hook, + void *udata); + +#endif /* _SYS_KHELP_H_ */ diff -r 622908642a20 sys/sys/module_khelp.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/sys/sys/module_khelp.h Sun Dec 12 00:59:58 2010 +1100 @@ -0,0 +1,111 @@ +/*- + * Copyright (c) 2010 Lawrence Stewart + * Copyright (c) 2010 The FreeBSD Foundation + * All rights reserved. + * + * This software was developed by Lawrence Stewart while studying at the Centre + * for Advanced Internet Architectures, Swinburne University, made possible in + * part by grants from the FreeBSD Foundation and Cisco University Research + * Program Fund at Community Foundation Silicon Valley. + * + * Portions of this software were developed at the Centre for Advanced + * Internet Architectures, Swinburne University of Technology, Melbourne, + * Australia by Lawrence Stewart under sponsorship from the FreeBSD Foundation. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD$ + */ + +#ifndef _SYS_MODULE_KHELP_H_ +#define _SYS_MODULE_KHELP_H_ + +/* XXXLAS: Needed for uma related typedefs. */ +#include + +/* Helper flags. */ +#define HELPER_NEEDS_OSD 0x0001 + +struct hook { + int hook_type; + int hook_id; + void *hook_udata; + hhook_func_t hook_func; +}; + +struct helper { + int (*mod_init) (void); + int (*mod_destroy) (void); +#define HELPER_NAME_MAXLEN 16 + char h_name[HELPER_NAME_MAXLEN]; + uma_zone_t h_zone; + struct hook *h_hooks; + uint32_t h_nhooks; + uint32_t h_classes; + int32_t h_id; + volatile uint32_t h_refcount; + uint16_t h_flags; + TAILQ_ENTRY(helper) h_next; +}; + +struct khelp_modevent_data { + char name[HELPER_NAME_MAXLEN]; + struct helper *helper; + int uma_zsize; + uma_ctor umactor; + uma_dtor umadtor; +}; + +#define DECLARE_HELPER(hname, hdata, version) \ + static struct khelp_modevent_data kmd_##hname = { \ + .name = #hname, \ + .helper = hdata \ + }; \ + static moduledata_t h_##hname = { \ + .name = #hname, \ + .evhand = khelp_modevent, \ + .priv = &kmd_##hname \ + }; \ + DECLARE_MODULE(hname, h_##hname, SI_SUB_PROTO_IFATTACHDOMAIN, \ + SI_ORDER_ANY); \ + MODULE_VERSION(hname, version) + +#define DECLARE_HELPER_UMA(hname, hdata, version, size, ctor, dtor) \ + static struct khelp_modevent_data kmd_##hname = { \ + .name = #hname, \ + .helper = hdata, \ + .uma_zsize = size, \ + .umactor = ctor, \ + .umadtor = dtor \ + }; \ + static moduledata_t h_##hname = { \ + .name = #hname, \ + .evhand = khelp_modevent, \ + .priv = &kmd_##hname \ + }; \ + DECLARE_MODULE(hname, h_##hname, SI_SUB_PROTO_IFATTACHDOMAIN, \ + SI_ORDER_ANY); \ + MODULE_VERSION(hname, version) + +int khelp_modevent(module_t mod, int type, void *data); + +#endif /* _SYS_MODULE_KHELP_H_ */ diff -r 622908642a20 sys/sys/osd.h --- a/sys/sys/osd.h Mon Dec 06 17:57:58 2010 +1100 +++ b/sys/sys/osd.h Sun Dec 12 00:59:58 2010 +1100 @@ -46,9 +46,10 @@ #define OSD_THREAD 0 #define OSD_JAIL 1 +#define OSD_KHELP 2 #define OSD_FIRST OSD_THREAD -#define OSD_LAST OSD_JAIL +#define OSD_LAST OSD_KHELP typedef void (*osd_destructor_t)(void *value); typedef int (*osd_method_t)(void *obj, void *data);