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$");
   29 
   30 #include <sys/param.h>
   31 #include <sys/kernel.h>
   32 #include <sys/systm.h>
   33 #include <sys/bus.h>
   34 #include <sys/bio.h>
   35 #include <sys/lock.h>
   36 #include <sys/mutex.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/sx.h>
   44 #include <sys/ctype.h>
   45 #include <sys/ucred.h>
   46 #include <sys/taskqueue.h>
   47 #include <machine/stdarg.h>
   48 
   49 #include <fs/devfs/devfs_int.h>
   50 #include <vm/vm.h>
   51 
   52 static MALLOC_DEFINE(M_DEVT, "cdev", "cdev storage");
   53 
   54 struct mtx devmtx;
   55 static void destroy_devl(struct cdev *dev);
   56 static int destroy_dev_sched_cbl(struct cdev *dev,
   57     void (*cb)(void *), void *arg);
   58 static void destroy_dev_tq(void *ctx, int pending);
   59 static int make_dev_credv(int flags, struct cdev **dres, struct cdevsw *devsw,
   60     int unit, struct ucred *cr, uid_t uid, gid_t gid, int mode, const char *fmt,
   61     va_list ap);
   62 
   63 static struct cdev_priv_list cdevp_free_list =
   64     TAILQ_HEAD_INITIALIZER(cdevp_free_list);
   65 static SLIST_HEAD(free_cdevsw, cdevsw) cdevsw_gt_post_list =
   66     SLIST_HEAD_INITIALIZER(cdevsw_gt_post_list);
   67 
   68 void
   69 dev_lock(void)
   70 {
   71 
   72         mtx_lock(&devmtx);
   73 }
   74 
   75 /*
   76  * Free all the memory collected while the cdev mutex was
   77  * locked. Since devmtx is after the system map mutex, free() cannot
   78  * be called immediately and is postponed until cdev mutex can be
   79  * dropped.
   80  */
   81 static void
   82 dev_unlock_and_free(void)
   83 {
   84         struct cdev_priv_list cdp_free;
   85         struct free_cdevsw csw_free;
   86         struct cdev_priv *cdp;
   87         struct cdevsw *csw;
   88 
   89         mtx_assert(&devmtx, MA_OWNED);
   90 
   91         /*
   92          * Make the local copy of the list heads while the dev_mtx is
   93          * held. Free it later.
   94          */
   95         TAILQ_INIT(&cdp_free);
   96         TAILQ_CONCAT(&cdp_free, &cdevp_free_list, cdp_list);
   97         csw_free = cdevsw_gt_post_list;
   98         SLIST_INIT(&cdevsw_gt_post_list);
   99 
  100         mtx_unlock(&devmtx);
  101 
  102         while ((cdp = TAILQ_FIRST(&cdp_free)) != NULL) {
  103                 TAILQ_REMOVE(&cdp_free, cdp, cdp_list);
  104                 devfs_free(&cdp->cdp_c);
  105         }
  106         while ((csw = SLIST_FIRST(&csw_free)) != NULL) {
  107                 SLIST_REMOVE_HEAD(&csw_free, d_postfree_list);
  108                 free(csw, M_DEVT);
  109         }
  110 }
  111 
  112 static void
  113 dev_free_devlocked(struct cdev *cdev)
  114 {
  115         struct cdev_priv *cdp;
  116 
  117         mtx_assert(&devmtx, MA_OWNED);
  118         cdp = cdev2priv(cdev);
  119         KASSERT((cdp->cdp_flags & CDP_UNREF_DTR) == 0,
  120             ("destroy_dev() was not called after delist_dev(%p)", cdev));
  121         TAILQ_INSERT_HEAD(&cdevp_free_list, cdp, cdp_list);
  122 }
  123 
  124 static void
  125 cdevsw_free_devlocked(struct cdevsw *csw)
  126 {
  127 
  128         mtx_assert(&devmtx, MA_OWNED);
  129         SLIST_INSERT_HEAD(&cdevsw_gt_post_list, csw, d_postfree_list);
  130 }
  131 
  132 void
  133 dev_unlock(void)
  134 {
  135 
  136         mtx_unlock(&devmtx);
  137 }
  138 
  139 void
  140 dev_ref(struct cdev *dev)
  141 {
  142 
  143         mtx_assert(&devmtx, MA_NOTOWNED);
  144         mtx_lock(&devmtx);
  145         dev->si_refcount++;
  146         mtx_unlock(&devmtx);
  147 }
  148 
  149 void
  150 dev_refl(struct cdev *dev)
  151 {
  152 
  153         mtx_assert(&devmtx, MA_OWNED);
  154         dev->si_refcount++;
  155 }
  156 
  157 void
  158 dev_rel(struct cdev *dev)
  159 {
  160         int flag = 0;
  161 
  162         mtx_assert(&devmtx, MA_NOTOWNED);
  163         dev_lock();
  164         dev->si_refcount--;
  165         KASSERT(dev->si_refcount >= 0,
  166             ("dev_rel(%s) gave negative count", devtoname(dev)));
  167         if (dev->si_devsw == NULL && dev->si_refcount == 0) {
  168                 LIST_REMOVE(dev, si_list);
  169                 flag = 1;
  170         }
  171         dev_unlock();
  172         if (flag)
  173                 devfs_free(dev);
  174 }
  175 
  176 struct cdevsw *
  177 dev_refthread(struct cdev *dev, int *ref)
  178 {
  179         struct cdevsw *csw;
  180         struct cdev_priv *cdp;
  181 
  182         mtx_assert(&devmtx, MA_NOTOWNED);
  183         if ((dev->si_flags & SI_ETERNAL) != 0) {
  184                 *ref = 0;
  185                 return (dev->si_devsw);
  186         }
  187         dev_lock();
  188         csw = dev->si_devsw;
  189         if (csw != NULL) {
  190                 cdp = cdev2priv(dev);
  191                 if ((cdp->cdp_flags & CDP_SCHED_DTR) == 0)
  192                         atomic_add_long(&dev->si_threadcount, 1);
  193                 else
  194                         csw = NULL;
  195         }
  196         dev_unlock();
  197         *ref = 1;
  198         return (csw);
  199 }
  200 
  201 struct cdevsw *
  202 devvn_refthread(struct vnode *vp, struct cdev **devp, int *ref)
  203 {
  204         struct cdevsw *csw;
  205         struct cdev_priv *cdp;
  206         struct cdev *dev;
  207 
  208         mtx_assert(&devmtx, MA_NOTOWNED);
  209         if ((vp->v_vflag & VV_ETERNALDEV) != 0) {
  210                 dev = vp->v_rdev;
  211                 if (dev == NULL)
  212                         return (NULL);
  213                 KASSERT((dev->si_flags & SI_ETERNAL) != 0,
  214                     ("Not eternal cdev"));
  215                 *ref = 0;
  216                 csw = dev->si_devsw;
  217                 KASSERT(csw != NULL, ("Eternal cdev is destroyed"));
  218                 *devp = dev;
  219                 return (csw);
  220         }
  221 
  222         csw = NULL;
  223         dev_lock();
  224         dev = vp->v_rdev;
  225         if (dev == NULL) {
  226                 dev_unlock();
  227                 return (NULL);
  228         }
  229         cdp = cdev2priv(dev);
  230         if ((cdp->cdp_flags & CDP_SCHED_DTR) == 0) {
  231                 csw = dev->si_devsw;
  232                 if (csw != NULL)
  233                         atomic_add_long(&dev->si_threadcount, 1);
  234         }
  235         dev_unlock();
  236         if (csw != NULL) {
  237                 *devp = dev;
  238                 *ref = 1;
  239         }
  240         return (csw);
  241 }
  242 
  243 void    
  244 dev_relthread(struct cdev *dev, int ref)
  245 {
  246 
  247         mtx_assert(&devmtx, MA_NOTOWNED);
  248         if (!ref)
  249                 return;
  250         KASSERT(dev->si_threadcount > 0,
  251             ("%s threadcount is wrong", dev->si_name));
  252         atomic_subtract_rel_long(&dev->si_threadcount, 1);
  253 }
  254 
  255 int
  256 nullop(void)
  257 {
  258 
  259         return (0);
  260 }
  261 
  262 int
  263 eopnotsupp(void)
  264 {
  265 
  266         return (EOPNOTSUPP);
  267 }
  268 
  269 static int
  270 enxio(void)
  271 {
  272         return (ENXIO);
  273 }
  274 
  275 static int
  276 enodev(void)
  277 {
  278         return (ENODEV);
  279 }
  280 
  281 /* Define a dead_cdevsw for use when devices leave unexpectedly. */
  282 
  283 #define dead_open       (d_open_t *)enxio
  284 #define dead_close      (d_close_t *)enxio
  285 #define dead_read       (d_read_t *)enxio
  286 #define dead_write      (d_write_t *)enxio
  287 #define dead_ioctl      (d_ioctl_t *)enxio
  288 #define dead_poll       (d_poll_t *)enodev
  289 #define dead_mmap       (d_mmap_t *)enodev
  290 
  291 static void
  292 dead_strategy(struct bio *bp)
  293 {
  294 
  295         biofinish(bp, NULL, ENXIO);
  296 }
  297 
  298 #define dead_dump       (dumper_t *)enxio
  299 #define dead_kqfilter   (d_kqfilter_t *)enxio
  300 #define dead_mmap_single (d_mmap_single_t *)enodev
  301 
  302 static struct cdevsw dead_cdevsw = {
  303         .d_version =    D_VERSION,
  304         .d_open =       dead_open,
  305         .d_close =      dead_close,
  306         .d_read =       dead_read,
  307         .d_write =      dead_write,
  308         .d_ioctl =      dead_ioctl,
  309         .d_poll =       dead_poll,
  310         .d_mmap =       dead_mmap,
  311         .d_strategy =   dead_strategy,
  312         .d_name =       "dead",
  313         .d_dump =       dead_dump,
  314         .d_kqfilter =   dead_kqfilter,
  315         .d_mmap_single = dead_mmap_single
  316 };
  317 
  318 /* Default methods if driver does not specify method */
  319 
  320 #define null_open       (d_open_t *)nullop
  321 #define null_close      (d_close_t *)nullop
  322 #define no_read         (d_read_t *)enodev
  323 #define no_write        (d_write_t *)enodev
  324 #define no_ioctl        (d_ioctl_t *)enodev
  325 #define no_mmap         (d_mmap_t *)enodev
  326 #define no_kqfilter     (d_kqfilter_t *)enodev
  327 #define no_mmap_single  (d_mmap_single_t *)enodev
  328 
  329 static void
  330 no_strategy(struct bio *bp)
  331 {
  332 
  333         biofinish(bp, NULL, ENODEV);
  334 }
  335 
  336 static int
  337 no_poll(struct cdev *dev __unused, int events, struct thread *td __unused)
  338 {
  339 
  340         return (poll_no_poll(events));
  341 }
  342 
  343 #define no_dump         (dumper_t *)enodev
  344 
  345 static int
  346 giant_open(struct cdev *dev, int oflags, int devtype, struct thread *td)
  347 {
  348         struct cdevsw *dsw;
  349         int ref, retval;
  350 
  351         dsw = dev_refthread(dev, &ref);
  352         if (dsw == NULL)
  353                 return (ENXIO);
  354         mtx_lock(&Giant);
  355         retval = dsw->d_gianttrick->d_open(dev, oflags, devtype, td);
  356         mtx_unlock(&Giant);
  357         dev_relthread(dev, ref);
  358         return (retval);
  359 }
  360 
  361 static int
  362 giant_fdopen(struct cdev *dev, int oflags, struct thread *td, struct file *fp)
  363 {
  364         struct cdevsw *dsw;
  365         int ref, retval;
  366 
  367         dsw = dev_refthread(dev, &ref);
  368         if (dsw == NULL)
  369                 return (ENXIO);
  370         mtx_lock(&Giant);
  371         retval = dsw->d_gianttrick->d_fdopen(dev, oflags, td, fp);
  372         mtx_unlock(&Giant);
  373         dev_relthread(dev, ref);
  374         return (retval);
  375 }
  376 
  377 static int
  378 giant_close(struct cdev *dev, int fflag, int devtype, struct thread *td)
  379 {
  380         struct cdevsw *dsw;
  381         int ref, retval;
  382 
  383         dsw = dev_refthread(dev, &ref);
  384         if (dsw == NULL)
  385                 return (ENXIO);
  386         mtx_lock(&Giant);
  387         retval = dsw->d_gianttrick->d_close(dev, fflag, devtype, td);
  388         mtx_unlock(&Giant);
  389         dev_relthread(dev, ref);
  390         return (retval);
  391 }
  392 
  393 static void
  394 giant_strategy(struct bio *bp)
  395 {
  396         struct cdevsw *dsw;
  397         struct cdev *dev;
  398         int ref;
  399 
  400         dev = bp->bio_dev;
  401         dsw = dev_refthread(dev, &ref);
  402         if (dsw == NULL) {
  403                 biofinish(bp, NULL, ENXIO);
  404                 return;
  405         }
  406         mtx_lock(&Giant);
  407         dsw->d_gianttrick->d_strategy(bp);
  408         mtx_unlock(&Giant);
  409         dev_relthread(dev, ref);
  410 }
  411 
  412 static int
  413 giant_ioctl(struct cdev *dev, u_long cmd, caddr_t data, int fflag, struct thread *td)
  414 {
  415         struct cdevsw *dsw;
  416         int ref, retval;
  417 
  418         dsw = dev_refthread(dev, &ref);
  419         if (dsw == NULL)
  420                 return (ENXIO);
  421         mtx_lock(&Giant);
  422         retval = dsw->d_gianttrick->d_ioctl(dev, cmd, data, fflag, td);
  423         mtx_unlock(&Giant);
  424         dev_relthread(dev, ref);
  425         return (retval);
  426 }
  427   
  428 static int
  429 giant_read(struct cdev *dev, struct uio *uio, int ioflag)
  430 {
  431         struct cdevsw *dsw;
  432         int ref, retval;
  433 
  434         dsw = dev_refthread(dev, &ref);
  435         if (dsw == NULL)
  436                 return (ENXIO);
  437         mtx_lock(&Giant);
  438         retval = dsw->d_gianttrick->d_read(dev, uio, ioflag);
  439         mtx_unlock(&Giant);
  440         dev_relthread(dev, ref);
  441         return (retval);
  442 }
  443 
  444 static int
  445 giant_write(struct cdev *dev, struct uio *uio, int ioflag)
  446 {
  447         struct cdevsw *dsw;
  448         int ref, retval;
  449 
  450         dsw = dev_refthread(dev, &ref);
  451         if (dsw == NULL)
  452                 return (ENXIO);
  453         mtx_lock(&Giant);
  454         retval = dsw->d_gianttrick->d_write(dev, uio, ioflag);
  455         mtx_unlock(&Giant);
  456         dev_relthread(dev, ref);
  457         return (retval);
  458 }
  459 
  460 static int
  461 giant_poll(struct cdev *dev, int events, struct thread *td)
  462 {
  463         struct cdevsw *dsw;
  464         int ref, retval;
  465 
  466         dsw = dev_refthread(dev, &ref);
  467         if (dsw == NULL)
  468                 return (ENXIO);
  469         mtx_lock(&Giant);
  470         retval = dsw->d_gianttrick->d_poll(dev, events, td);
  471         mtx_unlock(&Giant);
  472         dev_relthread(dev, ref);
  473         return (retval);
  474 }
  475 
  476 static int
  477 giant_kqfilter(struct cdev *dev, struct knote *kn)
  478 {
  479         struct cdevsw *dsw;
  480         int ref, retval;
  481 
  482         dsw = dev_refthread(dev, &ref);
  483         if (dsw == NULL)
  484                 return (ENXIO);
  485         mtx_lock(&Giant);
  486         retval = dsw->d_gianttrick->d_kqfilter(dev, kn);
  487         mtx_unlock(&Giant);
  488         dev_relthread(dev, ref);
  489         return (retval);
  490 }
  491 
  492 static int
  493 giant_mmap(struct cdev *dev, vm_ooffset_t offset, vm_paddr_t *paddr, int nprot,
  494     vm_memattr_t *memattr)
  495 {
  496         struct cdevsw *dsw;
  497         int ref, retval;
  498 
  499         dsw = dev_refthread(dev, &ref);
  500         if (dsw == NULL)
  501                 return (ENXIO);
  502         mtx_lock(&Giant);
  503         retval = dsw->d_gianttrick->d_mmap(dev, offset, paddr, nprot,
  504             memattr);
  505         mtx_unlock(&Giant);
  506         dev_relthread(dev, ref);
  507         return (retval);
  508 }
  509 
  510 static int
  511 giant_mmap_single(struct cdev *dev, vm_ooffset_t *offset, vm_size_t size,
  512     vm_object_t *object, int nprot)
  513 {
  514         struct cdevsw *dsw;
  515         int ref, retval;
  516 
  517         dsw = dev_refthread(dev, &ref);
  518         if (dsw == NULL)
  519                 return (ENXIO);
  520         mtx_lock(&Giant);
  521         retval = dsw->d_gianttrick->d_mmap_single(dev, offset, size, object,
  522             nprot);
  523         mtx_unlock(&Giant);
  524         dev_relthread(dev, ref);
  525         return (retval);
  526 }
  527 
  528 static void
  529 notify(struct cdev *dev, const char *ev, int flags)
  530 {
  531         static const char prefix[] = "cdev=";
  532         char *data;
  533         int namelen, mflags;
  534 
  535         if (cold)
  536                 return;
  537         mflags = (flags & MAKEDEV_NOWAIT) ? M_NOWAIT : M_WAITOK;
  538         namelen = strlen(dev->si_name);
  539         data = malloc(namelen + sizeof(prefix), M_TEMP, mflags);
  540         if (data == NULL)
  541                 return;
  542         memcpy(data, prefix, sizeof(prefix) - 1);
  543         memcpy(data + sizeof(prefix) - 1, dev->si_name, namelen + 1);
  544         devctl_notify_f("DEVFS", "CDEV", ev, data, mflags);
  545         free(data, M_TEMP);
  546 }
  547 
  548 static void
  549 notify_create(struct cdev *dev, int flags)
  550 {
  551 
  552         notify(dev, "CREATE", flags);
  553 }
  554 
  555 static void
  556 notify_destroy(struct cdev *dev)
  557 {
  558 
  559         notify(dev, "DESTROY", MAKEDEV_WAITOK);
  560 }
  561 
  562 static struct cdev *
  563 newdev(struct make_dev_args *args, struct cdev *si)
  564 {
  565         struct cdev *si2;
  566         struct cdevsw *csw;
  567 
  568         mtx_assert(&devmtx, MA_OWNED);
  569         csw = args->mda_devsw;
  570         si2 = NULL;
  571         if (csw->d_flags & D_NEEDMINOR) {
  572                 /* We may want to return an existing device */
  573                 LIST_FOREACH(si2, &csw->d_devs, si_list) {
  574                         if (dev2unit(si2) == args->mda_unit) {
  575                                 dev_free_devlocked(si);
  576                                 si = si2;
  577                                 break;
  578                         }
  579                 }
  580 
  581                 /*
  582                  * If we're returning an existing device, we should make sure
  583                  * it isn't already initialized.  This would have been caught
  584                  * in consumers anyways, but it's good to catch such a case
  585                  * early.  We still need to complete initialization of the
  586                  * device, and we'll use whatever make_dev_args were passed in
  587                  * to do so.
  588                  */
  589                 KASSERT(si2 == NULL || (si2->si_flags & SI_NAMED) == 0,
  590                     ("make_dev() by driver %s on pre-existing device (min=%x, name=%s)",
  591                     args->mda_devsw->d_name, dev2unit(si2), devtoname(si2)));
  592         }
  593         si->si_drv0 = args->mda_unit;
  594         si->si_drv1 = args->mda_si_drv1;
  595         si->si_drv2 = args->mda_si_drv2;
  596         /* Only push to csw->d_devs if it's not a cloned device. */
  597         if (si2 == NULL) {
  598                 si->si_devsw = csw;
  599                 LIST_INSERT_HEAD(&csw->d_devs, si, si_list);
  600         } else {
  601                 KASSERT(si->si_devsw == csw,
  602                     ("%s: inconsistent devsw between clone_create() and make_dev()",
  603                     __func__));
  604         }
  605         return (si);
  606 }
  607 
  608 static void
  609 fini_cdevsw(struct cdevsw *devsw)
  610 {
  611         struct cdevsw *gt;
  612 
  613         if (devsw->d_gianttrick != NULL) {
  614                 gt = devsw->d_gianttrick;
  615                 memcpy(devsw, gt, sizeof *devsw);
  616                 cdevsw_free_devlocked(gt);
  617                 devsw->d_gianttrick = NULL;
  618         }
  619         devsw->d_flags &= ~D_INIT;
  620 }
  621 
  622 static int
  623 prep_cdevsw(struct cdevsw *devsw, int flags)
  624 {
  625         struct cdevsw *dsw2;
  626 
  627         mtx_assert(&devmtx, MA_OWNED);
  628         if (devsw->d_flags & D_INIT)
  629                 return (0);
  630         if (devsw->d_flags & D_NEEDGIANT) {
  631                 dev_unlock();
  632                 dsw2 = malloc(sizeof *dsw2, M_DEVT,
  633                      (flags & MAKEDEV_NOWAIT) ? M_NOWAIT : M_WAITOK);
  634                 dev_lock();
  635                 if (dsw2 == NULL && !(devsw->d_flags & D_INIT))
  636                         return (ENOMEM);
  637         } else
  638                 dsw2 = NULL;
  639         if (devsw->d_flags & D_INIT) {
  640                 if (dsw2 != NULL)
  641                         cdevsw_free_devlocked(dsw2);
  642                 return (0);
  643         }
  644 
  645         if (devsw->d_version != D_VERSION_03) {
  646                 printf(
  647                     "WARNING: Device driver \"%s\" has wrong version %s\n",
  648                     devsw->d_name == NULL ? "???" : devsw->d_name,
  649                     "and is disabled.  Recompile KLD module.");
  650                 devsw->d_open = dead_open;
  651                 devsw->d_close = dead_close;
  652                 devsw->d_read = dead_read;
  653                 devsw->d_write = dead_write;
  654                 devsw->d_ioctl = dead_ioctl;
  655                 devsw->d_poll = dead_poll;
  656                 devsw->d_mmap = dead_mmap;
  657                 devsw->d_mmap_single = dead_mmap_single;
  658                 devsw->d_strategy = dead_strategy;
  659                 devsw->d_dump = dead_dump;
  660                 devsw->d_kqfilter = dead_kqfilter;
  661         }
  662         
  663         if (devsw->d_flags & D_NEEDGIANT) {
  664                 if (devsw->d_gianttrick == NULL) {
  665                         memcpy(dsw2, devsw, sizeof *dsw2);
  666                         devsw->d_gianttrick = dsw2;
  667                         dsw2 = NULL;
  668                 }
  669         }
  670 
  671 #define FIXUP(member, noop, giant)                              \
  672         do {                                                    \
  673                 if (devsw->member == NULL) {                    \
  674                         devsw->member = noop;                   \
  675                 } else if (devsw->d_flags & D_NEEDGIANT)        \
  676                         devsw->member = giant;                  \
  677                 }                                               \
  678         while (0)
  679 
  680         FIXUP(d_open,           null_open,      giant_open);
  681         FIXUP(d_fdopen,         NULL,           giant_fdopen);
  682         FIXUP(d_close,          null_close,     giant_close);
  683         FIXUP(d_read,           no_read,        giant_read);
  684         FIXUP(d_write,          no_write,       giant_write);
  685         FIXUP(d_ioctl,          no_ioctl,       giant_ioctl);
  686         FIXUP(d_poll,           no_poll,        giant_poll);
  687         FIXUP(d_mmap,           no_mmap,        giant_mmap);
  688         FIXUP(d_strategy,       no_strategy,    giant_strategy);
  689         FIXUP(d_kqfilter,       no_kqfilter,    giant_kqfilter);
  690         FIXUP(d_mmap_single,    no_mmap_single, giant_mmap_single);
  691 
  692         if (devsw->d_dump == NULL)      devsw->d_dump = no_dump;
  693 
  694         LIST_INIT(&devsw->d_devs);
  695 
  696         devsw->d_flags |= D_INIT;
  697 
  698         if (dsw2 != NULL)
  699                 cdevsw_free_devlocked(dsw2);
  700         return (0);
  701 }
  702 
  703 static int
  704 prep_devname(struct cdev *dev, const char *fmt, va_list ap)
  705 {
  706         int len;
  707         char *from, *q, *s, *to;
  708 
  709         mtx_assert(&devmtx, MA_OWNED);
  710 
  711         len = vsnrprintf(dev->si_name, sizeof(dev->si_name), 32, fmt, ap);
  712         if (len > sizeof(dev->si_name) - 1)
  713                 return (ENAMETOOLONG);
  714 
  715         /* Strip leading slashes. */
  716         for (from = dev->si_name; *from == '/'; from++)
  717                 ;
  718 
  719         for (to = dev->si_name; *from != '\0'; from++, to++) {
  720                 /*
  721                  * Spaces and double quotation marks cause
  722                  * problems for the devctl(4) protocol.
  723                  * Reject names containing those characters.
  724                  */
  725                 if (isspace(*from) || *from == '"')
  726                         return (EINVAL);
  727                 /* Treat multiple sequential slashes as single. */
  728                 while (from[0] == '/' && from[1] == '/')
  729                         from++;
  730                 /* Trailing slash is considered invalid. */
  731                 if (from[0] == '/' && from[1] == '\0')
  732                         return (EINVAL);
  733                 *to = *from;
  734         }
  735         *to = '\0';
  736 
  737         if (dev->si_name[0] == '\0')
  738                 return (EINVAL);
  739 
  740         /* Disallow "." and ".." components. */
  741         for (s = dev->si_name;;) {
  742                 for (q = s; *q != '/' && *q != '\0'; q++)
  743                         ;
  744                 if (q - s == 1 && s[0] == '.')
  745                         return (EINVAL);
  746                 if (q - s == 2 && s[0] == '.' && s[1] == '.')
  747                         return (EINVAL);
  748                 if (*q != '/')
  749                         break;
  750                 s = q + 1;
  751         }
  752 
  753         if (devfs_dev_exists(dev->si_name) != 0)
  754                 return (EEXIST);
  755 
  756         return (0);
  757 }
  758 
  759 void
  760 make_dev_args_init_impl(struct make_dev_args *args, size_t sz)
  761 {
  762 
  763         bzero(args, sz);
  764         args->mda_size = sz;
  765 }
  766 
  767 static int
  768 make_dev_sv(struct make_dev_args *args1, struct cdev **dres,
  769     const char *fmt, va_list ap)
  770 {
  771         struct cdev *dev, *dev_new;
  772         struct make_dev_args args;
  773         int res;
  774 
  775         bzero(&args, sizeof(args));
  776         if (sizeof(args) < args1->mda_size)
  777                 return (EINVAL);
  778         bcopy(args1, &args, args1->mda_size);
  779         KASSERT((args.mda_flags & MAKEDEV_WAITOK) == 0 ||
  780             (args.mda_flags & MAKEDEV_NOWAIT) == 0,
  781             ("make_dev_sv: both WAITOK and NOWAIT specified"));
  782         dev_new = devfs_alloc(args.mda_flags);
  783         if (dev_new == NULL)
  784                 return (ENOMEM);
  785         dev_lock();
  786         res = prep_cdevsw(args.mda_devsw, args.mda_flags);
  787         if (res != 0) {
  788                 dev_unlock();
  789                 devfs_free(dev_new);
  790                 return (res);
  791         }
  792         dev = newdev(&args, dev_new);
  793         if ((dev->si_flags & SI_NAMED) == 0) {
  794                 res = prep_devname(dev, fmt, ap);
  795                 if (res != 0) {
  796                         if ((args.mda_flags & MAKEDEV_CHECKNAME) == 0) {
  797                                 panic(
  798                         "make_dev_sv: bad si_name (error=%d, si_name=%s)",
  799                                     res, dev->si_name);
  800                         }
  801                         if (dev == dev_new) {
  802                                 LIST_REMOVE(dev, si_list);
  803                                 dev_unlock();
  804                                 devfs_free(dev);
  805                         } else
  806                                 dev_unlock();
  807                         return (res);
  808                 }
  809         }
  810         if ((args.mda_flags & MAKEDEV_REF) != 0)
  811                 dev_refl(dev);
  812         if ((args.mda_flags & MAKEDEV_ETERNAL) != 0)
  813                 dev->si_flags |= SI_ETERNAL;
  814         KASSERT(!(dev->si_flags & SI_NAMED),
  815             ("make_dev() by driver %s on pre-existing device (min=%x, name=%s)",
  816             args.mda_devsw->d_name, dev2unit(dev), devtoname(dev)));
  817         dev->si_flags |= SI_NAMED;
  818         if (args.mda_cr != NULL)
  819                 dev->si_cred = crhold(args.mda_cr);
  820         dev->si_uid = args.mda_uid;
  821         dev->si_gid = args.mda_gid;
  822         dev->si_mode = args.mda_mode;
  823 
  824         devfs_create(dev);
  825         clean_unrhdrl(devfs_inos);
  826         dev_unlock_and_free();
  827 
  828         notify_create(dev, args.mda_flags);
  829 
  830         *dres = dev;
  831         return (0);
  832 }
  833 
  834 int
  835 make_dev_s(struct make_dev_args *args, struct cdev **dres,
  836     const char *fmt, ...)
  837 {
  838         va_list ap;
  839         int res;
  840 
  841         va_start(ap, fmt);
  842         res = make_dev_sv(args, dres, fmt, ap);
  843         va_end(ap);
  844         return (res);
  845 }
  846 
  847 static int
  848 make_dev_credv(int flags, struct cdev **dres, struct cdevsw *devsw, int unit,
  849     struct ucred *cr, uid_t uid, gid_t gid, int mode, const char *fmt,
  850     va_list ap)
  851 {
  852         struct make_dev_args args;
  853 
  854         make_dev_args_init(&args);
  855         args.mda_flags = flags;
  856         args.mda_devsw = devsw;
  857         args.mda_cr = cr;
  858         args.mda_uid = uid;
  859         args.mda_gid = gid;
  860         args.mda_mode = mode;
  861         args.mda_unit = unit;
  862         return (make_dev_sv(&args, dres, fmt, ap));
  863 }
  864 
  865 struct cdev *
  866 make_dev(struct cdevsw *devsw, int unit, uid_t uid, gid_t gid, int mode,
  867     const char *fmt, ...)
  868 {
  869         struct cdev *dev;
  870         va_list ap;
  871         int res;
  872 
  873         va_start(ap, fmt);
  874         res = make_dev_credv(0, &dev, devsw, unit, NULL, uid, gid, mode, fmt,
  875             ap);
  876         va_end(ap);
  877         KASSERT(res == 0 && dev != NULL,
  878             ("make_dev: failed make_dev_credv (error=%d)", res));
  879         return (dev);
  880 }
  881 
  882 struct cdev *
  883 make_dev_cred(struct cdevsw *devsw, int unit, struct ucred *cr, uid_t uid,
  884     gid_t gid, int mode, const char *fmt, ...)
  885 {
  886         struct cdev *dev;
  887         va_list ap;
  888         int res;
  889 
  890         va_start(ap, fmt);
  891         res = make_dev_credv(0, &dev, devsw, unit, cr, uid, gid, mode, fmt, ap);
  892         va_end(ap);
  893 
  894         KASSERT(res == 0 && dev != NULL,
  895             ("make_dev_cred: failed make_dev_credv (error=%d)", res));
  896         return (dev);
  897 }
  898 
  899 struct cdev *
  900 make_dev_credf(int flags, struct cdevsw *devsw, int unit, struct ucred *cr,
  901     uid_t uid, gid_t gid, int mode, const char *fmt, ...)
  902 {
  903         struct cdev *dev;
  904         va_list ap;
  905         int res;
  906 
  907         va_start(ap, fmt);
  908         res = make_dev_credv(flags, &dev, devsw, unit, cr, uid, gid, mode,
  909             fmt, ap);
  910         va_end(ap);
  911 
  912         KASSERT(((flags & MAKEDEV_NOWAIT) != 0 && res == ENOMEM) ||
  913             ((flags & MAKEDEV_CHECKNAME) != 0 && res != ENOMEM) || res == 0,
  914             ("make_dev_credf: failed make_dev_credv (error=%d)", res));
  915         return (res == 0 ? dev : NULL);
  916 }
  917 
  918 int
  919 make_dev_p(int flags, struct cdev **cdev, struct cdevsw *devsw,
  920     struct ucred *cr, uid_t uid, gid_t gid, int mode, const char *fmt, ...)
  921 {
  922         va_list ap;
  923         int res;
  924 
  925         va_start(ap, fmt);
  926         res = make_dev_credv(flags, cdev, devsw, 0, cr, uid, gid, mode,
  927             fmt, ap);
  928         va_end(ap);
  929 
  930         KASSERT(((flags & MAKEDEV_NOWAIT) != 0 && res == ENOMEM) ||
  931             ((flags & MAKEDEV_CHECKNAME) != 0 && res != ENOMEM) || res == 0,
  932             ("make_dev_p: failed make_dev_credv (error=%d)", res));
  933         return (res);
  934 }
  935 
  936 static void
  937 dev_dependsl(struct cdev *pdev, struct cdev *cdev)
  938 {
  939 
  940         cdev->si_parent = pdev;
  941         cdev->si_flags |= SI_CHILD;
  942         LIST_INSERT_HEAD(&pdev->si_children, cdev, si_siblings);
  943 }
  944 
  945 
  946 void
  947 dev_depends(struct cdev *pdev, struct cdev *cdev)
  948 {
  949 
  950         dev_lock();
  951         dev_dependsl(pdev, cdev);
  952         dev_unlock();
  953 }
  954 
  955 static int
  956 make_dev_alias_v(int flags, struct cdev **cdev, struct cdev *pdev,
  957     const char *fmt, va_list ap)
  958 {
  959         struct cdev *dev;
  960         int error;
  961 
  962         KASSERT(pdev != NULL, ("make_dev_alias_v: pdev is NULL"));
  963         KASSERT((flags & MAKEDEV_WAITOK) == 0 || (flags & MAKEDEV_NOWAIT) == 0,
  964             ("make_dev_alias_v: both WAITOK and NOWAIT specified"));
  965         KASSERT((flags & ~(MAKEDEV_WAITOK | MAKEDEV_NOWAIT |
  966             MAKEDEV_CHECKNAME)) == 0,
  967             ("make_dev_alias_v: invalid flags specified (flags=%02x)", flags));
  968 
  969         dev = devfs_alloc(flags);
  970         if (dev == NULL)
  971                 return (ENOMEM);
  972         dev_lock();
  973         dev->si_flags |= SI_ALIAS;
  974         error = prep_devname(dev, fmt, ap);
  975         if (error != 0) {
  976                 if ((flags & MAKEDEV_CHECKNAME) == 0) {
  977                         panic("make_dev_alias_v: bad si_name "
  978                             "(error=%d, si_name=%s)", error, dev->si_name);
  979                 }
  980                 dev_unlock();
  981                 devfs_free(dev);
  982                 return (error);
  983         }
  984         dev->si_flags |= SI_NAMED;
  985         devfs_create(dev);
  986         dev_dependsl(pdev, dev);
  987         clean_unrhdrl(devfs_inos);
  988         dev_unlock();
  989 
  990         notify_create(dev, flags);
  991         *cdev = dev;
  992 
  993         return (0);
  994 }
  995 
  996 struct cdev *
  997 make_dev_alias(struct cdev *pdev, const char *fmt, ...)
  998 {
  999         struct cdev *dev;
 1000         va_list ap;
 1001         int res;
 1002 
 1003         va_start(ap, fmt);
 1004         res = make_dev_alias_v(MAKEDEV_WAITOK, &dev, pdev, fmt, ap);
 1005         va_end(ap);
 1006 
 1007         KASSERT(res == 0 && dev != NULL,
 1008             ("make_dev_alias: failed make_dev_alias_v (error=%d)", res));
 1009         return (dev);
 1010 }
 1011 
 1012 int
 1013 make_dev_alias_p(int flags, struct cdev **cdev, struct cdev *pdev,
 1014     const char *fmt, ...)
 1015 {
 1016         va_list ap;
 1017         int res;
 1018 
 1019         va_start(ap, fmt);
 1020         res = make_dev_alias_v(flags, cdev, pdev, fmt, ap);
 1021         va_end(ap);
 1022         return (res);
 1023 }
 1024 
 1025 int
 1026 make_dev_physpath_alias(int flags, struct cdev **cdev, struct cdev *pdev, 
 1027     struct cdev *old_alias, const char *physpath)
 1028 {
 1029         char *devfspath;
 1030         int physpath_len;
 1031         int max_parentpath_len;
 1032         int parentpath_len;
 1033         int devfspathbuf_len;
 1034         int mflags;
 1035         int ret;
 1036 
 1037         *cdev = NULL;
 1038         devfspath = NULL;
 1039         physpath_len = strlen(physpath);
 1040         ret = EINVAL;
 1041         if (physpath_len == 0)
 1042                 goto out;
 1043 
 1044         if (strncmp("id1,", physpath, 4) == 0) {
 1045                 physpath += 4;
 1046                 physpath_len -= 4;
 1047                 if (physpath_len == 0)
 1048                         goto out;
 1049         }
 1050 
 1051         max_parentpath_len = SPECNAMELEN - physpath_len - /*/*/1;
 1052         parentpath_len = strlen(pdev->si_name);
 1053         if (max_parentpath_len < parentpath_len) {
 1054                 if (bootverbose)
 1055                         printf("WARNING: Unable to alias %s "
 1056                             "to %s/%s - path too long\n",
 1057                             pdev->si_name, physpath, pdev->si_name);
 1058                 ret = ENAMETOOLONG;
 1059                 goto out;
 1060         }
 1061 
 1062         mflags = (flags & MAKEDEV_NOWAIT) ? M_NOWAIT : M_WAITOK;
 1063         devfspathbuf_len = physpath_len + /*/*/1 + parentpath_len + /*NUL*/1;
 1064         devfspath = malloc(devfspathbuf_len, M_DEVBUF, mflags);
 1065         if (devfspath == NULL) {
 1066                 ret = ENOMEM;
 1067                 goto out;
 1068         }
 1069 
 1070         sprintf(devfspath, "%s/%s", physpath, pdev->si_name);
 1071         if (old_alias != NULL && strcmp(old_alias->si_name, devfspath) == 0) {
 1072                 /* Retain the existing alias. */
 1073                 *cdev = old_alias;
 1074                 old_alias = NULL;
 1075                 ret = 0;
 1076         } else {
 1077                 ret = make_dev_alias_p(flags, cdev, pdev, "%s", devfspath);
 1078         }
 1079 out:
 1080         if (old_alias != NULL)  
 1081                 destroy_dev(old_alias);
 1082         if (devfspath != NULL)
 1083                 free(devfspath, M_DEVBUF);
 1084         return (ret);
 1085 }
 1086 
 1087 static void
 1088 destroy_devl(struct cdev *dev)
 1089 {
 1090         struct cdevsw *csw;
 1091         struct cdev_privdata *p;
 1092         struct cdev_priv *cdp;
 1093 
 1094         mtx_assert(&devmtx, MA_OWNED);
 1095         KASSERT(dev->si_flags & SI_NAMED,
 1096             ("WARNING: Driver mistake: destroy_dev on %d\n", dev2unit(dev)));
 1097         KASSERT((dev->si_flags & SI_ETERNAL) == 0,
 1098             ("WARNING: Driver mistake: destroy_dev on eternal %d\n",
 1099              dev2unit(dev)));
 1100 
 1101         cdp = cdev2priv(dev);
 1102         if ((cdp->cdp_flags & CDP_UNREF_DTR) == 0) {
 1103                 /*
 1104                  * Avoid race with dev_rel(), e.g. from the populate
 1105                  * loop.  If CDP_UNREF_DTR flag is set, the reference
 1106                  * to be dropped at the end of destroy_devl() was
 1107                  * already taken by delist_dev_locked().
 1108                  */
 1109                 dev_refl(dev);
 1110 
 1111                 devfs_destroy(dev);
 1112         }
 1113 
 1114         /* Remove name marking */
 1115         dev->si_flags &= ~SI_NAMED;
 1116 
 1117         /* If we are a child, remove us from the parents list */
 1118         if (dev->si_flags & SI_CHILD) {
 1119                 LIST_REMOVE(dev, si_siblings);
 1120                 dev->si_flags &= ~SI_CHILD;
 1121         }
 1122 
 1123         /* Kill our children */
 1124         while (!LIST_EMPTY(&dev->si_children))
 1125                 destroy_devl(LIST_FIRST(&dev->si_children));
 1126 
 1127         /* Remove from clone list */
 1128         if (dev->si_flags & SI_CLONELIST) {
 1129                 LIST_REMOVE(dev, si_clone);
 1130                 dev->si_flags &= ~SI_CLONELIST;
 1131         }
 1132 
 1133         csw = dev->si_devsw;
 1134         dev->si_devsw = NULL;   /* already NULL for SI_ALIAS */
 1135         while (csw != NULL && csw->d_purge != NULL && dev->si_threadcount) {
 1136                 csw->d_purge(dev);
 1137                 msleep(csw, &devmtx, PRIBIO, "devprg", hz/10);
 1138                 if (dev->si_threadcount)
 1139                         printf("Still %lu threads in %s\n",
 1140                             dev->si_threadcount, devtoname(dev));
 1141         }
 1142         while (dev->si_threadcount != 0) {
 1143                 /* Use unique dummy wait ident */
 1144                 msleep(&csw, &devmtx, PRIBIO, "devdrn", hz / 10);
 1145         }
 1146 
 1147         dev_unlock();
 1148         if ((cdp->cdp_flags & CDP_UNREF_DTR) == 0) {
 1149                 /* avoid out of order notify events */
 1150                 notify_destroy(dev);
 1151         }
 1152         mtx_lock(&cdevpriv_mtx);
 1153         while ((p = LIST_FIRST(&cdp->cdp_fdpriv)) != NULL) {
 1154                 devfs_destroy_cdevpriv(p);
 1155                 mtx_lock(&cdevpriv_mtx);
 1156         }
 1157         mtx_unlock(&cdevpriv_mtx);
 1158         dev_lock();
 1159 
 1160         dev->si_drv1 = 0;
 1161         dev->si_drv2 = 0;
 1162         bzero(&dev->__si_u, sizeof(dev->__si_u));
 1163 
 1164         if (!(dev->si_flags & SI_ALIAS)) {
 1165                 /* Remove from cdevsw list */
 1166                 LIST_REMOVE(dev, si_list);
 1167 
 1168                 /* If cdevsw has no more struct cdev *'s, clean it */
 1169                 if (LIST_EMPTY(&csw->d_devs)) {
 1170                         fini_cdevsw(csw);
 1171                         wakeup(&csw->d_devs);
 1172                 }
 1173         }
 1174         dev->si_flags &= ~SI_ALIAS;
 1175         cdp->cdp_flags &= ~CDP_UNREF_DTR;
 1176         dev->si_refcount--;
 1177 
 1178         if (dev->si_refcount > 0)
 1179                 LIST_INSERT_HEAD(&dead_cdevsw.d_devs, dev, si_list);
 1180         else
 1181                 dev_free_devlocked(dev);
 1182 }
 1183 
 1184 static void
 1185 delist_dev_locked(struct cdev *dev)
 1186 {
 1187         struct cdev_priv *cdp;
 1188         struct cdev *child;
 1189 
 1190         mtx_assert(&devmtx, MA_OWNED);
 1191         cdp = cdev2priv(dev);
 1192         if ((cdp->cdp_flags & CDP_UNREF_DTR) != 0)
 1193                 return;
 1194         cdp->cdp_flags |= CDP_UNREF_DTR;
 1195         dev_refl(dev);
 1196         devfs_destroy(dev);
 1197         LIST_FOREACH(child, &dev->si_children, si_siblings)
 1198                 delist_dev_locked(child);
 1199         dev_unlock();   
 1200         /* ensure the destroy event is queued in order */
 1201         notify_destroy(dev);
 1202         dev_lock();
 1203 }
 1204 
 1205 /*
 1206  * This function will delist a character device and its children from
 1207  * the directory listing and create a destroy event without waiting
 1208  * for all character device references to go away. At some later point
 1209  * destroy_dev() must be called to complete the character device
 1210  * destruction. After calling this function the character device name
 1211  * can instantly be re-used.
 1212  */
 1213 void
 1214 delist_dev(struct cdev *dev)
 1215 {
 1216 
 1217         WITNESS_WARN(WARN_GIANTOK | WARN_SLEEPOK, NULL, "delist_dev");
 1218         dev_lock();
 1219         delist_dev_locked(dev);
 1220         dev_unlock();
 1221 }
 1222 
 1223 void
 1224 destroy_dev(struct cdev *dev)
 1225 {
 1226 
 1227         WITNESS_WARN(WARN_GIANTOK | WARN_SLEEPOK, NULL, "destroy_dev");
 1228         dev_lock();
 1229         destroy_devl(dev);
 1230         dev_unlock_and_free();
 1231 }
 1232 
 1233 const char *
 1234 devtoname(struct cdev *dev)
 1235 {
 1236 
 1237         return (dev->si_name);
 1238 }
 1239 
 1240 int
 1241 dev_stdclone(char *name, char **namep, const char *stem, int *unit)
 1242 {
 1243         int u, i;
 1244 
 1245         i = strlen(stem);
 1246         if (bcmp(stem, name, i) != 0)
 1247                 return (0);
 1248         if (!isdigit(name[i]))
 1249                 return (0);
 1250         u = 0;
 1251         if (name[i] == '' && isdigit(name[i+1]))
 1252                 return (0);
 1253         while (isdigit(name[i])) {
 1254                 u *= 10;
 1255                 u += name[i++] - '';
 1256         }
 1257         if (u > 0xffffff)
 1258                 return (0);
 1259         *unit = u;
 1260         if (namep)
 1261                 *namep = &name[i];
 1262         if (name[i]) 
 1263                 return (2);
 1264         return (1);
 1265 }
 1266 
 1267 /*
 1268  * Helper functions for cloning device drivers.
 1269  *
 1270  * The objective here is to make it unnecessary for the device drivers to
 1271  * use rman or similar to manage their unit number space.  Due to the way
 1272  * we do "on-demand" devices, using rman or other "private" methods 
 1273  * will be very tricky to lock down properly once we lock down this file.
 1274  *
 1275  * Instead we give the drivers these routines which puts the struct cdev *'s
 1276  * that are to be managed on their own list, and gives the driver the ability
 1277  * to ask for the first free unit number or a given specified unit number.
 1278  *
 1279  * In addition these routines support paired devices (pty, nmdm and similar)
 1280  * by respecting a number of "flag" bits in the minor number.
 1281  *
 1282  */
 1283 
 1284 struct clonedevs {
 1285         LIST_HEAD(,cdev)        head;
 1286 };
 1287 
 1288 void
 1289 clone_setup(struct clonedevs **cdp)
 1290 {
 1291 
 1292         *cdp = malloc(sizeof **cdp, M_DEVBUF, M_WAITOK | M_ZERO);
 1293         LIST_INIT(&(*cdp)->head);
 1294 }
 1295 
 1296 int
 1297 clone_create(struct clonedevs **cdp, struct cdevsw *csw, int *up,
 1298     struct cdev **dp, int extra)
 1299 {
 1300         struct clonedevs *cd;
 1301         struct cdev *dev, *ndev, *dl, *de;
 1302         struct make_dev_args args;
 1303         int unit, low, u;
 1304 
 1305         KASSERT(*cdp != NULL,
 1306             ("clone_setup() not called in driver \"%s\"", csw->d_name));
 1307         KASSERT(!(extra & CLONE_UNITMASK),
 1308             ("Illegal extra bits (0x%x) in clone_create", extra));
 1309         KASSERT(*up <= CLONE_UNITMASK,
 1310             ("Too high unit (0x%x) in clone_create", *up));
 1311         KASSERT(csw->d_flags & D_NEEDMINOR,
 1312             ("clone_create() on cdevsw without minor numbers"));
 1313 
 1314 
 1315         /*
 1316          * Search the list for a lot of things in one go:
 1317          *   A preexisting match is returned immediately.
 1318          *   The lowest free unit number if we are passed -1, and the place
 1319          *       in the list where we should insert that new element.
 1320          *   The place to insert a specified unit number, if applicable
 1321          *       the end of the list.
 1322          */
 1323         unit = *up;
 1324         ndev = devfs_alloc(MAKEDEV_WAITOK);
 1325         dev_lock();
 1326         prep_cdevsw(csw, MAKEDEV_WAITOK);
 1327         low = extra;
 1328         de = dl = NULL;
 1329         cd = *cdp;
 1330         LIST_FOREACH(dev, &cd->head, si_clone) {
 1331                 KASSERT(dev->si_flags & SI_CLONELIST,
 1332                     ("Dev %p(%s) should be on clonelist", dev, dev->si_name));
 1333                 u = dev2unit(dev);
 1334                 if (u == (unit | extra)) {
 1335                         *dp = dev;
 1336                         dev_unlock();
 1337                         devfs_free(ndev);
 1338                         return (0);
 1339                 }
 1340                 if (unit == -1 && u == low) {
 1341                         low++;
 1342                         de = dev;
 1343                         continue;
 1344                 } else if (u < (unit | extra)) {
 1345                         de = dev;
 1346                         continue;
 1347                 } else if (u > (unit | extra)) {
 1348                         dl = dev;
 1349                         break;
 1350                 }
 1351         }
 1352         if (unit == -1)
 1353                 unit = low & CLONE_UNITMASK;
 1354         make_dev_args_init(&args);
 1355         args.mda_unit = unit | extra;
 1356         args.mda_devsw = csw;
 1357         dev = newdev(&args, ndev);
 1358         if (dev->si_flags & SI_CLONELIST) {
 1359                 printf("dev %p (%s) is on clonelist\n", dev, dev->si_name);
 1360                 printf("unit=%d, low=%d, extra=0x%x\n", unit, low, extra);
 1361                 LIST_FOREACH(dev, &cd->head, si_clone) {
 1362                         printf("\t%p %s\n", dev, dev->si_name);
 1363                 }
 1364                 panic("foo");
 1365         }
 1366         KASSERT(!(dev->si_flags & SI_CLONELIST),
 1367             ("Dev %p(%s) should not be on clonelist", dev, dev->si_name));
 1368         if (dl != NULL)
 1369                 LIST_INSERT_BEFORE(dl, dev, si_clone);
 1370         else if (de != NULL)
 1371                 LIST_INSERT_AFTER(de, dev, si_clone);
 1372         else
 1373                 LIST_INSERT_HEAD(&cd->head, dev, si_clone);
 1374         dev->si_flags |= SI_CLONELIST;
 1375         *up = unit;
 1376         dev_unlock_and_free();
 1377         return (1);
 1378 }
 1379 
 1380 /*
 1381  * Kill everything still on the list.  The driver should already have
 1382  * disposed of any softc hung of the struct cdev *'s at this time.
 1383  */
 1384 void
 1385 clone_cleanup(struct clonedevs **cdp)
 1386 {
 1387         struct cdev *dev;
 1388         struct cdev_priv *cp;
 1389         struct clonedevs *cd;
 1390         
 1391         cd = *cdp;
 1392         if (cd == NULL)
 1393                 return;
 1394         dev_lock();
 1395         while (!LIST_EMPTY(&cd->head)) {
 1396                 dev = LIST_FIRST(&cd->head);
 1397                 LIST_REMOVE(dev, si_clone);
 1398                 KASSERT(dev->si_flags & SI_CLONELIST,
 1399                     ("Dev %p(%s) should be on clonelist", dev, dev->si_name));
 1400                 dev->si_flags &= ~SI_CLONELIST;
 1401                 cp = cdev2priv(dev);
 1402                 if (!(cp->cdp_flags & CDP_SCHED_DTR)) {
 1403                         cp->cdp_flags |= CDP_SCHED_DTR;
 1404                         KASSERT(dev->si_flags & SI_NAMED,
 1405                                 ("Driver has goofed in cloning underways udev %jx unit %x",
 1406                                 (uintmax_t)dev2udev(dev), dev2unit(dev)));
 1407                         destroy_devl(dev);
 1408                 }
 1409         }
 1410         dev_unlock_and_free();
 1411         free(cd, M_DEVBUF);
 1412         *cdp = NULL;
 1413 }
 1414 
 1415 static TAILQ_HEAD(, cdev_priv) dev_ddtr =
 1416         TAILQ_HEAD_INITIALIZER(dev_ddtr);
 1417 static struct task dev_dtr_task = TASK_INITIALIZER(0, destroy_dev_tq, NULL);
 1418 
 1419 static void
 1420 destroy_dev_tq(void *ctx, int pending)
 1421 {
 1422         struct cdev_priv *cp;
 1423         struct cdev *dev;
 1424         void (*cb)(void *);
 1425         void *cb_arg;
 1426 
 1427         dev_lock();
 1428         while (!TAILQ_EMPTY(&dev_ddtr)) {
 1429                 cp = TAILQ_FIRST(&dev_ddtr);
 1430                 dev = &cp->cdp_c;
 1431                 KASSERT(cp->cdp_flags & CDP_SCHED_DTR,
 1432                     ("cdev %p in dev_destroy_tq without CDP_SCHED_DTR", cp));
 1433                 TAILQ_REMOVE(&dev_ddtr, cp, cdp_dtr_list);
 1434                 cb = cp->cdp_dtr_cb;
 1435                 cb_arg = cp->cdp_dtr_cb_arg;
 1436                 destroy_devl(dev);
 1437                 dev_unlock_and_free();
 1438                 dev_rel(dev);
 1439                 if (cb != NULL)
 1440                         cb(cb_arg);
 1441                 dev_lock();
 1442         }
 1443         dev_unlock();
 1444 }
 1445 
 1446 /*
 1447  * devmtx shall be locked on entry. devmtx will be unlocked after
 1448  * function return.
 1449  */
 1450 static int
 1451 destroy_dev_sched_cbl(struct cdev *dev, void (*cb)(void *), void *arg)
 1452 {
 1453         struct cdev_priv *cp;
 1454 
 1455         mtx_assert(&devmtx, MA_OWNED);
 1456         cp = cdev2priv(dev);
 1457         if (cp->cdp_flags & CDP_SCHED_DTR) {
 1458                 dev_unlock();
 1459                 return (0);
 1460         }
 1461         dev_refl(dev);
 1462         cp->cdp_flags |= CDP_SCHED_DTR;
 1463         cp->cdp_dtr_cb = cb;
 1464         cp->cdp_dtr_cb_arg = arg;
 1465         TAILQ_INSERT_TAIL(&dev_ddtr, cp, cdp_dtr_list);
 1466         dev_unlock();
 1467         taskqueue_enqueue(taskqueue_swi_giant, &dev_dtr_task);
 1468         return (1);
 1469 }
 1470 
 1471 int
 1472 destroy_dev_sched_cb(struct cdev *dev, void (*cb)(void *), void *arg)
 1473 {
 1474 
 1475         dev_lock();
 1476         return (destroy_dev_sched_cbl(dev, cb, arg));
 1477 }
 1478 
 1479 int
 1480 destroy_dev_sched(struct cdev *dev)
 1481 {
 1482 
 1483         return (destroy_dev_sched_cb(dev, NULL, NULL));
 1484 }
 1485 
 1486 void
 1487 destroy_dev_drain(struct cdevsw *csw)
 1488 {
 1489 
 1490         dev_lock();
 1491         while (!LIST_EMPTY(&csw->d_devs)) {
 1492                 msleep(&csw->d_devs, &devmtx, PRIBIO, "devscd", hz/10);
 1493         }
 1494         dev_unlock();
 1495 }
 1496 
 1497 void
 1498 drain_dev_clone_events(void)
 1499 {
 1500 
 1501         sx_xlock(&clone_drain_lock);
 1502         sx_xunlock(&clone_drain_lock);
 1503 }
 1504 
 1505 #include "opt_ddb.h"
 1506 #ifdef DDB
 1507 #include <sys/kernel.h>
 1508 
 1509 #include <ddb/ddb.h>
 1510 
 1511 DB_SHOW_COMMAND(cdev, db_show_cdev)
 1512 {
 1513         struct cdev_priv *cdp;
 1514         struct cdev *dev;
 1515         u_int flags;
 1516         char buf[512];
 1517 
 1518         if (!have_addr) {
 1519                 TAILQ_FOREACH(cdp, &cdevp_list, cdp_list) {
 1520                         dev = &cdp->cdp_c;
 1521                         db_printf("%s %p\n", dev->si_name, dev);
 1522                         if (db_pager_quit)
 1523                                 break;
 1524                 }
 1525                 return;
 1526         }
 1527 
 1528         dev = (struct cdev *)addr;
 1529         cdp = cdev2priv(dev);
 1530         db_printf("dev %s ref %d use %ld thr %ld inuse %u fdpriv %p\n",
 1531             dev->si_name, dev->si_refcount, dev->si_usecount,
 1532             dev->si_threadcount, cdp->cdp_inuse, cdp->cdp_fdpriv.lh_first);
 1533         db_printf("devsw %p si_drv0 %d si_drv1 %p si_drv2 %p\n",
 1534             dev->si_devsw, dev->si_drv0, dev->si_drv1, dev->si_drv2);
 1535         flags = dev->si_flags;
 1536 #define SI_FLAG(flag)   do {                                            \
 1537         if (flags & (flag)) {                                           \
 1538                 if (buf[0] != '\0')                                     \
 1539                         strlcat(buf, ", ", sizeof(buf));                \
 1540                 strlcat(buf, (#flag) + 3, sizeof(buf));                 \
 1541                 flags &= ~(flag);                                       \
 1542         }                                                               \
 1543 } while (0)
 1544         buf[0] = '\0';
 1545         SI_FLAG(SI_ETERNAL);
 1546         SI_FLAG(SI_ALIAS);
 1547         SI_FLAG(SI_NAMED);
 1548         SI_FLAG(SI_CHILD);
 1549         SI_FLAG(SI_DUMPDEV);
 1550         SI_FLAG(SI_CLONELIST);
 1551         db_printf("si_flags %s\n", buf);
 1552 
 1553         flags = cdp->cdp_flags;
 1554 #define CDP_FLAG(flag)  do {                                            \
 1555         if (flags & (flag)) {                                           \
 1556                 if (buf[0] != '\0')                                     \
 1557                         strlcat(buf, ", ", sizeof(buf));                \
 1558                 strlcat(buf, (#flag) + 4, sizeof(buf));                 \
 1559                 flags &= ~(flag);                                       \
 1560         }                                                               \
 1561 } while (0)
 1562         buf[0] = '\0';
 1563         CDP_FLAG(CDP_ACTIVE);
 1564         CDP_FLAG(CDP_SCHED_DTR);
 1565         db_printf("cdp_flags %s\n", buf);
 1566 }
 1567 #endif

Cache object: 5bf8d1d5f09825fd6ae41716d1f27f83


[ 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.