1a8d61afdSLawrence Stewart /*- 24d846d26SWarner Losh * SPDX-License-Identifier: BSD-2-Clause 38a36da99SPedro F. Giffuni * 4b1f53277SLawrence Stewart * Copyright (c) 2010,2013 Lawrence Stewart <lstewart@freebsd.org> 5a8d61afdSLawrence Stewart * Copyright (c) 2010 The FreeBSD Foundation 6a8d61afdSLawrence Stewart * All rights reserved. 7a8d61afdSLawrence Stewart * 8a8d61afdSLawrence Stewart * This software was developed by Lawrence Stewart while studying at the Centre 9891b8ed4SLawrence Stewart * for Advanced Internet Architectures, Swinburne University of Technology, 10891b8ed4SLawrence Stewart * made possible in part by grants from the FreeBSD Foundation and Cisco 11891b8ed4SLawrence Stewart * University Research Program Fund at Community Foundation Silicon Valley. 12a8d61afdSLawrence Stewart * 13a8d61afdSLawrence Stewart * Portions of this software were developed at the Centre for Advanced 14a8d61afdSLawrence Stewart * Internet Architectures, Swinburne University of Technology, Melbourne, 15a8d61afdSLawrence Stewart * Australia by Lawrence Stewart under sponsorship from the FreeBSD Foundation. 16a8d61afdSLawrence Stewart * 17a8d61afdSLawrence Stewart * Redistribution and use in source and binary forms, with or without 18a8d61afdSLawrence Stewart * modification, are permitted provided that the following conditions 19a8d61afdSLawrence Stewart * are met: 20a8d61afdSLawrence Stewart * 1. Redistributions of source code must retain the above copyright 21a8d61afdSLawrence Stewart * notice, this list of conditions and the following disclaimer. 22a8d61afdSLawrence Stewart * 2. Redistributions in binary form must reproduce the above copyright 23a8d61afdSLawrence Stewart * notice, this list of conditions and the following disclaimer in the 24a8d61afdSLawrence Stewart * documentation and/or other materials provided with the distribution. 25a8d61afdSLawrence Stewart * 26a8d61afdSLawrence Stewart * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 27a8d61afdSLawrence Stewart * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 28a8d61afdSLawrence Stewart * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 29a8d61afdSLawrence Stewart * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 30a8d61afdSLawrence Stewart * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 31a8d61afdSLawrence Stewart * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 32a8d61afdSLawrence Stewart * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 33a8d61afdSLawrence Stewart * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 34a8d61afdSLawrence Stewart * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 35a8d61afdSLawrence Stewart * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 36a8d61afdSLawrence Stewart * SUCH DAMAGE. 37a8d61afdSLawrence Stewart */ 38a8d61afdSLawrence Stewart 39a8d61afdSLawrence Stewart #include <sys/param.h> 40a8d61afdSLawrence Stewart #include <sys/kernel.h> 41a8d61afdSLawrence Stewart #include <sys/hhook.h> 42a8d61afdSLawrence Stewart #include <sys/khelp.h> 43a8d61afdSLawrence Stewart #include <sys/malloc.h> 44a8d61afdSLawrence Stewart #include <sys/module.h> 45a8d61afdSLawrence Stewart #include <sys/module_khelp.h> 46a8d61afdSLawrence Stewart #include <sys/osd.h> 47a8d61afdSLawrence Stewart #include <sys/queue.h> 48a8d61afdSLawrence Stewart #include <sys/refcount.h> 49a8d61afdSLawrence Stewart #include <sys/systm.h> 50a8d61afdSLawrence Stewart 51a8d61afdSLawrence Stewart #include <net/vnet.h> 52a8d61afdSLawrence Stewart 53a8d61afdSLawrence Stewart struct hhook { 54a8d61afdSLawrence Stewart hhook_func_t hhk_func; 55a8d61afdSLawrence Stewart struct helper *hhk_helper; 56a8d61afdSLawrence Stewart void *hhk_udata; 57a8d61afdSLawrence Stewart STAILQ_ENTRY(hhook) hhk_next; 58a8d61afdSLawrence Stewart }; 59a8d61afdSLawrence Stewart 606bed196cSSergey Kandaurov static MALLOC_DEFINE(M_HHOOK, "hhook", "Helper hooks are linked off hhook_head lists"); 61a8d61afdSLawrence Stewart 62a8d61afdSLawrence Stewart LIST_HEAD(hhookheadhead, hhook_head); 63601d4c75SLawrence Stewart struct hhookheadhead hhook_head_list; 64601d4c75SLawrence Stewart VNET_DEFINE(struct hhookheadhead, hhook_vhead_list); 65601d4c75SLawrence Stewart #define V_hhook_vhead_list VNET(hhook_vhead_list) 66a8d61afdSLawrence Stewart 67a8d61afdSLawrence Stewart static struct mtx hhook_head_list_lock; 68a8d61afdSLawrence Stewart MTX_SYSINIT(hhookheadlistlock, &hhook_head_list_lock, "hhook_head list lock", 69a8d61afdSLawrence Stewart MTX_DEF); 70a8d61afdSLawrence Stewart 71b1f53277SLawrence Stewart /* Protected by hhook_head_list_lock. */ 72b1f53277SLawrence Stewart static uint32_t n_hhookheads; 73b1f53277SLawrence Stewart 74a8d61afdSLawrence Stewart /* Private function prototypes. */ 75a8d61afdSLawrence Stewart static void hhook_head_destroy(struct hhook_head *hhh); 7658261d30SLawrence Stewart void khelp_new_hhook_registered(struct hhook_head *hhh, uint32_t flags); 77a8d61afdSLawrence Stewart 78a8d61afdSLawrence Stewart #define HHHLIST_LOCK() mtx_lock(&hhook_head_list_lock) 79a8d61afdSLawrence Stewart #define HHHLIST_UNLOCK() mtx_unlock(&hhook_head_list_lock) 80a8d61afdSLawrence Stewart #define HHHLIST_LOCK_ASSERT() mtx_assert(&hhook_head_list_lock, MA_OWNED) 81a8d61afdSLawrence Stewart 82a8d61afdSLawrence Stewart #define HHH_LOCK_INIT(hhh) rm_init(&(hhh)->hhh_lock, "hhook_head rm lock") 83a8d61afdSLawrence Stewart #define HHH_LOCK_DESTROY(hhh) rm_destroy(&(hhh)->hhh_lock) 84a8d61afdSLawrence Stewart #define HHH_WLOCK(hhh) rm_wlock(&(hhh)->hhh_lock) 85a8d61afdSLawrence Stewart #define HHH_WUNLOCK(hhh) rm_wunlock(&(hhh)->hhh_lock) 86a8d61afdSLawrence Stewart #define HHH_RLOCK(hhh, rmpt) rm_rlock(&(hhh)->hhh_lock, (rmpt)) 87a8d61afdSLawrence Stewart #define HHH_RUNLOCK(hhh, rmpt) rm_runlock(&(hhh)->hhh_lock, (rmpt)) 88a8d61afdSLawrence Stewart 89a8d61afdSLawrence Stewart /* 90a8d61afdSLawrence Stewart * Run all helper hook functions for a given hook point. 91a8d61afdSLawrence Stewart */ 92a8d61afdSLawrence Stewart void 93a8d61afdSLawrence Stewart hhook_run_hooks(struct hhook_head *hhh, void *ctx_data, struct osd *hosd) 94a8d61afdSLawrence Stewart { 95a8d61afdSLawrence Stewart struct hhook *hhk; 96a8d61afdSLawrence Stewart void *hdata; 97a8d61afdSLawrence Stewart struct rm_priotracker rmpt; 98a8d61afdSLawrence Stewart 99a8d61afdSLawrence Stewart KASSERT(hhh->hhh_refcount > 0, ("hhook_head %p refcount is 0", hhh)); 100a8d61afdSLawrence Stewart 101a8d61afdSLawrence Stewart HHH_RLOCK(hhh, &rmpt); 102a8d61afdSLawrence Stewart STAILQ_FOREACH(hhk, &hhh->hhh_hooks, hhk_next) { 1030991fe01SAndrey V. Elsukov if (hhk->hhk_helper != NULL && 1040991fe01SAndrey V. Elsukov hhk->hhk_helper->h_flags & HELPER_NEEDS_OSD) { 105a8d61afdSLawrence Stewart hdata = osd_get(OSD_KHELP, hosd, hhk->hhk_helper->h_id); 106a8d61afdSLawrence Stewart if (hdata == NULL) 107a8d61afdSLawrence Stewart continue; 108a8d61afdSLawrence Stewart } else 109a8d61afdSLawrence Stewart hdata = NULL; 110a8d61afdSLawrence Stewart 111a8d61afdSLawrence Stewart /* 112a8d61afdSLawrence Stewart * XXXLAS: We currently ignore the int returned by the hook, 113a8d61afdSLawrence Stewart * but will likely want to handle it in future to allow hhook to 114a8d61afdSLawrence Stewart * be used like pfil and effect changes at the hhook calling 115a8d61afdSLawrence Stewart * site e.g. we could define a new hook type of HHOOK_TYPE_PFIL 116a8d61afdSLawrence Stewart * and standardise what particular return values mean and set 117a8d61afdSLawrence Stewart * the context data to pass exactly the same information as pfil 118a8d61afdSLawrence Stewart * hooks currently receive, thus replicating pfil with hhook. 119a8d61afdSLawrence Stewart */ 120a8d61afdSLawrence Stewart hhk->hhk_func(hhh->hhh_type, hhh->hhh_id, hhk->hhk_udata, 121a8d61afdSLawrence Stewart ctx_data, hdata, hosd); 122a8d61afdSLawrence Stewart } 123a8d61afdSLawrence Stewart HHH_RUNLOCK(hhh, &rmpt); 124a8d61afdSLawrence Stewart } 125a8d61afdSLawrence Stewart 126a8d61afdSLawrence Stewart /* 127a8d61afdSLawrence Stewart * Register a new helper hook function with a helper hook point. 128a8d61afdSLawrence Stewart */ 129a8d61afdSLawrence Stewart int 130*941f8aceSZhenlei Huang hhook_add_hook(struct hhook_head *hhh, const struct hookinfo *hki, uint32_t flags) 131a8d61afdSLawrence Stewart { 132a8d61afdSLawrence Stewart struct hhook *hhk, *tmp; 133a8d61afdSLawrence Stewart int error; 134a8d61afdSLawrence Stewart 135a8d61afdSLawrence Stewart error = 0; 136a8d61afdSLawrence Stewart 137a8d61afdSLawrence Stewart if (hhh == NULL) 138a8d61afdSLawrence Stewart return (ENOENT); 139a8d61afdSLawrence Stewart 140a8d61afdSLawrence Stewart hhk = malloc(sizeof(struct hhook), M_HHOOK, 141a8d61afdSLawrence Stewart M_ZERO | ((flags & HHOOK_WAITOK) ? M_WAITOK : M_NOWAIT)); 142a8d61afdSLawrence Stewart 143a8d61afdSLawrence Stewart if (hhk == NULL) 144a8d61afdSLawrence Stewart return (ENOMEM); 145a8d61afdSLawrence Stewart 146a8d61afdSLawrence Stewart hhk->hhk_helper = hki->hook_helper; 147a8d61afdSLawrence Stewart hhk->hhk_func = hki->hook_func; 148a8d61afdSLawrence Stewart hhk->hhk_udata = hki->hook_udata; 149a8d61afdSLawrence Stewart 150a8d61afdSLawrence Stewart HHH_WLOCK(hhh); 151a8d61afdSLawrence Stewart STAILQ_FOREACH(tmp, &hhh->hhh_hooks, hhk_next) { 152a8d61afdSLawrence Stewart if (tmp->hhk_func == hki->hook_func && 153a8d61afdSLawrence Stewart tmp->hhk_udata == hki->hook_udata) { 154a8d61afdSLawrence Stewart /* The helper hook function is already registered. */ 155a8d61afdSLawrence Stewart error = EEXIST; 156a8d61afdSLawrence Stewart break; 157a8d61afdSLawrence Stewart } 158a8d61afdSLawrence Stewart } 159a8d61afdSLawrence Stewart 160a8d61afdSLawrence Stewart if (!error) { 161a8d61afdSLawrence Stewart STAILQ_INSERT_TAIL(&hhh->hhh_hooks, hhk, hhk_next); 162a8d61afdSLawrence Stewart hhh->hhh_nhooks++; 163188d9a49SLawrence Stewart } else 164a8d61afdSLawrence Stewart free(hhk, M_HHOOK); 165a8d61afdSLawrence Stewart 166a8d61afdSLawrence Stewart HHH_WUNLOCK(hhh); 167a8d61afdSLawrence Stewart 168a8d61afdSLawrence Stewart return (error); 169a8d61afdSLawrence Stewart } 170a8d61afdSLawrence Stewart 171a8d61afdSLawrence Stewart /* 172b1f53277SLawrence Stewart * Register a helper hook function with a helper hook point (including all 173b1f53277SLawrence Stewart * virtual instances of the hook point if it is virtualised). 174b1f53277SLawrence Stewart * 175b1f53277SLawrence Stewart * The logic is unfortunately far more complex than for 176b1f53277SLawrence Stewart * hhook_remove_hook_lookup() because hhook_add_hook() can call malloc() with 177b1f53277SLawrence Stewart * M_WAITOK and thus we cannot call hhook_add_hook() with the 178b1f53277SLawrence Stewart * hhook_head_list_lock held. 179b1f53277SLawrence Stewart * 180b1f53277SLawrence Stewart * The logic assembles an array of hhook_head structs that correspond to the 181b1f53277SLawrence Stewart * helper hook point being hooked and bumps the refcount on each (all done with 182b1f53277SLawrence Stewart * the hhook_head_list_lock held). The hhook_head_list_lock is then dropped, and 183b1f53277SLawrence Stewart * hhook_add_hook() is called and the refcount dropped for each hhook_head 184b1f53277SLawrence Stewart * struct in the array. 185a8d61afdSLawrence Stewart */ 186a8d61afdSLawrence Stewart int 187*941f8aceSZhenlei Huang hhook_add_hook_lookup(const struct hookinfo *hki, uint32_t flags) 188a8d61afdSLawrence Stewart { 189b1f53277SLawrence Stewart struct hhook_head **heads_to_hook, *hhh; 190b1f53277SLawrence Stewart int error, i, n_heads_to_hook; 191a8d61afdSLawrence Stewart 192b1f53277SLawrence Stewart tryagain: 193b1f53277SLawrence Stewart error = i = 0; 194b1f53277SLawrence Stewart /* 195b1f53277SLawrence Stewart * Accessing n_hhookheads without hhook_head_list_lock held opens up a 196b1f53277SLawrence Stewart * race with hhook_head_register() which we are unlikely to lose, but 197b1f53277SLawrence Stewart * nonetheless have to cope with - hence the complex goto logic. 198b1f53277SLawrence Stewart */ 199b1f53277SLawrence Stewart n_heads_to_hook = n_hhookheads; 200b1f53277SLawrence Stewart heads_to_hook = malloc(n_heads_to_hook * sizeof(struct hhook_head *), 201b1f53277SLawrence Stewart M_HHOOK, flags & HHOOK_WAITOK ? M_WAITOK : M_NOWAIT); 202b1f53277SLawrence Stewart if (heads_to_hook == NULL) 203b1f53277SLawrence Stewart return (ENOMEM); 204a8d61afdSLawrence Stewart 205b1f53277SLawrence Stewart HHHLIST_LOCK(); 206b1f53277SLawrence Stewart LIST_FOREACH(hhh, &hhook_head_list, hhh_next) { 207b1f53277SLawrence Stewart if (hhh->hhh_type == hki->hook_type && 208b1f53277SLawrence Stewart hhh->hhh_id == hki->hook_id) { 209b1f53277SLawrence Stewart if (i < n_heads_to_hook) { 210b1f53277SLawrence Stewart heads_to_hook[i] = hhh; 211b1f53277SLawrence Stewart refcount_acquire(&heads_to_hook[i]->hhh_refcount); 212b1f53277SLawrence Stewart i++; 213b1f53277SLawrence Stewart } else { 214b1f53277SLawrence Stewart /* 215b1f53277SLawrence Stewart * We raced with hhook_head_register() which 216b1f53277SLawrence Stewart * inserted a hhook_head that we need to hook 217b1f53277SLawrence Stewart * but did not malloc space for. Abort this run 218b1f53277SLawrence Stewart * and try again. 219b1f53277SLawrence Stewart */ 220b1f53277SLawrence Stewart for (i--; i >= 0; i--) 221b1f53277SLawrence Stewart refcount_release(&heads_to_hook[i]->hhh_refcount); 222b1f53277SLawrence Stewart free(heads_to_hook, M_HHOOK); 223b1f53277SLawrence Stewart HHHLIST_UNLOCK(); 224b1f53277SLawrence Stewart goto tryagain; 225b1f53277SLawrence Stewart } 226b1f53277SLawrence Stewart } 227b1f53277SLawrence Stewart } 228b1f53277SLawrence Stewart HHHLIST_UNLOCK(); 229a8d61afdSLawrence Stewart 230b1f53277SLawrence Stewart for (i--; i >= 0; i--) { 231b1f53277SLawrence Stewart if (!error) 232b1f53277SLawrence Stewart error = hhook_add_hook(heads_to_hook[i], hki, flags); 233b1f53277SLawrence Stewart refcount_release(&heads_to_hook[i]->hhh_refcount); 234b1f53277SLawrence Stewart } 235b1f53277SLawrence Stewart 236b1f53277SLawrence Stewart free(heads_to_hook, M_HHOOK); 237a8d61afdSLawrence Stewart 238a8d61afdSLawrence Stewart return (error); 239a8d61afdSLawrence Stewart } 240a8d61afdSLawrence Stewart 241a8d61afdSLawrence Stewart /* 242a8d61afdSLawrence Stewart * Remove a helper hook function from a helper hook point. 243a8d61afdSLawrence Stewart */ 244a8d61afdSLawrence Stewart int 245*941f8aceSZhenlei Huang hhook_remove_hook(struct hhook_head *hhh, const struct hookinfo *hki) 246a8d61afdSLawrence Stewart { 247a8d61afdSLawrence Stewart struct hhook *tmp; 248a8d61afdSLawrence Stewart 249a8d61afdSLawrence Stewart if (hhh == NULL) 250a8d61afdSLawrence Stewart return (ENOENT); 251a8d61afdSLawrence Stewart 252a8d61afdSLawrence Stewart HHH_WLOCK(hhh); 253a8d61afdSLawrence Stewart STAILQ_FOREACH(tmp, &hhh->hhh_hooks, hhk_next) { 254a8d61afdSLawrence Stewart if (tmp->hhk_func == hki->hook_func && 255a8d61afdSLawrence Stewart tmp->hhk_udata == hki->hook_udata) { 256a8d61afdSLawrence Stewart STAILQ_REMOVE(&hhh->hhh_hooks, tmp, hhook, hhk_next); 257a8d61afdSLawrence Stewart free(tmp, M_HHOOK); 258a8d61afdSLawrence Stewart hhh->hhh_nhooks--; 259a8d61afdSLawrence Stewart break; 260a8d61afdSLawrence Stewart } 261a8d61afdSLawrence Stewart } 262a8d61afdSLawrence Stewart HHH_WUNLOCK(hhh); 263a8d61afdSLawrence Stewart 264a8d61afdSLawrence Stewart return (0); 265a8d61afdSLawrence Stewart } 266a8d61afdSLawrence Stewart 267a8d61afdSLawrence Stewart /* 268b1f53277SLawrence Stewart * Remove a helper hook function from a helper hook point (including all 269b1f53277SLawrence Stewart * virtual instances of the hook point if it is virtualised). 270a8d61afdSLawrence Stewart */ 271a8d61afdSLawrence Stewart int 272*941f8aceSZhenlei Huang hhook_remove_hook_lookup(const struct hookinfo *hki) 273a8d61afdSLawrence Stewart { 274a8d61afdSLawrence Stewart struct hhook_head *hhh; 275a8d61afdSLawrence Stewart 276b1f53277SLawrence Stewart HHHLIST_LOCK(); 277b1f53277SLawrence Stewart LIST_FOREACH(hhh, &hhook_head_list, hhh_next) { 278b1f53277SLawrence Stewart if (hhh->hhh_type == hki->hook_type && 279b1f53277SLawrence Stewart hhh->hhh_id == hki->hook_id) 280a8d61afdSLawrence Stewart hhook_remove_hook(hhh, hki); 281b1f53277SLawrence Stewart } 282b1f53277SLawrence Stewart HHHLIST_UNLOCK(); 283a8d61afdSLawrence Stewart 284a8d61afdSLawrence Stewart return (0); 285a8d61afdSLawrence Stewart } 286a8d61afdSLawrence Stewart 287a8d61afdSLawrence Stewart /* 288a8d61afdSLawrence Stewart * Register a new helper hook point. 289a8d61afdSLawrence Stewart */ 290a8d61afdSLawrence Stewart int 291a8d61afdSLawrence Stewart hhook_head_register(int32_t hhook_type, int32_t hhook_id, struct hhook_head **hhh, 292a8d61afdSLawrence Stewart uint32_t flags) 293a8d61afdSLawrence Stewart { 294a8d61afdSLawrence Stewart struct hhook_head *tmphhh; 295a8d61afdSLawrence Stewart 296a8d61afdSLawrence Stewart tmphhh = hhook_head_get(hhook_type, hhook_id); 297a8d61afdSLawrence Stewart 298a8d61afdSLawrence Stewart if (tmphhh != NULL) { 299a8d61afdSLawrence Stewart /* Hook point previously registered. */ 300a8d61afdSLawrence Stewart hhook_head_release(tmphhh); 301a8d61afdSLawrence Stewart return (EEXIST); 302a8d61afdSLawrence Stewart } 303a8d61afdSLawrence Stewart 304a8d61afdSLawrence Stewart tmphhh = malloc(sizeof(struct hhook_head), M_HHOOK, 305a8d61afdSLawrence Stewart M_ZERO | ((flags & HHOOK_WAITOK) ? M_WAITOK : M_NOWAIT)); 306a8d61afdSLawrence Stewart 307a8d61afdSLawrence Stewart if (tmphhh == NULL) 308a8d61afdSLawrence Stewart return (ENOMEM); 309a8d61afdSLawrence Stewart 310a8d61afdSLawrence Stewart tmphhh->hhh_type = hhook_type; 311a8d61afdSLawrence Stewart tmphhh->hhh_id = hhook_id; 312a8d61afdSLawrence Stewart tmphhh->hhh_nhooks = 0; 313a8d61afdSLawrence Stewart STAILQ_INIT(&tmphhh->hhh_hooks); 314a8d61afdSLawrence Stewart HHH_LOCK_INIT(tmphhh); 315a8d61afdSLawrence Stewart refcount_init(&tmphhh->hhh_refcount, 1); 316a8d61afdSLawrence Stewart 317601d4c75SLawrence Stewart HHHLIST_LOCK(); 318a8d61afdSLawrence Stewart if (flags & HHOOK_HEADISINVNET) { 319a8d61afdSLawrence Stewart tmphhh->hhh_flags |= HHH_ISINVNET; 320bfe72a58SLawrence Stewart #ifdef VIMAGE 321601d4c75SLawrence Stewart KASSERT(curvnet != NULL, ("curvnet is NULL")); 322601d4c75SLawrence Stewart tmphhh->hhh_vid = (uintptr_t)curvnet; 323601d4c75SLawrence Stewart LIST_INSERT_HEAD(&V_hhook_vhead_list, tmphhh, hhh_vnext); 324bfe72a58SLawrence Stewart #endif 325a8d61afdSLawrence Stewart } 326601d4c75SLawrence Stewart LIST_INSERT_HEAD(&hhook_head_list, tmphhh, hhh_next); 327b1f53277SLawrence Stewart n_hhookheads++; 328601d4c75SLawrence Stewart HHHLIST_UNLOCK(); 329a8d61afdSLawrence Stewart 33058261d30SLawrence Stewart khelp_new_hhook_registered(tmphhh, flags); 33158261d30SLawrence Stewart 33258261d30SLawrence Stewart if (hhh != NULL) 33358261d30SLawrence Stewart *hhh = tmphhh; 33458261d30SLawrence Stewart else 33558261d30SLawrence Stewart refcount_release(&tmphhh->hhh_refcount); 33658261d30SLawrence Stewart 337a8d61afdSLawrence Stewart return (0); 338a8d61afdSLawrence Stewart } 339a8d61afdSLawrence Stewart 340a8d61afdSLawrence Stewart static void 341a8d61afdSLawrence Stewart hhook_head_destroy(struct hhook_head *hhh) 342a8d61afdSLawrence Stewart { 343a8d61afdSLawrence Stewart struct hhook *tmp, *tmp2; 344a8d61afdSLawrence Stewart 345a8d61afdSLawrence Stewart HHHLIST_LOCK_ASSERT(); 346b1f53277SLawrence Stewart KASSERT(n_hhookheads > 0, ("n_hhookheads should be > 0")); 347a8d61afdSLawrence Stewart 348a8d61afdSLawrence Stewart LIST_REMOVE(hhh, hhh_next); 349bfe72a58SLawrence Stewart #ifdef VIMAGE 350601d4c75SLawrence Stewart if (hhook_head_is_virtualised(hhh) == HHOOK_HEADISINVNET) 351601d4c75SLawrence Stewart LIST_REMOVE(hhh, hhh_vnext); 352bfe72a58SLawrence Stewart #endif 353a8d61afdSLawrence Stewart HHH_WLOCK(hhh); 354a8d61afdSLawrence Stewart STAILQ_FOREACH_SAFE(tmp, &hhh->hhh_hooks, hhk_next, tmp2) 355a8d61afdSLawrence Stewart free(tmp, M_HHOOK); 356a8d61afdSLawrence Stewart HHH_WUNLOCK(hhh); 357a8d61afdSLawrence Stewart HHH_LOCK_DESTROY(hhh); 358a8d61afdSLawrence Stewart free(hhh, M_HHOOK); 359b1f53277SLawrence Stewart n_hhookheads--; 360a8d61afdSLawrence Stewart } 361a8d61afdSLawrence Stewart 362a8d61afdSLawrence Stewart /* 363a8d61afdSLawrence Stewart * Remove a helper hook point. 364a8d61afdSLawrence Stewart */ 365a8d61afdSLawrence Stewart int 366a8d61afdSLawrence Stewart hhook_head_deregister(struct hhook_head *hhh) 367a8d61afdSLawrence Stewart { 368a8d61afdSLawrence Stewart int error; 369a8d61afdSLawrence Stewart 370a8d61afdSLawrence Stewart error = 0; 371a8d61afdSLawrence Stewart 372a8d61afdSLawrence Stewart HHHLIST_LOCK(); 373a8d61afdSLawrence Stewart if (hhh == NULL) 374a8d61afdSLawrence Stewart error = ENOENT; 375a8d61afdSLawrence Stewart else if (hhh->hhh_refcount > 1) 376a8d61afdSLawrence Stewart error = EBUSY; 377a8d61afdSLawrence Stewart else 378a8d61afdSLawrence Stewart hhook_head_destroy(hhh); 379a8d61afdSLawrence Stewart HHHLIST_UNLOCK(); 380a8d61afdSLawrence Stewart 381a8d61afdSLawrence Stewart return (error); 382a8d61afdSLawrence Stewart } 383a8d61afdSLawrence Stewart 384a8d61afdSLawrence Stewart /* 385a8d61afdSLawrence Stewart * Remove a helper hook point via a hhook_head lookup. 386a8d61afdSLawrence Stewart */ 387a8d61afdSLawrence Stewart int 388a8d61afdSLawrence Stewart hhook_head_deregister_lookup(int32_t hhook_type, int32_t hhook_id) 389a8d61afdSLawrence Stewart { 390a8d61afdSLawrence Stewart struct hhook_head *hhh; 391a8d61afdSLawrence Stewart int error; 392a8d61afdSLawrence Stewart 393a8d61afdSLawrence Stewart hhh = hhook_head_get(hhook_type, hhook_id); 394a8d61afdSLawrence Stewart error = hhook_head_deregister(hhh); 395a8d61afdSLawrence Stewart 396a8d61afdSLawrence Stewart if (error == EBUSY) 397a8d61afdSLawrence Stewart hhook_head_release(hhh); 398a8d61afdSLawrence Stewart 399a8d61afdSLawrence Stewart return (error); 400a8d61afdSLawrence Stewart } 401a8d61afdSLawrence Stewart 402a8d61afdSLawrence Stewart /* 403a8d61afdSLawrence Stewart * Lookup and return the hhook_head struct associated with the specified type 404a8d61afdSLawrence Stewart * and id, or NULL if not found. If found, the hhook_head's refcount is bumped. 405a8d61afdSLawrence Stewart */ 406a8d61afdSLawrence Stewart struct hhook_head * 407a8d61afdSLawrence Stewart hhook_head_get(int32_t hhook_type, int32_t hhook_id) 408a8d61afdSLawrence Stewart { 409a8d61afdSLawrence Stewart struct hhook_head *hhh; 410a8d61afdSLawrence Stewart 411a8d61afdSLawrence Stewart HHHLIST_LOCK(); 412601d4c75SLawrence Stewart LIST_FOREACH(hhh, &hhook_head_list, hhh_next) { 413a8d61afdSLawrence Stewart if (hhh->hhh_type == hhook_type && hhh->hhh_id == hhook_id) { 414bfe72a58SLawrence Stewart #ifdef VIMAGE 415601d4c75SLawrence Stewart if (hhook_head_is_virtualised(hhh) == 416601d4c75SLawrence Stewart HHOOK_HEADISINVNET) { 417601d4c75SLawrence Stewart KASSERT(curvnet != NULL, ("curvnet is NULL")); 418601d4c75SLawrence Stewart if (hhh->hhh_vid != (uintptr_t)curvnet) 419601d4c75SLawrence Stewart continue; 420601d4c75SLawrence Stewart } 421bfe72a58SLawrence Stewart #endif 422a8d61afdSLawrence Stewart refcount_acquire(&hhh->hhh_refcount); 423188d9a49SLawrence Stewart break; 424a8d61afdSLawrence Stewart } 425a8d61afdSLawrence Stewart } 426a8d61afdSLawrence Stewart HHHLIST_UNLOCK(); 427a8d61afdSLawrence Stewart 428188d9a49SLawrence Stewart return (hhh); 429a8d61afdSLawrence Stewart } 430a8d61afdSLawrence Stewart 431a8d61afdSLawrence Stewart void 432a8d61afdSLawrence Stewart hhook_head_release(struct hhook_head *hhh) 433a8d61afdSLawrence Stewart { 434a8d61afdSLawrence Stewart 435a8d61afdSLawrence Stewart refcount_release(&hhh->hhh_refcount); 436a8d61afdSLawrence Stewart } 437a8d61afdSLawrence Stewart 438a8d61afdSLawrence Stewart /* 439a8d61afdSLawrence Stewart * Check the hhook_head private flags and return the appropriate public 440a8d61afdSLawrence Stewart * representation of the flag to the caller. The function is implemented in a 441a8d61afdSLawrence Stewart * way that allows us to cope with other subsystems becoming virtualised in the 442a8d61afdSLawrence Stewart * future. 443a8d61afdSLawrence Stewart */ 444a8d61afdSLawrence Stewart uint32_t 445a8d61afdSLawrence Stewart hhook_head_is_virtualised(struct hhook_head *hhh) 446a8d61afdSLawrence Stewart { 447a8d61afdSLawrence Stewart uint32_t ret; 448a8d61afdSLawrence Stewart 4495a29e4d2SLawrence Stewart ret = 0; 450a8d61afdSLawrence Stewart 4515a29e4d2SLawrence Stewart if (hhh != NULL) { 452a8d61afdSLawrence Stewart if (hhh->hhh_flags & HHH_ISINVNET) 453a8d61afdSLawrence Stewart ret = HHOOK_HEADISINVNET; 4545a29e4d2SLawrence Stewart } 455a8d61afdSLawrence Stewart 456a8d61afdSLawrence Stewart return (ret); 457a8d61afdSLawrence Stewart } 458a8d61afdSLawrence Stewart 459a8d61afdSLawrence Stewart uint32_t 460a8d61afdSLawrence Stewart hhook_head_is_virtualised_lookup(int32_t hook_type, int32_t hook_id) 461a8d61afdSLawrence Stewart { 462a8d61afdSLawrence Stewart struct hhook_head *hhh; 463a8d61afdSLawrence Stewart uint32_t ret; 464a8d61afdSLawrence Stewart 465a8d61afdSLawrence Stewart hhh = hhook_head_get(hook_type, hook_id); 466a8d61afdSLawrence Stewart 467a8d61afdSLawrence Stewart if (hhh == NULL) 468a8d61afdSLawrence Stewart return (0); 469a8d61afdSLawrence Stewart 470a8d61afdSLawrence Stewart ret = hhook_head_is_virtualised(hhh); 471a8d61afdSLawrence Stewart hhook_head_release(hhh); 472a8d61afdSLawrence Stewart 473a8d61afdSLawrence Stewart return (ret); 474a8d61afdSLawrence Stewart } 475a8d61afdSLawrence Stewart 476a8d61afdSLawrence Stewart /* 477a8d61afdSLawrence Stewart * Vnet created and being initialised. 478a8d61afdSLawrence Stewart */ 479a8d61afdSLawrence Stewart static void 480a8d61afdSLawrence Stewart hhook_vnet_init(const void *unused __unused) 481a8d61afdSLawrence Stewart { 482a8d61afdSLawrence Stewart 483601d4c75SLawrence Stewart LIST_INIT(&V_hhook_vhead_list); 484a8d61afdSLawrence Stewart } 485a8d61afdSLawrence Stewart 486a8d61afdSLawrence Stewart /* 487a8d61afdSLawrence Stewart * Vnet being torn down and destroyed. 488a8d61afdSLawrence Stewart */ 489a8d61afdSLawrence Stewart static void 490a8d61afdSLawrence Stewart hhook_vnet_uninit(const void *unused __unused) 491a8d61afdSLawrence Stewart { 492a8d61afdSLawrence Stewart struct hhook_head *hhh, *tmphhh; 493a8d61afdSLawrence Stewart 494a8d61afdSLawrence Stewart /* 495a8d61afdSLawrence Stewart * If subsystems which export helper hook points use the hhook KPI 496a8d61afdSLawrence Stewart * correctly, the loop below should have no work to do because the 497a8d61afdSLawrence Stewart * subsystem should have already called hhook_head_deregister(). 498a8d61afdSLawrence Stewart */ 499a8d61afdSLawrence Stewart HHHLIST_LOCK(); 500601d4c75SLawrence Stewart LIST_FOREACH_SAFE(hhh, &V_hhook_vhead_list, hhh_vnext, tmphhh) { 501a8d61afdSLawrence Stewart printf("%s: hhook_head type=%d, id=%d cleanup required\n", 502a8d61afdSLawrence Stewart __func__, hhh->hhh_type, hhh->hhh_id); 503a8d61afdSLawrence Stewart hhook_head_destroy(hhh); 504a8d61afdSLawrence Stewart } 505a8d61afdSLawrence Stewart HHHLIST_UNLOCK(); 506a8d61afdSLawrence Stewart } 507a8d61afdSLawrence Stewart 508a8d61afdSLawrence Stewart /* 509601d4c75SLawrence Stewart * When a vnet is created and being initialised, init the V_hhook_vhead_list. 510a8d61afdSLawrence Stewart */ 51189856f7eSBjoern A. Zeeb VNET_SYSINIT(hhook_vnet_init, SI_SUB_INIT_IF, SI_ORDER_FIRST, 512a8d61afdSLawrence Stewart hhook_vnet_init, NULL); 513a8d61afdSLawrence Stewart 514a8d61afdSLawrence Stewart /* 515a8d61afdSLawrence Stewart * The hhook KPI provides a mechanism for subsystems which export helper hook 516a8d61afdSLawrence Stewart * points to clean up on vnet tear down, but in case the KPI is misused, 517a8d61afdSLawrence Stewart * provide a function to clean up and free memory for a vnet being destroyed. 518a8d61afdSLawrence Stewart */ 51989856f7eSBjoern A. Zeeb VNET_SYSUNINIT(hhook_vnet_uninit, SI_SUB_INIT_IF, SI_ORDER_FIRST, 520a8d61afdSLawrence Stewart hhook_vnet_uninit, NULL); 521