kern_conf.c revision 60938
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 60938 2000-05-26 02:09:24Z jake $ 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> 4549535Sphk#include <machine/stdarg.h> 4611126Sjulian 4747640Sphk#define cdevsw_ALLOCSTART (NUMCDEVSW/2) 4812954Sjulian 4947640Sphkstruct cdevsw *cdevsw[NUMCDEVSW]; 5012954Sjulian 5148936Sphkstatic int bmaj2cmaj[NUMCDEVSW]; 5246635Sphk 5348936SphkMALLOC_DEFINE(M_DEVT, "dev_t", "dev_t storage"); 5448936Sphk 5550522Sphk/* 5650522Sphk * This is the number of hash-buckets. Experiements with 'real-life' 5750522Sphk * udev_t's show that a prime halfway between two powers of two works 5850522Sphk * best. 5950522Sphk */ 6048936Sphk#define DEVT_HASH 83 6150522Sphk 6250522Sphk/* The number of dev_t's we can create before malloc(9) kick in. */ 6348936Sphk#define DEVT_STASH 50 6448936Sphk 6548936Sphkstatic struct specinfo devt_stash[DEVT_STASH]; 6648936Sphk 6760938Sjakestatic LIST_HEAD(, specinfo) dev_hash[DEVT_HASH]; 6848936Sphk 6960938Sjakestatic LIST_HEAD(, specinfo) dev_free; 7050549Sphk 7150254Sphkdevfs_create_t *devfs_create_hook; 7250549Sphkdevfs_remove_t *devfs_remove_hook; 7350254Sphk 7450549Sphkstatic int free_devt; 7550549SphkSYSCTL_INT(_debug, OID_AUTO, free_devt, CTLFLAG_RW, &free_devt, 0, ""); 7650549Sphk 7747640Sphkstruct cdevsw * 7847640Sphkdevsw(dev_t dev) 7951927Sphk{ 8049679Sphk if (dev->si_devsw) 8149679Sphk return (dev->si_devsw); 8247640Sphk return(cdevsw[major(dev)]); 8347640Sphk} 8447640Sphk 8547640Sphk/* 8647640Sphk * Add a cdevsw entry 8747640Sphk */ 8847640Sphk 8937389Sjulianint 9047640Sphkcdevsw_add(struct cdevsw *newentry) 9117264Sphk{ 9247028Sphk int i; 9347028Sphk static int setup; 9417264Sphk 9547028Sphk if (!setup) { 9647640Sphk for (i = 0; i < NUMCDEVSW; i++) 9747028Sphk if (!bmaj2cmaj[i]) 9848936Sphk bmaj2cmaj[i] = 254; 9947028Sphk setup++; 10047028Sphk } 10147028Sphk 10247640Sphk if (newentry->d_maj < 0 || newentry->d_maj >= NUMCDEVSW) { 10347640Sphk printf("%s: ERROR: driver has bogus cdevsw->d_maj = %d\n", 10447640Sphk newentry->d_name, newentry->d_maj); 10551927Sphk return (EINVAL); 10637389Sjulian } 10751927Sphk if (newentry->d_bmaj >= NUMCDEVSW) { 10851927Sphk printf("%s: ERROR: driver has bogus cdevsw->d_bmaj = %d\n", 10951927Sphk newentry->d_name, newentry->d_bmaj); 11051927Sphk return (EINVAL); 11151927Sphk } 11251927Sphk if (newentry->d_bmaj >= 0 && (newentry->d_flags & D_DISK) == 0) { 11351927Sphk printf("ERROR: \"%s\" bmaj but is not a disk\n", 11451927Sphk newentry->d_name); 11551927Sphk return (EINVAL); 11651927Sphk } 11717264Sphk 11848510Sphk if (cdevsw[newentry->d_maj]) { 11948510Sphk printf("WARNING: \"%s\" is usurping \"%s\"'s cdevsw[]\n", 12048510Sphk newentry->d_name, cdevsw[newentry->d_maj]->d_name); 12148510Sphk } 12251927Sphk 12347640Sphk cdevsw[newentry->d_maj] = newentry; 12437389Sjulian 12551927Sphk if (newentry->d_bmaj < 0) 12651927Sphk return (0); 12751927Sphk 12851927Sphk if (bmaj2cmaj[newentry->d_bmaj] != 254) { 12951927Sphk printf("WARNING: \"%s\" is usurping \"%s\"'s bmaj\n", 13051927Sphk newentry->d_name, 13151927Sphk cdevsw[bmaj2cmaj[newentry->d_bmaj]]->d_name); 13248510Sphk } 13351927Sphk bmaj2cmaj[newentry->d_bmaj] = newentry->d_maj; 13451927Sphk return (0); 13551927Sphk} 13647640Sphk 13748211Sgrog/* 13848211Sgrog * Remove a cdevsw entry 13948211Sgrog */ 14048211Sgrog 14136735Sdfrint 14248211Sgrogcdevsw_remove(struct cdevsw *oldentry) 14348211Sgrog{ 14448211Sgrog if (oldentry->d_maj < 0 || oldentry->d_maj >= NUMCDEVSW) { 14548211Sgrog printf("%s: ERROR: driver has bogus cdevsw->d_maj = %d\n", 14648211Sgrog oldentry->d_name, oldentry->d_maj); 14748211Sgrog return EINVAL; 14848211Sgrog } 14948211Sgrog 15048211Sgrog cdevsw[oldentry->d_maj] = NULL; 15148211Sgrog 15251927Sphk if (oldentry->d_bmaj >= 0 && oldentry->d_bmaj < NUMCDEVSW) 15349504Sgrog bmaj2cmaj[oldentry->d_bmaj] = 254; 15448211Sgrog 15548211Sgrog return 0; 15651927Sphk} 15748211Sgrog 15847028Sphk/* 15947028Sphk * dev_t and u_dev_t primitives 16047028Sphk */ 16147028Sphk 16251927Sphkint 16347028Sphkmajor(dev_t x) 16447028Sphk{ 16548936Sphk if (x == NODEV) 16648936Sphk return NOUDEV; 16748936Sphk return((x->si_udev >> 8) & 0xff); 16847028Sphk} 16947028Sphk 17047028Sphkint 17147028Sphkminor(dev_t x) 17247028Sphk{ 17348936Sphk if (x == NODEV) 17448936Sphk return NOUDEV; 17548936Sphk return(x->si_udev & 0xffff00ff); 17647028Sphk} 17747028Sphk 17849826Sphkint 17949826Sphklminor(dev_t x) 18049826Sphk{ 18149826Sphk int i; 18249826Sphk 18349826Sphk if (x == NODEV) 18449826Sphk return NOUDEV; 18549826Sphk i = minor(x); 18649826Sphk return ((i & 0xff) | (i >> 8)); 18749826Sphk} 18849826Sphk 18947028Sphkdev_t 19047680Sphkmakebdev(int x, int y) 19147680Sphk{ 19255414Sphk 19355414Sphk if (x == umajor(NOUDEV) && y == uminor(NOUDEV)) 19455414Sphk Debugger("makebdev of NOUDEV"); 19548892Sphk return (makedev(bmaj2cmaj[x], y)); 19647680Sphk} 19747680Sphk 19847680Sphkdev_t 19947028Sphkmakedev(int x, int y) 20047028Sphk{ 20148936Sphk struct specinfo *si; 20248936Sphk udev_t udev; 20348936Sphk int hash; 20448936Sphk static int stashed; 20548936Sphk 20655414Sphk if (x == umajor(NOUDEV) && y == uminor(NOUDEV)) 20755414Sphk Debugger("makedev of NOUDEV"); 20848936Sphk udev = (x << 8) | y; 20948936Sphk hash = udev % DEVT_HASH; 21050549Sphk LIST_FOREACH(si, &dev_hash[hash], si_hash) { 21148936Sphk if (si->si_udev == udev) 21248936Sphk return (si); 21348936Sphk } 21448936Sphk if (stashed >= DEVT_STASH) { 21551927Sphk MALLOC(si, struct specinfo *, sizeof(*si), M_DEVT, 21648936Sphk M_USE_RESERVE); 21750549Sphk bzero(si, sizeof(*si)); 21850549Sphk } else if (LIST_FIRST(&dev_free)) { 21950549Sphk si = LIST_FIRST(&dev_free); 22050549Sphk LIST_REMOVE(si, si_hash); 22148936Sphk } else { 22248936Sphk si = devt_stash + stashed++; 22350549Sphk si->si_flags |= SI_STASHED; 22448936Sphk } 22548936Sphk si->si_udev = udev; 22650549Sphk LIST_INSERT_HEAD(&dev_hash[hash], si, si_hash); 22748936Sphk return (si); 22847028Sphk} 22947028Sphk 23050549Sphkvoid 23150549Sphkfreedev(dev_t dev) 23250549Sphk{ 23350549Sphk int hash; 23450549Sphk 23550549Sphk if (!free_devt) 23650549Sphk return; 23750549Sphk if (SLIST_FIRST(&dev->si_hlist)) 23850549Sphk return; 23951927Sphk if (dev->si_devsw || dev->si_drv1 || dev->si_drv2) 24050549Sphk return; 24150549Sphk hash = dev->si_udev % DEVT_HASH; 24250549Sphk LIST_REMOVE(dev, si_hash); 24350549Sphk if (dev->si_flags & SI_STASHED) { 24450549Sphk bzero(dev, sizeof(*dev)); 24550549Sphk LIST_INSERT_HEAD(&dev_free, dev, si_hash); 24650549Sphk } else { 24750549Sphk FREE(dev, M_DEVT); 24850549Sphk } 24950549Sphk} 25050549Sphk 25147028Sphkudev_t 25247028Sphkdev2udev(dev_t x) 25347028Sphk{ 25448936Sphk if (x == NODEV) 25548936Sphk return NOUDEV; 25648936Sphk return (x->si_udev); 25747028Sphk} 25847028Sphk 25947028Sphkdev_t 26047028Sphkudev2dev(udev_t x, int b) 26147028Sphk{ 26255414Sphk 26355414Sphk if (x == NOUDEV) 26455414Sphk return (NODEV); 26548864Sphk switch (b) { 26648864Sphk case 0: 26748864Sphk return makedev(umajor(x), uminor(x)); 26848864Sphk case 1: 26948864Sphk return makebdev(umajor(x), uminor(x)); 27048864Sphk default: 27148864Sphk Debugger("udev2dev(...,X)"); 27248864Sphk return NODEV; 27348864Sphk } 27447028Sphk} 27547028Sphk 27647028Sphkint 27747028Sphkuminor(udev_t dev) 27847028Sphk{ 27947028Sphk return(dev & 0xffff00ff); 28047028Sphk} 28147028Sphk 28247028Sphkint 28347028Sphkumajor(udev_t dev) 28447028Sphk{ 28547028Sphk return((dev & 0xff00) >> 8); 28647028Sphk} 28747028Sphk 28847028Sphkudev_t 28948859Sphkmakeudev(int x, int y) 29047028Sphk{ 29147028Sphk return ((x << 8) | y); 29247028Sphk} 29347028Sphk 29449535Sphkdev_t 29549535Sphkmake_dev(struct cdevsw *devsw, int minor, uid_t uid, gid_t gid, int perms, char *fmt, ...) 29649535Sphk{ 29749535Sphk dev_t dev; 29849535Sphk va_list ap; 29949535Sphk int i; 30049535Sphk 30149535Sphk dev = makedev(devsw->d_maj, minor); 30249535Sphk va_start(ap, fmt); 30356465Sbp i = kvprintf(fmt, NULL, dev->si_name, 32, ap); 30449535Sphk dev->si_name[i] = '\0'; 30549535Sphk va_end(ap); 30649535Sphk dev->si_devsw = devsw; 30750092Sjulian 30850254Sphk if (devfs_create_hook) 30950254Sphk devfs_create_hook(dev, uid, gid, perms); 31049535Sphk return (dev); 31149535Sphk} 31249535Sphk 31350549Sphkvoid 31453000Sphkdestroy_dev(dev_t dev) 31550549Sphk{ 31650549Sphk if (devfs_remove_hook) 31750549Sphk devfs_remove_hook(dev); 31850549Sphk dev->si_drv1 = 0; 31950549Sphk dev->si_drv2 = 0; 32050549Sphk dev->si_devsw = 0; 32150549Sphk freedev(dev); 32250549Sphk} 32350549Sphk 32451225Sbdeconst char * 32549982Sbillfdevtoname(dev_t dev) 32649982Sbillf{ 32750549Sphk char *p; 32851225Sbde int mynor; 32949982Sbillf 33050549Sphk if (dev->si_name[0] == '#' || dev->si_name[0] == '\0') { 33150549Sphk p = dev->si_name; 33250549Sphk if (devsw(dev)) 33350549Sphk sprintf(p, "#%s/", devsw(dev)->d_name); 33450549Sphk else 33550549Sphk sprintf(p, "#%d/", major(dev)); 33650549Sphk p += strlen(p); 33751225Sbde mynor = minor(dev); 33851225Sbde if (mynor < 0 || mynor > 255) 33951225Sbde sprintf(p, "%#x", (u_int)mynor); 34051225Sbde else 34151225Sbde sprintf(p, "%d", mynor); 34250549Sphk } 34349982Sbillf return (dev->si_name); 34449982Sbillf} 345