Protect from creating striped and RAID5 plexes with unequally sized

subdisks.
This commit is contained in:
Lukas Ertl 2006-03-30 14:01:25 +00:00
parent 03e21a94e4
commit ff91880e5d
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=157292
5 changed files with 112 additions and 68 deletions

View file

@ -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;

View file

@ -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 *);

View file

@ -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;
}

View file

@ -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) {

View file

@ -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) {
@ -612,6 +621,63 @@ gv_sd_to_drive(struct gv_softc *sc, struct gv_drive *d, struct gv_sd *s,
return (0);
}
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)
{