diff options
author | le <le@FreeBSD.org> | 2006-03-30 14:01:25 +0000 |
---|---|---|
committer | le <le@FreeBSD.org> | 2006-03-30 14:01:25 +0000 |
commit | 148e4e97f6a72d5d47fc4da833170bd0aeb91c52 (patch) | |
tree | d19a280a99ea2e4b5d78e9da8ea03f61a14ab2f8 | |
parent | aa075cf284edd2192e4a6c6f086e2ac9edb16656 (diff) | |
download | FreeBSD-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.c | 49 | ||||
-rw-r--r-- | sys/geom/vinum/geom_vinum.h | 1 | ||||
-rw-r--r-- | sys/geom/vinum/geom_vinum_rm.c | 58 | ||||
-rw-r--r-- | sys/geom/vinum/geom_vinum_state.c | 6 | ||||
-rw-r--r-- | sys/geom/vinum/geom_vinum_subr.c | 66 |
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; |