kern_conf.c revision 64880
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 64880 2000-08-20 21:34:39Z 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> 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 19864880Sphkstatic dev_t 19964880Sphkallocdev(void) 20064880Sphk{ 20164880Sphk static int stashed; 20264880Sphk struct specinfo *si; 20364880Sphk 20464880Sphk if (stashed >= DEVT_STASH) { 20564880Sphk MALLOC(si, struct specinfo *, sizeof(*si), M_DEVT, 20664880Sphk M_USE_RESERVE); 20764880Sphk bzero(si, sizeof(*si)); 20864880Sphk } else if (LIST_FIRST(&dev_free)) { 20964880Sphk si = LIST_FIRST(&dev_free); 21064880Sphk LIST_REMOVE(si, si_hash); 21164880Sphk } else { 21264880Sphk si = devt_stash + stashed++; 21364880Sphk si->si_flags |= SI_STASHED; 21464880Sphk } 21564880Sphk LIST_INIT(&si->si_names); 21664880Sphk return (si); 21764880Sphk} 21864880Sphk 21947680Sphkdev_t 22047028Sphkmakedev(int x, int y) 22147028Sphk{ 22248936Sphk struct specinfo *si; 22348936Sphk udev_t udev; 22448936Sphk int hash; 22548936Sphk 22655414Sphk if (x == umajor(NOUDEV) && y == uminor(NOUDEV)) 22755414Sphk Debugger("makedev of NOUDEV"); 22848936Sphk udev = (x << 8) | y; 22948936Sphk hash = udev % DEVT_HASH; 23050549Sphk LIST_FOREACH(si, &dev_hash[hash], si_hash) { 23148936Sphk if (si->si_udev == udev) 23248936Sphk return (si); 23348936Sphk } 23464880Sphk si = allocdev(); 23548936Sphk si->si_udev = udev; 23650549Sphk LIST_INSERT_HEAD(&dev_hash[hash], si, si_hash); 23748936Sphk return (si); 23847028Sphk} 23947028Sphk 24050549Sphkvoid 24150549Sphkfreedev(dev_t dev) 24250549Sphk{ 24364880Sphk dev_t adev; 24450549Sphk 24550549Sphk if (!free_devt) 24650549Sphk return; 24750549Sphk if (SLIST_FIRST(&dev->si_hlist)) 24850549Sphk return; 24951927Sphk if (dev->si_devsw || dev->si_drv1 || dev->si_drv2) 25050549Sphk return; 25164880Sphk while (!LIST_EMPTY(&dev->si_names)) { 25264880Sphk adev = LIST_FIRST(&dev->si_names); 25364880Sphk adev->si_drv1 = NULL; 25464880Sphk freedev(adev); 25564880Sphk } 25650549Sphk LIST_REMOVE(dev, si_hash); 25750549Sphk if (dev->si_flags & SI_STASHED) { 25850549Sphk bzero(dev, sizeof(*dev)); 25950549Sphk LIST_INSERT_HEAD(&dev_free, dev, si_hash); 26050549Sphk } else { 26150549Sphk FREE(dev, M_DEVT); 26250549Sphk } 26350549Sphk} 26450549Sphk 26547028Sphkudev_t 26647028Sphkdev2udev(dev_t x) 26747028Sphk{ 26848936Sphk if (x == NODEV) 26948936Sphk return NOUDEV; 27048936Sphk return (x->si_udev); 27147028Sphk} 27247028Sphk 27347028Sphkdev_t 27447028Sphkudev2dev(udev_t x, int b) 27547028Sphk{ 27655414Sphk 27755414Sphk if (x == NOUDEV) 27855414Sphk return (NODEV); 27948864Sphk switch (b) { 28048864Sphk case 0: 28148864Sphk return makedev(umajor(x), uminor(x)); 28248864Sphk case 1: 28348864Sphk return makebdev(umajor(x), uminor(x)); 28448864Sphk default: 28548864Sphk Debugger("udev2dev(...,X)"); 28648864Sphk return NODEV; 28748864Sphk } 28847028Sphk} 28947028Sphk 29047028Sphkint 29147028Sphkuminor(udev_t dev) 29247028Sphk{ 29347028Sphk return(dev & 0xffff00ff); 29447028Sphk} 29547028Sphk 29647028Sphkint 29747028Sphkumajor(udev_t dev) 29847028Sphk{ 29947028Sphk return((dev & 0xff00) >> 8); 30047028Sphk} 30147028Sphk 30247028Sphkudev_t 30348859Sphkmakeudev(int x, int y) 30447028Sphk{ 30547028Sphk return ((x << 8) | y); 30647028Sphk} 30747028Sphk 30849535Sphkdev_t 30949535Sphkmake_dev(struct cdevsw *devsw, int minor, uid_t uid, gid_t gid, int perms, char *fmt, ...) 31049535Sphk{ 31149535Sphk dev_t dev; 31249535Sphk va_list ap; 31349535Sphk int i; 31449535Sphk 31549535Sphk dev = makedev(devsw->d_maj, minor); 31649535Sphk va_start(ap, fmt); 31756465Sbp i = kvprintf(fmt, NULL, dev->si_name, 32, ap); 31849535Sphk dev->si_name[i] = '\0'; 31949535Sphk va_end(ap); 32049535Sphk dev->si_devsw = devsw; 32164880Sphk dev->si_uid = uid; 32264880Sphk dev->si_gid = gid; 32364880Sphk dev->si_mode = perms; 32450092Sjulian 32550254Sphk if (devfs_create_hook) 32664880Sphk devfs_create_hook(dev); 32749535Sphk return (dev); 32849535Sphk} 32949535Sphk 33064880Sphkdev_t 33164880Sphkmake_dev_alias(dev_t pdev, char *fmt, ...) 33264880Sphk{ 33364880Sphk dev_t dev; 33464880Sphk va_list ap; 33564880Sphk int i; 33664880Sphk 33764880Sphk dev = allocdev(); 33864880Sphk dev->si_flags |= SI_ALIAS; 33964880Sphk dev->si_drv1 = pdev; 34064880Sphk LIST_INSERT_HEAD(&pdev->si_names, dev, si_hash); 34164880Sphk 34264880Sphk va_start(ap, fmt); 34364880Sphk i = kvprintf(fmt, NULL, dev->si_name, 32, ap); 34464880Sphk dev->si_name[i] = '\0'; 34564880Sphk va_end(ap); 34664880Sphk 34764880Sphk if (devfs_create_hook) 34864880Sphk devfs_create_hook(dev); 34964880Sphk return (dev); 35064880Sphk} 35164880Sphk 35250549Sphkvoid 35353000Sphkdestroy_dev(dev_t dev) 35450549Sphk{ 35550549Sphk if (devfs_remove_hook) 35650549Sphk devfs_remove_hook(dev); 35750549Sphk dev->si_drv1 = 0; 35850549Sphk dev->si_drv2 = 0; 35950549Sphk dev->si_devsw = 0; 36050549Sphk freedev(dev); 36150549Sphk} 36250549Sphk 36351225Sbdeconst char * 36449982Sbillfdevtoname(dev_t dev) 36549982Sbillf{ 36650549Sphk char *p; 36751225Sbde int mynor; 36849982Sbillf 36950549Sphk if (dev->si_name[0] == '#' || dev->si_name[0] == '\0') { 37050549Sphk p = dev->si_name; 37150549Sphk if (devsw(dev)) 37250549Sphk sprintf(p, "#%s/", devsw(dev)->d_name); 37350549Sphk else 37450549Sphk sprintf(p, "#%d/", major(dev)); 37550549Sphk p += strlen(p); 37651225Sbde mynor = minor(dev); 37751225Sbde if (mynor < 0 || mynor > 255) 37851225Sbde sprintf(p, "%#x", (u_int)mynor); 37951225Sbde else 38051225Sbde sprintf(p, "%d", mynor); 38150549Sphk } 38249982Sbillf return (dev->si_name); 38349982Sbillf} 384