mtree/BSD.root.dist: Use spaces.
[dragonfly.git] / sys / kern / kern_conf.c
blobf6efd1034bd892b43dea82431f8d5daf6ab48fb4
1 /*-
2 * Parts Copyright (c) 1995 Terrence R. Lambert
3 * Copyright (c) 1995 Julian R. Elischer
4 * All rights reserved.
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.
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.
33 * $FreeBSD: src/sys/kern/kern_conf.c,v 1.73.2.3 2003/03/10 02:18:25 imp Exp $
36 #include <sys/param.h>
37 #include <sys/kernel.h>
38 #include <sys/sysctl.h>
39 #include <sys/systm.h>
40 #include <sys/module.h>
41 #include <sys/conf.h>
42 #include <sys/vnode.h>
43 #include <sys/queue.h>
44 #include <sys/device.h>
45 #include <sys/disk.h>
46 #include <machine/stdarg.h>
48 #include <sys/sysref2.h>
50 #include <sys/devfs.h>
52 int dev_ref_debug = 0;
53 SYSCTL_INT(_debug, OID_AUTO, dev_refs, CTLFLAG_RW, &dev_ref_debug, 0,
54 "Toggle device reference debug output");
57 * cdev_t and u_dev_t primitives. Note that the major number is always
58 * extracted from si_umajor, not from si_devsw, because si_devsw is replaced
59 * when a device is destroyed.
61 int
62 major(cdev_t dev)
64 if (dev == NULL)
65 return NOUDEV;
66 return(dev->si_umajor);
69 int
70 minor(cdev_t dev)
72 if (dev == NULL)
73 return NOUDEV;
74 return(dev->si_uminor);
78 * Compatibility function with old udev_t format to convert the
79 * non-consecutive minor space into a consecutive minor space.
81 int
82 lminor(cdev_t dev)
84 int y;
86 if (dev == NULL)
87 return NOUDEV;
88 y = dev->si_uminor;
89 if (y & 0x0000ff00)
90 return NOUDEV;
91 return ((y & 0xff) | (y >> 8));
95 * Convert a device pointer to an old style device number. Return NOUDEV
96 * if the device is invalid or if the device (maj,min) cannot be converted
97 * to an old style udev_t.
99 udev_t
100 dev2udev(cdev_t dev)
102 if (dev == NULL)
103 return NOUDEV;
105 return (udev_t)dev->si_inode;
109 * Convert a device number to a device pointer. The device is referenced
110 * ad-hoc, meaning that the caller should call reference_dev() if it wishes
111 * to keep ahold of the returned structure long term.
113 * The returned device is associated with the currently installed cdevsw
114 * for the requested major number. NULL is returned if the major number
115 * has not been registered.
117 cdev_t
118 udev2dev(udev_t x, int b)
120 if (x == NOUDEV || b != 0)
121 return(NULL);
123 return devfs_find_device_by_udev(x);
127 dev_is_good(cdev_t dev)
129 if (dev != NULL && dev->si_ops != &dead_dev_ops)
130 return(1);
131 return(0);
135 * Various user device number extraction and conversion routines
138 uminor(udev_t dev)
140 if (dev == NOUDEV)
141 return(-1);
142 return(dev & 0xffff00ff);
146 umajor(udev_t dev)
148 if (dev == NOUDEV)
149 return(-1);
150 return((dev & 0xff00) >> 8);
153 udev_t
154 makeudev(int x, int y)
156 if ((x & 0xffffff00) || (y & 0x0000ff00))
157 return NOUDEV;
158 return ((x << 8) | y);
162 * Put a NUL-terminated ASCII number (base == 32) for use as device suffix.
163 * The buffer pointed to by `nbuf' must have length >= MAKEDEV_MINNBUF.
165 char *
166 makedev_unit_b32(char *nbuf, uintmax_t num)
168 char *p = &nbuf[MAKEDEV_MINNBUF - 1];
170 *p = '\0';
171 do {
172 *--p = hex2ascii(num % 32);
173 } while (num /= 32);
174 return (p);
178 * Create an internal or external device.
180 * This routine creates and returns an unreferenced ad-hoc entry for the
181 * device which will remain intact until the device is destroyed. If the
182 * caller intends to store the device pointer it must call reference_dev()
183 * to retain a real reference to the device.
185 * If an entry already exists, this function will set (or override)
186 * its cred requirements and name (XXX DEVFS interface).
188 cdev_t
189 make_dev(struct dev_ops *ops, int minor, uid_t uid, gid_t gid,
190 int perms, const char *fmt, ...)
192 cdev_t devfs_dev;
193 __va_list ap;
196 * compile the cdevsw and install the device
198 compile_dev_ops(ops);
200 devfs_dev = devfs_new_cdev(ops, minor, NULL);
201 __va_start(ap, fmt);
202 kvsnprintf(devfs_dev->si_name, sizeof(devfs_dev->si_name), fmt, ap);
203 __va_end(ap);
205 devfs_debug(DEVFS_DEBUG_INFO,
206 "make_dev called for %s\n",
207 devfs_dev->si_name);
208 devfs_create_dev(devfs_dev, uid, gid, perms);
210 return (devfs_dev);
214 * make_dev_covering has equivalent functionality to make_dev, except that it
215 * also takes the dev_ops of the underlying device. Hence this function should
216 * only be used by systems and drivers which create devices covering others
218 cdev_t
219 make_dev_covering(struct dev_ops *ops, struct dev_ops *bops, int minor,
220 uid_t uid, gid_t gid, int perms, const char *fmt, ...)
222 cdev_t devfs_dev;
223 __va_list ap;
226 * compile the cdevsw and install the device
228 compile_dev_ops(ops);
230 devfs_dev = devfs_new_cdev(ops, minor, bops);
231 __va_start(ap, fmt);
232 kvsnprintf(devfs_dev->si_name, sizeof(devfs_dev->si_name), fmt, ap);
233 __va_end(ap);
235 devfs_debug(DEVFS_DEBUG_INFO,
236 "make_dev called for %s\n",
237 devfs_dev->si_name);
238 devfs_create_dev(devfs_dev, uid, gid, perms);
240 return (devfs_dev);
245 cdev_t
246 make_only_devfs_dev(struct dev_ops *ops, int minor, uid_t uid, gid_t gid,
247 int perms, const char *fmt, ...)
249 cdev_t devfs_dev;
250 __va_list ap;
253 * compile the cdevsw and install the device
255 compile_dev_ops(ops);
256 devfs_dev = devfs_new_cdev(ops, minor, NULL);
259 * Set additional fields (XXX DEVFS interface goes here)
261 __va_start(ap, fmt);
262 kvsnprintf(devfs_dev->si_name, sizeof(devfs_dev->si_name), fmt, ap);
263 __va_end(ap);
265 devfs_create_dev(devfs_dev, uid, gid, perms);
267 return (devfs_dev);
270 cdev_t
271 make_only_dev(struct dev_ops *ops, int minor, uid_t uid, gid_t gid,
272 int perms, const char *fmt, ...)
274 cdev_t devfs_dev;
275 __va_list ap;
278 * compile the cdevsw and install the device
280 compile_dev_ops(ops);
281 devfs_dev = devfs_new_cdev(ops, minor, NULL);
282 devfs_dev->si_perms = perms;
283 devfs_dev->si_uid = uid;
284 devfs_dev->si_gid = gid;
287 * Set additional fields (XXX DEVFS interface goes here)
289 __va_start(ap, fmt);
290 kvsnprintf(devfs_dev->si_name, sizeof(devfs_dev->si_name), fmt, ap);
291 __va_end(ap);
293 reference_dev(devfs_dev);
295 return (devfs_dev);
298 cdev_t
299 make_only_dev_covering(struct dev_ops *ops, struct dev_ops *bops, int minor,
300 uid_t uid, gid_t gid, int perms, const char *fmt, ...)
302 cdev_t devfs_dev;
303 __va_list ap;
306 * compile the cdevsw and install the device
308 compile_dev_ops(ops);
309 devfs_dev = devfs_new_cdev(ops, minor, bops);
310 devfs_dev->si_perms = perms;
311 devfs_dev->si_uid = uid;
312 devfs_dev->si_gid = gid;
315 * Set additional fields (XXX DEVFS interface goes here)
317 __va_start(ap, fmt);
318 kvsnprintf(devfs_dev->si_name, sizeof(devfs_dev->si_name), fmt, ap);
319 __va_end(ap);
321 reference_dev(devfs_dev);
323 return (devfs_dev);
326 void
327 destroy_only_dev(cdev_t dev)
329 release_dev(dev);
330 release_dev(dev);
331 release_dev(dev);
335 * destroy_dev() removes the adhoc association for a device and revectors
336 * its ops to &dead_dev_ops.
338 * This routine releases the reference count associated with the ADHOC
339 * entry, plus releases the reference count held by the caller. What this
340 * means is that you should not call destroy_dev(make_dev(...)), because
341 * make_dev() does not bump the reference count (beyond what it needs to
342 * create the ad-hoc association). Any procedure that intends to destroy
343 * a device must have its own reference to it first.
345 void
346 destroy_dev(cdev_t dev)
348 if (dev) {
349 devfs_debug(DEVFS_DEBUG_DEBUG,
350 "destroy_dev called for %s\n",
351 dev->si_name);
352 devfs_destroy_dev(dev);
357 * Make sure all asynchronous disk and devfs related operations have
358 * completed.
360 * Typically called prior to mountroot to ensure that all disks have
361 * been completely probed and on module unload to ensure that ops
362 * structures have been dereferenced.
364 void
365 sync_devs(void)
367 disk_config(NULL);
368 devfs_config();
369 disk_config(NULL);
370 devfs_config();
374 make_dev_alias(cdev_t target, const char *fmt, ...)
376 __va_list ap;
377 char *name;
379 __va_start(ap, fmt);
380 kvasnprintf(&name, PATH_MAX, fmt, ap);
381 __va_end(ap);
383 devfs_make_alias(name, target);
384 kvasfree(&name);
386 return 0;
390 destroy_dev_alias(cdev_t target, const char *fmt, ...)
392 __va_list ap;
393 char *name;
395 __va_start(ap, fmt);
396 kvasnprintf(&name, PATH_MAX, fmt, ap);
397 __va_end(ap);
399 devfs_destroy_alias(name, target);
400 kvasfree(&name);
402 return 0;
405 extern struct dev_ops default_dev_ops;
407 cdev_t
408 make_autoclone_dev(struct dev_ops *ops, struct devfs_bitmap *bitmap,
409 d_clone_t *nhandler, uid_t uid, gid_t gid, int perms, const char *fmt, ...)
411 __va_list ap;
412 cdev_t dev;
413 char *name;
415 __va_start(ap, fmt);
416 kvasnprintf(&name, PATH_MAX, fmt, ap);
417 __va_end(ap);
419 if (bitmap != NULL)
420 devfs_clone_bitmap_init(bitmap);
422 devfs_clone_handler_add(name, nhandler);
423 dev = make_dev_covering(&default_dev_ops, ops, 0xffff00ff,
424 uid, gid, perms, "%s", name);
425 kvasfree(&name);
426 return dev;
429 void
430 destroy_autoclone_dev(cdev_t dev, struct devfs_bitmap *bitmap)
432 if (dev == NULL)
433 return;
435 devfs_clone_handler_del(dev->si_name);
437 if (bitmap != NULL)
438 devfs_clone_bitmap_uninit(bitmap);
440 destroy_dev(dev);
445 * Add a reference to a device. Callers generally add their own references
446 * when they are going to store a device node in a variable for long periods
447 * of time, to prevent a disassociation from free()ing the node.
449 * Also note that a caller that intends to call destroy_dev() must first
450 * obtain a reference on the device. The ad-hoc reference you get with
451 * make_dev() and friends is NOT sufficient to be able to call destroy_dev().
453 cdev_t
454 reference_dev(cdev_t dev)
456 //kprintf("reference_dev\n");
458 if (dev != NULL) {
459 sysref_get(&dev->si_sysref);
460 if (dev_ref_debug & 2) {
461 kprintf("reference dev %p %s(minor=%08x) refs=%d\n",
462 dev, devtoname(dev), dev->si_uminor,
463 dev->si_sysref.refcnt);
466 return(dev);
470 * release a reference on a device. The device will be terminated when the
471 * last reference has been released.
473 * NOTE: we must use si_umajor to figure out the original major number,
474 * because si_ops could already be pointing at dead_dev_ops.
476 void
477 release_dev(cdev_t dev)
479 //kprintf("release_dev\n");
481 if (dev == NULL)
482 return;
483 sysref_put(&dev->si_sysref);
486 const char *
487 devtoname(cdev_t dev)
489 int mynor;
490 int len;
491 char *p;
492 const char *dname;
494 if (dev == NULL)
495 return("#nodev");
496 if (dev->si_name[0] == '#' || dev->si_name[0] == '\0') {
497 p = dev->si_name;
498 len = sizeof(dev->si_name);
499 if ((dname = dev_dname(dev)) != NULL)
500 ksnprintf(p, len, "#%s/", dname);
501 else
502 ksnprintf(p, len, "#%d/", major(dev));
503 len -= strlen(p);
504 p += strlen(p);
505 mynor = minor(dev);
506 if (mynor < 0 || mynor > 255)
507 ksnprintf(p, len, "%#x", (u_int)mynor);
508 else
509 ksnprintf(p, len, "%d", mynor);
511 return (dev->si_name);