1 /*- 2 * Parts Copyright (c) 1995 Terrence R. Lambert 3 * Copyright (c) 1995 Julian R. Elischer 4 * All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 3. All advertising materials mentioning features or use of this software 15 * must display the following acknowledgement: 16 * This product includes software developed by Terrence R. Lambert. 17 * 4. The name Terrence R. Lambert may not be used to endorse or promote 18 * products derived from this software without specific prior written 19 * permission. 20 * 21 * THIS SOFTWARE IS PROVIDED BY Julian R. Elischer ``AS IS'' AND ANY 22 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24 * ARE DISCLAIMED. IN NO EVENT SHALL THE TERRENCE R. LAMBERT BE LIABLE 25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31 * SUCH DAMAGE. 32 * 33 * $FreeBSD: src/sys/kern/kern_conf.c,v 1.73.2.3 2003/03/10 02:18:25 imp Exp $ 34 * $DragonFly: src/sys/kern/kern_conf.c,v 1.20 2006/12/23 00:35:03 swildner Exp $ 35 */ 36 37 #include <sys/param.h> 38 #include <sys/kernel.h> 39 #include <sys/sysctl.h> 40 #include <sys/systm.h> 41 #include <sys/module.h> 42 #include <sys/malloc.h> 43 #include <sys/conf.h> 44 #include <sys/vnode.h> 45 #include <sys/queue.h> 46 #include <sys/device.h> 47 #include <machine/stdarg.h> 48 49 #define cdevsw_ALLOCSTART (NUMCDEVSW/2) 50 51 MALLOC_DEFINE(M_DEVT, "cdev_t", "dev_t storage"); 52 53 /* 54 * This is the number of hash-buckets. Experiements with 'real-life' 55 * udev_t's show that a prime halfway between two powers of two works 56 * best. 57 */ 58 #define DEVT_HASH 83 59 60 /* The number of cdev_t's we can create before malloc(9) kick in. */ 61 #define DEVT_STASH 50 62 63 static struct cdev devt_stash[DEVT_STASH]; 64 static LIST_HEAD(, cdev) dev_hash[DEVT_HASH]; 65 static LIST_HEAD(, cdev) dev_free_list; 66 67 static int free_devt; 68 SYSCTL_INT(_debug, OID_AUTO, free_devt, CTLFLAG_RW, &free_devt, 0, ""); 69 int dev_ref_debug = 0; 70 SYSCTL_INT(_debug, OID_AUTO, dev_refs, CTLFLAG_RW, &dev_ref_debug, 0, ""); 71 72 /* 73 * cdev_t and u_dev_t primitives. Note that the major number is always 74 * extracted from si_udev, not from si_devsw, because si_devsw is replaced 75 * when a device is destroyed. 76 */ 77 int 78 major(cdev_t x) 79 { 80 if (x == NOCDEV) 81 return NOUDEV; 82 return((x->si_udev >> 8) & 0xff); 83 } 84 85 int 86 minor(cdev_t x) 87 { 88 if (x == NOCDEV) 89 return NOUDEV; 90 return(x->si_udev & 0xffff00ff); 91 } 92 93 int 94 lminor(cdev_t x) 95 { 96 int i; 97 98 if (x == NOCDEV) 99 return NOUDEV; 100 i = minor(x); 101 return ((i & 0xff) | (i >> 8)); 102 } 103 104 /* 105 * This is a bit complex because devices are always created relative to 106 * a particular cdevsw, including 'hidden' cdevsw's (such as the raw device 107 * backing a disk subsystem overlay), so we have to compare both the 108 * devsw and udev fields to locate the correct device. 109 * 110 * The device is created if it does not already exist. If SI_ADHOC is not 111 * set the device will be referenced (once) and SI_ADHOC will be set. 112 * The caller must explicitly add additional references to the device if 113 * the caller wishes to track additional references. 114 * 115 * NOTE: The passed ops vector must normally match the device. This is 116 * because the kernel may create shadow devices that are INVISIBLE TO 117 * USERLAND. For example, the block device backing a disk is created 118 * as a shadow underneath the user-visible disklabel management device. 119 * Sometimes a device ops vector can be overridden, such as by /dev/console. 120 * In this case and this case only we allow a match when the ops vector 121 * otherwise would not match. 122 */ 123 static 124 cdev_t 125 hashdev(struct dev_ops *ops, int x, int y, int allow_intercept) 126 { 127 struct cdev *si; 128 udev_t udev; 129 int hash; 130 static int stashed; 131 132 udev = makeudev(x, y); 133 hash = udev % DEVT_HASH; 134 LIST_FOREACH(si, &dev_hash[hash], si_hash) { 135 if (si->si_udev == udev) { 136 if (si->si_ops == ops) 137 return (si); 138 if (allow_intercept && (si->si_flags & SI_INTERCEPTED)) 139 return (si); 140 } 141 } 142 if (stashed >= DEVT_STASH) { 143 MALLOC(si, struct cdev *, sizeof(*si), M_DEVT, 144 M_WAITOK|M_USE_RESERVE|M_ZERO); 145 } else if (LIST_FIRST(&dev_free_list)) { 146 si = LIST_FIRST(&dev_free_list); 147 LIST_REMOVE(si, si_hash); 148 } else { 149 si = devt_stash + stashed++; 150 si->si_flags |= SI_STASHED; 151 } 152 si->si_ops = ops; 153 si->si_flags |= SI_HASHED | SI_ADHOC; 154 si->si_udev = udev; 155 si->si_refs = 1; 156 LIST_INSERT_HEAD(&dev_hash[hash], si, si_hash); 157 158 dev_dclone(si); 159 if (ops != &dead_dev_ops) 160 ++ops->head.refs; 161 if (dev_ref_debug) { 162 kprintf("create dev %p %s(minor=%08x) refs=%d\n", 163 si, devtoname(si), uminor(si->si_udev), 164 si->si_refs); 165 } 166 return (si); 167 } 168 169 /* 170 * Convert a device pointer to a device number 171 */ 172 udev_t 173 dev2udev(cdev_t x) 174 { 175 if (x == NOCDEV) 176 return NOUDEV; 177 return (x->si_udev); 178 } 179 180 /* 181 * Convert a device number to a device pointer. The device is referenced 182 * ad-hoc, meaning that the caller should call reference_dev() if it wishes 183 * to keep ahold of the returned structure long term. 184 * 185 * The returned device is associated with the currently installed cdevsw 186 * for the requested major number. NOCDEV is returned if the major number 187 * has not been registered. 188 */ 189 cdev_t 190 udev2dev(udev_t x, int b) 191 { 192 cdev_t dev; 193 struct dev_ops *ops; 194 195 if (x == NOUDEV || b != 0) 196 return(NOCDEV); 197 ops = dev_ops_get(umajor(x), uminor(x)); 198 if (ops == NULL) 199 return(NOCDEV); 200 dev = hashdev(ops, umajor(x), uminor(x), TRUE); 201 return(dev); 202 } 203 204 int 205 dev_is_good(cdev_t dev) 206 { 207 if (dev != NOCDEV && dev->si_ops != &dead_dev_ops) 208 return(1); 209 return(0); 210 } 211 212 /* 213 * Various user device number extraction and conversion routines 214 */ 215 int 216 uminor(udev_t dev) 217 { 218 return(dev & 0xffff00ff); 219 } 220 221 int 222 umajor(udev_t dev) 223 { 224 return((dev & 0xff00) >> 8); 225 } 226 227 udev_t 228 makeudev(int x, int y) 229 { 230 return ((x << 8) | y); 231 } 232 233 /* 234 * Create an internal or external device. 235 * 236 * Device majors can be overloaded and used directly by the kernel without 237 * conflict, but userland will only see the particular device major that 238 * has been installed with dev_ops_add(). 239 * 240 * This routine creates and returns an unreferenced ad-hoc entry for the 241 * device which will remain intact until the device is destroyed. If the 242 * caller intends to store the device pointer it must call reference_dev() 243 * to retain a real reference to the device. 244 * 245 * If an entry already exists, this function will set (or override) 246 * its cred requirements and name (XXX DEVFS interface). 247 */ 248 cdev_t 249 make_dev(struct dev_ops *ops, int minor, uid_t uid, gid_t gid, 250 int perms, const char *fmt, ...) 251 { 252 cdev_t dev; 253 __va_list ap; 254 int i; 255 256 /* 257 * compile the cdevsw and install the device 258 */ 259 compile_dev_ops(ops); 260 dev = hashdev(ops, ops->head.maj, minor, FALSE); 261 262 /* 263 * Set additional fields (XXX DEVFS interface goes here) 264 */ 265 __va_start(ap, fmt); 266 i = kvcprintf(fmt, NULL, dev->si_name, 32, ap); 267 dev->si_name[i] = '\0'; 268 __va_end(ap); 269 270 return (dev); 271 } 272 273 /* 274 * This function is similar to make_dev() but no cred information or name 275 * need be specified. 276 */ 277 cdev_t 278 make_adhoc_dev(struct dev_ops *ops, int minor) 279 { 280 cdev_t dev; 281 282 dev = hashdev(ops, ops->head.maj, minor, FALSE); 283 return(dev); 284 } 285 286 /* 287 * This function is similar to make_dev() except the new device is created 288 * using an old device as a template. 289 */ 290 cdev_t 291 make_sub_dev(cdev_t odev, int minor) 292 { 293 cdev_t dev; 294 295 dev = hashdev(odev->si_ops, umajor(odev->si_udev), minor, FALSE); 296 297 /* 298 * Copy cred requirements and name info XXX DEVFS. 299 */ 300 if (dev->si_name[0] == 0 && odev->si_name[0]) 301 bcopy(odev->si_name, dev->si_name, sizeof(dev->si_name)); 302 return (dev); 303 } 304 305 /* 306 * destroy_dev() removes the adhoc association for a device and revectors 307 * its ops to &dead_dev_ops. 308 * 309 * This routine releases the reference count associated with the ADHOC 310 * entry, plus releases the reference count held by the caller. What this 311 * means is that you should not call destroy_dev(make_dev(...)), because 312 * make_dev() does not bump the reference count (beyond what it needs to 313 * create the ad-hoc association). Any procedure that intends to destroy 314 * a device must have its own reference to it first. 315 */ 316 void 317 destroy_dev(cdev_t dev) 318 { 319 int hash; 320 321 if (dev == NOCDEV) 322 return; 323 if ((dev->si_flags & SI_ADHOC) == 0) { 324 release_dev(dev); 325 return; 326 } 327 if (dev_ref_debug) { 328 kprintf("destroy dev %p %s(minor=%08x) refs=%d\n", 329 dev, devtoname(dev), uminor(dev->si_udev), 330 dev->si_refs); 331 } 332 if (dev->si_refs < 2) { 333 kprintf("destroy_dev(): too few references on device! " 334 "%p %s(minor=%08x) refs=%d\n", 335 dev, devtoname(dev), uminor(dev->si_udev), 336 dev->si_refs); 337 } 338 dev->si_flags &= ~SI_ADHOC; 339 if (dev->si_flags & SI_HASHED) { 340 hash = dev->si_udev % DEVT_HASH; 341 LIST_REMOVE(dev, si_hash); 342 dev->si_flags &= ~SI_HASHED; 343 } 344 345 /* 346 * We have to release the ops reference before we replace the 347 * device switch with dead_dev_ops. 348 */ 349 if (dead_dev_ops.d_strategy == NULL) 350 compile_dev_ops(&dead_dev_ops); 351 if (dev->si_ops && dev->si_ops != &dead_dev_ops) 352 dev_ops_release(dev->si_ops); 353 dev->si_drv1 = NULL; 354 dev->si_drv2 = NULL; 355 dev->si_ops = &dead_dev_ops; 356 --dev->si_refs; /* release adhoc association reference */ 357 release_dev(dev); /* release callers reference */ 358 } 359 360 /* 361 * Destroy all ad-hoc device associations associated with a domain within a 362 * device switch. Only the minor numbers are included in the mask/match 363 * values. 364 * 365 * Unlike the ops functions whos link structures do not contain 366 * any major bits, this function scans through the dev list via si_udev 367 * which is a 32 bit field that contains both major and minor bits. 368 * Because of this, we must mask the minor bits in the passed mask variable 369 * to allow -1 to be specified generically. 370 * 371 * The caller must not include any major bits in the match value. 372 */ 373 void 374 destroy_all_devs(struct dev_ops *ops, u_int mask, u_int match) 375 { 376 int i; 377 cdev_t dev; 378 cdev_t ndev; 379 380 mask = uminor(mask); 381 for (i = 0; i < DEVT_HASH; ++i) { 382 ndev = LIST_FIRST(&dev_hash[i]); 383 while ((dev = ndev) != NULL) { 384 ndev = LIST_NEXT(dev, si_hash); 385 KKASSERT(dev->si_flags & SI_ADHOC); 386 if (dev->si_ops == ops && 387 (dev->si_udev & mask) == match 388 ) { 389 ++dev->si_refs; 390 destroy_dev(dev); 391 } 392 } 393 } 394 } 395 396 /* 397 * Add a reference to a device. Callers generally add their own references 398 * when they are going to store a device node in a variable for long periods 399 * of time, to prevent a disassociation from free()ing the node. 400 * 401 * Also note that a caller that intends to call destroy_dev() must first 402 * obtain a reference on the device. The ad-hoc reference you get with 403 * make_dev() and friends is NOT sufficient to be able to call destroy_dev(). 404 */ 405 cdev_t 406 reference_dev(cdev_t dev) 407 { 408 if (dev != NOCDEV) { 409 ++dev->si_refs; 410 if (dev_ref_debug) { 411 kprintf("reference dev %p %s(minor=%08x) refs=%d\n", 412 dev, devtoname(dev), uminor(dev->si_udev), 413 dev->si_refs); 414 } 415 } 416 return(dev); 417 } 418 419 /* 420 * release a reference on a device. The device will be freed when the last 421 * reference has been released. 422 * 423 * NOTE: we must use si_udev to figure out the original (major, minor), 424 * because si_ops could already be pointing at dead_dev_ops. 425 */ 426 void 427 release_dev(cdev_t dev) 428 { 429 if (dev == NOCDEV) 430 return; 431 if (free_devt) { 432 KKASSERT(dev->si_refs > 0); 433 } else { 434 if (dev->si_refs <= 0) { 435 kprintf("Warning: extra release of dev %p(%s)\n", 436 dev, devtoname(dev)); 437 free_devt = 0; /* prevent bad things from occuring */ 438 } 439 } 440 --dev->si_refs; 441 if (dev_ref_debug) { 442 kprintf("release dev %p %s(minor=%08x) refs=%d\n", 443 dev, devtoname(dev), uminor(dev->si_udev), 444 dev->si_refs); 445 } 446 if (dev->si_refs == 0) { 447 if (dev->si_flags & SI_ADHOC) { 448 kprintf("Warning: illegal final release on ADHOC" 449 " device %p(%s), the device was never" 450 " destroyed!\n", 451 dev, devtoname(dev)); 452 } 453 if (dev->si_flags & SI_HASHED) { 454 kprintf("Warning: last release on device, no call" 455 " to destroy_dev() was made! dev %p(%s)\n", 456 dev, devtoname(dev)); 457 dev->si_refs = 3; 458 destroy_dev(dev); 459 dev->si_refs = 0; 460 } 461 if (SLIST_FIRST(&dev->si_hlist) != NULL) { 462 kprintf("Warning: last release on device, vnode" 463 " associations still exist! dev %p(%s)\n", 464 dev, devtoname(dev)); 465 free_devt = 0; /* prevent bad things from occuring */ 466 } 467 if (dev->si_ops && dev->si_ops != &dead_dev_ops) { 468 dev_ops_release(dev->si_ops); 469 dev->si_ops = NULL; 470 } 471 if (free_devt) { 472 if (dev->si_flags & SI_STASHED) { 473 bzero(dev, sizeof(*dev)); 474 LIST_INSERT_HEAD(&dev_free_list, dev, si_hash); 475 } else { 476 FREE(dev, M_DEVT); 477 } 478 } 479 } 480 } 481 482 const char * 483 devtoname(cdev_t dev) 484 { 485 int mynor; 486 int len; 487 char *p; 488 const char *dname; 489 490 if (dev == NOCDEV) 491 return("#nodev"); 492 if (dev->si_name[0] == '#' || dev->si_name[0] == '\0') { 493 p = dev->si_name; 494 len = sizeof(dev->si_name); 495 if ((dname = dev_dname(dev)) != NULL) 496 ksnprintf(p, len, "#%s/", dname); 497 else 498 ksnprintf(p, len, "#%d/", major(dev)); 499 len -= strlen(p); 500 p += strlen(p); 501 mynor = minor(dev); 502 if (mynor < 0 || mynor > 255) 503 ksnprintf(p, len, "%#x", (u_int)mynor); 504 else 505 ksnprintf(p, len, "%d", mynor); 506 } 507 return (dev->si_name); 508 } 509 510