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