The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/kern/kern_conf.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

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

Cache object: 5699c7441185067b9236022c141a6808


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.