xref: /dflybsd-src/sys/kern/kern_conf.c (revision cd29885abfb8f68adb0c082e313b891156d66964)
1 /*-
2  * Parts Copyright (c) 1995 Terrence R. Lambert
3  * Copyright (c) 1995 Julian R. Elischer
4  * All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  * 1. Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in the
13  *    documentation and/or other materials provided with the distribution.
14  * 3. All advertising materials mentioning features or use of this software
15  *    must display the following acknowledgement:
16  *      This product includes software developed by Terrence R. Lambert.
17  * 4. The name Terrence R. Lambert may not be used to endorse or promote
18  *    products derived from this software without specific prior written
19  *    permission.
20  *
21  * THIS SOFTWARE IS PROVIDED BY Julian R. Elischer ``AS IS'' AND ANY
22  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24  * ARE DISCLAIMED.  IN NO EVENT SHALL THE TERRENCE R. LAMBERT BE LIABLE
25  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31  * SUCH DAMAGE.
32  *
33  * $FreeBSD: src/sys/kern/kern_conf.c,v 1.73.2.3 2003/03/10 02:18:25 imp Exp $
34  * $DragonFly: src/sys/kern/kern_conf.c,v 1.23 2007/05/09 00:53:34 dillon Exp $
35  */
36 
37 #include <sys/param.h>
38 #include <sys/kernel.h>
39 #include <sys/sysctl.h>
40 #include <sys/systm.h>
41 #include <sys/module.h>
42 #include <sys/malloc.h>
43 #include <sys/conf.h>
44 #include <sys/vnode.h>
45 #include <sys/queue.h>
46 #include <sys/device.h>
47 #include <machine/stdarg.h>
48 
49 #include <sys/sysref2.h>
50 
51 #include <vfs/devfs/devfs.h>
52 
53 
54 static void cdev_terminate(struct cdev *dev);
55 
56 MALLOC_DEFINE(M_DEVT, "cdev_t", "dev_t storage");
57 
58 /*
59  * SYSREF Integration - reference counting, allocation,
60  * sysid and syslink integration.
61  */
62 static struct sysref_class     cdev_sysref_class = {
63 	.name =         "cdev",
64 	.mtype =        M_DEVT,
65 	.proto =        SYSREF_PROTO_DEV,
66 	.offset =       offsetof(struct cdev, si_sysref),
67 	.objsize =      sizeof(struct cdev),
68 	.mag_capacity = 32,
69 	.flags =        0,
70 	.ops =  {
71 		.terminate = (sysref_terminate_func_t)cdev_terminate
72 	}
73 };
74 
75 /*
76  * This is the number of hash-buckets.  Experiements with 'real-life'
77  * udev_t's show that a prime halfway between two powers of two works
78  * best.
79  */
80 #define DEVT_HASH 128	/* must be power of 2 */
81 static LIST_HEAD(, cdev) dev_hash[DEVT_HASH];
82 
83 static int free_devt;
84 SYSCTL_INT(_debug, OID_AUTO, free_devt, CTLFLAG_RW, &free_devt, 0, "");
85 int dev_ref_debug = 0;
86 SYSCTL_INT(_debug, OID_AUTO, dev_refs, CTLFLAG_RW, &dev_ref_debug, 0, "");
87 
88 /*
89  * cdev_t and u_dev_t primitives.  Note that the major number is always
90  * extracted from si_umajor, not from si_devsw, because si_devsw is replaced
91  * when a device is destroyed.
92  */
93 int
94 major(cdev_t dev)
95 {
96 	if (dev == NULL)
97 		return NOUDEV;
98 	return(dev->si_umajor);
99 }
100 
101 int
102 minor(cdev_t dev)
103 {
104 	if (dev == NULL)
105 		return NOUDEV;
106 	return(dev->si_uminor);
107 }
108 
109 /*
110  * Compatibility function with old udev_t format to convert the
111  * non-consecutive minor space into a consecutive minor space.
112  */
113 int
114 lminor(cdev_t dev)
115 {
116 	int y;
117 
118 	if (dev == NULL)
119 		return NOUDEV;
120 	y = dev->si_uminor;
121 	if (y & 0x0000ff00)
122 		return NOUDEV;
123 	return ((y & 0xff) | (y >> 8));
124 }
125 
126 /*
127  * This is a bit complex because devices are always created relative to
128  * a particular cdevsw, including 'hidden' cdevsw's (such as the raw device
129  * backing a disk subsystem overlay), so we have to compare both the
130  * devsw and udev fields to locate the correct device.
131  *
132  * The device is created if it does not already exist.  If SI_ADHOC is not
133  * set the device will be referenced (once) and SI_ADHOC will be set.
134  * The caller must explicitly add additional references to the device if
135  * the caller wishes to track additional references.
136  *
137  * NOTE: The passed ops vector must normally match the device.  This is
138  * because the kernel may create shadow devices that are INVISIBLE TO
139  * USERLAND.  For example, the block device backing a disk is created
140  * as a shadow underneath the user-visible disklabel management device.
141  * Sometimes a device ops vector can be overridden, such as by /dev/console.
142  * In this case and this case only we allow a match when the ops vector
143  * otherwise would not match.
144  */
145 static
146 int
147 __devthash(int x, int y)
148 {
149 	return(((x << 2) ^ y) & (DEVT_HASH - 1));
150 }
151 
152 static
153 cdev_t
154 hashdev(struct dev_ops *ops, int x, int y, int allow_intercept)
155 {
156 	struct cdev *si;
157 	int hash;
158 
159 	hash = __devthash(x, y);
160 	LIST_FOREACH(si, &dev_hash[hash], si_hash) {
161 		if (si->si_umajor == x && si->si_uminor == y) {
162 			if (si->si_ops == ops)
163 				return (si);
164 			if (allow_intercept && (si->si_flags & SI_INTERCEPTED))
165 				return (si);
166 		}
167 	}
168 	si = sysref_alloc(&cdev_sysref_class);
169 	si->si_ops = ops;
170 	si->si_flags |= SI_HASHED | SI_ADHOC;
171 	si->si_umajor = x;
172 	si->si_uminor = y;
173 	si->si_inode = 0;
174 	LIST_INSERT_HEAD(&dev_hash[hash], si, si_hash);
175 	sysref_activate(&si->si_sysref);
176 
177 	dev_dclone(si);
178 	if (ops != &dead_dev_ops)
179 		++ops->head.refs;
180 	if (dev_ref_debug) {
181 		kprintf("create    dev %p %s(minor=%08x) refs=%d\n",
182 			si, devtoname(si), y,
183 			si->si_sysref.refcnt);
184 	}
185         return (si);
186 }
187 
188 /*
189  * Convert a device pointer to an old style device number.  Return NOUDEV
190  * if the device is invalid or if the device (maj,min) cannot be converted
191  * to an old style udev_t.
192  */
193 udev_t
194 dev2udev(cdev_t dev)
195 {
196 	if (dev == NULL)
197 		return NOUDEV;
198 
199 	return (udev_t)dev->si_inode;
200 }
201 
202 /*
203  * Convert a device number to a device pointer.  The device is referenced
204  * ad-hoc, meaning that the caller should call reference_dev() if it wishes
205  * to keep ahold of the returned structure long term.
206  *
207  * The returned device is associated with the currently installed cdevsw
208  * for the requested major number.  NULL is returned if the major number
209  * has not been registered.
210  */
211 cdev_t
212 udev2dev(udev_t x, int b)
213 {
214 	if (x == NOUDEV || b != 0)
215 		return(NULL);
216 
217 	return devfs_find_device_by_udev(x);
218 }
219 
220 int
221 dev_is_good(cdev_t dev)
222 {
223 	if (dev != NULL && dev->si_ops != &dead_dev_ops)
224 		return(1);
225 	return(0);
226 }
227 
228 /*
229  * Various user device number extraction and conversion routines
230  */
231 int
232 uminor(udev_t dev)
233 {
234 	if (dev == NOUDEV)
235 		return(-1);
236 	return(dev & 0xffff00ff);
237 }
238 
239 int
240 umajor(udev_t dev)
241 {
242 	if (dev == NOUDEV)
243 		return(-1);
244 	return((dev & 0xff00) >> 8);
245 }
246 
247 udev_t
248 makeudev(int x, int y)
249 {
250 	if ((x & 0xffffff00) || (y & 0x0000ff00))
251 		return NOUDEV;
252         return ((x << 8) | y);
253 }
254 
255 /*
256  * Create an internal or external device.
257  *
258  * Device majors can be overloaded and used directly by the kernel without
259  * conflict, but userland will only see the particular device major that
260  * has been installed with dev_ops_add().
261  *
262  * This routine creates and returns an unreferenced ad-hoc entry for the
263  * device which will remain intact until the device is destroyed.  If the
264  * caller intends to store the device pointer it must call reference_dev()
265  * to retain a real reference to the device.
266  *
267  * If an entry already exists, this function will set (or override)
268  * its cred requirements and name (XXX DEVFS interface).
269  */
270 cdev_t
271 make_dev(struct dev_ops *ops, int minor, uid_t uid, gid_t gid,
272 	int perms, const char *fmt, ...)
273 {
274 	cdev_t	devfs_dev;
275 	__va_list ap;
276 	int i;
277 	char dev_name[PATH_MAX+1];
278 
279 	/*
280 	 * compile the cdevsw and install the device
281 	 */
282 	compile_dev_ops(ops);
283 
284 	/*
285 	 * Set additional fields (XXX DEVFS interface goes here)
286 	 */
287 	__va_start(ap, fmt);
288 	i = kvcprintf(fmt, NULL, dev_name, 32, ap);
289 	dev_name[i] = '\0';
290 	__va_end(ap);
291 
292 /*
293 	if ((devfs_dev = devfs_find_device_by_name(dev_name)) != NULL) {
294 		kprintf("make_dev: Device %s already exists, returning old dev without creating new node\n", dev_name);
295 		return devfs_dev;
296 	}
297 */
298 
299 	devfs_dev = devfs_new_cdev(ops, minor);
300 	memcpy(devfs_dev->si_name, dev_name, i+1);
301 
302 	devfs_debug(DEVFS_DEBUG_INFO, "make_dev called for %s\n", devfs_dev->si_name);
303 	devfs_create_dev(devfs_dev, uid, gid, perms);
304 
305 	return (devfs_dev);
306 }
307 
308 
309 cdev_t
310 make_only_devfs_dev(struct dev_ops *ops, int minor, uid_t uid, gid_t gid,
311 	int perms, const char *fmt, ...)
312 {
313 	cdev_t	devfs_dev;
314 	__va_list ap;
315 	int i;
316 	//char *dev_name;
317 
318 	/*
319 	 * compile the cdevsw and install the device
320 	 */
321 	compile_dev_ops(ops);
322 	devfs_dev = devfs_new_cdev(ops, minor);
323 
324 	/*
325 	 * Set additional fields (XXX DEVFS interface goes here)
326 	 */
327 	__va_start(ap, fmt);
328 	i = kvcprintf(fmt, NULL, devfs_dev->si_name, 32, ap);
329 	devfs_dev->si_name[i] = '\0';
330 	__va_end(ap);
331 
332 
333 	devfs_create_dev(devfs_dev, uid, gid, perms);
334 
335 	return (devfs_dev);
336 }
337 
338 
339 cdev_t
340 make_only_dev(struct dev_ops *ops, int minor, uid_t uid, gid_t gid,
341 	int perms, const char *fmt, ...)
342 {
343 	cdev_t	devfs_dev;
344 	__va_list ap;
345 	int i;
346 	//char *dev_name;
347 
348 	/*
349 	 * compile the cdevsw and install the device
350 	 */
351 	compile_dev_ops(ops);
352 	devfs_dev = devfs_new_cdev(ops, minor);
353 	devfs_dev->si_perms = perms;
354 	devfs_dev->si_uid = uid;
355 	devfs_dev->si_gid = gid;
356 
357 	/*
358 	 * Set additional fields (XXX DEVFS interface goes here)
359 	 */
360 	__va_start(ap, fmt);
361 	i = kvcprintf(fmt, NULL, devfs_dev->si_name, 32, ap);
362 	devfs_dev->si_name[i] = '\0';
363 	__va_end(ap);
364 
365 	reference_dev(devfs_dev);
366 
367 	return (devfs_dev);
368 }
369 
370 void
371 destroy_only_dev(cdev_t dev)
372 {
373 	devfs_destroy_cdev(dev);
374 }
375 
376 
377 /*
378  * This function is similar to make_dev() but no cred information or name
379  * need be specified.
380  */
381 cdev_t
382 make_adhoc_dev(struct dev_ops *ops, int minor)
383 {
384 	cdev_t dev;
385 
386 	dev = hashdev(ops, ops->head.maj, minor, FALSE);
387 	return(dev);
388 }
389 
390 /*
391  * This function is similar to make_dev() except the new device is created
392  * using an old device as a template.
393  */
394 cdev_t
395 make_sub_dev(cdev_t odev, int minor)
396 {
397 	cdev_t	dev;
398 
399 	dev = hashdev(odev->si_ops, odev->si_umajor, minor, FALSE);
400 
401 	/*
402 	 * Copy cred requirements and name info XXX DEVFS.
403 	 */
404 	if (dev->si_name[0] == 0 && odev->si_name[0])
405 		bcopy(odev->si_name, dev->si_name, sizeof(dev->si_name));
406 	return (dev);
407 }
408 
409 cdev_t
410 get_dev(int x, int y)
411 {
412 	cdev_t dev;
413 	struct dev_ops *ops;
414 
415 	if (x == NOUDEV)
416 		return(NULL);
417 	ops = dev_ops_get(x, y);
418 	if (ops == NULL)
419 		return(NULL);
420 	dev = hashdev(ops, x, y, TRUE);
421 	return(dev);
422 }
423 
424 /*
425  * destroy_dev() removes the adhoc association for a device and revectors
426  * its ops to &dead_dev_ops.
427  *
428  * This routine releases the reference count associated with the ADHOC
429  * entry, plus releases the reference count held by the caller.  What this
430  * means is that you should not call destroy_dev(make_dev(...)), because
431  * make_dev() does not bump the reference count (beyond what it needs to
432  * create the ad-hoc association).  Any procedure that intends to destroy
433  * a device must have its own reference to it first.
434  */
435 void
436 destroy_dev(cdev_t dev)
437 {
438 	int hash;
439 
440 	if (dev == NULL)
441 		return;
442 
443 	devfs_debug(DEVFS_DEBUG_DEBUG, "destroy_dev called for %s\n", dev->si_name);
444 	devfs_destroy_dev(dev);
445 
446 	return;
447 
448 	if ((dev->si_flags & SI_ADHOC) == 0) {
449 		release_dev(dev);
450 		return;
451 	}
452 	if (dev_ref_debug) {
453 		kprintf("destroy   dev %p %s(minor=%08x) refs=%d\n",
454 			dev, devtoname(dev), dev->si_uminor,
455 			dev->si_sysref.refcnt);
456 	}
457 	if (dev->si_sysref.refcnt < 2) {
458 		kprintf("destroy_dev(): too few references on device! "
459 			"%p %s(minor=%08x) refs=%d\n",
460 		    dev, devtoname(dev), dev->si_uminor,
461 		    dev->si_sysref.refcnt);
462 	}
463 	dev->si_flags &= ~SI_ADHOC;
464 	if (dev->si_flags & SI_HASHED) {
465 		hash = __devthash(dev->si_umajor, dev->si_uminor);
466 		LIST_REMOVE(dev, si_hash);
467 		dev->si_flags &= ~SI_HASHED;
468 	}
469 
470 	/*
471 	 * We have to release the ops reference before we replace the
472 	 * device switch with dead_dev_ops.
473 	 */
474 
475 
476 	if (dead_dev_ops.d_strategy == NULL)
477 		compile_dev_ops(&dead_dev_ops);
478 	if (dev->si_ops && dev->si_ops != &dead_dev_ops)
479 		dev_ops_release(dev->si_ops);
480 	dev->si_drv1 = NULL;
481 	dev->si_drv2 = NULL;
482 	dev->si_ops = &dead_dev_ops;
483 	sysref_put(&dev->si_sysref);	/* release adhoc association */
484 
485 	release_dev(dev);		/* release callers reference */
486 }
487 
488 /*
489  * Destroy all ad-hoc device associations associated with a domain within a
490  * device switch.  Only the minor numbers are included in the mask/match
491  * values.
492  *
493  * Unlike the ops functions whos link structures do not contain
494  * any major bits, this function scans through the dev list via
495  * si_umajor/si_uminor.
496  *
497  * The caller must not include any major bits in the match value.
498  */
499 void
500 destroy_all_devs(struct dev_ops *ops, u_int mask, u_int match)
501 {
502 	int i;
503 	cdev_t dev;
504 	cdev_t ndev;
505 
506 	for (i = 0; i < DEVT_HASH; ++i) {
507 		ndev = LIST_FIRST(&dev_hash[i]);
508 		while ((dev = ndev) != NULL) {
509 		    ndev = LIST_NEXT(dev, si_hash);
510 		    if (dev->si_ops == ops &&
511 			((u_int)dev->si_uminor & mask) == match
512 		    ) {
513 			KKASSERT(dev->si_flags & SI_ADHOC);
514 			reference_dev(dev);
515 			destroy_dev(dev);
516 		    }
517 		}
518 	}
519 }
520 
521 
522 int
523 make_dev_alias(cdev_t target, const char *fmt, ...)
524 {
525 	char name[PATH_MAX + 1];
526 	__va_list ap;
527 	int i;
528 
529 	__va_start(ap, fmt);
530 	i = kvcprintf(fmt, NULL, name, 32, ap);
531 	name[i] = '\0';
532 	__va_end(ap);
533 
534 	devfs_make_alias(name, target);
535 
536 	return 0;
537 }
538 
539 
540 /*
541  * Add a reference to a device.  Callers generally add their own references
542  * when they are going to store a device node in a variable for long periods
543  * of time, to prevent a disassociation from free()ing the node.
544  *
545  * Also note that a caller that intends to call destroy_dev() must first
546  * obtain a reference on the device.  The ad-hoc reference you get with
547  * make_dev() and friends is NOT sufficient to be able to call destroy_dev().
548  */
549 cdev_t
550 reference_dev(cdev_t dev)
551 {
552 	//kprintf("reference_dev\n");
553 
554 	if (dev != NULL) {
555 		sysref_get(&dev->si_sysref);
556 		if (dev_ref_debug) {
557 			kprintf("reference dev %p %s(minor=%08x) refs=%d\n",
558 			    dev, devtoname(dev), dev->si_uminor,
559 			    dev->si_sysref.refcnt);
560 		}
561 	}
562 	return(dev);
563 }
564 
565 /*
566  * release a reference on a device.  The device will be terminated when the
567  * last reference has been released.
568  *
569  * NOTE: we must use si_umajor to figure out the original major number,
570  * because si_ops could already be pointing at dead_dev_ops.
571  */
572 void
573 release_dev(cdev_t dev)
574 {
575 	//kprintf("release_dev\n");
576 
577 	if (dev == NULL)
578 		return;
579 	sysref_put(&dev->si_sysref);
580 }
581 
582 static
583 void
584 cdev_terminate(struct cdev *dev)
585 {
586 	int messedup = 0;
587 
588 	if (dev_ref_debug) {
589 		kprintf("release   dev %p %s(minor=%08x) refs=%d\n",
590 			dev, devtoname(dev), dev->si_uminor,
591 			dev->si_sysref.refcnt);
592 	}
593 	if (dev->si_flags & SI_ADHOC) {
594 		kprintf("Warning: illegal final release on ADHOC"
595 			" device %p(%s), the device was never"
596 			" destroyed!\n",
597 			dev, devtoname(dev));
598 		messedup = 1;
599 	}
600 	if (dev->si_flags & SI_HASHED) {
601 		kprintf("Warning: last release on device, no call"
602 			" to destroy_dev() was made! dev %p(%s)\n",
603 			dev, devtoname(dev));
604 		reference_dev(dev);
605 		destroy_dev(dev);
606 		messedup = 1;
607 	}
608 	if (SLIST_FIRST(&dev->si_hlist) != NULL) {
609 		kprintf("Warning: last release on device, vnode"
610 			" associations still exist! dev %p(%s)\n",
611 			dev, devtoname(dev));
612 		messedup = 1;
613 	}
614 	if (dev->si_ops && dev->si_ops != &dead_dev_ops) {
615 		dev_ops_release(dev->si_ops);
616 		dev->si_ops = NULL;
617 	}
618 	if (messedup == 0)
619 		sysref_put(&dev->si_sysref);
620 }
621 
622 const char *
623 devtoname(cdev_t dev)
624 {
625 	int mynor;
626 	int len;
627 	char *p;
628 	const char *dname;
629 
630 	if (dev == NULL)
631 		return("#nodev");
632 	if (dev->si_name[0] == '#' || dev->si_name[0] == '\0') {
633 		p = dev->si_name;
634 		len = sizeof(dev->si_name);
635 		if ((dname = dev_dname(dev)) != NULL)
636 			ksnprintf(p, len, "#%s/", dname);
637 		else
638 			ksnprintf(p, len, "#%d/", major(dev));
639 		len -= strlen(p);
640 		p += strlen(p);
641 		mynor = minor(dev);
642 		if (mynor < 0 || mynor > 255)
643 			ksnprintf(p, len, "%#x", (u_int)mynor);
644 		else
645 			ksnprintf(p, len, "%d", mynor);
646 	}
647 	return (dev->si_name);
648 }
649 
650