xref: /freebsd/sys/kern/kern_conf.c (revision 7660b554bc59a07be0431c17e0e33815818baa69)
1 /*-
2  * Copyright (c) 1999-2002 Poul-Henning Kamp
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24  * SUCH DAMAGE.
25  */
26 
27 #include <sys/cdefs.h>
28 __FBSDID("$FreeBSD$");
29 
30 #include <sys/param.h>
31 #include <sys/kernel.h>
32 #include <sys/systm.h>
33 #include <sys/bio.h>
34 #include <sys/lock.h>
35 #include <sys/mutex.h>
36 #include <sys/sysctl.h>
37 #include <sys/module.h>
38 #include <sys/malloc.h>
39 #include <sys/conf.h>
40 #include <sys/vnode.h>
41 #include <sys/queue.h>
42 #include <sys/ctype.h>
43 #include <machine/stdarg.h>
44 
45 static MALLOC_DEFINE(M_DEVT, "dev_t", "dev_t storage");
46 
47 /* Built at compile time from sys/conf/majors */
48 extern unsigned char reserved_majors[256];
49 
50 /*
51  * This is the number of hash-buckets.  Experiements with 'real-life'
52  * udev_t's show that a prime halfway between two powers of two works
53  * best.
54  */
55 #define DEVT_HASH 83
56 
57 /* The number of dev_t's we can create before malloc(9) kick in.  */
58 #define DEVT_STASH 50
59 
60 static struct cdev devt_stash[DEVT_STASH];
61 
62 static LIST_HEAD(, cdev) dev_hash[DEVT_HASH];
63 
64 static LIST_HEAD(, cdev) dev_free;
65 
66 static int ready_for_devs;
67 
68 static int free_devt;
69 SYSCTL_INT(_debug, OID_AUTO, free_devt, CTLFLAG_RW, &free_devt, 0, "");
70 
71 /* Define a dead_cdevsw for use when devices leave unexpectedly. */
72 
73 static int
74 enxio(void)
75 {
76 	return (ENXIO);
77 }
78 
79 #define dead_open	(d_open_t *)enxio
80 #define dead_close	(d_close_t *)enxio
81 #define dead_read	(d_read_t *)enxio
82 #define dead_write	(d_write_t *)enxio
83 #define dead_ioctl	(d_ioctl_t *)enxio
84 #define dead_poll	nopoll
85 #define dead_mmap	nommap
86 
87 static void
88 dead_strategy(struct bio *bp)
89 {
90 
91 	biofinish(bp, NULL, ENXIO);
92 }
93 
94 #define dead_dump	(dumper_t *)enxio
95 
96 #define dead_kqfilter	(d_kqfilter_t *)enxio
97 
98 static struct cdevsw dead_cdevsw = {
99 	.d_open =	dead_open,
100 	.d_close =	dead_close,
101 	.d_read =	dead_read,
102 	.d_write =	dead_write,
103 	.d_ioctl =	dead_ioctl,
104 	.d_poll =	dead_poll,
105 	.d_mmap =	dead_mmap,
106 	.d_strategy =	dead_strategy,
107 	.d_name =	"dead",
108 	.d_maj =	255,
109 	.d_dump =	dead_dump,
110 	.d_kqfilter =	dead_kqfilter
111 };
112 
113 
114 struct cdevsw *
115 devsw(dev_t dev)
116 {
117 	if (dev->si_devsw)
118 		return (dev->si_devsw);
119 	return (&dead_cdevsw);
120 }
121 
122 /*
123  * dev_t and u_dev_t primitives
124  */
125 
126 int
127 major(dev_t x)
128 {
129 	if (x == NODEV)
130 		return NOUDEV;
131 	return((x->si_udev >> 8) & 0xff);
132 }
133 
134 int
135 minor(dev_t x)
136 {
137 	if (x == NODEV)
138 		return NOUDEV;
139 	return(x->si_udev & 0xffff00ff);
140 }
141 
142 int
143 dev2unit(dev_t x)
144 {
145 	int i;
146 
147 	if (x == NODEV)
148 		return NOUDEV;
149 	i = minor(x);
150 	return ((i & 0xff) | (i >> 8));
151 }
152 
153 int
154 unit2minor(int unit)
155 {
156 
157 	KASSERT(unit <= 0xffffff, ("Invalid unit (%d) in unit2minor", unit));
158 	return ((unit & 0xff) | ((unit << 8) & ~0xffff));
159 }
160 
161 static dev_t
162 allocdev(void)
163 {
164 	static int stashed;
165 	struct cdev *si;
166 
167 	if (LIST_FIRST(&dev_free)) {
168 		si = LIST_FIRST(&dev_free);
169 		LIST_REMOVE(si, si_hash);
170 	} else if (stashed >= DEVT_STASH) {
171 		MALLOC(si, struct cdev *, sizeof(*si), M_DEVT,
172 		    M_USE_RESERVE | M_ZERO | M_WAITOK);
173 	} else {
174 		si = devt_stash + stashed++;
175 		bzero(si, sizeof *si);
176 		si->si_flags |= SI_STASHED;
177 	}
178 	si->__si_namebuf[0] = '\0';
179 	si->si_name = si->__si_namebuf;
180 	LIST_INIT(&si->si_children);
181 	TAILQ_INIT(&si->si_snapshots);
182 	return (si);
183 }
184 
185 dev_t
186 makedev(int x, int y)
187 {
188 	struct cdev *si;
189 	udev_t	udev;
190 	int hash;
191 
192 	if (x == umajor(NOUDEV) && y == uminor(NOUDEV))
193 		panic("makedev of NOUDEV");
194 	udev = (x << 8) | y;
195 	hash = udev % DEVT_HASH;
196 	LIST_FOREACH(si, &dev_hash[hash], si_hash) {
197 		if (si->si_udev == udev)
198 			return (si);
199 	}
200 	si = allocdev();
201 	si->si_udev = udev;
202 	LIST_INSERT_HEAD(&dev_hash[hash], si, si_hash);
203         return (si);
204 }
205 
206 void
207 freedev(dev_t dev)
208 {
209 
210 	if (!free_devt)
211 		return;
212 	if (SLIST_FIRST(&dev->si_hlist))
213 		return;
214 	if (dev->si_devsw || dev->si_drv1 || dev->si_drv2)
215 		return;
216 	LIST_REMOVE(dev, si_hash);
217 	if (dev->si_flags & SI_STASHED) {
218 		bzero(dev, sizeof(*dev));
219 		dev->si_flags |= SI_STASHED;
220 		LIST_INSERT_HEAD(&dev_free, dev, si_hash);
221 	} else {
222 		FREE(dev, M_DEVT);
223 	}
224 }
225 
226 udev_t
227 dev2udev(dev_t x)
228 {
229 	if (x == NODEV)
230 		return NOUDEV;
231 	return (x->si_udev);
232 }
233 
234 dev_t
235 udev2dev(udev_t x, int b)
236 {
237 
238 	if (x == NOUDEV)
239 		return (NODEV);
240 	switch (b) {
241 		case 0:
242 			return makedev(umajor(x), uminor(x));
243 		case 1:
244 			return (NODEV);
245 		default:
246 			Debugger("udev2dev(...,X)");
247 			return NODEV;
248 	}
249 }
250 
251 int
252 uminor(udev_t dev)
253 {
254 	return(dev & 0xffff00ff);
255 }
256 
257 int
258 umajor(udev_t dev)
259 {
260 	return((dev & 0xff00) >> 8);
261 }
262 
263 udev_t
264 makeudev(int x, int y)
265 {
266         return ((x << 8) | y);
267 }
268 
269 dev_t
270 make_dev(struct cdevsw *devsw, int minor, uid_t uid, gid_t gid, int perms, const char *fmt, ...)
271 {
272 	dev_t	dev;
273 	va_list ap;
274 	int i;
275 
276 	KASSERT((minor & ~0xffff00ff) == 0,
277 	    ("Invalid minor (0x%x) in make_dev", minor));
278 
279 	if (devsw->d_open == NULL)	devsw->d_open = noopen;
280 	if (devsw->d_close == NULL)	devsw->d_close = noclose;
281 	if (devsw->d_read == NULL)	devsw->d_read = noread;
282 	if (devsw->d_write == NULL)	devsw->d_write = nowrite;
283 	if (devsw->d_ioctl == NULL)	devsw->d_ioctl = noioctl;
284 	if (devsw->d_poll == NULL)	devsw->d_poll = nopoll;
285 	if (devsw->d_mmap == NULL)	devsw->d_mmap = nommap;
286 	if (devsw->d_strategy == NULL)	devsw->d_strategy = nostrategy;
287 	if (devsw->d_dump == NULL)	devsw->d_dump = nodump;
288 	if (devsw->d_kqfilter == NULL)	devsw->d_kqfilter = nokqfilter;
289 
290 	if (devsw->d_maj == MAJOR_AUTO) {
291 		for (i = NUMCDEVSW - 1; i > 0; i--)
292 			if (reserved_majors[i] != i)
293 				break;
294 		KASSERT(i > 0, ("Out of major numbers (%s)", devsw->d_name));
295 		devsw->d_maj = i;
296 		reserved_majors[i] = i;
297 	} else {
298 		if (devsw->d_maj == 256)	/* XXX: tty_cons.c is magic */
299 			devsw->d_maj = 0;
300 		KASSERT(devsw->d_maj >= 0 && devsw->d_maj < 256,
301 		    ("Invalid major (%d) in make_dev", devsw->d_maj));
302 		if (reserved_majors[devsw->d_maj] != devsw->d_maj) {
303 			printf("WARNING: driver \"%s\" used %s %d\n",
304 			    devsw->d_name, "unreserved major device number",
305 			    devsw->d_maj);
306 			reserved_majors[devsw->d_maj] = devsw->d_maj;
307 		}
308 	}
309 
310 	if (!ready_for_devs) {
311 		printf("WARNING: Driver mistake: make_dev(%s) called before SI_SUB_DRIVERS\n",
312 		       fmt);
313 		/* XXX panic here once drivers are cleaned up */
314 	}
315 
316 	dev = makedev(devsw->d_maj, minor);
317 	if (dev->si_flags & SI_NAMED) {
318 		printf( "WARNING: Driver mistake: repeat make_dev(\"%s\")\n",
319 		    dev->si_name);
320 		panic("don't do that");
321 	}
322 	va_start(ap, fmt);
323 	i = vsnrprintf(dev->__si_namebuf, sizeof dev->__si_namebuf, 32, fmt, ap);
324 	if (i > (sizeof dev->__si_namebuf - 1)) {
325 		printf("WARNING: Device name truncated! (%s)",
326 		    dev->__si_namebuf);
327 	}
328 	va_end(ap);
329 	dev->si_devsw = devsw;
330 	dev->si_uid = uid;
331 	dev->si_gid = gid;
332 	dev->si_mode = perms;
333 	dev->si_flags |= SI_NAMED;
334 
335 	devfs_create(dev);
336 	return (dev);
337 }
338 
339 int
340 dev_named(dev_t pdev, const char *name)
341 {
342 	dev_t cdev;
343 
344 	if (strcmp(devtoname(pdev), name) == 0)
345 		return (1);
346 	LIST_FOREACH(cdev, &pdev->si_children, si_siblings)
347 		if (strcmp(devtoname(cdev), name) == 0)
348 			return (1);
349 	return (0);
350 }
351 
352 void
353 dev_depends(dev_t pdev, dev_t cdev)
354 {
355 
356 	cdev->si_parent = pdev;
357 	cdev->si_flags |= SI_CHILD;
358 	LIST_INSERT_HEAD(&pdev->si_children, cdev, si_siblings);
359 }
360 
361 dev_t
362 make_dev_alias(dev_t pdev, const char *fmt, ...)
363 {
364 	dev_t	dev;
365 	va_list ap;
366 	int i;
367 
368 	dev = allocdev();
369 	dev->si_flags |= SI_ALIAS;
370 	dev->si_flags |= SI_NAMED;
371 	dev_depends(pdev, dev);
372 	va_start(ap, fmt);
373 	i = vsnrprintf(dev->__si_namebuf, sizeof dev->__si_namebuf, 32, fmt, ap);
374 	if (i > (sizeof dev->__si_namebuf - 1)) {
375 		printf("WARNING: Device name truncated! (%s)",
376 		    dev->__si_namebuf);
377 	}
378 	va_end(ap);
379 
380 	devfs_create(dev);
381 	return (dev);
382 }
383 
384 void
385 revoke_and_destroy_dev(dev_t dev)
386 {
387 	struct vnode *vp;
388 
389 	GIANT_REQUIRED;
390 
391 	vp = SLIST_FIRST(&dev->si_hlist);
392 	if (vp != NULL)
393 		VOP_REVOKE(vp, REVOKEALL);
394 	destroy_dev(dev);
395 }
396 
397 void
398 destroy_dev(dev_t dev)
399 {
400 
401 	if (!(dev->si_flags & SI_NAMED)) {
402 		printf( "WARNING: Driver mistake: destroy_dev on %d/%d\n",
403 		    major(dev), minor(dev));
404 		panic("don't do that");
405 	}
406 
407 	devfs_destroy(dev);
408 	if (dev->si_flags & SI_CHILD) {
409 		LIST_REMOVE(dev, si_siblings);
410 		dev->si_flags &= ~SI_CHILD;
411 	}
412 	while (!LIST_EMPTY(&dev->si_children))
413 		destroy_dev(LIST_FIRST(&dev->si_children));
414 	dev->si_drv1 = 0;
415 	dev->si_drv2 = 0;
416 	dev->si_devsw = 0;
417 	bzero(&dev->__si_u, sizeof(dev->__si_u));
418 	dev->si_flags &= ~SI_NAMED;
419 	dev->si_flags &= ~SI_ALIAS;
420 	freedev(dev);
421 }
422 
423 const char *
424 devtoname(dev_t dev)
425 {
426 	char *p;
427 	int mynor;
428 
429 	if (dev->si_name[0] == '#' || dev->si_name[0] == '\0') {
430 		p = dev->si_name;
431 		if (devsw(dev))
432 			sprintf(p, "#%s/", devsw(dev)->d_name);
433 		else
434 			sprintf(p, "#%d/", major(dev));
435 		p += strlen(p);
436 		mynor = minor(dev);
437 		if (mynor < 0 || mynor > 255)
438 			sprintf(p, "%#x", (u_int)mynor);
439 		else
440 			sprintf(p, "%d", mynor);
441 	}
442 	return (dev->si_name);
443 }
444 
445 int
446 dev_stdclone(char *name, char **namep, const char *stem, int *unit)
447 {
448 	int u, i;
449 
450 	i = strlen(stem);
451 	if (bcmp(stem, name, i) != 0)
452 		return (0);
453 	if (!isdigit(name[i]))
454 		return (0);
455 	u = 0;
456 	if (name[i] == '0' && isdigit(name[i+1]))
457 		return (0);
458 	while (isdigit(name[i])) {
459 		u *= 10;
460 		u += name[i++] - '0';
461 	}
462 	if (u > 0xffffff)
463 		return (0);
464 	*unit = u;
465 	if (namep)
466 		*namep = &name[i];
467 	if (name[i])
468 		return (2);
469 	return (1);
470 }
471 
472 /*
473  * Helper sysctl for devname(3).  We're given a {u}dev_t and return
474  * the name, if any, registered by the device driver.
475  */
476 static int
477 sysctl_devname(SYSCTL_HANDLER_ARGS)
478 {
479 	int error;
480 	udev_t ud;
481 	dev_t dev;
482 
483 	error = SYSCTL_IN(req, &ud, sizeof (ud));
484 	if (error)
485 		return (error);
486 	if (ud == NOUDEV)
487 		return(EINVAL);
488 	dev = makedev(umajor(ud), uminor(ud));
489 	if (dev->si_name[0] == '\0')
490 		error = ENOENT;
491 	else
492 		error = SYSCTL_OUT(req, dev->si_name, strlen(dev->si_name) + 1);
493 	freedev(dev);
494 	return (error);
495 }
496 
497 SYSCTL_PROC(_kern, OID_AUTO, devname, CTLTYPE_OPAQUE|CTLFLAG_RW|CTLFLAG_ANYBODY,
498 	NULL, 0, sysctl_devname, "", "devname(3) handler");
499 
500 /*
501  * Set ready_for_devs; prior to this point, device creation is not allowed.
502  */
503 static void
504 dev_set_ready(void *junk)
505 {
506 	ready_for_devs = 1;
507 }
508 
509 SYSINIT(dev_ready, SI_SUB_DEVFS, SI_ORDER_FIRST, dev_set_ready, NULL);
510