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/geom/geom_dev.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) 2002 Poul-Henning Kamp
    3  * Copyright (c) 2002 Networks Associates Technology, Inc.
    4  * All rights reserved.
    5  *
    6  * This software was developed for the FreeBSD Project by Poul-Henning Kamp
    7  * and NAI Labs, the Security Research Division of Network Associates, Inc.
    8  * under DARPA/SPAWAR contract N66001-01-C-8035 ("CBOSS"), as part of the
    9  * DARPA CHATS research program.
   10  *
   11  * Redistribution and use in source and binary forms, with or without
   12  * modification, are permitted provided that the following conditions
   13  * are met:
   14  * 1. Redistributions of source code must retain the above copyright
   15  *    notice, this list of conditions and the following disclaimer.
   16  * 2. Redistributions in binary form must reproduce the above copyright
   17  *    notice, this list of conditions and the following disclaimer in the
   18  *    documentation and/or other materials provided with the distribution.
   19  * 3. The names of the authors may not be used to endorse or promote
   20  *    products derived from this software without specific prior written
   21  *    permission.
   22  *
   23  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
   24  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   25  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   26  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
   27  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   28  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   29  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   30  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   31  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   32  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   33  * SUCH DAMAGE.
   34  */
   35 
   36 #include <sys/cdefs.h>
   37 __FBSDID("$FreeBSD: releng/5.2/sys/geom/geom_dev.c 121253 2003-10-19 19:06:54Z phk $");
   38 
   39 #include <sys/param.h>
   40 #include <sys/systm.h>
   41 #include <sys/malloc.h>
   42 #include <sys/kernel.h>
   43 #include <sys/conf.h>
   44 #include <sys/bio.h>
   45 #include <sys/lock.h>
   46 #include <sys/mutex.h>
   47 #include <sys/errno.h>
   48 #include <sys/time.h>
   49 #include <sys/disk.h>
   50 #include <sys/fcntl.h>
   51 #include <sys/limits.h>
   52 #include <geom/geom.h>
   53 #include <geom/geom_int.h>
   54 
   55 static d_open_t         g_dev_open;
   56 static d_close_t        g_dev_close;
   57 static d_strategy_t     g_dev_strategy;
   58 static d_ioctl_t        g_dev_ioctl;
   59 
   60 static struct cdevsw g_dev_cdevsw = {
   61         .d_open =       g_dev_open,
   62         .d_close =      g_dev_close,
   63         .d_read =       physread,
   64         .d_write =      physwrite,
   65         .d_ioctl =      g_dev_ioctl,
   66         .d_strategy =   g_dev_strategy,
   67         .d_name =       "g_dev",
   68         .d_maj =        GEOM_MAJOR,
   69         .d_flags =      D_DISK | D_TRACKCLOSE | D_NOGIANT,
   70 };
   71 
   72 static g_taste_t g_dev_taste;
   73 static g_orphan_t g_dev_orphan;
   74 
   75 static struct g_class g_dev_class       = {
   76         .name = "DEV",
   77         .taste = g_dev_taste,
   78 };
   79 
   80 void
   81 g_dev_print(void)
   82 {
   83         struct g_geom *gp;
   84         char const *p = "";
   85 
   86         LIST_FOREACH(gp, &g_dev_class.geom, geom) {
   87                 printf("%s%s", p, gp->name);
   88                 p = " ";
   89         }
   90         printf("\n");
   91 }
   92 
   93 /*
   94  * XXX: This is disgusting and wrong in every way imaginable:  The only reason
   95  * XXX: we have a clone function is because of the root-mount hack we currently
   96  * XXX: employ.  An improvment would be to unregister this cloner once we know
   97  * XXX: we no longer need it.  Ideally, root-fs would be mounted through DEVFS
   98  * XXX: eliminating the need for this hack.
   99  */
  100 static void
  101 g_dev_clone(void *arg __unused, char *name, int namelen __unused, dev_t *dev)
  102 {
  103         struct g_geom *gp;
  104 
  105         if (*dev != NODEV)
  106                 return;
  107 
  108         g_waitidle();
  109 
  110         /* g_topology_lock(); */
  111         LIST_FOREACH(gp, &g_dev_class.geom, geom) {
  112                 if (strcmp(gp->name, name))
  113                         continue;
  114                 *dev = gp->softc;
  115                 g_trace(G_T_TOPOLOGY, "g_dev_clone(%s) = %p", name, *dev);
  116                 return;
  117         }
  118         /* g_topology_unlock(); */
  119         return;
  120 }
  121 
  122 static void
  123 g_dev_register_cloner(void *foo __unused)
  124 {
  125         static int once;
  126 
  127         /* XXX: why would this happen more than once ?? */
  128         if (!once) {
  129                 EVENTHANDLER_REGISTER(dev_clone, g_dev_clone, 0, 1000);
  130                 once++;
  131         }
  132 }
  133 
  134 SYSINIT(geomdev,SI_SUB_DRIVERS,SI_ORDER_MIDDLE,g_dev_register_cloner,NULL);
  135 
  136 struct g_provider *
  137 g_dev_getprovider(dev_t dev)
  138 {
  139         struct g_consumer *cp;
  140 
  141         if (dev == NULL)
  142                 return (NULL);
  143         if (devsw(dev) != &g_dev_cdevsw)
  144                 return (NULL);
  145         cp = dev->si_drv2;
  146         return (cp->provider);
  147 }
  148 
  149 
  150 static struct g_geom *
  151 g_dev_taste(struct g_class *mp, struct g_provider *pp, int insist __unused)
  152 {
  153         struct g_geom *gp;
  154         struct g_consumer *cp;
  155         static int unit = GEOM_MINOR_PROVIDERS;
  156         int error;
  157         dev_t dev;
  158 
  159         g_trace(G_T_TOPOLOGY, "dev_taste(%s,%s)", mp->name, pp->name);
  160         g_topology_assert();
  161         LIST_FOREACH(cp, &pp->consumers, consumers)
  162                 if (cp->geom->class == mp)
  163                         return (NULL);
  164         gp = g_new_geomf(mp, pp->name);
  165         gp->orphan = g_dev_orphan;
  166         cp = g_new_consumer(gp);
  167         error = g_attach(cp, pp);
  168         KASSERT(error == 0,
  169             ("g_dev_taste(%s) failed to g_attach, err=%d", pp->name, error));
  170         /*
  171          * XXX: I'm not 100% sure we can call make_dev(9) without Giant
  172          * yet.  Once we can, we don't need to drop topology here either.
  173          */
  174         g_topology_unlock();
  175         mtx_lock(&Giant);
  176         dev = make_dev(&g_dev_cdevsw, unit2minor(unit++),
  177             UID_ROOT, GID_OPERATOR, 0640, gp->name);
  178         if (pp->flags & G_PF_CANDELETE)
  179                 dev->si_flags |= SI_CANDELETE;
  180         mtx_unlock(&Giant);
  181         g_topology_lock();
  182         dev->si_iosize_max = MAXPHYS;
  183         dev->si_stripesize = pp->stripesize;
  184         dev->si_stripeoffset = pp->stripeoffset;
  185         gp->softc = dev;
  186         dev->si_drv1 = gp;
  187         dev->si_drv2 = cp;
  188         return (gp);
  189 }
  190 
  191 static int
  192 g_dev_open(dev_t dev, int flags, int fmt, struct thread *td)
  193 {
  194         struct g_geom *gp;
  195         struct g_consumer *cp;
  196         int error, r, w, e;
  197 
  198         gp = dev->si_drv1;
  199         cp = dev->si_drv2;
  200         if (gp == NULL || cp == NULL || gp->softc != dev)
  201                 return(ENXIO);          /* g_dev_taste() not done yet */
  202 
  203         g_trace(G_T_ACCESS, "g_dev_open(%s, %d, %d, %p)",
  204             gp->name, flags, fmt, td);
  205         r = flags & FREAD ? 1 : 0;
  206         w = flags & FWRITE ? 1 : 0;
  207 #ifdef notyet
  208         e = flags & O_EXCL ? 1 : 0;
  209 #else
  210         e = 0;
  211 #endif
  212         g_topology_lock();
  213         if (dev->si_devsw == NULL)
  214                 error = ENXIO;          /* We were orphaned */
  215         else
  216                 error = g_access_rel(cp, r, w, e);
  217         g_topology_unlock();
  218         g_waitidle();
  219         if (!error)
  220                 dev->si_bsize_phys = cp->provider->sectorsize;
  221         return(error);
  222 }
  223 
  224 static int
  225 g_dev_close(dev_t dev, int flags, int fmt, struct thread *td)
  226 {
  227         struct g_geom *gp;
  228         struct g_consumer *cp;
  229         int error, r, w, e, i;
  230 
  231         gp = dev->si_drv1;
  232         cp = dev->si_drv2;
  233         if (gp == NULL || cp == NULL)
  234                 return(ENXIO);
  235         g_trace(G_T_ACCESS, "g_dev_close(%s, %d, %d, %p)",
  236             gp->name, flags, fmt, td);
  237         r = flags & FREAD ? -1 : 0;
  238         w = flags & FWRITE ? -1 : 0;
  239 #ifdef notyet
  240         e = flags & O_EXCL ? -1 : 0;
  241 #else
  242         e = 0;
  243 #endif
  244         g_topology_lock();
  245         if (dev->si_devsw == NULL)
  246                 error = ENXIO;          /* We were orphaned */
  247         else
  248                 error = g_access_rel(cp, r, w, e);
  249         for (i = 0; i < 10 * hz;) {
  250                 if (cp->acr != 0 || cp->acw != 0)
  251                         break;
  252                 if (cp->nstart == cp->nend)
  253                         break;
  254                 tsleep(&i, PRIBIO, "gdevwclose", hz / 10);
  255                 i += hz / 10;
  256         }
  257         if (cp->acr == 0 && cp->acw == 0 && cp->nstart != cp->nend) {
  258                 printf("WARNING: Final close of geom_dev(%s) %s %s",
  259                     gp->name,
  260                     "still has outstanding I/O after 10 seconds.",
  261                     "Completing close anyway, panic may happen later.");
  262         }
  263         g_topology_unlock();
  264         g_waitidle();
  265         return (error);
  266 }
  267 
  268 /*
  269  * XXX: Until we have unmessed the ioctl situation, there is a race against
  270  * XXX: a concurrent orphanization.  We cannot close it by holding topology
  271  * XXX: since that would prevent us from doing our job, and stalling events
  272  * XXX: will break (actually: stall) the BSD disklabel hacks.
  273  */
  274 static int
  275 g_dev_ioctl(dev_t dev, u_long cmd, caddr_t data, int fflag, struct thread *td)
  276 {
  277         struct g_geom *gp;
  278         struct g_consumer *cp;
  279         struct g_kerneldump kd;
  280         int i, error;
  281         u_int u;
  282 
  283         gp = dev->si_drv1;
  284         cp = dev->si_drv2;
  285 
  286         error = 0;
  287         KASSERT(cp->acr || cp->acw,
  288             ("Consumer with zero access count in g_dev_ioctl"));
  289 
  290         i = IOCPARM_LEN(cmd);
  291         switch (cmd) {
  292         case DIOCGSECTORSIZE:
  293                 *(u_int *)data = cp->provider->sectorsize;
  294                 if (*(u_int *)data == 0)
  295                         error = ENOENT;
  296                 break;
  297         case DIOCGMEDIASIZE:
  298                 *(off_t *)data = cp->provider->mediasize;
  299                 if (*(off_t *)data == 0)
  300                         error = ENOENT;
  301                 break;
  302         case DIOCGFWSECTORS:
  303                 error = g_io_getattr("GEOM::fwsectors", cp, &i, data);
  304                 if (error == 0 && *(u_int *)data == 0)
  305                         error = ENOENT;
  306                 break;
  307         case DIOCGFWHEADS:
  308                 error = g_io_getattr("GEOM::fwheads", cp, &i, data);
  309                 if (error == 0 && *(u_int *)data == 0)
  310                         error = ENOENT;
  311                 break;
  312         case DIOCGFRONTSTUFF:
  313                 error = g_io_getattr("GEOM::frontstuff", cp, &i, data);
  314                 break;
  315         case DIOCSKERNELDUMP:
  316                 u = *((u_int *)data);
  317                 if (!u) {
  318                         set_dumper(NULL);
  319                         error = 0;
  320                         break;
  321                 }
  322                 kd.offset = 0;
  323                 kd.length = OFF_MAX;
  324                 i = sizeof kd;
  325                 error = g_io_getattr("GEOM::kerneldump", cp, &i, &kd);
  326                 if (!error)
  327                         dev->si_flags |= SI_DUMPDEV;
  328                 break;
  329 
  330         default:
  331                 if (cp->provider->geom->ioctl != NULL) {
  332                         error = cp->provider->geom->ioctl(cp->provider, cmd, data, td);
  333                 } else {
  334                         error = ENOIOCTL;
  335                 }
  336         }
  337 
  338         g_waitidle();
  339         return (error);
  340 }
  341 
  342 static void
  343 g_dev_done(struct bio *bp2)
  344 {
  345         struct bio *bp;
  346 
  347         bp = bp2->bio_parent;
  348         bp->bio_error = bp2->bio_error;
  349         if (bp->bio_error != 0) {
  350                 g_trace(G_T_BIO, "g_dev_done(%p) had error %d",
  351                     bp2, bp->bio_error);
  352                 bp->bio_flags |= BIO_ERROR;
  353         } else {
  354                 g_trace(G_T_BIO, "g_dev_done(%p/%p) resid %ld completed %jd",
  355                     bp2, bp, bp->bio_resid, (intmax_t)bp2->bio_completed);
  356         }
  357         bp->bio_resid = bp->bio_bcount - bp2->bio_completed;
  358         g_destroy_bio(bp2);
  359         biodone(bp);
  360 }
  361 
  362 static void
  363 g_dev_strategy(struct bio *bp)
  364 {
  365         struct g_consumer *cp;
  366         struct bio *bp2;
  367         dev_t dev;
  368 
  369         KASSERT(bp->bio_cmd == BIO_READ ||
  370                 bp->bio_cmd == BIO_WRITE ||
  371                 bp->bio_cmd == BIO_DELETE,
  372                 ("Wrong bio_cmd bio=%p cmd=%d", bp, bp->bio_cmd));
  373         dev = bp->bio_dev;
  374         cp = dev->si_drv2;
  375         KASSERT(cp->acr || cp->acw,
  376             ("Consumer with zero access count in g_dev_strategy"));
  377 
  378         for (;;) {
  379                 /*
  380                  * XXX: This is not an ideal solution, but I belive it to
  381                  * XXX: deadlock safe, all things considered.
  382                  */
  383                 bp2 = g_clone_bio(bp);
  384                 if (bp2 != NULL)
  385                         break;
  386                 tsleep(&bp, PRIBIO, "gdstrat", hz / 10);
  387         }
  388         KASSERT(bp2 != NULL, ("XXX: ENOMEM in a bad place"));
  389         bp2->bio_length = (off_t)bp->bio_bcount;
  390         bp2->bio_done = g_dev_done;
  391         g_trace(G_T_BIO,
  392             "g_dev_strategy(%p/%p) offset %jd length %jd data %p cmd %d",
  393             bp, bp2, (intmax_t)bp->bio_offset, (intmax_t)bp2->bio_length,
  394             bp2->bio_data, bp2->bio_cmd);
  395         g_io_request(bp2, cp);
  396         KASSERT(cp->acr || cp->acw,
  397             ("g_dev_strategy raced with g_dev_close and lost"));
  398 
  399 }
  400 
  401 /*
  402  * g_dev_orphan()
  403  *
  404  * Called from below when the provider orphaned us.
  405  * - Clear any dump settings.
  406  * - Destroy the dev_t to prevent any more request from coming in.  The
  407  *   provider is already marked with an error, so anything which comes in
  408  *   in the interrim will be returned immediately.
  409  * - Wait for any outstanding I/O to finish.
  410  * - Set our access counts to zero, whatever they were.
  411  * - Detach and self-destruct.
  412  */
  413 
  414 static void
  415 g_dev_orphan(struct g_consumer *cp)
  416 {
  417         struct g_geom *gp;
  418         dev_t dev;
  419 
  420         g_topology_assert();
  421         gp = cp->geom;
  422         dev = gp->softc;
  423         g_trace(G_T_TOPOLOGY, "g_dev_orphan(%p(%s))", cp, gp->name);
  424 
  425         /* Reset any dump-area set on this device */
  426         if (dev->si_flags & SI_DUMPDEV)
  427                 set_dumper(NULL);
  428 
  429         /* Destroy the dev_t so we get no more requests */
  430         destroy_dev(dev);
  431 
  432         /* Wait for the cows to come home */
  433         while (cp->nstart != cp->nend)
  434                 msleep(&dev, NULL, PRIBIO, "gdevorphan", hz / 10);
  435 
  436         if (cp->acr > 0 || cp->acw > 0 || cp->ace > 0)
  437                 g_access_rel(cp, -cp->acr, -cp->acw, -cp->ace);
  438 
  439         g_detach(cp);
  440         g_destroy_consumer(cp);
  441         g_destroy_geom(gp);
  442 }
  443 
  444 DECLARE_GEOM_CLASS(g_dev_class, g_dev);

Cache object: 27ec8f40fc2057b05a07fb39968304e8


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