svn commit: r190513 - head/sys/geom/vinum

Ulf Lilleengen lulf at FreeBSD.org
Sat Mar 28 14:07:00 PDT 2009


Author: lulf
Date: Sat Mar 28 21:06:59 2009
New Revision: 190513
URL: http://svn.freebsd.org/changeset/base/190513

Log:
  - Add files that should have been added in r190507.

Added:
  head/sys/geom/vinum/geom_vinum_create.c   (contents, props changed)
  head/sys/geom/vinum/geom_vinum_events.c   (contents, props changed)

Added: head/sys/geom/vinum/geom_vinum_create.c
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ head/sys/geom/vinum/geom_vinum_create.c	Sat Mar 28 21:06:59 2009	(r190513)
@@ -0,0 +1,614 @@
+/*-
+ * Copyright (c) 2007 Lukas Ertl
+ * Copyright (c) 2007, 2009 Ulf Lilleengen
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/bio.h>
+#include <sys/conf.h>
+#include <sys/kernel.h>
+#include <sys/malloc.h>
+#include <sys/systm.h>
+#include <sys/vimage.h>
+
+#include <geom/geom.h>
+#include <geom/vinum/geom_vinum_var.h>
+#include <geom/vinum/geom_vinum.h>
+
+#define DEFAULT_STRIPESIZE	262144
+
+/*
+ * Create a new drive object, either by user request, during taste of the drive
+ * itself, or because it was referenced by a subdisk during taste.
+ */
+int
+gv_create_drive(struct gv_softc *sc, struct gv_drive *d)
+{
+	struct g_geom *gp;
+	struct g_provider *pp;
+	struct g_consumer *cp, *cp2;
+	struct gv_drive *d2;
+	struct gv_hdr *hdr;
+	struct gv_freelist *fl;
+
+	KASSERT(d != NULL, ("gv_create_drive: NULL d"));
+
+	gp = sc->geom;
+
+	pp = NULL;
+	cp = cp2 = NULL;
+
+	/* The drive already has a consumer if it was tasted before. */
+	if (d->consumer != NULL) {
+		cp = d->consumer;
+		cp->private = d;
+		pp = cp->provider;
+	} else if (!(d->flags & GV_DRIVE_REFERENCED)) {
+		if (gv_find_drive(sc, d->name) != NULL) {
+			G_VINUM_DEBUG(0, "drive '%s' already exists", d->name);
+			g_free(d);
+			return (GV_ERR_CREATE);
+		}
+
+		if (gv_find_drive_device(sc, d->device) != NULL) {
+			G_VINUM_DEBUG(0, "provider '%s' already in use by "
+			    "gvinum", d->device);
+			return (GV_ERR_CREATE);
+		}
+
+		pp = g_provider_by_name(d->device);
+		if (pp == NULL) {
+			G_VINUM_DEBUG(0, "create '%s': device '%s' disappeared",
+			    d->name, d->device);
+			g_free(d);
+			return (GV_ERR_CREATE);
+		}
+
+		g_topology_lock();
+		cp = g_new_consumer(gp);
+		if (g_attach(cp, pp) != 0) {
+			g_destroy_consumer(cp);
+			g_topology_unlock();
+			G_VINUM_DEBUG(0, "create drive '%s': couldn't attach",
+			    d->name);
+			g_free(d);
+			return (GV_ERR_CREATE);
+		}
+		g_topology_unlock();
+
+		d->consumer = cp;
+		cp->private = d;
+	}
+
+	/*
+	 * If this was just a "referenced" drive, we're almost finished, but
+	 * insert this drive not on the head of the drives list, as
+	 * gv_drive_is_newer() expects a "real" drive from LIST_FIRST().
+	 */
+	if (d->flags & GV_DRIVE_REFERENCED) {
+		snprintf(d->device, sizeof(d->device), "???");
+		d2 = LIST_FIRST(&sc->drives);
+		if (d2 == NULL)
+			LIST_INSERT_HEAD(&sc->drives, d, drive);
+		else
+			LIST_INSERT_AFTER(d2, d, drive);
+		return (0);
+	}
+
+	/*
+	 * Update access counts of the new drive to those of an already
+	 * existing drive.
+	 */
+	LIST_FOREACH(d2, &sc->drives, drive) {
+		if ((d == d2) || (d2->consumer == NULL))
+			continue;
+
+		cp2 = d2->consumer;
+		g_topology_lock();
+		if ((cp2->acr || cp2->acw || cp2->ace) &&
+		    (g_access(cp, cp2->acr, cp2->acw, cp2->ace) != 0)) {
+			g_detach(cp);
+			g_destroy_consumer(cp);
+			g_topology_unlock();
+			G_VINUM_DEBUG(0, "create drive '%s': couldn't update "
+			    "access counts", d->name);
+			if (d->hdr != NULL)
+				g_free(d->hdr);
+			g_free(d);
+			return (GV_ERR_CREATE);
+		}
+		g_topology_unlock();
+		break;
+	}
+
+	d->size = pp->mediasize - GV_DATA_START;
+	d->avail = d->size;
+	d->vinumconf = sc;
+	LIST_INIT(&d->subdisks);
+	LIST_INIT(&d->freelist);
+
+	/* The header might have been set during taste. */
+	if (d->hdr == NULL) {
+		hdr = g_malloc(sizeof(*hdr), M_WAITOK | M_ZERO);
+		hdr->magic = GV_MAGIC;
+		hdr->config_length = GV_CFG_LEN;
+		mtx_lock(&hostname_mtx);
+		bcopy(G_hostname, hdr->label.sysname, GV_HOSTNAME_LEN);
+		mtx_unlock(&hostname_mtx);
+		strlcpy(hdr->label.name, d->name, sizeof(hdr->label.name));
+		microtime(&hdr->label.date_of_birth);
+		d->hdr = hdr;
+	}
+
+	/* We also need a freelist entry. */
+	fl = g_malloc(sizeof(struct gv_freelist), M_WAITOK | M_ZERO);
+	fl->offset = GV_DATA_START;
+	fl->size = d->avail;
+	LIST_INSERT_HEAD(&d->freelist, fl, freelist);
+	d->freelist_entries = 1;
+
+	if (gv_find_drive(sc, d->name) == NULL)
+		LIST_INSERT_HEAD(&sc->drives, d, drive);
+
+	gv_set_drive_state(d, GV_DRIVE_UP, 0);
+	return (0);
+}
+
+int
+gv_create_volume(struct gv_softc *sc, struct gv_volume *v)
+{
+	KASSERT(v != NULL, ("gv_create_volume: NULL v"));
+
+	v->vinumconf = sc;
+	v->flags |= GV_VOL_NEWBORN;
+	LIST_INIT(&v->plexes);
+	LIST_INSERT_HEAD(&sc->volumes, v, volume);
+	v->wqueue = g_malloc(sizeof(struct bio_queue_head), M_WAITOK | M_ZERO);
+	bioq_init(v->wqueue);
+	return (0);
+}
+
+int
+gv_create_plex(struct gv_softc *sc, struct gv_plex *p)
+{
+	struct gv_volume *v;
+
+	KASSERT(p != NULL, ("gv_create_plex: NULL p"));
+
+	/* Find the volume this plex should be attached to. */
+	v = gv_find_vol(sc, p->volume);
+	if (v == NULL) {
+		G_VINUM_DEBUG(0, "create plex '%s': volume '%s' not found",
+		    p->name, p->volume);
+		g_free(p);
+		return (GV_ERR_CREATE);
+	}
+	if (!(v->flags & GV_VOL_NEWBORN))
+		p->flags |= GV_PLEX_ADDED;
+	p->vol_sc = v;
+	v->plexcount++;
+	p->vinumconf = sc;
+	p->synced = 0;
+	p->flags |= GV_PLEX_NEWBORN;
+	LIST_INSERT_HEAD(&v->plexes, p, in_volume);
+	LIST_INIT(&p->subdisks);
+	TAILQ_INIT(&p->packets);
+	LIST_INSERT_HEAD(&sc->plexes, p, plex);
+	p->bqueue = g_malloc(sizeof(struct bio_queue_head), M_WAITOK | M_ZERO);
+	bioq_init(p->bqueue);
+	p->wqueue = g_malloc(sizeof(struct bio_queue_head), M_WAITOK | M_ZERO);
+	bioq_init(p->wqueue);
+	p->rqueue = g_malloc(sizeof(struct bio_queue_head), M_WAITOK | M_ZERO);
+	bioq_init(p->rqueue);
+	return (0);
+}
+
+int
+gv_create_sd(struct gv_softc *sc, struct gv_sd *s)
+{
+	struct gv_plex *p;
+	struct gv_drive *d;
+
+	KASSERT(s != NULL, ("gv_create_sd: NULL s"));
+
+	/* Find the drive where this subdisk should be put on. */
+	d = gv_find_drive(sc, s->drive);
+	if (d == NULL) {
+		/*
+		 * It's possible that the subdisk references a drive that
+		 * doesn't exist yet (during the taste process), so create a
+		 * practically empty "referenced" drive.
+		 */
+		if (s->flags & GV_SD_TASTED) {
+			d = g_malloc(sizeof(struct gv_drive),
+			    M_WAITOK | M_ZERO);
+			d->flags |= GV_DRIVE_REFERENCED;
+			strlcpy(d->name, s->drive, sizeof(d->name));
+			gv_create_drive(sc, d);
+		} else {
+			G_VINUM_DEBUG(0, "create sd '%s': drive '%s' not found",
+			    s->name, s->drive);
+			g_free(s);
+			return (GV_ERR_CREATE);
+		}
+	}
+
+	/* Find the plex where this subdisk belongs to. */
+	p = gv_find_plex(sc, s->plex);
+	if (p == NULL) {
+		G_VINUM_DEBUG(0, "create sd '%s': plex '%s' not found",
+		    s->name, s->plex);
+		g_free(s);
+		return (GV_ERR_CREATE);
+	}
+
+	/*
+	 * First we give the subdisk to the drive, to handle autosized
+	 * values ...
+	 */
+	if (gv_sd_to_drive(s, d) != 0) {
+		g_free(s);
+		return (GV_ERR_CREATE);
+	}
+
+	/*
+	 * Then, we give the subdisk to the plex; we check if the
+	 * given values are correct and maybe adjust them.
+	 */
+	if (gv_sd_to_plex(s, p) != 0) {
+		G_VINUM_DEBUG(0, "unable to give sd '%s' to plex '%s'",
+		    s->name, p->name);
+		if (s->drive_sc && !(s->drive_sc->flags & GV_DRIVE_REFERENCED))
+			LIST_REMOVE(s, from_drive);
+		gv_free_sd(s);
+		g_free(s);
+		/*
+		 * If this subdisk can't be created, we won't create
+		 * the attached plex either, if it is also a new one.
+		 */
+		if (!(p->flags & GV_PLEX_NEWBORN))
+			return (GV_ERR_CREATE);
+		gv_rm_plex(sc, p);
+		return (GV_ERR_CREATE);
+	}
+	s->flags |= GV_SD_NEWBORN;
+
+	s->vinumconf = sc;
+	LIST_INSERT_HEAD(&sc->subdisks, s, sd);
+
+	return (0);
+}
+
+/*
+ * Create a concatenated volume from specified drives or drivegroups.
+ */
+void
+gv_concat(struct g_geom *gp, struct gctl_req *req)
+{
+	struct gv_drive *d;
+	struct gv_sd *s;
+	struct gv_volume *v;
+	struct gv_plex *p;
+	struct gv_softc *sc;
+	char *drive, buf[30], *vol;
+	int *drives, *flags, dcount;
+
+	sc = gp->softc;
+	dcount = 0;
+	vol = gctl_get_param(req, "name", NULL);
+	if (vol == NULL) {
+		gctl_error(req, "volume names not given");	
+		return;
+	}
+
+	flags = gctl_get_paraml(req, "flags", sizeof(*flags));
+	drives = gctl_get_paraml(req, "drives", sizeof(*drives));
+
+	if (drives == NULL) { 
+		gctl_error(req, "drive names not given");
+		return;
+	}
+
+	/* First we create the volume. */
+	v = g_malloc(sizeof(*v), M_WAITOK | M_ZERO);
+	strlcpy(v->name, vol, sizeof(v->name));
+	v->state = GV_VOL_UP;
+	gv_post_event(sc, GV_EVENT_CREATE_VOLUME, v, NULL, 0, 0);
+
+	/* Then we create the plex. */
+	p = g_malloc(sizeof(*p), M_WAITOK | M_ZERO);
+	snprintf(p->name, sizeof(p->name), "%s.p%d", v->name, v->plexcount);
+	strlcpy(p->volume, v->name, sizeof(p->volume));
+	p->org = GV_PLEX_CONCAT;
+	p->stripesize = 0;
+	gv_post_event(sc, GV_EVENT_CREATE_PLEX, p, NULL, 0, 0);
+
+	/* Drives are first (right now) priority */
+	for (dcount = 0; dcount < *drives; dcount++) {
+		snprintf(buf, sizeof(buf), "drive%d", dcount);
+		drive = gctl_get_param(req, buf, NULL);
+		d = gv_find_drive(sc, drive);
+		if (d == NULL) {
+			gctl_error(req, "No such drive '%s'", drive);
+			continue;
+		}
+		s = g_malloc(sizeof(*s), M_WAITOK | M_ZERO);
+		snprintf(s->name, sizeof(s->name), "%s.s%d", p->name, dcount);
+		strlcpy(s->plex, p->name, sizeof(s->plex));
+		strlcpy(s->drive, drive, sizeof(s->drive));
+		s->plex_offset = -1;
+		s->drive_offset = -1;
+		s->size = -1;
+		gv_post_event(sc, GV_EVENT_CREATE_SD, s, NULL, 0, 0);
+	}
+	gv_post_event(sc, GV_EVENT_SETUP_OBJECTS, sc, NULL, 0, 0);
+	gv_post_event(sc, GV_EVENT_SAVE_CONFIG, sc, NULL, 0, 0);
+}
+
+/*
+ * Create a mirrored volume from specified drives or drivegroups.
+ */
+void
+gv_mirror(struct g_geom *gp, struct gctl_req *req)
+{
+	struct gv_drive *d;
+	struct gv_sd *s;
+	struct gv_volume *v;
+	struct gv_plex *p;
+	struct gv_softc *sc;
+	char *drive, buf[30], *vol;
+	int *drives, *flags, dcount, pcount, scount;
+
+	sc = gp->softc;
+	dcount = 0;
+	scount = 0;
+	pcount = 0;
+	vol = gctl_get_param(req, "name", NULL);
+	if (vol == NULL) {
+		gctl_error(req, "volume's not given");	
+		return;
+	}
+
+	flags = gctl_get_paraml(req, "flags", sizeof(*flags));
+	drives = gctl_get_paraml(req, "drives", sizeof(*drives));
+
+	if (drives == NULL) { 
+		gctl_error(req, "drives not given");
+		return;
+	}
+
+	/* We must have an even number of drives. */
+	if (*drives % 2 != 0) {
+		gctl_error(req, "mirror organization must have an even number "
+		    "of drives");
+		return;
+	}
+	if (*flags & GV_FLAG_S && *drives < 4) {
+		gctl_error(req, "must have at least 4 drives for striped plex");
+		return;
+	}
+
+	/* First we create the volume. */
+	v = g_malloc(sizeof(*v), M_WAITOK | M_ZERO);
+	strlcpy(v->name, vol, sizeof(v->name));
+	v->state = GV_VOL_UP;
+	gv_post_event(sc, GV_EVENT_CREATE_VOLUME, v, NULL, 0, 0);
+
+	/* Then we create the plexes. */
+	for (pcount = 0; pcount < 2; pcount++) {
+		p = g_malloc(sizeof(*p), M_WAITOK | M_ZERO);
+		snprintf(p->name, sizeof(p->name), "%s.p%d", v->name,
+		    pcount);
+		strlcpy(p->volume, v->name, sizeof(p->volume));
+		if (*flags & GV_FLAG_S) {
+			p->org = GV_PLEX_STRIPED;
+			p->stripesize = DEFAULT_STRIPESIZE;
+		} else {
+			p->org = GV_PLEX_CONCAT;
+			p->stripesize = -1;
+		}
+		gv_post_event(sc, GV_EVENT_CREATE_PLEX, p, NULL, 0, 0);
+
+		/*
+		 * We just gives each even drive to plex one, and each odd to
+		 * plex two.
+		 */
+		scount = 0;
+		for (dcount = pcount; dcount < *drives; dcount += 2) {
+			snprintf(buf, sizeof(buf), "drive%d", dcount);
+			drive = gctl_get_param(req, buf, NULL);
+			d = gv_find_drive(sc, drive);
+			if (d == NULL) {
+				gctl_error(req, "No such drive '%s', aborting",
+				    drive);
+				scount++;
+				break;
+			}
+			s = g_malloc(sizeof(*s), M_WAITOK | M_ZERO);
+			snprintf(s->name, sizeof(s->name), "%s.s%d", p->name,
+			    scount);
+			strlcpy(s->plex, p->name, sizeof(s->plex));
+			strlcpy(s->drive, drive, sizeof(s->drive));
+			s->plex_offset = -1;
+			s->drive_offset = -1;
+			s->size = -1;
+			gv_post_event(sc, GV_EVENT_CREATE_SD, s, NULL, 0, 0);
+			scount++;
+		}
+	}
+	gv_post_event(sc, GV_EVENT_SETUP_OBJECTS, sc, NULL, 0, 0);
+	gv_post_event(sc, GV_EVENT_SAVE_CONFIG, sc, NULL, 0, 0);
+}
+
+void
+gv_raid5(struct g_geom *gp, struct gctl_req *req)
+{
+	struct gv_softc *sc;
+	struct gv_drive *d;
+	struct gv_volume *v;
+	struct gv_plex *p;
+	struct gv_sd *s;
+	int *drives, *flags, dcount;
+	char *vol, *drive, buf[30];
+	off_t *stripesize;
+
+	dcount = 0;
+	sc = gp->softc;
+
+	vol = gctl_get_param(req, "name", NULL);
+	if (vol == NULL) {
+		gctl_error(req, "volume's not given");
+		return;
+	}
+	flags = gctl_get_paraml(req, "flags", sizeof(*flags));
+	drives = gctl_get_paraml(req, "drives", sizeof(*drives));
+	stripesize = gctl_get_paraml(req, "stripesize", sizeof(*stripesize));
+
+	if (stripesize == NULL) {
+		gctl_error(req, "no stripesize given");
+		return;
+	}
+
+	if (drives == NULL) {
+		gctl_error(req, "drives not given");
+		return;
+	}
+
+	/* We must have at least three drives. */
+	if (*drives < 3) {
+		gctl_error(req, "must have at least three drives for this "
+		    "plex organisation");
+		return;
+	}
+	/* First we create the volume. */
+	v = g_malloc(sizeof(*v), M_WAITOK | M_ZERO);
+	strlcpy(v->name, vol, sizeof(v->name));
+	v->state = GV_VOL_UP;
+	gv_post_event(sc, GV_EVENT_CREATE_VOLUME, v, NULL, 0, 0);
+
+	/* Then we create the plex. */
+	p = g_malloc(sizeof(*p), M_WAITOK | M_ZERO);
+	snprintf(p->name, sizeof(p->name), "%s.p%d", v->name, v->plexcount);
+	strlcpy(p->volume, v->name, sizeof(p->volume));
+	p->org = GV_PLEX_RAID5;
+	p->stripesize = *stripesize;
+	gv_post_event(sc, GV_EVENT_CREATE_PLEX, p, NULL, 0, 0);
+
+	/* Create subdisks on drives. */
+	for (dcount = 0; dcount < *drives; dcount++) {
+		snprintf(buf, sizeof(buf), "drive%d", dcount);
+		drive = gctl_get_param(req, buf, NULL);
+		d = gv_find_drive(sc, drive);
+		if (d == NULL) {
+			gctl_error(req, "No such drive '%s'", drive);
+			continue;
+		}
+		s = g_malloc(sizeof(*s), M_WAITOK | M_ZERO);
+		snprintf(s->name, sizeof(s->name), "%s.s%d", p->name, dcount);
+		strlcpy(s->plex, p->name, sizeof(s->plex));
+		strlcpy(s->drive, drive, sizeof(s->drive));
+		s->plex_offset = -1;
+		s->drive_offset = -1;
+		s->size = -1;
+		gv_post_event(sc, GV_EVENT_CREATE_SD, s, NULL, 0, 0);
+	}
+	gv_post_event(sc, GV_EVENT_SETUP_OBJECTS, sc, NULL, 0, 0);
+	gv_post_event(sc, GV_EVENT_SAVE_CONFIG, sc, NULL, 0, 0);
+}
+
+/*
+ * Create a striped volume from specified drives or drivegroups.
+ */
+void
+gv_stripe(struct g_geom *gp, struct gctl_req *req)
+{
+	struct gv_drive *d;
+	struct gv_sd *s;
+	struct gv_volume *v;
+	struct gv_plex *p;
+	struct gv_softc *sc;
+	char *drive, buf[30], *vol;
+	int *drives, *flags, dcount, pcount;
+
+	sc = gp->softc;
+	dcount = 0;
+	pcount = 0;
+	vol = gctl_get_param(req, "name", NULL);
+	if (vol == NULL) {
+		gctl_error(req, "volume's not given");	
+		return;
+	}
+	flags = gctl_get_paraml(req, "flags", sizeof(*flags));
+	drives = gctl_get_paraml(req, "drives", sizeof(*drives));
+
+	if (drives == NULL) { 
+		gctl_error(req, "drives not given");
+		return;
+	}
+
+	/* We must have at least two drives. */
+	if (*drives < 2) {
+		gctl_error(req, "must have at least 2 drives");
+		return;
+	}
+
+	/* First we create the volume. */
+	v = g_malloc(sizeof(*v), M_WAITOK | M_ZERO);
+	strlcpy(v->name, vol, sizeof(v->name));
+	v->state = GV_VOL_UP;
+	gv_post_event(sc, GV_EVENT_CREATE_VOLUME, v, NULL, 0, 0);
+
+	/* Then we create the plex. */
+	p = g_malloc(sizeof(*p), M_WAITOK | M_ZERO);
+	snprintf(p->name, sizeof(p->name), "%s.p%d", v->name, v->plexcount);
+	strlcpy(p->volume, v->name, sizeof(p->volume));
+	p->org = GV_PLEX_STRIPED;
+	p->stripesize = 262144;
+	gv_post_event(sc, GV_EVENT_CREATE_PLEX, p, NULL, 0, 0);
+
+	/* Create subdisks on drives. */
+	for (dcount = 0; dcount < *drives; dcount++) {
+		snprintf(buf, sizeof(buf), "drive%d", dcount);
+		drive = gctl_get_param(req, buf, NULL);
+		d = gv_find_drive(sc, drive);
+		if (d == NULL) {
+			gctl_error(req, "No such drive '%s'", drive);
+			continue;
+		}
+		s = g_malloc(sizeof(*s), M_WAITOK | M_ZERO);
+		snprintf(s->name, sizeof(s->name), "%s.s%d", p->name, dcount);
+		strlcpy(s->plex, p->name, sizeof(s->plex));
+		strlcpy(s->drive, drive, sizeof(s->drive));
+		s->plex_offset = -1;
+		s->drive_offset = -1;
+		s->size = -1;
+		gv_post_event(sc, GV_EVENT_CREATE_SD, s, NULL, 0, 0);
+	}
+	gv_post_event(sc, GV_EVENT_SETUP_OBJECTS, sc, NULL, 0, 0);
+	gv_post_event(sc, GV_EVENT_SAVE_CONFIG, sc, NULL, 0, 0);
+}

Added: head/sys/geom/vinum/geom_vinum_events.c
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ head/sys/geom/vinum/geom_vinum_events.c	Sat Mar 28 21:06:59 2009	(r190513)
@@ -0,0 +1,217 @@
+/*-
+ *  Copyright (c) 2007 Lukas Ertl
+ *  All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/kernel.h>
+#include <sys/lock.h>
+#include <sys/malloc.h>
+#include <sys/mutex.h>
+#include <sys/systm.h>
+
+#include <geom/geom.h>
+#include <geom/vinum/geom_vinum_var.h>
+#include <geom/vinum/geom_vinum.h>
+
+void
+gv_post_event(struct gv_softc *sc, int event, void *arg1, void *arg2,
+    intmax_t arg3, intmax_t arg4)
+{
+	struct gv_event *ev;
+
+	ev = g_malloc(sizeof(*ev), M_WAITOK | M_ZERO);
+	ev->type = event;
+	ev->arg1 = arg1;
+	ev->arg2 = arg2;
+	ev->arg3 = arg3;
+	ev->arg4 = arg4;
+
+	mtx_lock(&sc->queue_mtx);
+	TAILQ_INSERT_TAIL(&sc->equeue, ev, events);
+	wakeup(sc);
+	mtx_unlock(&sc->queue_mtx);
+}
+
+void
+gv_drive_tasted(struct gv_softc *sc, struct g_provider *pp)
+{
+	struct g_geom *gp;
+	struct g_consumer *cp;
+	struct gv_hdr *hdr;
+	struct gv_drive *d;
+	char *buf;
+	int error;
+
+	hdr = NULL;
+	buf = NULL;
+
+	G_VINUM_DEBUG(2, "tasted drive on '%s'", pp->name);
+
+	gp = sc->geom;
+	g_topology_lock();
+	cp = g_new_consumer(gp);
+	if (g_attach(cp, pp) != 0) {
+		g_destroy_consumer(cp);
+		g_topology_unlock();
+		G_VINUM_DEBUG(0, "failed to attach to provider on taste event");
+		return;
+	}
+	if (g_access(cp, 1, 0, 0) != 0) {
+		g_detach(cp);
+		g_destroy_consumer(cp);
+		g_topology_unlock();
+		G_VINUM_DEBUG(0, "failed to access consumer on taste event");
+		return;
+	}
+	g_topology_unlock();
+
+	hdr = g_malloc(GV_HDR_LEN, M_WAITOK | M_ZERO);
+	/* Read header and on-disk configuration. */
+	error = gv_read_header(cp, hdr);
+	if (error) {
+		G_VINUM_DEBUG(0, "failed to read header during taste");
+		goto failed;
+	}
+
+	/*
+	 * Setup the drive before we parse the on-disk configuration, so that
+	 * we already know about the drive then.
+	 */
+	d = gv_find_drive(sc, hdr->label.name);
+	if (d == NULL) {
+		d = g_malloc(sizeof(*d), M_WAITOK | M_ZERO);
+		strlcpy(d->name, hdr->label.name, sizeof(d->name));
+		strlcpy(d->device, pp->name, sizeof(d->device));
+	} else if (d->flags & GV_DRIVE_REFERENCED) {
+		strlcpy(d->device, pp->name, sizeof(d->device));
+		d->flags &= ~GV_DRIVE_REFERENCED;
+	} else {
+		G_VINUM_DEBUG(2, "drive '%s' is already known", d->name);
+		goto failed;
+	}
+
+	/* Add the consumer and header to the new drive. */
+	d->consumer = cp;
+	d->hdr = hdr;
+	gv_create_drive(sc, d);
+
+	buf = g_read_data(cp, GV_CFG_OFFSET, GV_CFG_LEN, NULL);
+	if (buf == NULL) {
+		G_VINUM_DEBUG(0, "failed to read config during taste");
+		goto failed;
+	}
+	gv_parse_config(sc, buf, d);
+	g_free(buf);
+
+	g_topology_lock();
+	g_access(cp, -1, 0, 0);
+	g_topology_unlock();
+
+	gv_setup_objects(sc);
+	gv_set_drive_state(d, GV_DRIVE_UP, 0);
+
+	return;
+
+failed:
+	if (hdr != NULL)
+		g_free(hdr);
+	g_topology_lock();
+	g_access(cp, -1, 0, 0);
+	g_detach(cp);
+	g_destroy_consumer(cp);
+	g_topology_unlock();
+}
+
+/*
+ * When losing a drive (e.g. hardware failure), we cut down the consumer
+ * attached to the underlying device and bring the drive itself to a
+ * "referenced" state so that normal tasting could bring it up cleanly if it
+ * possibly arrives again.
+ */
+void
+gv_drive_lost(struct gv_softc *sc, struct gv_drive *d)
+{
+	struct g_consumer *cp;
+	struct gv_drive *d2;
+	struct gv_sd *s, *s2;
+	struct gv_freelist *fl, *fl2;
+
+	gv_set_drive_state(d, GV_DRIVE_DOWN,
+	    GV_SETSTATE_FORCE | GV_SETSTATE_CONFIG);
+
+	cp = d->consumer;
+
+	if (cp != NULL) {
+		if (cp->nstart != cp->nend) {
+			G_VINUM_DEBUG(0, "dead drive '%s' has still active "
+			    "requests, can't detach consumer", d->name);
+			gv_post_event(sc, GV_EVENT_DRIVE_LOST, d, NULL, 0, 0);
+			return;
+		}
+		g_topology_lock();
+		if (cp->acr != 0 || cp->acw != 0 || cp->ace != 0)
+			g_access(cp, -cp->acr, -cp->acw, -cp->ace);
+		g_detach(cp);
+		g_destroy_consumer(cp);
+		g_topology_unlock();
+	}
+
+	LIST_FOREACH_SAFE(fl, &d->freelist, freelist, fl2) {
+		LIST_REMOVE(fl, freelist);
+		g_free(fl);
+	}
+
+	d->consumer = NULL;
+	g_free(d->hdr);
+	d->hdr = NULL;
+	d->flags |= GV_DRIVE_REFERENCED;
+	snprintf(d->device, sizeof(d->device), "???");
+	d->size = 0;
+	d->avail = 0;
+	d->freelist_entries = 0;
+	d->sdcount = 0;
+
+	/* Put the subdisk in tasted mode, and remove from drive list. */
+	LIST_FOREACH_SAFE(s, &d->subdisks, from_drive, s2) {
+		LIST_REMOVE(s, from_drive);
+		s->flags |= GV_SD_TASTED;
+	}
+
+	/*
+	 * Don't forget that gv_is_newer wants a "real" drive at the beginning
+	 * of the list, so, just to be safe, we shuffle around.
+	 */
+	LIST_REMOVE(d, drive);
+	d2 = LIST_FIRST(&sc->drives);
+	if (d2 == NULL)
+		LIST_INSERT_HEAD(&sc->drives, d, drive);
+	else
+		LIST_INSERT_AFTER(d2, d, drive);
+	gv_save_config(sc);
+}


More information about the svn-src-all mailing list