Deleted Added
full compact
kern_hhook.c (251732) kern_hhook.c (251752)
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);