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/nop/g_nop.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  * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
    3  *
    4  * Copyright (c) 2004-2006 Pawel Jakub Dawidek <pjd@FreeBSD.org>
    5  * Copyright (c) 2019 Mariusz Zaborski <oshogbo@FreeBSD.org>
    6  * All rights reserved.
    7  *
    8  * Redistribution and use in source and binary forms, with or without
    9  * modification, are permitted provided that the following conditions
   10  * are met:
   11  * 1. Redistributions of source code must retain the above copyright
   12  *    notice, this list of conditions and the following disclaimer.
   13  * 2. Redistributions in binary form must reproduce the above copyright
   14  *    notice, this list of conditions and the following disclaimer in the
   15  *    documentation and/or other materials provided with the distribution.
   16  *
   17  * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
   18  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   19  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   20  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
   21  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   22  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   23  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   24  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   25  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   26  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   27  * SUCH DAMAGE.
   28  */
   29 
   30 #include <sys/cdefs.h>
   31 __FBSDID("$FreeBSD$");
   32 
   33 #include <sys/param.h>
   34 #include <sys/ctype.h>
   35 #include <sys/systm.h>
   36 #include <sys/kernel.h>
   37 #include <sys/module.h>
   38 #include <sys/lock.h>
   39 #include <sys/mutex.h>
   40 #include <sys/bio.h>
   41 #include <sys/sbuf.h>
   42 #include <sys/sysctl.h>
   43 #include <sys/malloc.h>
   44 #include <geom/geom.h>
   45 #include <geom/geom_dbg.h>
   46 #include <geom/nop/g_nop.h>
   47 
   48 SYSCTL_DECL(_kern_geom);
   49 static SYSCTL_NODE(_kern_geom, OID_AUTO, nop, CTLFLAG_RW | CTLFLAG_MPSAFE, 0,
   50     "GEOM_NOP stuff");
   51 static u_int g_nop_debug = 0;
   52 SYSCTL_UINT(_kern_geom_nop, OID_AUTO, debug, CTLFLAG_RW, &g_nop_debug, 0,
   53     "Debug level");
   54 
   55 static int g_nop_destroy(struct g_geom *gp, boolean_t force);
   56 static int g_nop_destroy_geom(struct gctl_req *req, struct g_class *mp,
   57     struct g_geom *gp);
   58 static void g_nop_config(struct gctl_req *req, struct g_class *mp,
   59     const char *verb);
   60 static g_access_t g_nop_access;
   61 static g_dumpconf_t g_nop_dumpconf;
   62 static g_orphan_t g_nop_orphan;
   63 static g_provgone_t g_nop_providergone;
   64 static g_resize_t g_nop_resize;
   65 static g_start_t g_nop_start;
   66 
   67 struct g_class g_nop_class = {
   68         .name = G_NOP_CLASS_NAME,
   69         .version = G_VERSION,
   70         .ctlreq = g_nop_config,
   71         .destroy_geom = g_nop_destroy_geom,
   72         .access = g_nop_access,
   73         .dumpconf = g_nop_dumpconf,
   74         .orphan = g_nop_orphan,
   75         .providergone = g_nop_providergone,
   76         .resize = g_nop_resize,
   77         .start = g_nop_start,
   78 };
   79 
   80 struct g_nop_delay {
   81         struct callout                   dl_cal;
   82         struct bio                      *dl_bio;
   83         TAILQ_ENTRY(g_nop_delay)         dl_next;
   84 };
   85 
   86 static bool
   87 g_nop_verify_nprefix(const char *name)
   88 {
   89         int i;
   90 
   91         for (i = 0; i < strlen(name); i++) {
   92                 if (isalpha(name[i]) == 0 && isdigit(name[i]) == 0) {
   93                         return (false);
   94                 }
   95         }
   96 
   97         return (true);
   98 }
   99 
  100 static void
  101 g_nop_orphan(struct g_consumer *cp)
  102 {
  103 
  104         g_topology_assert();
  105         g_nop_destroy(cp->geom, 1);
  106 }
  107 
  108 static void
  109 g_nop_resize(struct g_consumer *cp)
  110 {
  111         struct g_nop_softc *sc;
  112         struct g_geom *gp;
  113         struct g_provider *pp;
  114         off_t size;
  115 
  116         g_topology_assert();
  117 
  118         gp = cp->geom;
  119         sc = gp->softc;
  120 
  121         if (sc->sc_explicitsize != 0)
  122                 return;
  123         if (cp->provider->mediasize < sc->sc_offset) {
  124                 g_nop_destroy(gp, 1);
  125                 return;
  126         }
  127         size = cp->provider->mediasize - sc->sc_offset;
  128         LIST_FOREACH(pp, &gp->provider, provider)
  129                 g_resize_provider(pp, size);
  130 }
  131 
  132 static int
  133 g_nop_dumper(void *priv, void *virtual, off_t offset, size_t length)
  134 {
  135 
  136         return (0);
  137 }
  138 
  139 static void
  140 g_nop_kerneldump(struct bio *bp, struct g_nop_softc *sc)
  141 {
  142         struct g_kerneldump *gkd;
  143         struct g_geom *gp;
  144         struct g_provider *pp;
  145 
  146         gkd = (struct g_kerneldump *)bp->bio_data;
  147         gp = bp->bio_to->geom;
  148         g_trace(G_T_TOPOLOGY, "%s(%s, %jd, %jd)", __func__, gp->name,
  149             (intmax_t)gkd->offset, (intmax_t)gkd->length);
  150 
  151         pp = LIST_FIRST(&gp->provider);
  152 
  153         gkd->di.dumper = g_nop_dumper;
  154         gkd->di.priv = sc;
  155         gkd->di.blocksize = pp->sectorsize;
  156         gkd->di.maxiosize = DFLTPHYS;
  157         gkd->di.mediaoffset = sc->sc_offset + gkd->offset;
  158         if (gkd->offset > sc->sc_explicitsize) {
  159                 g_io_deliver(bp, ENODEV);
  160                 return;
  161         }
  162         if (gkd->offset + gkd->length > sc->sc_explicitsize)
  163                 gkd->length = sc->sc_explicitsize - gkd->offset;
  164         gkd->di.mediasize = gkd->length;
  165         g_io_deliver(bp, 0);
  166 }
  167 
  168 static void
  169 g_nop_pass(struct bio *cbp, struct g_geom *gp)
  170 {
  171 
  172         G_NOP_LOGREQ(cbp, "Sending request.");
  173         g_io_request(cbp, LIST_FIRST(&gp->consumer));
  174 }
  175 
  176 static void
  177 g_nop_pass_timeout(void *data)
  178 {
  179         struct g_nop_softc *sc;
  180         struct g_geom *gp;
  181         struct g_nop_delay *gndelay;
  182 
  183         gndelay = (struct g_nop_delay *)data;
  184 
  185         gp = gndelay->dl_bio->bio_to->geom;
  186         sc = gp->softc;
  187 
  188         mtx_lock(&sc->sc_lock);
  189         TAILQ_REMOVE(&sc->sc_head_delay, gndelay, dl_next);
  190         mtx_unlock(&sc->sc_lock);
  191 
  192         g_nop_pass(gndelay->dl_bio, gp);
  193 
  194         g_free(data);
  195 }
  196 
  197 static void
  198 g_nop_start(struct bio *bp)
  199 {
  200         struct g_nop_softc *sc;
  201         struct g_geom *gp;
  202         struct g_provider *pp;
  203         struct bio *cbp;
  204         u_int failprob, delayprob, delaytime;
  205 
  206         failprob = delayprob = delaytime = 0;
  207 
  208         gp = bp->bio_to->geom;
  209         sc = gp->softc;
  210 
  211         G_NOP_LOGREQ(bp, "Request received.");
  212         mtx_lock(&sc->sc_lock);
  213         switch (bp->bio_cmd) {
  214         case BIO_READ:
  215                 sc->sc_reads++;
  216                 sc->sc_readbytes += bp->bio_length;
  217                 if (sc->sc_count_until_fail != 0) {
  218                         sc->sc_count_until_fail -= 1;
  219                 } else {
  220                         failprob = sc->sc_rfailprob;
  221                         delayprob = sc->sc_rdelayprob;
  222                         delaytime = sc->sc_delaymsec;
  223                 }
  224                 break;
  225         case BIO_WRITE:
  226                 sc->sc_writes++;
  227                 sc->sc_wrotebytes += bp->bio_length;
  228                 if (sc->sc_count_until_fail != 0) {
  229                         sc->sc_count_until_fail -= 1;
  230                 } else {
  231                         failprob = sc->sc_wfailprob;
  232                         delayprob = sc->sc_wdelayprob;
  233                         delaytime = sc->sc_delaymsec;
  234                 }
  235                 break;
  236         case BIO_DELETE:
  237                 sc->sc_deletes++;
  238                 break;
  239         case BIO_GETATTR:
  240                 sc->sc_getattrs++;
  241                 if (sc->sc_physpath &&
  242                     g_handleattr_str(bp, "GEOM::physpath", sc->sc_physpath))
  243                         ;
  244                 else if (strcmp(bp->bio_attribute, "GEOM::kerneldump") == 0)
  245                         g_nop_kerneldump(bp, sc);
  246                 else
  247                         /*
  248                          * Fallthrough to forwarding the GETATTR down to the
  249                          * lower level device.
  250                          */
  251                         break;
  252                 mtx_unlock(&sc->sc_lock);
  253                 return;
  254         case BIO_FLUSH:
  255                 sc->sc_flushes++;
  256                 break;
  257         case BIO_SPEEDUP:
  258                 sc->sc_speedups++;
  259                 break;
  260         case BIO_CMD0:
  261                 sc->sc_cmd0s++;
  262                 break;
  263         case BIO_CMD1:
  264                 sc->sc_cmd1s++;
  265                 break;
  266         case BIO_CMD2:
  267                 sc->sc_cmd2s++;
  268                 break;
  269         }
  270         mtx_unlock(&sc->sc_lock);
  271 
  272         if (failprob > 0) {
  273                 u_int rval;
  274 
  275                 rval = arc4random() % 100;
  276                 if (rval < failprob) {
  277                         G_NOP_LOGREQLVL(1, bp, "Returning error=%d.", sc->sc_error);
  278                         g_io_deliver(bp, sc->sc_error);
  279                         return;
  280                 }
  281         }
  282 
  283         cbp = g_clone_bio(bp);
  284         if (cbp == NULL) {
  285                 g_io_deliver(bp, ENOMEM);
  286                 return;
  287         }
  288         cbp->bio_done = g_std_done;
  289         cbp->bio_offset = bp->bio_offset + sc->sc_offset;
  290         pp = LIST_FIRST(&gp->provider);
  291         KASSERT(pp != NULL, ("NULL pp"));
  292         cbp->bio_to = pp;
  293 
  294         if (delayprob > 0) {
  295                 struct g_nop_delay *gndelay;
  296                 u_int rval;
  297 
  298                 rval = arc4random() % 100;
  299                 if (rval < delayprob) {
  300                         gndelay = g_malloc(sizeof(*gndelay), M_NOWAIT | M_ZERO);
  301                         if (gndelay != NULL) {
  302                                 callout_init(&gndelay->dl_cal, 1);
  303 
  304                                 gndelay->dl_bio = cbp;
  305 
  306                                 mtx_lock(&sc->sc_lock);
  307                                 TAILQ_INSERT_TAIL(&sc->sc_head_delay, gndelay,
  308                                     dl_next);
  309                                 mtx_unlock(&sc->sc_lock);
  310 
  311                                 callout_reset(&gndelay->dl_cal,
  312                                     MSEC_2_TICKS(delaytime), g_nop_pass_timeout,
  313                                     gndelay);
  314                                 return;
  315                         }
  316                 }
  317         }
  318 
  319         g_nop_pass(cbp, gp);
  320 }
  321 
  322 static int
  323 g_nop_access(struct g_provider *pp, int dr, int dw, int de)
  324 {
  325         struct g_geom *gp;
  326         struct g_consumer *cp;
  327         int error;
  328 
  329         gp = pp->geom;
  330         cp = LIST_FIRST(&gp->consumer);
  331         error = g_access(cp, dr, dw, de);
  332 
  333         return (error);
  334 }
  335 
  336 static int
  337 g_nop_create(struct gctl_req *req, struct g_class *mp, struct g_provider *pp,
  338     const char *gnopname, int ioerror, u_int count_until_fail,
  339     u_int rfailprob, u_int wfailprob, u_int delaymsec, u_int rdelayprob,
  340     u_int wdelayprob, off_t offset, off_t size, u_int secsize, off_t stripesize,
  341     off_t stripeoffset, const char *physpath)
  342 {
  343         struct g_nop_softc *sc;
  344         struct g_geom *gp;
  345         struct g_provider *newpp;
  346         struct g_consumer *cp;
  347         struct g_geom_alias *gap;
  348         char name[64];
  349         int error, n;
  350         off_t explicitsize;
  351 
  352         g_topology_assert();
  353 
  354         gp = NULL;
  355         newpp = NULL;
  356         cp = NULL;
  357 
  358         if ((offset % pp->sectorsize) != 0) {
  359                 gctl_error(req, "Invalid offset for provider %s.", pp->name);
  360                 return (EINVAL);
  361         }
  362         if ((size % pp->sectorsize) != 0) {
  363                 gctl_error(req, "Invalid size for provider %s.", pp->name);
  364                 return (EINVAL);
  365         }
  366         if (offset >= pp->mediasize) {
  367                 gctl_error(req, "Invalid offset for provider %s.", pp->name);
  368                 return (EINVAL);
  369         }
  370         explicitsize = size;
  371         if (size == 0)
  372                 size = pp->mediasize - offset;
  373         if (offset + size > pp->mediasize) {
  374                 gctl_error(req, "Invalid size for provider %s.", pp->name);
  375                 return (EINVAL);
  376         }
  377         if (secsize == 0)
  378                 secsize = pp->sectorsize;
  379         else if ((secsize % pp->sectorsize) != 0) {
  380                 gctl_error(req, "Invalid secsize for provider %s.", pp->name);
  381                 return (EINVAL);
  382         }
  383         if (secsize > maxphys) {
  384                 gctl_error(req, "secsize is too big.");
  385                 return (EINVAL);
  386         }
  387         size -= size % secsize;
  388         if ((stripesize % pp->sectorsize) != 0) {
  389                 gctl_error(req, "Invalid stripesize for provider %s.", pp->name);
  390                 return (EINVAL);
  391         }
  392         if ((stripeoffset % pp->sectorsize) != 0) {
  393                 gctl_error(req, "Invalid stripeoffset for provider %s.", pp->name);
  394                 return (EINVAL);
  395         }
  396         if (stripesize != 0 && stripeoffset >= stripesize) {
  397                 gctl_error(req, "stripeoffset is too big.");
  398                 return (EINVAL);
  399         }
  400         if (gnopname != NULL && !g_nop_verify_nprefix(gnopname)) {
  401                 gctl_error(req, "Name %s is invalid.", gnopname);
  402                 return (EINVAL);
  403         }
  404 
  405         if (gnopname != NULL) {
  406                 n = snprintf(name, sizeof(name), "%s%s", gnopname,
  407                     G_NOP_SUFFIX);
  408         } else {
  409                 n = snprintf(name, sizeof(name), "%s%s", pp->name,
  410                     G_NOP_SUFFIX);
  411         }
  412         if (n <= 0 || n >= sizeof(name)) {
  413                 gctl_error(req, "Invalid provider name.");
  414                 return (EINVAL);
  415         }
  416         LIST_FOREACH(gp, &mp->geom, geom) {
  417                 if (strcmp(gp->name, name) == 0) {
  418                         gctl_error(req, "Provider %s already exists.", name);
  419                         return (EEXIST);
  420                 }
  421         }
  422         gp = g_new_geomf(mp, "%s", name);
  423         sc = g_malloc(sizeof(*sc), M_WAITOK | M_ZERO);
  424         sc->sc_offset = offset;
  425         sc->sc_explicitsize = explicitsize;
  426         sc->sc_stripesize = stripesize;
  427         sc->sc_stripeoffset = stripeoffset;
  428         if (physpath && strcmp(physpath, G_NOP_PHYSPATH_PASSTHROUGH)) {
  429                 sc->sc_physpath = strndup(physpath, MAXPATHLEN, M_GEOM);
  430         } else
  431                 sc->sc_physpath = NULL;
  432         sc->sc_error = ioerror;
  433         sc->sc_count_until_fail = count_until_fail;
  434         sc->sc_rfailprob = rfailprob;
  435         sc->sc_wfailprob = wfailprob;
  436         sc->sc_delaymsec = delaymsec;
  437         sc->sc_rdelayprob = rdelayprob;
  438         sc->sc_wdelayprob = wdelayprob;
  439         sc->sc_reads = 0;
  440         sc->sc_writes = 0;
  441         sc->sc_deletes = 0;
  442         sc->sc_getattrs = 0;
  443         sc->sc_flushes = 0;
  444         sc->sc_speedups = 0;
  445         sc->sc_cmd0s = 0;
  446         sc->sc_cmd1s = 0;
  447         sc->sc_cmd2s = 0;
  448         sc->sc_readbytes = 0;
  449         sc->sc_wrotebytes = 0;
  450         TAILQ_INIT(&sc->sc_head_delay);
  451         mtx_init(&sc->sc_lock, "gnop lock", NULL, MTX_DEF);
  452         gp->softc = sc;
  453 
  454         newpp = g_new_providerf(gp, "%s", gp->name);
  455         newpp->flags |= G_PF_DIRECT_SEND | G_PF_DIRECT_RECEIVE;
  456         newpp->mediasize = size;
  457         newpp->sectorsize = secsize;
  458         newpp->stripesize = stripesize;
  459         newpp->stripeoffset = stripeoffset;
  460         LIST_FOREACH(gap, &pp->aliases, ga_next)
  461                 g_provider_add_alias(newpp, "%s%s", gap->ga_alias, G_NOP_SUFFIX);
  462 
  463         cp = g_new_consumer(gp);
  464         cp->flags |= G_CF_DIRECT_SEND | G_CF_DIRECT_RECEIVE;
  465         error = g_attach(cp, pp);
  466         if (error != 0) {
  467                 gctl_error(req, "Cannot attach to provider %s.", pp->name);
  468                 goto fail;
  469         }
  470 
  471         newpp->flags |= pp->flags & G_PF_ACCEPT_UNMAPPED;
  472         g_error_provider(newpp, 0);
  473         G_NOP_DEBUG(0, "Device %s created.", gp->name);
  474         return (0);
  475 fail:
  476         if (cp->provider != NULL)
  477                 g_detach(cp);
  478         g_destroy_consumer(cp);
  479         g_destroy_provider(newpp);
  480         mtx_destroy(&sc->sc_lock);
  481         free(sc->sc_physpath, M_GEOM);
  482         g_free(gp->softc);
  483         g_destroy_geom(gp);
  484         return (error);
  485 }
  486 
  487 static void
  488 g_nop_providergone(struct g_provider *pp)
  489 {
  490         struct g_geom *gp = pp->geom;
  491         struct g_nop_softc *sc = gp->softc;
  492 
  493         KASSERT(TAILQ_EMPTY(&sc->sc_head_delay),
  494             ("delayed request list is not empty"));
  495 
  496         gp->softc = NULL;
  497         free(sc->sc_physpath, M_GEOM);
  498         mtx_destroy(&sc->sc_lock);
  499         g_free(sc);
  500 }
  501 
  502 static int
  503 g_nop_destroy(struct g_geom *gp, boolean_t force)
  504 {
  505         struct g_nop_softc *sc;
  506         struct g_provider *pp;
  507 
  508         g_topology_assert();
  509         sc = gp->softc;
  510         if (sc == NULL)
  511                 return (ENXIO);
  512         pp = LIST_FIRST(&gp->provider);
  513         if (pp != NULL && (pp->acr != 0 || pp->acw != 0 || pp->ace != 0)) {
  514                 if (force) {
  515                         G_NOP_DEBUG(0, "Device %s is still open, so it "
  516                             "can't be definitely removed.", pp->name);
  517                 } else {
  518                         G_NOP_DEBUG(1, "Device %s is still open (r%dw%de%d).",
  519                             pp->name, pp->acr, pp->acw, pp->ace);
  520                         return (EBUSY);
  521                 }
  522         } else {
  523                 G_NOP_DEBUG(0, "Device %s removed.", gp->name);
  524         }
  525 
  526         g_wither_geom(gp, ENXIO);
  527 
  528         return (0);
  529 }
  530 
  531 static int
  532 g_nop_destroy_geom(struct gctl_req *req, struct g_class *mp, struct g_geom *gp)
  533 {
  534 
  535         return (g_nop_destroy(gp, 0));
  536 }
  537 
  538 static void
  539 g_nop_ctl_create(struct gctl_req *req, struct g_class *mp)
  540 {
  541         struct g_provider *pp;
  542         intmax_t *val, error, rfailprob, wfailprob, count_until_fail, offset,
  543             secsize, size, stripesize, stripeoffset, delaymsec,
  544             rdelayprob, wdelayprob;
  545         const char *physpath, *gnopname;
  546         char param[16];
  547         int i, *nargs;
  548 
  549         g_topology_assert();
  550 
  551         error = -1;
  552         rfailprob = -1;
  553         wfailprob = -1;
  554         count_until_fail = -1;
  555         offset = 0;
  556         secsize = 0;
  557         size = 0;
  558         stripesize = 0;
  559         stripeoffset = 0;
  560         delaymsec = -1;
  561         rdelayprob = -1;
  562         wdelayprob = -1;
  563 
  564         nargs = gctl_get_paraml(req, "nargs", sizeof(*nargs));
  565         if (nargs == NULL) {
  566                 gctl_error(req, "No '%s' argument", "nargs");
  567                 return;
  568         }
  569         if (*nargs <= 0) {
  570                 gctl_error(req, "Missing device(s).");
  571                 return;
  572         }
  573         val = gctl_get_paraml_opt(req, "error", sizeof(*val));
  574         if (val != NULL) {
  575                 error = *val;
  576         }
  577         val = gctl_get_paraml_opt(req, "rfailprob", sizeof(*val));
  578         if (val != NULL) {
  579                 rfailprob = *val;
  580                 if (rfailprob < -1 || rfailprob > 100) {
  581                         gctl_error(req, "Invalid '%s' argument", "rfailprob");
  582                         return;
  583                 }
  584         }
  585         val = gctl_get_paraml_opt(req, "wfailprob", sizeof(*val));
  586         if (val != NULL) {
  587                 wfailprob = *val;
  588                 if (wfailprob < -1 || wfailprob > 100) {
  589                         gctl_error(req, "Invalid '%s' argument", "wfailprob");
  590                         return;
  591                 }
  592         }
  593         val = gctl_get_paraml_opt(req, "delaymsec", sizeof(*val));
  594         if (val != NULL) {
  595                 delaymsec = *val;
  596                 if (delaymsec < 1 && delaymsec != -1) {
  597                         gctl_error(req, "Invalid '%s' argument", "delaymsec");
  598                         return;
  599                 }
  600         }
  601         val = gctl_get_paraml_opt(req, "rdelayprob", sizeof(*val));
  602         if (val != NULL) {
  603                 rdelayprob = *val;
  604                 if (rdelayprob < -1 || rdelayprob > 100) {
  605                         gctl_error(req, "Invalid '%s' argument", "rdelayprob");
  606                         return;
  607                 }
  608         }
  609         val = gctl_get_paraml_opt(req, "wdelayprob", sizeof(*val));
  610         if (val != NULL) {
  611                 wdelayprob = *val;
  612                 if (wdelayprob < -1 || wdelayprob > 100) {
  613                         gctl_error(req, "Invalid '%s' argument", "wdelayprob");
  614                         return;
  615                 }
  616         }
  617         val = gctl_get_paraml_opt(req, "count_until_fail", sizeof(*val));
  618         if (val != NULL) {
  619                 count_until_fail = *val;
  620                 if (count_until_fail < -1) {
  621                         gctl_error(req, "Invalid '%s' argument",
  622                             "count_until_fail");
  623                         return;
  624                 }
  625         }
  626         val = gctl_get_paraml_opt(req, "offset", sizeof(*val));
  627         if (val != NULL) {
  628                 offset = *val;
  629                 if (offset < 0) {
  630                         gctl_error(req, "Invalid '%s' argument", "offset");
  631                         return;
  632                 }
  633         }
  634         val = gctl_get_paraml_opt(req, "size", sizeof(*val));
  635         if (val != NULL) {
  636                 size = *val;
  637                 if (size < 0) {
  638                         gctl_error(req, "Invalid '%s' argument", "size");
  639                         return;
  640                 }
  641         }
  642         val = gctl_get_paraml_opt(req, "secsize", sizeof(*val));
  643         if (val != NULL) {
  644                 secsize = *val;
  645                 if (secsize < 0) {
  646                         gctl_error(req, "Invalid '%s' argument", "secsize");
  647                         return;
  648                 }
  649         }
  650         val = gctl_get_paraml_opt(req, "stripesize", sizeof(*val));
  651         if (val != NULL) {
  652                 stripesize = *val;
  653                 if (stripesize < 0) {
  654                         gctl_error(req, "Invalid '%s' argument", "stripesize");
  655                         return;
  656                 }
  657         }
  658         val = gctl_get_paraml_opt(req, "stripeoffset", sizeof(*val));
  659         if (val != NULL) {
  660                 stripeoffset = *val;
  661                 if (stripeoffset < 0) {
  662                         gctl_error(req, "Invalid '%s' argument",
  663                             "stripeoffset");
  664                         return;
  665                 }
  666         }
  667         physpath = gctl_get_asciiparam(req, "physpath");
  668         gnopname = gctl_get_asciiparam(req, "gnopname");
  669 
  670         for (i = 0; i < *nargs; i++) {
  671                 snprintf(param, sizeof(param), "arg%d", i);
  672                 pp = gctl_get_provider(req, param);
  673                 if (pp == NULL)
  674                         return;
  675                 if (g_nop_create(req, mp, pp,
  676                     gnopname,
  677                     error == -1 ? EIO : (int)error,
  678                     count_until_fail == -1 ? 0 : (u_int)count_until_fail,
  679                     rfailprob == -1 ? 0 : (u_int)rfailprob,
  680                     wfailprob == -1 ? 0 : (u_int)wfailprob,
  681                     delaymsec == -1 ? 1 : (u_int)delaymsec,
  682                     rdelayprob == -1 ? 0 : (u_int)rdelayprob,
  683                     wdelayprob == -1 ? 0 : (u_int)wdelayprob,
  684                     (off_t)offset, (off_t)size, (u_int)secsize,
  685                     (off_t)stripesize, (off_t)stripeoffset,
  686                     physpath) != 0) {
  687                         return;
  688                 }
  689         }
  690 }
  691 
  692 static void
  693 g_nop_ctl_configure(struct gctl_req *req, struct g_class *mp)
  694 {
  695         struct g_nop_softc *sc;
  696         struct g_provider *pp;
  697         intmax_t *val, delaymsec, error, rdelayprob, rfailprob, wdelayprob,
  698             wfailprob, count_until_fail;
  699         char param[16];
  700         int i, *nargs;
  701 
  702         g_topology_assert();
  703 
  704         count_until_fail = -1;
  705         delaymsec = -1;
  706         error = -1;
  707         rdelayprob = -1;
  708         rfailprob = -1;
  709         wdelayprob = -1;
  710         wfailprob = -1;
  711 
  712         nargs = gctl_get_paraml(req, "nargs", sizeof(*nargs));
  713         if (nargs == NULL) {
  714                 gctl_error(req, "No '%s' argument", "nargs");
  715                 return;
  716         }
  717         if (*nargs <= 0) {
  718                 gctl_error(req, "Missing device(s).");
  719                 return;
  720         }
  721         val = gctl_get_paraml_opt(req, "error", sizeof(*val));
  722         if (val != NULL) {
  723                 error = *val;
  724         }
  725         val = gctl_get_paraml_opt(req, "count_until_fail", sizeof(*val));
  726         if (val != NULL) {
  727                 count_until_fail = *val;
  728         }
  729         val = gctl_get_paraml_opt(req, "rfailprob", sizeof(*val));
  730         if (val != NULL) {
  731                 rfailprob = *val;
  732                 if (rfailprob < -1 || rfailprob > 100) {
  733                         gctl_error(req, "Invalid '%s' argument", "rfailprob");
  734                         return;
  735                 }
  736         }
  737         val = gctl_get_paraml_opt(req, "wfailprob", sizeof(*val));
  738         if (val != NULL) {
  739                 wfailprob = *val;
  740                 if (wfailprob < -1 || wfailprob > 100) {
  741                         gctl_error(req, "Invalid '%s' argument", "wfailprob");
  742                         return;
  743                 }
  744         }
  745         val = gctl_get_paraml_opt(req, "delaymsec", sizeof(*val));
  746         if (val != NULL) {
  747                 delaymsec = *val;
  748                 if (delaymsec < 1 && delaymsec != -1) {
  749                         gctl_error(req, "Invalid '%s' argument", "delaymsec");
  750                         return;
  751                 }
  752         }
  753         val = gctl_get_paraml_opt(req, "rdelayprob", sizeof(*val));
  754         if (val != NULL) {
  755                 rdelayprob = *val;
  756                 if (rdelayprob < -1 || rdelayprob > 100) {
  757                         gctl_error(req, "Invalid '%s' argument", "rdelayprob");
  758                         return;
  759                 }
  760         }
  761         val = gctl_get_paraml_opt(req, "wdelayprob", sizeof(*val));
  762         if (val != NULL) {
  763                 wdelayprob = *val;
  764                 if (wdelayprob < -1 || wdelayprob > 100) {
  765                         gctl_error(req, "Invalid '%s' argument", "wdelayprob");
  766                         return;
  767                 }
  768         }
  769 
  770         for (i = 0; i < *nargs; i++) {
  771                 snprintf(param, sizeof(param), "arg%d", i);
  772                 pp = gctl_get_provider(req, param);
  773                 if (pp == NULL)
  774                         return;
  775                 if (pp->geom->class != mp) {
  776                         G_NOP_DEBUG(1, "Provider %s is invalid.", pp->name);
  777                         gctl_error(req, "Provider %s is invalid.", pp->name);
  778                         return;
  779                 }
  780                 sc = pp->geom->softc;
  781                 if (error != -1)
  782                         sc->sc_error = (int)error;
  783                 if (rfailprob != -1)
  784                         sc->sc_rfailprob = (u_int)rfailprob;
  785                 if (wfailprob != -1)
  786                         sc->sc_wfailprob = (u_int)wfailprob;
  787                 if (rdelayprob != -1)
  788                         sc->sc_rdelayprob = (u_int)rdelayprob;
  789                 if (wdelayprob != -1)
  790                         sc->sc_wdelayprob = (u_int)wdelayprob;
  791                 if (delaymsec != -1)
  792                         sc->sc_delaymsec = (u_int)delaymsec;
  793                 if (count_until_fail != -1)
  794                         sc->sc_count_until_fail = (u_int)count_until_fail;
  795         }
  796 }
  797 
  798 static struct g_geom *
  799 g_nop_find_geom(struct g_class *mp, const char *name)
  800 {
  801         struct g_geom *gp;
  802 
  803         LIST_FOREACH(gp, &mp->geom, geom) {
  804                 if (strcmp(gp->name, name) == 0)
  805                         return (gp);
  806         }
  807         return (NULL);
  808 }
  809 
  810 static void
  811 g_nop_ctl_destroy(struct gctl_req *req, struct g_class *mp)
  812 {
  813         int *nargs, *force, error, i;
  814         struct g_geom *gp;
  815         const char *name;
  816         char param[16];
  817 
  818         g_topology_assert();
  819 
  820         nargs = gctl_get_paraml(req, "nargs", sizeof(*nargs));
  821         if (nargs == NULL) {
  822                 gctl_error(req, "No '%s' argument", "nargs");
  823                 return;
  824         }
  825         if (*nargs <= 0) {
  826                 gctl_error(req, "Missing device(s).");
  827                 return;
  828         }
  829         force = gctl_get_paraml(req, "force", sizeof(*force));
  830         if (force == NULL) {
  831                 gctl_error(req, "No 'force' argument");
  832                 return;
  833         }
  834 
  835         for (i = 0; i < *nargs; i++) {
  836                 snprintf(param, sizeof(param), "arg%d", i);
  837                 name = gctl_get_asciiparam(req, param);
  838                 if (name == NULL) {
  839                         gctl_error(req, "No 'arg%d' argument", i);
  840                         return;
  841                 }
  842                 if (strncmp(name, _PATH_DEV, strlen(_PATH_DEV)) == 0)
  843                         name += strlen(_PATH_DEV);
  844                 gp = g_nop_find_geom(mp, name);
  845                 if (gp == NULL) {
  846                         G_NOP_DEBUG(1, "Device %s is invalid.", name);
  847                         gctl_error(req, "Device %s is invalid.", name);
  848                         return;
  849                 }
  850                 error = g_nop_destroy(gp, *force);
  851                 if (error != 0) {
  852                         gctl_error(req, "Cannot destroy device %s (error=%d).",
  853                             gp->name, error);
  854                         return;
  855                 }
  856         }
  857 }
  858 
  859 static void
  860 g_nop_ctl_reset(struct gctl_req *req, struct g_class *mp)
  861 {
  862         struct g_nop_softc *sc;
  863         struct g_provider *pp;
  864         char param[16];
  865         int i, *nargs;
  866 
  867         g_topology_assert();
  868 
  869         nargs = gctl_get_paraml(req, "nargs", sizeof(*nargs));
  870         if (nargs == NULL) {
  871                 gctl_error(req, "No '%s' argument", "nargs");
  872                 return;
  873         }
  874         if (*nargs <= 0) {
  875                 gctl_error(req, "Missing device(s).");
  876                 return;
  877         }
  878 
  879         for (i = 0; i < *nargs; i++) {
  880                 snprintf(param, sizeof(param), "arg%d", i);
  881                 pp = gctl_get_provider(req, param);
  882                 if (pp == NULL)
  883                         return;
  884                 if (pp->geom->class != mp) {
  885                         G_NOP_DEBUG(1, "Provider %s is invalid.", pp->name);
  886                         gctl_error(req, "Provider %s is invalid.", pp->name);
  887                         return;
  888                 }
  889                 sc = pp->geom->softc;
  890                 sc->sc_reads = 0;
  891                 sc->sc_writes = 0;
  892                 sc->sc_deletes = 0;
  893                 sc->sc_getattrs = 0;
  894                 sc->sc_flushes = 0;
  895                 sc->sc_speedups = 0;
  896                 sc->sc_cmd0s = 0;
  897                 sc->sc_cmd1s = 0;
  898                 sc->sc_cmd2s = 0;
  899                 sc->sc_readbytes = 0;
  900                 sc->sc_wrotebytes = 0;
  901         }
  902 }
  903 
  904 static void
  905 g_nop_config(struct gctl_req *req, struct g_class *mp, const char *verb)
  906 {
  907         uint32_t *version;
  908 
  909         g_topology_assert();
  910 
  911         version = gctl_get_paraml(req, "version", sizeof(*version));
  912         if (version == NULL) {
  913                 gctl_error(req, "No '%s' argument.", "version");
  914                 return;
  915         }
  916         if (*version != G_NOP_VERSION) {
  917                 gctl_error(req, "Userland and kernel parts are out of sync.");
  918                 return;
  919         }
  920 
  921         if (strcmp(verb, "create") == 0) {
  922                 g_nop_ctl_create(req, mp);
  923                 return;
  924         } else if (strcmp(verb, "configure") == 0) {
  925                 g_nop_ctl_configure(req, mp);
  926                 return;
  927         } else if (strcmp(verb, "destroy") == 0) {
  928                 g_nop_ctl_destroy(req, mp);
  929                 return;
  930         } else if (strcmp(verb, "reset") == 0) {
  931                 g_nop_ctl_reset(req, mp);
  932                 return;
  933         }
  934 
  935         gctl_error(req, "Unknown verb.");
  936 }
  937 
  938 static void
  939 g_nop_dumpconf(struct sbuf *sb, const char *indent, struct g_geom *gp,
  940     struct g_consumer *cp, struct g_provider *pp)
  941 {
  942         struct g_nop_softc *sc;
  943 
  944         if (pp != NULL || cp != NULL)
  945                 return;
  946         sc = gp->softc;
  947         sbuf_printf(sb, "%s<Offset>%jd</Offset>\n", indent,
  948             (intmax_t)sc->sc_offset);
  949         sbuf_printf(sb, "%s<ReadFailProb>%u</ReadFailProb>\n", indent,
  950             sc->sc_rfailprob);
  951         sbuf_printf(sb, "%s<WriteFailProb>%u</WriteFailProb>\n", indent,
  952             sc->sc_wfailprob);
  953         sbuf_printf(sb, "%s<ReadDelayedProb>%u</ReadDelayedProb>\n", indent,
  954             sc->sc_rdelayprob);
  955         sbuf_printf(sb, "%s<WriteDelayedProb>%u</WriteDelayedProb>\n", indent,
  956             sc->sc_wdelayprob);
  957         sbuf_printf(sb, "%s<Delay>%d</Delay>\n", indent, sc->sc_delaymsec);
  958         sbuf_printf(sb, "%s<CountUntilFail>%u</CountUntilFail>\n", indent,
  959             sc->sc_count_until_fail);
  960         sbuf_printf(sb, "%s<Error>%d</Error>\n", indent, sc->sc_error);
  961         sbuf_printf(sb, "%s<Reads>%ju</Reads>\n", indent, sc->sc_reads);
  962         sbuf_printf(sb, "%s<Writes>%ju</Writes>\n", indent, sc->sc_writes);
  963         sbuf_printf(sb, "%s<Deletes>%ju</Deletes>\n", indent, sc->sc_deletes);
  964         sbuf_printf(sb, "%s<Getattrs>%ju</Getattrs>\n", indent, sc->sc_getattrs);
  965         sbuf_printf(sb, "%s<Flushes>%ju</Flushes>\n", indent, sc->sc_flushes);
  966         sbuf_printf(sb, "%s<Speedups>%ju</Speedups>\n", indent, sc->sc_speedups);
  967         sbuf_printf(sb, "%s<Cmd0s>%ju</Cmd0s>\n", indent, sc->sc_cmd0s);
  968         sbuf_printf(sb, "%s<Cmd1s>%ju</Cmd1s>\n", indent, sc->sc_cmd1s);
  969         sbuf_printf(sb, "%s<Cmd2s>%ju</Cmd2s>\n", indent, sc->sc_cmd2s);
  970         sbuf_printf(sb, "%s<ReadBytes>%ju</ReadBytes>\n", indent,
  971             sc->sc_readbytes);
  972         sbuf_printf(sb, "%s<WroteBytes>%ju</WroteBytes>\n", indent,
  973             sc->sc_wrotebytes);
  974 }
  975 
  976 DECLARE_GEOM_CLASS(g_nop_class, g_nop);
  977 MODULE_VERSION(geom_nop, 0);

Cache object: ee2f87e4b36bf877f173bb03a20a1d1e


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