xref: /freebsd/sys/kern/kern_khelp.c (revision a8d61afdc24f4ba6964d85df11b8452f5151e70f)
1*a8d61afdSLawrence Stewart /*-
2*a8d61afdSLawrence Stewart  * Copyright (c) 2010 Lawrence Stewart <lstewart@freebsd.org>
3*a8d61afdSLawrence Stewart  * Copyright (c) 2010 The FreeBSD Foundation
4*a8d61afdSLawrence Stewart  * All rights reserved.
5*a8d61afdSLawrence Stewart  *
6*a8d61afdSLawrence Stewart  * This software was developed by Lawrence Stewart while studying at the Centre
7*a8d61afdSLawrence Stewart  * for Advanced Internet Architectures, Swinburne University, made possible in
8*a8d61afdSLawrence Stewart  * part by grants from the FreeBSD Foundation and Cisco University Research
9*a8d61afdSLawrence Stewart  * Program Fund at Community Foundation Silicon Valley.
10*a8d61afdSLawrence Stewart  *
11*a8d61afdSLawrence Stewart  * Portions of this software were developed at the Centre for Advanced
12*a8d61afdSLawrence Stewart  * Internet Architectures, Swinburne University of Technology, Melbourne,
13*a8d61afdSLawrence Stewart  * Australia by Lawrence Stewart under sponsorship from the FreeBSD Foundation.
14*a8d61afdSLawrence Stewart  *
15*a8d61afdSLawrence Stewart  * Redistribution and use in source and binary forms, with or without
16*a8d61afdSLawrence Stewart  * modification, are permitted provided that the following conditions
17*a8d61afdSLawrence Stewart  * are met:
18*a8d61afdSLawrence Stewart  * 1. Redistributions of source code must retain the above copyright
19*a8d61afdSLawrence Stewart  *    notice, this list of conditions and the following disclaimer.
20*a8d61afdSLawrence Stewart  * 2. Redistributions in binary form must reproduce the above copyright
21*a8d61afdSLawrence Stewart  *    notice, this list of conditions and the following disclaimer in the
22*a8d61afdSLawrence Stewart  *    documentation and/or other materials provided with the distribution.
23*a8d61afdSLawrence Stewart  *
24*a8d61afdSLawrence Stewart  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
25*a8d61afdSLawrence Stewart  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26*a8d61afdSLawrence Stewart  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27*a8d61afdSLawrence Stewart  * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
28*a8d61afdSLawrence Stewart  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
29*a8d61afdSLawrence Stewart  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
30*a8d61afdSLawrence Stewart  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
31*a8d61afdSLawrence Stewart  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32*a8d61afdSLawrence Stewart  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
33*a8d61afdSLawrence Stewart  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34*a8d61afdSLawrence Stewart  * SUCH DAMAGE.
35*a8d61afdSLawrence Stewart  */
36*a8d61afdSLawrence Stewart 
37*a8d61afdSLawrence Stewart #include <sys/cdefs.h>
38*a8d61afdSLawrence Stewart __FBSDID("$FreeBSD$");
39*a8d61afdSLawrence Stewart 
40*a8d61afdSLawrence Stewart #include <sys/param.h>
41*a8d61afdSLawrence Stewart #include <sys/kernel.h>
42*a8d61afdSLawrence Stewart #include <sys/hhook.h>
43*a8d61afdSLawrence Stewart #include <sys/jail.h>
44*a8d61afdSLawrence Stewart #include <sys/khelp.h>
45*a8d61afdSLawrence Stewart #include <sys/lock.h>
46*a8d61afdSLawrence Stewart #include <sys/malloc.h>
47*a8d61afdSLawrence Stewart #include <sys/module.h>
48*a8d61afdSLawrence Stewart #include <sys/module_khelp.h>
49*a8d61afdSLawrence Stewart #include <sys/osd.h>
50*a8d61afdSLawrence Stewart #include <sys/queue.h>
51*a8d61afdSLawrence Stewart #include <sys/refcount.h>
52*a8d61afdSLawrence Stewart #include <sys/rwlock.h>
53*a8d61afdSLawrence Stewart #include <sys/systm.h>
54*a8d61afdSLawrence Stewart 
55*a8d61afdSLawrence Stewart #include <net/vnet.h>
56*a8d61afdSLawrence Stewart 
57*a8d61afdSLawrence Stewart static struct rwlock khelp_list_lock;
58*a8d61afdSLawrence Stewart RW_SYSINIT(khelplistlock, &khelp_list_lock, "helper list lock");
59*a8d61afdSLawrence Stewart 
60*a8d61afdSLawrence Stewart static TAILQ_HEAD(helper_head, helper) helpers = TAILQ_HEAD_INITIALIZER(helpers);
61*a8d61afdSLawrence Stewart 
62*a8d61afdSLawrence Stewart /* Private function prototypes. */
63*a8d61afdSLawrence Stewart static inline void khelp_remove_osd(struct helper *h, struct osd *hosd);
64*a8d61afdSLawrence Stewart 
65*a8d61afdSLawrence Stewart #define	KHELP_LIST_WLOCK() rw_wlock(&khelp_list_lock)
66*a8d61afdSLawrence Stewart #define	KHELP_LIST_WUNLOCK() rw_wunlock(&khelp_list_lock)
67*a8d61afdSLawrence Stewart #define	KHELP_LIST_RLOCK() rw_rlock(&khelp_list_lock)
68*a8d61afdSLawrence Stewart #define	KHELP_LIST_RUNLOCK() rw_runlock(&khelp_list_lock)
69*a8d61afdSLawrence Stewart #define	KHELP_LIST_LOCK_ASSERT() rw_assert(&khelp_list_lock, RA_LOCKED)
70*a8d61afdSLawrence Stewart 
71*a8d61afdSLawrence Stewart int
72*a8d61afdSLawrence Stewart khelp_register_helper(struct helper *h)
73*a8d61afdSLawrence Stewart {
74*a8d61afdSLawrence Stewart 	struct helper *tmph;
75*a8d61afdSLawrence Stewart 	int error, i, inserted;
76*a8d61afdSLawrence Stewart 
77*a8d61afdSLawrence Stewart 	error = 0;
78*a8d61afdSLawrence Stewart 	inserted = 0;
79*a8d61afdSLawrence Stewart 	refcount_init(&h->h_refcount, 0);
80*a8d61afdSLawrence Stewart 	h->h_id = osd_register(OSD_KHELP, NULL, NULL);
81*a8d61afdSLawrence Stewart 
82*a8d61afdSLawrence Stewart 	/* It's only safe to add the hooks after osd_register(). */
83*a8d61afdSLawrence Stewart 	if (h->h_nhooks > 0) {
84*a8d61afdSLawrence Stewart 		for (i = 0; i < h->h_nhooks && !error; i++) {
85*a8d61afdSLawrence Stewart 			/* We don't require the module to assign hook_helper. */
86*a8d61afdSLawrence Stewart 			h->h_hooks[i].hook_helper = h;
87*a8d61afdSLawrence Stewart 			error = khelp_add_hhook(&h->h_hooks[i], HHOOK_NOWAIT);
88*a8d61afdSLawrence Stewart 		}
89*a8d61afdSLawrence Stewart 
90*a8d61afdSLawrence Stewart 		if (error) {
91*a8d61afdSLawrence Stewart 			for (i--; i >= 0; i--)
92*a8d61afdSLawrence Stewart 				khelp_remove_hhook(&h->h_hooks[i]);
93*a8d61afdSLawrence Stewart 
94*a8d61afdSLawrence Stewart 			osd_deregister(OSD_KHELP, h->h_id);
95*a8d61afdSLawrence Stewart 		}
96*a8d61afdSLawrence Stewart 	}
97*a8d61afdSLawrence Stewart 
98*a8d61afdSLawrence Stewart 	if (!error) {
99*a8d61afdSLawrence Stewart 		KHELP_LIST_WLOCK();
100*a8d61afdSLawrence Stewart 		/*
101*a8d61afdSLawrence Stewart 		 * Keep list of helpers sorted in descending h_id order. Due to
102*a8d61afdSLawrence Stewart 		 * the way osd_set() works, a sorted list ensures
103*a8d61afdSLawrence Stewart 		 * init_helper_osd() will operate with improved efficiency.
104*a8d61afdSLawrence Stewart 		 */
105*a8d61afdSLawrence Stewart 		TAILQ_FOREACH(tmph, &helpers, h_next) {
106*a8d61afdSLawrence Stewart 			if (tmph->h_id < h->h_id) {
107*a8d61afdSLawrence Stewart 				TAILQ_INSERT_BEFORE(tmph, h, h_next);
108*a8d61afdSLawrence Stewart 				inserted = 1;
109*a8d61afdSLawrence Stewart 				break;
110*a8d61afdSLawrence Stewart 			}
111*a8d61afdSLawrence Stewart 		}
112*a8d61afdSLawrence Stewart 
113*a8d61afdSLawrence Stewart 		if (!inserted)
114*a8d61afdSLawrence Stewart 			TAILQ_INSERT_TAIL(&helpers, h, h_next);
115*a8d61afdSLawrence Stewart 		KHELP_LIST_WUNLOCK();
116*a8d61afdSLawrence Stewart 	}
117*a8d61afdSLawrence Stewart 
118*a8d61afdSLawrence Stewart 	return (error);
119*a8d61afdSLawrence Stewart }
120*a8d61afdSLawrence Stewart 
121*a8d61afdSLawrence Stewart int
122*a8d61afdSLawrence Stewart khelp_deregister_helper(struct helper *h)
123*a8d61afdSLawrence Stewart {
124*a8d61afdSLawrence Stewart 	struct helper *tmph;
125*a8d61afdSLawrence Stewart 	int error, i;
126*a8d61afdSLawrence Stewart 
127*a8d61afdSLawrence Stewart 	error = 0;
128*a8d61afdSLawrence Stewart 
129*a8d61afdSLawrence Stewart 	KHELP_LIST_WLOCK();
130*a8d61afdSLawrence Stewart 	if (h->h_refcount > 0)
131*a8d61afdSLawrence Stewart 		error = EBUSY;
132*a8d61afdSLawrence Stewart 	else {
133*a8d61afdSLawrence Stewart 		error = ENOENT;
134*a8d61afdSLawrence Stewart 		TAILQ_FOREACH(tmph, &helpers, h_next) {
135*a8d61afdSLawrence Stewart 			if (tmph == h) {
136*a8d61afdSLawrence Stewart 				TAILQ_REMOVE(&helpers, h, h_next);
137*a8d61afdSLawrence Stewart 				error = 0;
138*a8d61afdSLawrence Stewart 				break;
139*a8d61afdSLawrence Stewart 			}
140*a8d61afdSLawrence Stewart 		}
141*a8d61afdSLawrence Stewart 	}
142*a8d61afdSLawrence Stewart 	KHELP_LIST_WUNLOCK();
143*a8d61afdSLawrence Stewart 
144*a8d61afdSLawrence Stewart 	if (!error) {
145*a8d61afdSLawrence Stewart 		if (h->h_nhooks > 0) {
146*a8d61afdSLawrence Stewart 			for (i = 0; i < h->h_nhooks; i++)
147*a8d61afdSLawrence Stewart 				khelp_remove_hhook(&h->h_hooks[i]);
148*a8d61afdSLawrence Stewart 		}
149*a8d61afdSLawrence Stewart 		osd_deregister(OSD_KHELP, h->h_id);
150*a8d61afdSLawrence Stewart 	}
151*a8d61afdSLawrence Stewart 
152*a8d61afdSLawrence Stewart 	return (error);
153*a8d61afdSLawrence Stewart }
154*a8d61afdSLawrence Stewart 
155*a8d61afdSLawrence Stewart int
156*a8d61afdSLawrence Stewart khelp_init_osd(uint32_t classes, struct osd *hosd)
157*a8d61afdSLawrence Stewart {
158*a8d61afdSLawrence Stewart 	struct helper *h;
159*a8d61afdSLawrence Stewart 	void *hdata;
160*a8d61afdSLawrence Stewart 	int error;
161*a8d61afdSLawrence Stewart 
162*a8d61afdSLawrence Stewart 	KASSERT(hosd != NULL, ("struct osd not initialised!"));
163*a8d61afdSLawrence Stewart 
164*a8d61afdSLawrence Stewart 	error = 0;
165*a8d61afdSLawrence Stewart 
166*a8d61afdSLawrence Stewart 	KHELP_LIST_RLOCK();
167*a8d61afdSLawrence Stewart 	TAILQ_FOREACH(h, &helpers, h_next) {
168*a8d61afdSLawrence Stewart 		/* If helper is correct class and needs to store OSD... */
169*a8d61afdSLawrence Stewart 		if (h->h_classes & classes && h->h_flags & HELPER_NEEDS_OSD) {
170*a8d61afdSLawrence Stewart 			hdata = uma_zalloc(h->h_zone, M_NOWAIT);
171*a8d61afdSLawrence Stewart 			if (hdata == NULL) {
172*a8d61afdSLawrence Stewart 				error = ENOMEM;
173*a8d61afdSLawrence Stewart 				break;
174*a8d61afdSLawrence Stewart 			}
175*a8d61afdSLawrence Stewart 			osd_set(OSD_KHELP, hosd, h->h_id, hdata);
176*a8d61afdSLawrence Stewart 			refcount_acquire(&h->h_refcount);
177*a8d61afdSLawrence Stewart 		}
178*a8d61afdSLawrence Stewart 	}
179*a8d61afdSLawrence Stewart 
180*a8d61afdSLawrence Stewart 	if (error) {
181*a8d61afdSLawrence Stewart 		/* Delete OSD that was assigned prior to the error. */
182*a8d61afdSLawrence Stewart 		TAILQ_FOREACH(h, &helpers, h_next) {
183*a8d61afdSLawrence Stewart 			if (h->h_classes & classes)
184*a8d61afdSLawrence Stewart 				khelp_remove_osd(h, hosd);
185*a8d61afdSLawrence Stewart 		}
186*a8d61afdSLawrence Stewart 	}
187*a8d61afdSLawrence Stewart 	KHELP_LIST_RUNLOCK();
188*a8d61afdSLawrence Stewart 
189*a8d61afdSLawrence Stewart 	return (error);
190*a8d61afdSLawrence Stewart }
191*a8d61afdSLawrence Stewart 
192*a8d61afdSLawrence Stewart int
193*a8d61afdSLawrence Stewart khelp_destroy_osd(struct osd *hosd)
194*a8d61afdSLawrence Stewart {
195*a8d61afdSLawrence Stewart 	struct helper *h;
196*a8d61afdSLawrence Stewart 	int error;
197*a8d61afdSLawrence Stewart 
198*a8d61afdSLawrence Stewart 	KASSERT(hosd != NULL, ("struct osd not initialised!"));
199*a8d61afdSLawrence Stewart 
200*a8d61afdSLawrence Stewart 	error = 0;
201*a8d61afdSLawrence Stewart 
202*a8d61afdSLawrence Stewart 	KHELP_LIST_RLOCK();
203*a8d61afdSLawrence Stewart 	/*
204*a8d61afdSLawrence Stewart 	 * Clean up all khelp related OSD.
205*a8d61afdSLawrence Stewart 	 *
206*a8d61afdSLawrence Stewart 	 * XXXLAS: Would be nice to use something like osd_exit() here but it
207*a8d61afdSLawrence Stewart 	 * doesn't have the right semantics for this purpose.
208*a8d61afdSLawrence Stewart 	 */
209*a8d61afdSLawrence Stewart 	TAILQ_FOREACH(h, &helpers, h_next)
210*a8d61afdSLawrence Stewart 		khelp_remove_osd(h, hosd);
211*a8d61afdSLawrence Stewart 	KHELP_LIST_RUNLOCK();
212*a8d61afdSLawrence Stewart 
213*a8d61afdSLawrence Stewart 	return (error);
214*a8d61afdSLawrence Stewart }
215*a8d61afdSLawrence Stewart 
216*a8d61afdSLawrence Stewart static inline void
217*a8d61afdSLawrence Stewart khelp_remove_osd(struct helper *h, struct osd *hosd)
218*a8d61afdSLawrence Stewart {
219*a8d61afdSLawrence Stewart 	void *hdata;
220*a8d61afdSLawrence Stewart 
221*a8d61afdSLawrence Stewart 	if (h->h_flags & HELPER_NEEDS_OSD) {
222*a8d61afdSLawrence Stewart 		/*
223*a8d61afdSLawrence Stewart 		 * If the current helper uses OSD and calling osd_get()
224*a8d61afdSLawrence Stewart 		 * on the helper's h_id returns non-NULL, the helper has
225*a8d61afdSLawrence Stewart 		 * OSD attached to 'hosd' which needs to be cleaned up.
226*a8d61afdSLawrence Stewart 		 */
227*a8d61afdSLawrence Stewart 		hdata = osd_get(OSD_KHELP, hosd, h->h_id);
228*a8d61afdSLawrence Stewart 		if (hdata != NULL) {
229*a8d61afdSLawrence Stewart 			uma_zfree(h->h_zone, hdata);
230*a8d61afdSLawrence Stewart 			osd_del(OSD_KHELP, hosd, h->h_id);
231*a8d61afdSLawrence Stewart 			refcount_release(&h->h_refcount);
232*a8d61afdSLawrence Stewart 		}
233*a8d61afdSLawrence Stewart 	}
234*a8d61afdSLawrence Stewart }
235*a8d61afdSLawrence Stewart 
236*a8d61afdSLawrence Stewart void *
237*a8d61afdSLawrence Stewart khelp_get_osd(struct osd *hosd, int32_t id)
238*a8d61afdSLawrence Stewart {
239*a8d61afdSLawrence Stewart 
240*a8d61afdSLawrence Stewart 	return (osd_get(OSD_KHELP, hosd, id));
241*a8d61afdSLawrence Stewart }
242*a8d61afdSLawrence Stewart 
243*a8d61afdSLawrence Stewart int32_t
244*a8d61afdSLawrence Stewart khelp_get_id(char *hname)
245*a8d61afdSLawrence Stewart {
246*a8d61afdSLawrence Stewart 	struct helper *h;
247*a8d61afdSLawrence Stewart 	int32_t id;
248*a8d61afdSLawrence Stewart 
249*a8d61afdSLawrence Stewart 	id = -1;
250*a8d61afdSLawrence Stewart 
251*a8d61afdSLawrence Stewart 	KHELP_LIST_RLOCK();
252*a8d61afdSLawrence Stewart 	TAILQ_FOREACH(h, &helpers, h_next) {
253*a8d61afdSLawrence Stewart 		if (strncmp(h->h_name, hname, HELPER_NAME_MAXLEN) == 0) {
254*a8d61afdSLawrence Stewart 			id = h->h_id;
255*a8d61afdSLawrence Stewart 			break;
256*a8d61afdSLawrence Stewart 		}
257*a8d61afdSLawrence Stewart 	}
258*a8d61afdSLawrence Stewart 	KHELP_LIST_RUNLOCK();
259*a8d61afdSLawrence Stewart 
260*a8d61afdSLawrence Stewart 	return (id);
261*a8d61afdSLawrence Stewart }
262*a8d61afdSLawrence Stewart 
263*a8d61afdSLawrence Stewart int
264*a8d61afdSLawrence Stewart khelp_add_hhook(struct hookinfo *hki, uint32_t flags)
265*a8d61afdSLawrence Stewart {
266*a8d61afdSLawrence Stewart 	VNET_ITERATOR_DECL(vnet_iter);
267*a8d61afdSLawrence Stewart 	int error;
268*a8d61afdSLawrence Stewart 
269*a8d61afdSLawrence Stewart 	error = 0;
270*a8d61afdSLawrence Stewart 
271*a8d61afdSLawrence Stewart 	/*
272*a8d61afdSLawrence Stewart 	 * XXXLAS: If a helper is dynamically adding a helper hook function at
273*a8d61afdSLawrence Stewart 	 * runtime using this function, we should update the helper's h_hooks
274*a8d61afdSLawrence Stewart 	 * struct member to include the additional hookinfo struct.
275*a8d61afdSLawrence Stewart 	 */
276*a8d61afdSLawrence Stewart 
277*a8d61afdSLawrence Stewart 	VNET_LIST_RLOCK_NOSLEEP();
278*a8d61afdSLawrence Stewart 	VNET_FOREACH(vnet_iter) {
279*a8d61afdSLawrence Stewart 		CURVNET_SET(vnet_iter);
280*a8d61afdSLawrence Stewart 		error = hhook_add_hook_lookup(hki, flags);
281*a8d61afdSLawrence Stewart 		CURVNET_RESTORE();
282*a8d61afdSLawrence Stewart #ifdef VIMAGE
283*a8d61afdSLawrence Stewart 		if (error)
284*a8d61afdSLawrence Stewart 			break;
285*a8d61afdSLawrence Stewart #endif
286*a8d61afdSLawrence Stewart 	}
287*a8d61afdSLawrence Stewart 	VNET_LIST_RUNLOCK_NOSLEEP();
288*a8d61afdSLawrence Stewart 
289*a8d61afdSLawrence Stewart 	return (error);
290*a8d61afdSLawrence Stewart }
291*a8d61afdSLawrence Stewart 
292*a8d61afdSLawrence Stewart int
293*a8d61afdSLawrence Stewart khelp_remove_hhook(struct hookinfo *hki)
294*a8d61afdSLawrence Stewart {
295*a8d61afdSLawrence Stewart 	VNET_ITERATOR_DECL(vnet_iter);
296*a8d61afdSLawrence Stewart 	int error;
297*a8d61afdSLawrence Stewart 
298*a8d61afdSLawrence Stewart 	error = 0;
299*a8d61afdSLawrence Stewart 
300*a8d61afdSLawrence Stewart 	/*
301*a8d61afdSLawrence Stewart 	 * XXXLAS: If a helper is dynamically removing a helper hook function at
302*a8d61afdSLawrence Stewart 	 * runtime using this function, we should update the helper's h_hooks
303*a8d61afdSLawrence Stewart 	 * struct member to remove the defunct hookinfo struct.
304*a8d61afdSLawrence Stewart 	 */
305*a8d61afdSLawrence Stewart 
306*a8d61afdSLawrence Stewart 	VNET_LIST_RLOCK_NOSLEEP();
307*a8d61afdSLawrence Stewart 	VNET_FOREACH(vnet_iter) {
308*a8d61afdSLawrence Stewart 		CURVNET_SET(vnet_iter);
309*a8d61afdSLawrence Stewart 		error = hhook_remove_hook_lookup(hki);
310*a8d61afdSLawrence Stewart 		CURVNET_RESTORE();
311*a8d61afdSLawrence Stewart #ifdef VIMAGE
312*a8d61afdSLawrence Stewart 		if (error)
313*a8d61afdSLawrence Stewart 			break;
314*a8d61afdSLawrence Stewart #endif
315*a8d61afdSLawrence Stewart 	}
316*a8d61afdSLawrence Stewart 	VNET_LIST_RUNLOCK_NOSLEEP();
317*a8d61afdSLawrence Stewart 
318*a8d61afdSLawrence Stewart 	return (error);
319*a8d61afdSLawrence Stewart }
320*a8d61afdSLawrence Stewart 
321*a8d61afdSLawrence Stewart int
322*a8d61afdSLawrence Stewart khelp_modevent(module_t mod, int event_type, void *data)
323*a8d61afdSLawrence Stewart {
324*a8d61afdSLawrence Stewart 	struct khelp_modevent_data *kmd;
325*a8d61afdSLawrence Stewart 	int error;
326*a8d61afdSLawrence Stewart 
327*a8d61afdSLawrence Stewart 	kmd = (struct khelp_modevent_data *)data;
328*a8d61afdSLawrence Stewart 	error = 0;
329*a8d61afdSLawrence Stewart 
330*a8d61afdSLawrence Stewart 	switch(event_type) {
331*a8d61afdSLawrence Stewart 	case MOD_LOAD:
332*a8d61afdSLawrence Stewart 		if (kmd->helper->h_flags & HELPER_NEEDS_OSD) {
333*a8d61afdSLawrence Stewart 			if (kmd->uma_zsize <= 0) {
334*a8d61afdSLawrence Stewart 				printf("Use KHELP_DECLARE_MOD_UMA() instead!\n");
335*a8d61afdSLawrence Stewart 				error = EDOOFUS;
336*a8d61afdSLawrence Stewart 				break;
337*a8d61afdSLawrence Stewart 			}
338*a8d61afdSLawrence Stewart 			kmd->helper->h_zone = uma_zcreate(kmd->name,
339*a8d61afdSLawrence Stewart 			    kmd->uma_zsize, kmd->umactor, kmd->umadtor, NULL,
340*a8d61afdSLawrence Stewart 			    NULL, 0, 0);
341*a8d61afdSLawrence Stewart 			if (kmd->helper->h_zone == NULL) {
342*a8d61afdSLawrence Stewart 				error = ENOMEM;
343*a8d61afdSLawrence Stewart 				break;
344*a8d61afdSLawrence Stewart 			}
345*a8d61afdSLawrence Stewart 		}
346*a8d61afdSLawrence Stewart 		strlcpy(kmd->helper->h_name, kmd->name, HELPER_NAME_MAXLEN);
347*a8d61afdSLawrence Stewart 		kmd->helper->h_hooks = kmd->hooks;
348*a8d61afdSLawrence Stewart 		kmd->helper->h_nhooks = kmd->nhooks;
349*a8d61afdSLawrence Stewart 		if (kmd->helper->mod_init != NULL)
350*a8d61afdSLawrence Stewart 			error = kmd->helper->mod_init();
351*a8d61afdSLawrence Stewart 		if (!error)
352*a8d61afdSLawrence Stewart 			error = khelp_register_helper(kmd->helper);
353*a8d61afdSLawrence Stewart 		break;
354*a8d61afdSLawrence Stewart 
355*a8d61afdSLawrence Stewart 	case MOD_QUIESCE:
356*a8d61afdSLawrence Stewart 	case MOD_SHUTDOWN:
357*a8d61afdSLawrence Stewart 	case MOD_UNLOAD:
358*a8d61afdSLawrence Stewart 		error = khelp_deregister_helper(kmd->helper);
359*a8d61afdSLawrence Stewart 		if (!error) {
360*a8d61afdSLawrence Stewart 			if (kmd->helper->h_flags & HELPER_NEEDS_OSD)
361*a8d61afdSLawrence Stewart 				uma_zdestroy(kmd->helper->h_zone);
362*a8d61afdSLawrence Stewart 			if (kmd->helper->mod_destroy != NULL)
363*a8d61afdSLawrence Stewart 				kmd->helper->mod_destroy();
364*a8d61afdSLawrence Stewart 		} else if (error == ENOENT)
365*a8d61afdSLawrence Stewart 			/* Do nothing and allow unload if helper not in list. */
366*a8d61afdSLawrence Stewart 			error = 0;
367*a8d61afdSLawrence Stewart 		else if (error == EBUSY)
368*a8d61afdSLawrence Stewart 			printf("Khelp module \"%s\" can't unload until its "
369*a8d61afdSLawrence Stewart 			    "refcount drops from %d to 0.\n", kmd->name,
370*a8d61afdSLawrence Stewart 			    kmd->helper->h_refcount);
371*a8d61afdSLawrence Stewart 		break;
372*a8d61afdSLawrence Stewart 
373*a8d61afdSLawrence Stewart 	default:
374*a8d61afdSLawrence Stewart 		error = EINVAL;
375*a8d61afdSLawrence Stewart 		break;
376*a8d61afdSLawrence Stewart 	}
377*a8d61afdSLawrence Stewart 
378*a8d61afdSLawrence Stewart 	return (error);
379*a8d61afdSLawrence Stewart }
380*a8d61afdSLawrence Stewart 
381*a8d61afdSLawrence Stewart /*
382*a8d61afdSLawrence Stewart  * This function is called in two separate situations:
383*a8d61afdSLawrence Stewart  *
384*a8d61afdSLawrence Stewart  * - When the kernel is booting, it is called directly by the SYSINIT framework
385*a8d61afdSLawrence Stewart  * to allow Khelp modules which were compiled into the kernel or loaded by the
386*a8d61afdSLawrence Stewart  * boot loader to insert their non-virtualised hook functions into the kernel.
387*a8d61afdSLawrence Stewart  *
388*a8d61afdSLawrence Stewart  * - When the kernel is booting or a vnet is created, this function is also
389*a8d61afdSLawrence Stewart  * called indirectly through khelp_vnet_init() by the vnet initialisation code.
390*a8d61afdSLawrence Stewart  * In this situation, Khelp modules are able to insert their virtualised hook
391*a8d61afdSLawrence Stewart  * functions into the virtualised hook points in the vnet which is being
392*a8d61afdSLawrence Stewart  * initialised. In the case where the kernel is not compiled with "options
393*a8d61afdSLawrence Stewart  * VIMAGE", this step is still run once at boot, but the hook functions get
394*a8d61afdSLawrence Stewart  * transparently inserted into the standard unvirtualised network stack.
395*a8d61afdSLawrence Stewart  */
396*a8d61afdSLawrence Stewart static void
397*a8d61afdSLawrence Stewart khelp_init(const void *vnet)
398*a8d61afdSLawrence Stewart {
399*a8d61afdSLawrence Stewart 	struct helper *h;
400*a8d61afdSLawrence Stewart 	int error, i, vinit;
401*a8d61afdSLawrence Stewart 	int32_t htype, hid;
402*a8d61afdSLawrence Stewart 
403*a8d61afdSLawrence Stewart 	error = 0;
404*a8d61afdSLawrence Stewart 	vinit = vnet != NULL;
405*a8d61afdSLawrence Stewart 
406*a8d61afdSLawrence Stewart 	KHELP_LIST_RLOCK();
407*a8d61afdSLawrence Stewart 	TAILQ_FOREACH(h, &helpers, h_next) {
408*a8d61afdSLawrence Stewart 		for (i = 0; i < h->h_nhooks && !error; i++) {
409*a8d61afdSLawrence Stewart 			htype = h->h_hooks[i].hook_type;
410*a8d61afdSLawrence Stewart 			hid = h->h_hooks[i].hook_id;
411*a8d61afdSLawrence Stewart 
412*a8d61afdSLawrence Stewart 			/*
413*a8d61afdSLawrence Stewart 			 * If we're doing a virtualised init (vinit != 0) and
414*a8d61afdSLawrence Stewart 			 * the hook point is virtualised, or we're doing a plain
415*a8d61afdSLawrence Stewart 			 * sysinit at boot and the hook point is not
416*a8d61afdSLawrence Stewart 			 * virtualised, insert the hook.
417*a8d61afdSLawrence Stewart 			 */
418*a8d61afdSLawrence Stewart 			if ((hhook_head_is_virtualised_lookup(htype, hid) ==
419*a8d61afdSLawrence Stewart 			    HHOOK_HEADISINVNET && vinit) ||
420*a8d61afdSLawrence Stewart 			    (!hhook_head_is_virtualised_lookup(htype, hid) &&
421*a8d61afdSLawrence Stewart 			    !vinit)) {
422*a8d61afdSLawrence Stewart 				error = hhook_add_hook_lookup(&h->h_hooks[i],
423*a8d61afdSLawrence Stewart 				    HHOOK_NOWAIT);
424*a8d61afdSLawrence Stewart 			}
425*a8d61afdSLawrence Stewart 		}
426*a8d61afdSLawrence Stewart 
427*a8d61afdSLawrence Stewart 		if (error) {
428*a8d61afdSLawrence Stewart 			 /* Remove any helper's hooks we successfully added. */
429*a8d61afdSLawrence Stewart 			for (i--; i >= 0; i--)
430*a8d61afdSLawrence Stewart 				hhook_remove_hook_lookup(&h->h_hooks[i]);
431*a8d61afdSLawrence Stewart 
432*a8d61afdSLawrence Stewart 			printf("%s: Failed to add hooks for helper \"%s\" (%p)",
433*a8d61afdSLawrence Stewart 				__func__, h->h_name, h);
434*a8d61afdSLawrence Stewart 			if (vinit)
435*a8d61afdSLawrence Stewart 				    printf(" to vnet %p.\n", vnet);
436*a8d61afdSLawrence Stewart 			else
437*a8d61afdSLawrence Stewart 				printf(".\n");
438*a8d61afdSLawrence Stewart 
439*a8d61afdSLawrence Stewart 			error = 0;
440*a8d61afdSLawrence Stewart 		}
441*a8d61afdSLawrence Stewart 	}
442*a8d61afdSLawrence Stewart 	KHELP_LIST_RUNLOCK();
443*a8d61afdSLawrence Stewart }
444*a8d61afdSLawrence Stewart 
445*a8d61afdSLawrence Stewart /*
446*a8d61afdSLawrence Stewart  * Vnet created and being initialised.
447*a8d61afdSLawrence Stewart  */
448*a8d61afdSLawrence Stewart static void
449*a8d61afdSLawrence Stewart khelp_vnet_init(const void *unused __unused)
450*a8d61afdSLawrence Stewart {
451*a8d61afdSLawrence Stewart 
452*a8d61afdSLawrence Stewart 	khelp_init(TD_TO_VNET(curthread));
453*a8d61afdSLawrence Stewart }
454*a8d61afdSLawrence Stewart 
455*a8d61afdSLawrence Stewart 
456*a8d61afdSLawrence Stewart /*
457*a8d61afdSLawrence Stewart  * As the kernel boots, allow Khelp modules which were compiled into the kernel
458*a8d61afdSLawrence Stewart  * or loaded by the boot loader to insert their non-virtualised hook functions
459*a8d61afdSLawrence Stewart  * into the kernel.
460*a8d61afdSLawrence Stewart  */
461*a8d61afdSLawrence Stewart SYSINIT(khelp_init, SI_SUB_PROTO_END, SI_ORDER_FIRST, khelp_init, NULL);
462*a8d61afdSLawrence Stewart 
463*a8d61afdSLawrence Stewart /*
464*a8d61afdSLawrence Stewart  * When a vnet is created and being initialised, we need to insert the helper
465*a8d61afdSLawrence Stewart  * hook functions for all currently registered Khelp modules into the vnet's
466*a8d61afdSLawrence Stewart  * helper hook points.  The hhook KPI provides a mechanism for subsystems which
467*a8d61afdSLawrence Stewart  * export helper hook points to clean up on vnet shutdown, so we don't need a
468*a8d61afdSLawrence Stewart  * VNET_SYSUNINIT for Khelp.
469*a8d61afdSLawrence Stewart  */
470*a8d61afdSLawrence Stewart VNET_SYSINIT(khelp_vnet_init, SI_SUB_PROTO_END, SI_ORDER_FIRST,
471*a8d61afdSLawrence Stewart     khelp_vnet_init, NULL);
472