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

Cache object: bf84ae2f8147131d3413e40f93fc10e6


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