kern_conf.c revision 65374
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 65374 2000-09-02 19:17:34Z 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 18149826Sphklminor(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 19147028Sphkdev_t 19247680Sphkmakebdev(int x, int y) 19347680Sphk{ 19455414Sphk 19555414Sphk if (x == umajor(NOUDEV) && y == uminor(NOUDEV)) 19655414Sphk Debugger("makebdev of NOUDEV"); 19748892Sphk return (makedev(bmaj2cmaj[x], y)); 19847680Sphk} 19947680Sphk 20064880Sphkstatic dev_t 20164880Sphkallocdev(void) 20264880Sphk{ 20364880Sphk static int stashed; 20464880Sphk struct specinfo *si; 20564880Sphk 20664880Sphk if (stashed >= DEVT_STASH) { 20764880Sphk MALLOC(si, struct specinfo *, sizeof(*si), M_DEVT, 20864880Sphk M_USE_RESERVE); 20964880Sphk bzero(si, sizeof(*si)); 21064880Sphk } else if (LIST_FIRST(&dev_free)) { 21164880Sphk si = LIST_FIRST(&dev_free); 21264880Sphk LIST_REMOVE(si, si_hash); 21364880Sphk } else { 21464880Sphk si = devt_stash + stashed++; 21564880Sphk si->si_flags |= SI_STASHED; 21664880Sphk } 21764880Sphk LIST_INIT(&si->si_names); 21864880Sphk return (si); 21964880Sphk} 22064880Sphk 22147680Sphkdev_t 22247028Sphkmakedev(int x, int y) 22347028Sphk{ 22448936Sphk struct specinfo *si; 22548936Sphk udev_t udev; 22648936Sphk int hash; 22748936Sphk 22855414Sphk if (x == umajor(NOUDEV) && y == uminor(NOUDEV)) 22955414Sphk Debugger("makedev of NOUDEV"); 23048936Sphk udev = (x << 8) | y; 23148936Sphk hash = udev % DEVT_HASH; 23250549Sphk LIST_FOREACH(si, &dev_hash[hash], si_hash) { 23348936Sphk if (si->si_udev == udev) 23448936Sphk return (si); 23548936Sphk } 23664880Sphk si = allocdev(); 23748936Sphk si->si_udev = udev; 23850549Sphk LIST_INSERT_HEAD(&dev_hash[hash], si, si_hash); 23948936Sphk return (si); 24047028Sphk} 24147028Sphk 24250549Sphkvoid 24350549Sphkfreedev(dev_t dev) 24450549Sphk{ 24564880Sphk dev_t adev; 24650549Sphk 24750549Sphk if (!free_devt) 24850549Sphk return; 24950549Sphk if (SLIST_FIRST(&dev->si_hlist)) 25050549Sphk return; 25151927Sphk if (dev->si_devsw || dev->si_drv1 || dev->si_drv2) 25250549Sphk return; 25364880Sphk while (!LIST_EMPTY(&dev->si_names)) { 25464880Sphk adev = LIST_FIRST(&dev->si_names); 25564880Sphk adev->si_drv1 = NULL; 25664880Sphk freedev(adev); 25764880Sphk } 25850549Sphk LIST_REMOVE(dev, si_hash); 25950549Sphk if (dev->si_flags & SI_STASHED) { 26050549Sphk bzero(dev, sizeof(*dev)); 26150549Sphk LIST_INSERT_HEAD(&dev_free, dev, si_hash); 26250549Sphk } else { 26350549Sphk FREE(dev, M_DEVT); 26450549Sphk } 26550549Sphk} 26650549Sphk 26747028Sphkudev_t 26847028Sphkdev2udev(dev_t x) 26947028Sphk{ 27048936Sphk if (x == NODEV) 27148936Sphk return NOUDEV; 27248936Sphk return (x->si_udev); 27347028Sphk} 27447028Sphk 27547028Sphkdev_t 27647028Sphkudev2dev(udev_t x, int b) 27747028Sphk{ 27855414Sphk 27955414Sphk if (x == NOUDEV) 28055414Sphk return (NODEV); 28148864Sphk switch (b) { 28248864Sphk case 0: 28348864Sphk return makedev(umajor(x), uminor(x)); 28448864Sphk case 1: 28548864Sphk return makebdev(umajor(x), uminor(x)); 28648864Sphk default: 28748864Sphk Debugger("udev2dev(...,X)"); 28848864Sphk return NODEV; 28948864Sphk } 29047028Sphk} 29147028Sphk 29247028Sphkint 29347028Sphkuminor(udev_t dev) 29447028Sphk{ 29547028Sphk return(dev & 0xffff00ff); 29647028Sphk} 29747028Sphk 29847028Sphkint 29947028Sphkumajor(udev_t dev) 30047028Sphk{ 30147028Sphk return((dev & 0xff00) >> 8); 30247028Sphk} 30347028Sphk 30447028Sphkudev_t 30548859Sphkmakeudev(int x, int y) 30647028Sphk{ 30747028Sphk return ((x << 8) | y); 30847028Sphk} 30947028Sphk 31049535Sphkdev_t 31149535Sphkmake_dev(struct cdevsw *devsw, int minor, uid_t uid, gid_t gid, int perms, char *fmt, ...) 31249535Sphk{ 31349535Sphk dev_t dev; 31449535Sphk va_list ap; 31549535Sphk int i; 31649535Sphk 31749535Sphk dev = makedev(devsw->d_maj, minor); 31849535Sphk va_start(ap, fmt); 31956465Sbp i = kvprintf(fmt, NULL, dev->si_name, 32, ap); 32049535Sphk dev->si_name[i] = '\0'; 32149535Sphk va_end(ap); 32249535Sphk dev->si_devsw = devsw; 32364880Sphk dev->si_uid = uid; 32464880Sphk dev->si_gid = gid; 32564880Sphk dev->si_mode = perms; 32650092Sjulian 32750254Sphk if (devfs_create_hook) 32864880Sphk devfs_create_hook(dev); 32949535Sphk return (dev); 33049535Sphk} 33149535Sphk 33264880Sphkdev_t 33364880Sphkmake_dev_alias(dev_t pdev, char *fmt, ...) 33464880Sphk{ 33564880Sphk dev_t dev; 33664880Sphk va_list ap; 33764880Sphk int i; 33864880Sphk 33964880Sphk dev = allocdev(); 34064880Sphk dev->si_flags |= SI_ALIAS; 34164880Sphk dev->si_drv1 = pdev; 34264880Sphk LIST_INSERT_HEAD(&pdev->si_names, dev, si_hash); 34364880Sphk 34464880Sphk va_start(ap, fmt); 34564880Sphk i = kvprintf(fmt, NULL, dev->si_name, 32, ap); 34664880Sphk dev->si_name[i] = '\0'; 34764880Sphk va_end(ap); 34864880Sphk 34964880Sphk if (devfs_create_hook) 35064880Sphk devfs_create_hook(dev); 35164880Sphk return (dev); 35264880Sphk} 35364880Sphk 35450549Sphkvoid 35553000Sphkdestroy_dev(dev_t dev) 35650549Sphk{ 35765374Sphk if (devfs_destroy_hook) 35865374Sphk devfs_destroy_hook(dev); 35950549Sphk dev->si_drv1 = 0; 36050549Sphk dev->si_drv2 = 0; 36150549Sphk dev->si_devsw = 0; 36250549Sphk freedev(dev); 36350549Sphk} 36450549Sphk 36551225Sbdeconst char * 36649982Sbillfdevtoname(dev_t dev) 36749982Sbillf{ 36850549Sphk char *p; 36951225Sbde int mynor; 37049982Sbillf 37150549Sphk if (dev->si_name[0] == '#' || dev->si_name[0] == '\0') { 37250549Sphk p = dev->si_name; 37350549Sphk if (devsw(dev)) 37450549Sphk sprintf(p, "#%s/", devsw(dev)->d_name); 37550549Sphk else 37650549Sphk sprintf(p, "#%d/", major(dev)); 37750549Sphk p += strlen(p); 37851225Sbde mynor = minor(dev); 37951225Sbde if (mynor < 0 || mynor > 255) 38051225Sbde sprintf(p, "%#x", (u_int)mynor); 38151225Sbde else 38251225Sbde sprintf(p, "%d", mynor); 38350549Sphk } 38449982Sbillf return (dev->si_name); 38549982Sbillf} 38665374Sphk 38765374Sphkint 38865374Sphkdev_stdclone(char *name, char **namep, char *stem, int *unit) 38965374Sphk{ 39065374Sphk int u, i; 39165374Sphk 39265374Sphk if (bcmp(stem, name, strlen(stem)) != 0) 39365374Sphk return (0); 39465374Sphk i = strlen(stem); 39565374Sphk if (!isdigit(name[i])) 39665374Sphk return (0); 39765374Sphk u = 0; 39865374Sphk while (isdigit(name[i])) { 39965374Sphk u *= 10; 40065374Sphk u += name[i++] - '0'; 40165374Sphk } 40265374Sphk *unit = u; 40365374Sphk if (namep) 40465374Sphk *namep = &name[i]; 40565374Sphk if (name[i]) 40665374Sphk return (2); 40765374Sphk return (1); 40865374Sphk} 409