kern_conf.c revision 85076
116239Sjkh/*- 24Srgrimes * Parts Copyright (c) 1995 Terrence R. Lambert 3509Srgrimes * Copyright (c) 1995 Julian R. Elischer 437581Sbde * All rights reserved. 54Srgrimes * 6509Srgrimes * Redistribution and use in source and binary forms, with or without 7509Srgrimes * modification, are permitted provided that the following conditions 84Srgrimes * are met: 94Srgrimes * 1. Redistributions of source code must retain the above copyright 104Srgrimes * notice, this list of conditions and the following disclaimer. 114Srgrimes * 2. Redistributions in binary form must reproduce the above copyright 124Srgrimes * notice, this list of conditions and the following disclaimer in the 134Srgrimes * documentation and/or other materials provided with the distribution. 144Srgrimes * 3. All advertising materials mentioning features or use of this software 154Srgrimes * must display the following acknowledgement: 164Srgrimes * This product includes software developed by Terrence R. Lambert. 174Srgrimes * 4. The name Terrence R. Lambert may not be used to endorse or promote 184Srgrimes * products derived from this software without specific prior written 1930640Speter * permission. 2037580Sbde * 2130640Speter * THIS SOFTWARE IS PROVIDED BY Julian R. Elischer ``AS IS'' AND ANY 2225083Sjdp * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2325537Sdfr * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2425083Sjdp * ARE DISCLAIMED. IN NO EVENT SHALL THE TERRENCE R. LAMBERT BE LIABLE 2525083Sjdp * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2627674Sphk * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2727674Sphk * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 282056Swollman * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 292056Swollman * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 302056Swollman * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 314Srgrimes * SUCH DAMAGE. 322056Swollman * 332056Swollman * $FreeBSD: head/sys/kern/kern_conf.c 85076 2001-10-17 18:47:12Z jlemon $ 344Srgrimes */ 354836Sdg 3618518Sbde#include <sys/param.h> 377627Snate#include <sys/kernel.h> 387627Snate#include <sys/systm.h> 397627Snate#include <sys/sysctl.h> 407627Snate#include <sys/module.h> 417627Snate#include <sys/malloc.h> 427627Snate#include <sys/conf.h> 4325202Speter#include <sys/vnode.h> 44712Swollman#include <sys/queue.h> 45974Sdg#include <sys/ctype.h> 4627065Sbde#include <machine/stdarg.h> 4720395Sbde 4827065Sbde#define cdevsw_ALLOCSTART (NUMCDEVSW/2) 4920395Sbde 5020395Sbdestruct cdevsw *cdevsw[NUMCDEVSW]; 5120395Sbde 5220395Sbdestatic MALLOC_DEFINE(M_DEVT, "dev_t", "dev_t storage"); 5320395Sbde 544Srgrimes/* 554Srgrimes * This is the number of hash-buckets. Experiements with 'real-life' 5637580Sbde * udev_t's show that a prime halfway between two powers of two works 572408Sbde * best. 5816028Speter */ 594Srgrimes#define DEVT_HASH 83 6037580Sbde 6116028Speter/* The number of dev_t's we can create before malloc(9) kick in. */ 6237580Sbde#define DEVT_STASH 50 632408Sbde 6425985Sjdpstatic struct specinfo devt_stash[DEVT_STASH]; 6525985Sjdp 6625985Sjdpstatic LIST_HEAD(, specinfo) dev_hash[DEVT_HASH]; 6725985Sjdp 6825985Sjdpstatic LIST_HEAD(, specinfo) dev_free; 692408Sbde 7013031Sbdedevfs_create_t *devfs_create_hook; 715908Sbdedevfs_destroy_t *devfs_destroy_hook; 725908Sbdeint devfs_present; 735908Sbde 7435514Simpstatic int free_devt; 7525083SjdpSYSCTL_INT(_debug, OID_AUTO, free_devt, CTLFLAG_RW, &free_devt, 0, ""); 7625985Sjdp 7735514Simpstruct cdevsw * 785908Sbdedevsw(dev_t dev) 7935514Simp{ 8035514Simp if (dev->si_devsw) 8125083Sjdp return (dev->si_devsw); 8225537Sdfr return(cdevsw[major(dev)]); 8325985Sjdp} 8435514Simp 8525537Sdfr/* 8635514Simp * Add a cdevsw entry 8735514Simp */ 8825537Sdfr 8925083Sjdpint 9025985Sjdpcdevsw_add(struct cdevsw *newentry) 9125985Sjdp{ 9225985Sjdp 9335514Simp if (newentry->d_maj < 0 || newentry->d_maj >= NUMCDEVSW) { 9435514Simp printf("%s: ERROR: driver has bogus cdevsw->d_maj = %d\n", 9525083Sjdp newentry->d_name, newentry->d_maj); 964Srgrimes return (EINVAL); 975327Sgibbs } 985327Sgibbs 994Srgrimes if (cdevsw[newentry->d_maj]) { 1004Srgrimes printf("WARNING: \"%s\" is usurping \"%s\"'s cdevsw[]\n", 1014Srgrimes newentry->d_name, cdevsw[newentry->d_maj]->d_name); 1024Srgrimes } 10311918Sdg 10411918Sdg cdevsw[newentry->d_maj] = newentry; 1054Srgrimes 1064Srgrimes return (0); 1076802Sgibbs} 1086802Sgibbs 1094Srgrimes/* 11025985Sjdp * Remove a cdevsw entry 11125985Sjdp */ 11237581Sbde 1134Srgrimesint 114715Swollmancdevsw_remove(struct cdevsw *oldentry) 11537580Sbde{ 116715Swollman if (oldentry->d_maj < 0 || oldentry->d_maj >= NUMCDEVSW) { 117715Swollman printf("%s: ERROR: driver has bogus cdevsw->d_maj = %d\n", 118715Swollman oldentry->d_name, oldentry->d_maj); 1194Srgrimes return EINVAL; 12037581Sbde } 1215908Sbde 1225908Sbde cdevsw[oldentry->d_maj] = NULL; 1235908Sbde 1244Srgrimes return 0; 1254Srgrimes} 1264Srgrimes 1274Srgrimes/* 1282464Sbde * dev_t and u_dev_t primitives 1292408Sbde */ 1304Srgrimes 13125985Sjdpint 13225083Sjdpmajor(dev_t x) 13325083Sjdp{ 13425985Sjdp if (x == NODEV) 13525083Sjdp return NOUDEV; 13625083Sjdp return((x->si_udev >> 8) & 0xff); 13725985Sjdp} 13825985Sjdp 13925985Sjdpint 14025985Sjdpminor(dev_t x) 14135514Simp{ 14225985Sjdp if (x == NODEV) 14325985Sjdp return NOUDEV; 14425985Sjdp return(x->si_udev & 0xffff00ff); 14525985Sjdp} 1462408Sbde 1472408Sbdeint 1482408Sbdedev2unit(dev_t x) 149649Snate{ 1503863Sbde int i; 1514Srgrimes 15237581Sbde if (x == NODEV) 15337580Sbde return NOUDEV; 1544Srgrimes i = minor(x); 1553863Sbde return ((i & 0xff) | (i >> 8)); 15637580Sbde} 1573863Sbde 15837581Sbdeint 15925202Speterunit2minor(int unit) 1602408Sbde{ 1615327Sgibbs 16214924Speter KASSERT(unit <= 0xffffff, ("Invalid unit (%d) in unit2minor", unit)); 16314924Speter return ((unit & 0xff) | ((unit << 8) & ~0xffff)); 16437580Sbde} 16525083Sjdp 16614924Speterstatic dev_t 16714331Speterallocdev(void) 16815679Swosch{ 1694Srgrimes static int stashed; 17032924Seivind struct specinfo *si; 17132924Seivind 17232924Seivind if (stashed >= DEVT_STASH) { 1734Srgrimes MALLOC(si, struct specinfo *, sizeof(*si), M_DEVT, 1748457Swollman M_USE_RESERVE | M_ZERO); 1754Srgrimes } else if (LIST_FIRST(&dev_free)) { 1768457Swollman si = LIST_FIRST(&dev_free); 1774Srgrimes LIST_REMOVE(si, si_hash); 1784Srgrimes } else { 1794Srgrimes si = devt_stash + stashed++; 1804Srgrimes bzero(si, sizeof *si); 1814Srgrimes si->si_flags |= SI_STASHED; 1824Srgrimes } 1834Srgrimes LIST_INIT(&si->si_children); 18415558Sjoerg TAILQ_INIT(&si->si_snapshots); 18515558Sjoerg return (si); 18615558Sjoerg} 18715558Sjoerg 18815558Sjoergdev_t 18932924Seivindmakedev(int x, int y) 19032924Seivind{ 19132924Seivind struct specinfo *si; 19232924Seivind udev_t udev; 19331846Sbde int hash; 19432924Seivind 19532924Seivind if (x == umajor(NOUDEV) && y == uminor(NOUDEV)) 19630912Sguido panic("makedev of NOUDEV"); 19730912Sguido udev = (x << 8) | y; 19830912Sguido hash = udev % DEVT_HASH; 19913321Sphk LIST_FOREACH(si, &dev_hash[hash], si_hash) { 20035244Sdima if (si->si_udev == udev) 2012627Swollman return (si); 20237581Sbde } 20337581Sbde si = allocdev(); 2044Srgrimes si->si_udev = udev; 20537581Sbde LIST_INSERT_HEAD(&dev_hash[hash], si, si_hash); 20637581Sbde return (si); 20737581Sbde} 208509Srgrimes 2094Srgrimesvoid 2104Srgrimesfreedev(dev_t dev) 2114Srgrimes{ 21237581Sbde 21337581Sbde if (!free_devt) 2144Srgrimes return; 21537581Sbde if (SLIST_FIRST(&dev->si_hlist)) 2164Srgrimes return; 2174Srgrimes if (dev->si_devsw || dev->si_drv1 || dev->si_drv2) 21837581Sbde return; 21937581Sbde LIST_REMOVE(dev, si_hash); 22037581Sbde if (dev->si_flags & SI_STASHED) { 22137581Sbde bzero(dev, sizeof(*dev)); 22237140Seivind dev->si_flags |= SI_STASHED; 22337581Sbde LIST_INSERT_HEAD(&dev_free, dev, si_hash); 22437581Sbde } else { 2251549Srgrimes FREE(dev, M_DEVT); 2261549Srgrimes } 22737581Sbde} 22837581Sbde 22937581Sbdeudev_t 23018820Sbdedev2udev(dev_t x) 23118820Sbde{ 2324Srgrimes if (x == NODEV) 2334Srgrimes return NOUDEV; 2344Srgrimes return (x->si_udev); 235} 236 237dev_t 238udev2dev(udev_t x, int b) 239{ 240 241 if (x == NOUDEV) 242 return (NODEV); 243 switch (b) { 244 case 0: 245 return makedev(umajor(x), uminor(x)); 246 case 1: 247 return (NODEV); 248 default: 249 Debugger("udev2dev(...,X)"); 250 return NODEV; 251 } 252} 253 254int 255uminor(udev_t dev) 256{ 257 return(dev & 0xffff00ff); 258} 259 260int 261umajor(udev_t dev) 262{ 263 return((dev & 0xff00) >> 8); 264} 265 266udev_t 267makeudev(int x, int y) 268{ 269 return ((x << 8) | y); 270} 271 272dev_t 273make_dev(struct cdevsw *devsw, int minor, uid_t uid, gid_t gid, int perms, const char *fmt, ...) 274{ 275 dev_t dev; 276 va_list ap; 277 int i; 278 279 KASSERT(umajor(makeudev(devsw->d_maj, minor)) == devsw->d_maj, 280 ("Invalid minor (%d) in make_dev", minor)); 281 282 dev = makedev(devsw->d_maj, minor); 283 if (dev->si_flags & SI_NAMED) { 284 printf( "WARNING: Driver mistake: repeat make_dev(\"%s\")\n", 285 dev->si_name); 286 return (dev); 287 } 288 va_start(ap, fmt); 289 i = kvprintf(fmt, NULL, dev->si_name, 32, ap); 290 dev->si_name[i] = '\0'; 291 va_end(ap); 292 dev->si_devsw = devsw; 293 dev->si_uid = uid; 294 dev->si_gid = gid; 295 dev->si_mode = perms; 296 dev->si_flags |= SI_NAMED; 297 298 if (devfs_create_hook) 299 devfs_create_hook(dev); 300 return (dev); 301} 302 303int 304dev_named(dev_t pdev, const char *name) 305{ 306 dev_t cdev; 307 308 if (strcmp(devtoname(pdev), name) == 0) 309 return (1); 310 LIST_FOREACH(cdev, &pdev->si_children, si_siblings) 311 if (strcmp(devtoname(cdev), name) == 0) 312 return (1); 313 return (0); 314} 315 316void 317dev_depends(dev_t pdev, dev_t cdev) 318{ 319 320 cdev->si_parent = pdev; 321 cdev->si_flags |= SI_CHILD; 322 LIST_INSERT_HEAD(&pdev->si_children, cdev, si_siblings); 323} 324 325dev_t 326make_dev_alias(dev_t pdev, const char *fmt, ...) 327{ 328 dev_t dev; 329 va_list ap; 330 int i; 331 332 dev = allocdev(); 333 dev->si_flags |= SI_ALIAS; 334 dev->si_flags |= SI_NAMED; 335 dev_depends(pdev, dev); 336 va_start(ap, fmt); 337 i = kvprintf(fmt, NULL, dev->si_name, 32, ap); 338 dev->si_name[i] = '\0'; 339 va_end(ap); 340 341 if (devfs_create_hook) 342 devfs_create_hook(dev); 343 return (dev); 344} 345 346void 347destroy_dev(dev_t dev) 348{ 349 350 if (!(dev->si_flags & SI_NAMED)) { 351 printf( "WARNING: Driver mistake: destroy_dev on %d/%d\n", 352 major(dev), minor(dev)); 353 return; 354 } 355 356 if (devfs_destroy_hook) 357 devfs_destroy_hook(dev); 358 if (dev->si_flags & SI_CHILD) { 359 LIST_REMOVE(dev, si_siblings); 360 dev->si_flags &= ~SI_CHILD; 361 } 362 while (!LIST_EMPTY(&dev->si_children)) 363 destroy_dev(LIST_FIRST(&dev->si_children)); 364 dev->si_drv1 = 0; 365 dev->si_drv2 = 0; 366 dev->si_devsw = 0; 367 dev->si_flags &= ~SI_NAMED; 368 dev->si_flags &= ~SI_ALIAS; 369 freedev(dev); 370} 371 372const char * 373devtoname(dev_t dev) 374{ 375 char *p; 376 int mynor; 377 378 if (dev->si_name[0] == '#' || dev->si_name[0] == '\0') { 379 p = dev->si_name; 380 if (devsw(dev)) 381 sprintf(p, "#%s/", devsw(dev)->d_name); 382 else 383 sprintf(p, "#%d/", major(dev)); 384 p += strlen(p); 385 mynor = minor(dev); 386 if (mynor < 0 || mynor > 255) 387 sprintf(p, "%#x", (u_int)mynor); 388 else 389 sprintf(p, "%d", mynor); 390 } 391 return (dev->si_name); 392} 393 394int 395dev_stdclone(char *name, char **namep, char *stem, int *unit) 396{ 397 int u, i; 398 399 i = strlen(stem); 400 if (bcmp(stem, name, i) != 0) 401 return (0); 402 if (!isdigit(name[i])) 403 return (0); 404 u = 0; 405 while (isdigit(name[i])) { 406 u *= 10; 407 u += name[i++] - '0'; 408 } 409 *unit = u; 410 if (namep) 411 *namep = &name[i]; 412 if (name[i]) 413 return (2); 414 return (1); 415} 416 417/* 418 * Helper sysctl for devname(3). We're given a {u}dev_t and return 419 * the name, if any, registered by the device driver. 420 */ 421static int 422sysctl_devname(SYSCTL_HANDLER_ARGS) 423{ 424 int error; 425 udev_t ud; 426 dev_t dev; 427 428 error = SYSCTL_IN(req, &ud, sizeof (ud)); 429 if (error) 430 return (error); 431 if (ud == NOUDEV) 432 return(EINVAL); 433 dev = makedev(umajor(ud), uminor(ud)); 434 if (dev->si_name[0] == '\0') 435 error = ENOENT; 436 else 437 error = SYSCTL_OUT(req, dev->si_name, strlen(dev->si_name) + 1); 438 freedev(dev); 439 return (error); 440} 441 442SYSCTL_PROC(_kern, OID_AUTO, devname, CTLTYPE_OPAQUE|CTLFLAG_RW|CTLFLAG_ANYBODY, 443 NULL, 0, sysctl_devname, "", "devname(3) handler"); 444 445