--- Add support for non-virtualised hhook points, which are uniquely identified --- by type and id, as compared to virtualised hook points which are now --- uniquely identified by type, id and a vid (which for vimage is the pointer --- to the vnet that the hhook resides in). --- --- All hhook_head structs for both virtualised and non-virtualised hook --- points coexist in hhook_head_list, and a separate list is maintained for --- hhook points within each vnet to simplify some vimage-related housekeeping. --- --- Reviewed by: ? --- MFC after: 1 week --- Index: sys/kern/kern_hhook.c =================================================================== --- sys/kern/kern_hhook.c (revision 251725) +++ sys/kern/kern_hhook.c (working copy) @@ -54,22 +54,23 @@ __FBSDID("$FreeBSD$"); struct hhook { hhook_func_t hhk_func; struct helper *hhk_helper; void *hhk_udata; STAILQ_ENTRY(hhook) hhk_next; }; static MALLOC_DEFINE(M_HHOOK, "hhook", "Helper hooks are linked off hhook_head lists"); LIST_HEAD(hhookheadhead, hhook_head); -VNET_DEFINE(struct hhookheadhead, hhook_head_list); -#define V_hhook_head_list VNET(hhook_head_list) +struct hhookheadhead hhook_head_list; +VNET_DEFINE(struct hhookheadhead, hhook_vhead_list); +#define V_hhook_vhead_list VNET(hhook_vhead_list) static struct mtx hhook_head_list_lock; MTX_SYSINIT(hhookheadlistlock, &hhook_head_list_lock, "hhook_head list lock", MTX_DEF); /* Private function prototypes. */ static void hhook_head_destroy(struct hhook_head *hhh); #define HHHLIST_LOCK() mtx_lock(&hhook_head_list_lock) #define HHHLIST_UNLOCK() mtx_unlock(&hhook_head_list_lock) @@ -238,65 +239,61 @@ hhook_head_register(int32_t hhook_type, struct hhook_head *tmphhh; tmphhh = hhook_head_get(hhook_type, hhook_id); if (tmphhh != NULL) { /* Hook point previously registered. */ hhook_head_release(tmphhh); return (EEXIST); } - /* XXXLAS: Need to implement support for non-virtualised hooks. */ - if ((flags & HHOOK_HEADISINVNET) == 0) { - printf("%s: only vnet-style virtualised hooks can be used\n", - __func__); - return (EINVAL); - } - tmphhh = malloc(sizeof(struct hhook_head), M_HHOOK, M_ZERO | ((flags & HHOOK_WAITOK) ? M_WAITOK : M_NOWAIT)); if (tmphhh == NULL) return (ENOMEM); tmphhh->hhh_type = hhook_type; tmphhh->hhh_id = hhook_id; 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); + HHHLIST_LOCK(); if (flags & HHOOK_HEADISINVNET) { tmphhh->hhh_flags |= HHH_ISINVNET; - HHHLIST_LOCK(); - LIST_INSERT_HEAD(&V_hhook_head_list, tmphhh, hhh_next); - HHHLIST_UNLOCK(); - } else { - /* XXXLAS: Add tmphhh to the non-virtualised list. */ + KASSERT(curvnet != NULL, ("curvnet is NULL")); + tmphhh->hhh_vid = (uintptr_t)curvnet; + LIST_INSERT_HEAD(&V_hhook_vhead_list, tmphhh, hhh_vnext); } + LIST_INSERT_HEAD(&hhook_head_list, tmphhh, hhh_next); + HHHLIST_UNLOCK(); return (0); } static void hhook_head_destroy(struct hhook_head *hhh) { struct hhook *tmp, *tmp2; HHHLIST_LOCK_ASSERT(); LIST_REMOVE(hhh, hhh_next); + if (hhook_head_is_virtualised(hhh) == HHOOK_HEADISINVNET) + LIST_REMOVE(hhh, hhh_vnext); HHH_WLOCK(hhh); STAILQ_FOREACH_SAFE(tmp, &hhh->hhh_hooks, hhk_next, tmp2) free(tmp, M_HHOOK); HHH_WUNLOCK(hhh); HHH_LOCK_DESTROY(hhh); free(hhh, M_HHOOK); } /* * Remove a helper hook point. @@ -340,24 +337,29 @@ hhook_head_deregister_lookup(int32_t hho /* * Lookup and return the hhook_head struct associated with the specified type * and id, or NULL if not found. If found, the hhook_head's refcount is bumped. */ struct hhook_head * hhook_head_get(int32_t hhook_type, int32_t hhook_id) { struct hhook_head *hhh; - /* XXXLAS: Pick hhook_head_list based on hhook_head flags. */ HHHLIST_LOCK(); - LIST_FOREACH(hhh, &V_hhook_head_list, hhh_next) { + LIST_FOREACH(hhh, &hhook_head_list, hhh_next) { if (hhh->hhh_type == hhook_type && hhh->hhh_id == hhook_id) { + if (hhook_head_is_virtualised(hhh) == + HHOOK_HEADISINVNET) { + KASSERT(curvnet != NULL, ("curvnet is NULL")); + if (hhh->hhh_vid != (uintptr_t)curvnet) + continue; + } refcount_acquire(&hhh->hhh_refcount); break; } } HHHLIST_UNLOCK(); return (hhh); } void @@ -405,48 +407,48 @@ hhook_head_is_virtualised_lookup(int32_t return (ret); } /* * Vnet created and being initialised. */ static void hhook_vnet_init(const void *unused __unused) { - LIST_INIT(&V_hhook_head_list); + LIST_INIT(&V_hhook_vhead_list); } /* * Vnet being torn down and destroyed. */ static void hhook_vnet_uninit(const void *unused __unused) { struct hhook_head *hhh, *tmphhh; /* * If subsystems which export helper hook points use the hhook KPI * correctly, the loop below should have no work to do because the * subsystem should have already called hhook_head_deregister(). */ HHHLIST_LOCK(); - LIST_FOREACH_SAFE(hhh, &V_hhook_head_list, hhh_next, tmphhh) { + LIST_FOREACH_SAFE(hhh, &V_hhook_vhead_list, hhh_vnext, tmphhh) { printf("%s: hhook_head type=%d, id=%d cleanup required\n", __func__, hhh->hhh_type, hhh->hhh_id); hhook_head_destroy(hhh); } HHHLIST_UNLOCK(); } /* - * When a vnet is created and being initialised, init the V_hhook_head_list. + * When a vnet is created and being initialised, init the V_hhook_vhead_list. */ VNET_SYSINIT(hhook_vnet_init, SI_SUB_PROTO_BEGIN, SI_ORDER_FIRST, hhook_vnet_init, NULL); /* * The hhook KPI provides a mechanism for subsystems which export helper hook * points to clean up on vnet tear down, but in case the KPI is misused, * provide a function to clean up and free memory for a vnet being destroyed. */ VNET_SYSUNINIT(hhook_vnet_uninit, SI_SUB_PROTO_BEGIN, SI_ORDER_FIRST, Index: sys/sys/hhook.h =================================================================== --- sys/sys/hhook.h (revision 251681) +++ sys/sys/hhook.h (working copy) @@ -84,26 +84,28 @@ struct hookinfo { int32_t hook_type; }; /* * Ideally this would be private but we need access to the hhh_nhooks member * variable in order to make the HHOOKS_RUN_IF() macro low impact. */ struct hhook_head { STAILQ_HEAD(hhook_list, hhook) hhh_hooks; struct rmlock hhh_lock; + uintptr_t hhh_vid; int32_t hhh_id; int32_t hhh_nhooks; int32_t hhh_type; uint32_t hhh_flags; volatile uint32_t hhh_refcount; LIST_ENTRY(hhook_head) hhh_next; + LIST_ENTRY(hhook_head) hhh_vnext; }; /* Public KPI functions. */ void hhook_run_hooks(struct hhook_head *hhh, void *ctx_data, struct osd *hosd); int hhook_add_hook(struct hhook_head *hhh, struct hookinfo *hki, uint32_t flags); int hhook_add_hook_lookup(struct hookinfo *hki, uint32_t flags);