geom_vinum_events.c revision 191849
1190513Slulf/*- 2190513Slulf * Copyright (c) 2007 Lukas Ertl 3190513Slulf * All rights reserved. 4190513Slulf * 5190513Slulf * Redistribution and use in source and binary forms, with or without 6190513Slulf * modification, are permitted provided that the following conditions 7190513Slulf * are met: 8190513Slulf * 1. Redistributions of source code must retain the above copyright 9190513Slulf * notice, this list of conditions and the following disclaimer. 10190513Slulf * 2. Redistributions in binary form must reproduce the above copyright 11190513Slulf * notice, this list of conditions and the following disclaimer in the 12190513Slulf * documentation and/or other materials provided with the distribution. 13190513Slulf * 14190513Slulf * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15190513Slulf * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16190513Slulf * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17190513Slulf * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE 18190513Slulf * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19190513Slulf * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20190513Slulf * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21190513Slulf * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22190513Slulf * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23190513Slulf * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24190513Slulf * SUCH DAMAGE. 25190513Slulf * 26190513Slulf */ 27190513Slulf 28190513Slulf#include <sys/cdefs.h> 29190513Slulf__FBSDID("$FreeBSD: head/sys/geom/vinum/geom_vinum_events.c 191849 2009-05-06 18:21:48Z lulf $"); 30190513Slulf 31190513Slulf#include <sys/param.h> 32190513Slulf#include <sys/kernel.h> 33190513Slulf#include <sys/lock.h> 34190513Slulf#include <sys/malloc.h> 35190513Slulf#include <sys/mutex.h> 36190513Slulf#include <sys/systm.h> 37190513Slulf 38190513Slulf#include <geom/geom.h> 39190513Slulf#include <geom/vinum/geom_vinum_var.h> 40190513Slulf#include <geom/vinum/geom_vinum.h> 41190513Slulf 42190513Slulfvoid 43190513Slulfgv_post_event(struct gv_softc *sc, int event, void *arg1, void *arg2, 44190513Slulf intmax_t arg3, intmax_t arg4) 45190513Slulf{ 46190513Slulf struct gv_event *ev; 47190513Slulf 48190513Slulf ev = g_malloc(sizeof(*ev), M_WAITOK | M_ZERO); 49190513Slulf ev->type = event; 50190513Slulf ev->arg1 = arg1; 51190513Slulf ev->arg2 = arg2; 52190513Slulf ev->arg3 = arg3; 53190513Slulf ev->arg4 = arg4; 54190513Slulf 55191849Slulf mtx_lock(&sc->equeue_mtx); 56190513Slulf TAILQ_INSERT_TAIL(&sc->equeue, ev, events); 57190513Slulf wakeup(sc); 58191849Slulf mtx_unlock(&sc->equeue_mtx); 59190513Slulf} 60190513Slulf 61191849Slulfstruct gv_event * 62191849Slulfgv_get_event(struct gv_softc *sc) 63191849Slulf{ 64191849Slulf struct gv_event *ev; 65191849Slulf 66191849Slulf KASSERT(sc != NULL, ("NULL sc")); 67191849Slulf mtx_lock(&sc->equeue_mtx); 68191849Slulf ev = TAILQ_FIRST(&sc->equeue); 69191849Slulf mtx_unlock(&sc->equeue_mtx); 70191849Slulf return (ev); 71191849Slulf} 72191849Slulf 73190513Slulfvoid 74191849Slulfgv_remove_event(struct gv_softc *sc, struct gv_event *ev) 75191849Slulf{ 76191849Slulf 77191849Slulf KASSERT(sc != NULL, ("NULL sc")); 78191849Slulf KASSERT(ev != NULL, ("NULL ev")); 79191849Slulf mtx_lock(&sc->equeue_mtx); 80191849Slulf TAILQ_REMOVE(&sc->equeue, ev, events); 81191849Slulf mtx_unlock(&sc->equeue_mtx); 82191849Slulf} 83191849Slulf 84191849Slulfvoid 85190513Slulfgv_drive_tasted(struct gv_softc *sc, struct g_provider *pp) 86190513Slulf{ 87190513Slulf struct g_geom *gp; 88190513Slulf struct g_consumer *cp; 89190513Slulf struct gv_hdr *hdr; 90190513Slulf struct gv_drive *d; 91190513Slulf char *buf; 92190513Slulf int error; 93190513Slulf 94190513Slulf hdr = NULL; 95190513Slulf buf = NULL; 96190513Slulf 97190513Slulf G_VINUM_DEBUG(2, "tasted drive on '%s'", pp->name); 98190513Slulf 99190513Slulf gp = sc->geom; 100190513Slulf g_topology_lock(); 101190513Slulf cp = g_new_consumer(gp); 102190513Slulf if (g_attach(cp, pp) != 0) { 103190513Slulf g_destroy_consumer(cp); 104190513Slulf g_topology_unlock(); 105190513Slulf G_VINUM_DEBUG(0, "failed to attach to provider on taste event"); 106190513Slulf return; 107190513Slulf } 108190513Slulf if (g_access(cp, 1, 0, 0) != 0) { 109190513Slulf g_detach(cp); 110190513Slulf g_destroy_consumer(cp); 111190513Slulf g_topology_unlock(); 112190513Slulf G_VINUM_DEBUG(0, "failed to access consumer on taste event"); 113190513Slulf return; 114190513Slulf } 115190513Slulf g_topology_unlock(); 116190513Slulf 117190513Slulf hdr = g_malloc(GV_HDR_LEN, M_WAITOK | M_ZERO); 118190513Slulf /* Read header and on-disk configuration. */ 119190513Slulf error = gv_read_header(cp, hdr); 120190513Slulf if (error) { 121190513Slulf G_VINUM_DEBUG(0, "failed to read header during taste"); 122190513Slulf goto failed; 123190513Slulf } 124190513Slulf 125190513Slulf /* 126190513Slulf * Setup the drive before we parse the on-disk configuration, so that 127190513Slulf * we already know about the drive then. 128190513Slulf */ 129190513Slulf d = gv_find_drive(sc, hdr->label.name); 130190513Slulf if (d == NULL) { 131190513Slulf d = g_malloc(sizeof(*d), M_WAITOK | M_ZERO); 132190513Slulf strlcpy(d->name, hdr->label.name, sizeof(d->name)); 133190513Slulf strlcpy(d->device, pp->name, sizeof(d->device)); 134190513Slulf } else if (d->flags & GV_DRIVE_REFERENCED) { 135190513Slulf strlcpy(d->device, pp->name, sizeof(d->device)); 136190513Slulf d->flags &= ~GV_DRIVE_REFERENCED; 137190513Slulf } else { 138190513Slulf G_VINUM_DEBUG(2, "drive '%s' is already known", d->name); 139190513Slulf goto failed; 140190513Slulf } 141190513Slulf 142190513Slulf /* Add the consumer and header to the new drive. */ 143190513Slulf d->consumer = cp; 144190513Slulf d->hdr = hdr; 145190513Slulf gv_create_drive(sc, d); 146190513Slulf 147190513Slulf buf = g_read_data(cp, GV_CFG_OFFSET, GV_CFG_LEN, NULL); 148190513Slulf if (buf == NULL) { 149190513Slulf G_VINUM_DEBUG(0, "failed to read config during taste"); 150190513Slulf goto failed; 151190513Slulf } 152190513Slulf gv_parse_config(sc, buf, d); 153190513Slulf g_free(buf); 154190513Slulf 155190513Slulf g_topology_lock(); 156190513Slulf g_access(cp, -1, 0, 0); 157190513Slulf g_topology_unlock(); 158190513Slulf 159190513Slulf gv_setup_objects(sc); 160190513Slulf gv_set_drive_state(d, GV_DRIVE_UP, 0); 161190513Slulf 162190513Slulf return; 163190513Slulf 164190513Slulffailed: 165190513Slulf if (hdr != NULL) 166190513Slulf g_free(hdr); 167190513Slulf g_topology_lock(); 168190513Slulf g_access(cp, -1, 0, 0); 169190513Slulf g_detach(cp); 170190513Slulf g_destroy_consumer(cp); 171190513Slulf g_topology_unlock(); 172190513Slulf} 173190513Slulf 174190513Slulf/* 175190513Slulf * When losing a drive (e.g. hardware failure), we cut down the consumer 176190513Slulf * attached to the underlying device and bring the drive itself to a 177190513Slulf * "referenced" state so that normal tasting could bring it up cleanly if it 178190513Slulf * possibly arrives again. 179190513Slulf */ 180190513Slulfvoid 181190513Slulfgv_drive_lost(struct gv_softc *sc, struct gv_drive *d) 182190513Slulf{ 183190513Slulf struct g_consumer *cp; 184190513Slulf struct gv_drive *d2; 185190513Slulf struct gv_sd *s, *s2; 186190513Slulf struct gv_freelist *fl, *fl2; 187190513Slulf 188190513Slulf gv_set_drive_state(d, GV_DRIVE_DOWN, 189190513Slulf GV_SETSTATE_FORCE | GV_SETSTATE_CONFIG); 190190513Slulf 191190513Slulf cp = d->consumer; 192190513Slulf 193190513Slulf if (cp != NULL) { 194190513Slulf if (cp->nstart != cp->nend) { 195190513Slulf G_VINUM_DEBUG(0, "dead drive '%s' has still active " 196190513Slulf "requests, can't detach consumer", d->name); 197190513Slulf gv_post_event(sc, GV_EVENT_DRIVE_LOST, d, NULL, 0, 0); 198190513Slulf return; 199190513Slulf } 200190513Slulf g_topology_lock(); 201190513Slulf if (cp->acr != 0 || cp->acw != 0 || cp->ace != 0) 202190513Slulf g_access(cp, -cp->acr, -cp->acw, -cp->ace); 203190513Slulf g_detach(cp); 204190513Slulf g_destroy_consumer(cp); 205190513Slulf g_topology_unlock(); 206190513Slulf } 207190513Slulf 208190513Slulf LIST_FOREACH_SAFE(fl, &d->freelist, freelist, fl2) { 209190513Slulf LIST_REMOVE(fl, freelist); 210190513Slulf g_free(fl); 211190513Slulf } 212190513Slulf 213190513Slulf d->consumer = NULL; 214190513Slulf g_free(d->hdr); 215190513Slulf d->hdr = NULL; 216190513Slulf d->flags |= GV_DRIVE_REFERENCED; 217190513Slulf snprintf(d->device, sizeof(d->device), "???"); 218190513Slulf d->size = 0; 219190513Slulf d->avail = 0; 220190513Slulf d->freelist_entries = 0; 221190513Slulf d->sdcount = 0; 222190513Slulf 223190513Slulf /* Put the subdisk in tasted mode, and remove from drive list. */ 224190513Slulf LIST_FOREACH_SAFE(s, &d->subdisks, from_drive, s2) { 225190513Slulf LIST_REMOVE(s, from_drive); 226190513Slulf s->flags |= GV_SD_TASTED; 227190513Slulf } 228190513Slulf 229190513Slulf /* 230190513Slulf * Don't forget that gv_is_newer wants a "real" drive at the beginning 231190513Slulf * of the list, so, just to be safe, we shuffle around. 232190513Slulf */ 233190513Slulf LIST_REMOVE(d, drive); 234190513Slulf d2 = LIST_FIRST(&sc->drives); 235190513Slulf if (d2 == NULL) 236190513Slulf LIST_INSERT_HEAD(&sc->drives, d, drive); 237190513Slulf else 238190513Slulf LIST_INSERT_AFTER(d2, d, drive); 239190513Slulf gv_save_config(sc); 240190513Slulf} 241