1 1.15 hannken /* $NetBSD: kern_hook.c,v 1.15 2024/01/17 10:18:41 hannken Exp $ */ 2 1.1 pooka 3 1.1 pooka /*- 4 1.1 pooka * Copyright (c) 1997, 1998, 1999, 2002, 2007, 2008 The NetBSD Foundation, Inc. 5 1.1 pooka * All rights reserved. 6 1.1 pooka * 7 1.1 pooka * This code is derived from software contributed to The NetBSD Foundation 8 1.1 pooka * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility, 9 1.1 pooka * NASA Ames Research Center, and by Luke Mewburn. 10 1.1 pooka * 11 1.1 pooka * Redistribution and use in source and binary forms, with or without 12 1.1 pooka * modification, are permitted provided that the following conditions 13 1.1 pooka * are met: 14 1.1 pooka * 1. Redistributions of source code must retain the above copyright 15 1.1 pooka * notice, this list of conditions and the following disclaimer. 16 1.1 pooka * 2. Redistributions in binary form must reproduce the above copyright 17 1.1 pooka * notice, this list of conditions and the following disclaimer in the 18 1.1 pooka * documentation and/or other materials provided with the distribution. 19 1.1 pooka * 20 1.1 pooka * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 21 1.1 pooka * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 22 1.1 pooka * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 23 1.1 pooka * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 24 1.1 pooka * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 25 1.1 pooka * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 26 1.1 pooka * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 27 1.1 pooka * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 28 1.1 pooka * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 29 1.1 pooka * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 30 1.1 pooka * POSSIBILITY OF SUCH DAMAGE. 31 1.1 pooka */ 32 1.1 pooka 33 1.1 pooka #include <sys/cdefs.h> 34 1.15 hannken __KERNEL_RCSID(0, "$NetBSD: kern_hook.c,v 1.15 2024/01/17 10:18:41 hannken Exp $"); 35 1.1 pooka 36 1.1 pooka #include <sys/param.h> 37 1.14 riastrad 38 1.10 skrll #include <sys/condvar.h> 39 1.11 skrll #include <sys/cpu.h> 40 1.10 skrll #include <sys/device.h> 41 1.14 riastrad #include <sys/exec.h> 42 1.10 skrll #include <sys/hook.h> 43 1.10 skrll #include <sys/kmem.h> 44 1.1 pooka #include <sys/malloc.h> 45 1.15 hannken #include <sys/once.h> 46 1.1 pooka #include <sys/rwlock.h> 47 1.1 pooka #include <sys/systm.h> 48 1.1 pooka 49 1.1 pooka /* 50 1.1 pooka * A generic linear hook. 51 1.1 pooka */ 52 1.1 pooka struct hook_desc { 53 1.1 pooka LIST_ENTRY(hook_desc) hk_list; 54 1.1 pooka void (*hk_fn)(void *); 55 1.1 pooka void *hk_arg; 56 1.1 pooka }; 57 1.1 pooka typedef LIST_HEAD(, hook_desc) hook_list_t; 58 1.1 pooka 59 1.9 yamaguch enum hook_list_st { 60 1.9 yamaguch HKLIST_IDLE, 61 1.9 yamaguch HKLIST_INUSE, 62 1.9 yamaguch }; 63 1.9 yamaguch 64 1.9 yamaguch struct khook_list { 65 1.9 yamaguch hook_list_t hl_list; 66 1.9 yamaguch kmutex_t hl_lock; 67 1.9 yamaguch kmutex_t *hl_cvlock; 68 1.9 yamaguch struct lwp *hl_lwp; 69 1.9 yamaguch kcondvar_t hl_cv; 70 1.9 yamaguch enum hook_list_st 71 1.9 yamaguch hl_state; 72 1.9 yamaguch khook_t *hl_active_hk; 73 1.9 yamaguch char hl_namebuf[HOOKNAMSIZ]; 74 1.9 yamaguch }; 75 1.9 yamaguch 76 1.1 pooka int powerhook_debug = 0; 77 1.1 pooka 78 1.15 hannken static ONCE_DECL(hook_control); 79 1.15 hannken static krwlock_t exithook_lock; 80 1.15 hannken static krwlock_t forkhook_lock; 81 1.15 hannken 82 1.15 hannken static int 83 1.15 hannken hook_init(void) 84 1.15 hannken { 85 1.15 hannken 86 1.15 hannken rw_init(&exithook_lock); 87 1.15 hannken rw_init(&forkhook_lock); 88 1.15 hannken 89 1.15 hannken return 0; 90 1.15 hannken } 91 1.15 hannken 92 1.1 pooka static void * 93 1.15 hannken hook_establish(hook_list_t *list, krwlock_t *lock, 94 1.15 hannken void (*fn)(void *), void *arg) 95 1.1 pooka { 96 1.1 pooka struct hook_desc *hd; 97 1.1 pooka 98 1.15 hannken RUN_ONCE(&hook_control, hook_init); 99 1.15 hannken 100 1.1 pooka hd = malloc(sizeof(*hd), M_DEVBUF, M_NOWAIT); 101 1.15 hannken if (hd != NULL) { 102 1.15 hannken if (lock) 103 1.15 hannken rw_enter(lock, RW_WRITER); 104 1.15 hannken hd->hk_fn = fn; 105 1.15 hannken hd->hk_arg = arg; 106 1.15 hannken LIST_INSERT_HEAD(list, hd, hk_list); 107 1.15 hannken if (lock) 108 1.15 hannken rw_exit(lock); 109 1.15 hannken } 110 1.1 pooka 111 1.1 pooka return (hd); 112 1.1 pooka } 113 1.1 pooka 114 1.1 pooka static void 115 1.15 hannken hook_disestablish(hook_list_t *list, krwlock_t *lock, void *vhook) 116 1.1 pooka { 117 1.15 hannken 118 1.15 hannken if (lock) 119 1.15 hannken rw_enter(lock, RW_WRITER); 120 1.1 pooka #ifdef DIAGNOSTIC 121 1.1 pooka struct hook_desc *hd; 122 1.1 pooka 123 1.1 pooka LIST_FOREACH(hd, list, hk_list) { 124 1.1 pooka if (hd == vhook) 125 1.1 pooka break; 126 1.1 pooka } 127 1.1 pooka 128 1.1 pooka if (hd == NULL) 129 1.1 pooka panic("hook_disestablish: hook %p not established", vhook); 130 1.1 pooka #endif 131 1.1 pooka LIST_REMOVE((struct hook_desc *)vhook, hk_list); 132 1.1 pooka free(vhook, M_DEVBUF); 133 1.15 hannken if (lock) 134 1.15 hannken rw_exit(lock); 135 1.1 pooka } 136 1.1 pooka 137 1.1 pooka static void 138 1.1 pooka hook_destroy(hook_list_t *list) 139 1.1 pooka { 140 1.1 pooka struct hook_desc *hd; 141 1.1 pooka 142 1.1 pooka while ((hd = LIST_FIRST(list)) != NULL) { 143 1.1 pooka LIST_REMOVE(hd, hk_list); 144 1.1 pooka free(hd, M_DEVBUF); 145 1.1 pooka } 146 1.1 pooka } 147 1.1 pooka 148 1.1 pooka static void 149 1.15 hannken hook_proc_run(hook_list_t *list, krwlock_t *lock, struct proc *p) 150 1.1 pooka { 151 1.1 pooka struct hook_desc *hd; 152 1.1 pooka 153 1.15 hannken RUN_ONCE(&hook_control, hook_init); 154 1.15 hannken 155 1.15 hannken if (lock) 156 1.15 hannken rw_enter(lock, RW_READER); 157 1.8 christos LIST_FOREACH(hd, list, hk_list) { 158 1.8 christos __FPTRCAST(void (*)(struct proc *, void *), *hd->hk_fn)(p, 159 1.8 christos hd->hk_arg); 160 1.8 christos } 161 1.15 hannken if (lock) 162 1.15 hannken rw_exit(lock); 163 1.1 pooka } 164 1.1 pooka 165 1.1 pooka /* 166 1.1 pooka * "Shutdown hook" types, functions, and variables. 167 1.1 pooka * 168 1.1 pooka * Should be invoked immediately before the 169 1.1 pooka * system is halted or rebooted, i.e. after file systems unmounted, 170 1.1 pooka * after crash dump done, etc. 171 1.1 pooka * 172 1.1 pooka * Each shutdown hook is removed from the list before it's run, so that 173 1.1 pooka * it won't be run again. 174 1.1 pooka */ 175 1.1 pooka 176 1.1 pooka static hook_list_t shutdownhook_list = LIST_HEAD_INITIALIZER(shutdownhook_list); 177 1.1 pooka 178 1.1 pooka void * 179 1.1 pooka shutdownhook_establish(void (*fn)(void *), void *arg) 180 1.1 pooka { 181 1.15 hannken return hook_establish(&shutdownhook_list, NULL, fn, arg); 182 1.1 pooka } 183 1.1 pooka 184 1.1 pooka void 185 1.1 pooka shutdownhook_disestablish(void *vhook) 186 1.1 pooka { 187 1.15 hannken hook_disestablish(&shutdownhook_list, NULL, vhook); 188 1.1 pooka } 189 1.1 pooka 190 1.1 pooka /* 191 1.1 pooka * Run shutdown hooks. Should be invoked immediately before the 192 1.1 pooka * system is halted or rebooted, i.e. after file systems unmounted, 193 1.1 pooka * after crash dump done, etc. 194 1.1 pooka * 195 1.1 pooka * Each shutdown hook is removed from the list before it's run, so that 196 1.1 pooka * it won't be run again. 197 1.1 pooka */ 198 1.1 pooka void 199 1.1 pooka doshutdownhooks(void) 200 1.1 pooka { 201 1.1 pooka struct hook_desc *dp; 202 1.1 pooka 203 1.1 pooka while ((dp = LIST_FIRST(&shutdownhook_list)) != NULL) { 204 1.1 pooka LIST_REMOVE(dp, hk_list); 205 1.1 pooka (*dp->hk_fn)(dp->hk_arg); 206 1.1 pooka #if 0 207 1.1 pooka /* 208 1.1 pooka * Don't bother freeing the hook structure,, since we may 209 1.1 pooka * be rebooting because of a memory corruption problem, 210 1.1 pooka * and this might only make things worse. It doesn't 211 1.1 pooka * matter, anyway, since the system is just about to 212 1.1 pooka * reboot. 213 1.1 pooka */ 214 1.1 pooka free(dp, M_DEVBUF); 215 1.1 pooka #endif 216 1.1 pooka } 217 1.1 pooka } 218 1.1 pooka 219 1.1 pooka /* 220 1.1 pooka * "Mountroot hook" types, functions, and variables. 221 1.1 pooka */ 222 1.1 pooka 223 1.1 pooka static hook_list_t mountroothook_list=LIST_HEAD_INITIALIZER(mountroothook_list); 224 1.1 pooka 225 1.1 pooka void * 226 1.1 pooka mountroothook_establish(void (*fn)(device_t), device_t dev) 227 1.1 pooka { 228 1.15 hannken return hook_establish(&mountroothook_list, NULL, 229 1.15 hannken __FPTRCAST(void (*), fn), dev); 230 1.1 pooka } 231 1.1 pooka 232 1.1 pooka void 233 1.1 pooka mountroothook_disestablish(void *vhook) 234 1.1 pooka { 235 1.15 hannken hook_disestablish(&mountroothook_list, NULL, vhook); 236 1.1 pooka } 237 1.1 pooka 238 1.1 pooka void 239 1.1 pooka mountroothook_destroy(void) 240 1.1 pooka { 241 1.1 pooka hook_destroy(&mountroothook_list); 242 1.1 pooka } 243 1.1 pooka 244 1.1 pooka void 245 1.5 chs domountroothook(device_t therootdev) 246 1.1 pooka { 247 1.1 pooka struct hook_desc *hd; 248 1.1 pooka 249 1.1 pooka LIST_FOREACH(hd, &mountroothook_list, hk_list) { 250 1.2 pooka if (hd->hk_arg == therootdev) { 251 1.1 pooka (*hd->hk_fn)(hd->hk_arg); 252 1.1 pooka return; 253 1.1 pooka } 254 1.1 pooka } 255 1.1 pooka } 256 1.1 pooka 257 1.1 pooka static hook_list_t exechook_list = LIST_HEAD_INITIALIZER(exechook_list); 258 1.1 pooka 259 1.1 pooka void * 260 1.1 pooka exechook_establish(void (*fn)(struct proc *, void *), void *arg) 261 1.1 pooka { 262 1.15 hannken return hook_establish(&exechook_list, &exec_lock, 263 1.15 hannken __FPTRCAST(void (*)(void *), fn), arg); 264 1.1 pooka } 265 1.1 pooka 266 1.1 pooka void 267 1.1 pooka exechook_disestablish(void *vhook) 268 1.1 pooka { 269 1.15 hannken hook_disestablish(&exechook_list, &exec_lock, vhook); 270 1.1 pooka } 271 1.1 pooka 272 1.1 pooka /* 273 1.1 pooka * Run exec hooks. 274 1.1 pooka */ 275 1.1 pooka void 276 1.1 pooka doexechooks(struct proc *p) 277 1.1 pooka { 278 1.15 hannken KASSERT(rw_lock_held(&exec_lock)); 279 1.15 hannken 280 1.15 hannken hook_proc_run(&exechook_list, NULL, p); 281 1.1 pooka } 282 1.1 pooka 283 1.1 pooka static hook_list_t exithook_list = LIST_HEAD_INITIALIZER(exithook_list); 284 1.1 pooka 285 1.1 pooka void * 286 1.1 pooka exithook_establish(void (*fn)(struct proc *, void *), void *arg) 287 1.1 pooka { 288 1.1 pooka 289 1.15 hannken return hook_establish(&exithook_list, &exithook_lock, 290 1.15 hannken __FPTRCAST(void (*)(void *), fn), arg); 291 1.1 pooka } 292 1.1 pooka 293 1.1 pooka void 294 1.1 pooka exithook_disestablish(void *vhook) 295 1.1 pooka { 296 1.1 pooka 297 1.15 hannken hook_disestablish(&exithook_list, &exithook_lock, vhook); 298 1.1 pooka } 299 1.1 pooka 300 1.1 pooka /* 301 1.1 pooka * Run exit hooks. 302 1.1 pooka */ 303 1.1 pooka void 304 1.1 pooka doexithooks(struct proc *p) 305 1.1 pooka { 306 1.15 hannken hook_proc_run(&exithook_list, &exithook_lock, p); 307 1.1 pooka } 308 1.1 pooka 309 1.1 pooka static hook_list_t forkhook_list = LIST_HEAD_INITIALIZER(forkhook_list); 310 1.1 pooka 311 1.1 pooka void * 312 1.1 pooka forkhook_establish(void (*fn)(struct proc *, struct proc *)) 313 1.1 pooka { 314 1.15 hannken return hook_establish(&forkhook_list, &forkhook_lock, 315 1.15 hannken __FPTRCAST(void (*)(void *), fn), NULL); 316 1.1 pooka } 317 1.1 pooka 318 1.1 pooka void 319 1.1 pooka forkhook_disestablish(void *vhook) 320 1.1 pooka { 321 1.15 hannken hook_disestablish(&forkhook_list, &forkhook_lock, vhook); 322 1.1 pooka } 323 1.1 pooka 324 1.1 pooka /* 325 1.1 pooka * Run fork hooks. 326 1.1 pooka */ 327 1.1 pooka void 328 1.1 pooka doforkhooks(struct proc *p2, struct proc *p1) 329 1.1 pooka { 330 1.1 pooka struct hook_desc *hd; 331 1.1 pooka 332 1.15 hannken RUN_ONCE(&hook_control, hook_init); 333 1.15 hannken 334 1.15 hannken rw_enter(&forkhook_lock, RW_READER); 335 1.1 pooka LIST_FOREACH(hd, &forkhook_list, hk_list) { 336 1.8 christos __FPTRCAST(void (*)(struct proc *, struct proc *), *hd->hk_fn) 337 1.1 pooka (p2, p1); 338 1.1 pooka } 339 1.15 hannken rw_exit(&forkhook_lock); 340 1.1 pooka } 341 1.1 pooka 342 1.4 matt static hook_list_t critpollhook_list = LIST_HEAD_INITIALIZER(critpollhook_list); 343 1.4 matt 344 1.4 matt void * 345 1.4 matt critpollhook_establish(void (*fn)(void *), void *arg) 346 1.4 matt { 347 1.15 hannken return hook_establish(&critpollhook_list, NULL, fn, arg); 348 1.4 matt } 349 1.4 matt 350 1.4 matt void 351 1.4 matt critpollhook_disestablish(void *vhook) 352 1.4 matt { 353 1.15 hannken hook_disestablish(&critpollhook_list, NULL, vhook); 354 1.4 matt } 355 1.4 matt 356 1.4 matt /* 357 1.4 matt * Run critical polling hooks. 358 1.4 matt */ 359 1.4 matt void 360 1.4 matt docritpollhooks(void) 361 1.4 matt { 362 1.4 matt struct hook_desc *hd; 363 1.4 matt 364 1.4 matt LIST_FOREACH(hd, &critpollhook_list, hk_list) { 365 1.4 matt (*hd->hk_fn)(hd->hk_arg); 366 1.4 matt } 367 1.4 matt } 368 1.4 matt 369 1.1 pooka /* 370 1.1 pooka * "Power hook" types, functions, and variables. 371 1.1 pooka * The list of power hooks is kept ordered with the last registered hook 372 1.1 pooka * first. 373 1.1 pooka * When running the hooks on power down the hooks are called in reverse 374 1.1 pooka * registration order, when powering up in registration order. 375 1.1 pooka */ 376 1.1 pooka struct powerhook_desc { 377 1.6 christos TAILQ_ENTRY(powerhook_desc) sfd_list; 378 1.1 pooka void (*sfd_fn)(int, void *); 379 1.1 pooka void *sfd_arg; 380 1.1 pooka char sfd_name[16]; 381 1.1 pooka }; 382 1.1 pooka 383 1.6 christos static TAILQ_HEAD(powerhook_head, powerhook_desc) powerhook_list = 384 1.6 christos TAILQ_HEAD_INITIALIZER(powerhook_list); 385 1.1 pooka 386 1.1 pooka void * 387 1.1 pooka powerhook_establish(const char *name, void (*fn)(int, void *), void *arg) 388 1.1 pooka { 389 1.1 pooka struct powerhook_desc *ndp; 390 1.1 pooka 391 1.1 pooka ndp = (struct powerhook_desc *) 392 1.1 pooka malloc(sizeof(*ndp), M_DEVBUF, M_NOWAIT); 393 1.1 pooka if (ndp == NULL) 394 1.1 pooka return (NULL); 395 1.1 pooka 396 1.1 pooka ndp->sfd_fn = fn; 397 1.1 pooka ndp->sfd_arg = arg; 398 1.1 pooka strlcpy(ndp->sfd_name, name, sizeof(ndp->sfd_name)); 399 1.6 christos TAILQ_INSERT_HEAD(&powerhook_list, ndp, sfd_list); 400 1.1 pooka 401 1.1 pooka aprint_error("%s: WARNING: powerhook_establish is deprecated\n", name); 402 1.1 pooka return (ndp); 403 1.1 pooka } 404 1.1 pooka 405 1.1 pooka void 406 1.1 pooka powerhook_disestablish(void *vhook) 407 1.1 pooka { 408 1.1 pooka #ifdef DIAGNOSTIC 409 1.1 pooka struct powerhook_desc *dp; 410 1.1 pooka 411 1.6 christos TAILQ_FOREACH(dp, &powerhook_list, sfd_list) 412 1.1 pooka if (dp == vhook) 413 1.1 pooka goto found; 414 1.1 pooka panic("powerhook_disestablish: hook %p not established", vhook); 415 1.1 pooka found: 416 1.1 pooka #endif 417 1.1 pooka 418 1.6 christos TAILQ_REMOVE(&powerhook_list, (struct powerhook_desc *)vhook, 419 1.1 pooka sfd_list); 420 1.1 pooka free(vhook, M_DEVBUF); 421 1.1 pooka } 422 1.1 pooka 423 1.1 pooka /* 424 1.1 pooka * Run power hooks. 425 1.1 pooka */ 426 1.1 pooka void 427 1.1 pooka dopowerhooks(int why) 428 1.1 pooka { 429 1.1 pooka struct powerhook_desc *dp; 430 1.1 pooka const char *why_name; 431 1.1 pooka static const char * pwr_names[] = {PWR_NAMES}; 432 1.1 pooka why_name = why < __arraycount(pwr_names) ? pwr_names[why] : "???"; 433 1.1 pooka 434 1.1 pooka if (why == PWR_RESUME || why == PWR_SOFTRESUME) { 435 1.6 christos TAILQ_FOREACH_REVERSE(dp, &powerhook_list, powerhook_head, 436 1.6 christos sfd_list) 437 1.6 christos { 438 1.1 pooka if (powerhook_debug) 439 1.1 pooka printf("dopowerhooks %s: %s (%p)\n", 440 1.1 pooka why_name, dp->sfd_name, dp); 441 1.1 pooka (*dp->sfd_fn)(why, dp->sfd_arg); 442 1.1 pooka } 443 1.1 pooka } else { 444 1.6 christos TAILQ_FOREACH(dp, &powerhook_list, sfd_list) { 445 1.1 pooka if (powerhook_debug) 446 1.1 pooka printf("dopowerhooks %s: %s (%p)\n", 447 1.1 pooka why_name, dp->sfd_name, dp); 448 1.1 pooka (*dp->sfd_fn)(why, dp->sfd_arg); 449 1.1 pooka } 450 1.1 pooka } 451 1.1 pooka 452 1.1 pooka if (powerhook_debug) 453 1.1 pooka printf("dopowerhooks: %s done\n", why_name); 454 1.1 pooka } 455 1.9 yamaguch 456 1.9 yamaguch /* 457 1.9 yamaguch * A simple linear hook. 458 1.9 yamaguch */ 459 1.9 yamaguch 460 1.9 yamaguch khook_list_t * 461 1.9 yamaguch simplehook_create(int ipl, const char *wmsg) 462 1.9 yamaguch { 463 1.9 yamaguch khook_list_t *l; 464 1.9 yamaguch 465 1.9 yamaguch l = kmem_zalloc(sizeof(*l), KM_SLEEP); 466 1.9 yamaguch 467 1.9 yamaguch mutex_init(&l->hl_lock, MUTEX_DEFAULT, ipl); 468 1.9 yamaguch strlcpy(l->hl_namebuf, wmsg, sizeof(l->hl_namebuf)); 469 1.9 yamaguch cv_init(&l->hl_cv, l->hl_namebuf); 470 1.9 yamaguch LIST_INIT(&l->hl_list); 471 1.9 yamaguch l->hl_state = HKLIST_IDLE; 472 1.9 yamaguch 473 1.9 yamaguch return l; 474 1.9 yamaguch } 475 1.9 yamaguch 476 1.9 yamaguch void 477 1.9 yamaguch simplehook_destroy(khook_list_t *l) 478 1.9 yamaguch { 479 1.9 yamaguch struct hook_desc *hd; 480 1.9 yamaguch 481 1.9 yamaguch KASSERT(l->hl_state == HKLIST_IDLE); 482 1.9 yamaguch 483 1.9 yamaguch while ((hd = LIST_FIRST(&l->hl_list)) != NULL) { 484 1.9 yamaguch LIST_REMOVE(hd, hk_list); 485 1.9 yamaguch kmem_free(hd, sizeof(*hd)); 486 1.9 yamaguch } 487 1.9 yamaguch 488 1.9 yamaguch cv_destroy(&l->hl_cv); 489 1.9 yamaguch mutex_destroy(&l->hl_lock); 490 1.9 yamaguch kmem_free(l, sizeof(*l)); 491 1.9 yamaguch } 492 1.9 yamaguch 493 1.9 yamaguch int 494 1.9 yamaguch simplehook_dohooks(khook_list_t *l) 495 1.9 yamaguch { 496 1.9 yamaguch struct hook_desc *hd, *nexthd; 497 1.9 yamaguch kmutex_t *cv_lock; 498 1.9 yamaguch void (*fn)(void *); 499 1.9 yamaguch void *arg; 500 1.9 yamaguch 501 1.9 yamaguch mutex_enter(&l->hl_lock); 502 1.9 yamaguch if (l->hl_state != HKLIST_IDLE) { 503 1.9 yamaguch mutex_exit(&l->hl_lock); 504 1.9 yamaguch return EBUSY; 505 1.9 yamaguch } 506 1.9 yamaguch 507 1.9 yamaguch /* stop removing hooks */ 508 1.9 yamaguch l->hl_state = HKLIST_INUSE; 509 1.9 yamaguch l->hl_lwp = curlwp; 510 1.9 yamaguch 511 1.9 yamaguch LIST_FOREACH(hd, &l->hl_list, hk_list) { 512 1.9 yamaguch if (hd->hk_fn == NULL) 513 1.9 yamaguch continue; 514 1.9 yamaguch 515 1.9 yamaguch fn = hd->hk_fn; 516 1.9 yamaguch arg = hd->hk_arg; 517 1.9 yamaguch l->hl_active_hk = hd; 518 1.9 yamaguch l->hl_cvlock = NULL; 519 1.9 yamaguch 520 1.9 yamaguch mutex_exit(&l->hl_lock); 521 1.9 yamaguch 522 1.9 yamaguch /* do callback without l->hl_lock */ 523 1.9 yamaguch (*fn)(arg); 524 1.9 yamaguch 525 1.9 yamaguch mutex_enter(&l->hl_lock); 526 1.9 yamaguch l->hl_active_hk = NULL; 527 1.9 yamaguch cv_lock = l->hl_cvlock; 528 1.9 yamaguch 529 1.9 yamaguch if (hd->hk_fn == NULL) { 530 1.9 yamaguch if (cv_lock != NULL) { 531 1.9 yamaguch mutex_exit(&l->hl_lock); 532 1.9 yamaguch mutex_enter(cv_lock); 533 1.9 yamaguch } 534 1.9 yamaguch 535 1.9 yamaguch cv_broadcast(&l->hl_cv); 536 1.9 yamaguch 537 1.9 yamaguch if (cv_lock != NULL) { 538 1.9 yamaguch mutex_exit(cv_lock); 539 1.9 yamaguch mutex_enter(&l->hl_lock); 540 1.9 yamaguch } 541 1.9 yamaguch } 542 1.9 yamaguch } 543 1.9 yamaguch 544 1.9 yamaguch /* remove marked node while running hooks */ 545 1.9 yamaguch LIST_FOREACH_SAFE(hd, &l->hl_list, hk_list, nexthd) { 546 1.9 yamaguch if (hd->hk_fn == NULL) { 547 1.9 yamaguch LIST_REMOVE(hd, hk_list); 548 1.9 yamaguch kmem_free(hd, sizeof(*hd)); 549 1.9 yamaguch } 550 1.9 yamaguch } 551 1.9 yamaguch 552 1.9 yamaguch l->hl_lwp = NULL; 553 1.9 yamaguch l->hl_state = HKLIST_IDLE; 554 1.9 yamaguch mutex_exit(&l->hl_lock); 555 1.9 yamaguch 556 1.9 yamaguch return 0; 557 1.9 yamaguch } 558 1.9 yamaguch 559 1.9 yamaguch khook_t * 560 1.12 gson simplehook_establish(khook_list_t *l, void (*fn)(void *), void *arg) 561 1.9 yamaguch { 562 1.9 yamaguch struct hook_desc *hd; 563 1.9 yamaguch 564 1.9 yamaguch hd = kmem_zalloc(sizeof(*hd), KM_SLEEP); 565 1.9 yamaguch hd->hk_fn = fn; 566 1.9 yamaguch hd->hk_arg = arg; 567 1.9 yamaguch 568 1.9 yamaguch mutex_enter(&l->hl_lock); 569 1.9 yamaguch LIST_INSERT_HEAD(&l->hl_list, hd, hk_list); 570 1.9 yamaguch mutex_exit(&l->hl_lock); 571 1.9 yamaguch 572 1.9 yamaguch return hd; 573 1.9 yamaguch } 574 1.9 yamaguch 575 1.9 yamaguch void 576 1.9 yamaguch simplehook_disestablish(khook_list_t *l, khook_t *hd, kmutex_t *lock) 577 1.9 yamaguch { 578 1.9 yamaguch struct hook_desc *hd0 __diagused; 579 1.9 yamaguch kmutex_t *cv_lock; 580 1.9 yamaguch 581 1.9 yamaguch KASSERT(lock == NULL || mutex_owned(lock)); 582 1.9 yamaguch mutex_enter(&l->hl_lock); 583 1.9 yamaguch 584 1.9 yamaguch #ifdef DIAGNOSTIC 585 1.9 yamaguch LIST_FOREACH(hd0, &l->hl_list, hk_list) { 586 1.9 yamaguch if (hd == hd0) 587 1.9 yamaguch break; 588 1.9 yamaguch } 589 1.9 yamaguch 590 1.9 yamaguch if (hd0 == NULL) 591 1.9 yamaguch panic("hook_disestablish: hook %p not established", hd); 592 1.9 yamaguch #endif 593 1.9 yamaguch 594 1.13 andvar /* The hook is not referred, remove immediately */ 595 1.9 yamaguch if (l->hl_state == HKLIST_IDLE) { 596 1.9 yamaguch LIST_REMOVE(hd, hk_list); 597 1.9 yamaguch kmem_free(hd, sizeof(*hd)); 598 1.9 yamaguch mutex_exit(&l->hl_lock); 599 1.9 yamaguch return; 600 1.9 yamaguch } 601 1.9 yamaguch 602 1.9 yamaguch /* remove callback. hd will be removed in dohooks */ 603 1.9 yamaguch hd->hk_fn = NULL; 604 1.9 yamaguch hd->hk_arg = NULL; 605 1.9 yamaguch 606 1.9 yamaguch /* If the hook is running, wait for the completion */ 607 1.9 yamaguch if (l->hl_active_hk == hd && 608 1.9 yamaguch l->hl_lwp != curlwp) { 609 1.9 yamaguch if (lock != NULL) { 610 1.9 yamaguch cv_lock = lock; 611 1.9 yamaguch KASSERT(l->hl_cvlock == NULL); 612 1.9 yamaguch l->hl_cvlock = lock; 613 1.9 yamaguch mutex_exit(&l->hl_lock); 614 1.9 yamaguch } else { 615 1.9 yamaguch cv_lock = &l->hl_lock; 616 1.9 yamaguch } 617 1.9 yamaguch 618 1.9 yamaguch cv_wait(&l->hl_cv, cv_lock); 619 1.9 yamaguch 620 1.9 yamaguch if (lock == NULL) 621 1.9 yamaguch mutex_exit(&l->hl_lock); 622 1.9 yamaguch } else { 623 1.9 yamaguch mutex_exit(&l->hl_lock); 624 1.9 yamaguch } 625 1.9 yamaguch } 626 1.9 yamaguch 627 1.9 yamaguch bool 628 1.9 yamaguch simplehook_has_hooks(khook_list_t *l) 629 1.9 yamaguch { 630 1.9 yamaguch bool empty; 631 1.9 yamaguch 632 1.9 yamaguch mutex_enter(&l->hl_lock); 633 1.9 yamaguch empty = LIST_EMPTY(&l->hl_list); 634 1.9 yamaguch mutex_exit(&l->hl_lock); 635 1.9 yamaguch 636 1.9 yamaguch return !empty; 637 1.9 yamaguch } 638