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.23 2007/05/09 00:53:34 dillon 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 <sys/disk.h> 48 #include <machine/stdarg.h> 49 50 #include <sys/sysref2.h> 51 52 #include <sys/devfs.h> 53 54 MALLOC_DEFINE(M_DEVT, "cdev_t", "dev_t storage"); 55 56 int dev_ref_debug = 0; 57 SYSCTL_INT(_debug, OID_AUTO, dev_refs, CTLFLAG_RW, &dev_ref_debug, 0, 58 "Toggle device reference debug output"); 59 60 /* 61 * cdev_t and u_dev_t primitives. Note that the major number is always 62 * extracted from si_umajor, not from si_devsw, because si_devsw is replaced 63 * when a device is destroyed. 64 */ 65 int 66 major(cdev_t dev) 67 { 68 if (dev == NULL) 69 return NOUDEV; 70 return(dev->si_umajor); 71 } 72 73 int 74 minor(cdev_t dev) 75 { 76 if (dev == NULL) 77 return NOUDEV; 78 return(dev->si_uminor); 79 } 80 81 /* 82 * Compatibility function with old udev_t format to convert the 83 * non-consecutive minor space into a consecutive minor space. 84 */ 85 int 86 lminor(cdev_t dev) 87 { 88 int y; 89 90 if (dev == NULL) 91 return NOUDEV; 92 y = dev->si_uminor; 93 if (y & 0x0000ff00) 94 return NOUDEV; 95 return ((y & 0xff) | (y >> 8)); 96 } 97 98 /* 99 * Convert a device pointer to an old style device number. Return NOUDEV 100 * if the device is invalid or if the device (maj,min) cannot be converted 101 * to an old style udev_t. 102 */ 103 udev_t 104 dev2udev(cdev_t dev) 105 { 106 if (dev == NULL) 107 return NOUDEV; 108 109 return (udev_t)dev->si_inode; 110 } 111 112 /* 113 * Convert a device number to a device pointer. The device is referenced 114 * ad-hoc, meaning that the caller should call reference_dev() if it wishes 115 * to keep ahold of the returned structure long term. 116 * 117 * The returned device is associated with the currently installed cdevsw 118 * for the requested major number. NULL is returned if the major number 119 * has not been registered. 120 */ 121 cdev_t 122 udev2dev(udev_t x, int b) 123 { 124 if (x == NOUDEV || b != 0) 125 return(NULL); 126 127 return devfs_find_device_by_udev(x); 128 } 129 130 int 131 dev_is_good(cdev_t dev) 132 { 133 if (dev != NULL && dev->si_ops != &dead_dev_ops) 134 return(1); 135 return(0); 136 } 137 138 /* 139 * Various user device number extraction and conversion routines 140 */ 141 int 142 uminor(udev_t dev) 143 { 144 if (dev == NOUDEV) 145 return(-1); 146 return(dev & 0xffff00ff); 147 } 148 149 int 150 umajor(udev_t dev) 151 { 152 if (dev == NOUDEV) 153 return(-1); 154 return((dev & 0xff00) >> 8); 155 } 156 157 udev_t 158 makeudev(int x, int y) 159 { 160 if ((x & 0xffffff00) || (y & 0x0000ff00)) 161 return NOUDEV; 162 return ((x << 8) | y); 163 } 164 165 /* 166 * Create an internal or external device. 167 * 168 * This routine creates and returns an unreferenced ad-hoc entry for the 169 * device which will remain intact until the device is destroyed. If the 170 * caller intends to store the device pointer it must call reference_dev() 171 * to retain a real reference to the device. 172 * 173 * If an entry already exists, this function will set (or override) 174 * its cred requirements and name (XXX DEVFS interface). 175 */ 176 cdev_t 177 make_dev(struct dev_ops *ops, int minor, uid_t uid, gid_t gid, 178 int perms, const char *fmt, ...) 179 { 180 cdev_t devfs_dev; 181 __va_list ap; 182 183 /* 184 * compile the cdevsw and install the device 185 */ 186 compile_dev_ops(ops); 187 188 devfs_dev = devfs_new_cdev(ops, minor, NULL); 189 __va_start(ap, fmt); 190 kvsnrprintf(devfs_dev->si_name, sizeof(devfs_dev->si_name), 191 32, fmt, ap); 192 __va_end(ap); 193 194 devfs_debug(DEVFS_DEBUG_INFO, 195 "make_dev called for %s\n", 196 devfs_dev->si_name); 197 devfs_create_dev(devfs_dev, uid, gid, perms); 198 199 return (devfs_dev); 200 } 201 202 /* 203 * make_dev_covering has equivalent functionality to make_dev, except that it 204 * also takes the cdev of the underlying device. Hence this function should 205 * only be used by systems and drivers which create devices covering others 206 */ 207 cdev_t 208 make_dev_covering(struct dev_ops *ops, struct dev_ops *bops, int minor, 209 uid_t uid, gid_t gid, int perms, const char *fmt, ...) 210 { 211 cdev_t devfs_dev; 212 __va_list ap; 213 214 /* 215 * compile the cdevsw and install the device 216 */ 217 compile_dev_ops(ops); 218 219 devfs_dev = devfs_new_cdev(ops, minor, bops); 220 __va_start(ap, fmt); 221 kvsnrprintf(devfs_dev->si_name, sizeof(devfs_dev->si_name), 222 32, fmt, ap); 223 __va_end(ap); 224 225 devfs_debug(DEVFS_DEBUG_INFO, 226 "make_dev called for %s\n", 227 devfs_dev->si_name); 228 devfs_create_dev(devfs_dev, uid, gid, perms); 229 230 return (devfs_dev); 231 } 232 233 234 235 cdev_t 236 make_only_devfs_dev(struct dev_ops *ops, int minor, uid_t uid, gid_t gid, 237 int perms, const char *fmt, ...) 238 { 239 cdev_t devfs_dev; 240 __va_list ap; 241 242 /* 243 * compile the cdevsw and install the device 244 */ 245 compile_dev_ops(ops); 246 devfs_dev = devfs_new_cdev(ops, minor, NULL); 247 248 /* 249 * Set additional fields (XXX DEVFS interface goes here) 250 */ 251 __va_start(ap, fmt); 252 kvsnrprintf(devfs_dev->si_name, sizeof(devfs_dev->si_name), 253 32, fmt, ap); 254 __va_end(ap); 255 256 devfs_create_dev(devfs_dev, uid, gid, perms); 257 258 return (devfs_dev); 259 } 260 261 cdev_t 262 make_only_dev(struct dev_ops *ops, int minor, uid_t uid, gid_t gid, 263 int perms, const char *fmt, ...) 264 { 265 cdev_t devfs_dev; 266 __va_list ap; 267 268 /* 269 * compile the cdevsw and install the device 270 */ 271 compile_dev_ops(ops); 272 devfs_dev = devfs_new_cdev(ops, minor, NULL); 273 devfs_dev->si_perms = perms; 274 devfs_dev->si_uid = uid; 275 devfs_dev->si_gid = gid; 276 277 /* 278 * Set additional fields (XXX DEVFS interface goes here) 279 */ 280 __va_start(ap, fmt); 281 kvsnrprintf(devfs_dev->si_name, sizeof(devfs_dev->si_name), 282 32, fmt, ap); 283 __va_end(ap); 284 285 reference_dev(devfs_dev); 286 287 return (devfs_dev); 288 } 289 290 cdev_t 291 make_only_dev_covering(struct dev_ops *ops, struct dev_ops *bops, int minor, 292 uid_t uid, gid_t gid, int perms, const char *fmt, ...) 293 { 294 cdev_t devfs_dev; 295 __va_list ap; 296 297 /* 298 * compile the cdevsw and install the device 299 */ 300 compile_dev_ops(ops); 301 devfs_dev = devfs_new_cdev(ops, minor, bops); 302 devfs_dev->si_perms = perms; 303 devfs_dev->si_uid = uid; 304 devfs_dev->si_gid = gid; 305 306 /* 307 * Set additional fields (XXX DEVFS interface goes here) 308 */ 309 __va_start(ap, fmt); 310 kvsnrprintf(devfs_dev->si_name, sizeof(devfs_dev->si_name), 311 32, fmt, ap); 312 __va_end(ap); 313 314 reference_dev(devfs_dev); 315 316 return (devfs_dev); 317 } 318 319 void 320 destroy_only_dev(cdev_t dev) 321 { 322 release_dev(dev); 323 release_dev(dev); 324 release_dev(dev); 325 } 326 327 /* 328 * destroy_dev() removes the adhoc association for a device and revectors 329 * its ops to &dead_dev_ops. 330 * 331 * This routine releases the reference count associated with the ADHOC 332 * entry, plus releases the reference count held by the caller. What this 333 * means is that you should not call destroy_dev(make_dev(...)), because 334 * make_dev() does not bump the reference count (beyond what it needs to 335 * create the ad-hoc association). Any procedure that intends to destroy 336 * a device must have its own reference to it first. 337 */ 338 void 339 destroy_dev(cdev_t dev) 340 { 341 if (dev) { 342 devfs_debug(DEVFS_DEBUG_DEBUG, 343 "destroy_dev called for %s\n", 344 dev->si_name); 345 devfs_destroy_dev(dev); 346 } 347 } 348 349 /* 350 * Make sure all asynchronous disk and devfs related operations have 351 * completed. 352 * 353 * Typically called prior to mountroot to ensure that all disks have 354 * been completely probed and on module unload to ensure that ops 355 * structures have been dereferenced. 356 */ 357 void 358 sync_devs(void) 359 { 360 disk_config(NULL); 361 devfs_config(); 362 disk_config(NULL); 363 devfs_config(); 364 } 365 366 int 367 make_dev_alias(cdev_t target, const char *fmt, ...) 368 { 369 __va_list ap; 370 char *name; 371 372 __va_start(ap, fmt); 373 kvasnrprintf(&name, PATH_MAX, 32, fmt, ap); 374 __va_end(ap); 375 376 devfs_make_alias(name, target); 377 kvasfree(&name); 378 379 return 0; 380 } 381 382 int 383 destroy_dev_alias(cdev_t target, const char *fmt, ...) 384 { 385 __va_list ap; 386 char *name; 387 388 __va_start(ap, fmt); 389 kvasnrprintf(&name, PATH_MAX, 32, fmt, ap); 390 __va_end(ap); 391 392 devfs_destroy_alias(name, target); 393 kvasfree(&name); 394 395 return 0; 396 } 397 398 extern struct dev_ops default_dev_ops; 399 400 cdev_t 401 make_autoclone_dev(struct dev_ops *ops, struct devfs_bitmap *bitmap, 402 d_clone_t *nhandler, uid_t uid, gid_t gid, int perms, const char *fmt, ...) 403 { 404 __va_list ap; 405 cdev_t dev; 406 char *name; 407 408 __va_start(ap, fmt); 409 kvasnrprintf(&name, PATH_MAX, 32, fmt, ap); 410 __va_end(ap); 411 412 if (bitmap != NULL) 413 devfs_clone_bitmap_init(bitmap); 414 415 devfs_clone_handler_add(name, nhandler); 416 dev = make_dev_covering(&default_dev_ops, ops, 0xffff00ff, 417 uid, gid, perms, "%s", name); 418 kvasfree(&name); 419 return dev; 420 } 421 422 void 423 destroy_autoclone_dev(cdev_t dev, struct devfs_bitmap *bitmap) 424 { 425 if (dev == NULL) 426 return; 427 428 devfs_clone_handler_del(dev->si_name); 429 430 if (bitmap != NULL) 431 devfs_clone_bitmap_uninit(bitmap); 432 433 destroy_dev(dev); 434 } 435 436 437 /* 438 * Add a reference to a device. Callers generally add their own references 439 * when they are going to store a device node in a variable for long periods 440 * of time, to prevent a disassociation from free()ing the node. 441 * 442 * Also note that a caller that intends to call destroy_dev() must first 443 * obtain a reference on the device. The ad-hoc reference you get with 444 * make_dev() and friends is NOT sufficient to be able to call destroy_dev(). 445 */ 446 cdev_t 447 reference_dev(cdev_t dev) 448 { 449 //kprintf("reference_dev\n"); 450 451 if (dev != NULL) { 452 sysref_get(&dev->si_sysref); 453 if (dev_ref_debug & 2) { 454 kprintf("reference dev %p %s(minor=%08x) refs=%d\n", 455 dev, devtoname(dev), dev->si_uminor, 456 dev->si_sysref.refcnt); 457 } 458 } 459 return(dev); 460 } 461 462 /* 463 * release a reference on a device. The device will be terminated when the 464 * last reference has been released. 465 * 466 * NOTE: we must use si_umajor to figure out the original major number, 467 * because si_ops could already be pointing at dead_dev_ops. 468 */ 469 void 470 release_dev(cdev_t dev) 471 { 472 //kprintf("release_dev\n"); 473 474 if (dev == NULL) 475 return; 476 sysref_put(&dev->si_sysref); 477 } 478 479 const char * 480 devtoname(cdev_t dev) 481 { 482 int mynor; 483 int len; 484 char *p; 485 const char *dname; 486 487 if (dev == NULL) 488 return("#nodev"); 489 if (dev->si_name[0] == '#' || dev->si_name[0] == '\0') { 490 p = dev->si_name; 491 len = sizeof(dev->si_name); 492 if ((dname = dev_dname(dev)) != NULL) 493 ksnprintf(p, len, "#%s/", dname); 494 else 495 ksnprintf(p, len, "#%d/", major(dev)); 496 len -= strlen(p); 497 p += strlen(p); 498 mynor = minor(dev); 499 if (mynor < 0 || mynor > 255) 500 ksnprintf(p, len, "%#x", (u_int)mynor); 501 else 502 ksnprintf(p, len, "%d", mynor); 503 } 504 return (dev->si_name); 505 } 506 507