Home | History | Annotate | Line # | Download | only in kern
kern_hook.c revision 1.9
      1  1.9  yamaguch /*	$NetBSD: kern_hook.c,v 1.9 2021/09/30 01:26:07 yamaguchi 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.9  yamaguch __KERNEL_RCSID(0, "$NetBSD: kern_hook.c,v 1.9 2021/09/30 01:26:07 yamaguchi Exp $");
     35  1.1     pooka 
     36  1.1     pooka #include <sys/param.h>
     37  1.1     pooka #include <sys/malloc.h>
     38  1.1     pooka #include <sys/rwlock.h>
     39  1.1     pooka #include <sys/systm.h>
     40  1.3    martin #include <sys/device.h>
     41  1.9  yamaguch #include <sys/hook.h>
     42  1.9  yamaguch #include <sys/kmem.h>
     43  1.9  yamaguch #include <sys/condvar.h>
     44  1.1     pooka 
     45  1.1     pooka /*
     46  1.1     pooka  * A generic linear hook.
     47  1.1     pooka  */
     48  1.1     pooka struct hook_desc {
     49  1.1     pooka 	LIST_ENTRY(hook_desc) hk_list;
     50  1.1     pooka 	void	(*hk_fn)(void *);
     51  1.1     pooka 	void	*hk_arg;
     52  1.1     pooka };
     53  1.1     pooka typedef LIST_HEAD(, hook_desc) hook_list_t;
     54  1.1     pooka 
     55  1.9  yamaguch enum hook_list_st {
     56  1.9  yamaguch 	HKLIST_IDLE,
     57  1.9  yamaguch 	HKLIST_INUSE,
     58  1.9  yamaguch };
     59  1.9  yamaguch 
     60  1.9  yamaguch struct khook_list {
     61  1.9  yamaguch 	hook_list_t	 hl_list;
     62  1.9  yamaguch 	kmutex_t	 hl_lock;
     63  1.9  yamaguch 	kmutex_t	*hl_cvlock;
     64  1.9  yamaguch 	struct lwp	*hl_lwp;
     65  1.9  yamaguch 	kcondvar_t	 hl_cv;
     66  1.9  yamaguch 	enum hook_list_st
     67  1.9  yamaguch 			 hl_state;
     68  1.9  yamaguch 	khook_t		*hl_active_hk;
     69  1.9  yamaguch 	char		 hl_namebuf[HOOKNAMSIZ];
     70  1.9  yamaguch };
     71  1.9  yamaguch 
     72  1.1     pooka int	powerhook_debug = 0;
     73  1.1     pooka 
     74  1.1     pooka static void *
     75  1.1     pooka hook_establish(hook_list_t *list, void (*fn)(void *), void *arg)
     76  1.1     pooka {
     77  1.1     pooka 	struct hook_desc *hd;
     78  1.1     pooka 
     79  1.1     pooka 	hd = malloc(sizeof(*hd), M_DEVBUF, M_NOWAIT);
     80  1.1     pooka 	if (hd == NULL)
     81  1.1     pooka 		return (NULL);
     82  1.1     pooka 
     83  1.1     pooka 	hd->hk_fn = fn;
     84  1.1     pooka 	hd->hk_arg = arg;
     85  1.1     pooka 	LIST_INSERT_HEAD(list, hd, hk_list);
     86  1.1     pooka 
     87  1.1     pooka 	return (hd);
     88  1.1     pooka }
     89  1.1     pooka 
     90  1.1     pooka static void
     91  1.1     pooka hook_disestablish(hook_list_t *list, void *vhook)
     92  1.1     pooka {
     93  1.1     pooka #ifdef DIAGNOSTIC
     94  1.1     pooka 	struct hook_desc *hd;
     95  1.1     pooka 
     96  1.1     pooka 	LIST_FOREACH(hd, list, hk_list) {
     97  1.1     pooka                 if (hd == vhook)
     98  1.1     pooka 			break;
     99  1.1     pooka 	}
    100  1.1     pooka 
    101  1.1     pooka 	if (hd == NULL)
    102  1.1     pooka 		panic("hook_disestablish: hook %p not established", vhook);
    103  1.1     pooka #endif
    104  1.1     pooka 	LIST_REMOVE((struct hook_desc *)vhook, hk_list);
    105  1.1     pooka 	free(vhook, M_DEVBUF);
    106  1.1     pooka }
    107  1.1     pooka 
    108  1.1     pooka static void
    109  1.1     pooka hook_destroy(hook_list_t *list)
    110  1.1     pooka {
    111  1.1     pooka 	struct hook_desc *hd;
    112  1.1     pooka 
    113  1.1     pooka 	while ((hd = LIST_FIRST(list)) != NULL) {
    114  1.1     pooka 		LIST_REMOVE(hd, hk_list);
    115  1.1     pooka 		free(hd, M_DEVBUF);
    116  1.1     pooka 	}
    117  1.1     pooka }
    118  1.1     pooka 
    119  1.1     pooka static void
    120  1.1     pooka hook_proc_run(hook_list_t *list, struct proc *p)
    121  1.1     pooka {
    122  1.1     pooka 	struct hook_desc *hd;
    123  1.1     pooka 
    124  1.8  christos 	LIST_FOREACH(hd, list, hk_list) {
    125  1.8  christos 		__FPTRCAST(void (*)(struct proc *, void *), *hd->hk_fn)(p,
    126  1.8  christos 		    hd->hk_arg);
    127  1.8  christos 	}
    128  1.1     pooka }
    129  1.1     pooka 
    130  1.1     pooka /*
    131  1.1     pooka  * "Shutdown hook" types, functions, and variables.
    132  1.1     pooka  *
    133  1.1     pooka  * Should be invoked immediately before the
    134  1.1     pooka  * system is halted or rebooted, i.e. after file systems unmounted,
    135  1.1     pooka  * after crash dump done, etc.
    136  1.1     pooka  *
    137  1.1     pooka  * Each shutdown hook is removed from the list before it's run, so that
    138  1.1     pooka  * it won't be run again.
    139  1.1     pooka  */
    140  1.1     pooka 
    141  1.1     pooka static hook_list_t shutdownhook_list = LIST_HEAD_INITIALIZER(shutdownhook_list);
    142  1.1     pooka 
    143  1.1     pooka void *
    144  1.1     pooka shutdownhook_establish(void (*fn)(void *), void *arg)
    145  1.1     pooka {
    146  1.1     pooka 	return hook_establish(&shutdownhook_list, fn, arg);
    147  1.1     pooka }
    148  1.1     pooka 
    149  1.1     pooka void
    150  1.1     pooka shutdownhook_disestablish(void *vhook)
    151  1.1     pooka {
    152  1.1     pooka 	hook_disestablish(&shutdownhook_list, vhook);
    153  1.1     pooka }
    154  1.1     pooka 
    155  1.1     pooka /*
    156  1.1     pooka  * Run shutdown hooks.  Should be invoked immediately before the
    157  1.1     pooka  * system is halted or rebooted, i.e. after file systems unmounted,
    158  1.1     pooka  * after crash dump done, etc.
    159  1.1     pooka  *
    160  1.1     pooka  * Each shutdown hook is removed from the list before it's run, so that
    161  1.1     pooka  * it won't be run again.
    162  1.1     pooka  */
    163  1.1     pooka void
    164  1.1     pooka doshutdownhooks(void)
    165  1.1     pooka {
    166  1.1     pooka 	struct hook_desc *dp;
    167  1.1     pooka 
    168  1.1     pooka 	while ((dp = LIST_FIRST(&shutdownhook_list)) != NULL) {
    169  1.1     pooka 		LIST_REMOVE(dp, hk_list);
    170  1.1     pooka 		(*dp->hk_fn)(dp->hk_arg);
    171  1.1     pooka #if 0
    172  1.1     pooka 		/*
    173  1.1     pooka 		 * Don't bother freeing the hook structure,, since we may
    174  1.1     pooka 		 * be rebooting because of a memory corruption problem,
    175  1.1     pooka 		 * and this might only make things worse.  It doesn't
    176  1.1     pooka 		 * matter, anyway, since the system is just about to
    177  1.1     pooka 		 * reboot.
    178  1.1     pooka 		 */
    179  1.1     pooka 		free(dp, M_DEVBUF);
    180  1.1     pooka #endif
    181  1.1     pooka 	}
    182  1.1     pooka }
    183  1.1     pooka 
    184  1.1     pooka /*
    185  1.1     pooka  * "Mountroot hook" types, functions, and variables.
    186  1.1     pooka  */
    187  1.1     pooka 
    188  1.1     pooka static hook_list_t mountroothook_list=LIST_HEAD_INITIALIZER(mountroothook_list);
    189  1.1     pooka 
    190  1.1     pooka void *
    191  1.1     pooka mountroothook_establish(void (*fn)(device_t), device_t dev)
    192  1.1     pooka {
    193  1.8  christos 	return hook_establish(&mountroothook_list, __FPTRCAST(void (*), fn),
    194  1.8  christos 	    dev);
    195  1.1     pooka }
    196  1.1     pooka 
    197  1.1     pooka void
    198  1.1     pooka mountroothook_disestablish(void *vhook)
    199  1.1     pooka {
    200  1.1     pooka 	hook_disestablish(&mountroothook_list, vhook);
    201  1.1     pooka }
    202  1.1     pooka 
    203  1.1     pooka void
    204  1.1     pooka mountroothook_destroy(void)
    205  1.1     pooka {
    206  1.1     pooka 	hook_destroy(&mountroothook_list);
    207  1.1     pooka }
    208  1.1     pooka 
    209  1.1     pooka void
    210  1.5       chs domountroothook(device_t therootdev)
    211  1.1     pooka {
    212  1.1     pooka 	struct hook_desc *hd;
    213  1.1     pooka 
    214  1.1     pooka 	LIST_FOREACH(hd, &mountroothook_list, hk_list) {
    215  1.2     pooka 		if (hd->hk_arg == therootdev) {
    216  1.1     pooka 			(*hd->hk_fn)(hd->hk_arg);
    217  1.1     pooka 			return;
    218  1.1     pooka 		}
    219  1.1     pooka 	}
    220  1.1     pooka }
    221  1.1     pooka 
    222  1.1     pooka static hook_list_t exechook_list = LIST_HEAD_INITIALIZER(exechook_list);
    223  1.1     pooka 
    224  1.1     pooka void *
    225  1.1     pooka exechook_establish(void (*fn)(struct proc *, void *), void *arg)
    226  1.1     pooka {
    227  1.8  christos 	return hook_establish(&exechook_list, __FPTRCAST(void (*)(void *), fn),
    228  1.8  christos 	    arg);
    229  1.1     pooka }
    230  1.1     pooka 
    231  1.1     pooka void
    232  1.1     pooka exechook_disestablish(void *vhook)
    233  1.1     pooka {
    234  1.1     pooka 	hook_disestablish(&exechook_list, vhook);
    235  1.1     pooka }
    236  1.1     pooka 
    237  1.1     pooka /*
    238  1.1     pooka  * Run exec hooks.
    239  1.1     pooka  */
    240  1.1     pooka void
    241  1.1     pooka doexechooks(struct proc *p)
    242  1.1     pooka {
    243  1.1     pooka 	hook_proc_run(&exechook_list, p);
    244  1.1     pooka }
    245  1.1     pooka 
    246  1.1     pooka static hook_list_t exithook_list = LIST_HEAD_INITIALIZER(exithook_list);
    247  1.1     pooka extern krwlock_t exec_lock;
    248  1.1     pooka 
    249  1.1     pooka void *
    250  1.1     pooka exithook_establish(void (*fn)(struct proc *, void *), void *arg)
    251  1.1     pooka {
    252  1.1     pooka 	void *rv;
    253  1.1     pooka 
    254  1.1     pooka 	rw_enter(&exec_lock, RW_WRITER);
    255  1.8  christos 	rv = hook_establish(&exithook_list, __FPTRCAST(void (*)(void *), fn),
    256  1.8  christos 	    arg);
    257  1.1     pooka 	rw_exit(&exec_lock);
    258  1.1     pooka 	return rv;
    259  1.1     pooka }
    260  1.1     pooka 
    261  1.1     pooka void
    262  1.1     pooka exithook_disestablish(void *vhook)
    263  1.1     pooka {
    264  1.1     pooka 
    265  1.1     pooka 	rw_enter(&exec_lock, RW_WRITER);
    266  1.1     pooka 	hook_disestablish(&exithook_list, vhook);
    267  1.1     pooka 	rw_exit(&exec_lock);
    268  1.1     pooka }
    269  1.1     pooka 
    270  1.1     pooka /*
    271  1.1     pooka  * Run exit hooks.
    272  1.1     pooka  */
    273  1.1     pooka void
    274  1.1     pooka doexithooks(struct proc *p)
    275  1.1     pooka {
    276  1.1     pooka 	hook_proc_run(&exithook_list, p);
    277  1.1     pooka }
    278  1.1     pooka 
    279  1.1     pooka static hook_list_t forkhook_list = LIST_HEAD_INITIALIZER(forkhook_list);
    280  1.1     pooka 
    281  1.1     pooka void *
    282  1.1     pooka forkhook_establish(void (*fn)(struct proc *, struct proc *))
    283  1.1     pooka {
    284  1.8  christos 	return hook_establish(&forkhook_list, __FPTRCAST(void (*)(void *), fn),
    285  1.8  christos 	    NULL);
    286  1.1     pooka }
    287  1.1     pooka 
    288  1.1     pooka void
    289  1.1     pooka forkhook_disestablish(void *vhook)
    290  1.1     pooka {
    291  1.1     pooka 	hook_disestablish(&forkhook_list, vhook);
    292  1.1     pooka }
    293  1.1     pooka 
    294  1.1     pooka /*
    295  1.1     pooka  * Run fork hooks.
    296  1.1     pooka  */
    297  1.1     pooka void
    298  1.1     pooka doforkhooks(struct proc *p2, struct proc *p1)
    299  1.1     pooka {
    300  1.1     pooka 	struct hook_desc *hd;
    301  1.1     pooka 
    302  1.1     pooka 	LIST_FOREACH(hd, &forkhook_list, hk_list) {
    303  1.8  christos 		__FPTRCAST(void (*)(struct proc *, struct proc *), *hd->hk_fn)
    304  1.1     pooka 		    (p2, p1);
    305  1.1     pooka 	}
    306  1.1     pooka }
    307  1.1     pooka 
    308  1.4      matt static hook_list_t critpollhook_list = LIST_HEAD_INITIALIZER(critpollhook_list);
    309  1.4      matt 
    310  1.4      matt void *
    311  1.4      matt critpollhook_establish(void (*fn)(void *), void *arg)
    312  1.4      matt {
    313  1.4      matt 	return hook_establish(&critpollhook_list, fn, arg);
    314  1.4      matt }
    315  1.4      matt 
    316  1.4      matt void
    317  1.4      matt critpollhook_disestablish(void *vhook)
    318  1.4      matt {
    319  1.4      matt 	hook_disestablish(&critpollhook_list, vhook);
    320  1.4      matt }
    321  1.4      matt 
    322  1.4      matt /*
    323  1.4      matt  * Run critical polling hooks.
    324  1.4      matt  */
    325  1.4      matt void
    326  1.4      matt docritpollhooks(void)
    327  1.4      matt {
    328  1.4      matt 	struct hook_desc *hd;
    329  1.4      matt 
    330  1.4      matt 	LIST_FOREACH(hd, &critpollhook_list, hk_list) {
    331  1.4      matt 		(*hd->hk_fn)(hd->hk_arg);
    332  1.4      matt 	}
    333  1.4      matt }
    334  1.4      matt 
    335  1.1     pooka /*
    336  1.1     pooka  * "Power hook" types, functions, and variables.
    337  1.1     pooka  * The list of power hooks is kept ordered with the last registered hook
    338  1.1     pooka  * first.
    339  1.1     pooka  * When running the hooks on power down the hooks are called in reverse
    340  1.1     pooka  * registration order, when powering up in registration order.
    341  1.1     pooka  */
    342  1.1     pooka struct powerhook_desc {
    343  1.6  christos 	TAILQ_ENTRY(powerhook_desc) sfd_list;
    344  1.1     pooka 	void	(*sfd_fn)(int, void *);
    345  1.1     pooka 	void	*sfd_arg;
    346  1.1     pooka 	char	sfd_name[16];
    347  1.1     pooka };
    348  1.1     pooka 
    349  1.6  christos static TAILQ_HEAD(powerhook_head, powerhook_desc) powerhook_list =
    350  1.6  christos     TAILQ_HEAD_INITIALIZER(powerhook_list);
    351  1.1     pooka 
    352  1.1     pooka void *
    353  1.1     pooka powerhook_establish(const char *name, void (*fn)(int, void *), void *arg)
    354  1.1     pooka {
    355  1.1     pooka 	struct powerhook_desc *ndp;
    356  1.1     pooka 
    357  1.1     pooka 	ndp = (struct powerhook_desc *)
    358  1.1     pooka 	    malloc(sizeof(*ndp), M_DEVBUF, M_NOWAIT);
    359  1.1     pooka 	if (ndp == NULL)
    360  1.1     pooka 		return (NULL);
    361  1.1     pooka 
    362  1.1     pooka 	ndp->sfd_fn = fn;
    363  1.1     pooka 	ndp->sfd_arg = arg;
    364  1.1     pooka 	strlcpy(ndp->sfd_name, name, sizeof(ndp->sfd_name));
    365  1.6  christos 	TAILQ_INSERT_HEAD(&powerhook_list, ndp, sfd_list);
    366  1.1     pooka 
    367  1.1     pooka 	aprint_error("%s: WARNING: powerhook_establish is deprecated\n", name);
    368  1.1     pooka 	return (ndp);
    369  1.1     pooka }
    370  1.1     pooka 
    371  1.1     pooka void
    372  1.1     pooka powerhook_disestablish(void *vhook)
    373  1.1     pooka {
    374  1.1     pooka #ifdef DIAGNOSTIC
    375  1.1     pooka 	struct powerhook_desc *dp;
    376  1.1     pooka 
    377  1.6  christos 	TAILQ_FOREACH(dp, &powerhook_list, sfd_list)
    378  1.1     pooka                 if (dp == vhook)
    379  1.1     pooka 			goto found;
    380  1.1     pooka 	panic("powerhook_disestablish: hook %p not established", vhook);
    381  1.1     pooka  found:
    382  1.1     pooka #endif
    383  1.1     pooka 
    384  1.6  christos 	TAILQ_REMOVE(&powerhook_list, (struct powerhook_desc *)vhook,
    385  1.1     pooka 	    sfd_list);
    386  1.1     pooka 	free(vhook, M_DEVBUF);
    387  1.1     pooka }
    388  1.1     pooka 
    389  1.1     pooka /*
    390  1.1     pooka  * Run power hooks.
    391  1.1     pooka  */
    392  1.1     pooka void
    393  1.1     pooka dopowerhooks(int why)
    394  1.1     pooka {
    395  1.1     pooka 	struct powerhook_desc *dp;
    396  1.1     pooka 	const char *why_name;
    397  1.1     pooka 	static const char * pwr_names[] = {PWR_NAMES};
    398  1.1     pooka 	why_name = why < __arraycount(pwr_names) ? pwr_names[why] : "???";
    399  1.1     pooka 
    400  1.1     pooka 	if (why == PWR_RESUME || why == PWR_SOFTRESUME) {
    401  1.6  christos 		TAILQ_FOREACH_REVERSE(dp, &powerhook_list, powerhook_head,
    402  1.6  christos 		    sfd_list)
    403  1.6  christos 		{
    404  1.1     pooka 			if (powerhook_debug)
    405  1.1     pooka 				printf("dopowerhooks %s: %s (%p)\n",
    406  1.1     pooka 				    why_name, dp->sfd_name, dp);
    407  1.1     pooka 			(*dp->sfd_fn)(why, dp->sfd_arg);
    408  1.1     pooka 		}
    409  1.1     pooka 	} else {
    410  1.6  christos 		TAILQ_FOREACH(dp, &powerhook_list, sfd_list) {
    411  1.1     pooka 			if (powerhook_debug)
    412  1.1     pooka 				printf("dopowerhooks %s: %s (%p)\n",
    413  1.1     pooka 				    why_name, dp->sfd_name, dp);
    414  1.1     pooka 			(*dp->sfd_fn)(why, dp->sfd_arg);
    415  1.1     pooka 		}
    416  1.1     pooka 	}
    417  1.1     pooka 
    418  1.1     pooka 	if (powerhook_debug)
    419  1.1     pooka 		printf("dopowerhooks: %s done\n", why_name);
    420  1.1     pooka }
    421  1.9  yamaguch 
    422  1.9  yamaguch /*
    423  1.9  yamaguch  * A simple linear hook.
    424  1.9  yamaguch  */
    425  1.9  yamaguch 
    426  1.9  yamaguch khook_list_t *
    427  1.9  yamaguch simplehook_create(int ipl, const char *wmsg)
    428  1.9  yamaguch {
    429  1.9  yamaguch 	khook_list_t *l;
    430  1.9  yamaguch 
    431  1.9  yamaguch 	l = kmem_zalloc(sizeof(*l), KM_SLEEP);
    432  1.9  yamaguch 
    433  1.9  yamaguch 	mutex_init(&l->hl_lock, MUTEX_DEFAULT, ipl);
    434  1.9  yamaguch 	strlcpy(l->hl_namebuf, wmsg, sizeof(l->hl_namebuf));
    435  1.9  yamaguch 	cv_init(&l->hl_cv, l->hl_namebuf);
    436  1.9  yamaguch 	LIST_INIT(&l->hl_list);
    437  1.9  yamaguch 	l->hl_state = HKLIST_IDLE;
    438  1.9  yamaguch 
    439  1.9  yamaguch 	return l;
    440  1.9  yamaguch }
    441  1.9  yamaguch 
    442  1.9  yamaguch void
    443  1.9  yamaguch simplehook_destroy(khook_list_t *l)
    444  1.9  yamaguch {
    445  1.9  yamaguch 	struct hook_desc *hd;
    446  1.9  yamaguch 
    447  1.9  yamaguch 	KASSERT(l->hl_state == HKLIST_IDLE);
    448  1.9  yamaguch 
    449  1.9  yamaguch 	while ((hd = LIST_FIRST(&l->hl_list)) != NULL) {
    450  1.9  yamaguch 		LIST_REMOVE(hd, hk_list);
    451  1.9  yamaguch 		kmem_free(hd, sizeof(*hd));
    452  1.9  yamaguch 	}
    453  1.9  yamaguch 
    454  1.9  yamaguch 	cv_destroy(&l->hl_cv);
    455  1.9  yamaguch 	mutex_destroy(&l->hl_lock);
    456  1.9  yamaguch 	kmem_free(l, sizeof(*l));
    457  1.9  yamaguch }
    458  1.9  yamaguch 
    459  1.9  yamaguch int
    460  1.9  yamaguch simplehook_dohooks(khook_list_t *l)
    461  1.9  yamaguch {
    462  1.9  yamaguch 	struct hook_desc *hd, *nexthd;
    463  1.9  yamaguch 	kmutex_t *cv_lock;
    464  1.9  yamaguch 	void (*fn)(void *);
    465  1.9  yamaguch 	void *arg;
    466  1.9  yamaguch 
    467  1.9  yamaguch 	mutex_enter(&l->hl_lock);
    468  1.9  yamaguch 	if (l->hl_state != HKLIST_IDLE) {
    469  1.9  yamaguch 		mutex_exit(&l->hl_lock);
    470  1.9  yamaguch 		return EBUSY;
    471  1.9  yamaguch 	}
    472  1.9  yamaguch 
    473  1.9  yamaguch 	/* stop removing hooks */
    474  1.9  yamaguch 	l->hl_state = HKLIST_INUSE;
    475  1.9  yamaguch 	l->hl_lwp = curlwp;
    476  1.9  yamaguch 
    477  1.9  yamaguch 	LIST_FOREACH(hd, &l->hl_list, hk_list) {
    478  1.9  yamaguch 		if (hd->hk_fn == NULL)
    479  1.9  yamaguch 			continue;
    480  1.9  yamaguch 
    481  1.9  yamaguch 		fn = hd->hk_fn;
    482  1.9  yamaguch 		arg = hd->hk_arg;
    483  1.9  yamaguch 		l->hl_active_hk = hd;
    484  1.9  yamaguch 		l->hl_cvlock = NULL;
    485  1.9  yamaguch 
    486  1.9  yamaguch 		mutex_exit(&l->hl_lock);
    487  1.9  yamaguch 
    488  1.9  yamaguch 		/* do callback without l->hl_lock */
    489  1.9  yamaguch 		(*fn)(arg);
    490  1.9  yamaguch 
    491  1.9  yamaguch 		mutex_enter(&l->hl_lock);
    492  1.9  yamaguch 		l->hl_active_hk = NULL;
    493  1.9  yamaguch 		cv_lock = l->hl_cvlock;
    494  1.9  yamaguch 
    495  1.9  yamaguch 		if (hd->hk_fn == NULL) {
    496  1.9  yamaguch 			if (cv_lock != NULL) {
    497  1.9  yamaguch 				mutex_exit(&l->hl_lock);
    498  1.9  yamaguch 				mutex_enter(cv_lock);
    499  1.9  yamaguch 			}
    500  1.9  yamaguch 
    501  1.9  yamaguch 			cv_broadcast(&l->hl_cv);
    502  1.9  yamaguch 
    503  1.9  yamaguch 			if (cv_lock != NULL) {
    504  1.9  yamaguch 				mutex_exit(cv_lock);
    505  1.9  yamaguch 				mutex_enter(&l->hl_lock);
    506  1.9  yamaguch 			}
    507  1.9  yamaguch 		}
    508  1.9  yamaguch 	}
    509  1.9  yamaguch 
    510  1.9  yamaguch 	/* remove marked node while running hooks */
    511  1.9  yamaguch 	LIST_FOREACH_SAFE(hd, &l->hl_list, hk_list, nexthd) {
    512  1.9  yamaguch 		if (hd->hk_fn == NULL) {
    513  1.9  yamaguch 			LIST_REMOVE(hd, hk_list);
    514  1.9  yamaguch 			kmem_free(hd, sizeof(*hd));
    515  1.9  yamaguch 		}
    516  1.9  yamaguch 	}
    517  1.9  yamaguch 
    518  1.9  yamaguch 	l->hl_lwp = NULL;
    519  1.9  yamaguch 	l->hl_state = HKLIST_IDLE;
    520  1.9  yamaguch 	mutex_exit(&l->hl_lock);
    521  1.9  yamaguch 
    522  1.9  yamaguch 	return 0;
    523  1.9  yamaguch }
    524  1.9  yamaguch 
    525  1.9  yamaguch khook_t *
    526  1.9  yamaguch simplehook_establish(khook_list_t *l,  void (*fn)(void *), void *arg)
    527  1.9  yamaguch {
    528  1.9  yamaguch 	struct hook_desc *hd;
    529  1.9  yamaguch 
    530  1.9  yamaguch 	hd = kmem_zalloc(sizeof(*hd), KM_SLEEP);
    531  1.9  yamaguch 	hd->hk_fn = fn;
    532  1.9  yamaguch 	hd->hk_arg = arg;
    533  1.9  yamaguch 
    534  1.9  yamaguch 	mutex_enter(&l->hl_lock);
    535  1.9  yamaguch 	LIST_INSERT_HEAD(&l->hl_list, hd, hk_list);
    536  1.9  yamaguch 	mutex_exit(&l->hl_lock);
    537  1.9  yamaguch 
    538  1.9  yamaguch 	return hd;
    539  1.9  yamaguch }
    540  1.9  yamaguch 
    541  1.9  yamaguch void
    542  1.9  yamaguch simplehook_disestablish(khook_list_t *l, khook_t *hd, kmutex_t *lock)
    543  1.9  yamaguch {
    544  1.9  yamaguch 	struct hook_desc *hd0 __diagused;
    545  1.9  yamaguch 	kmutex_t *cv_lock;
    546  1.9  yamaguch 
    547  1.9  yamaguch 	KASSERT(lock == NULL || mutex_owned(lock));
    548  1.9  yamaguch 	mutex_enter(&l->hl_lock);
    549  1.9  yamaguch 
    550  1.9  yamaguch #ifdef DIAGNOSTIC
    551  1.9  yamaguch 	LIST_FOREACH(hd0, &l->hl_list, hk_list) {
    552  1.9  yamaguch 		if (hd == hd0)
    553  1.9  yamaguch 			break;
    554  1.9  yamaguch 	}
    555  1.9  yamaguch 
    556  1.9  yamaguch 	if (hd0 == NULL)
    557  1.9  yamaguch 		panic("hook_disestablish: hook %p not established", hd);
    558  1.9  yamaguch #endif
    559  1.9  yamaguch 
    560  1.9  yamaguch 	/* The hook is not referred, remove immidiately */
    561  1.9  yamaguch 	if (l->hl_state == HKLIST_IDLE) {
    562  1.9  yamaguch 		LIST_REMOVE(hd, hk_list);
    563  1.9  yamaguch 		kmem_free(hd, sizeof(*hd));
    564  1.9  yamaguch 		mutex_exit(&l->hl_lock);
    565  1.9  yamaguch 		return;
    566  1.9  yamaguch 	}
    567  1.9  yamaguch 
    568  1.9  yamaguch 	/* remove callback. hd will be removed in dohooks */
    569  1.9  yamaguch 	hd->hk_fn = NULL;
    570  1.9  yamaguch 	hd->hk_arg = NULL;
    571  1.9  yamaguch 
    572  1.9  yamaguch 	/* If the hook is running, wait for the completion */
    573  1.9  yamaguch 	if (l->hl_active_hk == hd &&
    574  1.9  yamaguch 	    l->hl_lwp != curlwp) {
    575  1.9  yamaguch 		if (lock != NULL) {
    576  1.9  yamaguch 			cv_lock = lock;
    577  1.9  yamaguch 			KASSERT(l->hl_cvlock == NULL);
    578  1.9  yamaguch 			l->hl_cvlock = lock;
    579  1.9  yamaguch 			mutex_exit(&l->hl_lock);
    580  1.9  yamaguch 		} else {
    581  1.9  yamaguch 			cv_lock = &l->hl_lock;
    582  1.9  yamaguch 		}
    583  1.9  yamaguch 
    584  1.9  yamaguch 		cv_wait(&l->hl_cv, cv_lock);
    585  1.9  yamaguch 
    586  1.9  yamaguch 		if (lock == NULL)
    587  1.9  yamaguch 			mutex_exit(&l->hl_lock);
    588  1.9  yamaguch 	} else {
    589  1.9  yamaguch 		mutex_exit(&l->hl_lock);
    590  1.9  yamaguch 	}
    591  1.9  yamaguch }
    592  1.9  yamaguch 
    593  1.9  yamaguch bool
    594  1.9  yamaguch simplehook_has_hooks(khook_list_t *l)
    595  1.9  yamaguch {
    596  1.9  yamaguch 	bool empty;
    597  1.9  yamaguch 
    598  1.9  yamaguch 	mutex_enter(&l->hl_lock);
    599  1.9  yamaguch 	empty = LIST_EMPTY(&l->hl_list);
    600  1.9  yamaguch 	mutex_exit(&l->hl_lock);
    601  1.9  yamaguch 
    602  1.9  yamaguch 	return !empty;
    603  1.9  yamaguch }
    604