summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--sbin/gvinum/gvinum.c58
-rw-r--r--sys/geom/vinum/geom_vinum.c3
-rw-r--r--sys/geom/vinum/geom_vinum.h1
-rw-r--r--sys/geom/vinum/geom_vinum_state.c83
4 files changed, 140 insertions, 5 deletions
diff --git a/sbin/gvinum/gvinum.c b/sbin/gvinum/gvinum.c
index 524a08e..bb3166c 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 **);
@@ -482,6 +483,61 @@ gvinum_init(int argc, char **argv)
}
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] <state> <obj>");
+ 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)
{
struct gctl_req *req;
@@ -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 5a54bee..7b5b456 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 c215e2e..15216dc 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 4e17108..6913a4b 100644
--- a/sys/geom/vinum/geom_vinum_state.c
+++ b/sys/geom/vinum/geom_vinum_state.c
@@ -37,7 +37,78 @@ __FBSDID("$FreeBSD$");
#include <geom/vinum/geom_vinum.h>
#include <geom/vinum/geom_vinum_share.h>
-/* 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) &&
OpenPOWER on IntegriCloud