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/gate/g_gate.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) 2004-2006 Pawel Jakub Dawidek <pjd@FreeBSD.org>
    3  * Copyright (c) 2009-2010 The FreeBSD Foundation
    4  * All rights reserved.
    5  *
    6  * Portions of this software were developed by Pawel Jakub Dawidek
    7  * under sponsorship from the FreeBSD Foundation.
    8  *
    9  * Redistribution and use in source and binary forms, with or without
   10  * modification, are permitted provided that the following conditions
   11  * are met:
   12  * 1. Redistributions of source code must retain the above copyright
   13  *    notice, this list of conditions and the following disclaimer.
   14  * 2. Redistributions in binary form must reproduce the above copyright
   15  *    notice, this list of conditions and the following disclaimer in the
   16  *    documentation and/or other materials provided with the distribution.
   17  *
   18  * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
   19  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   20  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   21  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
   22  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   23  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   24  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   25  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   26  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   27  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   28  * SUCH DAMAGE.
   29  */
   30 
   31 #include <sys/cdefs.h>
   32 __FBSDID("$FreeBSD: releng/9.0/sys/geom/gate/g_gate.c 223921 2011-07-11 05:22:31Z ae $");
   33 
   34 #include <sys/param.h>
   35 #include <sys/systm.h>
   36 #include <sys/bio.h>
   37 #include <sys/conf.h>
   38 #include <sys/kernel.h>
   39 #include <sys/kthread.h>
   40 #include <sys/fcntl.h>
   41 #include <sys/linker.h>
   42 #include <sys/lock.h>
   43 #include <sys/malloc.h>
   44 #include <sys/mutex.h>
   45 #include <sys/proc.h>
   46 #include <sys/limits.h>
   47 #include <sys/queue.h>
   48 #include <sys/sbuf.h>
   49 #include <sys/sysctl.h>
   50 #include <sys/signalvar.h>
   51 #include <sys/time.h>
   52 #include <machine/atomic.h>
   53 
   54 #include <geom/geom.h>
   55 #include <geom/gate/g_gate.h>
   56 
   57 FEATURE(geom_gate, "GEOM Gate module");
   58 
   59 static MALLOC_DEFINE(M_GATE, "gg_data", "GEOM Gate Data");
   60 
   61 SYSCTL_DECL(_kern_geom);
   62 SYSCTL_NODE(_kern_geom, OID_AUTO, gate, CTLFLAG_RW, 0, "GEOM_GATE stuff");
   63 static int g_gate_debug = 0;
   64 TUNABLE_INT("kern.geom.gate.debug", &g_gate_debug);
   65 SYSCTL_INT(_kern_geom_gate, OID_AUTO, debug, CTLFLAG_RW, &g_gate_debug, 0,
   66     "Debug level");
   67 static u_int g_gate_maxunits = 256;
   68 TUNABLE_INT("kern.geom.gate.maxunits", &g_gate_maxunits);
   69 SYSCTL_UINT(_kern_geom_gate, OID_AUTO, maxunits, CTLFLAG_RDTUN,
   70     &g_gate_maxunits, 0, "Maximum number of ggate devices");
   71 
   72 struct g_class g_gate_class = {
   73         .name = G_GATE_CLASS_NAME,
   74         .version = G_VERSION,
   75 };
   76 
   77 static struct cdev *status_dev;
   78 static d_ioctl_t g_gate_ioctl;
   79 static struct cdevsw g_gate_cdevsw = {
   80         .d_version =    D_VERSION,
   81         .d_ioctl =      g_gate_ioctl,
   82         .d_name =       G_GATE_CTL_NAME
   83 };
   84 
   85 
   86 static struct g_gate_softc **g_gate_units;
   87 static u_int g_gate_nunits;
   88 static struct mtx g_gate_units_lock;
   89 
   90 static int
   91 g_gate_destroy(struct g_gate_softc *sc, boolean_t force)
   92 {
   93         struct g_provider *pp;
   94         struct g_geom *gp;
   95         struct bio *bp;
   96 
   97         g_topology_assert();
   98         mtx_assert(&g_gate_units_lock, MA_OWNED);
   99         pp = sc->sc_provider;
  100         if (!force && (pp->acr != 0 || pp->acw != 0 || pp->ace != 0)) {
  101                 mtx_unlock(&g_gate_units_lock);
  102                 return (EBUSY);
  103         }
  104         mtx_unlock(&g_gate_units_lock);
  105         mtx_lock(&sc->sc_queue_mtx);
  106         if ((sc->sc_flags & G_GATE_FLAG_DESTROY) == 0)
  107                 sc->sc_flags |= G_GATE_FLAG_DESTROY;
  108         wakeup(sc);
  109         mtx_unlock(&sc->sc_queue_mtx);
  110         gp = pp->geom;
  111         pp->flags |= G_PF_WITHER;
  112         g_orphan_provider(pp, ENXIO);
  113         callout_drain(&sc->sc_callout);
  114         mtx_lock(&sc->sc_queue_mtx);
  115         while ((bp = bioq_first(&sc->sc_inqueue)) != NULL) {
  116                 bioq_remove(&sc->sc_inqueue, bp);
  117                 sc->sc_queue_count--;
  118                 G_GATE_LOGREQ(1, bp, "Request canceled.");
  119                 g_io_deliver(bp, ENXIO);
  120         }
  121         while ((bp = bioq_first(&sc->sc_outqueue)) != NULL) {
  122                 bioq_remove(&sc->sc_outqueue, bp);
  123                 sc->sc_queue_count--;
  124                 G_GATE_LOGREQ(1, bp, "Request canceled.");
  125                 g_io_deliver(bp, ENXIO);
  126         }
  127         mtx_unlock(&sc->sc_queue_mtx);
  128         g_topology_unlock();
  129         mtx_lock(&g_gate_units_lock);
  130         /* One reference is ours. */
  131         sc->sc_ref--;
  132         while (sc->sc_ref > 0)
  133                 msleep(&sc->sc_ref, &g_gate_units_lock, 0, "gg:destroy", 0);
  134         g_gate_units[sc->sc_unit] = NULL;
  135         KASSERT(g_gate_nunits > 0, ("negative g_gate_nunits?"));
  136         g_gate_nunits--;
  137         mtx_unlock(&g_gate_units_lock);
  138         mtx_destroy(&sc->sc_queue_mtx);
  139         g_topology_lock();
  140         G_GATE_DEBUG(1, "Device %s destroyed.", gp->name);
  141         gp->softc = NULL;
  142         g_wither_geom(gp, ENXIO);
  143         sc->sc_provider = NULL;
  144         free(sc, M_GATE);
  145         return (0);
  146 }
  147 
  148 static int
  149 g_gate_access(struct g_provider *pp, int dr, int dw, int de)
  150 {
  151         struct g_gate_softc *sc;
  152 
  153         if (dr <= 0 && dw <= 0 && de <= 0)
  154                 return (0);
  155         sc = pp->geom->softc;
  156         if (sc == NULL || (sc->sc_flags & G_GATE_FLAG_DESTROY) != 0)
  157                 return (ENXIO);
  158         /* XXX: Hack to allow read-only mounts. */
  159 #if 0
  160         if ((sc->sc_flags & G_GATE_FLAG_READONLY) != 0 && dw > 0)
  161                 return (EPERM);
  162 #endif
  163         if ((sc->sc_flags & G_GATE_FLAG_WRITEONLY) != 0 && dr > 0)
  164                 return (EPERM);
  165         return (0);
  166 }
  167 
  168 static void
  169 g_gate_start(struct bio *bp)
  170 {
  171         struct g_gate_softc *sc;
  172 
  173         sc = bp->bio_to->geom->softc;
  174         if (sc == NULL || (sc->sc_flags & G_GATE_FLAG_DESTROY) != 0) {
  175                 g_io_deliver(bp, ENXIO);
  176                 return;
  177         }
  178         G_GATE_LOGREQ(2, bp, "Request received.");
  179         switch (bp->bio_cmd) {
  180         case BIO_READ:
  181                 break;
  182         case BIO_DELETE:
  183         case BIO_WRITE:
  184         case BIO_FLUSH:
  185                 /* XXX: Hack to allow read-only mounts. */
  186                 if ((sc->sc_flags & G_GATE_FLAG_READONLY) != 0) {
  187                         g_io_deliver(bp, EPERM);
  188                         return;
  189                 }
  190                 break;
  191         case BIO_GETATTR:
  192         default:
  193                 G_GATE_LOGREQ(2, bp, "Ignoring request.");
  194                 g_io_deliver(bp, EOPNOTSUPP);
  195                 return;
  196         }
  197 
  198         mtx_lock(&sc->sc_queue_mtx);
  199         if (sc->sc_queue_size > 0 && sc->sc_queue_count > sc->sc_queue_size) {
  200                 mtx_unlock(&sc->sc_queue_mtx);
  201                 G_GATE_LOGREQ(1, bp, "Queue full, request canceled.");
  202                 g_io_deliver(bp, ENOMEM);
  203                 return;
  204         }
  205 
  206         bp->bio_driver1 = (void *)sc->sc_seq;
  207         sc->sc_seq++;
  208         sc->sc_queue_count++;
  209 
  210         bioq_insert_tail(&sc->sc_inqueue, bp);
  211         wakeup(sc);
  212 
  213         mtx_unlock(&sc->sc_queue_mtx);
  214 }
  215 
  216 static struct g_gate_softc *
  217 g_gate_hold(int unit, const char *name)
  218 {
  219         struct g_gate_softc *sc = NULL;
  220 
  221         mtx_lock(&g_gate_units_lock);
  222         if (unit >= 0 && unit < g_gate_maxunits)
  223                 sc = g_gate_units[unit];
  224         else if (unit == G_GATE_NAME_GIVEN) {
  225                 KASSERT(name != NULL, ("name is NULL"));
  226                 for (unit = 0; unit < g_gate_maxunits; unit++) {
  227                         if (g_gate_units[unit] == NULL)
  228                                 continue;
  229                         if (strcmp(name,
  230                             g_gate_units[unit]->sc_provider->name) != 0) {
  231                                 continue;
  232                         }
  233                         sc = g_gate_units[unit];
  234                         break;
  235                 }
  236         }
  237         if (sc != NULL)
  238                 sc->sc_ref++;
  239         mtx_unlock(&g_gate_units_lock);
  240         return (sc);
  241 }
  242 
  243 static void
  244 g_gate_release(struct g_gate_softc *sc)
  245 {
  246 
  247         g_topology_assert_not();
  248         mtx_lock(&g_gate_units_lock);
  249         sc->sc_ref--;
  250         KASSERT(sc->sc_ref >= 0, ("Negative sc_ref for %s.", sc->sc_name));
  251         if (sc->sc_ref == 0 && (sc->sc_flags & G_GATE_FLAG_DESTROY) != 0)
  252                 wakeup(&sc->sc_ref);
  253         mtx_unlock(&g_gate_units_lock);
  254 }
  255 
  256 static int
  257 g_gate_getunit(int unit, int *errorp)
  258 {
  259 
  260         mtx_assert(&g_gate_units_lock, MA_OWNED);
  261         if (unit >= 0) {
  262                 if (unit >= g_gate_maxunits)
  263                         *errorp = EINVAL;
  264                 else if (g_gate_units[unit] == NULL)
  265                         return (unit);
  266                 else
  267                         *errorp = EEXIST;
  268         } else {
  269                 for (unit = 0; unit < g_gate_maxunits; unit++) {
  270                         if (g_gate_units[unit] == NULL)
  271                                 return (unit);
  272                 }
  273                 *errorp = ENFILE;
  274         }
  275         return (-1);
  276 }
  277 
  278 static void
  279 g_gate_guard(void *arg)
  280 {
  281         struct g_gate_softc *sc;
  282         struct bintime curtime;
  283         struct bio *bp, *bp2;
  284 
  285         sc = arg;
  286         binuptime(&curtime);
  287         g_gate_hold(sc->sc_unit, NULL);
  288         mtx_lock(&sc->sc_queue_mtx);
  289         TAILQ_FOREACH_SAFE(bp, &sc->sc_inqueue.queue, bio_queue, bp2) {
  290                 if (curtime.sec - bp->bio_t0.sec < 5)
  291                         continue;
  292                 bioq_remove(&sc->sc_inqueue, bp);
  293                 sc->sc_queue_count--;
  294                 G_GATE_LOGREQ(1, bp, "Request timeout.");
  295                 g_io_deliver(bp, EIO);
  296         }
  297         TAILQ_FOREACH_SAFE(bp, &sc->sc_outqueue.queue, bio_queue, bp2) {
  298                 if (curtime.sec - bp->bio_t0.sec < 5)
  299                         continue;
  300                 bioq_remove(&sc->sc_outqueue, bp);
  301                 sc->sc_queue_count--;
  302                 G_GATE_LOGREQ(1, bp, "Request timeout.");
  303                 g_io_deliver(bp, EIO);
  304         }
  305         mtx_unlock(&sc->sc_queue_mtx);
  306         if ((sc->sc_flags & G_GATE_FLAG_DESTROY) == 0) {
  307                 callout_reset(&sc->sc_callout, sc->sc_timeout * hz,
  308                     g_gate_guard, sc);
  309         }
  310         g_gate_release(sc);
  311 }
  312 
  313 static void
  314 g_gate_dumpconf(struct sbuf *sb, const char *indent, struct g_geom *gp,
  315     struct g_consumer *cp, struct g_provider *pp)
  316 {
  317         struct g_gate_softc *sc;
  318 
  319         sc = gp->softc;
  320         if (sc == NULL || pp != NULL || cp != NULL)
  321                 return;
  322         g_gate_hold(sc->sc_unit, NULL);
  323         if ((sc->sc_flags & G_GATE_FLAG_READONLY) != 0) {
  324                 sbuf_printf(sb, "%s<access>%s</access>\n", indent, "read-only");
  325         } else if ((sc->sc_flags & G_GATE_FLAG_WRITEONLY) != 0) {
  326                 sbuf_printf(sb, "%s<access>%s</access>\n", indent,
  327                     "write-only");
  328         } else {
  329                 sbuf_printf(sb, "%s<access>%s</access>\n", indent,
  330                     "read-write");
  331         }
  332         sbuf_printf(sb, "%s<timeout>%u</timeout>\n", indent, sc->sc_timeout);
  333         sbuf_printf(sb, "%s<info>%s</info>\n", indent, sc->sc_info);
  334         sbuf_printf(sb, "%s<queue_count>%u</queue_count>\n", indent,
  335             sc->sc_queue_count);
  336         sbuf_printf(sb, "%s<queue_size>%u</queue_size>\n", indent,
  337             sc->sc_queue_size);
  338         sbuf_printf(sb, "%s<ref>%u</ref>\n", indent, sc->sc_ref);
  339         sbuf_printf(sb, "%s<unit>%d</unit>\n", indent, sc->sc_unit);
  340         g_topology_unlock();
  341         g_gate_release(sc);
  342         g_topology_lock();
  343 }
  344 
  345 static int
  346 g_gate_create(struct g_gate_ctl_create *ggio)
  347 {
  348         struct g_gate_softc *sc;
  349         struct g_geom *gp;
  350         struct g_provider *pp;
  351         char name[NAME_MAX];
  352         int error = 0, unit;
  353 
  354         if (ggio->gctl_mediasize == 0) {
  355                 G_GATE_DEBUG(1, "Invalid media size.");
  356                 return (EINVAL);
  357         }
  358         if (ggio->gctl_sectorsize > 0 && !powerof2(ggio->gctl_sectorsize)) {
  359                 G_GATE_DEBUG(1, "Invalid sector size.");
  360                 return (EINVAL);
  361         }
  362         if ((ggio->gctl_mediasize % ggio->gctl_sectorsize) != 0) {
  363                 G_GATE_DEBUG(1, "Invalid media size.");
  364                 return (EINVAL);
  365         }
  366         if ((ggio->gctl_flags & G_GATE_FLAG_READONLY) != 0 &&
  367             (ggio->gctl_flags & G_GATE_FLAG_WRITEONLY) != 0) {
  368                 G_GATE_DEBUG(1, "Invalid flags.");
  369                 return (EINVAL);
  370         }
  371         if (ggio->gctl_unit != G_GATE_UNIT_AUTO &&
  372             ggio->gctl_unit != G_GATE_NAME_GIVEN &&
  373             ggio->gctl_unit < 0) {
  374                 G_GATE_DEBUG(1, "Invalid unit number.");
  375                 return (EINVAL);
  376         }
  377         if (ggio->gctl_unit == G_GATE_NAME_GIVEN &&
  378             ggio->gctl_name[0] == '\0') {
  379                 G_GATE_DEBUG(1, "No device name.");
  380                 return (EINVAL);
  381         }
  382 
  383         sc = malloc(sizeof(*sc), M_GATE, M_WAITOK | M_ZERO);
  384         sc->sc_flags = (ggio->gctl_flags & G_GATE_USERFLAGS);
  385         strlcpy(sc->sc_info, ggio->gctl_info, sizeof(sc->sc_info));
  386         sc->sc_seq = 1;
  387         bioq_init(&sc->sc_inqueue);
  388         bioq_init(&sc->sc_outqueue);
  389         mtx_init(&sc->sc_queue_mtx, "gg:queue", NULL, MTX_DEF);
  390         sc->sc_queue_count = 0;
  391         sc->sc_queue_size = ggio->gctl_maxcount;
  392         if (sc->sc_queue_size > G_GATE_MAX_QUEUE_SIZE)
  393                 sc->sc_queue_size = G_GATE_MAX_QUEUE_SIZE;
  394         sc->sc_timeout = ggio->gctl_timeout;
  395         callout_init(&sc->sc_callout, CALLOUT_MPSAFE);
  396         mtx_lock(&g_gate_units_lock);
  397         sc->sc_unit = g_gate_getunit(ggio->gctl_unit, &error);
  398         if (sc->sc_unit < 0) {
  399                 mtx_unlock(&g_gate_units_lock);
  400                 mtx_destroy(&sc->sc_queue_mtx);
  401                 free(sc, M_GATE);
  402                 return (error);
  403         }
  404         if (ggio->gctl_unit == G_GATE_NAME_GIVEN)
  405                 snprintf(name, sizeof(name), "%s", ggio->gctl_name);
  406         else {
  407                 snprintf(name, sizeof(name), "%s%d", G_GATE_PROVIDER_NAME,
  408                     sc->sc_unit);
  409         }
  410         /* Check for name collision. */
  411         for (unit = 0; unit < g_gate_maxunits; unit++) {
  412                 if (g_gate_units[unit] == NULL)
  413                         continue;
  414                 if (strcmp(name, g_gate_units[unit]->sc_name) != 0)
  415                         continue;
  416                 mtx_unlock(&g_gate_units_lock);
  417                 mtx_destroy(&sc->sc_queue_mtx);
  418                 free(sc, M_GATE);
  419                 return (EEXIST);
  420         }
  421         sc->sc_name = name;
  422         g_gate_units[sc->sc_unit] = sc;
  423         g_gate_nunits++;
  424         mtx_unlock(&g_gate_units_lock);
  425 
  426         ggio->gctl_unit = sc->sc_unit;
  427 
  428         g_topology_lock();
  429         gp = g_new_geomf(&g_gate_class, "%s", name);
  430         gp->start = g_gate_start;
  431         gp->access = g_gate_access;
  432         gp->dumpconf = g_gate_dumpconf;
  433         gp->softc = sc;
  434         pp = g_new_providerf(gp, "%s", name);
  435         pp->mediasize = ggio->gctl_mediasize;
  436         pp->sectorsize = ggio->gctl_sectorsize;
  437         sc->sc_provider = pp;
  438         g_error_provider(pp, 0);
  439         g_topology_unlock();
  440         mtx_lock(&g_gate_units_lock);
  441         sc->sc_name = sc->sc_provider->name;
  442         mtx_unlock(&g_gate_units_lock);
  443         G_GATE_DEBUG(1, "Device %s created.", gp->name);
  444 
  445         if (sc->sc_timeout > 0) {
  446                 callout_reset(&sc->sc_callout, sc->sc_timeout * hz,
  447                     g_gate_guard, sc);
  448         }
  449         return (0);
  450 }
  451 
  452 #define G_GATE_CHECK_VERSION(ggio)      do {                            \
  453         if ((ggio)->gctl_version != G_GATE_VERSION) {                   \
  454                 printf("Version mismatch %d != %d.\n",                  \
  455                     ggio->gctl_version, G_GATE_VERSION);                \
  456                 return (EINVAL);                                        \
  457         }                                                               \
  458 } while (0)
  459 static int
  460 g_gate_ioctl(struct cdev *dev, u_long cmd, caddr_t addr, int flags, struct thread *td)
  461 {
  462         struct g_gate_softc *sc;
  463         struct bio *bp;
  464         int error = 0;
  465 
  466         G_GATE_DEBUG(4, "ioctl(%s, %lx, %p, %x, %p)", devtoname(dev), cmd, addr,
  467             flags, td);
  468 
  469         switch (cmd) {
  470         case G_GATE_CMD_CREATE:
  471             {
  472                 struct g_gate_ctl_create *ggio = (void *)addr;
  473 
  474                 G_GATE_CHECK_VERSION(ggio);
  475                 error = g_gate_create(ggio);
  476                 /*
  477                  * Reset TDP_GEOM flag.
  478                  * There are pending events for sure, because we just created
  479                  * new provider and other classes want to taste it, but we
  480                  * cannot answer on I/O requests until we're here.
  481                  */
  482                 td->td_pflags &= ~TDP_GEOM;
  483                 return (error);
  484             }
  485         case G_GATE_CMD_DESTROY:
  486             {
  487                 struct g_gate_ctl_destroy *ggio = (void *)addr;
  488 
  489                 G_GATE_CHECK_VERSION(ggio);
  490                 sc = g_gate_hold(ggio->gctl_unit, ggio->gctl_name);
  491                 if (sc == NULL)
  492                         return (ENXIO);
  493                 g_topology_lock();
  494                 mtx_lock(&g_gate_units_lock);
  495                 error = g_gate_destroy(sc, ggio->gctl_force);
  496                 g_topology_unlock();
  497                 if (error != 0)
  498                         g_gate_release(sc);
  499                 return (error);
  500             }
  501         case G_GATE_CMD_CANCEL:
  502             {
  503                 struct g_gate_ctl_cancel *ggio = (void *)addr;
  504                 struct bio *tbp, *lbp;
  505 
  506                 G_GATE_CHECK_VERSION(ggio);
  507                 sc = g_gate_hold(ggio->gctl_unit, ggio->gctl_name);
  508                 if (sc == NULL)
  509                         return (ENXIO);
  510                 lbp = NULL;
  511                 mtx_lock(&sc->sc_queue_mtx);
  512                 TAILQ_FOREACH_SAFE(bp, &sc->sc_outqueue.queue, bio_queue, tbp) {
  513                         if (ggio->gctl_seq == 0 ||
  514                             ggio->gctl_seq == (uintptr_t)bp->bio_driver1) {
  515                                 G_GATE_LOGREQ(1, bp, "Request canceled.");
  516                                 bioq_remove(&sc->sc_outqueue, bp);
  517                                 /*
  518                                  * Be sure to put requests back onto incoming
  519                                  * queue in the proper order.
  520                                  */
  521                                 if (lbp == NULL)
  522                                         bioq_insert_head(&sc->sc_inqueue, bp);
  523                                 else {
  524                                         TAILQ_INSERT_AFTER(&sc->sc_inqueue.queue,
  525                                             lbp, bp, bio_queue);
  526                                 }
  527                                 lbp = bp;
  528                                 /*
  529                                  * If only one request was canceled, leave now.
  530                                  */
  531                                 if (ggio->gctl_seq != 0)
  532                                         break;
  533                         }
  534                 }
  535                 if (ggio->gctl_unit == G_GATE_NAME_GIVEN)
  536                         ggio->gctl_unit = sc->sc_unit;
  537                 mtx_unlock(&sc->sc_queue_mtx);
  538                 g_gate_release(sc);
  539                 return (error);
  540             }
  541         case G_GATE_CMD_START:
  542             {
  543                 struct g_gate_ctl_io *ggio = (void *)addr;
  544 
  545                 G_GATE_CHECK_VERSION(ggio);
  546                 sc = g_gate_hold(ggio->gctl_unit, NULL);
  547                 if (sc == NULL)
  548                         return (ENXIO);
  549                 error = 0;
  550                 for (;;) {
  551                         mtx_lock(&sc->sc_queue_mtx);
  552                         bp = bioq_first(&sc->sc_inqueue);
  553                         if (bp != NULL)
  554                                 break;
  555                         if ((sc->sc_flags & G_GATE_FLAG_DESTROY) != 0) {
  556                                 ggio->gctl_error = ECANCELED;
  557                                 mtx_unlock(&sc->sc_queue_mtx);
  558                                 goto start_end;
  559                         }
  560                         if (msleep(sc, &sc->sc_queue_mtx,
  561                             PPAUSE | PDROP | PCATCH, "ggwait", 0) != 0) {
  562                                 ggio->gctl_error = ECANCELED;
  563                                 goto start_end;
  564                         }
  565                 }
  566                 ggio->gctl_cmd = bp->bio_cmd;
  567                 if ((bp->bio_cmd == BIO_DELETE || bp->bio_cmd == BIO_WRITE) &&
  568                     bp->bio_length > ggio->gctl_length) {
  569                         mtx_unlock(&sc->sc_queue_mtx);
  570                         ggio->gctl_length = bp->bio_length;
  571                         ggio->gctl_error = ENOMEM;
  572                         goto start_end;
  573                 }
  574                 bioq_remove(&sc->sc_inqueue, bp);
  575                 bioq_insert_tail(&sc->sc_outqueue, bp);
  576                 mtx_unlock(&sc->sc_queue_mtx);
  577 
  578                 ggio->gctl_seq = (uintptr_t)bp->bio_driver1;
  579                 ggio->gctl_offset = bp->bio_offset;
  580                 ggio->gctl_length = bp->bio_length;
  581 
  582                 switch (bp->bio_cmd) {
  583                 case BIO_READ:
  584                 case BIO_DELETE:
  585                 case BIO_FLUSH:
  586                         break;
  587                 case BIO_WRITE:
  588                         error = copyout(bp->bio_data, ggio->gctl_data,
  589                             bp->bio_length);
  590                         if (error != 0) {
  591                                 mtx_lock(&sc->sc_queue_mtx);
  592                                 bioq_remove(&sc->sc_outqueue, bp);
  593                                 bioq_insert_head(&sc->sc_inqueue, bp);
  594                                 mtx_unlock(&sc->sc_queue_mtx);
  595                                 goto start_end;
  596                         }
  597                         break;
  598                 }
  599 start_end:
  600                 g_gate_release(sc);
  601                 return (error);
  602             }
  603         case G_GATE_CMD_DONE:
  604             {
  605                 struct g_gate_ctl_io *ggio = (void *)addr;
  606 
  607                 G_GATE_CHECK_VERSION(ggio);
  608                 sc = g_gate_hold(ggio->gctl_unit, NULL);
  609                 if (sc == NULL)
  610                         return (ENOENT);
  611                 error = 0;
  612                 mtx_lock(&sc->sc_queue_mtx);
  613                 TAILQ_FOREACH(bp, &sc->sc_outqueue.queue, bio_queue) {
  614                         if (ggio->gctl_seq == (uintptr_t)bp->bio_driver1)
  615                                 break;
  616                 }
  617                 if (bp != NULL) {
  618                         bioq_remove(&sc->sc_outqueue, bp);
  619                         sc->sc_queue_count--;
  620                 }
  621                 mtx_unlock(&sc->sc_queue_mtx);
  622                 if (bp == NULL) {
  623                         /*
  624                          * Request was probably canceled.
  625                          */
  626                         goto done_end;
  627                 }
  628                 if (ggio->gctl_error == EAGAIN) {
  629                         bp->bio_error = 0;
  630                         G_GATE_LOGREQ(1, bp, "Request desisted.");
  631                         mtx_lock(&sc->sc_queue_mtx);
  632                         sc->sc_queue_count++;
  633                         bioq_insert_head(&sc->sc_inqueue, bp);
  634                         wakeup(sc);
  635                         mtx_unlock(&sc->sc_queue_mtx);
  636                 } else {
  637                         bp->bio_error = ggio->gctl_error;
  638                         if (bp->bio_error == 0) {
  639                                 bp->bio_completed = bp->bio_length;
  640                                 switch (bp->bio_cmd) {
  641                                 case BIO_READ:
  642                                         error = copyin(ggio->gctl_data,
  643                                             bp->bio_data, bp->bio_length);
  644                                         if (error != 0)
  645                                                 bp->bio_error = error;
  646                                         break;
  647                                 case BIO_DELETE:
  648                                 case BIO_WRITE:
  649                                 case BIO_FLUSH:
  650                                         break;
  651                                 }
  652                         }
  653                         G_GATE_LOGREQ(2, bp, "Request done.");
  654                         g_io_deliver(bp, bp->bio_error);
  655                 }
  656 done_end:
  657                 g_gate_release(sc);
  658                 return (error);
  659             }
  660         }
  661         return (ENOIOCTL);
  662 }
  663 
  664 static void
  665 g_gate_device(void)
  666 {
  667 
  668         status_dev = make_dev(&g_gate_cdevsw, 0x0, UID_ROOT, GID_WHEEL, 0600,
  669             G_GATE_CTL_NAME);
  670 }
  671 
  672 static int
  673 g_gate_modevent(module_t mod, int type, void *data)
  674 {
  675         int error = 0;
  676 
  677         switch (type) {
  678         case MOD_LOAD:
  679                 mtx_init(&g_gate_units_lock, "gg_units_lock", NULL, MTX_DEF);
  680                 g_gate_units = malloc(g_gate_maxunits * sizeof(g_gate_units[0]),
  681                     M_GATE, M_WAITOK | M_ZERO);
  682                 g_gate_nunits = 0;
  683                 g_gate_device();
  684                 break;
  685         case MOD_UNLOAD:
  686                 mtx_lock(&g_gate_units_lock);
  687                 if (g_gate_nunits > 0) {
  688                         mtx_unlock(&g_gate_units_lock);
  689                         error = EBUSY;
  690                         break;
  691                 }
  692                 mtx_unlock(&g_gate_units_lock);
  693                 mtx_destroy(&g_gate_units_lock);
  694                 if (status_dev != 0)
  695                         destroy_dev(status_dev);
  696                 free(g_gate_units, M_GATE);
  697                 break;
  698         default:
  699                 return (EOPNOTSUPP);
  700                 break;
  701         }
  702 
  703         return (error);
  704 }
  705 static moduledata_t g_gate_module = {
  706         G_GATE_MOD_NAME,
  707         g_gate_modevent,
  708         NULL
  709 };
  710 DECLARE_MODULE(geom_gate, g_gate_module, SI_SUB_DRIVERS, SI_ORDER_MIDDLE);
  711 DECLARE_GEOM_CLASS(g_gate_class, g_gate);

Cache object: bb7efa0ccb1b59caf703f2b9be32d37c


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