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/vinum/geom_vinum.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 Lukas Ertl
    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 AUTHOR 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 AUTHOR 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 
   28 #include <sys/cdefs.h>
   29 __FBSDID("$FreeBSD$");
   30 
   31 #include <sys/param.h>
   32 #include <sys/bio.h>
   33 #include <sys/kernel.h>
   34 #include <sys/lock.h>
   35 #include <sys/malloc.h>
   36 #include <sys/module.h>
   37 #include <sys/mutex.h>
   38 #include <sys/systm.h>
   39 
   40 #include <geom/geom.h>
   41 #include <geom/vinum/geom_vinum_var.h>
   42 #include <geom/vinum/geom_vinum.h>
   43 #include <geom/vinum/geom_vinum_share.h>
   44 
   45 #if 0
   46 SYSCTL_DECL(_kern_geom);
   47 SYSCTL_NODE(_kern_geom, OID_AUTO, vinum, CTLFLAG_RW, 0, "GEOM_VINUM stuff");
   48 SYSCTL_UINT(_kern_geom_vinum, OID_AUTO, debug, CTLFLAG_RW, &gv_debug, 0,
   49     "Debug level");
   50 #endif
   51 
   52 int     gv_create(struct g_geom *, struct gctl_req *);
   53 
   54 static void
   55 gv_orphan(struct g_consumer *cp)
   56 {
   57         struct g_geom *gp;
   58         struct gv_softc *sc;
   59         int error;
   60         
   61         g_topology_assert();
   62 
   63         KASSERT(cp != NULL, ("gv_orphan: null cp"));
   64         gp = cp->geom;
   65         KASSERT(gp != NULL, ("gv_orphan: null gp"));
   66         sc = gp->softc;
   67 
   68         g_trace(G_T_TOPOLOGY, "gv_orphan(%s)", gp->name);
   69 
   70         if (cp->acr != 0 || cp->acw != 0 || cp->ace != 0)
   71                 g_access(cp, -cp->acr, -cp->acw, -cp->ace);
   72         error = cp->provider->error;
   73         if (error == 0)
   74                 error = ENXIO;
   75         g_detach(cp);
   76         g_destroy_consumer(cp);
   77         if (!LIST_EMPTY(&gp->consumer))
   78                 return;
   79         g_free(sc);
   80         g_wither_geom(gp, error);
   81 }
   82 
   83 static void
   84 gv_start(struct bio *bp)
   85 {
   86         struct bio *bp2;
   87         struct g_geom *gp;
   88         
   89         gp = bp->bio_to->geom;
   90         switch(bp->bio_cmd) {
   91         case BIO_READ:
   92         case BIO_WRITE:
   93         case BIO_DELETE:
   94                 bp2 = g_clone_bio(bp);
   95                 if (bp2 == NULL)
   96                         g_io_deliver(bp, ENOMEM);
   97                 else {
   98                         bp2->bio_done = g_std_done;
   99                         g_io_request(bp2, LIST_FIRST(&gp->consumer));
  100                 }
  101                 return;
  102         default:
  103                 g_io_deliver(bp, EOPNOTSUPP);
  104                 return;
  105         }
  106 }
  107 
  108 static int
  109 gv_access(struct g_provider *pp, int dr, int dw, int de)
  110 {
  111         struct g_geom *gp;
  112         struct g_consumer *cp;
  113         int error;
  114         
  115         gp = pp->geom;
  116         error = ENXIO;
  117         cp = LIST_FIRST(&gp->consumer);
  118         error = g_access(cp, dr, dw, de);
  119         return (error);
  120 }
  121 
  122 static void
  123 gv_init(struct g_class *mp)
  124 {
  125         struct g_geom *gp;
  126         struct gv_softc *sc;
  127 
  128         g_trace(G_T_TOPOLOGY, "gv_init(%p)", mp);
  129 
  130         gp = g_new_geomf(mp, "VINUM");
  131         gp->spoiled = gv_orphan;
  132         gp->orphan = gv_orphan;
  133         gp->access = gv_access;
  134         gp->start = gv_start;
  135         gp->softc = g_malloc(sizeof(struct gv_softc), M_WAITOK | M_ZERO);
  136         sc = gp->softc;
  137         sc->geom = gp;
  138         LIST_INIT(&sc->drives);
  139         LIST_INIT(&sc->subdisks);
  140         LIST_INIT(&sc->plexes);
  141         LIST_INIT(&sc->volumes);
  142 }
  143 
  144 /* Handle userland requests for creating new objects. */
  145 int
  146 gv_create(struct g_geom *gp, struct gctl_req *req)
  147 {
  148         struct gv_softc *sc;
  149         struct gv_drive *d, *d2;
  150         struct gv_plex *p, *p2;
  151         struct gv_sd *s, *s2;
  152         struct gv_volume *v, *v2;
  153         struct g_consumer *cp;
  154         struct g_provider *pp;
  155         int error, i, *drives, *plexes, *subdisks, *volumes;
  156         char buf[20], errstr[ERRBUFSIZ];
  157 
  158         g_topology_assert();
  159 
  160         sc = gp->softc;
  161 
  162         /* Find out how many of each object have been passed in. */
  163         volumes = gctl_get_paraml(req, "volumes", sizeof(*volumes));
  164         plexes = gctl_get_paraml(req, "plexes", sizeof(*plexes));
  165         subdisks = gctl_get_paraml(req, "subdisks", sizeof(*subdisks));
  166         drives = gctl_get_paraml(req, "drives", sizeof(*drives));
  167 
  168         /* First, handle drive definitions ... */
  169         for (i = 0; i < *drives; i++) {
  170                 snprintf(buf, sizeof(buf), "drive%d", i);
  171                 d2 = gctl_get_paraml(req, buf, sizeof(*d2));
  172 
  173                 d = gv_find_drive(sc, d2->name);
  174                 if (d != NULL) {
  175                         gctl_error(req, "drive '%s' is already known",
  176                             d->name);
  177                         continue;
  178                 }
  179 
  180                 d = g_malloc(sizeof(*d), M_WAITOK | M_ZERO);
  181                 bcopy(d2, d, sizeof(*d));
  182 
  183                 /*
  184                  * Make sure that the provider specified in the drive
  185                  * specification is an active GEOM provider.
  186                  */
  187                 pp = g_provider_by_name(d->device);
  188                 if (pp == NULL) {
  189                         gctl_error(req, "%s: drive not found", d->device);
  190                         g_free(d);
  191                         return (-1);
  192                 }
  193                 d->size = pp->mediasize - GV_DATA_START;
  194                 d->avail = d->size;
  195 
  196                 gv_config_new_drive(d);
  197 
  198                 d->flags |= GV_DRIVE_NEWBORN;
  199                 LIST_INSERT_HEAD(&sc->drives, d, drive);
  200         }
  201 
  202         /* ... then volume definitions ... */
  203         for (i = 0; i < *volumes; i++) {
  204                 error = 0;
  205                 snprintf(buf, sizeof(buf), "volume%d", i);
  206                 v2 = gctl_get_paraml(req, buf, sizeof(*v2));
  207 
  208                 v = gv_find_vol(sc, v2->name);
  209                 if (v != NULL) {
  210                         gctl_error(req, "volume '%s' is already known",
  211                             v->name);
  212                         return (-1);
  213                 }
  214 
  215                 v = g_malloc(sizeof(*v), M_WAITOK | M_ZERO);
  216                 bcopy(v2, v, sizeof(*v));
  217 
  218                 v->vinumconf = sc;
  219                 LIST_INIT(&v->plexes);
  220                 LIST_INSERT_HEAD(&sc->volumes, v, volume);
  221         }
  222 
  223         /* ... then plex definitions ... */
  224         for (i = 0; i < *plexes; i++) {
  225                 error = 0;
  226                 snprintf(buf, sizeof(buf), "plex%d", i);
  227                 p2 = gctl_get_paraml(req, buf, sizeof(*p2));
  228 
  229                 p = gv_find_plex(sc, p2->name);
  230                 if (p != NULL) {
  231                         gctl_error(req, "plex '%s' is already known", p->name);
  232                         return (-1);
  233                 }
  234 
  235                 p = g_malloc(sizeof(*p), M_WAITOK | M_ZERO);
  236                 bcopy(p2, p, sizeof(*p));
  237 
  238                 /* Find the volume this plex should be attached to. */
  239                 v = gv_find_vol(sc, p->volume);
  240                 if (v == NULL) {
  241                         gctl_error(req, "volume '%s' not found", p->volume);
  242                         g_free(p);
  243                         continue;
  244                 }
  245                 if (v->plexcount)
  246                         p->flags |= GV_PLEX_ADDED;
  247                 p->vol_sc = v;
  248                 v->plexcount++;
  249                 LIST_INSERT_HEAD(&v->plexes, p, in_volume);
  250 
  251                 p->vinumconf = sc;
  252                 p->flags |= GV_PLEX_NEWBORN;
  253                 LIST_INIT(&p->subdisks);
  254                 LIST_INSERT_HEAD(&sc->plexes, p, plex);
  255         }
  256 
  257         /* ... and finally, subdisk definitions. */
  258         for (i = 0; i < *subdisks; i++) {
  259                 error = 0;
  260                 snprintf(buf, sizeof(buf), "sd%d", i);
  261                 s2 = gctl_get_paraml(req, buf, sizeof(*s2));
  262 
  263                 s = gv_find_sd(sc, s2->name);
  264                 if (s != NULL) {
  265                         gctl_error(req, "subdisk '%s' is already known",
  266                             s->name);
  267                         return (-1);
  268                 }
  269 
  270                 s = g_malloc(sizeof(*s), M_WAITOK | M_ZERO);
  271                 bcopy(s2, s, sizeof(*s));
  272 
  273                 /* Find the drive where this subdisk should be put on. */
  274                 d = gv_find_drive(sc, s->drive);
  275 
  276                 /* drive not found - XXX */
  277                 if (d == NULL) {
  278                         gctl_error(req, "drive '%s' not found", s->drive);
  279                         g_free(s);
  280                         continue;
  281                 }
  282 
  283                 /* Find the plex where this subdisk belongs to. */
  284                 p = gv_find_plex(sc, s->plex);
  285 
  286                 /* plex not found - XXX */
  287                 if (p == NULL) {
  288                         gctl_error(req, "plex '%s' not found\n", s->plex);
  289                         g_free(s);
  290                         continue;
  291                 }
  292 
  293                 /*
  294                  * First we give the subdisk to the drive, to handle autosized
  295                  * values ...
  296                  */
  297                 error = gv_sd_to_drive(sc, d, s, errstr, sizeof(errstr));
  298                 if (error) {
  299                         gctl_error(req, errstr);
  300                         g_free(s);
  301                         continue;
  302                 }
  303 
  304                 /*
  305                  * Then, we give the subdisk to the plex; we check if the
  306                  * given values are correct and maybe adjust them.
  307                  */
  308                 error = gv_sd_to_plex(p, s, 1);
  309                 if (error) {
  310                         gctl_error(req, "GEOM_VINUM: couldn't give sd '%s' "
  311                             "to plex '%s'\n", s->name, p->name);
  312                         if (s->drive_sc)
  313                                 LIST_REMOVE(s, from_drive);
  314                         gv_free_sd(s);
  315                         g_free(s);
  316                         /*
  317                          * If this subdisk can't be created, we won't create
  318                          * the attached plex either, if it is also a new one.
  319                          */
  320                         if (!(p->flags & GV_PLEX_NEWBORN))
  321                                 continue;
  322                         LIST_FOREACH_SAFE(s, &p->subdisks, in_plex, s2) {
  323                                 if (s->drive_sc)
  324                                         LIST_REMOVE(s, from_drive);
  325                                 p->sdcount--;
  326                                 LIST_REMOVE(s, in_plex);
  327                                 LIST_REMOVE(s, sd);
  328                                 gv_free_sd(s);
  329                                 g_free(s);
  330                         }
  331                         if (p->vol_sc != NULL) {
  332                                 LIST_REMOVE(p, in_volume);
  333                                 p->vol_sc->plexcount--;
  334                         }
  335                         LIST_REMOVE(p, plex);
  336                         g_free(p);
  337                         continue;
  338                 }
  339                 s->flags |= GV_SD_NEWBORN;
  340 
  341                 s->vinumconf = sc;
  342                 LIST_INSERT_HEAD(&sc->subdisks, s, sd);
  343         }
  344 
  345         LIST_FOREACH(s, &sc->subdisks, sd)
  346                 gv_update_sd_state(s);
  347         LIST_FOREACH(p, &sc->plexes, plex)
  348                 gv_update_plex_config(p);
  349         LIST_FOREACH(v, &sc->volumes, volume)
  350                 gv_update_vol_state(v);
  351 
  352         /*
  353          * Write out the configuration to each drive.  If the drive doesn't
  354          * have a valid geom_slice geom yet, attach it temporarily to our VINUM
  355          * geom.
  356          */
  357         LIST_FOREACH(d, &sc->drives, drive) {
  358                 if (d->geom == NULL) {
  359                         /*
  360                          * XXX if the provider disapears before we get a chance
  361                          * to write the config out to the drive, should this
  362                          * be handled any differently?
  363                          */
  364                         pp = g_provider_by_name(d->device);
  365                         if (pp == NULL) {
  366                                 printf("geom_vinum: %s: drive disapeared?\n",
  367                                     d->device);
  368                                 continue;
  369                         }
  370                         cp = g_new_consumer(gp);
  371                         g_attach(cp, pp);
  372                         gv_save_config(cp, d, sc);
  373                         g_detach(cp);
  374                         g_destroy_consumer(cp);
  375                 } else
  376                         gv_save_config(NULL, d, sc);
  377                 d->flags &= ~GV_DRIVE_NEWBORN;
  378         }
  379 
  380         return (0);
  381 }
  382 
  383 static void
  384 gv_config(struct gctl_req *req, struct g_class *mp, char const *verb)
  385 {
  386         struct g_geom *gp;
  387         struct gv_softc *sc;
  388         struct sbuf *sb;
  389         char *comment;
  390 
  391         g_topology_assert();
  392 
  393         gp = LIST_FIRST(&mp->geom);
  394         sc = gp->softc;
  395 
  396         if (!strcmp(verb, "list")) {
  397                 gv_list(gp, req);
  398 
  399         /* Save our configuration back to disk. */
  400         } else if (!strcmp(verb, "saveconfig")) {
  401 
  402                 gv_save_config_all(sc);
  403 
  404         /* Return configuration in string form. */
  405         } else if (!strcmp(verb, "getconfig")) {
  406                 comment = gctl_get_param(req, "comment", NULL);
  407 
  408                 sb = sbuf_new(NULL, NULL, GV_CFG_LEN, SBUF_FIXEDLEN);
  409                 gv_format_config(sc, sb, 0, comment);
  410                 sbuf_finish(sb);
  411                 gctl_set_param(req, "config", sbuf_data(sb), sbuf_len(sb) + 1);
  412                 sbuf_delete(sb);
  413 
  414         } else if (!strcmp(verb, "create")) {
  415                 gv_create(gp, req);
  416 
  417         } else if (!strcmp(verb, "move")) {
  418                 gv_move(gp, req);
  419 
  420         } else if (!strcmp(verb, "parityop")) {
  421                 gv_parityop(gp, req);
  422 
  423         } else if (!strcmp(verb, "remove")) {
  424                 gv_remove(gp, req);
  425 
  426         } else if (!strcmp(verb, "rename")) {
  427                 gv_rename(gp, req);
  428         
  429         } else if (!strcmp(verb, "resetconfig")) {
  430                 gv_resetconfig(gp, req);
  431 
  432         } else if (!strcmp(verb, "start")) {
  433                 gv_start_obj(gp, req);
  434 
  435         } else if (!strcmp(verb, "setstate")) {
  436                 gv_setstate(gp, req);
  437 
  438         } else
  439                 gctl_error(req, "Unknown verb parameter");
  440 }
  441 
  442 #if 0
  443 static int
  444 gv_destroy_geom(struct gctl_req *req, struct g_class *mp, struct g_geom *gp)
  445 {
  446         struct g_geom *gp2;
  447         struct g_consumer *cp;
  448         struct gv_softc *sc;
  449         struct gv_drive *d, *d2;
  450         struct gv_plex *p, *p2;
  451         struct gv_sd *s, *s2;
  452         struct gv_volume *v, *v2;
  453         struct gv_freelist *fl, *fl2;
  454 
  455         g_trace(G_T_TOPOLOGY, "gv_destroy_geom: %s", gp->name);
  456         g_topology_assert();
  457 
  458         KASSERT(gp != NULL, ("gv_destroy_geom: null gp"));
  459         KASSERT(gp->softc != NULL, ("gv_destroy_geom: null sc"));
  460 
  461         sc = gp->softc;
  462 
  463         /*
  464          * Check if any of our drives is still open; if so, refuse destruction.
  465          */
  466         LIST_FOREACH(d, &sc->drives, drive) {
  467                 gp2 = d->geom;
  468                 cp = LIST_FIRST(&gp2->consumer);
  469                 if (cp != NULL)
  470                         g_access(cp, -1, -1, -1);
  471                 if (gv_is_open(gp2))
  472                         return (EBUSY);
  473         }
  474 
  475         /* Clean up and deallocate what we allocated. */
  476         LIST_FOREACH_SAFE(d, &sc->drives, drive, d2) {
  477                 LIST_REMOVE(d, drive);
  478                 g_free(d->hdr);
  479                 d->hdr = NULL;
  480                 LIST_FOREACH_SAFE(fl, &d->freelist, freelist, fl2) {
  481                         d->freelist_entries--;
  482                         LIST_REMOVE(fl, freelist);
  483                         g_free(fl);
  484                         fl = NULL;
  485                 }
  486                 d->geom->softc = NULL;
  487                 g_free(d);
  488         }
  489 
  490         LIST_FOREACH_SAFE(s, &sc->subdisks, sd, s2) {
  491                 LIST_REMOVE(s, sd);
  492                 s->drive_sc = NULL;
  493                 s->plex_sc = NULL;
  494                 s->provider = NULL;
  495                 s->consumer = NULL;
  496                 g_free(s);
  497         }
  498 
  499         LIST_FOREACH_SAFE(p, &sc->plexes, plex, p2) {
  500                 LIST_REMOVE(p, plex);
  501                 gv_kill_thread(p);
  502                 p->vol_sc = NULL;
  503                 p->geom->softc = NULL;
  504                 p->provider = NULL;
  505                 p->consumer = NULL;
  506                 if (p->org == GV_PLEX_RAID5) {
  507                         mtx_destroy(&p->worklist_mtx);
  508                 }
  509                 g_free(p);
  510         }
  511 
  512         LIST_FOREACH_SAFE(v, &sc->volumes, volume, v2) {
  513                 LIST_REMOVE(v, volume);
  514                 v->geom->softc = NULL;
  515                 g_free(v);
  516         }
  517 
  518         gp->softc = NULL;
  519         g_free(sc);
  520         g_wither_geom(gp, ENXIO);
  521         return (0);
  522 }
  523 #endif
  524 
  525 #define VINUM_CLASS_NAME "VINUM"
  526 
  527 static struct g_class g_vinum_class     = {
  528         .name = VINUM_CLASS_NAME,
  529         .version = G_VERSION,
  530         .init = gv_init,
  531         /*.destroy_geom = gv_destroy_geom,*/
  532         .ctlreq = gv_config,
  533 };
  534 
  535 DECLARE_GEOM_CLASS(g_vinum_class, g_vinum);

Cache object: 6c2b65f1cec284a30e89b804f0c26952


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