2 * Copyright (c) 2007 Lukas Ertl
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
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.
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
28 #include <sys/cdefs.h>
29 __FBSDID("$FreeBSD$");
31 #include <sys/param.h>
32 #include <sys/kernel.h>
34 #include <sys/malloc.h>
35 #include <sys/mutex.h>
36 #include <sys/systm.h>
38 #include <geom/geom.h>
39 #include <geom/vinum/geom_vinum_var.h>
40 #include <geom/vinum/geom_vinum.h>
43 gv_post_event(struct gv_softc *sc, int event, void *arg1, void *arg2,
44 intmax_t arg3, intmax_t arg4)
48 ev = g_malloc(sizeof(*ev), M_WAITOK | M_ZERO);
55 mtx_lock(&sc->equeue_mtx);
56 TAILQ_INSERT_TAIL(&sc->equeue, ev, events);
58 mtx_unlock(&sc->equeue_mtx);
62 gv_get_event(struct gv_softc *sc)
66 KASSERT(sc != NULL, ("NULL sc"));
67 mtx_lock(&sc->equeue_mtx);
68 ev = TAILQ_FIRST(&sc->equeue);
69 mtx_unlock(&sc->equeue_mtx);
74 gv_remove_event(struct gv_softc *sc, struct gv_event *ev)
77 KASSERT(sc != NULL, ("NULL sc"));
78 KASSERT(ev != NULL, ("NULL ev"));
79 mtx_lock(&sc->equeue_mtx);
80 TAILQ_REMOVE(&sc->equeue, ev, events);
81 mtx_unlock(&sc->equeue_mtx);
85 gv_drive_tasted(struct gv_softc *sc, struct g_provider *pp)
88 struct g_consumer *cp;
97 G_VINUM_DEBUG(2, "tasted drive on '%s'", pp->name);
101 cp = g_new_consumer(gp);
102 if (g_attach(cp, pp) != 0) {
103 g_destroy_consumer(cp);
105 G_VINUM_DEBUG(0, "failed to attach to provider on taste event");
108 if (g_access(cp, 1, 0, 0) != 0) {
110 g_destroy_consumer(cp);
112 G_VINUM_DEBUG(0, "failed to access consumer on taste event");
117 hdr = g_malloc(GV_HDR_LEN, M_WAITOK | M_ZERO);
118 /* Read header and on-disk configuration. */
119 error = gv_read_header(cp, hdr);
121 G_VINUM_DEBUG(0, "failed to read header during taste");
126 * Setup the drive before we parse the on-disk configuration, so that
127 * we already know about the drive then.
129 d = gv_find_drive(sc, hdr->label.name);
131 d = g_malloc(sizeof(*d), M_WAITOK | M_ZERO);
132 strlcpy(d->name, hdr->label.name, sizeof(d->name));
133 strlcpy(d->device, pp->name, sizeof(d->device));
134 } else if (d->flags & GV_DRIVE_REFERENCED) {
135 strlcpy(d->device, pp->name, sizeof(d->device));
136 d->flags &= ~GV_DRIVE_REFERENCED;
138 G_VINUM_DEBUG(2, "drive '%s' is already known", d->name);
142 /* Add the consumer and header to the new drive. */
145 gv_create_drive(sc, d);
147 buf = g_read_data(cp, GV_CFG_OFFSET, GV_CFG_LEN, NULL);
149 G_VINUM_DEBUG(0, "failed to read config during taste");
152 gv_parse_config(sc, buf, d);
156 g_access(cp, -1, 0, 0);
159 gv_setup_objects(sc);
160 gv_set_drive_state(d, GV_DRIVE_UP, 0);
168 g_access(cp, -1, 0, 0);
170 g_destroy_consumer(cp);
175 * When losing a drive (e.g. hardware failure), we cut down the consumer
176 * attached to the underlying device and bring the drive itself to a
177 * "referenced" state so that normal tasting could bring it up cleanly if it
178 * possibly arrives again.
181 gv_drive_lost(struct gv_softc *sc, struct gv_drive *d)
183 struct g_consumer *cp;
185 struct gv_sd *s, *s2;
186 struct gv_freelist *fl, *fl2;
188 gv_set_drive_state(d, GV_DRIVE_DOWN,
189 GV_SETSTATE_FORCE | GV_SETSTATE_CONFIG);
194 if (cp->nstart != cp->nend) {
195 G_VINUM_DEBUG(0, "dead drive '%s' has still active "
196 "requests, can't detach consumer", d->name);
197 gv_post_event(sc, GV_EVENT_DRIVE_LOST, d, NULL, 0, 0);
201 if (cp->acr != 0 || cp->acw != 0 || cp->ace != 0)
202 g_access(cp, -cp->acr, -cp->acw, -cp->ace);
204 g_destroy_consumer(cp);
208 LIST_FOREACH_SAFE(fl, &d->freelist, freelist, fl2) {
209 LIST_REMOVE(fl, freelist);
216 d->flags |= GV_DRIVE_REFERENCED;
217 snprintf(d->device, sizeof(d->device), "???");
220 d->freelist_entries = 0;
223 /* Put the subdisk in tasted mode, and remove from drive list. */
224 LIST_FOREACH_SAFE(s, &d->subdisks, from_drive, s2) {
225 LIST_REMOVE(s, from_drive);
226 s->flags |= GV_SD_TASTED;
230 * Don't forget that gv_is_newer wants a "real" drive at the beginning
231 * of the list, so, just to be safe, we shuffle around.
233 LIST_REMOVE(d, drive);
234 d2 = LIST_FIRST(&sc->drives);
236 LIST_INSERT_HEAD(&sc->drives, d, drive);
238 LIST_INSERT_AFTER(d2, d, drive);