kern_conf.c revision 91998
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 91998 2002-03-10 10:50:05Z phk $ 3411126Sjulian */ 3511126Sjulian 3611126Sjulian#include <sys/param.h> 3748936Sphk#include <sys/kernel.h> 3883366Sjulian#include <sys/systm.h> 3990737Sgreen#include <sys/lock.h> 4090737Sgreen#include <sys/mutex.h> 4150549Sphk#include <sys/sysctl.h> 4236735Sdfr#include <sys/module.h> 4348936Sphk#include <sys/malloc.h> 4411126Sjulian#include <sys/conf.h> 4512954Sjulian#include <sys/vnode.h> 4648936Sphk#include <sys/queue.h> 4765374Sphk#include <sys/ctype.h> 4849535Sphk#include <machine/stdarg.h> 4911126Sjulian 5047640Sphk#define cdevsw_ALLOCSTART (NUMCDEVSW/2) 5112954Sjulian 5285539Sphkstatic struct cdevsw *cdevsw[NUMCDEVSW]; 5312954Sjulian 5469774Sphkstatic MALLOC_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 7689118Smsmithstatic int ready_for_devs; 7789118Smsmith 7850549Sphkstatic int free_devt; 7950549SphkSYSCTL_INT(_debug, OID_AUTO, free_devt, CTLFLAG_RW, &free_devt, 0, ""); 8050549Sphk 8185603Sphk/* XXX: This is a hack */ 8285603Sphkvoid disk_dev_synth(dev_t dev); 8385603Sphk 8447640Sphkstruct cdevsw * 8547640Sphkdevsw(dev_t dev) 8651927Sphk{ 8749679Sphk if (dev->si_devsw) 8849679Sphk return (dev->si_devsw); 8985603Sphk /* XXX: Hack around our backwards disk code */ 9085603Sphk disk_dev_synth(dev); 9185603Sphk if (dev->si_devsw) 9285603Sphk return (dev->si_devsw); 9385603Sphk if (devfs_present) 9485624Sphk return (NULL); 9547640Sphk return(cdevsw[major(dev)]); 9647640Sphk} 9747640Sphk 9847640Sphk/* 9947640Sphk * Add a cdevsw entry 10047640Sphk */ 10147640Sphk 10237389Sjulianint 10347640Sphkcdevsw_add(struct cdevsw *newentry) 10417264Sphk{ 10517264Sphk 10647640Sphk if (newentry->d_maj < 0 || newentry->d_maj >= NUMCDEVSW) { 10747640Sphk printf("%s: ERROR: driver has bogus cdevsw->d_maj = %d\n", 10847640Sphk newentry->d_name, newentry->d_maj); 10951927Sphk return (EINVAL); 11037389Sjulian } 11117264Sphk 11248510Sphk if (cdevsw[newentry->d_maj]) { 11348510Sphk printf("WARNING: \"%s\" is usurping \"%s\"'s cdevsw[]\n", 11448510Sphk newentry->d_name, cdevsw[newentry->d_maj]->d_name); 11548510Sphk } 11651927Sphk 11747640Sphk cdevsw[newentry->d_maj] = newentry; 11837389Sjulian 11951927Sphk return (0); 12051927Sphk} 12147640Sphk 12248211Sgrog/* 12348211Sgrog * Remove a cdevsw entry 12448211Sgrog */ 12548211Sgrog 12636735Sdfrint 12748211Sgrogcdevsw_remove(struct cdevsw *oldentry) 12848211Sgrog{ 12948211Sgrog if (oldentry->d_maj < 0 || oldentry->d_maj >= NUMCDEVSW) { 13048211Sgrog printf("%s: ERROR: driver has bogus cdevsw->d_maj = %d\n", 13148211Sgrog oldentry->d_name, oldentry->d_maj); 13248211Sgrog return EINVAL; 13348211Sgrog } 13448211Sgrog 13548211Sgrog cdevsw[oldentry->d_maj] = NULL; 13648211Sgrog 13748211Sgrog return 0; 13851927Sphk} 13948211Sgrog 14047028Sphk/* 14147028Sphk * dev_t and u_dev_t primitives 14247028Sphk */ 14347028Sphk 14451927Sphkint 14547028Sphkmajor(dev_t x) 14647028Sphk{ 14748936Sphk if (x == NODEV) 14848936Sphk return NOUDEV; 14948936Sphk return((x->si_udev >> 8) & 0xff); 15047028Sphk} 15147028Sphk 15247028Sphkint 15347028Sphkminor(dev_t x) 15447028Sphk{ 15548936Sphk if (x == NODEV) 15648936Sphk return NOUDEV; 15748936Sphk return(x->si_udev & 0xffff00ff); 15847028Sphk} 15947028Sphk 16049826Sphkint 16166067Sphkdev2unit(dev_t x) 16249826Sphk{ 16349826Sphk int i; 16449826Sphk 16549826Sphk if (x == NODEV) 16649826Sphk return NOUDEV; 16749826Sphk i = minor(x); 16849826Sphk return ((i & 0xff) | (i >> 8)); 16949826Sphk} 17049826Sphk 17166067Sphkint 17266067Sphkunit2minor(int unit) 17366067Sphk{ 17466067Sphk 17574522Sphk KASSERT(unit <= 0xffffff, ("Invalid unit (%d) in unit2minor", unit)); 17666067Sphk return ((unit & 0xff) | ((unit << 8) & ~0xffff)); 17766067Sphk} 17866067Sphk 17964880Sphkstatic dev_t 18064880Sphkallocdev(void) 18164880Sphk{ 18264880Sphk static int stashed; 18364880Sphk struct specinfo *si; 18464880Sphk 18564880Sphk if (stashed >= DEVT_STASH) { 18664880Sphk MALLOC(si, struct specinfo *, sizeof(*si), M_DEVT, 18769781Sdwmalone M_USE_RESERVE | M_ZERO); 18864880Sphk } else if (LIST_FIRST(&dev_free)) { 18964880Sphk si = LIST_FIRST(&dev_free); 19064880Sphk LIST_REMOVE(si, si_hash); 19164880Sphk } else { 19264880Sphk si = devt_stash + stashed++; 19377215Sphk bzero(si, sizeof *si); 19477215Sphk si->si_flags |= SI_STASHED; 19564880Sphk } 19677215Sphk LIST_INIT(&si->si_children); 19773942Smckusick TAILQ_INIT(&si->si_snapshots); 19864880Sphk return (si); 19964880Sphk} 20064880Sphk 20147680Sphkdev_t 20247028Sphkmakedev(int x, int y) 20347028Sphk{ 20448936Sphk struct specinfo *si; 20548936Sphk udev_t udev; 20648936Sphk int hash; 20748936Sphk 20855414Sphk if (x == umajor(NOUDEV) && y == uminor(NOUDEV)) 20971342Sphk panic("makedev of NOUDEV"); 21048936Sphk udev = (x << 8) | y; 21148936Sphk hash = udev % DEVT_HASH; 21250549Sphk LIST_FOREACH(si, &dev_hash[hash], si_hash) { 21348936Sphk if (si->si_udev == udev) 21448936Sphk return (si); 21548936Sphk } 21664880Sphk si = allocdev(); 21748936Sphk si->si_udev = udev; 21850549Sphk LIST_INSERT_HEAD(&dev_hash[hash], si, si_hash); 21948936Sphk return (si); 22047028Sphk} 22147028Sphk 22250549Sphkvoid 22350549Sphkfreedev(dev_t dev) 22450549Sphk{ 22550549Sphk 22650549Sphk if (!free_devt) 22750549Sphk return; 22850549Sphk if (SLIST_FIRST(&dev->si_hlist)) 22950549Sphk return; 23051927Sphk if (dev->si_devsw || dev->si_drv1 || dev->si_drv2) 23150549Sphk return; 23250549Sphk LIST_REMOVE(dev, si_hash); 23350549Sphk if (dev->si_flags & SI_STASHED) { 23450549Sphk bzero(dev, sizeof(*dev)); 23577215Sphk dev->si_flags |= SI_STASHED; 23650549Sphk LIST_INSERT_HEAD(&dev_free, dev, si_hash); 23750549Sphk } else { 23850549Sphk FREE(dev, M_DEVT); 23950549Sphk } 24050549Sphk} 24150549Sphk 24247028Sphkudev_t 24347028Sphkdev2udev(dev_t x) 24447028Sphk{ 24548936Sphk if (x == NODEV) 24648936Sphk return NOUDEV; 24748936Sphk return (x->si_udev); 24847028Sphk} 24947028Sphk 25047028Sphkdev_t 25147028Sphkudev2dev(udev_t x, int b) 25247028Sphk{ 25355414Sphk 25455414Sphk if (x == NOUDEV) 25555414Sphk return (NODEV); 25648864Sphk switch (b) { 25748864Sphk case 0: 25848864Sphk return makedev(umajor(x), uminor(x)); 25948864Sphk case 1: 26068063Sphk return (NODEV); 26148864Sphk default: 26248864Sphk Debugger("udev2dev(...,X)"); 26348864Sphk return NODEV; 26448864Sphk } 26547028Sphk} 26647028Sphk 26747028Sphkint 26847028Sphkuminor(udev_t dev) 26947028Sphk{ 27047028Sphk return(dev & 0xffff00ff); 27147028Sphk} 27247028Sphk 27347028Sphkint 27447028Sphkumajor(udev_t dev) 27547028Sphk{ 27647028Sphk return((dev & 0xff00) >> 8); 27747028Sphk} 27847028Sphk 27947028Sphkudev_t 28048859Sphkmakeudev(int x, int y) 28147028Sphk{ 28247028Sphk return ((x << 8) | y); 28347028Sphk} 28447028Sphk 28549535Sphkdev_t 28681068Simpmake_dev(struct cdevsw *devsw, int minor, uid_t uid, gid_t gid, int perms, const char *fmt, ...) 28749535Sphk{ 28849535Sphk dev_t dev; 28949535Sphk va_list ap; 29049535Sphk int i; 29149535Sphk 29271920Sbrian KASSERT(umajor(makeudev(devsw->d_maj, minor)) == devsw->d_maj, 29371920Sbrian ("Invalid minor (%d) in make_dev", minor)); 29471920Sbrian 29589118Smsmith if (!ready_for_devs) { 29689118Smsmith printf("WARNING: Driver mistake: make_dev(%s) called before SI_SUB_DRIVERS\n", 29789118Smsmith fmt); 29889118Smsmith /* XXX panic here once drivers are cleaned up */ 29989118Smsmith } 30089118Smsmith 30149535Sphk dev = makedev(devsw->d_maj, minor); 30265747Sphk if (dev->si_flags & SI_NAMED) { 30365747Sphk printf( "WARNING: Driver mistake: repeat make_dev(\"%s\")\n", 30465747Sphk dev->si_name); 30585603Sphk panic("don't do that"); 30665747Sphk return (dev); 30765747Sphk } 30849535Sphk va_start(ap, fmt); 30956465Sbp i = kvprintf(fmt, NULL, dev->si_name, 32, ap); 31049535Sphk dev->si_name[i] = '\0'; 31149535Sphk va_end(ap); 31249535Sphk dev->si_devsw = devsw; 31364880Sphk dev->si_uid = uid; 31464880Sphk dev->si_gid = gid; 31564880Sphk dev->si_mode = perms; 31665747Sphk dev->si_flags |= SI_NAMED; 31750092Sjulian 31850254Sphk if (devfs_create_hook) 31964880Sphk devfs_create_hook(dev); 32049535Sphk return (dev); 32149535Sphk} 32249535Sphk 32385076Sjlemonint 32485076Sjlemondev_named(dev_t pdev, const char *name) 32585076Sjlemon{ 32685076Sjlemon dev_t cdev; 32785076Sjlemon 32885076Sjlemon if (strcmp(devtoname(pdev), name) == 0) 32985076Sjlemon return (1); 33085076Sjlemon LIST_FOREACH(cdev, &pdev->si_children, si_siblings) 33185076Sjlemon if (strcmp(devtoname(cdev), name) == 0) 33285076Sjlemon return (1); 33385076Sjlemon return (0); 33485076Sjlemon} 33585076Sjlemon 33677215Sphkvoid 33777215Sphkdev_depends(dev_t pdev, dev_t cdev) 33877215Sphk{ 33977215Sphk 34077215Sphk cdev->si_parent = pdev; 34177215Sphk cdev->si_flags |= SI_CHILD; 34277215Sphk LIST_INSERT_HEAD(&pdev->si_children, cdev, si_siblings); 34377215Sphk} 34477215Sphk 34564880Sphkdev_t 34681068Simpmake_dev_alias(dev_t pdev, const 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; 35577215Sphk dev_depends(pdev, dev); 35664880Sphk va_start(ap, fmt); 35764880Sphk i = kvprintf(fmt, NULL, dev->si_name, 32, ap); 35864880Sphk dev->si_name[i] = '\0'; 35964880Sphk va_end(ap); 36064880Sphk 36164880Sphk if (devfs_create_hook) 36264880Sphk devfs_create_hook(dev); 36364880Sphk return (dev); 36464880Sphk} 36564880Sphk 36650549Sphkvoid 36790736Sgreenrevoke_and_destroy_dev(dev_t dev) 36890736Sgreen{ 36990736Sgreen struct vnode *vp; 37090736Sgreen 37190736Sgreen GIANT_REQUIRED; 37290736Sgreen 37390736Sgreen vp = SLIST_FIRST(&dev->si_hlist); 37490736Sgreen if (vp != NULL) 37590736Sgreen VOP_REVOKE(vp, REVOKEALL); 37690736Sgreen destroy_dev(dev); 37790736Sgreen} 37890736Sgreen 37990736Sgreenvoid 38053000Sphkdestroy_dev(dev_t dev) 38150549Sphk{ 38265747Sphk 38365747Sphk if (!(dev->si_flags & SI_NAMED)) { 38465747Sphk printf( "WARNING: Driver mistake: destroy_dev on %d/%d\n", 38565747Sphk major(dev), minor(dev)); 38685603Sphk panic("don't do that"); 38765747Sphk return; 38865747Sphk } 38965747Sphk 39065374Sphk if (devfs_destroy_hook) 39165374Sphk devfs_destroy_hook(dev); 39277215Sphk if (dev->si_flags & SI_CHILD) { 39377215Sphk LIST_REMOVE(dev, si_siblings); 39477215Sphk dev->si_flags &= ~SI_CHILD; 39577215Sphk } 39677215Sphk while (!LIST_EMPTY(&dev->si_children)) 39777215Sphk destroy_dev(LIST_FIRST(&dev->si_children)); 39850549Sphk dev->si_drv1 = 0; 39950549Sphk dev->si_drv2 = 0; 40050549Sphk dev->si_devsw = 0; 40165747Sphk dev->si_flags &= ~SI_NAMED; 40265747Sphk dev->si_flags &= ~SI_ALIAS; 40350549Sphk freedev(dev); 40450549Sphk} 40550549Sphk 40651225Sbdeconst char * 40749982Sbillfdevtoname(dev_t dev) 40849982Sbillf{ 40950549Sphk char *p; 41051225Sbde int mynor; 41149982Sbillf 41250549Sphk if (dev->si_name[0] == '#' || dev->si_name[0] == '\0') { 41350549Sphk p = dev->si_name; 41450549Sphk if (devsw(dev)) 41550549Sphk sprintf(p, "#%s/", devsw(dev)->d_name); 41650549Sphk else 41750549Sphk sprintf(p, "#%d/", major(dev)); 41850549Sphk p += strlen(p); 41951225Sbde mynor = minor(dev); 42051225Sbde if (mynor < 0 || mynor > 255) 42151225Sbde sprintf(p, "%#x", (u_int)mynor); 42251225Sbde else 42351225Sbde sprintf(p, "%d", mynor); 42450549Sphk } 42549982Sbillf return (dev->si_name); 42649982Sbillf} 42765374Sphk 42865374Sphkint 42991998Sphkdev_stdclone(char *name, char **namep, const char *stem, int *unit) 43065374Sphk{ 43165374Sphk int u, i; 43265374Sphk 43375519Sbrian i = strlen(stem); 43475519Sbrian if (bcmp(stem, name, i) != 0) 43565374Sphk return (0); 43665374Sphk if (!isdigit(name[i])) 43765374Sphk return (0); 43865374Sphk u = 0; 43986461Sphk if (name[i] == '0' && isdigit(name[i+1])) 44086461Sphk return (0); 44165374Sphk while (isdigit(name[i])) { 44265374Sphk u *= 10; 44365374Sphk u += name[i++] - '0'; 44465374Sphk } 44565374Sphk *unit = u; 44665374Sphk if (namep) 44765374Sphk *namep = &name[i]; 44865374Sphk if (name[i]) 44965374Sphk return (2); 45065374Sphk return (1); 45165374Sphk} 45265632Sphk 45365632Sphk/* 45465632Sphk * Helper sysctl for devname(3). We're given a {u}dev_t and return 45565632Sphk * the name, if any, registered by the device driver. 45665632Sphk */ 45765632Sphkstatic int 45865632Sphksysctl_devname(SYSCTL_HANDLER_ARGS) 45965632Sphk{ 46065632Sphk int error; 46165632Sphk udev_t ud; 46265632Sphk dev_t dev; 46365632Sphk 46465632Sphk error = SYSCTL_IN(req, &ud, sizeof (ud)); 46565632Sphk if (error) 46665632Sphk return (error); 46771342Sphk if (ud == NOUDEV) 46871342Sphk return(EINVAL); 46965632Sphk dev = makedev(umajor(ud), uminor(ud)); 47065632Sphk if (dev->si_name[0] == '\0') 47165632Sphk error = ENOENT; 47265632Sphk else 47365632Sphk error = SYSCTL_OUT(req, dev->si_name, strlen(dev->si_name) + 1); 47465632Sphk freedev(dev); 47565632Sphk return (error); 47665632Sphk} 47765632Sphk 47867905SphkSYSCTL_PROC(_kern, OID_AUTO, devname, CTLTYPE_OPAQUE|CTLFLAG_RW|CTLFLAG_ANYBODY, 47965632Sphk NULL, 0, sysctl_devname, "", "devname(3) handler"); 48089118Smsmith 48189118Smsmith/* 48289118Smsmith * Set ready_for_devs; prior to this point, device creation is not allowed. 48389118Smsmith */ 48489118Smsmithstatic void 48589118Smsmithdev_set_ready(void *junk) 48689118Smsmith{ 48789118Smsmith ready_for_devs = 1; 48889118Smsmith} 48989118Smsmith 49089118SmsmithSYSINIT(dev_ready, SI_SUB_DEVFS, SI_ORDER_FIRST, dev_set_ready, NULL); 491