Index: geom_vinum.h =================================================================== RCS file: /home/ncvs/src/sys/geom/vinum/geom_vinum.h,v retrieving revision 1.12 diff -u -r1.12 geom_vinum.h --- geom_vinum.h 30 Mar 2006 14:01:25 -0000 1.12 +++ geom_vinum.h 25 May 2006 19:26:35 -0000 @@ -66,6 +67,8 @@ void gv_setstate(struct g_geom *, struct gctl_req *); int gv_set_drive_state(struct gv_drive *, int, int); int gv_set_sd_state(struct gv_sd *, int, int); +int gv_set_plex_state(struct gv_plex *, int, int); +int gv_set_vol_state(struct gv_volume *, int, int); void gv_update_sd_state(struct gv_sd *); void gv_update_plex_state(struct gv_plex *); void gv_update_vol_state(struct gv_volume *); Index: geom_vinum_state.c =================================================================== RCS file: /home/ncvs/src/sys/geom/vinum/geom_vinum_state.c,v retrieving revision 1.8 diff -u -r1.8 geom_vinum_state.c --- geom_vinum_state.c 30 Mar 2006 14:01:25 -0000 1.8 +++ geom_vinum_state.c 25 May 2006 19:26:35 -0000 @@ -43,6 +43,8 @@ struct gv_softc *sc; struct gv_sd *s; struct gv_drive *d; + struct gv_volume *v; + struct gv_plex *p; char *obj, *state; int err, f, *flags, newstate, type; @@ -72,8 +74,27 @@ type = gv_object_type(sc, obj); switch (type) { case GV_TYPE_VOL: + newstate = gv_volstatei(state); + if (newstate < 0) { + gctl_error(req, "invalid volume state '%s'", state); + break; + } + v = gv_find_vol(sc, obj); + err = gv_set_vol_state(v, newstate, f); + if (err) + gctl_error(req, "cannot set volume state"); + break; + case GV_TYPE_PLEX: - gctl_error(req, "volume or plex state cannot be set currently"); + newstate = gv_plexstatei(state); + if (newstate < 0) { + gctl_error(req, "invalid plex state '%s'", state); + break; + } + p = gv_find_plex(sc, obj); + err = gv_set_plex_state(p, newstate, f); + if (err) + gctl_error(req, "cannot set plex state"); break; case GV_TYPE_SD: @@ -400,3 +421,85 @@ } return (statemap); } + +int +gv_set_plex_state(struct gv_plex *p, int newstate, int flags) +{ + struct gv_volume *v; + struct gv_sd *s; + int oldstate; + + KASSERT(p != NULL, ("gv_set_plex_state: NULL p")); + + oldstate = p->state; + v = p->vol_sc; + + if (newstate == oldstate) + return (0); + + switch (newstate) { + case GV_PLEX_UP: + /* Let update_plex handle if the plex can come up */ + gv_update_plex_state(p); /* XXX: Should return error if fail */ + break; + case GV_PLEX_DOWN: + if (v != NULL) { + /* If the only one, or only one up, force is needed. */ + if ((v->plexcount != 1) || + ((v->plexcount - v->plexdown) != 1) || + ((flags & GV_SETSTATE_FORCE) == 0)) + return (-1); + } + p->state = GV_PLEX_DOWN + /* Force down all subdisks. */ + LIST_FOREACH(s, &p->subdisks, gv_sd) { + gv_set_sd_state(s, GV_SD_DOWN, flags); + } + break; + /* XXX: Also add support for GV_PLEX_INITIALIZING AND + * GV_PLEX_DEGRADED. */ + } + /* Update our volume, if we have one. */ + if (p->vol_sc != NULL) + gv_update_vol_state(p->vol_sc); + + /* Save config */ + if (flags & GV_SETSTATE_CONFIG) + gv_save_config_all(v->vinumconf); + return (0); +} + +int +gv_set_vol_state(struct gv_volume *v, int newstate, int flags) +{ + int oldstate; + + KASSERT(v != NULL, ("gv_set_vol_state: NULL v")); + + oldstate = v->state; + + if (newstate == oldstate) + return (0); + + switch (newstate) { + case GV_VOL_UP: + /* Let update handle if the volume can come up */ + gv_update_vol_state(v); /* XXX: Should return error for this. */ + break; + case GV_VOL_DOWN: + /* + * Set state to GV_VOL_DOWN only if noone is using the volume, + * or if the state should be forced. + */ + if (((v->flags & GV_VOL_THREAD_ACTIVE) != 0) || + ((flags & GV_SETSTATE_FORCE) == 0)) + return (-1); + v->state = GV_VOL_DOWN; + break; + } + + /* Save config */ + if (flags & GV_SETSTATE_CONFIG) + gv_save_config_all(v->vinumconf); + return (0); +}