kern_conf.c revision 170152
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 170152 2007-05-31 11:51:53Z kib $"); 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/module.h> 37#include <sys/malloc.h> 38#include <sys/conf.h> 39#include <sys/vnode.h> 40#include <sys/queue.h> 41#include <sys/poll.h> 42#include <sys/ctype.h> 43#include <sys/tty.h> 44#include <sys/ucred.h> 45#include <machine/stdarg.h> 46 47#include <fs/devfs/devfs_int.h> 48 49static MALLOC_DEFINE(M_DEVT, "cdev", "cdev storage"); 50 51struct mtx devmtx; 52static void destroy_devl(struct cdev *dev); 53static struct cdev *make_dev_credv(struct cdevsw *devsw, int minornr, 54 struct ucred *cr, uid_t uid, gid_t gid, int mode, const char *fmt, 55 va_list ap); 56 57void 58dev_lock(void) 59{ 60 61 mtx_lock(&devmtx); 62} 63 64void 65dev_unlock(void) 66{ 67 68 mtx_unlock(&devmtx); 69} 70 71void 72dev_ref(struct cdev *dev) 73{ 74 75 mtx_assert(&devmtx, MA_NOTOWNED); 76 mtx_lock(&devmtx); 77 dev->si_refcount++; 78 mtx_unlock(&devmtx); 79} 80 81void 82dev_refl(struct cdev *dev) 83{ 84 85 mtx_assert(&devmtx, MA_OWNED); 86 dev->si_refcount++; 87} 88 89void 90dev_rel(struct cdev *dev) 91{ 92 int flag = 0; 93 94 mtx_assert(&devmtx, MA_NOTOWNED); 95 dev_lock(); 96 dev->si_refcount--; 97 KASSERT(dev->si_refcount >= 0, 98 ("dev_rel(%s) gave negative count", devtoname(dev))); 99#if 0 100 if (dev->si_usecount == 0 && 101 (dev->si_flags & SI_CHEAPCLONE) && (dev->si_flags & SI_NAMED)) 102 ; 103 else 104#endif 105 if (dev->si_devsw == NULL && dev->si_refcount == 0) { 106 LIST_REMOVE(dev, si_list); 107 flag = 1; 108 } 109 dev_unlock(); 110 if (flag) 111 devfs_free(dev); 112} 113 114struct cdevsw * 115dev_refthread(struct cdev *dev) 116{ 117 struct cdevsw *csw; 118 119 mtx_assert(&devmtx, MA_NOTOWNED); 120 dev_lock(); 121 csw = dev->si_devsw; 122 if (csw != NULL) 123 dev->si_threadcount++; 124 dev_unlock(); 125 return (csw); 126} 127 128struct cdevsw * 129devvn_refthread(struct vnode *vp, struct cdev **devp) 130{ 131 struct cdevsw *csw; 132 133 mtx_assert(&devmtx, MA_NOTOWNED); 134 csw = NULL; 135 dev_lock(); 136 *devp = vp->v_rdev; 137 if (*devp != NULL) { 138 csw = (*devp)->si_devsw; 139 if (csw != NULL) 140 (*devp)->si_threadcount++; 141 } 142 dev_unlock(); 143 return (csw); 144} 145 146void 147dev_relthread(struct cdev *dev) 148{ 149 150 mtx_assert(&devmtx, MA_NOTOWNED); 151 dev_lock(); 152 dev->si_threadcount--; 153 dev_unlock(); 154} 155 156int 157nullop(void) 158{ 159 160 return (0); 161} 162 163int 164eopnotsupp(void) 165{ 166 167 return (EOPNOTSUPP); 168} 169 170static int 171enxio(void) 172{ 173 return (ENXIO); 174} 175 176static int 177enodev(void) 178{ 179 return (ENODEV); 180} 181 182/* Define a dead_cdevsw for use when devices leave unexpectedly. */ 183 184#define dead_open (d_open_t *)enxio 185#define dead_close (d_close_t *)enxio 186#define dead_read (d_read_t *)enxio 187#define dead_write (d_write_t *)enxio 188#define dead_ioctl (d_ioctl_t *)enxio 189#define dead_poll (d_poll_t *)enodev 190#define dead_mmap (d_mmap_t *)enodev 191 192static void 193dead_strategy(struct bio *bp) 194{ 195 196 biofinish(bp, NULL, ENXIO); 197} 198 199#define dead_dump (dumper_t *)enxio 200#define dead_kqfilter (d_kqfilter_t *)enxio 201 202static struct cdevsw dead_cdevsw = { 203 .d_version = D_VERSION, 204 .d_flags = D_NEEDGIANT, /* XXX: does dead_strategy need this ? */ 205 .d_open = dead_open, 206 .d_close = dead_close, 207 .d_read = dead_read, 208 .d_write = dead_write, 209 .d_ioctl = dead_ioctl, 210 .d_poll = dead_poll, 211 .d_mmap = dead_mmap, 212 .d_strategy = dead_strategy, 213 .d_name = "dead", 214 .d_dump = dead_dump, 215 .d_kqfilter = dead_kqfilter 216}; 217 218/* Default methods if driver does not specify method */ 219 220#define null_open (d_open_t *)nullop 221#define null_close (d_close_t *)nullop 222#define no_read (d_read_t *)enodev 223#define no_write (d_write_t *)enodev 224#define no_ioctl (d_ioctl_t *)enodev 225#define no_mmap (d_mmap_t *)enodev 226#define no_kqfilter (d_kqfilter_t *)enodev 227 228static void 229no_strategy(struct bio *bp) 230{ 231 232 biofinish(bp, NULL, ENODEV); 233} 234 235static int 236no_poll(struct cdev *dev __unused, int events, struct thread *td __unused) 237{ 238 /* 239 * Return true for read/write. If the user asked for something 240 * special, return POLLNVAL, so that clients have a way of 241 * determining reliably whether or not the extended 242 * functionality is present without hard-coding knowledge 243 * of specific filesystem implementations. 244 * Stay in sync with vop_nopoll(). 245 */ 246 if (events & ~POLLSTANDARD) 247 return (POLLNVAL); 248 249 return (events & (POLLIN | POLLOUT | POLLRDNORM | POLLWRNORM)); 250} 251 252#define no_dump (dumper_t *)enodev 253 254static int 255giant_open(struct cdev *dev, int oflags, int devtype, struct thread *td) 256{ 257 int retval; 258 259 mtx_lock(&Giant); 260 retval = dev->si_devsw->d_gianttrick-> 261 d_open(dev, oflags, devtype, td); 262 mtx_unlock(&Giant); 263 return (retval); 264} 265 266static int 267giant_fdopen(struct cdev *dev, int oflags, struct thread *td, struct file *fp) 268{ 269 int retval; 270 271 mtx_lock(&Giant); 272 retval = dev->si_devsw->d_gianttrick-> 273 d_fdopen(dev, oflags, td, fp); 274 mtx_unlock(&Giant); 275 return (retval); 276} 277 278static int 279giant_close(struct cdev *dev, int fflag, int devtype, struct thread *td) 280{ 281 int retval; 282 283 mtx_lock(&Giant); 284 retval = dev->si_devsw->d_gianttrick-> 285 d_close(dev, fflag, devtype, td); 286 mtx_unlock(&Giant); 287 return (retval); 288} 289 290static void 291giant_strategy(struct bio *bp) 292{ 293 294 mtx_lock(&Giant); 295 bp->bio_dev->si_devsw->d_gianttrick-> 296 d_strategy(bp); 297 mtx_unlock(&Giant); 298} 299 300static int 301giant_ioctl(struct cdev *dev, u_long cmd, caddr_t data, int fflag, struct thread *td) 302{ 303 int retval; 304 305 mtx_lock(&Giant); 306 retval = dev->si_devsw->d_gianttrick-> 307 d_ioctl(dev, cmd, data, fflag, td); 308 mtx_unlock(&Giant); 309 return (retval); 310} 311 312static int 313giant_read(struct cdev *dev, struct uio *uio, int ioflag) 314{ 315 int retval; 316 317 mtx_lock(&Giant); 318 retval = dev->si_devsw->d_gianttrick-> 319 d_read(dev, uio, ioflag); 320 mtx_unlock(&Giant); 321 return (retval); 322} 323 324static int 325giant_write(struct cdev *dev, struct uio *uio, int ioflag) 326{ 327 int retval; 328 329 mtx_lock(&Giant); 330 retval = dev->si_devsw->d_gianttrick-> 331 d_write(dev, uio, ioflag); 332 mtx_unlock(&Giant); 333 return (retval); 334} 335 336static int 337giant_poll(struct cdev *dev, int events, struct thread *td) 338{ 339 int retval; 340 341 mtx_lock(&Giant); 342 retval = dev->si_devsw->d_gianttrick-> 343 d_poll(dev, events, td); 344 mtx_unlock(&Giant); 345 return (retval); 346} 347 348static int 349giant_kqfilter(struct cdev *dev, struct knote *kn) 350{ 351 int retval; 352 353 mtx_lock(&Giant); 354 retval = dev->si_devsw->d_gianttrick-> 355 d_kqfilter(dev, kn); 356 mtx_unlock(&Giant); 357 return (retval); 358} 359 360static int 361giant_mmap(struct cdev *dev, vm_offset_t offset, vm_paddr_t *paddr, int nprot) 362{ 363 int retval; 364 365 mtx_lock(&Giant); 366 retval = dev->si_devsw->d_gianttrick-> 367 d_mmap(dev, offset, paddr, nprot); 368 mtx_unlock(&Giant); 369 return (retval); 370} 371 372 373/* 374 * struct cdev * and u_dev_t primitives 375 */ 376 377int 378minor(struct cdev *x) 379{ 380 if (x == NULL) 381 return NODEV; 382 return(x->si_drv0 & MAXMINOR); 383} 384 385int 386dev2unit(struct cdev *x) 387{ 388 389 if (x == NULL) 390 return NODEV; 391 return (minor2unit(minor(x))); 392} 393 394u_int 395minor2unit(u_int _minor) 396{ 397 398 KASSERT((_minor & ~MAXMINOR) == 0, ("Illegal minor %x", _minor)); 399 return ((_minor & 0xff) | ((_minor >> 8) & 0xffff00)); 400} 401 402int 403unit2minor(int unit) 404{ 405 406 KASSERT(unit <= 0xffffff, ("Invalid unit (%d) in unit2minor", unit)); 407 return ((unit & 0xff) | ((unit << 8) & ~0xffff)); 408} 409 410static struct cdev * 411newdev(struct cdevsw *csw, int y, struct cdev *si) 412{ 413 struct cdev *si2; 414 dev_t udev; 415 416 mtx_assert(&devmtx, MA_OWNED); 417 udev = y; 418 LIST_FOREACH(si2, &csw->d_devs, si_list) { 419 if (si2->si_drv0 == udev) { 420 devfs_free(si); 421 return (si2); 422 } 423 } 424 si->si_drv0 = udev; 425 si->si_devsw = csw; 426 LIST_INSERT_HEAD(&csw->d_devs, si, si_list); 427 return (si); 428} 429 430int 431uminor(dev_t dev) 432{ 433 return (dev & MAXMINOR); 434} 435 436int 437umajor(dev_t dev) 438{ 439 return ((dev & ~MAXMINOR) >> 8); 440} 441 442static void 443fini_cdevsw(struct cdevsw *devsw) 444{ 445 struct cdevsw *gt; 446 447 if (devsw->d_gianttrick != NULL) { 448 gt = devsw->d_gianttrick; 449 memcpy(devsw, gt, sizeof *devsw); 450 free(gt, M_DEVT); 451 devsw->d_gianttrick = NULL; 452 } 453 devsw->d_flags &= ~D_INIT; 454} 455 456static void 457prep_cdevsw(struct cdevsw *devsw) 458{ 459 struct cdevsw *dsw2; 460 461 if (devsw->d_flags & D_NEEDGIANT) 462 dsw2 = malloc(sizeof *dsw2, M_DEVT, M_WAITOK); 463 else 464 dsw2 = NULL; 465 dev_lock(); 466 467 if (devsw->d_version != D_VERSION_01) { 468 printf( 469 "WARNING: Device driver \"%s\" has wrong version %s\n", 470 devsw->d_name == NULL ? "???" : devsw->d_name, 471 "and is disabled. Recompile KLD module."); 472 devsw->d_open = dead_open; 473 devsw->d_close = dead_close; 474 devsw->d_read = dead_read; 475 devsw->d_write = dead_write; 476 devsw->d_ioctl = dead_ioctl; 477 devsw->d_poll = dead_poll; 478 devsw->d_mmap = dead_mmap; 479 devsw->d_strategy = dead_strategy; 480 devsw->d_dump = dead_dump; 481 devsw->d_kqfilter = dead_kqfilter; 482 } 483 484 if (devsw->d_flags & D_TTY) { 485 if (devsw->d_ioctl == NULL) devsw->d_ioctl = ttyioctl; 486 if (devsw->d_read == NULL) devsw->d_read = ttyread; 487 if (devsw->d_write == NULL) devsw->d_write = ttywrite; 488 if (devsw->d_kqfilter == NULL) devsw->d_kqfilter = ttykqfilter; 489 if (devsw->d_poll == NULL) devsw->d_poll = ttypoll; 490 } 491 492 if (devsw->d_flags & D_NEEDGIANT) { 493 if (devsw->d_gianttrick == NULL) { 494 memcpy(dsw2, devsw, sizeof *dsw2); 495 devsw->d_gianttrick = dsw2; 496 } else 497 free(dsw2, M_DEVT); 498 } 499 500#define FIXUP(member, noop, giant) \ 501 do { \ 502 if (devsw->member == NULL) { \ 503 devsw->member = noop; \ 504 } else if (devsw->d_flags & D_NEEDGIANT) \ 505 devsw->member = giant; \ 506 } \ 507 while (0) 508 509 FIXUP(d_open, null_open, giant_open); 510 FIXUP(d_fdopen, NULL, giant_fdopen); 511 FIXUP(d_close, null_close, giant_close); 512 FIXUP(d_read, no_read, giant_read); 513 FIXUP(d_write, no_write, giant_write); 514 FIXUP(d_ioctl, no_ioctl, giant_ioctl); 515 FIXUP(d_poll, no_poll, giant_poll); 516 FIXUP(d_mmap, no_mmap, giant_mmap); 517 FIXUP(d_strategy, no_strategy, giant_strategy); 518 FIXUP(d_kqfilter, no_kqfilter, giant_kqfilter); 519 520 if (devsw->d_dump == NULL) devsw->d_dump = no_dump; 521 522 LIST_INIT(&devsw->d_devs); 523 524 devsw->d_flags |= D_INIT; 525 526 dev_unlock(); 527} 528 529static struct cdev * 530make_dev_credv(struct cdevsw *devsw, int minornr, struct ucred *cr, uid_t uid, 531 gid_t gid, int mode, const char *fmt, va_list ap) 532{ 533 struct cdev *dev; 534 int i; 535 536 KASSERT((minornr & ~MAXMINOR) == 0, 537 ("Invalid minor (0x%x) in make_dev", minornr)); 538 539 if (!(devsw->d_flags & D_INIT)) 540 prep_cdevsw(devsw); 541 dev = devfs_alloc(); 542 dev_lock(); 543 dev = newdev(devsw, minornr, dev); 544 if (dev->si_flags & SI_CHEAPCLONE && 545 dev->si_flags & SI_NAMED) { 546 /* 547 * This is allowed as it removes races and generally 548 * simplifies cloning devices. 549 * XXX: still ?? 550 */ 551 dev_unlock(); 552 return (dev); 553 } 554 KASSERT(!(dev->si_flags & SI_NAMED), 555 ("make_dev() by driver %s on pre-existing device (min=%x, name=%s)", 556 devsw->d_name, minor(dev), devtoname(dev))); 557 558 i = vsnrprintf(dev->__si_namebuf, sizeof dev->__si_namebuf, 32, fmt, ap); 559 if (i > (sizeof dev->__si_namebuf - 1)) { 560 printf("WARNING: Device name truncated! (%s)\n", 561 dev->__si_namebuf); 562 } 563 564 dev->si_flags |= SI_NAMED; 565 if (cr != NULL) 566 dev->si_cred = crhold(cr); 567 else 568 dev->si_cred = NULL; 569 dev->si_uid = uid; 570 dev->si_gid = gid; 571 dev->si_mode = mode; 572 573 devfs_create(dev); 574 dev_unlock(); 575 return (dev); 576} 577 578struct cdev * 579make_dev(struct cdevsw *devsw, int minornr, uid_t uid, gid_t gid, int mode, 580 const char *fmt, ...) 581{ 582 struct cdev *dev; 583 va_list ap; 584 585 va_start(ap, fmt); 586 dev = make_dev_credv(devsw, minornr, NULL, uid, gid, mode, fmt, ap); 587 va_end(ap); 588 return (dev); 589} 590 591struct cdev * 592make_dev_cred(struct cdevsw *devsw, int minornr, struct ucred *cr, uid_t uid, 593 gid_t gid, int mode, const char *fmt, ...) 594{ 595 struct cdev *dev; 596 va_list ap; 597 598 va_start(ap, fmt); 599 dev = make_dev_credv(devsw, minornr, cr, uid, gid, mode, fmt, ap); 600 va_end(ap); 601 602 return (dev); 603} 604 605static void 606dev_dependsl(struct cdev *pdev, struct cdev *cdev) 607{ 608 609 cdev->si_parent = pdev; 610 cdev->si_flags |= SI_CHILD; 611 LIST_INSERT_HEAD(&pdev->si_children, cdev, si_siblings); 612} 613 614 615void 616dev_depends(struct cdev *pdev, struct cdev *cdev) 617{ 618 619 dev_lock(); 620 dev_dependsl(pdev, cdev); 621 dev_unlock(); 622} 623 624struct cdev * 625make_dev_alias(struct cdev *pdev, const char *fmt, ...) 626{ 627 struct cdev *dev; 628 va_list ap; 629 int i; 630 631 dev = devfs_alloc(); 632 dev_lock(); 633 dev->si_flags |= SI_ALIAS; 634 dev->si_flags |= SI_NAMED; 635 va_start(ap, fmt); 636 i = vsnrprintf(dev->__si_namebuf, sizeof dev->__si_namebuf, 32, fmt, ap); 637 if (i > (sizeof dev->__si_namebuf - 1)) { 638 printf("WARNING: Device name truncated! (%s)\n", 639 dev->__si_namebuf); 640 } 641 va_end(ap); 642 643 devfs_create(dev); 644 dev_unlock(); 645 dev_depends(pdev, dev); 646 return (dev); 647} 648 649static void 650destroy_devl(struct cdev *dev) 651{ 652 struct cdevsw *csw; 653 654 mtx_assert(&devmtx, MA_OWNED); 655 KASSERT(dev->si_flags & SI_NAMED, 656 ("WARNING: Driver mistake: destroy_dev on %d\n", minor(dev))); 657 658 devfs_destroy(dev); 659 660 /* Remove name marking */ 661 dev->si_flags &= ~SI_NAMED; 662 663 /* If we are a child, remove us from the parents list */ 664 if (dev->si_flags & SI_CHILD) { 665 LIST_REMOVE(dev, si_siblings); 666 dev->si_flags &= ~SI_CHILD; 667 } 668 669 /* Kill our children */ 670 while (!LIST_EMPTY(&dev->si_children)) 671 destroy_devl(LIST_FIRST(&dev->si_children)); 672 673 /* Remove from clone list */ 674 if (dev->si_flags & SI_CLONELIST) { 675 LIST_REMOVE(dev, si_clone); 676 dev->si_flags &= ~SI_CLONELIST; 677 } 678 679 dev->si_refcount++; /* Avoid race with dev_rel() */ 680 csw = dev->si_devsw; 681 dev->si_devsw = NULL; /* already NULL for SI_ALIAS */ 682 while (csw != NULL && csw->d_purge != NULL && dev->si_threadcount) { 683 csw->d_purge(dev); 684 msleep(csw, &devmtx, PRIBIO, "devprg", hz/10); 685 if (dev->si_threadcount) 686 printf("Still %lu threads in %s\n", 687 dev->si_threadcount, devtoname(dev)); 688 } 689 while (dev->si_threadcount != 0) { 690 /* Use unique dummy wait ident */ 691 msleep(&csw, &devmtx, PRIBIO, "devdrn", hz / 10); 692 } 693 694 dev->si_drv1 = 0; 695 dev->si_drv2 = 0; 696 bzero(&dev->__si_u, sizeof(dev->__si_u)); 697 698 if (!(dev->si_flags & SI_ALIAS)) { 699 /* Remove from cdevsw list */ 700 LIST_REMOVE(dev, si_list); 701 702 /* If cdevsw has no more struct cdev *'s, clean it */ 703 if (LIST_EMPTY(&csw->d_devs)) 704 fini_cdevsw(csw); 705 } 706 dev->si_flags &= ~SI_ALIAS; 707 dev->si_refcount--; /* Avoid race with dev_rel() */ 708 709 if (dev->si_refcount > 0) { 710 LIST_INSERT_HEAD(&dead_cdevsw.d_devs, dev, si_list); 711 } else { 712 devfs_free(dev); 713 } 714} 715 716void 717destroy_dev(struct cdev *dev) 718{ 719 720 dev_lock(); 721 destroy_devl(dev); 722 dev_unlock(); 723} 724 725const char * 726devtoname(struct cdev *dev) 727{ 728 char *p; 729 struct cdevsw *csw; 730 int mynor; 731 732 if (dev->si_name[0] == '#' || dev->si_name[0] == '\0') { 733 p = dev->si_name; 734 csw = dev_refthread(dev); 735 if (csw != NULL) { 736 sprintf(p, "(%s)", csw->d_name); 737 dev_relthread(dev); 738 } 739 p += strlen(p); 740 mynor = minor(dev); 741 if (mynor < 0 || mynor > 255) 742 sprintf(p, "/%#x", (u_int)mynor); 743 else 744 sprintf(p, "/%d", mynor); 745 } 746 return (dev->si_name); 747} 748 749int 750dev_stdclone(char *name, char **namep, const char *stem, int *unit) 751{ 752 int u, i; 753 754 i = strlen(stem); 755 if (bcmp(stem, name, i) != 0) 756 return (0); 757 if (!isdigit(name[i])) 758 return (0); 759 u = 0; 760 if (name[i] == '0' && isdigit(name[i+1])) 761 return (0); 762 while (isdigit(name[i])) { 763 u *= 10; 764 u += name[i++] - '0'; 765 } 766 if (u > 0xffffff) 767 return (0); 768 *unit = u; 769 if (namep) 770 *namep = &name[i]; 771 if (name[i]) 772 return (2); 773 return (1); 774} 775 776/* 777 * Helper functions for cloning device drivers. 778 * 779 * The objective here is to make it unnecessary for the device drivers to 780 * use rman or similar to manage their unit number space. Due to the way 781 * we do "on-demand" devices, using rman or other "private" methods 782 * will be very tricky to lock down properly once we lock down this file. 783 * 784 * Instead we give the drivers these routines which puts the struct cdev *'s 785 * that are to be managed on their own list, and gives the driver the ability 786 * to ask for the first free unit number or a given specified unit number. 787 * 788 * In addition these routines support paired devices (pty, nmdm and similar) 789 * by respecting a number of "flag" bits in the minor number. 790 * 791 */ 792 793struct clonedevs { 794 LIST_HEAD(,cdev) head; 795}; 796 797void 798clone_setup(struct clonedevs **cdp) 799{ 800 801 *cdp = malloc(sizeof **cdp, M_DEVBUF, M_WAITOK | M_ZERO); 802 LIST_INIT(&(*cdp)->head); 803} 804 805int 806clone_create(struct clonedevs **cdp, struct cdevsw *csw, int *up, struct cdev **dp, int extra) 807{ 808 struct clonedevs *cd; 809 struct cdev *dev, *ndev, *dl, *de; 810 int unit, low, u; 811 812 KASSERT(*cdp != NULL, 813 ("clone_setup() not called in driver \"%s\"", csw->d_name)); 814 KASSERT(!(extra & CLONE_UNITMASK), 815 ("Illegal extra bits (0x%x) in clone_create", extra)); 816 KASSERT(*up <= CLONE_UNITMASK, 817 ("Too high unit (0x%x) in clone_create", *up)); 818 819 if (!(csw->d_flags & D_INIT)) 820 prep_cdevsw(csw); 821 822 /* 823 * Search the list for a lot of things in one go: 824 * A preexisting match is returned immediately. 825 * The lowest free unit number if we are passed -1, and the place 826 * in the list where we should insert that new element. 827 * The place to insert a specified unit number, if applicable 828 * the end of the list. 829 */ 830 unit = *up; 831 ndev = devfs_alloc(); 832 dev_lock(); 833 low = extra; 834 de = dl = NULL; 835 cd = *cdp; 836 LIST_FOREACH(dev, &cd->head, si_clone) { 837 KASSERT(dev->si_flags & SI_CLONELIST, 838 ("Dev %p(%s) should be on clonelist", dev, dev->si_name)); 839 u = dev2unit(dev); 840 if (u == (unit | extra)) { 841 *dp = dev; 842 devfs_free(ndev); 843 dev_unlock(); 844 return (0); 845 } 846 if (unit == -1 && u == low) { 847 low++; 848 de = dev; 849 continue; 850 } else if (u < (unit | extra)) { 851 de = dev; 852 continue; 853 } else if (u > (unit | extra)) { 854 dl = dev; 855 break; 856 } 857 } 858 if (unit == -1) 859 unit = low & CLONE_UNITMASK; 860 dev = newdev(csw, unit2minor(unit | extra), ndev); 861 if (dev->si_flags & SI_CLONELIST) { 862 printf("dev %p (%s) is on clonelist\n", dev, dev->si_name); 863 printf("unit=%d, low=%d, extra=0x%x\n", unit, low, extra); 864 LIST_FOREACH(dev, &cd->head, si_clone) { 865 printf("\t%p %s\n", dev, dev->si_name); 866 } 867 panic("foo"); 868 } 869 KASSERT(!(dev->si_flags & SI_CLONELIST), 870 ("Dev %p(%s) should not be on clonelist", dev, dev->si_name)); 871 if (dl != NULL) 872 LIST_INSERT_BEFORE(dl, dev, si_clone); 873 else if (de != NULL) 874 LIST_INSERT_AFTER(de, dev, si_clone); 875 else 876 LIST_INSERT_HEAD(&cd->head, dev, si_clone); 877 dev->si_flags |= SI_CLONELIST; 878 *up = unit; 879 dev_unlock(); 880 return (1); 881} 882 883/* 884 * Kill everything still on the list. The driver should already have 885 * disposed of any softc hung of the struct cdev *'s at this time. 886 */ 887void 888clone_cleanup(struct clonedevs **cdp) 889{ 890 struct cdev *dev, *tdev; 891 struct clonedevs *cd; 892 893 cd = *cdp; 894 if (cd == NULL) 895 return; 896 dev_lock(); 897 LIST_FOREACH_SAFE(dev, &cd->head, si_clone, tdev) { 898 KASSERT(dev->si_flags & SI_CLONELIST, 899 ("Dev %p(%s) should be on clonelist", dev, dev->si_name)); 900 KASSERT(dev->si_flags & SI_NAMED, 901 ("Driver has goofed in cloning underways udev %x", dev->si_drv0)); 902 destroy_devl(dev); 903 } 904 dev_unlock(); 905 free(cd, M_DEVBUF); 906 *cdp = NULL; 907} 908