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_events.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) 2007 Lukas Ertl
    5  *  All rights reserved.
    6  * 
    7  * Redistribution and use in source and binary forms, with or without
    8  * modification, are permitted provided that the following conditions
    9  * are met:
   10  * 1. Redistributions of source code must retain the above copyright
   11  *    notice, this list of conditions and the following disclaimer.
   12  * 2. Redistributions in binary form must reproduce the above copyright
   13  *    notice, this list of conditions and the following disclaimer in the
   14  *    documentation and/or other materials provided with the distribution.
   15  * 
   16  * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND
   17  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   18  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   19  * ARE DISCLAIMED.  IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
   20  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   21  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   22  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   23  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   24  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   25  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   26  * SUCH DAMAGE.
   27  *
   28  */
   29 
   30 #include <sys/cdefs.h>
   31 __FBSDID("$FreeBSD$");
   32 
   33 #include <sys/param.h>
   34 #include <sys/kernel.h>
   35 #include <sys/lock.h>
   36 #include <sys/malloc.h>
   37 #include <sys/mutex.h>
   38 #include <sys/systm.h>
   39 
   40 #include <geom/geom.h>
   41 #include <geom/geom_dbg.h>
   42 #include <geom/vinum/geom_vinum_var.h>
   43 #include <geom/vinum/geom_vinum.h>
   44 
   45 void
   46 gv_post_event(struct gv_softc *sc, int event, void *arg1, void *arg2,
   47     intmax_t arg3, intmax_t arg4)
   48 {
   49         struct gv_event *ev;
   50 
   51         ev = g_malloc(sizeof(*ev), M_WAITOK | M_ZERO);
   52         ev->type = event;
   53         ev->arg1 = arg1;
   54         ev->arg2 = arg2;
   55         ev->arg3 = arg3;
   56         ev->arg4 = arg4;
   57 
   58         mtx_lock(&sc->equeue_mtx);
   59         TAILQ_INSERT_TAIL(&sc->equeue, ev, events);
   60         wakeup(sc);
   61         mtx_unlock(&sc->equeue_mtx);
   62 }
   63 
   64 void
   65 gv_worker_exit(struct gv_softc *sc)
   66 {
   67         struct gv_event *ev;
   68 
   69         ev = g_malloc(sizeof(*ev), M_WAITOK | M_ZERO);
   70         ev->type = GV_EVENT_THREAD_EXIT;
   71 
   72         mtx_lock(&sc->equeue_mtx);
   73         TAILQ_INSERT_TAIL(&sc->equeue, ev, events);
   74         wakeup(sc);
   75         msleep(sc->worker, &sc->equeue_mtx, PDROP, "gv_wor", 0);
   76 }
   77 
   78 struct gv_event *
   79 gv_get_event(struct gv_softc *sc)
   80 {
   81         struct gv_event *ev;
   82 
   83         KASSERT(sc != NULL, ("NULL sc"));
   84         mtx_lock(&sc->equeue_mtx);
   85         ev = TAILQ_FIRST(&sc->equeue);
   86         mtx_unlock(&sc->equeue_mtx);
   87         return (ev);
   88 }
   89 
   90 void
   91 gv_remove_event(struct gv_softc *sc, struct gv_event *ev)
   92 {
   93 
   94         KASSERT(sc != NULL, ("NULL sc"));
   95         KASSERT(ev != NULL, ("NULL ev"));
   96         mtx_lock(&sc->equeue_mtx);
   97         TAILQ_REMOVE(&sc->equeue, ev, events);
   98         mtx_unlock(&sc->equeue_mtx);
   99 }
  100 
  101 void
  102 gv_drive_tasted(struct gv_softc *sc, struct g_provider *pp)
  103 {
  104         struct g_geom *gp;
  105         struct g_consumer *cp;
  106         struct gv_hdr *hdr;
  107         struct gv_drive *d;
  108         char *buf;
  109         int error;
  110 
  111         hdr = NULL;
  112         buf = NULL;
  113 
  114         G_VINUM_DEBUG(2, "tasted drive on '%s'", pp->name);
  115         if ((GV_CFG_OFFSET % pp->sectorsize) != 0 ||
  116             (GV_CFG_LEN % pp->sectorsize) != 0) {
  117                 G_VINUM_DEBUG(0, "provider %s has unsupported sectorsize.",
  118                     pp->name);
  119                 return;
  120         }
  121 
  122         gp = sc->geom;
  123         g_topology_lock();
  124         cp = g_new_consumer(gp);
  125         if (g_attach(cp, pp) != 0) {
  126                 g_destroy_consumer(cp);
  127                 g_topology_unlock();
  128                 G_VINUM_DEBUG(0, "failed to attach to provider on taste event");
  129                 return;
  130         }
  131         if (g_access(cp, 1, 0, 0) != 0) {
  132                 g_detach(cp);
  133                 g_destroy_consumer(cp);
  134                 g_topology_unlock();
  135                 G_VINUM_DEBUG(0, "failed to access consumer on taste event");
  136                 return;
  137         }
  138         g_topology_unlock();
  139 
  140         hdr = g_malloc(GV_HDR_LEN, M_WAITOK | M_ZERO);
  141         /* Read header and on-disk configuration. */
  142         error = gv_read_header(cp, hdr);
  143         if (error) {
  144                 G_VINUM_DEBUG(0, "failed to read header during taste");
  145                 goto failed;
  146         }
  147 
  148         /*
  149          * Setup the drive before we parse the on-disk configuration, so that
  150          * we already know about the drive then.
  151          */
  152         d = gv_find_drive(sc, hdr->label.name);
  153         if (d == NULL) {
  154                 d = g_malloc(sizeof(*d), M_WAITOK | M_ZERO);
  155                 strlcpy(d->name, hdr->label.name, sizeof(d->name));
  156                 strlcpy(d->device, pp->name, sizeof(d->device));
  157         } else if (d->flags & GV_DRIVE_REFERENCED) {
  158                 strlcpy(d->device, pp->name, sizeof(d->device));
  159                 d->flags &= ~GV_DRIVE_REFERENCED;
  160         } else {
  161                 G_VINUM_DEBUG(2, "drive '%s' is already known", d->name);
  162                 goto failed;
  163         }
  164 
  165         /* Add the consumer and header to the new drive. */
  166         d->consumer = cp;
  167         d->hdr = hdr;
  168         gv_create_drive(sc, d);
  169 
  170         buf = g_read_data(cp, GV_CFG_OFFSET, GV_CFG_LEN, NULL);
  171         if (buf == NULL) {
  172                 G_VINUM_DEBUG(0, "failed to read config during taste");
  173                 goto failed;
  174         }
  175         gv_parse_config(sc, buf, d);
  176         g_free(buf);
  177 
  178         g_topology_lock();
  179         g_access(cp, -1, 0, 0);
  180         g_topology_unlock();
  181 
  182         gv_setup_objects(sc);
  183         gv_set_drive_state(d, GV_DRIVE_UP, 0);
  184 
  185         return;
  186 
  187 failed:
  188         g_free(hdr);
  189         g_topology_lock();
  190         g_access(cp, -1, 0, 0);
  191         g_detach(cp);
  192         g_destroy_consumer(cp);
  193         g_topology_unlock();
  194 }
  195 
  196 /*
  197  * Count completed BIOs and handle orphanization when all are done.
  198  */
  199 void
  200 gv_drive_done(struct gv_drive *d)
  201 {
  202 
  203         KASSERT(d->active >= 0, ("Negative number of BIOs (%d)", d->active));
  204         if (--d->active == 0 && (d->flags & GV_DRIVE_ORPHANED)) {
  205                 d->flags &= ~GV_DRIVE_ORPHANED;
  206                 gv_post_event(d->vinumconf, GV_EVENT_DRIVE_LOST, d, NULL, 0, 0);
  207         }
  208 }
  209 
  210 /*
  211  * When losing a drive (e.g. hardware failure), we cut down the consumer
  212  * attached to the underlying device and bring the drive itself to a
  213  * "referenced" state so that normal tasting could bring it up cleanly if it
  214  * possibly arrives again.
  215  */
  216 void
  217 gv_drive_lost(struct gv_softc *sc, struct gv_drive *d)
  218 {
  219         struct g_consumer *cp;
  220         struct gv_drive *d2;
  221         struct gv_sd *s, *s2;
  222         struct gv_freelist *fl, *fl2;
  223 
  224         gv_set_drive_state(d, GV_DRIVE_DOWN,
  225             GV_SETSTATE_FORCE | GV_SETSTATE_CONFIG);
  226 
  227         cp = d->consumer;
  228 
  229         if (cp != NULL) {
  230                 if (d->active > 0) {
  231                         G_VINUM_DEBUG(2, "dead drive '%s' has still active "
  232                             "requests, unable to detach consumer", d->name);
  233                         d->flags |= GV_DRIVE_ORPHANED;
  234                         return;
  235                 }
  236                 g_topology_lock();
  237                 if (cp->acr != 0 || cp->acw != 0 || cp->ace != 0)
  238                         g_access(cp, -cp->acr, -cp->acw, -cp->ace);
  239                 g_detach(cp);
  240                 g_destroy_consumer(cp);
  241                 g_topology_unlock();
  242         }
  243 
  244         LIST_FOREACH_SAFE(fl, &d->freelist, freelist, fl2) {
  245                 LIST_REMOVE(fl, freelist);
  246                 g_free(fl);
  247         }
  248 
  249         d->consumer = NULL;
  250         g_free(d->hdr);
  251         d->hdr = NULL;
  252         d->flags |= GV_DRIVE_REFERENCED;
  253         snprintf(d->device, sizeof(d->device), "???");
  254         d->size = 0;
  255         d->avail = 0;
  256         d->freelist_entries = 0;
  257         d->sdcount = 0;
  258 
  259         /* Put the subdisk in tasted mode, and remove from drive list. */
  260         LIST_FOREACH_SAFE(s, &d->subdisks, from_drive, s2) {
  261                 LIST_REMOVE(s, from_drive);
  262                 s->flags |= GV_SD_TASTED;
  263         }
  264 
  265         /*
  266          * Don't forget that gv_is_newer wants a "real" drive at the beginning
  267          * of the list, so, just to be safe, we shuffle around.
  268          */
  269         LIST_REMOVE(d, drive);
  270         d2 = LIST_FIRST(&sc->drives);
  271         if (d2 == NULL)
  272                 LIST_INSERT_HEAD(&sc->drives, d, drive);
  273         else
  274                 LIST_INSERT_AFTER(d2, d, drive);
  275         gv_save_config(sc);
  276 }

Cache object: 2b92b45de2f5db19065453a86766f333


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