kern_conf.c revision 60938
1119381Sjake/*-
2119381Sjake * Parts Copyright (c) 1995 Terrence R. Lambert
3119381Sjake * Copyright (c) 1995 Julian R. Elischer
4139749Simp * All rights reserved.
5119381Sjake *
6119381Sjake * Redistribution and use in source and binary forms, with or without
7119381Sjake * modification, are permitted provided that the following conditions
8119381Sjake * are met:
9119381Sjake * 1. Redistributions of source code must retain the above copyright
10119381Sjake *    notice, this list of conditions and the following disclaimer.
11119381Sjake * 2. Redistributions in binary form must reproduce the above copyright
12119381Sjake *    notice, this list of conditions and the following disclaimer in the
13119381Sjake *    documentation and/or other materials provided with the distribution.
14119381Sjake * 3. All advertising materials mentioning features or use of this software
15119381Sjake *    must display the following acknowledgement:
16119381Sjake *      This product includes software developed by Terrence R. Lambert.
17119381Sjake * 4. The name Terrence R. Lambert may not be used to endorse or promote
18119381Sjake *    products derived from this software without specific prior written
19119381Sjake *    permission.
20119381Sjake *
21119381Sjake * THIS SOFTWARE IS PROVIDED BY Julian R. Elischer ``AS IS'' AND ANY
22119381Sjake * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23119381Sjake * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24119381Sjake * ARE DISCLAIMED.  IN NO EVENT SHALL THE TERRENCE R. LAMBERT BE LIABLE
25119381Sjake * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26119381Sjake * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27119381Sjake * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28119381Sjake * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29119381Sjake * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30119381Sjake * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31119381Sjake * SUCH DAMAGE.
32119381Sjake *
33119381Sjake * $FreeBSD: head/sys/kern/kern_conf.c 60938 2000-05-26 02:09:24Z jake $
34119381Sjake */
35119381Sjake
36119381Sjake#include <sys/param.h>
37119381Sjake#include <sys/kernel.h>
38119381Sjake#include <sys/sysctl.h>
39170840Smarius#include <sys/systm.h>
40170840Smarius#include <sys/module.h>
41170840Smarius#include <sys/malloc.h>
42170840Smarius#include <sys/conf.h>
43170840Smarius#include <sys/vnode.h>
44170840Smarius#include <sys/queue.h>
45170840Smarius#include <machine/stdarg.h>
46170840Smarius
47170840Smarius#define cdevsw_ALLOCSTART	(NUMCDEVSW/2)
48170840Smarius
49170840Smariusstruct cdevsw 	*cdevsw[NUMCDEVSW];
50119381Sjake
51119381Sjakestatic int	bmaj2cmaj[NUMCDEVSW];
52119381Sjake
53119381SjakeMALLOC_DEFINE(M_DEVT, "dev_t", "dev_t storage");
54119381Sjake
55119381Sjake/*
56119381Sjake * This is the number of hash-buckets.  Experiements with 'real-life'
57119381Sjake * udev_t's show that a prime halfway between two powers of two works
58119381Sjake * best.
59119381Sjake */
60119381Sjake#define DEVT_HASH 83
61119381Sjake
62119381Sjake/* The number of dev_t's we can create before malloc(9) kick in.  */
63119381Sjake#define DEVT_STASH 50
64119381Sjake
65119381Sjakestatic struct specinfo devt_stash[DEVT_STASH];
66119381Sjake
67119381Sjakestatic LIST_HEAD(, specinfo) dev_hash[DEVT_HASH];
68119381Sjake
69119381Sjakestatic LIST_HEAD(, specinfo) dev_free;
70119381Sjake
71119381Sjakedevfs_create_t *devfs_create_hook;
72119381Sjakedevfs_remove_t *devfs_remove_hook;
73119381Sjake
74119381Sjakestatic int free_devt;
75119381SjakeSYSCTL_INT(_debug, OID_AUTO, free_devt, CTLFLAG_RW, &free_devt, 0, "");
76119381Sjake
77119381Sjakestruct cdevsw *
78119381Sjakedevsw(dev_t dev)
79119381Sjake{
80119381Sjake	if (dev->si_devsw)
81119381Sjake		return (dev->si_devsw);
82119381Sjake        return(cdevsw[major(dev)]);
83119381Sjake}
84119381Sjake
85119381Sjake/*
86119381Sjake *  Add a cdevsw entry
87119381Sjake */
88119381Sjake
89119381Sjakeint
90119381Sjakecdevsw_add(struct cdevsw *newentry)
91119381Sjake{
92119381Sjake	int i;
93119381Sjake	static int setup;
94119381Sjake
95119381Sjake	if (!setup) {
96119381Sjake		for (i = 0; i < NUMCDEVSW; i++)
97119381Sjake			if (!bmaj2cmaj[i])
98119381Sjake				bmaj2cmaj[i] = 254;
99119381Sjake		setup++;
100119381Sjake	}
101119381Sjake
102119381Sjake	if (newentry->d_maj < 0 || newentry->d_maj >= NUMCDEVSW) {
103119381Sjake		printf("%s: ERROR: driver has bogus cdevsw->d_maj = %d\n",
104119381Sjake		    newentry->d_name, newentry->d_maj);
105119381Sjake		return (EINVAL);
106119381Sjake	}
107119381Sjake	if (newentry->d_bmaj >= NUMCDEVSW) {
108119381Sjake		printf("%s: ERROR: driver has bogus cdevsw->d_bmaj = %d\n",
109119381Sjake		    newentry->d_name, newentry->d_bmaj);
110119381Sjake		return (EINVAL);
111119381Sjake	}
112119381Sjake	if (newentry->d_bmaj >= 0 && (newentry->d_flags & D_DISK) == 0) {
113119381Sjake		printf("ERROR: \"%s\" bmaj but is not a disk\n",
114119381Sjake		    newentry->d_name);
115119381Sjake		return (EINVAL);
116119381Sjake	}
117119381Sjake
118119381Sjake	if (cdevsw[newentry->d_maj]) {
119119381Sjake		printf("WARNING: \"%s\" is usurping \"%s\"'s cdevsw[]\n",
120119381Sjake		    newentry->d_name, cdevsw[newentry->d_maj]->d_name);
121119381Sjake	}
122119381Sjake
123119381Sjake	cdevsw[newentry->d_maj] = newentry;
124119381Sjake
125119381Sjake	if (newentry->d_bmaj < 0)
126119381Sjake		return (0);
127119381Sjake
128119381Sjake	if (bmaj2cmaj[newentry->d_bmaj] != 254) {
129119381Sjake		printf("WARNING: \"%s\" is usurping \"%s\"'s bmaj\n",
130119381Sjake		    newentry->d_name,
131119381Sjake		    cdevsw[bmaj2cmaj[newentry->d_bmaj]]->d_name);
132119381Sjake	}
133119381Sjake	bmaj2cmaj[newentry->d_bmaj] = newentry->d_maj;
134119381Sjake	return (0);
135119381Sjake}
136119381Sjake
137119381Sjake/*
138119381Sjake *  Remove a cdevsw entry
139119381Sjake */
140119381Sjake
141119381Sjakeint
142119381Sjakecdevsw_remove(struct cdevsw *oldentry)
143119381Sjake{
144119381Sjake	if (oldentry->d_maj < 0 || oldentry->d_maj >= NUMCDEVSW) {
145119381Sjake		printf("%s: ERROR: driver has bogus cdevsw->d_maj = %d\n",
146119381Sjake		    oldentry->d_name, oldentry->d_maj);
147119381Sjake		return EINVAL;
148119381Sjake	}
149119381Sjake
150119381Sjake	cdevsw[oldentry->d_maj] = NULL;
151119381Sjake
152119381Sjake	if (oldentry->d_bmaj >= 0 && oldentry->d_bmaj < NUMCDEVSW)
153119381Sjake		bmaj2cmaj[oldentry->d_bmaj] = 254;
154119381Sjake
155119381Sjake	return 0;
156119381Sjake}
157119381Sjake
158119381Sjake/*
159119381Sjake * dev_t and u_dev_t primitives
160119381Sjake */
161119381Sjake
162119381Sjakeint
163119381Sjakemajor(dev_t x)
164119381Sjake{
165119381Sjake	if (x == NODEV)
166119381Sjake		return NOUDEV;
167119381Sjake	return((x->si_udev >> 8) & 0xff);
168119381Sjake}
169119381Sjake
170119381Sjakeint
171119381Sjakeminor(dev_t x)
172119381Sjake{
173119381Sjake	if (x == NODEV)
174119381Sjake		return NOUDEV;
175119381Sjake	return(x->si_udev & 0xffff00ff);
176119381Sjake}
177119381Sjake
178119381Sjakeint
179119381Sjakelminor(dev_t x)
180119381Sjake{
181119381Sjake	int i;
182119381Sjake
183119381Sjake	if (x == NODEV)
184119381Sjake		return NOUDEV;
185119381Sjake	i = minor(x);
186119381Sjake	return ((i & 0xff) | (i >> 8));
187119381Sjake}
188119381Sjake
189119381Sjakedev_t
190119381Sjakemakebdev(int x, int y)
191119381Sjake{
192119381Sjake
193119381Sjake	if (x == umajor(NOUDEV) && y == uminor(NOUDEV))
194119381Sjake		Debugger("makebdev of NOUDEV");
195119381Sjake	return (makedev(bmaj2cmaj[x], y));
196119381Sjake}
197119381Sjake
198119381Sjakedev_t
199119381Sjakemakedev(int x, int y)
200119381Sjake{
201119381Sjake	struct specinfo *si;
202119381Sjake	udev_t	udev;
203119381Sjake	int hash;
204119381Sjake	static int stashed;
205119381Sjake
206119381Sjake	if (x == umajor(NOUDEV) && y == uminor(NOUDEV))
207119381Sjake		Debugger("makedev of NOUDEV");
208119381Sjake	udev = (x << 8) | y;
209119381Sjake	hash = udev % DEVT_HASH;
210119381Sjake	LIST_FOREACH(si, &dev_hash[hash], si_hash) {
211119381Sjake		if (si->si_udev == udev)
212119381Sjake			return (si);
213119381Sjake	}
214119381Sjake	if (stashed >= DEVT_STASH) {
215119381Sjake		MALLOC(si, struct specinfo *, sizeof(*si), M_DEVT,
216119381Sjake		    M_USE_RESERVE);
217119381Sjake		bzero(si, sizeof(*si));
218119381Sjake	} else if (LIST_FIRST(&dev_free)) {
219119381Sjake		si = LIST_FIRST(&dev_free);
220119381Sjake		LIST_REMOVE(si, si_hash);
221119381Sjake	} else {
222119381Sjake		si = devt_stash + stashed++;
223119381Sjake		si->si_flags |= SI_STASHED;
224119381Sjake	}
225119381Sjake	si->si_udev = udev;
226119381Sjake	LIST_INSERT_HEAD(&dev_hash[hash], si, si_hash);
227119381Sjake        return (si);
228119381Sjake}
229119381Sjake
230119381Sjakevoid
231119381Sjakefreedev(dev_t dev)
232119381Sjake{
233119381Sjake	int hash;
234119381Sjake
235119381Sjake	if (!free_devt)
236119381Sjake		return;
237119381Sjake	if (SLIST_FIRST(&dev->si_hlist))
238119381Sjake		return;
239119381Sjake	if (dev->si_devsw || dev->si_drv1 || dev->si_drv2)
240119381Sjake		return;
241119381Sjake	hash = dev->si_udev % DEVT_HASH;
242119381Sjake	LIST_REMOVE(dev, si_hash);
243119381Sjake	if (dev->si_flags & SI_STASHED) {
244119381Sjake		bzero(dev, sizeof(*dev));
245119381Sjake		LIST_INSERT_HEAD(&dev_free, dev, si_hash);
246119381Sjake	} else {
247119381Sjake		FREE(dev, M_DEVT);
248119381Sjake	}
249119381Sjake}
250119381Sjake
251119381Sjakeudev_t
252119381Sjakedev2udev(dev_t x)
253119381Sjake{
254119381Sjake	if (x == NODEV)
255119381Sjake		return NOUDEV;
256119381Sjake	return (x->si_udev);
257119381Sjake}
258119381Sjake
259119381Sjakedev_t
260119381Sjakeudev2dev(udev_t x, int b)
261119381Sjake{
262119381Sjake
263119381Sjake	if (x == NOUDEV)
264119381Sjake		return (NODEV);
265119381Sjake	switch (b) {
266119381Sjake		case 0:
267119381Sjake			return makedev(umajor(x), uminor(x));
268119381Sjake		case 1:
269119381Sjake			return makebdev(umajor(x), uminor(x));
270119381Sjake		default:
271119381Sjake			Debugger("udev2dev(...,X)");
272119381Sjake			return NODEV;
273119381Sjake	}
274119381Sjake}
275119381Sjake
276119381Sjakeint
277119381Sjakeuminor(udev_t dev)
278119381Sjake{
279119381Sjake	return(dev & 0xffff00ff);
280119381Sjake}
281119381Sjake
282119381Sjakeint
283119381Sjakeumajor(udev_t dev)
284119381Sjake{
285119381Sjake	return((dev & 0xff00) >> 8);
286119381Sjake}
287119381Sjake
288119381Sjakeudev_t
289119381Sjakemakeudev(int x, int y)
290119381Sjake{
291119381Sjake        return ((x << 8) | y);
292119381Sjake}
293119381Sjake
294119381Sjakedev_t
295119381Sjakemake_dev(struct cdevsw *devsw, int minor, uid_t uid, gid_t gid, int perms, char *fmt, ...)
296119381Sjake{
297119381Sjake	dev_t	dev;
298119381Sjake	va_list ap;
299119381Sjake	int i;
300119381Sjake
301119381Sjake	dev = makedev(devsw->d_maj, minor);
302119381Sjake	va_start(ap, fmt);
303119381Sjake	i = kvprintf(fmt, NULL, dev->si_name, 32, ap);
304119381Sjake	dev->si_name[i] = '\0';
305119381Sjake	va_end(ap);
306119381Sjake	dev->si_devsw = devsw;
307119381Sjake
308119381Sjake	if (devfs_create_hook)
309119381Sjake		devfs_create_hook(dev, uid, gid, perms);
310119381Sjake	return (dev);
311119381Sjake}
312119381Sjake
313119381Sjakevoid
314119381Sjakedestroy_dev(dev_t dev)
315119381Sjake{
316119381Sjake	if (devfs_remove_hook)
317119381Sjake		devfs_remove_hook(dev);
318119381Sjake	dev->si_drv1 = 0;
319119381Sjake	dev->si_drv2 = 0;
320119381Sjake	dev->si_devsw = 0;
321119381Sjake	freedev(dev);
322119381Sjake}
323119381Sjake
324119381Sjakeconst char *
325119381Sjakedevtoname(dev_t dev)
326119381Sjake{
327119381Sjake	char *p;
328119381Sjake	int mynor;
329119381Sjake
330119381Sjake	if (dev->si_name[0] == '#' || dev->si_name[0] == '\0') {
331119381Sjake		p = dev->si_name;
332119381Sjake		if (devsw(dev))
333119381Sjake			sprintf(p, "#%s/", devsw(dev)->d_name);
334119381Sjake		else
335119381Sjake			sprintf(p, "#%d/", major(dev));
336119381Sjake		p += strlen(p);
337119381Sjake		mynor = minor(dev);
338119381Sjake		if (mynor < 0 || mynor > 255)
339119381Sjake			sprintf(p, "%#x", (u_int)mynor);
340119381Sjake		else
341119381Sjake			sprintf(p, "%d", mynor);
342119381Sjake	}
343119381Sjake	return (dev->si_name);
344119381Sjake}
345119381Sjake