diff --git a/sbin/gvinum/gvinum.c b/sbin/gvinum/gvinum.c index 524a08ebbab2..bb3166c6ff64 100644 --- a/sbin/gvinum/gvinum.c +++ b/sbin/gvinum/gvinum.c @@ -59,6 +59,7 @@ void gvinum_parityop(int, char **, int); void gvinum_printconfig(int, char **); void gvinum_rm(int, char **); void gvinum_saveconfig(void); +void gvinum_setstate(int, char **); void gvinum_start(int, char **); void gvinum_stop(int, char **); void parseline(int, char **); @@ -481,6 +482,61 @@ gvinum_init(int argc, char **argv) gvinum_list(0, NULL); } +void +gvinum_setstate(int argc, char **argv) +{ + struct gctl_req *req; + int flags, i; + const char *errstr; + + flags = 0; + + optreset = 1; + optind = 1; + + while ((i = getopt(argc, argv, "f")) != -1) { + switch (i) { + case 'f': + flags |= GV_FLAG_F; + break; + case '?': + default: + warn("invalid flag: %c", i); + return; + } + } + + argc -= optind; + argv += optind; + + if (argc != 2) { + warnx("usage: setstate [-f] "); + return; + } + + /* + * XXX: This hack is needed to avoid tripping over (now) invalid + * 'classic' vinum states and will go away later. + */ + if (strcmp(argv[0], "up") && strcmp(argv[0], "down") && + strcmp(argv[0], "stale")) { + warnx("invalid state '%s'", argv[0]); + return; + } + + req = gctl_get_handle(); + gctl_ro_param(req, "class", -1, "VINUM"); + gctl_ro_param(req, "verb", -1, "setstate"); + gctl_ro_param(req, "state", -1, argv[0]); + gctl_ro_param(req, "object", -1, argv[1]); + gctl_ro_param(req, "flags", sizeof(int), &flags); + + errstr = gctl_issue(req); + if (errstr != NULL) + warnx("%s", errstr); + gctl_free(req); +} + void gvinum_list(int argc, char **argv) { @@ -801,6 +857,8 @@ parseline(int argc, char **argv) gvinum_rm(argc, argv); else if (!strcmp(argv[0], "saveconfig")) gvinum_saveconfig(); + else if (!strcmp(argv[0], "setstate")) + gvinum_setstate(argc, argv); else if (!strcmp(argv[0], "start")) gvinum_start(argc, argv); else if (!strcmp(argv[0], "stop")) diff --git a/sys/geom/vinum/geom_vinum.c b/sys/geom/vinum/geom_vinum.c index 5a54bee58729..7b5b456abddb 100644 --- a/sys/geom/vinum/geom_vinum.c +++ b/sys/geom/vinum/geom_vinum.c @@ -512,6 +512,9 @@ gv_config(struct gctl_req *req, struct g_class *mp, char const *verb) } else if (!strcmp(verb, "start")) { gv_start_obj(gp, req); + } else if (!strcmp(verb, "setstate")) { + gv_setstate(gp, req); + } else gctl_error(req, "Unknown verb parameter"); } diff --git a/sys/geom/vinum/geom_vinum.h b/sys/geom/vinum/geom_vinum.h index c215e2ea0095..15216dc09549 100644 --- a/sys/geom/vinum/geom_vinum.h +++ b/sys/geom/vinum/geom_vinum.h @@ -53,6 +53,7 @@ void gv_remove(struct g_geom *, struct gctl_req *); /* geom_vinum_state.c */ int gv_sdstatemap(struct gv_plex *); +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); void gv_update_sd_state(struct gv_sd *); diff --git a/sys/geom/vinum/geom_vinum_state.c b/sys/geom/vinum/geom_vinum_state.c index 4e1710815dfe..6913a4bf66c9 100644 --- a/sys/geom/vinum/geom_vinum_state.c +++ b/sys/geom/vinum/geom_vinum_state.c @@ -37,7 +37,78 @@ __FBSDID("$FreeBSD$"); #include #include -/* Update drive state; return 1 if the state changes, otherwise 0. */ +void +gv_setstate(struct g_geom *gp, struct gctl_req *req) +{ + struct gv_softc *sc; + struct gv_sd *s; + struct gv_drive *d; + char *obj, *state; + int err, f, *flags, newstate, type; + + f = 0; + obj = gctl_get_param(req, "object", NULL); + if (obj == NULL) { + gctl_error(req, "no object given"); + return; + } + + state = gctl_get_param(req, "state", NULL); + if (state == NULL) { + gctl_error(req, "no state given"); + return; + } + + flags = gctl_get_paraml(req, "flags", sizeof(*flags)); + if (flags == NULL) { + gctl_error(req, "no flags given"); + return; + } + + if (*flags & GV_FLAG_F) + f = GV_SETSTATE_FORCE; + + sc = gp->softc; + type = gv_object_type(sc, obj); + switch (type) { + case GV_TYPE_VOL: + case GV_TYPE_PLEX: + gctl_error(req, "volume or plex state cannot be set currently"); + break; + + case GV_TYPE_SD: + newstate = gv_sdstatei(state); + if (newstate < 0) { + gctl_error(req, "invalid subdisk state '%s'", state); + break; + } + s = gv_find_sd(sc, obj); + err = gv_set_sd_state(s, newstate, f); + if (err) + gctl_error(req, "cannot set subdisk state"); + break; + + case GV_TYPE_DRIVE: + newstate = gv_drivestatei(state); + if (newstate < 0) { + gctl_error(req, "invalid drive state '%s'", state); + break; + } + d = gv_find_drive(sc, obj); + err = gv_set_drive_state(d, newstate, f); + if (err) + gctl_error(req, "cannot set drive state"); + break; + + default: + gctl_error(req, "unknown object '%s'", obj); + break; + } + + return; +} + +/* Update drive state; return 0 if the state changes, otherwise -1. */ int gv_set_drive_state(struct gv_drive *d, int newstate, int flags) { @@ -49,12 +120,12 @@ gv_set_drive_state(struct gv_drive *d, int newstate, int flags) oldstate = d->state; if (newstate == oldstate) - return (1); + return (0); /* We allow to take down an open drive only with force. */ if ((newstate == GV_DRIVE_DOWN) && gv_is_open(d->geom) && (!(flags & GV_SETSTATE_FORCE))) - return (0); + return (-1); d->state = newstate; @@ -67,7 +138,7 @@ gv_set_drive_state(struct gv_drive *d, int newstate, int flags) if (flags & GV_SETSTATE_CONFIG) gv_save_config_all(d->vinumconf); - return (1); + return (0); } int @@ -130,6 +201,8 @@ gv_set_sd_state(struct gv_sd *s, int newstate, int flags) if (p->org != GV_PLEX_RAID5) break; + else if (flags & GV_SETSTATE_FORCE) + break; else s->state = GV_SD_STALE; @@ -145,7 +218,7 @@ gv_set_sd_state(struct gv_sd *s, int newstate, int flags) * first. */ p = s->plex_sc; - if (p == NULL) + if (p == NULL || flags & GV_SETSTATE_FORCE) break; if ((p->org != GV_PLEX_RAID5) &&