summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorle <le@FreeBSD.org>2006-03-30 14:01:25 +0000
committerle <le@FreeBSD.org>2006-03-30 14:01:25 +0000
commit148e4e97f6a72d5d47fc4da833170bd0aeb91c52 (patch)
treed19a280a99ea2e4b5d78e9da8ea03f61a14ab2f8
parentaa075cf284edd2192e4a6c6f086e2ac9edb16656 (diff)
downloadFreeBSD-src-148e4e97f6a72d5d47fc4da833170bd0aeb91c52.zip
FreeBSD-src-148e4e97f6a72d5d47fc4da833170bd0aeb91c52.tar.gz
Protect from creating striped and RAID5 plexes with unequally sized
subdisks.
-rw-r--r--sys/geom/vinum/geom_vinum.c49
-rw-r--r--sys/geom/vinum/geom_vinum.h1
-rw-r--r--sys/geom/vinum/geom_vinum_rm.c58
-rw-r--r--sys/geom/vinum/geom_vinum_state.c6
-rw-r--r--sys/geom/vinum/geom_vinum_subr.c66
5 files changed, 112 insertions, 68 deletions
diff --git a/sys/geom/vinum/geom_vinum.c b/sys/geom/vinum/geom_vinum.c
index 7e045d9..7ebe58f 100644
--- a/sys/geom/vinum/geom_vinum.c
+++ b/sys/geom/vinum/geom_vinum.c
@@ -237,13 +237,16 @@ gv_create(struct g_geom *gp, struct gctl_req *req)
/* Find the volume this plex should be attached to. */
v = gv_find_vol(sc, p->volume);
- if (v != NULL) {
- if (v->plexcount)
- p->flags |= GV_PLEX_ADDED;
- p->vol_sc = v;
- v->plexcount++;
- LIST_INSERT_HEAD(&v->plexes, p, in_volume);
+ if (v == NULL) {
+ gctl_error(req, "volume '%s' not found", p->volume);
+ g_free(p);
+ continue;
}
+ if (v->plexcount)
+ p->flags |= GV_PLEX_ADDED;
+ p->vol_sc = v;
+ v->plexcount++;
+ LIST_INSERT_HEAD(&v->plexes, p, in_volume);
p->vinumconf = sc;
p->flags |= GV_PLEX_NEWBORN;
@@ -272,7 +275,7 @@ gv_create(struct g_geom *gp, struct gctl_req *req)
/* drive not found - XXX */
if (d == NULL) {
- printf("FOO: drive '%s' not found\n", s->drive);
+ gctl_error(req, "drive '%s' not found", s->drive);
g_free(s);
continue;
}
@@ -282,7 +285,7 @@ gv_create(struct g_geom *gp, struct gctl_req *req)
/* plex not found - XXX */
if (p == NULL) {
- printf("FOO: plex '%s' not found\n", s->plex);
+ gctl_error(req, "plex '%s' not found\n", s->plex);
g_free(s);
continue;
}
@@ -304,8 +307,34 @@ gv_create(struct g_geom *gp, struct gctl_req *req)
*/
error = gv_sd_to_plex(p, s, 1);
if (error) {
- printf("FOO: couldn't give sd '%s' to plex '%s'\n",
- s->name, p->name);
+ gctl_error(req, "GEOM_VINUM: couldn't give sd '%s' "
+ "to plex '%s'\n", s->name, p->name);
+ if (s->drive_sc)
+ 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))
+ continue;
+ LIST_FOREACH_SAFE(s, &p->subdisks, in_plex, s2) {
+ if (s->drive_sc)
+ LIST_REMOVE(s, from_drive);
+ p->sdcount--;
+ LIST_REMOVE(s, in_plex);
+ LIST_REMOVE(s, sd);
+ gv_free_sd(s);
+ g_free(s);
+ }
+ if (p->vol_sc != NULL) {
+ LIST_REMOVE(p, in_volume);
+ p->vol_sc->plexcount--;
+ }
+ LIST_REMOVE(p, plex);
+ g_free(p);
+ continue;
}
s->flags |= GV_SD_NEWBORN;
diff --git a/sys/geom/vinum/geom_vinum.h b/sys/geom/vinum/geom_vinum.h
index 0e272ce..493c493 100644
--- a/sys/geom/vinum/geom_vinum.h
+++ b/sys/geom/vinum/geom_vinum.h
@@ -72,6 +72,7 @@ void gv_update_vol_state(struct gv_volume *);
/* geom_vinum_subr.c */
void gv_adjust_freespace(struct gv_sd *, off_t);
+void gv_free_sd(struct gv_sd *);
struct g_geom *find_vinum_geom(void);
struct gv_drive *gv_find_drive(struct gv_softc *, char *);
struct gv_plex *gv_find_plex(struct gv_softc *, char *);
diff --git a/sys/geom/vinum/geom_vinum_rm.c b/sys/geom/vinum/geom_vinum_rm.c
index 959181d..9b1247d 100644
--- a/sys/geom/vinum/geom_vinum_rm.c
+++ b/sys/geom/vinum/geom_vinum_rm.c
@@ -38,7 +38,6 @@ __FBSDID("$FreeBSD$");
#include <geom/vinum/geom_vinum.h>
#include <geom/vinum/geom_vinum_share.h>
-static void gv_free_sd(struct gv_sd *);
static int gv_rm_drive(struct gv_softc *, struct gctl_req *,
struct gv_drive *, int);
static int gv_rm_plex(struct gv_softc *, struct gctl_req *,
@@ -381,60 +380,3 @@ gv_rm_drive(struct gv_softc *sc, struct gctl_req *req, struct gv_drive *d, int f
return (err);
}
-
-static void
-gv_free_sd(struct gv_sd *s)
-{
- struct gv_drive *d;
- struct gv_freelist *fl, *fl2;
-
- KASSERT(s != NULL, ("gv_free_sd: NULL s"));
-
- d = s->drive_sc;
- if (d == NULL)
- return;
-
- /*
- * First, find the free slot that's immediately before or after this
- * subdisk.
- */
- fl = NULL;
- LIST_FOREACH(fl, &d->freelist, freelist) {
- if (fl->offset == s->drive_offset + s->size)
- break;
- if (fl->offset + fl->size == s->drive_offset)
- break;
- }
-
- /* If there is no free slot behind this subdisk, so create one. */
- if (fl == NULL) {
-
- fl = g_malloc(sizeof(*fl), M_WAITOK | M_ZERO);
- fl->size = s->size;
- fl->offset = s->drive_offset;
-
- if (d->freelist_entries == 0) {
- LIST_INSERT_HEAD(&d->freelist, fl, freelist);
- } else {
- LIST_FOREACH(fl2, &d->freelist, freelist) {
- if (fl->offset < fl2->offset) {
- LIST_INSERT_BEFORE(fl2, fl, freelist);
- break;
- } else if (LIST_NEXT(fl2, freelist) == NULL) {
- LIST_INSERT_AFTER(fl2, fl, freelist);
- break;
- }
- }
- }
-
- d->freelist_entries++;
-
- /* Expand the free slot we just found. */
- } else {
- fl->size += s->size;
- if (fl->offset > s->drive_offset)
- fl->offset = s->drive_offset;
- }
-
- d->avail += s->size;
-}
diff --git a/sys/geom/vinum/geom_vinum_state.c b/sys/geom/vinum/geom_vinum_state.c
index 81e305a..549503f 100644
--- a/sys/geom/vinum/geom_vinum_state.c
+++ b/sys/geom/vinum/geom_vinum_state.c
@@ -340,6 +340,12 @@ gv_update_vol_state(struct gv_volume *v)
KASSERT(v != NULL, ("gv_update_vol_state: NULL v"));
+ /* The volume can't be up without plexes. */
+ if (v->plexcount == 0) {
+ v->state = GV_VOL_DOWN;
+ return;
+ }
+
LIST_FOREACH(p, &v->plexes, in_volume) {
/* One of our plexes is accessible, and so are we. */
if (p->state > GV_PLEX_DEGRADED) {
diff --git a/sys/geom/vinum/geom_vinum_subr.c b/sys/geom/vinum/geom_vinum_subr.c
index ce79a18..323bb7c 100644
--- a/sys/geom/vinum/geom_vinum_subr.c
+++ b/sys/geom/vinum/geom_vinum_subr.c
@@ -246,6 +246,15 @@ gv_sd_to_plex(struct gv_plex *p, struct gv_sd *s, int check)
if (s->plex_sc == p)
return (0);
+ /* Check correct size of this subdisk. */
+ s2 = LIST_FIRST(&p->subdisks);
+ if (s2 != NULL && gv_is_striped(p) && (s2->size != s->size)) {
+ printf("GEOM_VINUM: need equal sized subdisks for "
+ "this plex organisation - %s (%jd) <-> %s (%jd)\n",
+ s2->name, s2->size, s->name, s->size);
+ return (-1);
+ }
+
/* Find the correct plex offset for this subdisk, if needed. */
if (s->plex_offset == -1) {
if (p->sdcount) {
@@ -613,6 +622,63 @@ gv_sd_to_drive(struct gv_softc *sc, struct gv_drive *d, struct gv_sd *s,
}
void
+gv_free_sd(struct gv_sd *s)
+{
+ struct gv_drive *d;
+ struct gv_freelist *fl, *fl2;
+
+ KASSERT(s != NULL, ("gv_free_sd: NULL s"));
+
+ d = s->drive_sc;
+ if (d == NULL)
+ return;
+
+ /*
+ * First, find the free slot that's immediately before or after this
+ * subdisk.
+ */
+ fl = NULL;
+ LIST_FOREACH(fl, &d->freelist, freelist) {
+ if (fl->offset == s->drive_offset + s->size)
+ break;
+ if (fl->offset + fl->size == s->drive_offset)
+ break;
+ }
+
+ /* If there is no free slot behind this subdisk, so create one. */
+ if (fl == NULL) {
+
+ fl = g_malloc(sizeof(*fl), M_WAITOK | M_ZERO);
+ fl->size = s->size;
+ fl->offset = s->drive_offset;
+
+ if (d->freelist_entries == 0) {
+ LIST_INSERT_HEAD(&d->freelist, fl, freelist);
+ } else {
+ LIST_FOREACH(fl2, &d->freelist, freelist) {
+ if (fl->offset < fl2->offset) {
+ LIST_INSERT_BEFORE(fl2, fl, freelist);
+ break;
+ } else if (LIST_NEXT(fl2, freelist) == NULL) {
+ LIST_INSERT_AFTER(fl2, fl, freelist);
+ break;
+ }
+ }
+ }
+
+ d->freelist_entries++;
+
+ /* Expand the free slot we just found. */
+ } else {
+ fl->size += s->size;
+ if (fl->offset > s->drive_offset)
+ fl->offset = s->drive_offset;
+ }
+
+ d->avail += s->size;
+}
+
+void
gv_adjust_freespace(struct gv_sd *s, off_t remainder)
{
struct gv_drive *d;
OpenPOWER on IntegriCloud