summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorlstewart <lstewart@FreeBSD.org>2013-06-15 05:57:29 +0000
committerlstewart <lstewart@FreeBSD.org>2013-06-15 05:57:29 +0000
commitd36754819367380242eb3a06f8af722934064444 (patch)
tree98e275f1cfad8d91268550ace0b032fe59cfb3a6
parent90080fdf0774fdb0967bc134795d58ec414cdde8 (diff)
downloadFreeBSD-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.c15
-rw-r--r--sys/kern/kern_khelp.c126
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);
OpenPOWER on IntegriCloud