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
This commit is contained in:
parent
127a9483ed
commit
58261d30e1
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
|
Loading…
x
Reference in New Issue
Block a user