kern_conf.c revision 144292
1/*- 2 * Copyright (c) 1999-2002 Poul-Henning Kamp 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24 * SUCH DAMAGE. 25 */ 26 27#include <sys/cdefs.h> 28__FBSDID("$FreeBSD: head/sys/kern/kern_conf.c 144292 2005-03-29 11:15:54Z phk $"); 29 30#include <sys/param.h> 31#include <sys/kernel.h> 32#include <sys/systm.h> 33#include <sys/bio.h> 34#include <sys/lock.h> 35#include <sys/mutex.h> 36#include <sys/sysctl.h> 37#include <sys/module.h> 38#include <sys/malloc.h> 39#include <sys/conf.h> 40#include <sys/vnode.h> 41#include <sys/queue.h> 42#include <sys/poll.h> 43#include <sys/ctype.h> 44#include <sys/tty.h> 45#include <machine/stdarg.h> 46 47static MALLOC_DEFINE(M_DEVT, "cdev", "cdev storage"); 48 49/* Built at compile time from sys/conf/majors */ 50 51static struct mtx devmtx; 52static void freedev(struct cdev *dev); 53static void destroy_devl(struct cdev *dev); 54 55void 56dev_lock(void) 57{ 58 if (!mtx_initialized(&devmtx)) 59 mtx_init(&devmtx, "cdev", NULL, MTX_DEF); 60 mtx_lock(&devmtx); 61} 62 63void 64dev_unlock(void) 65{ 66 67 mtx_unlock(&devmtx); 68} 69 70void 71dev_ref(struct cdev *dev) 72{ 73 74 mtx_assert(&devmtx, MA_OWNED); 75 dev->si_refcount++; 76} 77 78void 79dev_rel(struct cdev *dev) 80{ 81 int flag = 0; 82 83 mtx_assert(&devmtx, MA_NOTOWNED); 84 dev_lock(); 85 dev->si_refcount--; 86 KASSERT(dev->si_refcount >= 0, 87 ("dev_rel(%s) gave negative count", devtoname(dev))); 88 if (dev->si_usecount == 0 && 89 (dev->si_flags & SI_CHEAPCLONE) && (dev->si_flags & SI_NAMED)) 90 if (dev->si_devsw == NULL && dev->si_refcount == 0) { 91 LIST_REMOVE(dev, si_list); 92 flag = 1; 93 } 94 dev_unlock(); 95 if (flag) 96 freedev(dev); 97} 98 99struct cdevsw * 100dev_refthread(struct cdev *dev) 101{ 102 struct cdevsw *csw; 103 104 mtx_assert(&devmtx, MA_NOTOWNED); 105 dev_lock(); 106 csw = dev->si_devsw; 107 if (csw != NULL) 108 dev->si_threadcount++; 109 dev_unlock(); 110 return (csw); 111} 112 113void 114dev_relthread(struct cdev *dev) 115{ 116 117 mtx_assert(&devmtx, MA_NOTOWNED); 118 dev_lock(); 119 dev->si_threadcount--; 120 dev_unlock(); 121} 122 123int 124nullop(void) 125{ 126 127 return (0); 128} 129 130int 131eopnotsupp(void) 132{ 133 134 return (EOPNOTSUPP); 135} 136 137static int 138enxio(void) 139{ 140 return (ENXIO); 141} 142 143static int 144enodev(void) 145{ 146 return (ENODEV); 147} 148 149/* Define a dead_cdevsw for use when devices leave unexpectedly. */ 150 151#define dead_open (d_open_t *)enxio 152#define dead_close (d_close_t *)enxio 153#define dead_read (d_read_t *)enxio 154#define dead_write (d_write_t *)enxio 155#define dead_ioctl (d_ioctl_t *)enxio 156#define dead_poll (d_poll_t *)enodev 157#define dead_mmap (d_mmap_t *)enodev 158 159static void 160dead_strategy(struct bio *bp) 161{ 162 163 biofinish(bp, NULL, ENXIO); 164} 165 166#define dead_dump (dumper_t *)enxio 167#define dead_kqfilter (d_kqfilter_t *)enxio 168 169static struct cdevsw dead_cdevsw = { 170 .d_version = D_VERSION, 171 .d_flags = D_NEEDGIANT, /* XXX: does dead_strategy need this ? */ 172 .d_open = dead_open, 173 .d_close = dead_close, 174 .d_read = dead_read, 175 .d_write = dead_write, 176 .d_ioctl = dead_ioctl, 177 .d_poll = dead_poll, 178 .d_mmap = dead_mmap, 179 .d_strategy = dead_strategy, 180 .d_name = "dead", 181 .d_dump = dead_dump, 182 .d_kqfilter = dead_kqfilter 183}; 184 185/* Default methods if driver does not specify method */ 186 187#define null_open (d_open_t *)nullop 188#define null_close (d_close_t *)nullop 189#define no_read (d_read_t *)enodev 190#define no_write (d_write_t *)enodev 191#define no_ioctl (d_ioctl_t *)enodev 192#define no_mmap (d_mmap_t *)enodev 193#define no_kqfilter (d_kqfilter_t *)enodev 194 195static void 196no_strategy(struct bio *bp) 197{ 198 199 biofinish(bp, NULL, ENODEV); 200} 201 202static int 203no_poll(struct cdev *dev __unused, int events, struct thread *td __unused) 204{ 205 /* 206 * Return true for read/write. If the user asked for something 207 * special, return POLLNVAL, so that clients have a way of 208 * determining reliably whether or not the extended 209 * functionality is present without hard-coding knowledge 210 * of specific filesystem implementations. 211 * Stay in sync with vop_nopoll(). 212 */ 213 if (events & ~POLLSTANDARD) 214 return (POLLNVAL); 215 216 return (events & (POLLIN | POLLOUT | POLLRDNORM | POLLWRNORM)); 217} 218 219#define no_dump (dumper_t *)enodev 220 221/* 222 * struct cdev * and u_dev_t primitives 223 */ 224 225int 226minor(struct cdev *x) 227{ 228 if (x == NULL) 229 return NODEV; 230 return(x->si_drv0 & MAXMINOR); 231} 232 233int 234dev2unit(struct cdev *x) 235{ 236 237 if (x == NULL) 238 return NODEV; 239 return (minor2unit(minor(x))); 240} 241 242u_int 243minor2unit(u_int _minor) 244{ 245 246 KASSERT((_minor & ~MAXMINOR) == 0, ("Illegal minor %x", _minor)); 247 return ((_minor & 0xff) | ((_minor >> 8) & 0xffff00)); 248} 249 250int 251unit2minor(int unit) 252{ 253 254 KASSERT(unit <= 0xffffff, ("Invalid unit (%d) in unit2minor", unit)); 255 return ((unit & 0xff) | ((unit << 8) & ~0xffff)); 256} 257 258static struct cdev * 259allocdev(void) 260{ 261 struct cdev *si; 262 263 si = malloc(sizeof *si, M_DEVT, M_USE_RESERVE | M_ZERO | M_WAITOK); 264 si->si_name = si->__si_namebuf; 265 LIST_INIT(&si->si_children); 266 LIST_INIT(&si->si_alist); 267 return (si); 268} 269 270static struct cdev * 271newdev(struct cdevsw *csw, int y, struct cdev *si) 272{ 273 struct cdev *si2; 274 dev_t udev; 275 276 mtx_assert(&devmtx, MA_OWNED); 277 udev = y; 278 LIST_FOREACH(si2, &csw->d_devs, si_list) { 279 if (si2->si_drv0 == udev) { 280 freedev(si); 281 return (si2); 282 } 283 } 284 si->si_drv0 = udev; 285 LIST_INSERT_HEAD(&csw->d_devs, si, si_list); 286 return (si); 287} 288 289static void 290freedev(struct cdev *dev) 291{ 292 293 free(dev, M_DEVT); 294} 295 296int 297uminor(dev_t dev) 298{ 299 return (dev & MAXMINOR); 300} 301 302int 303umajor(dev_t dev) 304{ 305 return ((dev & ~MAXMINOR) >> 8); 306} 307 308static void 309fini_cdevsw(struct cdevsw *devsw) 310{ 311 312 devsw->d_flags &= ~D_INIT; 313} 314 315static void 316prep_cdevsw(struct cdevsw *devsw) 317{ 318 319 dev_lock(); 320 321 if (devsw->d_version != D_VERSION_01) { 322 printf( 323 "WARNING: Device driver \"%s\" has wrong version %s\n", 324 devsw->d_name, "and is disabled. Recompile KLD module."); 325 devsw->d_open = dead_open; 326 devsw->d_close = dead_close; 327 devsw->d_read = dead_read; 328 devsw->d_write = dead_write; 329 devsw->d_ioctl = dead_ioctl; 330 devsw->d_poll = dead_poll; 331 devsw->d_mmap = dead_mmap; 332 devsw->d_strategy = dead_strategy; 333 devsw->d_dump = dead_dump; 334 devsw->d_kqfilter = dead_kqfilter; 335 } 336 337 if (devsw->d_flags & D_TTY) { 338 if (devsw->d_ioctl == NULL) devsw->d_ioctl = ttyioctl; 339 if (devsw->d_read == NULL) devsw->d_read = ttyread; 340 if (devsw->d_write == NULL) devsw->d_write = ttywrite; 341 if (devsw->d_kqfilter == NULL) devsw->d_kqfilter = ttykqfilter; 342 if (devsw->d_poll == NULL) devsw->d_poll = ttypoll; 343 } 344 345 if (devsw->d_open == NULL) devsw->d_open = null_open; 346 if (devsw->d_close == NULL) devsw->d_close = null_close; 347 if (devsw->d_read == NULL) devsw->d_read = no_read; 348 if (devsw->d_write == NULL) devsw->d_write = no_write; 349 if (devsw->d_ioctl == NULL) devsw->d_ioctl = no_ioctl; 350 if (devsw->d_poll == NULL) devsw->d_poll = no_poll; 351 if (devsw->d_mmap == NULL) devsw->d_mmap = no_mmap; 352 if (devsw->d_strategy == NULL) devsw->d_strategy = no_strategy; 353 if (devsw->d_dump == NULL) devsw->d_dump = no_dump; 354 if (devsw->d_kqfilter == NULL) devsw->d_kqfilter = no_kqfilter; 355 356 LIST_INIT(&devsw->d_devs); 357 358 devsw->d_flags |= D_INIT; 359 360 dev_unlock(); 361} 362 363struct cdev * 364make_dev(struct cdevsw *devsw, int minornr, uid_t uid, gid_t gid, int perms, const char *fmt, ...) 365{ 366 struct cdev *dev; 367 va_list ap; 368 int i; 369 370 KASSERT((minornr & ~MAXMINOR) == 0, 371 ("Invalid minor (0x%x) in make_dev", minornr)); 372 373 if (!(devsw->d_flags & D_INIT)) { 374 prep_cdevsw(devsw); 375 if (devsw->d_uid == 0) 376 devsw->d_uid = uid; 377 if (devsw->d_gid == 0) 378 devsw->d_gid = gid; 379 if (devsw->d_mode == 0) 380 devsw->d_mode = perms; 381 } 382 dev = allocdev(); 383 dev_lock(); 384 dev = newdev(devsw, minornr, dev); 385 if (dev->si_flags & SI_CHEAPCLONE && 386 dev->si_flags & SI_NAMED && 387 dev->si_devsw == devsw) { 388 /* 389 * This is allowed as it removes races and generally 390 * simplifies cloning devices. 391 * XXX: still ?? 392 */ 393 dev_unlock(); 394 return (dev); 395 } 396 KASSERT(!(dev->si_flags & SI_NAMED), 397 ("make_dev() by driver %s on pre-existing device (min=%x, name=%s)", 398 devsw->d_name, minor(dev), devtoname(dev))); 399 400 va_start(ap, fmt); 401 i = vsnrprintf(dev->__si_namebuf, sizeof dev->__si_namebuf, 32, fmt, ap); 402 if (i > (sizeof dev->__si_namebuf - 1)) { 403 printf("WARNING: Device name truncated! (%s)\n", 404 dev->__si_namebuf); 405 } 406 va_end(ap); 407 408 dev->si_devsw = devsw; 409 dev->si_flags |= SI_NAMED; 410 411 devfs_create(dev); 412 dev_unlock(); 413 return (dev); 414} 415 416int 417dev_named(struct cdev *pdev, const char *name) 418{ 419 struct cdev *cdev; 420 421 if (strcmp(devtoname(pdev), name) == 0) 422 return (1); 423 LIST_FOREACH(cdev, &pdev->si_children, si_siblings) 424 if (strcmp(devtoname(cdev), name) == 0) 425 return (1); 426 return (0); 427} 428 429void 430dev_depends(struct cdev *pdev, struct cdev *cdev) 431{ 432 433 dev_lock(); 434 cdev->si_parent = pdev; 435 cdev->si_flags |= SI_CHILD; 436 LIST_INSERT_HEAD(&pdev->si_children, cdev, si_siblings); 437 dev_unlock(); 438} 439 440struct cdev * 441make_dev_alias(struct cdev *pdev, const char *fmt, ...) 442{ 443 struct cdev *dev; 444 va_list ap; 445 int i; 446 447 dev = allocdev(); 448 dev_lock(); 449 dev->si_flags |= SI_ALIAS; 450 dev->si_flags |= SI_NAMED; 451 va_start(ap, fmt); 452 i = vsnrprintf(dev->__si_namebuf, sizeof dev->__si_namebuf, 32, fmt, ap); 453 if (i > (sizeof dev->__si_namebuf - 1)) { 454 printf("WARNING: Device name truncated! (%s)\n", 455 dev->__si_namebuf); 456 } 457 va_end(ap); 458 459 devfs_create(dev); 460 dev_unlock(); 461 dev_depends(pdev, dev); 462 return (dev); 463} 464 465static void 466destroy_devl(struct cdev *dev) 467{ 468 struct cdevsw *csw; 469 470 mtx_assert(&devmtx, MA_OWNED); 471 KASSERT(dev->si_flags & SI_NAMED, 472 ("WARNING: Driver mistake: destroy_dev on %d\n", minor(dev))); 473 474 devfs_destroy(dev); 475 476 /* Remove name marking */ 477 dev->si_flags &= ~SI_NAMED; 478 479 /* If we are a child, remove us from the parents list */ 480 if (dev->si_flags & SI_CHILD) { 481 LIST_REMOVE(dev, si_siblings); 482 dev->si_flags &= ~SI_CHILD; 483 } 484 485 /* Kill our children */ 486 while (!LIST_EMPTY(&dev->si_children)) 487 destroy_devl(LIST_FIRST(&dev->si_children)); 488 489 /* Remove from clone list */ 490 if (dev->si_flags & SI_CLONELIST) { 491 LIST_REMOVE(dev, si_clone); 492 dev->si_flags &= ~SI_CLONELIST; 493 } 494 495 csw = dev->si_devsw; 496 dev->si_devsw = NULL; /* already NULL for SI_ALIAS */ 497 while (csw != NULL && csw->d_purge != NULL && dev->si_threadcount) { 498 printf("Purging %lu threads from %s\n", 499 dev->si_threadcount, devtoname(dev)); 500 csw->d_purge(dev); 501 msleep(csw, &devmtx, PRIBIO, "devprg", hz/10); 502 } 503 if (csw != NULL && csw->d_purge != NULL) 504 printf("All threads purged from %s\n", devtoname(dev)); 505 506 dev->si_drv1 = 0; 507 dev->si_drv2 = 0; 508 bzero(&dev->__si_u, sizeof(dev->__si_u)); 509 510 if (!(dev->si_flags & SI_ALIAS)) { 511 /* Remove from cdevsw list */ 512 LIST_REMOVE(dev, si_list); 513 514 /* If cdevsw has no struct cdev *'s, clean it */ 515 if (LIST_EMPTY(&csw->d_devs)) 516 fini_cdevsw(csw); 517 } 518 dev->si_flags &= ~SI_ALIAS; 519 520 if (dev->si_refcount > 0) { 521 LIST_INSERT_HEAD(&dead_cdevsw.d_devs, dev, si_list); 522 } else { 523 freedev(dev); 524 } 525} 526 527void 528destroy_dev(struct cdev *dev) 529{ 530 531 dev_lock(); 532 destroy_devl(dev); 533 dev_unlock(); 534} 535 536const char * 537devtoname(struct cdev *dev) 538{ 539 char *p; 540 struct cdevsw *csw; 541 int mynor; 542 543 if (dev->si_name[0] == '#' || dev->si_name[0] == '\0') { 544 p = dev->si_name; 545 csw = dev_refthread(dev); 546 if (csw != NULL) { 547 sprintf(p, "(%s)", csw->d_name); 548 dev_relthread(dev); 549 } 550 p += strlen(p); 551 mynor = minor(dev); 552 if (mynor < 0 || mynor > 255) 553 sprintf(p, "/%#x", (u_int)mynor); 554 else 555 sprintf(p, "/%d", mynor); 556 } 557 return (dev->si_name); 558} 559 560int 561dev_stdclone(char *name, char **namep, const char *stem, int *unit) 562{ 563 int u, i; 564 565 i = strlen(stem); 566 if (bcmp(stem, name, i) != 0) 567 return (0); 568 if (!isdigit(name[i])) 569 return (0); 570 u = 0; 571 if (name[i] == '0' && isdigit(name[i+1])) 572 return (0); 573 while (isdigit(name[i])) { 574 u *= 10; 575 u += name[i++] - '0'; 576 } 577 if (u > 0xffffff) 578 return (0); 579 *unit = u; 580 if (namep) 581 *namep = &name[i]; 582 if (name[i]) 583 return (2); 584 return (1); 585} 586 587/* 588 * Helper functions for cloning device drivers. 589 * 590 * The objective here is to make it unnecessary for the device drivers to 591 * use rman or similar to manage their unit number space. Due to the way 592 * we do "on-demand" devices, using rman or other "private" methods 593 * will be very tricky to lock down properly once we lock down this file. 594 * 595 * Instead we give the drivers these routines which puts the struct cdev *'s 596 * that are to be managed on their own list, and gives the driver the ability 597 * to ask for the first free unit number or a given specified unit number. 598 * 599 * In addition these routines support paired devices (pty, nmdm and similar) 600 * by respecting a number of "flag" bits in the minor number. 601 * 602 */ 603 604struct clonedevs { 605 LIST_HEAD(,cdev) head; 606}; 607 608void 609clone_setup(struct clonedevs **cdp) 610{ 611 612 *cdp = malloc(sizeof **cdp, M_DEVBUF, M_WAITOK | M_ZERO); 613 LIST_INIT(&(*cdp)->head); 614} 615 616int 617clone_create(struct clonedevs **cdp, struct cdevsw *csw, int *up, struct cdev **dp, u_int extra) 618{ 619 struct clonedevs *cd; 620 struct cdev *dev, *ndev, *dl, *de; 621 int unit, low, u; 622 623 KASSERT(*cdp != NULL, 624 ("clone_setup() not called in driver \"%s\"", csw->d_name)); 625 KASSERT(!(extra & CLONE_UNITMASK), 626 ("Illegal extra bits (0x%x) in clone_create", extra)); 627 KASSERT(*up <= CLONE_UNITMASK, 628 ("Too high unit (0x%x) in clone_create", *up)); 629 630 if (!(csw->d_flags & D_INIT)) 631 prep_cdevsw(csw); 632 633 /* 634 * Search the list for a lot of things in one go: 635 * A preexisting match is returned immediately. 636 * The lowest free unit number if we are passed -1, and the place 637 * in the list where we should insert that new element. 638 * The place to insert a specified unit number, if applicable 639 * the end of the list. 640 */ 641 unit = *up; 642 ndev = allocdev(); 643 dev_lock(); 644 low = extra; 645 de = dl = NULL; 646 cd = *cdp; 647 LIST_FOREACH(dev, &cd->head, si_clone) { 648 KASSERT(dev->si_flags & SI_CLONELIST, 649 ("Dev %p(%s) should be on clonelist", dev, dev->si_name)); 650 u = dev2unit(dev); 651 if (u == (unit | extra)) { 652 *dp = dev; 653 freedev(ndev); 654 dev_unlock(); 655 return (0); 656 } 657 if (unit == -1 && u == low) { 658 low++; 659 de = dev; 660 continue; 661 } 662 if (u > (unit | extra)) { 663 dl = dev; 664 break; 665 } 666 } 667 if (unit == -1) 668 unit = low & CLONE_UNITMASK; 669 dev = newdev(csw, unit2minor(unit | extra), ndev); 670 if (dev->si_flags & SI_CLONELIST) { 671 printf("dev %p (%s) is on clonelist\n", dev, dev->si_name); 672 printf("unit=%d\n", unit); 673 LIST_FOREACH(dev, &cd->head, si_clone) { 674 printf("\t%p %s\n", dev, dev->si_name); 675 } 676 panic("foo"); 677 } 678 KASSERT(!(dev->si_flags & SI_CLONELIST), 679 ("Dev %p(%s) should not be on clonelist", dev, dev->si_name)); 680 if (dl != NULL) 681 LIST_INSERT_BEFORE(dl, dev, si_clone); 682 else if (de != NULL) 683 LIST_INSERT_AFTER(de, dev, si_clone); 684 else 685 LIST_INSERT_HEAD(&cd->head, dev, si_clone); 686 dev->si_flags |= SI_CLONELIST; 687 *up = unit; 688 dev_unlock(); 689 return (1); 690} 691 692/* 693 * Kill everything still on the list. The driver should already have 694 * disposed of any softc hung of the struct cdev *'s at this time. 695 */ 696void 697clone_cleanup(struct clonedevs **cdp) 698{ 699 struct cdev *dev, *tdev; 700 struct clonedevs *cd; 701 702 cd = *cdp; 703 if (cd == NULL) 704 return; 705 dev_lock(); 706 LIST_FOREACH_SAFE(dev, &cd->head, si_clone, tdev) { 707 KASSERT(dev->si_flags & SI_CLONELIST, 708 ("Dev %p(%s) should be on clonelist", dev, dev->si_name)); 709 KASSERT(dev->si_flags & SI_NAMED, 710 ("Driver has goofed in cloning underways udev %x", dev->si_drv0)); 711 destroy_devl(dev); 712 } 713 dev_unlock(); 714 free(cd, M_DEVBUF); 715 *cdp = NULL; 716} 717