Change how multipath labels are created and managed. This makes it easier
to support various storage boxes which really aren't active-active. We only write the label on the *first* provider. For all other providers we just "add" the disk. This also allows for an "add" verb. A usage implication is that you should specificy the currently active storage path as the first provider. Note that this does not add RDAC-like functionality, but better allows for autovolumefailover configurations (additional checkins elsewhere will support this). Sponsored by: Panasas MFC after: 1 month
This commit is contained in:
parent
11b168b80e
commit
2b4969ff9e
@ -48,12 +48,17 @@ uint32_t version = G_MULTIPATH_VERSION;
|
||||
static void mp_main(struct gctl_req *, unsigned int);
|
||||
static void mp_label(struct gctl_req *);
|
||||
static void mp_clear(struct gctl_req *);
|
||||
static void mp_add(struct gctl_req *);
|
||||
|
||||
struct g_command class_commands[] = {
|
||||
{
|
||||
"label", G_FLAG_VERBOSE | G_FLAG_LOADKLD, mp_main, G_NULL_OPTS,
|
||||
NULL, "[-v] name prov ..."
|
||||
},
|
||||
{
|
||||
"add", G_FLAG_VERBOSE | G_FLAG_LOADKLD, mp_main, G_NULL_OPTS,
|
||||
NULL, "[-v] name prov ..."
|
||||
},
|
||||
{
|
||||
"destroy", G_FLAG_VERBOSE, NULL, G_NULL_OPTS,
|
||||
NULL, "[-v] prov ..."
|
||||
@ -85,6 +90,8 @@ mp_main(struct gctl_req *req, unsigned int flags __unused)
|
||||
}
|
||||
if (strcmp(name, "label") == 0) {
|
||||
mp_label(req);
|
||||
} else if (strcmp(name, "add") == 0) {
|
||||
mp_add(req);
|
||||
} else if (strcmp(name, "clear") == 0) {
|
||||
mp_clear(req);
|
||||
} else {
|
||||
@ -101,7 +108,7 @@ mp_label(struct gctl_req *req)
|
||||
char *ptr;
|
||||
uuid_t uuid;
|
||||
uint32_t secsize = 0, ssize, status;
|
||||
const char *name;
|
||||
const char *name, *mpname;
|
||||
int error, i, nargs;
|
||||
|
||||
nargs = gctl_get_int(req, "nargs");
|
||||
@ -156,8 +163,8 @@ mp_label(struct gctl_req *req)
|
||||
*/
|
||||
strlcpy(md.md_magic, G_MULTIPATH_MAGIC, sizeof(md.md_magic));
|
||||
md.md_version = G_MULTIPATH_VERSION;
|
||||
name = gctl_get_ascii(req, "arg0");
|
||||
strlcpy(md.md_name, name, sizeof(md.md_name));
|
||||
mpname = gctl_get_ascii(req, "arg0");
|
||||
strlcpy(md.md_name, mpname, sizeof(md.md_name));
|
||||
md.md_size = disksiz;
|
||||
md.md_sectorsize = secsize;
|
||||
uuid_create(&uuid, &status);
|
||||
@ -174,46 +181,44 @@ mp_label(struct gctl_req *req)
|
||||
free(ptr);
|
||||
|
||||
/*
|
||||
* Clear last sector first for each provider to spoil anything extant
|
||||
* Clear metadata on initial provider first.
|
||||
*/
|
||||
for (i = 1; i < nargs; i++) {
|
||||
name = gctl_get_ascii(req, "arg%d", i);
|
||||
error = g_metadata_clear(name, NULL);
|
||||
if (error != 0) {
|
||||
gctl_error(req, "cannot clear metadata on %s: %s.",
|
||||
name, strerror(error));
|
||||
return;
|
||||
}
|
||||
name = gctl_get_ascii(req, "arg1");
|
||||
error = g_metadata_clear(name, NULL);
|
||||
if (error != 0) {
|
||||
gctl_error(req, "cannot clear metadata on %s: %s.", name, strerror(error));
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* encode the metadata
|
||||
*/
|
||||
multipath_metadata_encode(&md, sector);
|
||||
|
||||
/*
|
||||
* Ok, store metadata.
|
||||
* Store metadata on the initial provider.
|
||||
*/
|
||||
for (i = 1; i < nargs; i++) {
|
||||
name = gctl_get_ascii(req, "arg%d", i);
|
||||
error = g_metadata_store(name, sector, secsize);
|
||||
if (error != 0) {
|
||||
fprintf(stderr, "Can't store metadata on %s: %s.\n",
|
||||
name, strerror(error));
|
||||
goto fail;
|
||||
}
|
||||
error = g_metadata_store(name, sector, secsize);
|
||||
if (error != 0) {
|
||||
gctl_error(req, "cannot store metadata on %s: %s.", name, strerror(error));
|
||||
return;
|
||||
}
|
||||
return;
|
||||
|
||||
fail:
|
||||
/*
|
||||
* Clear last sector first for each provider to spoil anything extant
|
||||
* Now add the rest of the providers.
|
||||
*/
|
||||
for (i = 1; i < nargs; i++) {
|
||||
name = gctl_get_ascii(req, "arg%d", i);
|
||||
error = g_metadata_clear(name, NULL);
|
||||
if (error != 0) {
|
||||
gctl_error(req, "cannot clear metadata on %s: %s.",
|
||||
name, strerror(error));
|
||||
error = gctl_change_param(req, "verb", -1, "add");
|
||||
if (error) {
|
||||
gctl_error(req, "unable to change verb to \"add\": %s.", strerror(error));
|
||||
return;
|
||||
}
|
||||
for (i = 2; i < nargs; i++) {
|
||||
error = gctl_change_param(req, "arg1", -1, gctl_get_ascii(req, "arg%d", i));
|
||||
if (error) {
|
||||
gctl_error(req, "unable to add %s to %s: %s.", gctl_get_ascii(req, "arg%d", i), mpname, strerror(error));
|
||||
continue;
|
||||
}
|
||||
mp_add(req);
|
||||
}
|
||||
}
|
||||
|
||||
@ -221,22 +226,23 @@ static void
|
||||
mp_clear(struct gctl_req *req)
|
||||
{
|
||||
const char *name;
|
||||
int error, i, nargs;
|
||||
int error;
|
||||
|
||||
nargs = gctl_get_int(req, "nargs");
|
||||
if (nargs < 1) {
|
||||
gctl_error(req, "Too few arguments.");
|
||||
return;
|
||||
name = gctl_get_ascii(req, "arg1");
|
||||
error = g_metadata_clear(name, G_MULTIPATH_MAGIC);
|
||||
if (error != 0) {
|
||||
fprintf(stderr, "Can't clear metadata on %s: %s.\n", name, strerror(error));
|
||||
gctl_error(req, "Not fully done.");
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
mp_add(struct gctl_req *req)
|
||||
{
|
||||
const char *errstr;
|
||||
|
||||
errstr = gctl_issue(req);
|
||||
if (errstr != NULL && errstr[0] != '\0') {
|
||||
gctl_error(req, "%s", errstr);
|
||||
}
|
||||
|
||||
for (i = 0; i < nargs; i++) {
|
||||
name = gctl_get_ascii(req, "arg%d", i);
|
||||
error = g_metadata_clear(name, G_MULTIPATH_MAGIC);
|
||||
if (error != 0) {
|
||||
fprintf(stderr, "Can't clear metadata on %s: %s.\n",
|
||||
name, strerror(error));
|
||||
gctl_error(req, "Not fully done.");
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -70,6 +70,7 @@ static int g_multipath_destroy(struct g_geom *);
|
||||
static int
|
||||
g_multipath_destroy_geom(struct gctl_req *, struct g_class *, struct g_geom *);
|
||||
|
||||
static struct g_geom *g_multipath_find_geom(struct g_class *, const char *);
|
||||
static int g_multipath_rotate(struct g_geom *);
|
||||
|
||||
static g_taste_t g_multipath_taste;
|
||||
@ -602,14 +603,13 @@ g_multipath_taste(struct g_class *mp, struct g_provider *pp, int flags __unused)
|
||||
}
|
||||
|
||||
static void
|
||||
g_multipath_ctl_create(struct gctl_req *req, struct g_class *mp)
|
||||
g_multipath_ctl_add(struct gctl_req *req, struct g_class *mp)
|
||||
{
|
||||
struct g_geom *gp;
|
||||
struct g_provider *pp0, *pp1;
|
||||
struct g_multipath_metadata md;
|
||||
const char *name, *mpname, *uuid;
|
||||
struct g_consumer *cp;
|
||||
struct g_provider *pp, *pp0;
|
||||
const char *name, *mpname;
|
||||
static const char devpf[6] = "/dev/";
|
||||
int *nargs, error;
|
||||
|
||||
g_topology_assert();
|
||||
|
||||
@ -618,14 +618,9 @@ g_multipath_ctl_create(struct gctl_req *req, struct g_class *mp)
|
||||
gctl_error(req, "No 'arg0' argument");
|
||||
return;
|
||||
}
|
||||
|
||||
nargs = gctl_get_paraml(req, "nargs", sizeof(*nargs));
|
||||
if (nargs == NULL) {
|
||||
gctl_error(req, "No 'nargs' argument");
|
||||
return;
|
||||
}
|
||||
if (*nargs != 4) {
|
||||
gctl_error(req, "missing device or uuid arguments");
|
||||
gp = g_multipath_find_geom(mp, mpname);
|
||||
if (gp == NULL) {
|
||||
gctl_error(req, "Device %s is invalid", mpname);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -636,78 +631,45 @@ g_multipath_ctl_create(struct gctl_req *req, struct g_class *mp)
|
||||
}
|
||||
if (strncmp(name, devpf, 5) == 0)
|
||||
name += 5;
|
||||
pp0 = g_provider_by_name(name);
|
||||
if (pp0 == NULL) {
|
||||
pp = g_provider_by_name(name);
|
||||
if (pp == NULL) {
|
||||
gctl_error(req, "Provider %s is invalid", name);
|
||||
return;
|
||||
}
|
||||
|
||||
name = gctl_get_asciiparam(req, "arg2");
|
||||
if (name == NULL) {
|
||||
gctl_error(req, "No 'arg2' argument");
|
||||
return;
|
||||
/*
|
||||
* Check to make sure parameters match, if we already have one.
|
||||
*/
|
||||
cp = LIST_FIRST(&gp->consumer);
|
||||
if (cp) {
|
||||
pp0 = cp->provider;
|
||||
} else {
|
||||
pp0 = NULL;
|
||||
}
|
||||
if (strncmp(name, devpf, 5) == 0)
|
||||
name += 5;
|
||||
pp1 = g_provider_by_name(name);
|
||||
if (pp1 == NULL) {
|
||||
gctl_error(req, "Provider %s is invalid", name);
|
||||
return;
|
||||
}
|
||||
|
||||
uuid = gctl_get_asciiparam(req, "arg3");
|
||||
if (uuid == NULL) {
|
||||
gctl_error(req, "No uuid argument");
|
||||
return;
|
||||
}
|
||||
if (strlen(uuid) != 36) {
|
||||
gctl_error(req, "Malformed uuid argument");
|
||||
return;
|
||||
if (pp0) {
|
||||
if (pp0 == pp) {
|
||||
gctl_error(req, "providers %s and %s are the same",
|
||||
pp0->name, pp->name);
|
||||
return;
|
||||
}
|
||||
if (pp0->mediasize != pp->mediasize) {
|
||||
gctl_error(req, "Provider %s is %jd; Provider %s is %jd",
|
||||
pp0->name, (intmax_t) pp0->mediasize,
|
||||
pp->name, (intmax_t) pp->mediasize);
|
||||
return;
|
||||
}
|
||||
if (pp0->sectorsize != pp->sectorsize) {
|
||||
gctl_error(req, "Provider %s has sectorsize %u; Provider %s "
|
||||
"has sectorsize %u", pp0->name, pp0->sectorsize,
|
||||
pp->name, pp->sectorsize);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Check to make sure parameters from the two providers are the same
|
||||
* Now add....
|
||||
*/
|
||||
if (pp0 == pp1) {
|
||||
gctl_error(req, "providers %s and %s are the same",
|
||||
pp0->name, pp1->name);
|
||||
return;
|
||||
}
|
||||
if (pp0->mediasize != pp1->mediasize) {
|
||||
gctl_error(req, "Provider %s is %jd; Provider %s is %jd",
|
||||
pp0->name, (intmax_t) pp0->mediasize,
|
||||
pp1->name, (intmax_t) pp1->mediasize);
|
||||
return;
|
||||
}
|
||||
if (pp0->sectorsize != pp1->sectorsize) {
|
||||
gctl_error(req, "Provider %s has sectorsize %u; Provider %s "
|
||||
"has sectorsize %u", pp0->name, pp0->sectorsize,
|
||||
pp1->name, pp1->sectorsize);
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* cons up enough of a metadata structure to use.
|
||||
*/
|
||||
memset(&md, 0, sizeof(md));
|
||||
md.md_size = pp0->mediasize;
|
||||
md.md_sectorsize = pp0->sectorsize;
|
||||
strlcpy(md.md_name, mpname, sizeof(md.md_name));
|
||||
strlcpy(md.md_uuid, uuid, sizeof(md.md_uuid));
|
||||
|
||||
gp = g_multipath_create(mp, &md);
|
||||
if (gp == NULL)
|
||||
return;
|
||||
error = g_multipath_add_disk(gp, pp0);
|
||||
if (error) {
|
||||
g_multipath_destroy(gp);
|
||||
return;
|
||||
}
|
||||
error = g_multipath_add_disk(gp, pp1);
|
||||
if (error) {
|
||||
g_multipath_destroy(gp);
|
||||
return;
|
||||
}
|
||||
(void) g_multipath_add_disk(gp, pp);
|
||||
}
|
||||
|
||||
static struct g_geom *
|
||||
@ -815,8 +777,8 @@ g_multipath_config(struct gctl_req *req, struct g_class *mp, const char *verb)
|
||||
gctl_error(req, "No 'version' argument");
|
||||
} else if (*version != G_MULTIPATH_VERSION) {
|
||||
gctl_error(req, "Userland and kernel parts are out of sync");
|
||||
} else if (strcmp(verb, "create") == 0) {
|
||||
g_multipath_ctl_create(req, mp);
|
||||
} else if (strcmp(verb, "add") == 0) {
|
||||
g_multipath_ctl_add(req, mp);
|
||||
} else if (strcmp(verb, "destroy") == 0) {
|
||||
g_multipath_ctl_destroy(req, mp);
|
||||
} else if (strcmp(verb, "rotate") == 0) {
|
||||
|
Loading…
Reference in New Issue
Block a user