kern_conf.c revision 67905
111126Sjulian/*- 211126Sjulian * Parts Copyright (c) 1995 Terrence R. Lambert 311126Sjulian * Copyright (c) 1995 Julian R. Elischer 411126Sjulian * All rights reserved. 511126Sjulian * 611126Sjulian * Redistribution and use in source and binary forms, with or without 711126Sjulian * modification, are permitted provided that the following conditions 811126Sjulian * are met: 911126Sjulian * 1. Redistributions of source code must retain the above copyright 1011126Sjulian * notice, this list of conditions and the following disclaimer. 1111126Sjulian * 2. Redistributions in binary form must reproduce the above copyright 1211126Sjulian * notice, this list of conditions and the following disclaimer in the 1311126Sjulian * documentation and/or other materials provided with the distribution. 1411126Sjulian * 3. All advertising materials mentioning features or use of this software 1511126Sjulian * must display the following acknowledgement: 1611126Sjulian * This product includes software developed by Terrence R. Lambert. 1711126Sjulian * 4. The name Terrence R. Lambert may not be used to endorse or promote 1811126Sjulian * products derived from this software without specific prior written 1911126Sjulian * permission. 2011126Sjulian * 2111126Sjulian * THIS SOFTWARE IS PROVIDED BY Julian R. Elischer ``AS IS'' AND ANY 2211126Sjulian * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2311126Sjulian * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2411126Sjulian * ARE DISCLAIMED. IN NO EVENT SHALL THE TERRENCE R. LAMBERT BE LIABLE 2511126Sjulian * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2611126Sjulian * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2711126Sjulian * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2811126Sjulian * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2911126Sjulian * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 3011126Sjulian * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 3111126Sjulian * SUCH DAMAGE. 3211126Sjulian * 3350477Speter * $FreeBSD: head/sys/kern/kern_conf.c 67905 2000-10-29 19:50:06Z phk $ 3411126Sjulian */ 3511126Sjulian 3611126Sjulian#include <sys/param.h> 3748936Sphk#include <sys/kernel.h> 3850549Sphk#include <sys/sysctl.h> 3911127Sjulian#include <sys/systm.h> 4036735Sdfr#include <sys/module.h> 4148936Sphk#include <sys/malloc.h> 4211126Sjulian#include <sys/conf.h> 4312954Sjulian#include <sys/vnode.h> 4448936Sphk#include <sys/queue.h> 4565374Sphk#include <sys/ctype.h> 4649535Sphk#include <machine/stdarg.h> 4711126Sjulian 4847640Sphk#define cdevsw_ALLOCSTART (NUMCDEVSW/2) 4912954Sjulian 5047640Sphkstruct cdevsw *cdevsw[NUMCDEVSW]; 5112954Sjulian 5248936Sphkstatic int bmaj2cmaj[NUMCDEVSW]; 5346635Sphk 5448936SphkMALLOC_DEFINE(M_DEVT, "dev_t", "dev_t storage"); 5548936Sphk 5650522Sphk/* 5750522Sphk * This is the number of hash-buckets. Experiements with 'real-life' 5850522Sphk * udev_t's show that a prime halfway between two powers of two works 5950522Sphk * best. 6050522Sphk */ 6148936Sphk#define DEVT_HASH 83 6250522Sphk 6350522Sphk/* The number of dev_t's we can create before malloc(9) kick in. */ 6448936Sphk#define DEVT_STASH 50 6548936Sphk 6648936Sphkstatic struct specinfo devt_stash[DEVT_STASH]; 6748936Sphk 6860938Sjakestatic LIST_HEAD(, specinfo) dev_hash[DEVT_HASH]; 6948936Sphk 7060938Sjakestatic LIST_HEAD(, specinfo) dev_free; 7150549Sphk 7250254Sphkdevfs_create_t *devfs_create_hook; 7365374Sphkdevfs_destroy_t *devfs_destroy_hook; 7465374Sphkint devfs_present; 7550254Sphk 7650549Sphkstatic int free_devt; 7750549SphkSYSCTL_INT(_debug, OID_AUTO, free_devt, CTLFLAG_RW, &free_devt, 0, ""); 7850549Sphk 7947640Sphkstruct cdevsw * 8047640Sphkdevsw(dev_t dev) 8151927Sphk{ 8249679Sphk if (dev->si_devsw) 8349679Sphk return (dev->si_devsw); 8447640Sphk return(cdevsw[major(dev)]); 8547640Sphk} 8647640Sphk 8747640Sphk/* 8847640Sphk * Add a cdevsw entry 8947640Sphk */ 9047640Sphk 9137389Sjulianint 9247640Sphkcdevsw_add(struct cdevsw *newentry) 9317264Sphk{ 9447028Sphk int i; 9547028Sphk static int setup; 9617264Sphk 9747028Sphk if (!setup) { 9847640Sphk for (i = 0; i < NUMCDEVSW; i++) 9947028Sphk if (!bmaj2cmaj[i]) 10048936Sphk bmaj2cmaj[i] = 254; 10147028Sphk setup++; 10247028Sphk } 10347028Sphk 10447640Sphk if (newentry->d_maj < 0 || newentry->d_maj >= NUMCDEVSW) { 10547640Sphk printf("%s: ERROR: driver has bogus cdevsw->d_maj = %d\n", 10647640Sphk newentry->d_name, newentry->d_maj); 10751927Sphk return (EINVAL); 10837389Sjulian } 10951927Sphk if (newentry->d_bmaj >= NUMCDEVSW) { 11051927Sphk printf("%s: ERROR: driver has bogus cdevsw->d_bmaj = %d\n", 11151927Sphk newentry->d_name, newentry->d_bmaj); 11251927Sphk return (EINVAL); 11351927Sphk } 11451927Sphk if (newentry->d_bmaj >= 0 && (newentry->d_flags & D_DISK) == 0) { 11551927Sphk printf("ERROR: \"%s\" bmaj but is not a disk\n", 11651927Sphk newentry->d_name); 11751927Sphk return (EINVAL); 11851927Sphk } 11917264Sphk 12048510Sphk if (cdevsw[newentry->d_maj]) { 12148510Sphk printf("WARNING: \"%s\" is usurping \"%s\"'s cdevsw[]\n", 12248510Sphk newentry->d_name, cdevsw[newentry->d_maj]->d_name); 12348510Sphk } 12451927Sphk 12547640Sphk cdevsw[newentry->d_maj] = newentry; 12637389Sjulian 12751927Sphk if (newentry->d_bmaj < 0) 12851927Sphk return (0); 12951927Sphk 13051927Sphk if (bmaj2cmaj[newentry->d_bmaj] != 254) { 13151927Sphk printf("WARNING: \"%s\" is usurping \"%s\"'s bmaj\n", 13251927Sphk newentry->d_name, 13351927Sphk cdevsw[bmaj2cmaj[newentry->d_bmaj]]->d_name); 13448510Sphk } 13551927Sphk bmaj2cmaj[newentry->d_bmaj] = newentry->d_maj; 13651927Sphk return (0); 13751927Sphk} 13847640Sphk 13948211Sgrog/* 14048211Sgrog * Remove a cdevsw entry 14148211Sgrog */ 14248211Sgrog 14336735Sdfrint 14448211Sgrogcdevsw_remove(struct cdevsw *oldentry) 14548211Sgrog{ 14648211Sgrog if (oldentry->d_maj < 0 || oldentry->d_maj >= NUMCDEVSW) { 14748211Sgrog printf("%s: ERROR: driver has bogus cdevsw->d_maj = %d\n", 14848211Sgrog oldentry->d_name, oldentry->d_maj); 14948211Sgrog return EINVAL; 15048211Sgrog } 15148211Sgrog 15248211Sgrog cdevsw[oldentry->d_maj] = NULL; 15348211Sgrog 15451927Sphk if (oldentry->d_bmaj >= 0 && oldentry->d_bmaj < NUMCDEVSW) 15549504Sgrog bmaj2cmaj[oldentry->d_bmaj] = 254; 15648211Sgrog 15748211Sgrog return 0; 15851927Sphk} 15948211Sgrog 16047028Sphk/* 16147028Sphk * dev_t and u_dev_t primitives 16247028Sphk */ 16347028Sphk 16451927Sphkint 16547028Sphkmajor(dev_t x) 16647028Sphk{ 16748936Sphk if (x == NODEV) 16848936Sphk return NOUDEV; 16948936Sphk return((x->si_udev >> 8) & 0xff); 17047028Sphk} 17147028Sphk 17247028Sphkint 17347028Sphkminor(dev_t x) 17447028Sphk{ 17548936Sphk if (x == NODEV) 17648936Sphk return NOUDEV; 17748936Sphk return(x->si_udev & 0xffff00ff); 17847028Sphk} 17947028Sphk 18049826Sphkint 18166067Sphkdev2unit(dev_t x) 18249826Sphk{ 18349826Sphk int i; 18449826Sphk 18549826Sphk if (x == NODEV) 18649826Sphk return NOUDEV; 18749826Sphk i = minor(x); 18849826Sphk return ((i & 0xff) | (i >> 8)); 18949826Sphk} 19049826Sphk 19166067Sphkint 19266067Sphkunit2minor(int unit) 19366067Sphk{ 19466067Sphk 19566067Sphk return ((unit & 0xff) | ((unit << 8) & ~0xffff)); 19666067Sphk} 19766067Sphk 19847028Sphkdev_t 19947680Sphkmakebdev(int x, int y) 20047680Sphk{ 20155414Sphk 20255414Sphk if (x == umajor(NOUDEV) && y == uminor(NOUDEV)) 20355414Sphk Debugger("makebdev of NOUDEV"); 20448892Sphk return (makedev(bmaj2cmaj[x], y)); 20547680Sphk} 20647680Sphk 20764880Sphkstatic dev_t 20864880Sphkallocdev(void) 20964880Sphk{ 21064880Sphk static int stashed; 21164880Sphk struct specinfo *si; 21264880Sphk 21364880Sphk if (stashed >= DEVT_STASH) { 21464880Sphk MALLOC(si, struct specinfo *, sizeof(*si), M_DEVT, 21564880Sphk M_USE_RESERVE); 21664880Sphk bzero(si, sizeof(*si)); 21764880Sphk } else if (LIST_FIRST(&dev_free)) { 21864880Sphk si = LIST_FIRST(&dev_free); 21964880Sphk LIST_REMOVE(si, si_hash); 22064880Sphk } else { 22164880Sphk si = devt_stash + stashed++; 22264880Sphk si->si_flags |= SI_STASHED; 22364880Sphk } 22464880Sphk LIST_INIT(&si->si_names); 22564880Sphk return (si); 22664880Sphk} 22764880Sphk 22847680Sphkdev_t 22947028Sphkmakedev(int x, int y) 23047028Sphk{ 23148936Sphk struct specinfo *si; 23248936Sphk udev_t udev; 23348936Sphk int hash; 23448936Sphk 23555414Sphk if (x == umajor(NOUDEV) && y == uminor(NOUDEV)) 23655414Sphk Debugger("makedev of NOUDEV"); 23748936Sphk udev = (x << 8) | y; 23848936Sphk hash = udev % DEVT_HASH; 23950549Sphk LIST_FOREACH(si, &dev_hash[hash], si_hash) { 24048936Sphk if (si->si_udev == udev) 24148936Sphk return (si); 24248936Sphk } 24364880Sphk si = allocdev(); 24448936Sphk si->si_udev = udev; 24550549Sphk LIST_INSERT_HEAD(&dev_hash[hash], si, si_hash); 24648936Sphk return (si); 24747028Sphk} 24847028Sphk 24950549Sphkvoid 25050549Sphkfreedev(dev_t dev) 25150549Sphk{ 25264880Sphk dev_t adev; 25350549Sphk 25450549Sphk if (!free_devt) 25550549Sphk return; 25650549Sphk if (SLIST_FIRST(&dev->si_hlist)) 25750549Sphk return; 25851927Sphk if (dev->si_devsw || dev->si_drv1 || dev->si_drv2) 25950549Sphk return; 26064880Sphk while (!LIST_EMPTY(&dev->si_names)) { 26164880Sphk adev = LIST_FIRST(&dev->si_names); 26264880Sphk adev->si_drv1 = NULL; 26364880Sphk freedev(adev); 26464880Sphk } 26550549Sphk LIST_REMOVE(dev, si_hash); 26650549Sphk if (dev->si_flags & SI_STASHED) { 26750549Sphk bzero(dev, sizeof(*dev)); 26850549Sphk LIST_INSERT_HEAD(&dev_free, dev, si_hash); 26950549Sphk } else { 27050549Sphk FREE(dev, M_DEVT); 27150549Sphk } 27250549Sphk} 27350549Sphk 27447028Sphkudev_t 27547028Sphkdev2udev(dev_t x) 27647028Sphk{ 27748936Sphk if (x == NODEV) 27848936Sphk return NOUDEV; 27948936Sphk return (x->si_udev); 28047028Sphk} 28147028Sphk 28247028Sphkdev_t 28347028Sphkudev2dev(udev_t x, int b) 28447028Sphk{ 28555414Sphk 28655414Sphk if (x == NOUDEV) 28755414Sphk return (NODEV); 28848864Sphk switch (b) { 28948864Sphk case 0: 29048864Sphk return makedev(umajor(x), uminor(x)); 29148864Sphk case 1: 29248864Sphk return makebdev(umajor(x), uminor(x)); 29348864Sphk default: 29448864Sphk Debugger("udev2dev(...,X)"); 29548864Sphk return NODEV; 29648864Sphk } 29747028Sphk} 29847028Sphk 29947028Sphkint 30047028Sphkuminor(udev_t dev) 30147028Sphk{ 30247028Sphk return(dev & 0xffff00ff); 30347028Sphk} 30447028Sphk 30547028Sphkint 30647028Sphkumajor(udev_t dev) 30747028Sphk{ 30847028Sphk return((dev & 0xff00) >> 8); 30947028Sphk} 31047028Sphk 31147028Sphkudev_t 31248859Sphkmakeudev(int x, int y) 31347028Sphk{ 31447028Sphk return ((x << 8) | y); 31547028Sphk} 31647028Sphk 31749535Sphkdev_t 31849535Sphkmake_dev(struct cdevsw *devsw, int minor, uid_t uid, gid_t gid, int perms, char *fmt, ...) 31949535Sphk{ 32049535Sphk dev_t dev; 32149535Sphk va_list ap; 32249535Sphk int i; 32349535Sphk 32449535Sphk dev = makedev(devsw->d_maj, minor); 32565747Sphk if (dev->si_flags & SI_NAMED) { 32665747Sphk printf( "WARNING: Driver mistake: repeat make_dev(\"%s\")\n", 32765747Sphk dev->si_name); 32865747Sphk return (dev); 32965747Sphk } 33049535Sphk va_start(ap, fmt); 33156465Sbp i = kvprintf(fmt, NULL, dev->si_name, 32, ap); 33249535Sphk dev->si_name[i] = '\0'; 33349535Sphk va_end(ap); 33449535Sphk dev->si_devsw = devsw; 33564880Sphk dev->si_uid = uid; 33664880Sphk dev->si_gid = gid; 33764880Sphk dev->si_mode = perms; 33865747Sphk dev->si_flags |= SI_NAMED; 33950092Sjulian 34050254Sphk if (devfs_create_hook) 34164880Sphk devfs_create_hook(dev); 34249535Sphk return (dev); 34349535Sphk} 34449535Sphk 34564880Sphkdev_t 34664880Sphkmake_dev_alias(dev_t pdev, char *fmt, ...) 34764880Sphk{ 34864880Sphk dev_t dev; 34964880Sphk va_list ap; 35064880Sphk int i; 35164880Sphk 35264880Sphk dev = allocdev(); 35364880Sphk dev->si_flags |= SI_ALIAS; 35465747Sphk dev->si_flags |= SI_NAMED; 35564880Sphk dev->si_drv1 = pdev; 35664880Sphk LIST_INSERT_HEAD(&pdev->si_names, dev, si_hash); 35764880Sphk 35864880Sphk va_start(ap, fmt); 35964880Sphk i = kvprintf(fmt, NULL, dev->si_name, 32, ap); 36064880Sphk dev->si_name[i] = '\0'; 36164880Sphk va_end(ap); 36264880Sphk 36364880Sphk if (devfs_create_hook) 36464880Sphk devfs_create_hook(dev); 36564880Sphk return (dev); 36664880Sphk} 36764880Sphk 36850549Sphkvoid 36953000Sphkdestroy_dev(dev_t dev) 37050549Sphk{ 37165747Sphk 37265747Sphk if (!(dev->si_flags & SI_NAMED)) { 37365747Sphk printf( "WARNING: Driver mistake: destroy_dev on %d/%d\n", 37465747Sphk major(dev), minor(dev)); 37565747Sphk return; 37665747Sphk } 37765747Sphk 37865374Sphk if (devfs_destroy_hook) 37965374Sphk devfs_destroy_hook(dev); 38050549Sphk dev->si_drv1 = 0; 38150549Sphk dev->si_drv2 = 0; 38250549Sphk dev->si_devsw = 0; 38365747Sphk dev->si_flags &= ~SI_NAMED; 38465747Sphk dev->si_flags &= ~SI_ALIAS; 38550549Sphk freedev(dev); 38650549Sphk} 38750549Sphk 38851225Sbdeconst char * 38949982Sbillfdevtoname(dev_t dev) 39049982Sbillf{ 39150549Sphk char *p; 39251225Sbde int mynor; 39349982Sbillf 39450549Sphk if (dev->si_name[0] == '#' || dev->si_name[0] == '\0') { 39550549Sphk p = dev->si_name; 39650549Sphk if (devsw(dev)) 39750549Sphk sprintf(p, "#%s/", devsw(dev)->d_name); 39850549Sphk else 39950549Sphk sprintf(p, "#%d/", major(dev)); 40050549Sphk p += strlen(p); 40151225Sbde mynor = minor(dev); 40251225Sbde if (mynor < 0 || mynor > 255) 40351225Sbde sprintf(p, "%#x", (u_int)mynor); 40451225Sbde else 40551225Sbde sprintf(p, "%d", mynor); 40650549Sphk } 40749982Sbillf return (dev->si_name); 40849982Sbillf} 40965374Sphk 41065374Sphkint 41165374Sphkdev_stdclone(char *name, char **namep, char *stem, int *unit) 41265374Sphk{ 41365374Sphk int u, i; 41465374Sphk 41565374Sphk if (bcmp(stem, name, strlen(stem)) != 0) 41665374Sphk return (0); 41765374Sphk i = strlen(stem); 41865374Sphk if (!isdigit(name[i])) 41965374Sphk return (0); 42065374Sphk u = 0; 42165374Sphk while (isdigit(name[i])) { 42265374Sphk u *= 10; 42365374Sphk u += name[i++] - '0'; 42465374Sphk } 42565374Sphk *unit = u; 42665374Sphk if (namep) 42765374Sphk *namep = &name[i]; 42865374Sphk if (name[i]) 42965374Sphk return (2); 43065374Sphk return (1); 43165374Sphk} 43265632Sphk 43365632Sphk/* 43465632Sphk * Helper sysctl for devname(3). We're given a {u}dev_t and return 43565632Sphk * the name, if any, registered by the device driver. 43665632Sphk */ 43765632Sphkstatic int 43865632Sphksysctl_devname(SYSCTL_HANDLER_ARGS) 43965632Sphk{ 44065632Sphk int error; 44165632Sphk udev_t ud; 44265632Sphk dev_t dev; 44365632Sphk 44465632Sphk error = SYSCTL_IN(req, &ud, sizeof (ud)); 44565632Sphk if (error) 44665632Sphk return (error); 44765632Sphk dev = makedev(umajor(ud), uminor(ud)); 44865632Sphk if (dev->si_name[0] == '\0') 44965632Sphk error = ENOENT; 45065632Sphk else 45165632Sphk error = SYSCTL_OUT(req, dev->si_name, strlen(dev->si_name) + 1); 45265632Sphk freedev(dev); 45365632Sphk return (error); 45465632Sphk} 45565632Sphk 45667905SphkSYSCTL_PROC(_kern, OID_AUTO, devname, CTLTYPE_OPAQUE|CTLFLAG_RW|CTLFLAG_ANYBODY, 45765632Sphk NULL, 0, sysctl_devname, "", "devname(3) handler"); 45865632Sphk 459