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/tty.h>
   46 #include <sys/ucred.h>
   47 #include <sys/taskqueue.h>
   48 #include <machine/stdarg.h>
   49 
   50 #include <fs/devfs/devfs_int.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 struct cdev *make_dev_credv(int flags,
   59     struct cdevsw *devsw, int minornr,
   60     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();
   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 = cdev->si_priv;
  119         TAILQ_INSERT_HEAD(&cdevp_free_list, cdp, cdp_list);
  120 }
  121 
  122 static void
  123 cdevsw_free_devlocked(struct cdevsw *csw)
  124 {
  125 
  126         mtx_assert(&devmtx, MA_OWNED);
  127         SLIST_INSERT_HEAD(&cdevsw_gt_post_list, csw, d_postfree_list);
  128 }
  129 
  130 void
  131 dev_unlock(void)
  132 {
  133 
  134         mtx_unlock(&devmtx);
  135 }
  136 
  137 void
  138 dev_ref(struct cdev *dev)
  139 {
  140 
  141         mtx_assert(&devmtx, MA_NOTOWNED);
  142         mtx_lock(&devmtx);
  143         dev->si_refcount++;
  144         mtx_unlock(&devmtx);
  145 }
  146 
  147 void
  148 dev_refl(struct cdev *dev)
  149 {
  150 
  151         mtx_assert(&devmtx, MA_OWNED);
  152         dev->si_refcount++;
  153 }
  154 
  155 void
  156 dev_rel(struct cdev *dev)
  157 {
  158         int flag = 0;
  159 
  160         mtx_assert(&devmtx, MA_NOTOWNED);
  161         dev_lock();
  162         dev->si_refcount--;
  163         KASSERT(dev->si_refcount >= 0,
  164             ("dev_rel(%s) gave negative count", devtoname(dev)));
  165 #if 0
  166         if (dev->si_usecount == 0 &&
  167             (dev->si_flags & SI_CHEAPCLONE) && (dev->si_flags & SI_NAMED))
  168                 ;
  169         else 
  170 #endif
  171         if (dev->si_devsw == NULL && dev->si_refcount == 0) {
  172                 LIST_REMOVE(dev, si_list);
  173                 flag = 1;
  174         }
  175         dev_unlock();
  176         if (flag)
  177                 devfs_free(dev);
  178 }
  179 
  180 struct cdevsw *
  181 dev_refthread(struct cdev *dev)
  182 {
  183         struct cdevsw *csw;
  184         struct cdev_priv *cdp;
  185 
  186         mtx_assert(&devmtx, MA_NOTOWNED);
  187         dev_lock();
  188         csw = dev->si_devsw;
  189         if (csw != NULL) {
  190                 cdp = dev->si_priv;
  191                 if ((cdp->cdp_flags & CDP_SCHED_DTR) == 0)
  192                         dev->si_threadcount++;
  193                 else
  194                         csw = NULL;
  195         }
  196         dev_unlock();
  197         return (csw);
  198 }
  199 
  200 struct cdevsw *
  201 devvn_refthread(struct vnode *vp, struct cdev **devp)
  202 {
  203         struct cdevsw *csw;
  204         struct cdev_priv *cdp;
  205 
  206         mtx_assert(&devmtx, MA_NOTOWNED);
  207         csw = NULL;
  208         dev_lock();
  209         *devp = vp->v_rdev;
  210         if (*devp != NULL) {
  211                 cdp = (*devp)->si_priv;
  212                 if ((cdp->cdp_flags & CDP_SCHED_DTR) == 0) {
  213                         csw = (*devp)->si_devsw;
  214                         if (csw != NULL)
  215                                 (*devp)->si_threadcount++;
  216                 }
  217         }
  218         dev_unlock();
  219         return (csw);
  220 }
  221 
  222 void    
  223 dev_relthread(struct cdev *dev)
  224 {
  225 
  226         mtx_assert(&devmtx, MA_NOTOWNED);
  227         dev_lock();
  228         KASSERT(dev->si_threadcount > 0,
  229             ("%s threadcount is wrong", dev->si_name));
  230         dev->si_threadcount--;
  231         dev_unlock();
  232 }
  233 
  234 int
  235 nullop(void)
  236 {
  237 
  238         return (0);
  239 }
  240 
  241 int
  242 eopnotsupp(void)
  243 {
  244 
  245         return (EOPNOTSUPP);
  246 }
  247 
  248 static int
  249 enxio(void)
  250 {
  251         return (ENXIO);
  252 }
  253 
  254 static int
  255 enodev(void)
  256 {
  257         return (ENODEV);
  258 }
  259 
  260 /* Define a dead_cdevsw for use when devices leave unexpectedly. */
  261 
  262 #define dead_open       (d_open_t *)enxio
  263 #define dead_close      (d_close_t *)enxio
  264 #define dead_read       (d_read_t *)enxio
  265 #define dead_write      (d_write_t *)enxio
  266 #define dead_ioctl      (d_ioctl_t *)enxio
  267 #define dead_poll       (d_poll_t *)enodev
  268 #define dead_mmap       (d_mmap_t *)enodev
  269 
  270 static void
  271 dead_strategy(struct bio *bp)
  272 {
  273 
  274         biofinish(bp, NULL, ENXIO);
  275 }
  276 
  277 #define dead_dump       (dumper_t *)enxio
  278 #define dead_kqfilter   (d_kqfilter_t *)enxio
  279 
  280 static struct cdevsw dead_cdevsw = {
  281         .d_version =    D_VERSION,
  282         .d_flags =      D_NEEDGIANT, /* XXX: does dead_strategy need this ? */
  283         .d_open =       dead_open,
  284         .d_close =      dead_close,
  285         .d_read =       dead_read,
  286         .d_write =      dead_write,
  287         .d_ioctl =      dead_ioctl,
  288         .d_poll =       dead_poll,
  289         .d_mmap =       dead_mmap,
  290         .d_strategy =   dead_strategy,
  291         .d_name =       "dead",
  292         .d_dump =       dead_dump,
  293         .d_kqfilter =   dead_kqfilter
  294 };
  295 
  296 /* Default methods if driver does not specify method */
  297 
  298 #define null_open       (d_open_t *)nullop
  299 #define null_close      (d_close_t *)nullop
  300 #define no_read         (d_read_t *)enodev
  301 #define no_write        (d_write_t *)enodev
  302 #define no_ioctl        (d_ioctl_t *)enodev
  303 #define no_mmap         (d_mmap_t *)enodev
  304 #define no_kqfilter     (d_kqfilter_t *)enodev
  305 
  306 static void
  307 no_strategy(struct bio *bp)
  308 {
  309 
  310         biofinish(bp, NULL, ENODEV);
  311 }
  312 
  313 static int
  314 no_poll(struct cdev *dev __unused, int events, struct thread *td __unused)
  315 {
  316         /*
  317          * Return true for read/write.  If the user asked for something
  318          * special, return POLLNVAL, so that clients have a way of
  319          * determining reliably whether or not the extended
  320          * functionality is present without hard-coding knowledge
  321          * of specific filesystem implementations.
  322          * Stay in sync with vop_nopoll().
  323          */
  324         if (events & ~POLLSTANDARD)
  325                 return (POLLNVAL);
  326 
  327         return (events & (POLLIN | POLLOUT | POLLRDNORM | POLLWRNORM));
  328 }
  329 
  330 #define no_dump         (dumper_t *)enodev
  331 
  332 static int
  333 giant_open(struct cdev *dev, int oflags, int devtype, struct thread *td)
  334 {
  335         struct cdevsw *dsw;
  336         int retval;
  337 
  338         dsw = dev_refthread(dev);
  339         if (dsw == NULL)
  340                 return (ENXIO);
  341         mtx_lock(&Giant);
  342         retval = dsw->d_gianttrick->d_open(dev, oflags, devtype, td);
  343         mtx_unlock(&Giant);
  344         dev_relthread(dev);
  345         return (retval);
  346 }
  347 
  348 static int
  349 giant_fdopen(struct cdev *dev, int oflags, struct thread *td, struct file *fp)
  350 {
  351         struct cdevsw *dsw;
  352         int retval;
  353 
  354         dsw = dev_refthread(dev);
  355         if (dsw == NULL)
  356                 return (ENXIO);
  357         mtx_lock(&Giant);
  358         retval = dsw->d_gianttrick->d_fdopen(dev, oflags, td, fp);
  359         mtx_unlock(&Giant);
  360         dev_relthread(dev);
  361         return (retval);
  362 }
  363 
  364 static int
  365 giant_close(struct cdev *dev, int fflag, int devtype, struct thread *td)
  366 {
  367         struct cdevsw *dsw;
  368         int retval;
  369 
  370         dsw = dev_refthread(dev);
  371         if (dsw == NULL)
  372                 return (ENXIO);
  373         mtx_lock(&Giant);
  374         retval = dsw->d_gianttrick->d_close(dev, fflag, devtype, td);
  375         mtx_unlock(&Giant);
  376         dev_relthread(dev);
  377         return (retval);
  378 }
  379 
  380 static void
  381 giant_strategy(struct bio *bp)
  382 {
  383         struct cdevsw *dsw;
  384         struct cdev *dev;
  385 
  386         dev = bp->bio_dev;
  387         dsw = dev_refthread(dev);
  388         if (dsw == NULL) {
  389                 biofinish(bp, NULL, ENXIO);
  390                 return;
  391         }
  392         mtx_lock(&Giant);
  393         dsw->d_gianttrick->d_strategy(bp);
  394         mtx_unlock(&Giant);
  395         dev_relthread(dev);
  396 }
  397 
  398 static int
  399 giant_ioctl(struct cdev *dev, u_long cmd, caddr_t data, int fflag, struct thread *td)
  400 {
  401         struct cdevsw *dsw;
  402         int retval;
  403 
  404         dsw = dev_refthread(dev);
  405         if (dsw == NULL)
  406                 return (ENXIO);
  407         mtx_lock(&Giant);
  408         retval = dsw->d_gianttrick->d_ioctl(dev, cmd, data, fflag, td);
  409         mtx_unlock(&Giant);
  410         dev_relthread(dev);
  411         return (retval);
  412 }
  413   
  414 static int
  415 giant_read(struct cdev *dev, struct uio *uio, int ioflag)
  416 {
  417         struct cdevsw *dsw;
  418         int retval;
  419 
  420         dsw = dev_refthread(dev);
  421         if (dsw == NULL)
  422                 return (ENXIO);
  423         mtx_lock(&Giant);
  424         retval = dsw->d_gianttrick->d_read(dev, uio, ioflag);
  425         mtx_unlock(&Giant);
  426         dev_relthread(dev);
  427         return (retval);
  428 }
  429 
  430 static int
  431 giant_write(struct cdev *dev, struct uio *uio, int ioflag)
  432 {
  433         struct cdevsw *dsw;
  434         int retval;
  435 
  436         dsw = dev_refthread(dev);
  437         if (dsw == NULL)
  438                 return (ENXIO);
  439         mtx_lock(&Giant);
  440         retval = dsw->d_gianttrick->d_write(dev, uio, ioflag);
  441         mtx_unlock(&Giant);
  442         dev_relthread(dev);
  443         return (retval);
  444 }
  445 
  446 static int
  447 giant_poll(struct cdev *dev, int events, struct thread *td)
  448 {
  449         struct cdevsw *dsw;
  450         int retval;
  451 
  452         dsw = dev_refthread(dev);
  453         if (dsw == NULL)
  454                 return (ENXIO);
  455         mtx_lock(&Giant);
  456         retval = dsw->d_gianttrick->d_poll(dev, events, td);
  457         mtx_unlock(&Giant);
  458         dev_relthread(dev);
  459         return (retval);
  460 }
  461 
  462 static int
  463 giant_kqfilter(struct cdev *dev, struct knote *kn)
  464 {
  465         struct cdevsw *dsw;
  466         int retval;
  467 
  468         dsw = dev_refthread(dev);
  469         if (dsw == NULL)
  470                 return (ENXIO);
  471         mtx_lock(&Giant);
  472         retval = dsw->d_gianttrick->d_kqfilter(dev, kn);
  473         mtx_unlock(&Giant);
  474         dev_relthread(dev);
  475         return (retval);
  476 }
  477 
  478 static int
  479 giant_mmap(struct cdev *dev, vm_offset_t offset, vm_paddr_t *paddr, int nprot)
  480 {
  481         struct cdevsw *dsw;
  482         int retval;
  483 
  484         dsw = dev_refthread(dev);
  485         if (dsw == NULL)
  486                 return (ENXIO);
  487         mtx_lock(&Giant);
  488         retval = dsw->d_gianttrick->d_mmap(dev, offset, paddr, nprot);
  489         mtx_unlock(&Giant);
  490         dev_relthread(dev);
  491         return (retval);
  492 }
  493 
  494 
  495 /*
  496  * struct cdev * and u_dev_t primitives
  497  */
  498 
  499 int
  500 minor(struct cdev *x)
  501 {
  502         if (x == NULL)
  503                 return NODEV;
  504         return(x->si_drv0 & MAXMINOR);
  505 }
  506 
  507 int
  508 dev2unit(struct cdev *x)
  509 {
  510 
  511         if (x == NULL)
  512                 return NODEV;
  513         return (minor2unit(minor(x)));
  514 }
  515 
  516 u_int
  517 minor2unit(u_int _minor)
  518 {
  519 
  520         KASSERT((_minor & ~MAXMINOR) == 0, ("Illegal minor %x", _minor));
  521         return ((_minor & 0xff) | ((_minor >> 8) & 0xffff00));
  522 }
  523 
  524 int
  525 unit2minor(int unit)
  526 {
  527 
  528         KASSERT(unit <= 0xffffff, ("Invalid unit (%d) in unit2minor", unit));
  529         return ((unit & 0xff) | ((unit << 8) & ~0xffff));
  530 }
  531 
  532 static void
  533 notify(struct cdev *dev, const char *ev)
  534 {
  535         static const char prefix[] = "cdev=";
  536         char *data;
  537         int namelen;
  538 
  539         if (cold)
  540                 return;
  541         namelen = strlen(dev->si_name);
  542         data = malloc(namelen + sizeof(prefix), M_TEMP, M_WAITOK);
  543         memcpy(data, prefix, sizeof(prefix) - 1);
  544         memcpy(data + sizeof(prefix) - 1, dev->si_name, namelen + 1);
  545         devctl_notify("DEVFS", "CDEV", ev, data);
  546         free(data, M_TEMP);
  547 }
  548 
  549 static void
  550 notify_create(struct cdev *dev)
  551 {
  552 
  553         notify(dev, "CREATE");
  554 }
  555 
  556 static void
  557 notify_destroy(struct cdev *dev)
  558 {
  559 
  560         notify(dev, "DESTROY");
  561 }
  562 
  563 static struct cdev *
  564 newdev(struct cdevsw *csw, int y, struct cdev *si)
  565 {
  566         struct cdev *si2;
  567         dev_t   udev;
  568 
  569         mtx_assert(&devmtx, MA_OWNED);
  570         udev = y;
  571         LIST_FOREACH(si2, &csw->d_devs, si_list) {
  572                 if (si2->si_drv0 == udev) {
  573                         dev_free_devlocked(si);
  574                         return (si2);
  575                 }
  576         }
  577         si->si_drv0 = udev;
  578         si->si_devsw = csw;
  579         LIST_INSERT_HEAD(&csw->d_devs, si, si_list);
  580         return (si);
  581 }
  582 
  583 int
  584 uminor(dev_t dev)
  585 {
  586         return (dev & MAXMINOR);
  587 }
  588 
  589 int
  590 umajor(dev_t dev)
  591 {
  592         return ((dev & ~MAXMINOR) >> 8);
  593 }
  594 
  595 static void
  596 fini_cdevsw(struct cdevsw *devsw)
  597 {
  598         struct cdevsw *gt;
  599 
  600         if (devsw->d_gianttrick != NULL) {
  601                 gt = devsw->d_gianttrick;
  602                 memcpy(devsw, gt, sizeof *devsw);
  603                 cdevsw_free_devlocked(gt);
  604                 devsw->d_gianttrick = NULL;
  605         }
  606         devsw->d_flags &= ~D_INIT;
  607 }
  608 
  609 static void
  610 prep_cdevsw(struct cdevsw *devsw)
  611 {
  612         struct cdevsw *dsw2;
  613 
  614         mtx_assert(&devmtx, MA_OWNED);
  615         if (devsw->d_flags & D_INIT)
  616                 return;
  617         if (devsw->d_flags & D_NEEDGIANT) {
  618                 dev_unlock();
  619                 dsw2 = malloc(sizeof *dsw2, M_DEVT, M_WAITOK);
  620                 dev_lock();
  621         } else
  622                 dsw2 = NULL;
  623         if (devsw->d_flags & D_INIT) {
  624                 if (dsw2 != NULL)
  625                         cdevsw_free_devlocked(dsw2);
  626                 return;
  627         }
  628 
  629         if (devsw->d_version != D_VERSION_01) {
  630                 printf(
  631                     "WARNING: Device driver \"%s\" has wrong version %s\n",
  632                     devsw->d_name == NULL ? "???" : devsw->d_name,
  633                     "and is disabled.  Recompile KLD module.");
  634                 devsw->d_open = dead_open;
  635                 devsw->d_close = dead_close;
  636                 devsw->d_read = dead_read;
  637                 devsw->d_write = dead_write;
  638                 devsw->d_ioctl = dead_ioctl;
  639                 devsw->d_poll = dead_poll;
  640                 devsw->d_mmap = dead_mmap;
  641                 devsw->d_strategy = dead_strategy;
  642                 devsw->d_dump = dead_dump;
  643                 devsw->d_kqfilter = dead_kqfilter;
  644         }
  645         
  646         if (devsw->d_flags & D_TTY) {
  647                 if (devsw->d_ioctl == NULL)     devsw->d_ioctl = ttyioctl;
  648                 if (devsw->d_read == NULL)      devsw->d_read = ttyread;
  649                 if (devsw->d_write == NULL)     devsw->d_write = ttywrite;
  650                 if (devsw->d_kqfilter == NULL)  devsw->d_kqfilter = ttykqfilter;
  651                 if (devsw->d_poll == NULL)      devsw->d_poll = ttypoll;
  652         }
  653 
  654         if (devsw->d_flags & D_NEEDGIANT) {
  655                 if (devsw->d_gianttrick == NULL) {
  656                         memcpy(dsw2, devsw, sizeof *dsw2);
  657                         devsw->d_gianttrick = dsw2;
  658                         dsw2 = NULL;
  659                 }
  660         }
  661 
  662 #define FIXUP(member, noop, giant)                              \
  663         do {                                                    \
  664                 if (devsw->member == NULL) {                    \
  665                         devsw->member = noop;                   \
  666                 } else if (devsw->d_flags & D_NEEDGIANT)        \
  667                         devsw->member = giant;                  \
  668                 }                                               \
  669         while (0)
  670 
  671         FIXUP(d_open,           null_open,      giant_open);
  672         FIXUP(d_fdopen,         NULL,           giant_fdopen);
  673         FIXUP(d_close,          null_close,     giant_close);
  674         FIXUP(d_read,           no_read,        giant_read);
  675         FIXUP(d_write,          no_write,       giant_write);
  676         FIXUP(d_ioctl,          no_ioctl,       giant_ioctl);
  677         FIXUP(d_poll,           no_poll,        giant_poll);
  678         FIXUP(d_mmap,           no_mmap,        giant_mmap);
  679         FIXUP(d_strategy,       no_strategy,    giant_strategy);
  680         FIXUP(d_kqfilter,       no_kqfilter,    giant_kqfilter);
  681 
  682         if (devsw->d_dump == NULL)      devsw->d_dump = no_dump;
  683 
  684         LIST_INIT(&devsw->d_devs);
  685 
  686         devsw->d_flags |= D_INIT;
  687 
  688         if (dsw2 != NULL)
  689                 cdevsw_free_devlocked(dsw2);
  690 }
  691 
  692 struct cdev *
  693 make_dev_credv(int flags, struct cdevsw *devsw, int minornr,
  694     struct ucred *cr, uid_t uid,
  695     gid_t gid, int mode, const char *fmt, va_list ap)
  696 {
  697         struct cdev *dev;
  698         int i;
  699 
  700         KASSERT((minornr & ~MAXMINOR) == 0,
  701             ("Invalid minor (0x%x) in make_dev", minornr));
  702 
  703         dev = devfs_alloc();
  704         dev_lock();
  705         prep_cdevsw(devsw);
  706         dev = newdev(devsw, minornr, dev);
  707         if (flags & MAKEDEV_REF)
  708                 dev_refl(dev);
  709         if (dev->si_flags & SI_CHEAPCLONE &&
  710             dev->si_flags & SI_NAMED) {
  711                 /*
  712                  * This is allowed as it removes races and generally
  713                  * simplifies cloning devices.
  714                  * XXX: still ??
  715                  */
  716                 dev_unlock_and_free();
  717                 return (dev);
  718         }
  719         KASSERT(!(dev->si_flags & SI_NAMED),
  720             ("make_dev() by driver %s on pre-existing device (min=%x, name=%s)",
  721             devsw->d_name, minor(dev), devtoname(dev)));
  722 
  723         i = vsnrprintf(dev->__si_namebuf, sizeof dev->__si_namebuf, 32, fmt, ap);
  724         if (i > (sizeof dev->__si_namebuf - 1)) {
  725                 printf("WARNING: Device name truncated! (%s)\n", 
  726                     dev->__si_namebuf);
  727         }
  728                 
  729         dev->si_flags |= SI_NAMED;
  730 #ifdef MAC
  731         if (cr != NULL)
  732                 dev->si_cred = crhold(cr);
  733         else
  734 #endif
  735                 dev->si_cred = NULL;
  736         dev->si_uid = uid;
  737         dev->si_gid = gid;
  738         dev->si_mode = mode;
  739 
  740         devfs_create(dev);
  741         clean_unrhdrl(devfs_inos);
  742         dev_unlock_and_free();
  743 
  744         notify_create(dev);
  745 
  746         return (dev);
  747 }
  748 
  749 struct cdev *
  750 make_dev(struct cdevsw *devsw, int minornr, uid_t uid, gid_t gid, int mode,
  751     const char *fmt, ...)
  752 {
  753         struct cdev *dev;
  754         va_list ap;
  755 
  756         va_start(ap, fmt);
  757         dev = make_dev_credv(0, devsw, minornr, NULL, uid, gid, mode, fmt, ap);
  758         va_end(ap);
  759         return (dev);
  760 }
  761 
  762 struct cdev *
  763 make_dev_cred(struct cdevsw *devsw, int minornr, struct ucred *cr, uid_t uid,
  764     gid_t gid, int mode, const char *fmt, ...)
  765 {
  766         struct cdev *dev;
  767         va_list ap;
  768 
  769         va_start(ap, fmt);
  770         dev = make_dev_credv(0, devsw, minornr, cr, uid, gid, mode, fmt, ap);
  771         va_end(ap);
  772 
  773         return (dev);
  774 }
  775 
  776 struct cdev *
  777 make_dev_credf(int flags, struct cdevsw *devsw, int minornr,
  778     struct ucred *cr, uid_t uid,
  779     gid_t gid, int mode, const char *fmt, ...)
  780 {
  781         struct cdev *dev;
  782         va_list ap;
  783 
  784         va_start(ap, fmt);
  785         dev = make_dev_credv(flags, devsw, minornr, cr, uid, gid, mode,
  786             fmt, ap);
  787         va_end(ap);
  788 
  789         return (dev);
  790 }
  791 
  792 static void
  793 dev_dependsl(struct cdev *pdev, struct cdev *cdev)
  794 {
  795 
  796         cdev->si_parent = pdev;
  797         cdev->si_flags |= SI_CHILD;
  798         LIST_INSERT_HEAD(&pdev->si_children, cdev, si_siblings);
  799 }
  800 
  801 
  802 void
  803 dev_depends(struct cdev *pdev, struct cdev *cdev)
  804 {
  805 
  806         dev_lock();
  807         dev_dependsl(pdev, cdev);
  808         dev_unlock();
  809 }
  810 
  811 struct cdev *
  812 make_dev_alias(struct cdev *pdev, const char *fmt, ...)
  813 {
  814         struct cdev *dev;
  815         va_list ap;
  816         int i;
  817 
  818         KASSERT(pdev != NULL, ("NULL pdev"));
  819         dev = devfs_alloc();
  820         dev_lock();
  821         dev->si_flags |= SI_ALIAS;
  822         dev->si_flags |= SI_NAMED;
  823         va_start(ap, fmt);
  824         i = vsnrprintf(dev->__si_namebuf, sizeof dev->__si_namebuf, 32, fmt, ap);
  825         if (i > (sizeof dev->__si_namebuf - 1)) {
  826                 printf("WARNING: Device name truncated! (%s)\n", 
  827                     dev->__si_namebuf);
  828         }
  829         va_end(ap);
  830 
  831         devfs_create(dev);
  832         dev_dependsl(pdev, dev);
  833         clean_unrhdrl(devfs_inos);
  834         dev_unlock();
  835 
  836         notify_create(dev);
  837 
  838         return (dev);
  839 }
  840 
  841 static void
  842 destroy_devl(struct cdev *dev)
  843 {
  844         struct cdevsw *csw;
  845         struct cdev_privdata *p, *p1;
  846 
  847         mtx_assert(&devmtx, MA_OWNED);
  848         KASSERT(dev->si_flags & SI_NAMED,
  849             ("WARNING: Driver mistake: destroy_dev on %d\n", minor(dev)));
  850 
  851         devfs_destroy(dev);
  852 
  853         /* Remove name marking */
  854         dev->si_flags &= ~SI_NAMED;
  855 
  856         /* If we are a child, remove us from the parents list */
  857         if (dev->si_flags & SI_CHILD) {
  858                 LIST_REMOVE(dev, si_siblings);
  859                 dev->si_flags &= ~SI_CHILD;
  860         }
  861 
  862         /* Kill our children */
  863         while (!LIST_EMPTY(&dev->si_children))
  864                 destroy_devl(LIST_FIRST(&dev->si_children));
  865 
  866         /* Remove from clone list */
  867         if (dev->si_flags & SI_CLONELIST) {
  868                 LIST_REMOVE(dev, si_clone);
  869                 dev->si_flags &= ~SI_CLONELIST;
  870         }
  871 
  872         dev->si_refcount++;     /* Avoid race with dev_rel() */
  873         csw = dev->si_devsw;
  874         dev->si_devsw = NULL;   /* already NULL for SI_ALIAS */
  875         while (csw != NULL && csw->d_purge != NULL && dev->si_threadcount) {
  876                 csw->d_purge(dev);
  877                 msleep(csw, &devmtx, PRIBIO, "devprg", hz/10);
  878                 if (dev->si_threadcount)
  879                         printf("Still %lu threads in %s\n",
  880                             dev->si_threadcount, devtoname(dev));
  881         }
  882         while (dev->si_threadcount != 0) {
  883                 /* Use unique dummy wait ident */
  884                 msleep(&csw, &devmtx, PRIBIO, "devdrn", hz / 10);
  885         }
  886 
  887         dev_unlock();
  888         notify_destroy(dev);
  889         mtx_lock(&cdevpriv_mtx);
  890         LIST_FOREACH_SAFE(p, &dev->si_priv->cdp_fdpriv, cdpd_list, p1) {
  891                 devfs_destroy_cdevpriv(p);
  892                 mtx_lock(&cdevpriv_mtx);
  893         }
  894         mtx_unlock(&cdevpriv_mtx);
  895         dev_lock();
  896 
  897         dev->si_drv1 = 0;
  898         dev->si_drv2 = 0;
  899         bzero(&dev->__si_u, sizeof(dev->__si_u));
  900 
  901         if (!(dev->si_flags & SI_ALIAS)) {
  902                 /* Remove from cdevsw list */
  903                 LIST_REMOVE(dev, si_list);
  904 
  905                 /* If cdevsw has no more struct cdev *'s, clean it */
  906                 if (LIST_EMPTY(&csw->d_devs)) {
  907                         fini_cdevsw(csw);
  908                         wakeup(&csw->d_devs);
  909                 }
  910         }
  911         dev->si_flags &= ~SI_ALIAS;
  912         dev->si_refcount--;     /* Avoid race with dev_rel() */
  913 
  914         if (dev->si_refcount > 0) {
  915                 LIST_INSERT_HEAD(&dead_cdevsw.d_devs, dev, si_list);
  916         } else {
  917                 dev_free_devlocked(dev);
  918         }
  919 }
  920 
  921 void
  922 destroy_dev(struct cdev *dev)
  923 {
  924 
  925         dev_lock();
  926         destroy_devl(dev);
  927         dev_unlock_and_free();
  928 }
  929 
  930 const char *
  931 devtoname(struct cdev *dev)
  932 {
  933         char *p;
  934         struct cdevsw *csw;
  935         int mynor;
  936 
  937         if (dev->si_name[0] == '#' || dev->si_name[0] == '\0') {
  938                 p = dev->si_name;
  939                 csw = dev_refthread(dev);
  940                 if (csw != NULL) {
  941                         sprintf(p, "(%s)", csw->d_name);
  942                         dev_relthread(dev);
  943                 }
  944                 p += strlen(p);
  945                 mynor = minor(dev);
  946                 if (mynor < 0 || mynor > 255)
  947                         sprintf(p, "/%#x", (u_int)mynor);
  948                 else
  949                         sprintf(p, "/%d", mynor);
  950         }
  951         return (dev->si_name);
  952 }
  953 
  954 int
  955 dev_stdclone(char *name, char **namep, const char *stem, int *unit)
  956 {
  957         int u, i;
  958 
  959         i = strlen(stem);
  960         if (bcmp(stem, name, i) != 0)
  961                 return (0);
  962         if (!isdigit(name[i]))
  963                 return (0);
  964         u = 0;
  965         if (name[i] == '' && isdigit(name[i+1]))
  966                 return (0);
  967         while (isdigit(name[i])) {
  968                 u *= 10;
  969                 u += name[i++] - '';
  970         }
  971         if (u > 0xffffff)
  972                 return (0);
  973         *unit = u;
  974         if (namep)
  975                 *namep = &name[i];
  976         if (name[i]) 
  977                 return (2);
  978         return (1);
  979 }
  980 
  981 /*
  982  * Helper functions for cloning device drivers.
  983  *
  984  * The objective here is to make it unnecessary for the device drivers to
  985  * use rman or similar to manage their unit number space.  Due to the way
  986  * we do "on-demand" devices, using rman or other "private" methods 
  987  * will be very tricky to lock down properly once we lock down this file.
  988  *
  989  * Instead we give the drivers these routines which puts the struct cdev *'s
  990  * that are to be managed on their own list, and gives the driver the ability
  991  * to ask for the first free unit number or a given specified unit number.
  992  *
  993  * In addition these routines support paired devices (pty, nmdm and similar)
  994  * by respecting a number of "flag" bits in the minor number.
  995  *
  996  */
  997 
  998 struct clonedevs {
  999         LIST_HEAD(,cdev)        head;
 1000 };
 1001 
 1002 void
 1003 clone_setup(struct clonedevs **cdp)
 1004 {
 1005 
 1006         *cdp = malloc(sizeof **cdp, M_DEVBUF, M_WAITOK | M_ZERO);
 1007         LIST_INIT(&(*cdp)->head);
 1008 }
 1009 
 1010 int
 1011 clone_create(struct clonedevs **cdp, struct cdevsw *csw, int *up, struct cdev **dp, int extra)
 1012 {
 1013         struct clonedevs *cd;
 1014         struct cdev *dev, *ndev, *dl, *de;
 1015         int unit, low, u;
 1016 
 1017         KASSERT(*cdp != NULL,
 1018             ("clone_setup() not called in driver \"%s\"", csw->d_name));
 1019         KASSERT(!(extra & CLONE_UNITMASK),
 1020             ("Illegal extra bits (0x%x) in clone_create", extra));
 1021         KASSERT(*up <= CLONE_UNITMASK,
 1022             ("Too high unit (0x%x) in clone_create", *up));
 1023 
 1024 
 1025         /*
 1026          * Search the list for a lot of things in one go:
 1027          *   A preexisting match is returned immediately.
 1028          *   The lowest free unit number if we are passed -1, and the place
 1029          *       in the list where we should insert that new element.
 1030          *   The place to insert a specified unit number, if applicable
 1031          *       the end of the list.
 1032          */
 1033         unit = *up;
 1034         ndev = devfs_alloc();
 1035         dev_lock();
 1036         prep_cdevsw(csw);
 1037         low = extra;
 1038         de = dl = NULL;
 1039         cd = *cdp;
 1040         LIST_FOREACH(dev, &cd->head, si_clone) {
 1041                 KASSERT(dev->si_flags & SI_CLONELIST,
 1042                     ("Dev %p(%s) should be on clonelist", dev, dev->si_name));
 1043                 u = dev2unit(dev);
 1044                 if (u == (unit | extra)) {
 1045                         *dp = dev;
 1046                         dev_unlock();
 1047                         devfs_free(ndev);
 1048                         return (0);
 1049                 }
 1050                 if (unit == -1 && u == low) {
 1051                         low++;
 1052                         de = dev;
 1053                         continue;
 1054                 } else if (u < (unit | extra)) {
 1055                         de = dev;
 1056                         continue;
 1057                 } else if (u > (unit | extra)) {
 1058                         dl = dev;
 1059                         break;
 1060                 }
 1061         }
 1062         if (unit == -1)
 1063                 unit = low & CLONE_UNITMASK;
 1064         dev = newdev(csw, unit2minor(unit | extra), ndev);
 1065         if (dev->si_flags & SI_CLONELIST) {
 1066                 printf("dev %p (%s) is on clonelist\n", dev, dev->si_name);
 1067                 printf("unit=%d, low=%d, extra=0x%x\n", unit, low, extra);
 1068                 LIST_FOREACH(dev, &cd->head, si_clone) {
 1069                         printf("\t%p %s\n", dev, dev->si_name);
 1070                 }
 1071                 panic("foo");
 1072         }
 1073         KASSERT(!(dev->si_flags & SI_CLONELIST),
 1074             ("Dev %p(%s) should not be on clonelist", dev, dev->si_name));
 1075         if (dl != NULL)
 1076                 LIST_INSERT_BEFORE(dl, dev, si_clone);
 1077         else if (de != NULL)
 1078                 LIST_INSERT_AFTER(de, dev, si_clone);
 1079         else
 1080                 LIST_INSERT_HEAD(&cd->head, dev, si_clone);
 1081         dev->si_flags |= SI_CLONELIST;
 1082         *up = unit;
 1083         dev_unlock_and_free();
 1084         return (1);
 1085 }
 1086 
 1087 /*
 1088  * Kill everything still on the list.  The driver should already have
 1089  * disposed of any softc hung of the struct cdev *'s at this time.
 1090  */
 1091 void
 1092 clone_cleanup(struct clonedevs **cdp)
 1093 {
 1094         struct cdev *dev;
 1095         struct cdev_priv *cp;
 1096         struct clonedevs *cd;
 1097         
 1098         cd = *cdp;
 1099         if (cd == NULL)
 1100                 return;
 1101         dev_lock();
 1102         while (!LIST_EMPTY(&cd->head)) {
 1103                 dev = LIST_FIRST(&cd->head);
 1104                 LIST_REMOVE(dev, si_clone);
 1105                 KASSERT(dev->si_flags & SI_CLONELIST,
 1106                     ("Dev %p(%s) should be on clonelist", dev, dev->si_name));
 1107                 dev->si_flags &= ~SI_CLONELIST;
 1108                 cp = dev->si_priv;
 1109                 if (!(cp->cdp_flags & CDP_SCHED_DTR)) {
 1110                         cp->cdp_flags |= CDP_SCHED_DTR;
 1111                         KASSERT(dev->si_flags & SI_NAMED,
 1112                                 ("Driver has goofed in cloning underways udev %x", dev->si_drv0));
 1113                         destroy_devl(dev);
 1114                 }
 1115         }
 1116         dev_unlock_and_free();
 1117         free(cd, M_DEVBUF);
 1118         *cdp = NULL;
 1119 }
 1120 
 1121 static TAILQ_HEAD(, cdev_priv) dev_ddtr =
 1122         TAILQ_HEAD_INITIALIZER(dev_ddtr);
 1123 static struct task dev_dtr_task;
 1124 
 1125 static void
 1126 destroy_dev_tq(void *ctx, int pending)
 1127 {
 1128         struct cdev_priv *cp;
 1129         struct cdev *dev;
 1130         void (*cb)(void *);
 1131         void *cb_arg;
 1132 
 1133         dev_lock();
 1134         while (!TAILQ_EMPTY(&dev_ddtr)) {
 1135                 cp = TAILQ_FIRST(&dev_ddtr);
 1136                 dev = &cp->cdp_c;
 1137                 KASSERT(cp->cdp_flags & CDP_SCHED_DTR,
 1138                     ("cdev %p in dev_destroy_tq without CDP_SCHED_DTR", cp));
 1139                 TAILQ_REMOVE(&dev_ddtr, cp, cdp_dtr_list);
 1140                 cb = cp->cdp_dtr_cb;
 1141                 cb_arg = cp->cdp_dtr_cb_arg;
 1142                 destroy_devl(dev);
 1143                 dev_unlock_and_free();
 1144                 dev_rel(dev);
 1145                 if (cb != NULL)
 1146                         cb(cb_arg);
 1147                 dev_lock();
 1148         }
 1149         dev_unlock();
 1150 }
 1151 
 1152 /*
 1153  * devmtx shall be locked on entry. devmtx will be unlocked after
 1154  * function return.
 1155  */
 1156 static int
 1157 destroy_dev_sched_cbl(struct cdev *dev, void (*cb)(void *), void *arg)
 1158 {
 1159         struct cdev_priv *cp;
 1160 
 1161         mtx_assert(&devmtx, MA_OWNED);
 1162         cp = dev->si_priv;
 1163         if (cp->cdp_flags & CDP_SCHED_DTR) {
 1164                 dev_unlock();
 1165                 return (0);
 1166         }
 1167         dev_refl(dev);
 1168         cp->cdp_flags |= CDP_SCHED_DTR;
 1169         cp->cdp_dtr_cb = cb;
 1170         cp->cdp_dtr_cb_arg = arg;
 1171         TAILQ_INSERT_TAIL(&dev_ddtr, cp, cdp_dtr_list);
 1172         dev_unlock();
 1173         taskqueue_enqueue(taskqueue_swi_giant, &dev_dtr_task);
 1174         return (1);
 1175 }
 1176 
 1177 int
 1178 destroy_dev_sched_cb(struct cdev *dev, void (*cb)(void *), void *arg)
 1179 {
 1180         dev_lock();
 1181         return (destroy_dev_sched_cbl(dev, cb, arg));
 1182 }
 1183 
 1184 int
 1185 destroy_dev_sched(struct cdev *dev)
 1186 {
 1187         return (destroy_dev_sched_cb(dev, NULL, NULL));
 1188 }
 1189 
 1190 void
 1191 destroy_dev_drain(struct cdevsw *csw)
 1192 {
 1193 
 1194         dev_lock();
 1195         while (!LIST_EMPTY(&csw->d_devs)) {
 1196                 msleep(&csw->d_devs, &devmtx, PRIBIO, "devscd", hz/10);
 1197         }
 1198         dev_unlock();
 1199 }
 1200 
 1201 void
 1202 drain_dev_clone_events(void)
 1203 {
 1204 
 1205         sx_xlock(&clone_drain_lock);
 1206         sx_xunlock(&clone_drain_lock);
 1207 }
 1208 
 1209 static void
 1210 devdtr_init(void *dummy __unused)
 1211 {
 1212 
 1213         TASK_INIT(&dev_dtr_task, 0, destroy_dev_tq, NULL);
 1214 }
 1215 
 1216 SYSINIT(devdtr, SI_SUB_DEVFS, SI_ORDER_SECOND, devdtr_init, NULL);

Cache object: 75e4770856d39085fe7f0404e8162c20


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