1185029Spjd/*-
2185029Spjd * Copyright (c) 2007 Pawel Jakub Dawidek <pjd@FreeBSD.org>
3185029Spjd * All rights reserved.
4185029Spjd *
5185029Spjd * Redistribution and use in source and binary forms, with or without
6185029Spjd * modification, are permitted provided that the following conditions
7185029Spjd * are met:
8185029Spjd * 1. Redistributions of source code must retain the above copyright
9185029Spjd *    notice, this list of conditions and the following disclaimer.
10185029Spjd * 2. Redistributions in binary form must reproduce the above copyright
11185029Spjd *    notice, this list of conditions and the following disclaimer in the
12185029Spjd *    documentation and/or other materials provided with the distribution.
13185029Spjd *
14185029Spjd * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
15185029Spjd * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16185029Spjd * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17185029Spjd * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
18185029Spjd * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19185029Spjd * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20185029Spjd * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21185029Spjd * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22185029Spjd * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23185029Spjd * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24185029Spjd * SUCH DAMAGE.
25185029Spjd */
26185029Spjd
27185029Spjd#include <sys/cdefs.h>
28185029Spjd__FBSDID("$FreeBSD$");
29185029Spjd
30185029Spjd#include <sys/param.h>
31185029Spjd#include <sys/kernel.h>
32185029Spjd#include <sys/systm.h>
33185029Spjd#include <sys/sysctl.h>
34185029Spjd#include <sys/errno.h>
35191806Sjamie#include <sys/jail.h>
36185029Spjd#include <sys/malloc.h>
37185029Spjd#include <sys/lock.h>
38185029Spjd#include <sys/mutex.h>
39188894Sjamie#include <sys/rmlock.h>
40188894Sjamie#include <sys/sx.h>
41185029Spjd#include <sys/queue.h>
42185029Spjd#include <sys/proc.h>
43185029Spjd#include <sys/osd.h>
44185029Spjd
45185029Spjd/* OSD (Object Specific Data) */
46185029Spjd
47298834Sjamie/*
48298834Sjamie * Lock key:
49298834Sjamie *  (m) osd_module_lock
50298834Sjamie *  (o) osd_object_lock
51298834Sjamie *  (l) osd_list_lock
52298834Sjamie */
53298834Sjamiestruct osd_master {
54298834Sjamie	struct sx		 osd_module_lock;
55298834Sjamie	struct rmlock		 osd_object_lock;
56298834Sjamie	struct mtx		 osd_list_lock;
57298834Sjamie	LIST_HEAD(, osd)	 osd_list;		/* (l) */
58298834Sjamie	osd_destructor_t	*osd_destructors;	/* (o) */
59298834Sjamie	osd_method_t		*osd_methods;		/* (m) */
60298834Sjamie	u_int			 osd_ntslots;		/* (m) */
61298834Sjamie	const u_int		 osd_nmethods;
62298834Sjamie};
63298834Sjamie
64185029Spjdstatic MALLOC_DEFINE(M_OSD, "osd", "Object Specific Data");
65185029Spjd
66185029Spjdstatic int osd_debug = 0;
67185029SpjdTUNABLE_INT("debug.osd", &osd_debug);
68185029SpjdSYSCTL_INT(_debug, OID_AUTO, osd, CTLFLAG_RW, &osd_debug, 0, "OSD debug level");
69185029Spjd
70185029Spjd#define	OSD_DEBUG(...)	do {						\
71185029Spjd	if (osd_debug) {						\
72185029Spjd		printf("OSD (%s:%u): ", __func__, __LINE__);		\
73185029Spjd		printf(__VA_ARGS__);					\
74185029Spjd		printf("\n");						\
75185029Spjd	}								\
76185029Spjd} while (0)
77185029Spjd
78188894Sjamiestatic void do_osd_del(u_int type, struct osd *osd, u_int slot,
79188894Sjamie    int list_locked);
80188894Sjamie
81185029Spjd/*
82298834Sjamie * List of objects with OSD.
83185029Spjd */
84298834Sjamiestruct osd_master osdm[OSD_LAST + 1] = {
85298834Sjamie	[OSD_JAIL] = { .osd_nmethods = PR_MAXMETHOD },
86191673Sjamie};
87185029Spjd
88185029Spjdstatic void
89185029Spjdosd_default_destructor(void *value __unused)
90185029Spjd{
91185029Spjd	/* Do nothing. */
92185029Spjd}
93185029Spjd
94185029Spjdint
95188894Sjamieosd_register(u_int type, osd_destructor_t destructor, osd_method_t *methods)
96185029Spjd{
97185029Spjd	void *newptr;
98188894Sjamie	u_int i, m;
99185029Spjd
100185029Spjd	KASSERT(type >= OSD_FIRST && type <= OSD_LAST, ("Invalid type."));
101185029Spjd
102185029Spjd	/*
103185029Spjd	 * If no destructor is given, use default one. We need to use some
104185029Spjd	 * destructor, because NULL destructor means unused slot.
105185029Spjd	 */
106185029Spjd	if (destructor == NULL)
107185029Spjd		destructor = osd_default_destructor;
108185029Spjd
109298834Sjamie	sx_xlock(&osdm[type].osd_module_lock);
110185029Spjd	/*
111185029Spjd	 * First, we try to find unused slot.
112185029Spjd	 */
113298834Sjamie	for (i = 0; i < osdm[type].osd_ntslots; i++) {
114298834Sjamie		if (osdm[type].osd_destructors[i] == NULL) {
115185029Spjd			OSD_DEBUG("Unused slot found (type=%u, slot=%u).",
116185029Spjd			    type, i);
117185029Spjd			break;
118185029Spjd		}
119185029Spjd	}
120185029Spjd	/*
121185029Spjd	 * If no unused slot was found, allocate one.
122185029Spjd	 */
123298834Sjamie	if (i == osdm[type].osd_ntslots) {
124298834Sjamie		osdm[type].osd_ntslots++;
125298834Sjamie		if (osdm[type].osd_nmethods != 0)
126298834Sjamie			osdm[type].osd_methods = realloc(osdm[type].osd_methods,
127298834Sjamie			    sizeof(osd_method_t) * osdm[type].osd_ntslots *
128298834Sjamie			    osdm[type].osd_nmethods, M_OSD, M_WAITOK);
129298834Sjamie		newptr = malloc(sizeof(osd_destructor_t) *
130298834Sjamie		    osdm[type].osd_ntslots, M_OSD, M_WAITOK);
131298834Sjamie		rm_wlock(&osdm[type].osd_object_lock);
132298834Sjamie		bcopy(osdm[type].osd_destructors, newptr,
133188894Sjamie		    sizeof(osd_destructor_t) * i);
134298834Sjamie		free(osdm[type].osd_destructors, M_OSD);
135298834Sjamie		osdm[type].osd_destructors = newptr;
136298834Sjamie		rm_wunlock(&osdm[type].osd_object_lock);
137185029Spjd		OSD_DEBUG("New slot allocated (type=%u, slot=%u).",
138185029Spjd		    type, i + 1);
139185029Spjd	}
140188894Sjamie
141298834Sjamie	osdm[type].osd_destructors[i] = destructor;
142298834Sjamie	if (osdm[type].osd_nmethods != 0) {
143298834Sjamie		for (m = 0; m < osdm[type].osd_nmethods; m++)
144298834Sjamie			osdm[type].osd_methods[i * osdm[type].osd_nmethods + m]
145298834Sjamie			    = methods != NULL ? methods[m] : NULL;
146188894Sjamie	}
147298834Sjamie	sx_xunlock(&osdm[type].osd_module_lock);
148185029Spjd	return (i + 1);
149185029Spjd}
150185029Spjd
151185029Spjdvoid
152185029Spjdosd_deregister(u_int type, u_int slot)
153185029Spjd{
154185029Spjd	struct osd *osd, *tosd;
155185029Spjd
156185029Spjd	KASSERT(type >= OSD_FIRST && type <= OSD_LAST, ("Invalid type."));
157185029Spjd	KASSERT(slot > 0, ("Invalid slot."));
158298834Sjamie	KASSERT(osdm[type].osd_destructors[slot - 1] != NULL, ("Unused slot."));
159185029Spjd
160298834Sjamie	sx_xlock(&osdm[type].osd_module_lock);
161298834Sjamie	rm_wlock(&osdm[type].osd_object_lock);
162185029Spjd	/*
163185029Spjd	 * Free all OSD for the given slot.
164185029Spjd	 */
165298834Sjamie	mtx_lock(&osdm[type].osd_list_lock);
166298834Sjamie	LIST_FOREACH_SAFE(osd, &osdm[type].osd_list, osd_next, tosd)
167188894Sjamie		do_osd_del(type, osd, slot, 1);
168298834Sjamie	mtx_unlock(&osdm[type].osd_list_lock);
169185029Spjd	/*
170185029Spjd	 * Set destructor to NULL to free the slot.
171185029Spjd	 */
172298834Sjamie	osdm[type].osd_destructors[slot - 1] = NULL;
173298834Sjamie	if (slot == osdm[type].osd_ntslots) {
174298834Sjamie		osdm[type].osd_ntslots--;
175298834Sjamie		osdm[type].osd_destructors = realloc(osdm[type].osd_destructors,
176298834Sjamie		    sizeof(osd_destructor_t) * osdm[type].osd_ntslots, M_OSD,
177185029Spjd		    M_NOWAIT | M_ZERO);
178298834Sjamie		if (osdm[type].osd_nmethods != 0)
179298834Sjamie			osdm[type].osd_methods = realloc(osdm[type].osd_methods,
180298834Sjamie			    sizeof(osd_method_t) * osdm[type].osd_ntslots *
181298834Sjamie			    osdm[type].osd_nmethods, M_OSD, M_NOWAIT | M_ZERO);
182185029Spjd		/*
183185029Spjd		 * We always reallocate to smaller size, so we assume it will
184185029Spjd		 * always succeed.
185185029Spjd		 */
186298834Sjamie		KASSERT(osdm[type].osd_destructors != NULL &&
187298834Sjamie		    (osdm[type].osd_nmethods == 0 ||
188298834Sjamie		     osdm[type].osd_methods != NULL), ("realloc() failed"));
189185029Spjd		OSD_DEBUG("Deregistration of the last slot (type=%u, slot=%u).",
190185029Spjd		    type, slot);
191185029Spjd	} else {
192185029Spjd		OSD_DEBUG("Slot deregistration (type=%u, slot=%u).",
193185029Spjd		    type, slot);
194185029Spjd	}
195298834Sjamie	rm_wunlock(&osdm[type].osd_object_lock);
196298834Sjamie	sx_xunlock(&osdm[type].osd_module_lock);
197185029Spjd}
198185029Spjd
199185029Spjdint
200185029Spjdosd_set(u_int type, struct osd *osd, u_int slot, void *value)
201185029Spjd{
202298834Sjamie
203298834Sjamie	return (osd_set_reserved(type, osd, slot, NULL, value));
204298834Sjamie}
205298834Sjamie
206298834Sjamievoid *
207298834Sjamieosd_reserve(u_int slot)
208298834Sjamie{
209298834Sjamie
210298834Sjamie	KASSERT(slot > 0, ("Invalid slot."));
211298834Sjamie
212298834Sjamie	OSD_DEBUG("Reserving slot array (slot=%u).", slot);
213298834Sjamie	return (malloc(sizeof(void *) * slot, M_OSD, M_WAITOK | M_ZERO));
214298834Sjamie}
215298834Sjamie
216298834Sjamieint
217298834Sjamieosd_set_reserved(u_int type, struct osd *osd, u_int slot, void *rsv,
218298834Sjamie    void *value)
219298834Sjamie{
220188894Sjamie	struct rm_priotracker tracker;
221185029Spjd
222185029Spjd	KASSERT(type >= OSD_FIRST && type <= OSD_LAST, ("Invalid type."));
223185029Spjd	KASSERT(slot > 0, ("Invalid slot."));
224298834Sjamie	KASSERT(osdm[type].osd_destructors[slot - 1] != NULL, ("Unused slot."));
225185029Spjd
226298834Sjamie	rm_rlock(&osdm[type].osd_object_lock, &tracker);
227188894Sjamie	if (slot > osd->osd_nslots) {
228298834Sjamie		void *newptr;
229298834Sjamie
230188894Sjamie		if (value == NULL) {
231188894Sjamie			OSD_DEBUG(
232188894Sjamie			    "Not allocating null slot (type=%u, slot=%u).",
233188894Sjamie			    type, slot);
234298834Sjamie			rm_runlock(&osdm[type].osd_object_lock, &tracker);
235298834Sjamie			if (rsv)
236298834Sjamie				osd_free_reserved(rsv);
237188894Sjamie			return (0);
238298834Sjamie		}
239298834Sjamie
240298834Sjamie		/*
241298834Sjamie		 * Too few slots allocated here, so we need to extend or create
242298834Sjamie		 * the array.
243298834Sjamie		 */
244298834Sjamie		if (rsv) {
245188894Sjamie			/*
246298834Sjamie			 * Use the reserve passed in (assumed to be
247298834Sjamie			 * the right size).
248188894Sjamie			 */
249298834Sjamie			newptr = rsv;
250298834Sjamie			if (osd->osd_nslots != 0) {
251298834Sjamie				memcpy(newptr, osd->osd_slots,
252298834Sjamie				    sizeof(void *) * osd->osd_nslots);
253298834Sjamie				free(osd->osd_slots, M_OSD);
254188894Sjamie			}
255188894Sjamie		} else {
256188894Sjamie			newptr = realloc(osd->osd_slots, sizeof(void *) * slot,
257188894Sjamie			    M_OSD, M_NOWAIT | M_ZERO);
258188894Sjamie			if (newptr == NULL) {
259298834Sjamie				rm_runlock(&osdm[type].osd_object_lock,
260298834Sjamie				    &tracker);
261188894Sjamie				return (ENOMEM);
262188894Sjamie			}
263298834Sjamie		}
264298834Sjamie		if (osd->osd_nslots == 0) {
265298834Sjamie			/*
266298834Sjamie			 * First OSD for this object, so we need to put it
267298834Sjamie			 * onto the list.
268298834Sjamie			 */
269298834Sjamie			mtx_lock(&osdm[type].osd_list_lock);
270298834Sjamie			LIST_INSERT_HEAD(&osdm[type].osd_list, osd, osd_next);
271298834Sjamie			mtx_unlock(&osdm[type].osd_list_lock);
272298834Sjamie			OSD_DEBUG("Setting first slot (type=%u).", type);
273298834Sjamie		} else
274188894Sjamie			OSD_DEBUG("Growing slots array (type=%u).", type);
275298834Sjamie		osd->osd_slots = newptr;
276298834Sjamie		osd->osd_nslots = slot;
277298834Sjamie	} else if (rsv)
278298834Sjamie		osd_free_reserved(rsv);
279185029Spjd	OSD_DEBUG("Setting slot value (type=%u, slot=%u, value=%p).", type,
280185029Spjd	    slot, value);
281185029Spjd	osd->osd_slots[slot - 1] = value;
282298834Sjamie	rm_runlock(&osdm[type].osd_object_lock, &tracker);
283185029Spjd	return (0);
284185029Spjd}
285185029Spjd
286298834Sjamievoid
287298834Sjamieosd_free_reserved(void *rsv)
288298834Sjamie{
289298834Sjamie
290298834Sjamie	OSD_DEBUG("Discarding reserved slot array.");
291298834Sjamie	free(rsv, M_OSD);
292298834Sjamie}
293298834Sjamie
294185029Spjdvoid *
295185029Spjdosd_get(u_int type, struct osd *osd, u_int slot)
296185029Spjd{
297188894Sjamie	struct rm_priotracker tracker;
298188894Sjamie	void *value;
299185029Spjd
300185029Spjd	KASSERT(type >= OSD_FIRST && type <= OSD_LAST, ("Invalid type."));
301185029Spjd	KASSERT(slot > 0, ("Invalid slot."));
302298834Sjamie	KASSERT(osdm[type].osd_destructors[slot - 1] != NULL, ("Unused slot."));
303185029Spjd
304298834Sjamie	rm_rlock(&osdm[type].osd_object_lock, &tracker);
305185029Spjd	if (slot > osd->osd_nslots) {
306188894Sjamie		value = NULL;
307185029Spjd		OSD_DEBUG("Slot doesn't exist (type=%u, slot=%u).", type, slot);
308188894Sjamie	} else {
309188894Sjamie		value = osd->osd_slots[slot - 1];
310188894Sjamie		OSD_DEBUG("Returning slot value (type=%u, slot=%u, value=%p).",
311188894Sjamie		    type, slot, value);
312185029Spjd	}
313298834Sjamie	rm_runlock(&osdm[type].osd_object_lock, &tracker);
314188894Sjamie	return (value);
315185029Spjd}
316185029Spjd
317185029Spjdvoid
318185029Spjdosd_del(u_int type, struct osd *osd, u_int slot)
319185029Spjd{
320188894Sjamie	struct rm_priotracker tracker;
321188894Sjamie
322298834Sjamie	rm_rlock(&osdm[type].osd_object_lock, &tracker);
323188894Sjamie	do_osd_del(type, osd, slot, 0);
324298834Sjamie	rm_runlock(&osdm[type].osd_object_lock, &tracker);
325188894Sjamie}
326188894Sjamie
327188894Sjamiestatic void
328188894Sjamiedo_osd_del(u_int type, struct osd *osd, u_int slot, int list_locked)
329188894Sjamie{
330185029Spjd	int i;
331185029Spjd
332185029Spjd	KASSERT(type >= OSD_FIRST && type <= OSD_LAST, ("Invalid type."));
333185029Spjd	KASSERT(slot > 0, ("Invalid slot."));
334298834Sjamie	KASSERT(osdm[type].osd_destructors[slot - 1] != NULL, ("Unused slot."));
335185029Spjd
336185029Spjd	OSD_DEBUG("Deleting slot (type=%u, slot=%u).", type, slot);
337185029Spjd
338185029Spjd	if (slot > osd->osd_nslots) {
339185029Spjd		OSD_DEBUG("Slot doesn't exist (type=%u, slot=%u).", type, slot);
340185029Spjd		return;
341185029Spjd	}
342191711Sjamie	if (osd->osd_slots[slot - 1] != NULL) {
343298834Sjamie		osdm[type].osd_destructors[slot - 1](osd->osd_slots[slot - 1]);
344191711Sjamie		osd->osd_slots[slot - 1] = NULL;
345191711Sjamie	}
346185029Spjd	for (i = osd->osd_nslots - 1; i >= 0; i--) {
347185029Spjd		if (osd->osd_slots[i] != NULL) {
348188894Sjamie			OSD_DEBUG("Slot still has a value (type=%u, slot=%u).",
349188894Sjamie			    type, i + 1);
350185029Spjd			break;
351185029Spjd		}
352185029Spjd	}
353185029Spjd	if (i == -1) {
354185029Spjd		/* No values left for this object. */
355185029Spjd		OSD_DEBUG("No more slots left (type=%u).", type);
356188894Sjamie		if (!list_locked)
357298834Sjamie			mtx_lock(&osdm[type].osd_list_lock);
358185029Spjd		LIST_REMOVE(osd, osd_next);
359188894Sjamie		if (!list_locked)
360298834Sjamie			mtx_unlock(&osdm[type].osd_list_lock);
361185029Spjd		free(osd->osd_slots, M_OSD);
362185029Spjd		osd->osd_slots = NULL;
363185029Spjd		osd->osd_nslots = 0;
364185029Spjd	} else if (slot == osd->osd_nslots) {
365185029Spjd		/* This was the last slot. */
366185029Spjd		osd->osd_slots = realloc(osd->osd_slots,
367185029Spjd		    sizeof(void *) * (i + 1), M_OSD, M_NOWAIT | M_ZERO);
368185029Spjd		/*
369185029Spjd		 * We always reallocate to smaller size, so we assume it will
370185029Spjd		 * always succeed.
371185029Spjd		 */
372185029Spjd		KASSERT(osd->osd_slots != NULL, ("realloc() failed"));
373185029Spjd		osd->osd_nslots = i + 1;
374185029Spjd		OSD_DEBUG("Reducing slots array to %u (type=%u).",
375185029Spjd		    osd->osd_nslots, type);
376185029Spjd	}
377185029Spjd}
378185029Spjd
379188894Sjamieint
380188894Sjamieosd_call(u_int type, u_int method, void *obj, void *data)
381188894Sjamie{
382188894Sjamie	osd_method_t methodfun;
383188894Sjamie	int error, i;
384188894Sjamie
385188894Sjamie	KASSERT(type >= OSD_FIRST && type <= OSD_LAST, ("Invalid type."));
386298834Sjamie	KASSERT(method < osdm[type].osd_nmethods, ("Invalid method."));
387188894Sjamie
388188894Sjamie	/*
389188894Sjamie	 * Call this method for every slot that defines it, stopping if an
390188894Sjamie	 * error is encountered.
391188894Sjamie	 */
392188894Sjamie	error = 0;
393298834Sjamie	sx_slock(&osdm[type].osd_module_lock);
394298834Sjamie	for (i = 0; i < osdm[type].osd_ntslots; i++) {
395298834Sjamie		methodfun = osdm[type].osd_methods[i * osdm[type].osd_nmethods +
396298834Sjamie		    method];
397188894Sjamie		if (methodfun != NULL && (error = methodfun(obj, data)) != 0)
398188894Sjamie			break;
399188894Sjamie	}
400298834Sjamie	sx_sunlock(&osdm[type].osd_module_lock);
401188894Sjamie	return (error);
402188894Sjamie}
403188894Sjamie
404185029Spjdvoid
405185029Spjdosd_exit(u_int type, struct osd *osd)
406185029Spjd{
407188894Sjamie	struct rm_priotracker tracker;
408185029Spjd	u_int i;
409185029Spjd
410185029Spjd	KASSERT(type >= OSD_FIRST && type <= OSD_LAST, ("Invalid type."));
411185029Spjd
412185029Spjd	if (osd->osd_nslots == 0) {
413185029Spjd		KASSERT(osd->osd_slots == NULL, ("Non-null osd_slots."));
414185029Spjd		/* No OSD attached, just leave. */
415185029Spjd		return;
416185029Spjd	}
417185029Spjd
418298834Sjamie	rm_rlock(&osdm[type].osd_object_lock, &tracker);
419188894Sjamie	for (i = 1; i <= osd->osd_nslots; i++) {
420298834Sjamie		if (osdm[type].osd_destructors[i - 1] != NULL)
421188894Sjamie			do_osd_del(type, osd, i, 0);
422188894Sjamie		else
423188894Sjamie			OSD_DEBUG("Unused slot (type=%u, slot=%u).", type, i);
424188894Sjamie	}
425298834Sjamie	rm_runlock(&osdm[type].osd_object_lock, &tracker);
426185029Spjd	OSD_DEBUG("Object exit (type=%u).", type);
427185029Spjd}
428185029Spjd
429185029Spjdstatic void
430185029Spjdosd_init(void *arg __unused)
431185029Spjd{
432185029Spjd	u_int i;
433185029Spjd
434185029Spjd	for (i = OSD_FIRST; i <= OSD_LAST; i++) {
435298834Sjamie		sx_init(&osdm[i].osd_module_lock, "osd_module");
436298834Sjamie		rm_init(&osdm[i].osd_object_lock, "osd_object");
437298834Sjamie		mtx_init(&osdm[i].osd_list_lock, "osd_list", NULL, MTX_DEF);
438298834Sjamie		LIST_INIT(&osdm[i].osd_list);
439298834Sjamie		osdm[i].osd_destructors = NULL;
440298834Sjamie		osdm[i].osd_ntslots = 0;
441298834Sjamie		osdm[i].osd_methods = NULL;
442185029Spjd	}
443185029Spjd}
444185029SpjdSYSINIT(osd, SI_SUB_LOCK, SI_ORDER_ANY, osd_init, NULL);
445