kern_conf.c revision 60938
1119381Sjake/*- 2119381Sjake * Parts Copyright (c) 1995 Terrence R. Lambert 3119381Sjake * Copyright (c) 1995 Julian R. Elischer 4139749Simp * All rights reserved. 5119381Sjake * 6119381Sjake * Redistribution and use in source and binary forms, with or without 7119381Sjake * modification, are permitted provided that the following conditions 8119381Sjake * are met: 9119381Sjake * 1. Redistributions of source code must retain the above copyright 10119381Sjake * notice, this list of conditions and the following disclaimer. 11119381Sjake * 2. Redistributions in binary form must reproduce the above copyright 12119381Sjake * notice, this list of conditions and the following disclaimer in the 13119381Sjake * documentation and/or other materials provided with the distribution. 14119381Sjake * 3. All advertising materials mentioning features or use of this software 15119381Sjake * must display the following acknowledgement: 16119381Sjake * This product includes software developed by Terrence R. Lambert. 17119381Sjake * 4. The name Terrence R. Lambert may not be used to endorse or promote 18119381Sjake * products derived from this software without specific prior written 19119381Sjake * permission. 20119381Sjake * 21119381Sjake * THIS SOFTWARE IS PROVIDED BY Julian R. Elischer ``AS IS'' AND ANY 22119381Sjake * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23119381Sjake * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24119381Sjake * ARE DISCLAIMED. IN NO EVENT SHALL THE TERRENCE R. LAMBERT BE LIABLE 25119381Sjake * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26119381Sjake * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 27119381Sjake * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28119381Sjake * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 29119381Sjake * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 30119381Sjake * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31119381Sjake * SUCH DAMAGE. 32119381Sjake * 33119381Sjake * $FreeBSD: head/sys/kern/kern_conf.c 60938 2000-05-26 02:09:24Z jake $ 34119381Sjake */ 35119381Sjake 36119381Sjake#include <sys/param.h> 37119381Sjake#include <sys/kernel.h> 38119381Sjake#include <sys/sysctl.h> 39170840Smarius#include <sys/systm.h> 40170840Smarius#include <sys/module.h> 41170840Smarius#include <sys/malloc.h> 42170840Smarius#include <sys/conf.h> 43170840Smarius#include <sys/vnode.h> 44170840Smarius#include <sys/queue.h> 45170840Smarius#include <machine/stdarg.h> 46170840Smarius 47170840Smarius#define cdevsw_ALLOCSTART (NUMCDEVSW/2) 48170840Smarius 49170840Smariusstruct cdevsw *cdevsw[NUMCDEVSW]; 50119381Sjake 51119381Sjakestatic int bmaj2cmaj[NUMCDEVSW]; 52119381Sjake 53119381SjakeMALLOC_DEFINE(M_DEVT, "dev_t", "dev_t storage"); 54119381Sjake 55119381Sjake/* 56119381Sjake * This is the number of hash-buckets. Experiements with 'real-life' 57119381Sjake * udev_t's show that a prime halfway between two powers of two works 58119381Sjake * best. 59119381Sjake */ 60119381Sjake#define DEVT_HASH 83 61119381Sjake 62119381Sjake/* The number of dev_t's we can create before malloc(9) kick in. */ 63119381Sjake#define DEVT_STASH 50 64119381Sjake 65119381Sjakestatic struct specinfo devt_stash[DEVT_STASH]; 66119381Sjake 67119381Sjakestatic LIST_HEAD(, specinfo) dev_hash[DEVT_HASH]; 68119381Sjake 69119381Sjakestatic LIST_HEAD(, specinfo) dev_free; 70119381Sjake 71119381Sjakedevfs_create_t *devfs_create_hook; 72119381Sjakedevfs_remove_t *devfs_remove_hook; 73119381Sjake 74119381Sjakestatic int free_devt; 75119381SjakeSYSCTL_INT(_debug, OID_AUTO, free_devt, CTLFLAG_RW, &free_devt, 0, ""); 76119381Sjake 77119381Sjakestruct cdevsw * 78119381Sjakedevsw(dev_t dev) 79119381Sjake{ 80119381Sjake if (dev->si_devsw) 81119381Sjake return (dev->si_devsw); 82119381Sjake return(cdevsw[major(dev)]); 83119381Sjake} 84119381Sjake 85119381Sjake/* 86119381Sjake * Add a cdevsw entry 87119381Sjake */ 88119381Sjake 89119381Sjakeint 90119381Sjakecdevsw_add(struct cdevsw *newentry) 91119381Sjake{ 92119381Sjake int i; 93119381Sjake static int setup; 94119381Sjake 95119381Sjake if (!setup) { 96119381Sjake for (i = 0; i < NUMCDEVSW; i++) 97119381Sjake if (!bmaj2cmaj[i]) 98119381Sjake bmaj2cmaj[i] = 254; 99119381Sjake setup++; 100119381Sjake } 101119381Sjake 102119381Sjake if (newentry->d_maj < 0 || newentry->d_maj >= NUMCDEVSW) { 103119381Sjake printf("%s: ERROR: driver has bogus cdevsw->d_maj = %d\n", 104119381Sjake newentry->d_name, newentry->d_maj); 105119381Sjake return (EINVAL); 106119381Sjake } 107119381Sjake if (newentry->d_bmaj >= NUMCDEVSW) { 108119381Sjake printf("%s: ERROR: driver has bogus cdevsw->d_bmaj = %d\n", 109119381Sjake newentry->d_name, newentry->d_bmaj); 110119381Sjake return (EINVAL); 111119381Sjake } 112119381Sjake if (newentry->d_bmaj >= 0 && (newentry->d_flags & D_DISK) == 0) { 113119381Sjake printf("ERROR: \"%s\" bmaj but is not a disk\n", 114119381Sjake newentry->d_name); 115119381Sjake return (EINVAL); 116119381Sjake } 117119381Sjake 118119381Sjake if (cdevsw[newentry->d_maj]) { 119119381Sjake printf("WARNING: \"%s\" is usurping \"%s\"'s cdevsw[]\n", 120119381Sjake newentry->d_name, cdevsw[newentry->d_maj]->d_name); 121119381Sjake } 122119381Sjake 123119381Sjake cdevsw[newentry->d_maj] = newentry; 124119381Sjake 125119381Sjake if (newentry->d_bmaj < 0) 126119381Sjake return (0); 127119381Sjake 128119381Sjake if (bmaj2cmaj[newentry->d_bmaj] != 254) { 129119381Sjake printf("WARNING: \"%s\" is usurping \"%s\"'s bmaj\n", 130119381Sjake newentry->d_name, 131119381Sjake cdevsw[bmaj2cmaj[newentry->d_bmaj]]->d_name); 132119381Sjake } 133119381Sjake bmaj2cmaj[newentry->d_bmaj] = newentry->d_maj; 134119381Sjake return (0); 135119381Sjake} 136119381Sjake 137119381Sjake/* 138119381Sjake * Remove a cdevsw entry 139119381Sjake */ 140119381Sjake 141119381Sjakeint 142119381Sjakecdevsw_remove(struct cdevsw *oldentry) 143119381Sjake{ 144119381Sjake if (oldentry->d_maj < 0 || oldentry->d_maj >= NUMCDEVSW) { 145119381Sjake printf("%s: ERROR: driver has bogus cdevsw->d_maj = %d\n", 146119381Sjake oldentry->d_name, oldentry->d_maj); 147119381Sjake return EINVAL; 148119381Sjake } 149119381Sjake 150119381Sjake cdevsw[oldentry->d_maj] = NULL; 151119381Sjake 152119381Sjake if (oldentry->d_bmaj >= 0 && oldentry->d_bmaj < NUMCDEVSW) 153119381Sjake bmaj2cmaj[oldentry->d_bmaj] = 254; 154119381Sjake 155119381Sjake return 0; 156119381Sjake} 157119381Sjake 158119381Sjake/* 159119381Sjake * dev_t and u_dev_t primitives 160119381Sjake */ 161119381Sjake 162119381Sjakeint 163119381Sjakemajor(dev_t x) 164119381Sjake{ 165119381Sjake if (x == NODEV) 166119381Sjake return NOUDEV; 167119381Sjake return((x->si_udev >> 8) & 0xff); 168119381Sjake} 169119381Sjake 170119381Sjakeint 171119381Sjakeminor(dev_t x) 172119381Sjake{ 173119381Sjake if (x == NODEV) 174119381Sjake return NOUDEV; 175119381Sjake return(x->si_udev & 0xffff00ff); 176119381Sjake} 177119381Sjake 178119381Sjakeint 179119381Sjakelminor(dev_t x) 180119381Sjake{ 181119381Sjake int i; 182119381Sjake 183119381Sjake if (x == NODEV) 184119381Sjake return NOUDEV; 185119381Sjake i = minor(x); 186119381Sjake return ((i & 0xff) | (i >> 8)); 187119381Sjake} 188119381Sjake 189119381Sjakedev_t 190119381Sjakemakebdev(int x, int y) 191119381Sjake{ 192119381Sjake 193119381Sjake if (x == umajor(NOUDEV) && y == uminor(NOUDEV)) 194119381Sjake Debugger("makebdev of NOUDEV"); 195119381Sjake return (makedev(bmaj2cmaj[x], y)); 196119381Sjake} 197119381Sjake 198119381Sjakedev_t 199119381Sjakemakedev(int x, int y) 200119381Sjake{ 201119381Sjake struct specinfo *si; 202119381Sjake udev_t udev; 203119381Sjake int hash; 204119381Sjake static int stashed; 205119381Sjake 206119381Sjake if (x == umajor(NOUDEV) && y == uminor(NOUDEV)) 207119381Sjake Debugger("makedev of NOUDEV"); 208119381Sjake udev = (x << 8) | y; 209119381Sjake hash = udev % DEVT_HASH; 210119381Sjake LIST_FOREACH(si, &dev_hash[hash], si_hash) { 211119381Sjake if (si->si_udev == udev) 212119381Sjake return (si); 213119381Sjake } 214119381Sjake if (stashed >= DEVT_STASH) { 215119381Sjake MALLOC(si, struct specinfo *, sizeof(*si), M_DEVT, 216119381Sjake M_USE_RESERVE); 217119381Sjake bzero(si, sizeof(*si)); 218119381Sjake } else if (LIST_FIRST(&dev_free)) { 219119381Sjake si = LIST_FIRST(&dev_free); 220119381Sjake LIST_REMOVE(si, si_hash); 221119381Sjake } else { 222119381Sjake si = devt_stash + stashed++; 223119381Sjake si->si_flags |= SI_STASHED; 224119381Sjake } 225119381Sjake si->si_udev = udev; 226119381Sjake LIST_INSERT_HEAD(&dev_hash[hash], si, si_hash); 227119381Sjake return (si); 228119381Sjake} 229119381Sjake 230119381Sjakevoid 231119381Sjakefreedev(dev_t dev) 232119381Sjake{ 233119381Sjake int hash; 234119381Sjake 235119381Sjake if (!free_devt) 236119381Sjake return; 237119381Sjake if (SLIST_FIRST(&dev->si_hlist)) 238119381Sjake return; 239119381Sjake if (dev->si_devsw || dev->si_drv1 || dev->si_drv2) 240119381Sjake return; 241119381Sjake hash = dev->si_udev % DEVT_HASH; 242119381Sjake LIST_REMOVE(dev, si_hash); 243119381Sjake if (dev->si_flags & SI_STASHED) { 244119381Sjake bzero(dev, sizeof(*dev)); 245119381Sjake LIST_INSERT_HEAD(&dev_free, dev, si_hash); 246119381Sjake } else { 247119381Sjake FREE(dev, M_DEVT); 248119381Sjake } 249119381Sjake} 250119381Sjake 251119381Sjakeudev_t 252119381Sjakedev2udev(dev_t x) 253119381Sjake{ 254119381Sjake if (x == NODEV) 255119381Sjake return NOUDEV; 256119381Sjake return (x->si_udev); 257119381Sjake} 258119381Sjake 259119381Sjakedev_t 260119381Sjakeudev2dev(udev_t x, int b) 261119381Sjake{ 262119381Sjake 263119381Sjake if (x == NOUDEV) 264119381Sjake return (NODEV); 265119381Sjake switch (b) { 266119381Sjake case 0: 267119381Sjake return makedev(umajor(x), uminor(x)); 268119381Sjake case 1: 269119381Sjake return makebdev(umajor(x), uminor(x)); 270119381Sjake default: 271119381Sjake Debugger("udev2dev(...,X)"); 272119381Sjake return NODEV; 273119381Sjake } 274119381Sjake} 275119381Sjake 276119381Sjakeint 277119381Sjakeuminor(udev_t dev) 278119381Sjake{ 279119381Sjake return(dev & 0xffff00ff); 280119381Sjake} 281119381Sjake 282119381Sjakeint 283119381Sjakeumajor(udev_t dev) 284119381Sjake{ 285119381Sjake return((dev & 0xff00) >> 8); 286119381Sjake} 287119381Sjake 288119381Sjakeudev_t 289119381Sjakemakeudev(int x, int y) 290119381Sjake{ 291119381Sjake return ((x << 8) | y); 292119381Sjake} 293119381Sjake 294119381Sjakedev_t 295119381Sjakemake_dev(struct cdevsw *devsw, int minor, uid_t uid, gid_t gid, int perms, char *fmt, ...) 296119381Sjake{ 297119381Sjake dev_t dev; 298119381Sjake va_list ap; 299119381Sjake int i; 300119381Sjake 301119381Sjake dev = makedev(devsw->d_maj, minor); 302119381Sjake va_start(ap, fmt); 303119381Sjake i = kvprintf(fmt, NULL, dev->si_name, 32, ap); 304119381Sjake dev->si_name[i] = '\0'; 305119381Sjake va_end(ap); 306119381Sjake dev->si_devsw = devsw; 307119381Sjake 308119381Sjake if (devfs_create_hook) 309119381Sjake devfs_create_hook(dev, uid, gid, perms); 310119381Sjake return (dev); 311119381Sjake} 312119381Sjake 313119381Sjakevoid 314119381Sjakedestroy_dev(dev_t dev) 315119381Sjake{ 316119381Sjake if (devfs_remove_hook) 317119381Sjake devfs_remove_hook(dev); 318119381Sjake dev->si_drv1 = 0; 319119381Sjake dev->si_drv2 = 0; 320119381Sjake dev->si_devsw = 0; 321119381Sjake freedev(dev); 322119381Sjake} 323119381Sjake 324119381Sjakeconst char * 325119381Sjakedevtoname(dev_t dev) 326119381Sjake{ 327119381Sjake char *p; 328119381Sjake int mynor; 329119381Sjake 330119381Sjake if (dev->si_name[0] == '#' || dev->si_name[0] == '\0') { 331119381Sjake p = dev->si_name; 332119381Sjake if (devsw(dev)) 333119381Sjake sprintf(p, "#%s/", devsw(dev)->d_name); 334119381Sjake else 335119381Sjake sprintf(p, "#%d/", major(dev)); 336119381Sjake p += strlen(p); 337119381Sjake mynor = minor(dev); 338119381Sjake if (mynor < 0 || mynor > 255) 339119381Sjake sprintf(p, "%#x", (u_int)mynor); 340119381Sjake else 341119381Sjake sprintf(p, "%d", mynor); 342119381Sjake } 343119381Sjake return (dev->si_name); 344119381Sjake} 345119381Sjake