1/*- 2 * Copyright (c) 2010 Lawrence Stewart <lstewart@freebsd.org> 3 * Copyright (c) 2010 The FreeBSD Foundation 4 * All rights reserved. 5 * 6 * This software was developed by Lawrence Stewart while studying at the Centre 7 * for Advanced Internet Architectures, Swinburne University of Technology, 8 * made possible in part by grants from the FreeBSD Foundation and Cisco 9 * University Research Program Fund at Community Foundation Silicon Valley. 10 * 11 * Portions of this software were developed at the Centre for Advanced 12 * Internet Architectures, Swinburne University of Technology, Melbourne, 13 * Australia by Lawrence Stewart under sponsorship from the FreeBSD Foundation. 14 * 15 * Redistribution and use in source and binary forms, with or without 16 * modification, are permitted provided that the following conditions 17 * are met: 18 * 1. Redistributions of source code must retain the above copyright 19 * notice, this list of conditions and the following disclaimer. 20 * 2. Redistributions in binary form must reproduce the above copyright 21 * notice, this list of conditions and the following disclaimer in the 22 * documentation and/or other materials provided with the distribution. 23 * 24 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 25 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 26 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 27 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 28 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 29 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 30 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 31 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 32 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 33 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 34 * SUCH DAMAGE. 35 */ 36 37#include <sys/cdefs.h>
| 1/*- 2 * Copyright (c) 2010 Lawrence Stewart <lstewart@freebsd.org> 3 * Copyright (c) 2010 The FreeBSD Foundation 4 * All rights reserved. 5 * 6 * This software was developed by Lawrence Stewart while studying at the Centre 7 * for Advanced Internet Architectures, Swinburne University of Technology, 8 * made possible in part by grants from the FreeBSD Foundation and Cisco 9 * University Research Program Fund at Community Foundation Silicon Valley. 10 * 11 * Portions of this software were developed at the Centre for Advanced 12 * Internet Architectures, Swinburne University of Technology, Melbourne, 13 * Australia by Lawrence Stewart under sponsorship from the FreeBSD Foundation. 14 * 15 * Redistribution and use in source and binary forms, with or without 16 * modification, are permitted provided that the following conditions 17 * are met: 18 * 1. Redistributions of source code must retain the above copyright 19 * notice, this list of conditions and the following disclaimer. 20 * 2. Redistributions in binary form must reproduce the above copyright 21 * notice, this list of conditions and the following disclaimer in the 22 * documentation and/or other materials provided with the distribution. 23 * 24 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 25 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 26 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 27 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 28 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 29 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 30 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 31 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 32 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 33 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 34 * SUCH DAMAGE. 35 */ 36 37#include <sys/cdefs.h>
|
38__FBSDID("$FreeBSD: head/sys/kern/kern_hhook.c 251732 2013-06-14 04:10:34Z lstewart $");
| 38__FBSDID("$FreeBSD: head/sys/kern/kern_hhook.c 251752 2013-06-14 18:11:21Z lstewart $");
|
39 40#include <sys/param.h> 41#include <sys/kernel.h> 42#include <sys/hhook.h> 43#include <sys/khelp.h> 44#include <sys/malloc.h> 45#include <sys/module.h> 46#include <sys/module_khelp.h> 47#include <sys/osd.h> 48#include <sys/queue.h> 49#include <sys/refcount.h> 50#include <sys/systm.h> 51 52#include <net/vnet.h> 53 54struct hhook { 55 hhook_func_t hhk_func; 56 struct helper *hhk_helper; 57 void *hhk_udata; 58 STAILQ_ENTRY(hhook) hhk_next; 59}; 60 61static MALLOC_DEFINE(M_HHOOK, "hhook", "Helper hooks are linked off hhook_head lists"); 62 63LIST_HEAD(hhookheadhead, hhook_head); 64struct hhookheadhead hhook_head_list; 65VNET_DEFINE(struct hhookheadhead, hhook_vhead_list); 66#define V_hhook_vhead_list VNET(hhook_vhead_list) 67 68static struct mtx hhook_head_list_lock; 69MTX_SYSINIT(hhookheadlistlock, &hhook_head_list_lock, "hhook_head list lock", 70 MTX_DEF); 71 72/* Private function prototypes. */ 73static void hhook_head_destroy(struct hhook_head *hhh); 74 75#define HHHLIST_LOCK() mtx_lock(&hhook_head_list_lock) 76#define HHHLIST_UNLOCK() mtx_unlock(&hhook_head_list_lock) 77#define HHHLIST_LOCK_ASSERT() mtx_assert(&hhook_head_list_lock, MA_OWNED) 78 79#define HHH_LOCK_INIT(hhh) rm_init(&(hhh)->hhh_lock, "hhook_head rm lock") 80#define HHH_LOCK_DESTROY(hhh) rm_destroy(&(hhh)->hhh_lock) 81#define HHH_WLOCK(hhh) rm_wlock(&(hhh)->hhh_lock) 82#define HHH_WUNLOCK(hhh) rm_wunlock(&(hhh)->hhh_lock) 83#define HHH_RLOCK(hhh, rmpt) rm_rlock(&(hhh)->hhh_lock, (rmpt)) 84#define HHH_RUNLOCK(hhh, rmpt) rm_runlock(&(hhh)->hhh_lock, (rmpt)) 85 86/* 87 * Run all helper hook functions for a given hook point. 88 */ 89void 90hhook_run_hooks(struct hhook_head *hhh, void *ctx_data, struct osd *hosd) 91{ 92 struct hhook *hhk; 93 void *hdata; 94 struct rm_priotracker rmpt; 95 96 KASSERT(hhh->hhh_refcount > 0, ("hhook_head %p refcount is 0", hhh)); 97 98 HHH_RLOCK(hhh, &rmpt); 99 STAILQ_FOREACH(hhk, &hhh->hhh_hooks, hhk_next) { 100 if (hhk->hhk_helper->h_flags & HELPER_NEEDS_OSD) { 101 hdata = osd_get(OSD_KHELP, hosd, hhk->hhk_helper->h_id); 102 if (hdata == NULL) 103 continue; 104 } else 105 hdata = NULL; 106 107 /* 108 * XXXLAS: We currently ignore the int returned by the hook, 109 * but will likely want to handle it in future to allow hhook to 110 * be used like pfil and effect changes at the hhook calling 111 * site e.g. we could define a new hook type of HHOOK_TYPE_PFIL 112 * and standardise what particular return values mean and set 113 * the context data to pass exactly the same information as pfil 114 * hooks currently receive, thus replicating pfil with hhook. 115 */ 116 hhk->hhk_func(hhh->hhh_type, hhh->hhh_id, hhk->hhk_udata, 117 ctx_data, hdata, hosd); 118 } 119 HHH_RUNLOCK(hhh, &rmpt); 120} 121 122/* 123 * Register a new helper hook function with a helper hook point. 124 */ 125int 126hhook_add_hook(struct hhook_head *hhh, struct hookinfo *hki, uint32_t flags) 127{ 128 struct hhook *hhk, *tmp; 129 int error; 130 131 error = 0; 132 133 if (hhh == NULL) 134 return (ENOENT); 135 136 hhk = malloc(sizeof(struct hhook), M_HHOOK, 137 M_ZERO | ((flags & HHOOK_WAITOK) ? M_WAITOK : M_NOWAIT)); 138 139 if (hhk == NULL) 140 return (ENOMEM); 141 142 hhk->hhk_helper = hki->hook_helper; 143 hhk->hhk_func = hki->hook_func; 144 hhk->hhk_udata = hki->hook_udata; 145 146 HHH_WLOCK(hhh); 147 STAILQ_FOREACH(tmp, &hhh->hhh_hooks, hhk_next) { 148 if (tmp->hhk_func == hki->hook_func && 149 tmp->hhk_udata == hki->hook_udata) { 150 /* The helper hook function is already registered. */ 151 error = EEXIST; 152 break; 153 } 154 } 155 156 if (!error) { 157 STAILQ_INSERT_TAIL(&hhh->hhh_hooks, hhk, hhk_next); 158 hhh->hhh_nhooks++; 159 } else 160 free(hhk, M_HHOOK); 161 162 HHH_WUNLOCK(hhh); 163 164 return (error); 165} 166 167/* 168 * Lookup a helper hook point and register a new helper hook function with it. 169 */ 170int 171hhook_add_hook_lookup(struct hookinfo *hki, uint32_t flags) 172{ 173 struct hhook_head *hhh; 174 int error; 175 176 hhh = hhook_head_get(hki->hook_type, hki->hook_id); 177 178 if (hhh == NULL) 179 return (ENOENT); 180 181 error = hhook_add_hook(hhh, hki, flags); 182 hhook_head_release(hhh); 183 184 return (error); 185} 186 187/* 188 * Remove a helper hook function from a helper hook point. 189 */ 190int 191hhook_remove_hook(struct hhook_head *hhh, struct hookinfo *hki) 192{ 193 struct hhook *tmp; 194 195 if (hhh == NULL) 196 return (ENOENT); 197 198 HHH_WLOCK(hhh); 199 STAILQ_FOREACH(tmp, &hhh->hhh_hooks, hhk_next) { 200 if (tmp->hhk_func == hki->hook_func && 201 tmp->hhk_udata == hki->hook_udata) { 202 STAILQ_REMOVE(&hhh->hhh_hooks, tmp, hhook, hhk_next); 203 free(tmp, M_HHOOK); 204 hhh->hhh_nhooks--; 205 break; 206 } 207 } 208 HHH_WUNLOCK(hhh); 209 210 return (0); 211} 212 213/* 214 * Lookup a helper hook point and remove a helper hook function from it. 215 */ 216int 217hhook_remove_hook_lookup(struct hookinfo *hki) 218{ 219 struct hhook_head *hhh; 220 221 hhh = hhook_head_get(hki->hook_type, hki->hook_id); 222 223 if (hhh == NULL) 224 return (ENOENT); 225 226 hhook_remove_hook(hhh, hki); 227 hhook_head_release(hhh); 228 229 return (0); 230} 231 232/* 233 * Register a new helper hook point. 234 */ 235int 236hhook_head_register(int32_t hhook_type, int32_t hhook_id, struct hhook_head **hhh, 237 uint32_t flags) 238{ 239 struct hhook_head *tmphhh; 240 241 tmphhh = hhook_head_get(hhook_type, hhook_id); 242 243 if (tmphhh != NULL) { 244 /* Hook point previously registered. */ 245 hhook_head_release(tmphhh); 246 return (EEXIST); 247 } 248 249 tmphhh = malloc(sizeof(struct hhook_head), M_HHOOK, 250 M_ZERO | ((flags & HHOOK_WAITOK) ? M_WAITOK : M_NOWAIT)); 251 252 if (tmphhh == NULL) 253 return (ENOMEM); 254 255 tmphhh->hhh_type = hhook_type; 256 tmphhh->hhh_id = hhook_id; 257 tmphhh->hhh_nhooks = 0; 258 STAILQ_INIT(&tmphhh->hhh_hooks); 259 HHH_LOCK_INIT(tmphhh); 260 261 if (hhh != NULL) { 262 refcount_init(&tmphhh->hhh_refcount, 1); 263 *hhh = tmphhh; 264 } else 265 refcount_init(&tmphhh->hhh_refcount, 0); 266 267 HHHLIST_LOCK(); 268 if (flags & HHOOK_HEADISINVNET) { 269 tmphhh->hhh_flags |= HHH_ISINVNET;
| 39 40#include <sys/param.h> 41#include <sys/kernel.h> 42#include <sys/hhook.h> 43#include <sys/khelp.h> 44#include <sys/malloc.h> 45#include <sys/module.h> 46#include <sys/module_khelp.h> 47#include <sys/osd.h> 48#include <sys/queue.h> 49#include <sys/refcount.h> 50#include <sys/systm.h> 51 52#include <net/vnet.h> 53 54struct hhook { 55 hhook_func_t hhk_func; 56 struct helper *hhk_helper; 57 void *hhk_udata; 58 STAILQ_ENTRY(hhook) hhk_next; 59}; 60 61static MALLOC_DEFINE(M_HHOOK, "hhook", "Helper hooks are linked off hhook_head lists"); 62 63LIST_HEAD(hhookheadhead, hhook_head); 64struct hhookheadhead hhook_head_list; 65VNET_DEFINE(struct hhookheadhead, hhook_vhead_list); 66#define V_hhook_vhead_list VNET(hhook_vhead_list) 67 68static struct mtx hhook_head_list_lock; 69MTX_SYSINIT(hhookheadlistlock, &hhook_head_list_lock, "hhook_head list lock", 70 MTX_DEF); 71 72/* Private function prototypes. */ 73static void hhook_head_destroy(struct hhook_head *hhh); 74 75#define HHHLIST_LOCK() mtx_lock(&hhook_head_list_lock) 76#define HHHLIST_UNLOCK() mtx_unlock(&hhook_head_list_lock) 77#define HHHLIST_LOCK_ASSERT() mtx_assert(&hhook_head_list_lock, MA_OWNED) 78 79#define HHH_LOCK_INIT(hhh) rm_init(&(hhh)->hhh_lock, "hhook_head rm lock") 80#define HHH_LOCK_DESTROY(hhh) rm_destroy(&(hhh)->hhh_lock) 81#define HHH_WLOCK(hhh) rm_wlock(&(hhh)->hhh_lock) 82#define HHH_WUNLOCK(hhh) rm_wunlock(&(hhh)->hhh_lock) 83#define HHH_RLOCK(hhh, rmpt) rm_rlock(&(hhh)->hhh_lock, (rmpt)) 84#define HHH_RUNLOCK(hhh, rmpt) rm_runlock(&(hhh)->hhh_lock, (rmpt)) 85 86/* 87 * Run all helper hook functions for a given hook point. 88 */ 89void 90hhook_run_hooks(struct hhook_head *hhh, void *ctx_data, struct osd *hosd) 91{ 92 struct hhook *hhk; 93 void *hdata; 94 struct rm_priotracker rmpt; 95 96 KASSERT(hhh->hhh_refcount > 0, ("hhook_head %p refcount is 0", hhh)); 97 98 HHH_RLOCK(hhh, &rmpt); 99 STAILQ_FOREACH(hhk, &hhh->hhh_hooks, hhk_next) { 100 if (hhk->hhk_helper->h_flags & HELPER_NEEDS_OSD) { 101 hdata = osd_get(OSD_KHELP, hosd, hhk->hhk_helper->h_id); 102 if (hdata == NULL) 103 continue; 104 } else 105 hdata = NULL; 106 107 /* 108 * XXXLAS: We currently ignore the int returned by the hook, 109 * but will likely want to handle it in future to allow hhook to 110 * be used like pfil and effect changes at the hhook calling 111 * site e.g. we could define a new hook type of HHOOK_TYPE_PFIL 112 * and standardise what particular return values mean and set 113 * the context data to pass exactly the same information as pfil 114 * hooks currently receive, thus replicating pfil with hhook. 115 */ 116 hhk->hhk_func(hhh->hhh_type, hhh->hhh_id, hhk->hhk_udata, 117 ctx_data, hdata, hosd); 118 } 119 HHH_RUNLOCK(hhh, &rmpt); 120} 121 122/* 123 * Register a new helper hook function with a helper hook point. 124 */ 125int 126hhook_add_hook(struct hhook_head *hhh, struct hookinfo *hki, uint32_t flags) 127{ 128 struct hhook *hhk, *tmp; 129 int error; 130 131 error = 0; 132 133 if (hhh == NULL) 134 return (ENOENT); 135 136 hhk = malloc(sizeof(struct hhook), M_HHOOK, 137 M_ZERO | ((flags & HHOOK_WAITOK) ? M_WAITOK : M_NOWAIT)); 138 139 if (hhk == NULL) 140 return (ENOMEM); 141 142 hhk->hhk_helper = hki->hook_helper; 143 hhk->hhk_func = hki->hook_func; 144 hhk->hhk_udata = hki->hook_udata; 145 146 HHH_WLOCK(hhh); 147 STAILQ_FOREACH(tmp, &hhh->hhh_hooks, hhk_next) { 148 if (tmp->hhk_func == hki->hook_func && 149 tmp->hhk_udata == hki->hook_udata) { 150 /* The helper hook function is already registered. */ 151 error = EEXIST; 152 break; 153 } 154 } 155 156 if (!error) { 157 STAILQ_INSERT_TAIL(&hhh->hhh_hooks, hhk, hhk_next); 158 hhh->hhh_nhooks++; 159 } else 160 free(hhk, M_HHOOK); 161 162 HHH_WUNLOCK(hhh); 163 164 return (error); 165} 166 167/* 168 * Lookup a helper hook point and register a new helper hook function with it. 169 */ 170int 171hhook_add_hook_lookup(struct hookinfo *hki, uint32_t flags) 172{ 173 struct hhook_head *hhh; 174 int error; 175 176 hhh = hhook_head_get(hki->hook_type, hki->hook_id); 177 178 if (hhh == NULL) 179 return (ENOENT); 180 181 error = hhook_add_hook(hhh, hki, flags); 182 hhook_head_release(hhh); 183 184 return (error); 185} 186 187/* 188 * Remove a helper hook function from a helper hook point. 189 */ 190int 191hhook_remove_hook(struct hhook_head *hhh, struct hookinfo *hki) 192{ 193 struct hhook *tmp; 194 195 if (hhh == NULL) 196 return (ENOENT); 197 198 HHH_WLOCK(hhh); 199 STAILQ_FOREACH(tmp, &hhh->hhh_hooks, hhk_next) { 200 if (tmp->hhk_func == hki->hook_func && 201 tmp->hhk_udata == hki->hook_udata) { 202 STAILQ_REMOVE(&hhh->hhh_hooks, tmp, hhook, hhk_next); 203 free(tmp, M_HHOOK); 204 hhh->hhh_nhooks--; 205 break; 206 } 207 } 208 HHH_WUNLOCK(hhh); 209 210 return (0); 211} 212 213/* 214 * Lookup a helper hook point and remove a helper hook function from it. 215 */ 216int 217hhook_remove_hook_lookup(struct hookinfo *hki) 218{ 219 struct hhook_head *hhh; 220 221 hhh = hhook_head_get(hki->hook_type, hki->hook_id); 222 223 if (hhh == NULL) 224 return (ENOENT); 225 226 hhook_remove_hook(hhh, hki); 227 hhook_head_release(hhh); 228 229 return (0); 230} 231 232/* 233 * Register a new helper hook point. 234 */ 235int 236hhook_head_register(int32_t hhook_type, int32_t hhook_id, struct hhook_head **hhh, 237 uint32_t flags) 238{ 239 struct hhook_head *tmphhh; 240 241 tmphhh = hhook_head_get(hhook_type, hhook_id); 242 243 if (tmphhh != NULL) { 244 /* Hook point previously registered. */ 245 hhook_head_release(tmphhh); 246 return (EEXIST); 247 } 248 249 tmphhh = malloc(sizeof(struct hhook_head), M_HHOOK, 250 M_ZERO | ((flags & HHOOK_WAITOK) ? M_WAITOK : M_NOWAIT)); 251 252 if (tmphhh == NULL) 253 return (ENOMEM); 254 255 tmphhh->hhh_type = hhook_type; 256 tmphhh->hhh_id = hhook_id; 257 tmphhh->hhh_nhooks = 0; 258 STAILQ_INIT(&tmphhh->hhh_hooks); 259 HHH_LOCK_INIT(tmphhh); 260 261 if (hhh != NULL) { 262 refcount_init(&tmphhh->hhh_refcount, 1); 263 *hhh = tmphhh; 264 } else 265 refcount_init(&tmphhh->hhh_refcount, 0); 266 267 HHHLIST_LOCK(); 268 if (flags & HHOOK_HEADISINVNET) { 269 tmphhh->hhh_flags |= HHH_ISINVNET;
|
| 270#ifdef VIMAGE
|
270 KASSERT(curvnet != NULL, ("curvnet is NULL")); 271 tmphhh->hhh_vid = (uintptr_t)curvnet; 272 LIST_INSERT_HEAD(&V_hhook_vhead_list, tmphhh, hhh_vnext);
| 271 KASSERT(curvnet != NULL, ("curvnet is NULL")); 272 tmphhh->hhh_vid = (uintptr_t)curvnet; 273 LIST_INSERT_HEAD(&V_hhook_vhead_list, tmphhh, hhh_vnext);
|
| 274#endif
|
273 } 274 LIST_INSERT_HEAD(&hhook_head_list, tmphhh, hhh_next); 275 HHHLIST_UNLOCK(); 276 277 return (0); 278} 279 280static void 281hhook_head_destroy(struct hhook_head *hhh) 282{ 283 struct hhook *tmp, *tmp2; 284 285 HHHLIST_LOCK_ASSERT(); 286 287 LIST_REMOVE(hhh, hhh_next);
| 275 } 276 LIST_INSERT_HEAD(&hhook_head_list, tmphhh, hhh_next); 277 HHHLIST_UNLOCK(); 278 279 return (0); 280} 281 282static void 283hhook_head_destroy(struct hhook_head *hhh) 284{ 285 struct hhook *tmp, *tmp2; 286 287 HHHLIST_LOCK_ASSERT(); 288 289 LIST_REMOVE(hhh, hhh_next);
|
| 290#ifdef VIMAGE
|
288 if (hhook_head_is_virtualised(hhh) == HHOOK_HEADISINVNET) 289 LIST_REMOVE(hhh, hhh_vnext);
| 291 if (hhook_head_is_virtualised(hhh) == HHOOK_HEADISINVNET) 292 LIST_REMOVE(hhh, hhh_vnext);
|
| 293#endif
|
290 HHH_WLOCK(hhh); 291 STAILQ_FOREACH_SAFE(tmp, &hhh->hhh_hooks, hhk_next, tmp2) 292 free(tmp, M_HHOOK); 293 HHH_WUNLOCK(hhh); 294 HHH_LOCK_DESTROY(hhh); 295 free(hhh, M_HHOOK); 296} 297 298/* 299 * Remove a helper hook point. 300 */ 301int 302hhook_head_deregister(struct hhook_head *hhh) 303{ 304 int error; 305 306 error = 0; 307 308 HHHLIST_LOCK(); 309 if (hhh == NULL) 310 error = ENOENT; 311 else if (hhh->hhh_refcount > 1) 312 error = EBUSY; 313 else 314 hhook_head_destroy(hhh); 315 HHHLIST_UNLOCK(); 316 317 return (error); 318} 319 320/* 321 * Remove a helper hook point via a hhook_head lookup. 322 */ 323int 324hhook_head_deregister_lookup(int32_t hhook_type, int32_t hhook_id) 325{ 326 struct hhook_head *hhh; 327 int error; 328 329 hhh = hhook_head_get(hhook_type, hhook_id); 330 error = hhook_head_deregister(hhh); 331 332 if (error == EBUSY) 333 hhook_head_release(hhh); 334 335 return (error); 336} 337 338/* 339 * Lookup and return the hhook_head struct associated with the specified type 340 * and id, or NULL if not found. If found, the hhook_head's refcount is bumped. 341 */ 342struct hhook_head * 343hhook_head_get(int32_t hhook_type, int32_t hhook_id) 344{ 345 struct hhook_head *hhh; 346 347 HHHLIST_LOCK(); 348 LIST_FOREACH(hhh, &hhook_head_list, hhh_next) { 349 if (hhh->hhh_type == hhook_type && hhh->hhh_id == hhook_id) {
| 294 HHH_WLOCK(hhh); 295 STAILQ_FOREACH_SAFE(tmp, &hhh->hhh_hooks, hhk_next, tmp2) 296 free(tmp, M_HHOOK); 297 HHH_WUNLOCK(hhh); 298 HHH_LOCK_DESTROY(hhh); 299 free(hhh, M_HHOOK); 300} 301 302/* 303 * Remove a helper hook point. 304 */ 305int 306hhook_head_deregister(struct hhook_head *hhh) 307{ 308 int error; 309 310 error = 0; 311 312 HHHLIST_LOCK(); 313 if (hhh == NULL) 314 error = ENOENT; 315 else if (hhh->hhh_refcount > 1) 316 error = EBUSY; 317 else 318 hhook_head_destroy(hhh); 319 HHHLIST_UNLOCK(); 320 321 return (error); 322} 323 324/* 325 * Remove a helper hook point via a hhook_head lookup. 326 */ 327int 328hhook_head_deregister_lookup(int32_t hhook_type, int32_t hhook_id) 329{ 330 struct hhook_head *hhh; 331 int error; 332 333 hhh = hhook_head_get(hhook_type, hhook_id); 334 error = hhook_head_deregister(hhh); 335 336 if (error == EBUSY) 337 hhook_head_release(hhh); 338 339 return (error); 340} 341 342/* 343 * Lookup and return the hhook_head struct associated with the specified type 344 * and id, or NULL if not found. If found, the hhook_head's refcount is bumped. 345 */ 346struct hhook_head * 347hhook_head_get(int32_t hhook_type, int32_t hhook_id) 348{ 349 struct hhook_head *hhh; 350 351 HHHLIST_LOCK(); 352 LIST_FOREACH(hhh, &hhook_head_list, hhh_next) { 353 if (hhh->hhh_type == hhook_type && hhh->hhh_id == hhook_id) {
|
| 354#ifdef VIMAGE
|
350 if (hhook_head_is_virtualised(hhh) == 351 HHOOK_HEADISINVNET) { 352 KASSERT(curvnet != NULL, ("curvnet is NULL")); 353 if (hhh->hhh_vid != (uintptr_t)curvnet) 354 continue; 355 }
| 355 if (hhook_head_is_virtualised(hhh) == 356 HHOOK_HEADISINVNET) { 357 KASSERT(curvnet != NULL, ("curvnet is NULL")); 358 if (hhh->hhh_vid != (uintptr_t)curvnet) 359 continue; 360 }
|
| 361#endif
|
356 refcount_acquire(&hhh->hhh_refcount); 357 break; 358 } 359 } 360 HHHLIST_UNLOCK(); 361 362 return (hhh); 363} 364 365void 366hhook_head_release(struct hhook_head *hhh) 367{ 368 369 refcount_release(&hhh->hhh_refcount); 370} 371 372/* 373 * Check the hhook_head private flags and return the appropriate public 374 * representation of the flag to the caller. The function is implemented in a 375 * way that allows us to cope with other subsystems becoming virtualised in the 376 * future. 377 */ 378uint32_t 379hhook_head_is_virtualised(struct hhook_head *hhh) 380{ 381 uint32_t ret; 382 383 ret = 0; 384 385 if (hhh != NULL) { 386 if (hhh->hhh_flags & HHH_ISINVNET) 387 ret = HHOOK_HEADISINVNET; 388 } 389 390 return (ret); 391} 392 393uint32_t 394hhook_head_is_virtualised_lookup(int32_t hook_type, int32_t hook_id) 395{ 396 struct hhook_head *hhh; 397 uint32_t ret; 398 399 hhh = hhook_head_get(hook_type, hook_id); 400 401 if (hhh == NULL) 402 return (0); 403 404 ret = hhook_head_is_virtualised(hhh); 405 hhook_head_release(hhh); 406 407 return (ret); 408} 409 410/* 411 * Vnet created and being initialised. 412 */ 413static void 414hhook_vnet_init(const void *unused __unused) 415{ 416 417 LIST_INIT(&V_hhook_vhead_list); 418} 419 420/* 421 * Vnet being torn down and destroyed. 422 */ 423static void 424hhook_vnet_uninit(const void *unused __unused) 425{ 426 struct hhook_head *hhh, *tmphhh; 427 428 /* 429 * If subsystems which export helper hook points use the hhook KPI 430 * correctly, the loop below should have no work to do because the 431 * subsystem should have already called hhook_head_deregister(). 432 */ 433 HHHLIST_LOCK(); 434 LIST_FOREACH_SAFE(hhh, &V_hhook_vhead_list, hhh_vnext, tmphhh) { 435 printf("%s: hhook_head type=%d, id=%d cleanup required\n", 436 __func__, hhh->hhh_type, hhh->hhh_id); 437 hhook_head_destroy(hhh); 438 } 439 HHHLIST_UNLOCK(); 440} 441 442 443/* 444 * When a vnet is created and being initialised, init the V_hhook_vhead_list. 445 */ 446VNET_SYSINIT(hhook_vnet_init, SI_SUB_PROTO_BEGIN, SI_ORDER_FIRST, 447 hhook_vnet_init, NULL); 448 449/* 450 * The hhook KPI provides a mechanism for subsystems which export helper hook 451 * points to clean up on vnet tear down, but in case the KPI is misused, 452 * provide a function to clean up and free memory for a vnet being destroyed. 453 */ 454VNET_SYSUNINIT(hhook_vnet_uninit, SI_SUB_PROTO_BEGIN, SI_ORDER_FIRST, 455 hhook_vnet_uninit, NULL);
| 362 refcount_acquire(&hhh->hhh_refcount); 363 break; 364 } 365 } 366 HHHLIST_UNLOCK(); 367 368 return (hhh); 369} 370 371void 372hhook_head_release(struct hhook_head *hhh) 373{ 374 375 refcount_release(&hhh->hhh_refcount); 376} 377 378/* 379 * Check the hhook_head private flags and return the appropriate public 380 * representation of the flag to the caller. The function is implemented in a 381 * way that allows us to cope with other subsystems becoming virtualised in the 382 * future. 383 */ 384uint32_t 385hhook_head_is_virtualised(struct hhook_head *hhh) 386{ 387 uint32_t ret; 388 389 ret = 0; 390 391 if (hhh != NULL) { 392 if (hhh->hhh_flags & HHH_ISINVNET) 393 ret = HHOOK_HEADISINVNET; 394 } 395 396 return (ret); 397} 398 399uint32_t 400hhook_head_is_virtualised_lookup(int32_t hook_type, int32_t hook_id) 401{ 402 struct hhook_head *hhh; 403 uint32_t ret; 404 405 hhh = hhook_head_get(hook_type, hook_id); 406 407 if (hhh == NULL) 408 return (0); 409 410 ret = hhook_head_is_virtualised(hhh); 411 hhook_head_release(hhh); 412 413 return (ret); 414} 415 416/* 417 * Vnet created and being initialised. 418 */ 419static void 420hhook_vnet_init(const void *unused __unused) 421{ 422 423 LIST_INIT(&V_hhook_vhead_list); 424} 425 426/* 427 * Vnet being torn down and destroyed. 428 */ 429static void 430hhook_vnet_uninit(const void *unused __unused) 431{ 432 struct hhook_head *hhh, *tmphhh; 433 434 /* 435 * If subsystems which export helper hook points use the hhook KPI 436 * correctly, the loop below should have no work to do because the 437 * subsystem should have already called hhook_head_deregister(). 438 */ 439 HHHLIST_LOCK(); 440 LIST_FOREACH_SAFE(hhh, &V_hhook_vhead_list, hhh_vnext, tmphhh) { 441 printf("%s: hhook_head type=%d, id=%d cleanup required\n", 442 __func__, hhh->hhh_type, hhh->hhh_id); 443 hhook_head_destroy(hhh); 444 } 445 HHHLIST_UNLOCK(); 446} 447 448 449/* 450 * When a vnet is created and being initialised, init the V_hhook_vhead_list. 451 */ 452VNET_SYSINIT(hhook_vnet_init, SI_SUB_PROTO_BEGIN, SI_ORDER_FIRST, 453 hhook_vnet_init, NULL); 454 455/* 456 * The hhook KPI provides a mechanism for subsystems which export helper hook 457 * points to clean up on vnet tear down, but in case the KPI is misused, 458 * provide a function to clean up and free memory for a vnet being destroyed. 459 */ 460VNET_SYSUNINIT(hhook_vnet_uninit, SI_SUB_PROTO_BEGIN, SI_ORDER_FIRST, 461 hhook_vnet_uninit, NULL);
|