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
hhook_run_hooks(struct hhook_head * hhh,void * ctx_data,struct osd * hosd)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
hhook_add_hook(struct hhook_head * hhh,const struct hookinfo * hki,uint32_t flags)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
hhook_add_hook_lookup(const struct hookinfo * hki,uint32_t flags)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
hhook_remove_hook(struct hhook_head * hhh,const struct hookinfo * hki)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
hhook_remove_hook_lookup(const struct hookinfo * hki)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
hhook_head_register(int32_t hhook_type,int32_t hhook_id,struct hhook_head ** hhh,uint32_t flags)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
hhook_head_destroy(struct hhook_head * hhh)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
hhook_head_deregister(struct hhook_head * hhh)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
hhook_head_deregister_lookup(int32_t hhook_type,int32_t hhook_id)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 *
hhook_head_get(int32_t hhook_type,int32_t hhook_id)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
hhook_head_release(struct hhook_head * hhh)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
hhook_head_is_virtualised(struct hhook_head * hhh)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
hhook_head_is_virtualised_lookup(int32_t hook_type,int32_t hook_id)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
hhook_vnet_init(const void * unused __unused)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
hhook_vnet_uninit(const void * unused __unused)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