kern_conf.c revision 111622
111126Sjulian/*- 2103722Sphk * Copyright (c) 1999-2002 Poul-Henning Kamp 311126Sjulian * All rights reserved. 411126Sjulian * 511126Sjulian * Redistribution and use in source and binary forms, with or without 611126Sjulian * modification, are permitted provided that the following conditions 711126Sjulian * are met: 811126Sjulian * 1. Redistributions of source code must retain the above copyright 911126Sjulian * notice, this list of conditions and the following disclaimer. 1011126Sjulian * 2. Redistributions in binary form must reproduce the above copyright 1111126Sjulian * notice, this list of conditions and the following disclaimer in the 1211126Sjulian * documentation and/or other materials provided with the distribution. 1311126Sjulian * 14103722Sphk * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15103722Sphk * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1611126Sjulian * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17103722Sphk * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 1811126Sjulian * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 1911126Sjulian * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2011126Sjulian * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2111126Sjulian * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2211126Sjulian * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2311126Sjulian * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2411126Sjulian * SUCH DAMAGE. 2511126Sjulian * 2650477Speter * $FreeBSD: head/sys/kern/kern_conf.c 111622 2003-02-27 14:46:51Z phk $ 2711126Sjulian */ 2811126Sjulian 2911126Sjulian#include <sys/param.h> 3048936Sphk#include <sys/kernel.h> 3183366Sjulian#include <sys/systm.h> 32111179Sphk#include <sys/bio.h> 3390737Sgreen#include <sys/lock.h> 3490737Sgreen#include <sys/mutex.h> 3550549Sphk#include <sys/sysctl.h> 3636735Sdfr#include <sys/module.h> 3748936Sphk#include <sys/malloc.h> 3811126Sjulian#include <sys/conf.h> 3912954Sjulian#include <sys/vnode.h> 4048936Sphk#include <sys/queue.h> 4165374Sphk#include <sys/ctype.h> 4249535Sphk#include <machine/stdarg.h> 4311126Sjulian 4469774Sphkstatic MALLOC_DEFINE(M_DEVT, "dev_t", "dev_t storage"); 4548936Sphk 46111622Sphk/* Built at compile time from sys/conf/majors */ 47111622Sphkextern unsigned char reserved_majors[256]; 48111622Sphk 4950522Sphk/* 5050522Sphk * This is the number of hash-buckets. Experiements with 'real-life' 5150522Sphk * udev_t's show that a prime halfway between two powers of two works 5250522Sphk * best. 5350522Sphk */ 5448936Sphk#define DEVT_HASH 83 5550522Sphk 5650522Sphk/* The number of dev_t's we can create before malloc(9) kick in. */ 5748936Sphk#define DEVT_STASH 50 5848936Sphk 59104043Sphkstatic struct cdev devt_stash[DEVT_STASH]; 6048936Sphk 61104043Sphkstatic LIST_HEAD(, cdev) dev_hash[DEVT_HASH]; 6248936Sphk 63104043Sphkstatic LIST_HEAD(, cdev) dev_free; 6450549Sphk 6550254Sphkdevfs_create_t *devfs_create_hook; 6665374Sphkdevfs_destroy_t *devfs_destroy_hook; 6750254Sphk 6889118Smsmithstatic int ready_for_devs; 6989118Smsmith 7050549Sphkstatic int free_devt; 7150549SphkSYSCTL_INT(_debug, OID_AUTO, free_devt, CTLFLAG_RW, &free_devt, 0, ""); 7250549Sphk 73111179Sphk/* Define a dead_cdevsw for use when devices leave unexpectedly. */ 7485603Sphk 75111179Sphkstatic int 76111179Sphkenxio(void) 77111179Sphk{ 78111179Sphk return (ENXIO); 79111179Sphk} 80111179Sphk 81111179Sphk#define dead_open (d_open_t *)enxio 82111179Sphk#define dead_close (d_close_t *)enxio 83111179Sphk#define dead_read (d_read_t *)enxio 84111179Sphk#define dead_write (d_write_t *)enxio 85111179Sphk#define dead_ioctl (d_ioctl_t *)enxio 86111179Sphk#define dead_poll nopoll 87111179Sphk#define dead_mmap nommap 88111179Sphk 89111179Sphkstatic void 90111179Sphkdead_strategy(struct bio *bp) 91111179Sphk{ 92111179Sphk 93111179Sphk biofinish(bp, NULL, ENXIO); 94111179Sphk} 95111179Sphk 96111220Sphk#define dead_dump (dumper_t *)enxio 97111179Sphk 98111179Sphkstatic int 99111179Sphkdead_psize(dev_t dev) 100111179Sphk{ 101111179Sphk 102111179Sphk return (-1); 103111179Sphk} 104111179Sphk 105111179Sphk#define dead_kqfilter (d_kqfilter_t *)enxio 106111179Sphk 107111179Sphkstatic struct cdevsw dead_cdevsw = { 108111179Sphk /* open */ dead_open, 109111179Sphk /* close */ dead_close, 110111179Sphk /* read */ dead_read, 111111179Sphk /* write */ dead_write, 112111179Sphk /* ioctl */ dead_ioctl, 113111179Sphk /* poll */ dead_poll, 114111179Sphk /* mmap */ dead_mmap, 115111179Sphk /* strategy */ dead_strategy, 116111179Sphk /* name */ "dead", 117111179Sphk /* maj */ 255, 118111179Sphk /* dump */ dead_dump, 119111179Sphk /* psize */ dead_psize, 120111179Sphk /* flags */ 0, 121111179Sphk /* kqfilter */ dead_kqfilter 122111179Sphk}; 123111179Sphk 124111179Sphk 12547640Sphkstruct cdevsw * 12647640Sphkdevsw(dev_t dev) 12751927Sphk{ 12849679Sphk if (dev->si_devsw) 12949679Sphk return (dev->si_devsw); 130111179Sphk return (&dead_cdevsw); 13147640Sphk} 13247640Sphk 13347640Sphk/* 13447028Sphk * dev_t and u_dev_t primitives 13547028Sphk */ 13647028Sphk 13751927Sphkint 13847028Sphkmajor(dev_t x) 13947028Sphk{ 14048936Sphk if (x == NODEV) 14148936Sphk return NOUDEV; 14248936Sphk return((x->si_udev >> 8) & 0xff); 14347028Sphk} 14447028Sphk 14547028Sphkint 14647028Sphkminor(dev_t x) 14747028Sphk{ 14848936Sphk if (x == NODEV) 14948936Sphk return NOUDEV; 15048936Sphk return(x->si_udev & 0xffff00ff); 15147028Sphk} 15247028Sphk 15349826Sphkint 15466067Sphkdev2unit(dev_t x) 15549826Sphk{ 15649826Sphk int i; 15749826Sphk 15849826Sphk if (x == NODEV) 15949826Sphk return NOUDEV; 16049826Sphk i = minor(x); 16149826Sphk return ((i & 0xff) | (i >> 8)); 16249826Sphk} 16349826Sphk 16466067Sphkint 16566067Sphkunit2minor(int unit) 16666067Sphk{ 16766067Sphk 16874522Sphk KASSERT(unit <= 0xffffff, ("Invalid unit (%d) in unit2minor", unit)); 16966067Sphk return ((unit & 0xff) | ((unit << 8) & ~0xffff)); 17066067Sphk} 17166067Sphk 17264880Sphkstatic dev_t 17364880Sphkallocdev(void) 17464880Sphk{ 17564880Sphk static int stashed; 176104043Sphk struct cdev *si; 17764880Sphk 178103101Sphk if (LIST_FIRST(&dev_free)) { 179103101Sphk si = LIST_FIRST(&dev_free); 180103101Sphk LIST_REMOVE(si, si_hash); 181103101Sphk } else if (stashed >= DEVT_STASH) { 182104043Sphk MALLOC(si, struct cdev *, sizeof(*si), M_DEVT, 183111146Sphk M_USE_RESERVE | M_ZERO | M_WAITOK); 18464880Sphk } else { 18564880Sphk si = devt_stash + stashed++; 18677215Sphk bzero(si, sizeof *si); 187103101Sphk si->si_flags |= SI_STASHED; 18864880Sphk } 189110317Sphk si->__si_namebuf[0] = '\0'; 190110317Sphk si->si_name = si->__si_namebuf; 19177215Sphk LIST_INIT(&si->si_children); 19273942Smckusick TAILQ_INIT(&si->si_snapshots); 19364880Sphk return (si); 19464880Sphk} 19564880Sphk 19647680Sphkdev_t 19747028Sphkmakedev(int x, int y) 19847028Sphk{ 199104043Sphk struct cdev *si; 20048936Sphk udev_t udev; 20148936Sphk int hash; 20248936Sphk 20355414Sphk if (x == umajor(NOUDEV) && y == uminor(NOUDEV)) 20471342Sphk panic("makedev of NOUDEV"); 20548936Sphk udev = (x << 8) | y; 20648936Sphk hash = udev % DEVT_HASH; 20750549Sphk LIST_FOREACH(si, &dev_hash[hash], si_hash) { 20848936Sphk if (si->si_udev == udev) 20948936Sphk return (si); 21048936Sphk } 21164880Sphk si = allocdev(); 21248936Sphk si->si_udev = udev; 21350549Sphk LIST_INSERT_HEAD(&dev_hash[hash], si, si_hash); 21448936Sphk return (si); 21547028Sphk} 21647028Sphk 21750549Sphkvoid 21850549Sphkfreedev(dev_t dev) 21950549Sphk{ 22050549Sphk 22150549Sphk if (!free_devt) 22250549Sphk return; 22350549Sphk if (SLIST_FIRST(&dev->si_hlist)) 22450549Sphk return; 22551927Sphk if (dev->si_devsw || dev->si_drv1 || dev->si_drv2) 22650549Sphk return; 22750549Sphk LIST_REMOVE(dev, si_hash); 22850549Sphk if (dev->si_flags & SI_STASHED) { 22950549Sphk bzero(dev, sizeof(*dev)); 23077215Sphk dev->si_flags |= SI_STASHED; 23150549Sphk LIST_INSERT_HEAD(&dev_free, dev, si_hash); 23250549Sphk } else { 23350549Sphk FREE(dev, M_DEVT); 23450549Sphk } 23550549Sphk} 23650549Sphk 23747028Sphkudev_t 23847028Sphkdev2udev(dev_t x) 23947028Sphk{ 24048936Sphk if (x == NODEV) 24148936Sphk return NOUDEV; 24248936Sphk return (x->si_udev); 24347028Sphk} 24447028Sphk 24547028Sphkdev_t 24647028Sphkudev2dev(udev_t x, int b) 24747028Sphk{ 24855414Sphk 24955414Sphk if (x == NOUDEV) 25055414Sphk return (NODEV); 25148864Sphk switch (b) { 25248864Sphk case 0: 25348864Sphk return makedev(umajor(x), uminor(x)); 25448864Sphk case 1: 25568063Sphk return (NODEV); 25648864Sphk default: 25748864Sphk Debugger("udev2dev(...,X)"); 25848864Sphk return NODEV; 25948864Sphk } 26047028Sphk} 26147028Sphk 26247028Sphkint 26347028Sphkuminor(udev_t dev) 26447028Sphk{ 26547028Sphk return(dev & 0xffff00ff); 26647028Sphk} 26747028Sphk 26847028Sphkint 26947028Sphkumajor(udev_t dev) 27047028Sphk{ 27147028Sphk return((dev & 0xff00) >> 8); 27247028Sphk} 27347028Sphk 27447028Sphkudev_t 27548859Sphkmakeudev(int x, int y) 27647028Sphk{ 27747028Sphk return ((x << 8) | y); 27847028Sphk} 27947028Sphk 28049535Sphkdev_t 28181068Simpmake_dev(struct cdevsw *devsw, int minor, uid_t uid, gid_t gid, int perms, const char *fmt, ...) 28249535Sphk{ 28349535Sphk dev_t dev; 28449535Sphk va_list ap; 28549535Sphk int i; 28649535Sphk 287111622Sphk KASSERT((minor & ~0xffff00ff) == 0, 288111622Sphk ("Invalid minor (0x%x) in make_dev", minor)); 28971920Sbrian 290111622Sphk if (devsw->d_maj == MAJOR_AUTO) { 291111622Sphk for (i = NUMCDEVSW - 1; i > 0; i--) 292111622Sphk if (reserved_majors[i] != i) 293111622Sphk break; 294111622Sphk KASSERT(i > 0, ("Out of major numbers (%s)", devsw->d_name)); 295111622Sphk printf("Allocating major#%d to \"%s\"\n", i, devsw->d_name); 296111622Sphk devsw->d_maj = i; 297111622Sphk reserved_majors[i] = i; 298111622Sphk } 299111622Sphk 30089118Smsmith if (!ready_for_devs) { 30189118Smsmith printf("WARNING: Driver mistake: make_dev(%s) called before SI_SUB_DRIVERS\n", 30289118Smsmith fmt); 30389118Smsmith /* XXX panic here once drivers are cleaned up */ 30489118Smsmith } 30589118Smsmith 30649535Sphk dev = makedev(devsw->d_maj, minor); 30765747Sphk if (dev->si_flags & SI_NAMED) { 30865747Sphk printf( "WARNING: Driver mistake: repeat make_dev(\"%s\")\n", 30965747Sphk dev->si_name); 31085603Sphk panic("don't do that"); 31165747Sphk return (dev); 31265747Sphk } 31349535Sphk va_start(ap, fmt); 314110318Sphk i = vsnrprintf(dev->__si_namebuf, sizeof dev->__si_namebuf, 32, fmt, ap); 315110318Sphk if (i > (sizeof dev->__si_namebuf - 1)) { 316110318Sphk printf("WARNING: Device name truncated! (%s)", 317110318Sphk dev->__si_namebuf); 318110318Sphk } 31949535Sphk va_end(ap); 32049535Sphk dev->si_devsw = devsw; 32164880Sphk dev->si_uid = uid; 32264880Sphk dev->si_gid = gid; 32364880Sphk dev->si_mode = perms; 32465747Sphk dev->si_flags |= SI_NAMED; 32550092Sjulian 32650254Sphk if (devfs_create_hook) 32764880Sphk devfs_create_hook(dev); 32849535Sphk return (dev); 32949535Sphk} 33049535Sphk 33185076Sjlemonint 33285076Sjlemondev_named(dev_t pdev, const char *name) 33385076Sjlemon{ 33485076Sjlemon dev_t cdev; 33585076Sjlemon 33685076Sjlemon if (strcmp(devtoname(pdev), name) == 0) 33785076Sjlemon return (1); 33885076Sjlemon LIST_FOREACH(cdev, &pdev->si_children, si_siblings) 33985076Sjlemon if (strcmp(devtoname(cdev), name) == 0) 34085076Sjlemon return (1); 34185076Sjlemon return (0); 34285076Sjlemon} 34385076Sjlemon 34477215Sphkvoid 34577215Sphkdev_depends(dev_t pdev, dev_t cdev) 34677215Sphk{ 34777215Sphk 34877215Sphk cdev->si_parent = pdev; 34977215Sphk cdev->si_flags |= SI_CHILD; 35077215Sphk LIST_INSERT_HEAD(&pdev->si_children, cdev, si_siblings); 35177215Sphk} 35277215Sphk 35364880Sphkdev_t 35481068Simpmake_dev_alias(dev_t pdev, const char *fmt, ...) 35564880Sphk{ 35664880Sphk dev_t dev; 35764880Sphk va_list ap; 35864880Sphk int i; 35964880Sphk 36064880Sphk dev = allocdev(); 36164880Sphk dev->si_flags |= SI_ALIAS; 36265747Sphk dev->si_flags |= SI_NAMED; 36377215Sphk dev_depends(pdev, dev); 36464880Sphk va_start(ap, fmt); 365110318Sphk i = vsnrprintf(dev->__si_namebuf, sizeof dev->__si_namebuf, 32, fmt, ap); 366110318Sphk if (i > (sizeof dev->__si_namebuf - 1)) { 367110318Sphk printf("WARNING: Device name truncated! (%s)", 368110318Sphk dev->__si_namebuf); 369110318Sphk } 37064880Sphk va_end(ap); 37164880Sphk 37264880Sphk if (devfs_create_hook) 37364880Sphk devfs_create_hook(dev); 37464880Sphk return (dev); 37564880Sphk} 37664880Sphk 37750549Sphkvoid 37890736Sgreenrevoke_and_destroy_dev(dev_t dev) 37990736Sgreen{ 38090736Sgreen struct vnode *vp; 38190736Sgreen 38290736Sgreen GIANT_REQUIRED; 38390736Sgreen 38490736Sgreen vp = SLIST_FIRST(&dev->si_hlist); 38590736Sgreen if (vp != NULL) 38690736Sgreen VOP_REVOKE(vp, REVOKEALL); 38790736Sgreen destroy_dev(dev); 38890736Sgreen} 38990736Sgreen 39090736Sgreenvoid 39153000Sphkdestroy_dev(dev_t dev) 39250549Sphk{ 39365747Sphk 39465747Sphk if (!(dev->si_flags & SI_NAMED)) { 39565747Sphk printf( "WARNING: Driver mistake: destroy_dev on %d/%d\n", 39665747Sphk major(dev), minor(dev)); 39785603Sphk panic("don't do that"); 39865747Sphk return; 39965747Sphk } 40065747Sphk 40165374Sphk if (devfs_destroy_hook) 40265374Sphk devfs_destroy_hook(dev); 40377215Sphk if (dev->si_flags & SI_CHILD) { 40477215Sphk LIST_REMOVE(dev, si_siblings); 40577215Sphk dev->si_flags &= ~SI_CHILD; 40677215Sphk } 40777215Sphk while (!LIST_EMPTY(&dev->si_children)) 40877215Sphk destroy_dev(LIST_FIRST(&dev->si_children)); 40950549Sphk dev->si_drv1 = 0; 41050549Sphk dev->si_drv2 = 0; 41150549Sphk dev->si_devsw = 0; 41295446Sbde bzero(&dev->__si_u, sizeof(dev->__si_u)); 41365747Sphk dev->si_flags &= ~SI_NAMED; 41465747Sphk dev->si_flags &= ~SI_ALIAS; 41550549Sphk freedev(dev); 41650549Sphk} 41750549Sphk 41851225Sbdeconst char * 41949982Sbillfdevtoname(dev_t dev) 42049982Sbillf{ 42150549Sphk char *p; 42251225Sbde int mynor; 42349982Sbillf 42450549Sphk if (dev->si_name[0] == '#' || dev->si_name[0] == '\0') { 42550549Sphk p = dev->si_name; 42650549Sphk if (devsw(dev)) 42750549Sphk sprintf(p, "#%s/", devsw(dev)->d_name); 42850549Sphk else 42950549Sphk sprintf(p, "#%d/", major(dev)); 43050549Sphk p += strlen(p); 43151225Sbde mynor = minor(dev); 43251225Sbde if (mynor < 0 || mynor > 255) 43351225Sbde sprintf(p, "%#x", (u_int)mynor); 43451225Sbde else 43551225Sbde sprintf(p, "%d", mynor); 43650549Sphk } 43749982Sbillf return (dev->si_name); 43849982Sbillf} 43965374Sphk 44065374Sphkint 44191998Sphkdev_stdclone(char *name, char **namep, const char *stem, int *unit) 44265374Sphk{ 44365374Sphk int u, i; 44465374Sphk 44575519Sbrian i = strlen(stem); 44675519Sbrian if (bcmp(stem, name, i) != 0) 44765374Sphk return (0); 44865374Sphk if (!isdigit(name[i])) 44965374Sphk return (0); 45065374Sphk u = 0; 45186461Sphk if (name[i] == '0' && isdigit(name[i+1])) 45286461Sphk return (0); 45365374Sphk while (isdigit(name[i])) { 45465374Sphk u *= 10; 45565374Sphk u += name[i++] - '0'; 45665374Sphk } 457104523Sgreen if (u > 0xffffff) 458104523Sgreen return (0); 45965374Sphk *unit = u; 46065374Sphk if (namep) 46165374Sphk *namep = &name[i]; 46265374Sphk if (name[i]) 46365374Sphk return (2); 46465374Sphk return (1); 46565374Sphk} 46665632Sphk 46765632Sphk/* 46865632Sphk * Helper sysctl for devname(3). We're given a {u}dev_t and return 46965632Sphk * the name, if any, registered by the device driver. 47065632Sphk */ 47165632Sphkstatic int 47265632Sphksysctl_devname(SYSCTL_HANDLER_ARGS) 47365632Sphk{ 47465632Sphk int error; 47565632Sphk udev_t ud; 47665632Sphk dev_t dev; 47765632Sphk 47865632Sphk error = SYSCTL_IN(req, &ud, sizeof (ud)); 47965632Sphk if (error) 48065632Sphk return (error); 48171342Sphk if (ud == NOUDEV) 48271342Sphk return(EINVAL); 48365632Sphk dev = makedev(umajor(ud), uminor(ud)); 48465632Sphk if (dev->si_name[0] == '\0') 48565632Sphk error = ENOENT; 48665632Sphk else 48765632Sphk error = SYSCTL_OUT(req, dev->si_name, strlen(dev->si_name) + 1); 48865632Sphk freedev(dev); 48965632Sphk return (error); 49065632Sphk} 49165632Sphk 49267905SphkSYSCTL_PROC(_kern, OID_AUTO, devname, CTLTYPE_OPAQUE|CTLFLAG_RW|CTLFLAG_ANYBODY, 49365632Sphk NULL, 0, sysctl_devname, "", "devname(3) handler"); 49489118Smsmith 49589118Smsmith/* 49689118Smsmith * Set ready_for_devs; prior to this point, device creation is not allowed. 49789118Smsmith */ 49889118Smsmithstatic void 49989118Smsmithdev_set_ready(void *junk) 50089118Smsmith{ 50189118Smsmith ready_for_devs = 1; 50289118Smsmith} 50389118Smsmith 50489118SmsmithSYSINIT(dev_ready, SI_SUB_DEVFS, SI_ORDER_FIRST, dev_set_ready, NULL); 505