Implement 'setstate' to allow setting the state of drives and subdisks

for debugging and emergency purposes.
This commit is contained in:
Lukas Ertl 2004-11-26 12:31:36 +00:00
parent 3514b3b581
commit 997337fd20
4 changed files with 140 additions and 5 deletions

View File

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

View File

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

View File

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

View File

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