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  * $FreeBSD: releng/5.0/sys/geom/geom_dev.c 109193 2003-01-13 21:04:15Z phk $
   36  */
   37 
   38 #include <sys/param.h>
   39 #include <sys/stdint.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 <geom/geom.h>
   52 #include <geom/geom_int.h>
   53 #include <machine/limits.h>
   54 
   55 #define CDEV_MAJOR      4
   56 
   57 static d_open_t         g_dev_open;
   58 static d_close_t        g_dev_close;
   59 static d_strategy_t     g_dev_strategy;
   60 static d_ioctl_t        g_dev_ioctl;
   61 static d_psize_t        g_dev_psize;
   62 
   63 static struct cdevsw g_dev_cdevsw = {
   64         /* open */      g_dev_open,
   65         /* close */     g_dev_close,
   66         /* read */      physread,
   67         /* write */     physwrite,
   68         /* ioctl */     g_dev_ioctl,
   69         /* poll */      nopoll,
   70         /* mmap */      nommap,
   71         /* strategy */  g_dev_strategy,
   72         /* name */      "g_dev",
   73         /* maj */       CDEV_MAJOR,
   74         /* dump */      nodump,
   75         /* psize */     g_dev_psize,
   76         /* flags */     D_DISK | D_CANFREE | D_TRACKCLOSE,
   77         /* kqfilter */  nokqfilter
   78 };
   79 
   80 static g_taste_t g_dev_taste;
   81 static g_orphan_t g_dev_orphan;
   82 
   83 static struct g_class g_dev_class       = {
   84         "DEV",
   85         g_dev_taste,
   86         NULL,
   87         G_CLASS_INITIALIZER
   88 };
   89 
   90 int
   91 g_dev_print(void)
   92 {
   93         struct g_geom *gp;
   94 
   95         if (LIST_EMPTY(&g_dev_class.geom))
   96                 return (0);
   97         printf("List of GEOM disk devices:\n  ");
   98         LIST_FOREACH(gp, &g_dev_class.geom, geom)
   99                 printf(" %s", gp->name);
  100         printf("\n");
  101         return (1);
  102 }
  103 
  104 static void
  105 g_dev_clone(void *arg __unused, char *name, int namelen __unused, dev_t *dev)
  106 {
  107         struct g_geom *gp;
  108 
  109         if (*dev != NODEV)
  110                 return;
  111 
  112         g_waitidle();
  113 
  114         /* XXX: can I drop Giant here ??? */
  115         /* g_topology_lock(); */
  116         LIST_FOREACH(gp, &g_dev_class.geom, geom) {
  117                 if (strcmp(gp->name, name))
  118                         continue;
  119                 *dev = gp->softc;
  120                 g_trace(G_T_TOPOLOGY, "g_dev_clone(%s) = %p", name, *dev);
  121                 return;
  122         }
  123         /* g_topology_unlock(); */
  124         return;
  125 }
  126 
  127 static void
  128 g_dev_register_cloner(void *foo __unused)
  129 {
  130         static int once;
  131 
  132         /* XXX: why would this happen more than once ?? */
  133         if (!once) {
  134                 EVENTHANDLER_REGISTER(dev_clone, g_dev_clone, 0, 1000);
  135                 once++;
  136         }
  137 }
  138 
  139 SYSINIT(geomdev,SI_SUB_DRIVERS,SI_ORDER_MIDDLE,g_dev_register_cloner,NULL);
  140 
  141 static struct g_geom *
  142 g_dev_taste(struct g_class *mp, struct g_provider *pp, int insist __unused)
  143 {
  144         struct g_geom *gp;
  145         struct g_consumer *cp;
  146         static int unit;
  147         int error;
  148         dev_t dev;
  149 
  150         g_trace(G_T_TOPOLOGY, "dev_taste(%s,%s)", mp->name, pp->name);
  151         g_topology_assert();
  152         LIST_FOREACH(cp, &pp->consumers, consumers)
  153                 if (cp->geom->class == mp)
  154                         return (NULL);
  155         gp = g_new_geomf(mp, pp->name);
  156         gp->orphan = g_dev_orphan;
  157         cp = g_new_consumer(gp);
  158         error = g_attach(cp, pp);
  159         KASSERT(error == 0,
  160             ("g_dev_taste(%s) failed to g_attach, err=%d", pp->name, error));
  161         /*
  162          * XXX: I'm not 100% sure we can call make_dev(9) without Giant
  163          * yet.  Once we can, we don't need to drop topology here either.
  164          */
  165         g_topology_unlock();
  166         mtx_lock(&Giant);
  167         dev = make_dev(&g_dev_cdevsw, unit2minor(unit++),
  168             UID_ROOT, GID_OPERATOR, 0640, gp->name);
  169         mtx_unlock(&Giant);
  170         g_topology_lock();
  171 
  172         gp->softc = dev;
  173         dev->si_drv1 = gp;
  174         dev->si_drv2 = cp;
  175         return (gp);
  176 }
  177 
  178 static int
  179 g_dev_open(dev_t dev, int flags, int fmt, struct thread *td)
  180 {
  181         struct g_geom *gp;
  182         struct g_consumer *cp;
  183         int error, r, w, e;
  184 
  185         gp = dev->si_drv1;
  186         cp = dev->si_drv2;
  187         if (gp == NULL || cp == NULL)
  188                 return(ENXIO);
  189         g_trace(G_T_ACCESS, "g_dev_open(%s, %d, %d, %p)",
  190             gp->name, flags, fmt, td);
  191         DROP_GIANT();
  192         g_topology_lock();
  193         g_silence();
  194         r = flags & FREAD ? 1 : 0;
  195         w = flags & FWRITE ? 1 : 0;
  196 #ifdef notyet
  197         e = flags & O_EXCL ? 1 : 0;
  198 #else
  199         e = 0;
  200 #endif
  201         error = g_access_rel(cp, r, w, e);
  202         g_topology_unlock();
  203         PICKUP_GIANT();
  204         g_waitidle();
  205         dev->si_bsize_phys = cp->provider->sectorsize;
  206         return(error);
  207 }
  208 
  209 static int
  210 g_dev_close(dev_t dev, int flags, int fmt, struct thread *td)
  211 {
  212         struct g_geom *gp;
  213         struct g_consumer *cp;
  214         int error, r, w, e;
  215 
  216         gp = dev->si_drv1;
  217         cp = dev->si_drv2;
  218         if (gp == NULL || cp == NULL)
  219                 return(ENXIO);
  220         g_trace(G_T_ACCESS, "g_dev_close(%s, %d, %d, %p)",
  221             gp->name, flags, fmt, td);
  222         DROP_GIANT();
  223         g_topology_lock();
  224         g_silence();
  225         r = flags & FREAD ? -1 : 0;
  226         w = flags & FWRITE ? -1 : 0;
  227 #ifdef notyet
  228         e = flags & O_EXCL ? -1 : 0;
  229 #else
  230         e = 0;
  231 #endif
  232         error = g_access_rel(cp, r, w, e);
  233         g_topology_unlock();
  234         PICKUP_GIANT();
  235         g_waitidle();
  236         return (error);
  237 }
  238 
  239 static int
  240 g_dev_ioctl(dev_t dev, u_long cmd, caddr_t data, int fflag, struct thread *td)
  241 {
  242         struct g_geom *gp, *gp2;
  243         struct g_consumer *cp;
  244         struct g_provider *pp2;
  245         struct g_kerneldump kd;
  246         int i, error;
  247         u_int u;
  248         struct g_ioctl *gio;
  249 
  250         gp = dev->si_drv1;
  251         cp = dev->si_drv2;
  252         pp2 = cp->provider;
  253         gp2 = pp2->geom;
  254         gio = NULL;
  255 
  256         error = 0;
  257         DROP_GIANT();
  258 
  259         i = IOCPARM_LEN(cmd);
  260         switch (cmd) {
  261         case DIOCGSECTORSIZE:
  262                 *(u_int *)data = cp->provider->sectorsize;
  263                 if (*(u_int *)data == 0)
  264                         error = ENOENT;
  265                 break;
  266         case DIOCGMEDIASIZE:
  267                 *(off_t *)data = cp->provider->mediasize;
  268                 if (*(off_t *)data == 0)
  269                         error = ENOENT;
  270                 break;
  271         case DIOCGFWSECTORS:
  272                 error = g_io_getattr("GEOM::fwsectors", cp, &i, data);
  273                 if (error == 0 && *(u_int *)data == 0)
  274                         error = ENOENT;
  275                 break;
  276         case DIOCGFWHEADS:
  277                 error = g_io_getattr("GEOM::fwheads", cp, &i, data);
  278                 if (error == 0 && *(u_int *)data == 0)
  279                         error = ENOENT;
  280                 break;
  281         case DIOCGFRONTSTUFF:
  282                 error = g_io_getattr("GEOM::frontstuff", cp, &i, data);
  283                 break;
  284         case DIOCSKERNELDUMP:
  285                 u = *((u_int *)data);
  286                 if (!u) {
  287                         set_dumper(NULL);
  288                         error = 0;
  289                         break;
  290                 }
  291                 kd.offset = 0;
  292                 kd.length = OFF_MAX;
  293                 i = sizeof kd;
  294                 error = g_io_getattr("GEOM::kerneldump", cp, &i, &kd);
  295                 if (!error)
  296                         dev->si_flags |= SI_DUMPDEV;
  297                 break;
  298 
  299         default:
  300                 gio = g_malloc(sizeof *gio, M_WAITOK | M_ZERO);
  301                 gio->cmd = cmd;
  302                 gio->data = data;
  303                 gio->fflag = fflag;
  304                 gio->td = td;
  305                 i = sizeof *gio;
  306                 /*
  307                  * We always issue ioctls as getattr since the direction of data
  308                  * movement in ioctl is no indication of the ioctl being a "set"
  309                  * or "get" type ioctl or if such simplistic terms even apply
  310                  */
  311                 error = g_io_getattr("GEOM::ioctl", cp, &i, gio);
  312                 break;
  313         }
  314 
  315         PICKUP_GIANT();
  316         if (error == EDIRIOCTL) {
  317                 KASSERT(gio != NULL, ("NULL gio but EDIRIOCTL"));
  318                 KASSERT(gio->func != NULL, ("NULL function but EDIRIOCTL"));
  319                 error = (gio->func)(gio->dev, cmd, data, fflag, td);
  320         }
  321         if (gio != NULL)
  322                 g_free(gio);
  323         g_waitidle();
  324         if (error == ENOIOCTL) {
  325                 if (g_debugflags & G_T_TOPOLOGY) {
  326                         i = IOCGROUP(cmd);
  327                         printf("IOCTL(0x%lx) \"%s\"", cmd, gp->name);
  328                         if (i > ' ' && i <= '~')
  329                                 printf(" '%c'", (int)IOCGROUP(cmd));
  330                         else
  331                                 printf(" 0x%lx", IOCGROUP(cmd));
  332                         printf("/%ld ", cmd & 0xff);
  333                         if (cmd & IOC_IN)
  334                                 printf("I");
  335                         if (cmd & IOC_OUT)
  336                                 printf("O");
  337                         printf("(%ld) = ENOIOCTL\n", IOCPARM_LEN(cmd));
  338                 }
  339                 error = ENOTTY;
  340         }
  341         return (error);
  342 }
  343 
  344 static int
  345 g_dev_psize(dev_t dev)
  346 {
  347         struct g_consumer *cp;
  348         off_t mediasize;
  349 
  350         cp = dev->si_drv2;
  351 
  352         mediasize = cp->provider->mediasize;
  353         return (mediasize >> DEV_BSHIFT);
  354 }
  355 
  356 static void
  357 g_dev_done(struct bio *bp2)
  358 {
  359         struct bio *bp;
  360 
  361         bp = bp2->bio_linkage;
  362         bp->bio_error = bp2->bio_error;
  363         if (bp->bio_error != 0) {
  364                 g_trace(G_T_BIO, "g_dev_done(%p) had error %d",
  365                     bp2, bp->bio_error);
  366                 bp->bio_flags |= BIO_ERROR;
  367         } else {
  368                 g_trace(G_T_BIO, "g_dev_done(%p/%p) resid %ld completed %jd",
  369                     bp2, bp, bp->bio_resid, (intmax_t)bp2->bio_completed);
  370         }
  371         bp->bio_resid = bp->bio_bcount - bp2->bio_completed;
  372         g_destroy_bio(bp2);
  373         mtx_lock(&Giant);
  374         biodone(bp);
  375         mtx_unlock(&Giant);
  376 }
  377 
  378 static void
  379 g_dev_strategy(struct bio *bp)
  380 {
  381         struct g_geom *gp;
  382         struct g_consumer *cp;
  383         struct bio *bp2;
  384         dev_t dev;
  385 
  386         KASSERT(bp->bio_cmd == BIO_READ ||
  387                 bp->bio_cmd == BIO_WRITE ||
  388                 bp->bio_cmd == BIO_DELETE,
  389                 ("Wrong bio_cmd bio=%p cmd=%d", bp, bp->bio_cmd));
  390         dev = bp->bio_dev;
  391         gp = dev->si_drv1;
  392         cp = dev->si_drv2;
  393         bp2 = g_clone_bio(bp);
  394         KASSERT(bp2 != NULL, ("XXX: ENOMEM in a bad place"));
  395         bp2->bio_offset = (off_t)bp->bio_blkno << DEV_BSHIFT;
  396         KASSERT(bp2->bio_offset >= 0,
  397             ("Negative bio_offset (%jd) on bio %p",
  398             (intmax_t)bp2->bio_offset, bp));
  399         bp2->bio_length = (off_t)bp->bio_bcount;
  400         bp2->bio_done = g_dev_done;
  401         g_trace(G_T_BIO,
  402             "g_dev_strategy(%p/%p) offset %jd length %jd data %p cmd %d",
  403             bp, bp2, (intmax_t)bp->bio_offset, (intmax_t)bp2->bio_length,
  404             bp2->bio_data, bp2->bio_cmd);
  405         g_io_request(bp2, cp);
  406 }
  407 
  408 /*
  409  * g_dev_orphan()
  410  *
  411  * Called from below when the provider orphaned us.  It is our responsibility
  412  * to get the access counts back to zero, until we do so the stack below will
  413  * not unravel.  We must clear the kernel-dump settings, if this is the
  414  * current dumpdev.  We call destroy_dev(9) to send our dev_t the way of
  415  * punched cards and if we have non-zero access counts, we call down with
  416  * them negated before we detattch and selfdestruct.
  417  */
  418 
  419 static void
  420 g_dev_orphan(struct g_consumer *cp)
  421 {
  422         struct g_geom *gp;
  423         dev_t dev;
  424 
  425         gp = cp->geom;
  426         g_trace(G_T_TOPOLOGY, "g_dev_orphan(%p(%s))", cp, gp->name);
  427         g_topology_assert();
  428         if (cp->biocount > 0)
  429                 return;
  430         dev = gp->softc;
  431         if (dev->si_flags & SI_DUMPDEV)
  432                 set_dumper(NULL);
  433         /* XXX: we may need Giant for now */
  434         destroy_dev(dev);
  435         if (cp->acr > 0 || cp->acw > 0 || cp->ace > 0)
  436                 g_access_rel(cp, -cp->acr, -cp->acw, -cp->ace);
  437         g_detach(cp);
  438         g_destroy_consumer(cp);
  439         g_destroy_geom(gp);
  440 }
  441 
  442 DECLARE_GEOM_CLASS(g_dev_class, g_dev);

Cache object: cdf9d80d477e1e8fd4716b5ca3736205


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