diff options
author | lstewart <lstewart@FreeBSD.org> | 2013-06-15 05:57:29 +0000 |
---|---|---|
committer | lstewart <lstewart@FreeBSD.org> | 2013-06-15 05:57:29 +0000 |
commit | d36754819367380242eb3a06f8af722934064444 (patch) | |
tree | 98e275f1cfad8d91268550ace0b032fe59cfb3a6 | |
parent | 90080fdf0774fdb0967bc134795d58ec414cdde8 (diff) | |
download | FreeBSD-src-d36754819367380242eb3a06f8af722934064444.zip FreeBSD-src-d36754819367380242eb3a06f8af722934064444.tar.gz |
Add a private KPI between hhook and khelp that allows khelp modules to insert
hook functions into hhook points which register after the modules were loaded -
potentially useful during boot or if hhook points are dynamically registered.
MFC after: 1 week
-rw-r--r-- | sys/kern/kern_hhook.c | 15 | ||||
-rw-r--r-- | sys/kern/kern_khelp.c | 126 |
2 files changed, 40 insertions, 101 deletions
diff --git a/sys/kern/kern_hhook.c b/sys/kern/kern_hhook.c index 9e3919e..a9b5874 100644 --- a/sys/kern/kern_hhook.c +++ b/sys/kern/kern_hhook.c @@ -74,6 +74,7 @@ static uint32_t n_hhookheads; /* Private function prototypes. */ static void hhook_head_destroy(struct hhook_head *hhh); +void khelp_new_hhook_registered(struct hhook_head *hhh, uint32_t flags); #define HHHLIST_LOCK() mtx_lock(&hhook_head_list_lock) #define HHHLIST_UNLOCK() mtx_unlock(&hhook_head_list_lock) @@ -311,12 +312,7 @@ hhook_head_register(int32_t hhook_type, int32_t hhook_id, struct hhook_head **hh tmphhh->hhh_nhooks = 0; STAILQ_INIT(&tmphhh->hhh_hooks); HHH_LOCK_INIT(tmphhh); - - if (hhh != NULL) { - refcount_init(&tmphhh->hhh_refcount, 1); - *hhh = tmphhh; - } else - refcount_init(&tmphhh->hhh_refcount, 0); + refcount_init(&tmphhh->hhh_refcount, 1); HHHLIST_LOCK(); if (flags & HHOOK_HEADISINVNET) { @@ -331,6 +327,13 @@ hhook_head_register(int32_t hhook_type, int32_t hhook_id, struct hhook_head **hh n_hhookheads++; HHHLIST_UNLOCK(); + khelp_new_hhook_registered(tmphhh, flags); + + if (hhh != NULL) + *hhh = tmphhh; + else + refcount_release(&tmphhh->hhh_refcount); + return (0); } diff --git a/sys/kern/kern_khelp.c b/sys/kern/kern_khelp.c index fe7687e..7695ef5 100644 --- a/sys/kern/kern_khelp.c +++ b/sys/kern/kern_khelp.c @@ -40,7 +40,6 @@ __FBSDID("$FreeBSD$"); #include <sys/param.h> #include <sys/kernel.h> #include <sys/hhook.h> -#include <sys/jail.h> #include <sys/khelp.h> #include <sys/lock.h> #include <sys/malloc.h> @@ -52,8 +51,6 @@ __FBSDID("$FreeBSD$"); #include <sys/rwlock.h> #include <sys/systm.h> -#include <net/vnet.h> - static struct rwlock khelp_list_lock; RW_SYSINIT(khelplistlock, &khelp_list_lock, "helper list lock"); @@ -61,6 +58,7 @@ 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); +void khelp_new_hhook_registered(struct hhook_head *hhh, uint32_t flags); #define KHELP_LIST_WLOCK() rw_wlock(&khelp_list_lock) #define KHELP_LIST_WUNLOCK() rw_wunlock(&khelp_list_lock) @@ -289,6 +287,36 @@ khelp_remove_hhook(struct hookinfo *hki) return (error); } +/* + * Private KPI between hhook and khelp that allows khelp modules to insert hook + * functions into hhook points which register after the modules were loaded. + */ +void +khelp_new_hhook_registered(struct hhook_head *hhh, uint32_t flags) +{ + struct helper *h; + int error, i; + + KHELP_LIST_RLOCK(); + TAILQ_FOREACH(h, &helpers, h_next) { + for (i = 0; i < h->h_nhooks; i++) { + if (hhh->hhh_type != h->h_hooks[i].hook_type || + hhh->hhh_id != h->h_hooks[i].hook_id) + continue; + error = hhook_add_hook(hhh, &h->h_hooks[i], flags); + if (error) { + printf("%s: \"%s\" khelp module unable to " + "hook type %d id %d due to error %d\n", + __func__, h->h_name, + h->h_hooks[i].hook_type, + h->h_hooks[i].hook_id, error); + error = 0; + } + } + } + KHELP_LIST_RUNLOCK(); +} + int khelp_modevent(module_t mod, int event_type, void *data) { @@ -348,95 +376,3 @@ khelp_modevent(module_t mod, int event_type, void *data) return (error); } - -/* - * This function is called in two separate situations: - * - * - When the kernel is booting, it is called directly by the SYSINIT framework - * to allow Khelp modules which were compiled into the kernel or loaded by the - * boot loader to insert their non-virtualised hook functions into the kernel. - * - * - When the kernel is booting or a vnet is created, this function is also - * called indirectly through khelp_vnet_init() by the vnet initialisation code. - * In this situation, Khelp modules are able to insert their virtualised hook - * functions into the virtualised hook points in the vnet which is being - * initialised. In the case where the kernel is not compiled with "options - * VIMAGE", this step is still run once at boot, but the hook functions get - * transparently inserted into the standard unvirtualised network stack. - */ -static void -khelp_init(const void *vnet) -{ - struct helper *h; - int error, i, vinit; - int32_t htype, hid; - - error = 0; - vinit = vnet != NULL; - - KHELP_LIST_RLOCK(); - TAILQ_FOREACH(h, &helpers, h_next) { - for (i = 0; i < h->h_nhooks && !error; i++) { - htype = h->h_hooks[i].hook_type; - hid = h->h_hooks[i].hook_id; - - /* - * If we're doing a virtualised init (vinit != 0) and - * the hook point is virtualised, or we're doing a plain - * sysinit at boot and the hook point is not - * virtualised, insert the hook. - */ - if ((hhook_head_is_virtualised_lookup(htype, hid) == - HHOOK_HEADISINVNET && vinit) || - (!hhook_head_is_virtualised_lookup(htype, hid) && - !vinit)) { - error = hhook_add_hook_lookup(&h->h_hooks[i], - HHOOK_NOWAIT); - } - } - - if (error) { - /* Remove any helper's hooks we successfully added. */ - for (i--; i >= 0; i--) - hhook_remove_hook_lookup(&h->h_hooks[i]); - - printf("%s: Failed to add hooks for helper \"%s\" (%p)", - __func__, h->h_name, h); - if (vinit) - printf(" to vnet %p.\n", vnet); - else - printf(".\n"); - - error = 0; - } - } - KHELP_LIST_RUNLOCK(); -} - -/* - * Vnet created and being initialised. - */ -static void -khelp_vnet_init(const void *unused __unused) -{ - - khelp_init(TD_TO_VNET(curthread)); -} - - -/* - * As the kernel boots, allow Khelp modules which were compiled into the kernel - * or loaded by the boot loader to insert their non-virtualised hook functions - * into the kernel. - */ -SYSINIT(khelp_init, SI_SUB_PROTO_END, SI_ORDER_FIRST, khelp_init, NULL); - -/* - * When a vnet is created and being initialised, we need to insert the helper - * hook functions for all currently registered Khelp modules into the vnet's - * helper hook points. The hhook KPI provides a mechanism for subsystems which - * export helper hook points to clean up on vnet shutdown, so we don't need a - * VNET_SYSUNINIT for Khelp. - */ -VNET_SYSINIT(khelp_vnet_init, SI_SUB_PROTO_END, SI_ORDER_FIRST, - khelp_vnet_init, NULL); |