kern_conf.c revision 110060
118334Speter/*- 272566Sobrien * Copyright (c) 1999-2002 Poul-Henning Kamp 390282Sobrien * All rights reserved. 418334Speter * 590282Sobrien * Redistribution and use in source and binary forms, with or without 618334Speter * modification, are permitted provided that the following conditions 790282Sobrien * are met: 890282Sobrien * 1. Redistributions of source code must retain the above copyright 990282Sobrien * notice, this list of conditions and the following disclaimer. 1090282Sobrien * 2. Redistributions in binary form must reproduce the above copyright 1118334Speter * notice, this list of conditions and the following disclaimer in the 1290282Sobrien * documentation and/or other materials provided with the distribution. 1390282Sobrien * 1490282Sobrien * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 1590282Sobrien * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1618334Speter * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 1718334Speter * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 1890282Sobrien * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 1990282Sobrien * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2090282Sobrien * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2118334Speter * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2252558Sobrien * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2352558Sobrien * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2418334Speter * SUCH DAMAGE. 2518334Speter * 2618334Speter * $FreeBSD: head/sys/kern/kern_conf.c 110060 2003-01-29 21:54:03Z phk $ 2718334Speter */ 2818334Speter 2918334Speter#include <sys/param.h> 3050615Sobrien#include <sys/kernel.h> 3150615Sobrien#include <sys/systm.h> 3250615Sobrien#include <sys/lock.h> 3318334Speter#include <sys/mutex.h> 3418334Speter#include <sys/sysctl.h> 3518334Speter#include <sys/module.h> 3650615Sobrien#include <sys/malloc.h> 3750615Sobrien#include <sys/conf.h> 3818334Speter#include <sys/vnode.h> 3950615Sobrien#include <sys/queue.h> 4050615Sobrien#include <sys/ctype.h> 4150615Sobrien#include <machine/stdarg.h> 4218334Speter 4318334Speterstatic MALLOC_DEFINE(M_DEVT, "dev_t", "dev_t storage"); 4418334Speter 4518334Speter/* 4618334Speter * This is the number of hash-buckets. Experiements with 'real-life' 4790282Sobrien * udev_t's show that a prime halfway between two powers of two works 4818334Speter * best. 4918334Speter */ 5050615Sobrien#define DEVT_HASH 83 5190282Sobrien 5290282Sobrien/* The number of dev_t's we can create before malloc(9) kick in. */ 5350615Sobrien#define DEVT_STASH 50 5418334Speter 5550615Sobrienstatic struct cdev devt_stash[DEVT_STASH]; 5690282Sobrien 5750615Sobrienstatic LIST_HEAD(, cdev) dev_hash[DEVT_HASH]; 5852558Sobrien 5952558Sobrienstatic LIST_HEAD(, cdev) dev_free; 6052558Sobrien 6190282Sobriendevfs_create_t *devfs_create_hook; 6290282Sobriendevfs_destroy_t *devfs_destroy_hook; 6390282Sobrien 6490282Sobrienstatic int ready_for_devs; 6590282Sobrien 6690282Sobrienstatic int free_devt; 6790282SobrienSYSCTL_INT(_debug, OID_AUTO, free_devt, CTLFLAG_RW, &free_devt, 0, ""); 6890282Sobrien 6990282Sobrien#ifdef NO_GEOM 7090282Sobrien/* XXX: This is a hack */ 7190282Sobrienvoid disk_dev_synth(dev_t dev); 7290282Sobrien#endif 7390282Sobrien 7490282Sobrienstruct cdevsw * 7518334Speterdevsw(dev_t dev) 7650615Sobrien{ 7750615Sobrien if (dev->si_devsw) 7850615Sobrien return (dev->si_devsw); 7950615Sobrien#ifdef NO_GEOM 8050615Sobrien /* XXX: Hack around our backwards disk code */ 8150615Sobrien disk_dev_synth(dev); 8250615Sobrien#endif 8350615Sobrien if (dev->si_devsw) 8450615Sobrien return (dev->si_devsw); 8550615Sobrien return (NULL); 8650615Sobrien} 8750615Sobrien 8818334Speter/* 8990282Sobrien * Add a cdevsw entry 9090282Sobrien */ 9118334Speter 9290282Sobrienint 9390282Sobriencdevsw_add(struct cdevsw *newentry) 9490282Sobrien{ 9590282Sobrien 9618334Speter return (0); 9718334Speter} 9818334Speter 9918334Speter/* 10018334Speter * Remove a cdevsw entry 10118334Speter */ 10218334Speter 10390282Sobrienint 10490282Sobriencdevsw_remove(struct cdevsw *oldentry) 10590282Sobrien{ 10690282Sobrien 10790282Sobrien return 0; 10890282Sobrien} 10990282Sobrien 11090282Sobrien/* 11118334Speter * dev_t and u_dev_t primitives 11290282Sobrien */ 11390282Sobrien 11450615Sobrienint 11590282Sobrienmajor(dev_t x) 11690282Sobrien{ 11790282Sobrien if (x == NODEV) 11890282Sobrien return NOUDEV; 11990282Sobrien return((x->si_udev >> 8) & 0xff); 12090282Sobrien} 12118334Speter 12290282Sobrienint 12390282Sobrienminor(dev_t x) 12490282Sobrien{ 12590282Sobrien if (x == NODEV) 12690282Sobrien return NOUDEV; 12790282Sobrien return(x->si_udev & 0xffff00ff); 12890282Sobrien} 12990282Sobrien 13052558Sobrienint 13152558Sobriendev2unit(dev_t x) 13290282Sobrien{ 13352558Sobrien int i; 13452558Sobrien 13550615Sobrien if (x == NODEV) 13650615Sobrien return NOUDEV; 13718334Speter i = minor(x); 13818334Speter return ((i & 0xff) | (i >> 8)); 13918334Speter} 14090282Sobrien 14118334Speterint 14290282Sobrienunit2minor(int unit) 14318334Speter{ 14418334Speter 14518334Speter KASSERT(unit <= 0xffffff, ("Invalid unit (%d) in unit2minor", unit)); 14618334Speter return ((unit & 0xff) | ((unit << 8) & ~0xffff)); 14718334Speter} 14818334Speter 14990282Sobrienstatic dev_t 15018334Speterallocdev(void) 15118334Speter{ 15218334Speter static int stashed; 15318334Speter struct cdev *si; 15418334Speter 15590282Sobrien if (LIST_FIRST(&dev_free)) { 15618334Speter si = LIST_FIRST(&dev_free); 15718334Speter LIST_REMOVE(si, si_hash); 15818334Speter } else if (stashed >= DEVT_STASH) { 15918334Speter MALLOC(si, struct cdev *, sizeof(*si), M_DEVT, 16018334Speter M_USE_RESERVE | M_ZERO); 16152558Sobrien } else { 16252558Sobrien si = devt_stash + stashed++; 16352558Sobrien bzero(si, sizeof *si); 16418334Speter si->si_flags |= SI_STASHED; 16518334Speter } 16618334Speter LIST_INIT(&si->si_children); 16718334Speter TAILQ_INIT(&si->si_snapshots); 16818334Speter return (si); 16918334Speter} 17018334Speter 17118334Speterdev_t 17218334Spetermakedev(int x, int y) 17352558Sobrien{ 17418334Speter struct cdev *si; 17590282Sobrien udev_t udev; 17690282Sobrien int hash; 17790282Sobrien 17890282Sobrien if (x == umajor(NOUDEV) && y == uminor(NOUDEV)) 17990282Sobrien panic("makedev of NOUDEV"); 18018334Speter udev = (x << 8) | y; 18118334Speter hash = udev % DEVT_HASH; 18218334Speter LIST_FOREACH(si, &dev_hash[hash], si_hash) { 18318334Speter if (si->si_udev == udev) 18418334Speter return (si); 18518334Speter } 18690282Sobrien si = allocdev(); 18718334Speter si->si_udev = udev; 18890282Sobrien LIST_INSERT_HEAD(&dev_hash[hash], si, si_hash); 18990282Sobrien return (si); 19090282Sobrien} 19190282Sobrien 19290282Sobrienvoid 19390282Sobrienfreedev(dev_t dev) 19490282Sobrien{ 19590282Sobrien 19690282Sobrien if (!free_devt) 19790282Sobrien return; 19890282Sobrien if (SLIST_FIRST(&dev->si_hlist)) 19990282Sobrien return; 20090282Sobrien if (dev->si_devsw || dev->si_drv1 || dev->si_drv2) 20190282Sobrien return; 20290282Sobrien LIST_REMOVE(dev, si_hash); 20390282Sobrien if (dev->si_flags & SI_STASHED) { 20490282Sobrien bzero(dev, sizeof(*dev)); 20590282Sobrien dev->si_flags |= SI_STASHED; 20690282Sobrien LIST_INSERT_HEAD(&dev_free, dev, si_hash); 20790282Sobrien } else { 20890282Sobrien FREE(dev, M_DEVT); 20990282Sobrien } 21090282Sobrien} 21190282Sobrien 21290282Sobrienudev_t 21390282Sobriendev2udev(dev_t x) 21490282Sobrien{ 21590282Sobrien if (x == NODEV) 21690282Sobrien return NOUDEV; 21790282Sobrien return (x->si_udev); 21890282Sobrien} 21990282Sobrien 22090282Sobriendev_t 22190282Sobrienudev2dev(udev_t x, int b) 22290282Sobrien{ 22390282Sobrien 22490282Sobrien if (x == NOUDEV) 22590282Sobrien return (NODEV); 22690282Sobrien switch (b) { 22790282Sobrien case 0: 22890282Sobrien return makedev(umajor(x), uminor(x)); 22990282Sobrien case 1: 23090282Sobrien return (NODEV); 23190282Sobrien default: 23290282Sobrien Debugger("udev2dev(...,X)"); 23390282Sobrien return NODEV; 23490282Sobrien } 23590282Sobrien} 23690282Sobrien 23790282Sobrienint 23890282Sobrienuminor(udev_t dev) 23990282Sobrien{ 24090282Sobrien return(dev & 0xffff00ff); 24190282Sobrien} 24290282Sobrien 24390282Sobrienint 24490282Sobrienumajor(udev_t dev) 24590282Sobrien{ 24690282Sobrien return((dev & 0xff00) >> 8); 24790282Sobrien} 24890282Sobrien 24990282Sobrienudev_t 25090282Sobrienmakeudev(int x, int y) 25190282Sobrien{ 25290282Sobrien return ((x << 8) | y); 25390282Sobrien} 25490282Sobrien 25590282Sobriendev_t 25690282Sobrienmake_dev(struct cdevsw *devsw, int minor, uid_t uid, gid_t gid, int perms, const char *fmt, ...) 25790282Sobrien{ 25890282Sobrien dev_t dev; 25990282Sobrien va_list ap; 26090282Sobrien int i; 26190282Sobrien 26290282Sobrien KASSERT(umajor(makeudev(devsw->d_maj, minor)) == devsw->d_maj, 26390282Sobrien ("Invalid minor (%d) in make_dev", minor)); 26490282Sobrien 26590282Sobrien if (!ready_for_devs) { 26690282Sobrien printf("WARNING: Driver mistake: make_dev(%s) called before SI_SUB_DRIVERS\n", 26790282Sobrien fmt); 26890282Sobrien /* XXX panic here once drivers are cleaned up */ 26990282Sobrien } 27090282Sobrien 27190282Sobrien dev = makedev(devsw->d_maj, minor); 27290282Sobrien if (dev->si_flags & SI_NAMED) { 27390282Sobrien printf( "WARNING: Driver mistake: repeat make_dev(\"%s\")\n", 27490282Sobrien dev->si_name); 27590282Sobrien panic("don't do that"); 27690282Sobrien return (dev); 27790282Sobrien } 27890282Sobrien va_start(ap, fmt); 27990282Sobrien i = kvprintf(fmt, NULL, dev->si_name, 32, ap); 28090282Sobrien dev->si_name[i] = '\0'; 28190282Sobrien va_end(ap); 28290282Sobrien dev->si_devsw = devsw; 28390282Sobrien dev->si_uid = uid; 28490282Sobrien dev->si_gid = gid; 28590282Sobrien dev->si_mode = perms; 28690282Sobrien dev->si_flags |= SI_NAMED; 28790282Sobrien 28890282Sobrien if (devfs_create_hook) 28990282Sobrien devfs_create_hook(dev); 29090282Sobrien return (dev); 29190282Sobrien} 29290282Sobrien 29390282Sobrienint 29490282Sobriendev_named(dev_t pdev, const char *name) 29590282Sobrien{ 29690282Sobrien dev_t cdev; 29790282Sobrien 29890282Sobrien if (strcmp(devtoname(pdev), name) == 0) 29990282Sobrien return (1); 30090282Sobrien LIST_FOREACH(cdev, &pdev->si_children, si_siblings) 30190282Sobrien if (strcmp(devtoname(cdev), name) == 0) 30290282Sobrien return (1); 30390282Sobrien return (0); 30452558Sobrien} 30518334Speter 30618334Spetervoid 30718334Speterdev_depends(dev_t pdev, dev_t cdev) 30818334Speter{ 30918334Speter 31018334Speter cdev->si_parent = pdev; 31118334Speter cdev->si_flags |= SI_CHILD; 31218334Speter LIST_INSERT_HEAD(&pdev->si_children, cdev, si_siblings); 31318334Speter} 31418334Speter 31518334Speterdev_t 31618334Spetermake_dev_alias(dev_t pdev, const char *fmt, ...) 31718334Speter{ 31818334Speter dev_t dev; 31918334Speter va_list ap; 32018334Speter int i; 32118334Speter 32218334Speter dev = allocdev(); 32318334Speter dev->si_flags |= SI_ALIAS; 32418334Speter dev->si_flags |= SI_NAMED; 32518334Speter dev_depends(pdev, dev); 32618334Speter va_start(ap, fmt); 32718334Speter i = kvprintf(fmt, NULL, dev->si_name, 32, ap); 32818334Speter dev->si_name[i] = '\0'; 32918334Speter va_end(ap); 33018334Speter 33118334Speter if (devfs_create_hook) 33218334Speter devfs_create_hook(dev); 33318334Speter return (dev); 33418334Speter} 33518334Speter 33618334Spetervoid 33718334Speterrevoke_and_destroy_dev(dev_t dev) 33850615Sobrien{ 33950615Sobrien struct vnode *vp; 34050615Sobrien 34150615Sobrien GIANT_REQUIRED; 34250615Sobrien 34350615Sobrien vp = SLIST_FIRST(&dev->si_hlist); 34450615Sobrien if (vp != NULL) 34590282Sobrien VOP_REVOKE(vp, REVOKEALL); 34690282Sobrien destroy_dev(dev); 34718334Speter} 34890282Sobrien 34990282Sobrienvoid 35090282Sobriendestroy_dev(dev_t dev) 35118334Speter{ 35290282Sobrien 35390282Sobrien if (!(dev->si_flags & SI_NAMED)) { 35490282Sobrien printf( "WARNING: Driver mistake: destroy_dev on %d/%d\n", 35590282Sobrien major(dev), minor(dev)); 35650615Sobrien panic("don't do that"); 35750615Sobrien return; 35850615Sobrien } 35950615Sobrien 36050615Sobrien if (devfs_destroy_hook) 36150615Sobrien devfs_destroy_hook(dev); 36250615Sobrien if (dev->si_flags & SI_CHILD) { 36318334Speter LIST_REMOVE(dev, si_siblings); 36490282Sobrien dev->si_flags &= ~SI_CHILD; 36518334Speter } 36618334Speter while (!LIST_EMPTY(&dev->si_children)) 36718334Speter destroy_dev(LIST_FIRST(&dev->si_children)); 36852558Sobrien dev->si_drv1 = 0; 36990282Sobrien dev->si_drv2 = 0; 37052558Sobrien dev->si_devsw = 0; 37118334Speter bzero(&dev->__si_u, sizeof(dev->__si_u)); 37252558Sobrien dev->si_flags &= ~SI_NAMED; 37352558Sobrien dev->si_flags &= ~SI_ALIAS; 37418334Speter freedev(dev); 37518334Speter} 37618334Speter 37790282Sobrienconst char * 37818334Speterdevtoname(dev_t dev) 37990282Sobrien{ 38090282Sobrien char *p; 38190282Sobrien int mynor; 38290282Sobrien 38318334Speter if (dev->si_name[0] == '#' || dev->si_name[0] == '\0') { 38418334Speter p = dev->si_name; 38518334Speter if (devsw(dev)) 38618334Speter sprintf(p, "#%s/", devsw(dev)->d_name); 38750615Sobrien else 38850615Sobrien sprintf(p, "#%d/", major(dev)); 38950615Sobrien p += strlen(p); 39050615Sobrien mynor = minor(dev); 39150615Sobrien if (mynor < 0 || mynor > 255) 39250615Sobrien sprintf(p, "%#x", (u_int)mynor); 39350615Sobrien else 39450615Sobrien sprintf(p, "%d", mynor); 39550615Sobrien } 39650615Sobrien return (dev->si_name); 39750615Sobrien} 39850615Sobrien 39990282Sobrienint 40090282Sobriendev_stdclone(char *name, char **namep, const char *stem, int *unit) 40190282Sobrien{ 40290282Sobrien int u, i; 40390282Sobrien 40490282Sobrien i = strlen(stem); 40590282Sobrien if (bcmp(stem, name, i) != 0) 40690282Sobrien return (0); 40790282Sobrien if (!isdigit(name[i])) 40818334Speter return (0); 40918334Speter u = 0; 41018334Speter if (name[i] == '0' && isdigit(name[i+1])) 41118334Speter return (0); 41218334Speter while (isdigit(name[i])) { 41318334Speter u *= 10; 41418334Speter u += name[i++] - '0'; 41518334Speter } 41618334Speter if (u > 0xffffff) 41718334Speter return (0); 41890282Sobrien *unit = u; 41918334Speter if (namep) 42090282Sobrien *namep = &name[i]; 42118334Speter if (name[i]) 42290282Sobrien return (2); 42318334Speter return (1); 42490282Sobrien} 42590282Sobrien 42690282Sobrien/* 42790282Sobrien * Helper sysctl for devname(3). We're given a {u}dev_t and return 42890282Sobrien * the name, if any, registered by the device driver. 42990282Sobrien */ 43090282Sobrienstatic int 43190282Sobriensysctl_devname(SYSCTL_HANDLER_ARGS) 43290282Sobrien{ 43390282Sobrien int error; 43490282Sobrien udev_t ud; 43518334Speter dev_t dev; 43618334Speter 43718334Speter error = SYSCTL_IN(req, &ud, sizeof (ud)); 43818334Speter if (error) 43918334Speter return (error); 44018334Speter if (ud == NOUDEV) 44118334Speter return(EINVAL); 44218334Speter dev = makedev(umajor(ud), uminor(ud)); 44318334Speter if (dev->si_name[0] == '\0') 44418334Speter error = ENOENT; 44518334Speter else 44618334Speter error = SYSCTL_OUT(req, dev->si_name, strlen(dev->si_name) + 1); 44718334Speter freedev(dev); 44818334Speter return (error); 44918334Speter} 45018334Speter 45118334SpeterSYSCTL_PROC(_kern, OID_AUTO, devname, CTLTYPE_OPAQUE|CTLFLAG_RW|CTLFLAG_ANYBODY, 45218334Speter NULL, 0, sysctl_devname, "", "devname(3) handler"); 45318334Speter 45418334Speter/* 45518334Speter * Set ready_for_devs; prior to this point, device creation is not allowed. 45618334Speter */ 45718334Speterstatic void 45818334Speterdev_set_ready(void *junk) 45918334Speter{ 46018334Speter ready_for_devs = 1; 46118334Speter} 46218334Speter 46318334SpeterSYSINIT(dev_ready, SI_SUB_DEVFS, SI_ORDER_FIRST, dev_set_ready, NULL); 46418334Speter