PERFORCE change 111726 for review
Matt Jacob
mjacob at FreeBSD.org
Thu Dec 14 22:42:07 PST 2006
http://perforce.freebsd.org/chv.cgi?CH=111726
Change 111726 by mjacob at mjexp on 2006/12/15 06:41:23
Yet more toy playing - this time with label metadata.
Affected files ...
.. //depot/projects/mjexp/sbin/geom/class/multipath/geom_multipath.c#2 edit
.. //depot/projects/mjexp/sys/geom/multipath/g_multipath.c#4 edit
.. //depot/projects/mjexp/sys/geom/multipath/g_multipath.h#3 edit
Differences ...
==== //depot/projects/mjexp/sbin/geom/class/multipath/geom_multipath.c#2 (text+ko) ====
@@ -36,19 +36,167 @@
#include <strings.h>
#include <assert.h>
#include <libgeom.h>
+#include <uuid.h>
#include <geom/multipath/g_multipath.h>
#include "core/geom.h"
#include "misc/subr.h"
-
uint32_t lib_version = G_LIB_VERSION;
uint32_t version = G_MULTIPATH_VERSION;
+static void mp_main(struct gctl_req *, unsigned int);
+static void mp_label(struct gctl_req *);
+
struct g_command class_commands[] = {
{
- "create", G_FLAG_VERBOSE | G_FLAG_LOADKLD, NULL, G_NULL_OPTS,
- "[-hv] name prov prov"
+ "label", G_FLAG_VERBOSE | G_FLAG_LOADKLD, mp_main, G_NULL_OPTS,
+ "[-v] name prov prov"
},
+ {
+ "destroy", G_FLAG_VERBOSE, NULL, G_NULL_OPTS,
+ "[-fv] name"
+ },
G_CMD_SENTINEL
};
+
+static void
+mp_main(struct gctl_req *req, unsigned int flags __unused)
+{
+ const char *name;
+
+ name = gctl_get_ascii(req, "verb");
+ if (name == NULL) {
+ gctl_error(req, "No '%s' argument.", "verb");
+ return;
+ }
+ if (strcmp(name, "label") == 0) {
+ mp_label(req);
+ } else {
+ gctl_error(req, "Unknown command: %s.", name);
+ }
+}
+
+static void
+mp_label(struct gctl_req *req)
+{
+ struct g_multipath_metadata md;
+ off_t disksiz = 0, msize;
+ uint8_t *sector;
+ char *ptr;
+ uuid_t uuid;
+ uint32_t secsize = 0, ssize, status;
+ const char *name;
+ int error, i, nargs;
+
+ nargs = gctl_get_int(req, "nargs");
+ if (nargs != 3) {
+ gctl_error(req, "wrong number of arguments.");
+ return;
+ }
+
+ /*
+ * First, check each provider to make sure it's the same size.
+ * This also gets us our size and sectorsize for the metadata.
+ */
+ for (i = 1; i < nargs; i++) {
+ name = gctl_get_ascii(req, "arg%d", i);
+ msize = g_get_mediasize(name);
+ ssize = g_get_sectorsize(name);
+ if (msize == 0 || ssize == 0) {
+ gctl_error(req, "cannot get information about %s: %s.",
+ name, strerror(errno));
+ return;
+ }
+ if (i == 1) {
+ secsize = ssize;
+ disksiz = msize;
+ } else {
+ if (secsize != ssize) {
+ gctl_error(req, "%s sector size %u different.",
+ name, ssize);
+ return;
+ }
+ if (disksiz != msize) {
+ gctl_error(req, "%s media size %ju different.",
+ name, (intmax_t)msize);
+ return;
+ }
+ }
+
+ }
+
+ /*
+ * Allocate a sector to write as metadata.
+ */
+ sector = malloc(secsize);
+ if (sector == NULL) {
+ gctl_error(req, "unable to allocate metadata buffer");
+ return;
+ }
+ memset(sector, 0, secsize);
+
+ /*
+ * Generate metadata.
+ */
+ 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));
+ md.md_size = disksiz;
+ md.md_sectorsize = secsize;
+ uuid_create(&uuid, &status);
+ if (status != uuid_s_ok) {
+ gctl_error(req, "cannot create a UUID.");
+ return;
+ }
+ ptr = md.md_uuid;
+ uuid_to_string(&uuid, &ptr, &status);
+ if (status != uuid_s_ok) {
+ gctl_error(req, "cannot stringify a UUID.");
+ return;
+ }
+
+ /*
+ * Clear last sector first for each provider to spoil anything extant
+ */
+ 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;
+ }
+ }
+
+ multipath_metadata_encode(&md, sector);
+
+ /*
+ * Ok, store metadata.
+ */
+ 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;
+ }
+ }
+ return;
+
+fail:
+ /*
+ * Clear last sector first for each provider to spoil anything extant
+ */
+ 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));
+ continue;
+ }
+ }
+}
==== //depot/projects/mjexp/sys/geom/multipath/g_multipath.c#4 (text+ko) ====
@@ -23,6 +23,11 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
+/*
+ * Based upon work by Pawel Jakub Dawidek <pjd at FreeBSD.org> for all of the
+ * fine geom examples, and by Poul Henning Kamp <phk at FreeBSD.org> for GEOM
+ * itself, all of which is most gratefully acknowledged.
+ */
#include <sys/cdefs.h>
__FBSDID("$FreeBSD");
@@ -53,13 +58,15 @@
static int g_multipath_destroy(struct g_geom *);
static int
g_multipath_destroy_geom(struct gctl_req *, struct g_class *, struct g_geom *);
-static void
-g_multipath_config(struct gctl_req *, struct g_class *, const char *);
+
+static g_taste_t g_multipath_taste;
+static g_ctl_req_t g_multipath_config;
struct g_class g_multipath_class = {
.name = G_MULTIPATH_CLASS_NAME,
.version = G_VERSION,
.ctlreq = g_multipath_config,
+ .taste = g_multipath_taste,
.destroy_geom = g_multipath_destroy_geom
};
@@ -155,6 +162,9 @@
gp = pp->geom;
sc = gp->softc;
KASSERT(sc != NULL, ("NULL sc"));
+ if (sc->ready == 0) {
+ return (ENXIO);
+ }
error = g_access(sc->consumers[0], dr, dw, de);
if (error == 0) {
error = g_access(sc->consumers[1], dr, dw, de);
@@ -165,59 +175,34 @@
return (error);
}
-static int
-g_multipath_create(struct gctl_req *req, struct g_class *mp,
- const char *mpname, struct g_provider *pp0, struct g_provider *pp1)
+static struct g_geom *
+g_multipath_create(struct g_class *mp, struct g_multipath_metadata *md)
{
struct g_multipath_softc *sc;
struct g_geom *gp;
struct g_provider *newpp;
struct g_consumer *cp0, *cp1;
char name[64];
- int error;
g_topology_assert();
- /*
- * Check to make sure parameters from the two providers are the same
- */
- if (pp0 == pp1) {
- gctl_error(req, "providers are the same");
- return (EINVAL);
- }
- if (pp0->mediasize != pp1->mediasize) {
- gctl_error(req, "Provider %s has mediasize %zu; Provider %s "
- "has mediasize %zu", pp0->name, (intmax_t) pp0->mediasize,
- pp1->name, (intmax_t) pp1->mediasize);
- return (EINVAL);
- }
- 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 (EINVAL);
- }
-
gp = NULL;
newpp = NULL;
cp0 = cp1 = NULL;
LIST_FOREACH(gp, &mp->geom, geom) {
- if (strcmp(gp->name, mpname) == 0) {
- gctl_error(req, "Provider %s already exists", mpname);
- return (EEXIST);
+ if (strcmp(gp->name, md->md_name) == 0) {
+ return (NULL);
}
}
- gp = g_new_geomf(mp, mpname);
+
+ gp = g_new_geomf(mp, md->md_name);
if (gp == NULL) {
- gctl_error(req, "Cannot create geom %s", mpname);
- return (ENOMEM);
+ goto fail;
}
sc = g_malloc(sizeof(*sc), M_WAITOK | M_ZERO);
if (sc == NULL) {
- gctl_error(req, "Cannot allocate softc");
- error = ENOMEM;
goto fail;
}
@@ -225,78 +210,67 @@
gp->start = g_multipath_start;
gp->orphan = g_multipath_orphan;
gp->access = g_multipath_access;
+ memcpy(sc->sc_uuid, md->md_uuid, sizeof (sc->sc_uuid));
+ memcpy(sc->sc_name, md->md_name, sizeof (sc->sc_name));
-
- cp0 = g_new_consumer(gp);
- if (cp0 == NULL) {
- gctl_error(req, "Cannot create consumer for %s", pp0->name);
- error = ENOMEM;
- goto fail;
- }
- error = g_attach(cp0, pp0);
- if (error != 0) {
- gctl_error(req, "Cannot attach provider %s", pp0->name);
- goto fail;
- }
- cp0->private = sc;
- cp0->index = 0;
-
- cp1 = g_new_consumer(gp);
- if (cp1 == NULL) {
- gctl_error(req, "Cannot create consumer for %s", pp1->name);
- error = ENOMEM;
- goto fail;
- }
- error = g_attach(cp1, pp1);
- if (error != 0) {
- gctl_error(req, "Cannot attach provider %s", pp1->name);
- goto fail;
- }
- cp1->private = sc;
- cp1->index = 1;
-
- sc->consumers[0] = cp0;
- sc->consumers[1] = cp1;
- sc->providers[0] = pp0;
- sc->providers[1] = pp1;
-
- snprintf(name, sizeof(name), "multipath/%s", mpname);
+ snprintf(name, sizeof(name), "multipath/%s", md->md_name);
newpp = g_new_providerf(gp, name);
if (newpp == NULL) {
- gctl_error(req, "Cannot create provider %s", name);
- error = ENOMEM;
goto fail;
}
- newpp->mediasize = pp0->mediasize;
- newpp->sectorsize = pp0->sectorsize;
+ /* limit the provider to not have it stomp on metadata */
+ newpp->mediasize = md->md_size - md->md_sectorsize;
+ newpp->sectorsize = md->md_sectorsize;
+ g_error_provider(newpp, 0);
sc->pp = newpp;
- g_error_provider(newpp, 0);
- sc->ready = 1;
-
- return (0);
+ return (gp);
fail:
- if (cp0 != NULL) {
- if (cp0->provider != NULL) {
- g_detach(cp0);
- }
- g_destroy_consumer(cp0);
- }
- if (cp1 != NULL) {
- if (cp1->provider != NULL) {
- g_detach(cp1);
- }
- g_destroy_consumer(cp1);
- }
- if (newpp != NULL) {
- g_destroy_provider(newpp);
- }
if (gp != NULL) {
if (gp->softc != NULL) {
g_free(gp->softc);
}
g_destroy_geom(gp);
}
- return (error);
+ return (NULL);
+}
+
+static int
+g_multipath_add_disk(struct g_geom *gp, struct g_provider *pp)
+{
+ struct g_multipath_softc *sc;
+ struct g_consumer *cp;
+ int error;
+
+ sc = gp->softc;
+ KASSERT(sc, ("no softc"));
+
+ if (sc->nattached >= 2) {
+ printf("cannot attach %s to %s (%d disks already attached)\n",
+ pp->name, gp->name, sc->nattached);
+ return (EINVAL);
+ }
+
+ cp = g_new_consumer(gp);
+ if (cp == NULL) {
+ return (ENOMEM);
+ }
+ error = g_attach(cp, pp);
+ if (error != 0) {
+ printf("Cannot attach provider %s", pp->name);
+ g_destroy_consumer(cp);
+ return (error);
+ }
+ cp->private = sc;
+ cp->index = 0;
+
+ sc->consumers[sc->nattached] = cp;
+ sc->providers[sc->nattached] = pp;
+ sc->nattached++;
+ if (sc->nattached == 2) {
+ printf("activating %s\n", sc->sc_name);
+ sc->ready = 1;
+ }
+ return (0);
}
static int
@@ -305,8 +279,9 @@
struct g_provider *pp;
g_topology_assert();
- if (gp->softc == NULL)
+ if (gp->softc == NULL) {
return (ENXIO);
+ }
pp = LIST_FIRST(&gp->provider);
if (pp != NULL && (pp->acr != 0 || pp->acw != 0 || pp->ace != 0)) {
return (EBUSY);
@@ -324,13 +299,135 @@
return (g_multipath_destroy(gp));
}
+static int
+g_multipath_read_metadata(struct g_consumer *cp,
+ struct g_multipath_metadata *md)
+{
+ struct g_provider *pp;
+ u_char *buf;
+ int error;
+
+ g_topology_assert();
+ error = g_access(cp, 1, 0, 0);
+ if (error != 0) {
+ return (error);
+ }
+ pp = cp->provider;
+ g_topology_unlock();
+ buf = g_read_data(cp, pp->mediasize - pp->sectorsize,
+ pp->sectorsize, &error);
+ g_topology_lock();
+ g_access(cp, -1, 0, 0);
+ if (buf == NULL) {
+ return (error);
+ }
+ multipath_metadata_decode(buf, md);
+ g_free(buf);
+ return (0);
+}
+
+static struct g_geom *
+g_multipath_taste(struct g_class *mp, struct g_provider *pp, int flags __unused)
+{
+ struct g_multipath_metadata md;
+ struct g_multipath_softc *sc;
+ struct g_consumer *cp;
+ struct g_geom *gp;
+ int error, isnew;
+
+ g_topology_assert();
+
+ gp = g_new_geomf(mp, "multipath:taste");
+ gp->start = g_multipath_start;
+ gp->access = g_multipath_access;
+ gp->orphan = g_multipath_orphan;
+ cp = g_new_consumer(gp);
+ g_attach(cp, pp);
+ error = g_multipath_read_metadata(cp, &md);
+ g_detach(cp);
+ g_destroy_consumer(cp);
+ g_destroy_geom(gp);
+ if (error != 0) {
+ return (NULL);
+ }
+ gp = NULL;
+
+ if (strcmp(md.md_magic, G_MULTIPATH_MAGIC) != 0) {
+ return (NULL);
+ }
+ if (md.md_version != G_MULTIPATH_VERSION) {
+ printf("%s has version %d multipath id- this module is version "
+ " %d: rejecting\n", pp->name, md.md_version,
+ G_MULTIPATH_VERSION);
+ return (NULL);
+ }
+
+ /*
+ * Let's check if such a device already is present. We check against
+ * uuid alone at first because that's the true distinguishor. After
+ * that test passes, we run through and make sure that the name is
+ * unique and if it isn't, we generate a name.
+ */
+ sc = NULL;
+ LIST_FOREACH(gp, &mp->geom, geom) {
+ sc = gp->softc;
+ if (sc == NULL) {
+ continue;
+ }
+ if (strncmp(md.md_uuid, sc->sc_uuid, sizeof(md.md_uuid)) == 0) {
+ break;
+ }
+ }
+
+ if (gp == NULL) {
+ gp = g_multipath_create(mp, &md);
+ if (gp == NULL) {
+ printf("cannot create geom %s\n", md.md_name);
+ return (NULL);
+ }
+ isnew = 1;
+ } else {
+ struct g_geom *gp1;
+ LIST_FOREACH(gp1, &mp->geom, geom) {
+ sc = gp1->softc;
+ if (sc == NULL) {
+ continue;
+ }
+ if (strncmp(md.md_name, sc->sc_name,
+ sizeof(md.md_name)) == 0) {
+ break;
+ }
+ }
+ if (gp1 != NULL) {
+ printf("cannot add %s to %s because %s already exists "
+ "with a different uuid\n", pp->name, gp1->name,
+ gp1->name);
+ return (NULL);
+ }
+ isnew = 0;
+ }
+
+ sc = gp->softc;
+ KASSERT(sc != NULL, ("sc is NULL"));
+ error = g_multipath_add_disk(gp, pp);
+ if (error != 0) {
+ if (isnew) {
+ g_multipath_destroy(gp);
+ }
+ return (NULL);
+ }
+ return (gp);
+}
+
static void
g_multipath_ctl_create(struct gctl_req *req, struct g_class *mp)
{
+ struct g_geom *gp;
struct g_provider *pp0, *pp1;
- const char *name, *mpname;
+ struct g_multipath_metadata md;
+ const char *name, *mpname, *uuid;
static const char devpf[6] = "/dev/";
- int *nargs;
+ int *nargs, error;
g_topology_assert();
@@ -345,8 +442,8 @@
gctl_error(req, "No 'nargs' argument");
return;
}
- if (*nargs != 3) {
- gctl_error(req, "Missing the two devices required");
+ if (*nargs != 4) {
+ gctl_error(req, "missing device or uuid arguments");
return;
}
@@ -378,7 +475,58 @@
return;
}
- if (g_multipath_create(req, mp, mpname, pp0, pp1)) {
+ 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;
+ }
+
+ /*
+ * Check to make sure parameters from the two providers are the same
+ */
+ 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 has mediasize %zu; Provider %s "
+ "has mediasize %zu", 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;
+ strncpy(md.md_name, mpname, sizeof (md.md_name));
+ strncpy(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;
}
}
@@ -389,8 +537,9 @@
struct g_geom *gp;
LIST_FOREACH(gp, &mp->geom, geom) {
- if (strcmp(gp->name, name) == 0)
+ if (strcmp(gp->name, name) == 0) {
return (gp);
+ }
}
return (NULL);
}
@@ -424,27 +573,18 @@
g_multipath_config(struct gctl_req *req, struct g_class *mp, const char *verb)
{
uint32_t *version;
-
g_topology_assert();
-
version = gctl_get_paraml(req, "version", sizeof(*version));
if (version == NULL) {
- gctl_error(req, "No '%s' argument.", "version");
- return;
- }
- if (*version != G_MULTIPATH_VERSION) {
- gctl_error(req, "Userland and kernel parts are out of sync.");
- return;
- }
-
- if (strcmp(verb, "create") == 0) {
+ 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);
- return;
} else if (strcmp(verb, "destroy") == 0) {
g_multipath_ctl_destroy(req, mp);
- return;
+ } else {
+ gctl_error(req, "Unknown verb %s", verb);
}
-
- gctl_error(req, "Unknown verb.");
}
DECLARE_GEOM_CLASS(g_multipath_class, g_multipath);
==== //depot/projects/mjexp/sys/geom/multipath/g_multipath.h#3 (text+ko) ====
@@ -25,24 +25,81 @@
*
* $FreeBSD$
*/
+/*
+ * Based upon work by Pawel Jakub Dawidek <pjd at FreeBSD.org> for all of the
+ * fine geom examples, and by Poul Henning Kamp <phk at FreeBSD.org> for GEOM
+ * itself, all of which is most gratefully acknowledged.
+ */
#ifndef _G_MULTIPATH_H_
#define _G_MULTIPATH_H_
-#define G_MULTIPATH_CLASS_NAME "MULTIPATH"
-#define G_MULTIPATH_VERSION 0
+#define G_MULTIPATH_CLASS_NAME "MULTIPATH"
+#define G_MULTIPATH_VERSION 1
+#define G_MULTIPATH_MAGIC "GEOM::MULTIPATH"
+
+#include <sys/endian.h>
#ifdef _KERNEL
#define G_MULTIPATH_BIO_PFLAG_ERROR 0x1
-
struct g_multipath_softc {
struct g_provider * pp;
- unsigned int : 30,
+ unsigned int : 28,
+ nattached : 2,
ready : 1,
cur_prov : 1;
struct g_consumer * consumers[2];
struct g_provider * providers[2];
+ char sc_name[16];
+ char sc_uuid[40];
};
#endif /* _KERNEL */
+
+struct g_multipath_metadata {
+ char md_magic[16]; /* Magic Value */
+ char md_uuid[40]; /* more magic */
+ char md_name[16]; /* a friendly name */
+ uint32_t md_version; /* version */
+ uint32_t md_sectorsize; /* sectorsize of provider */
+ uint64_t md_size; /* absolute size of provider */
+};
+
+static __inline void
+multipath_metadata_encode(const struct g_multipath_metadata *, u_char *);
+
+static __inline void
+multipath_metadata_decode(u_char *, struct g_multipath_metadata *);
+
+static __inline void
+multipath_metadata_encode(const struct g_multipath_metadata *md, u_char *data)
+{
+ bcopy(md->md_magic, data, sizeof(md->md_magic));
+ data += sizeof(md->md_magic);
+ bcopy(md->md_uuid, data, sizeof(md->md_uuid));
+ data += sizeof(md->md_uuid);
+ bcopy(md->md_name, data, sizeof(md->md_name));
+ data += sizeof(md->md_name);
+ le32enc(data, md->md_version);
+ data += sizeof(md->md_version);
+ le32enc(data, md->md_sectorsize);
+ data += sizeof(md->md_sectorsize);
+ le64enc(data, md->md_size);
+}
+
+static __inline void
+multipath_metadata_decode(u_char *data, struct g_multipath_metadata *md)
+{
+ bcopy(data, md->md_magic, sizeof(md->md_magic));
+ data += sizeof(md->md_magic);
+ bcopy(data, md->md_uuid, sizeof(md->md_uuid));
+ data += sizeof(md->md_uuid);
+ bcopy(data, md->md_name, sizeof(md->md_name));
+ data += sizeof(md->md_name);
+ md->md_version = le32dec(data);
+ data += sizeof(md->md_version);
+ md->md_sectorsize = le32dec(data);
+ data += sizeof(md->md_sectorsize);
+ md->md_size = le64dec(data);
+}
#endif /* _G_MULTIPATH_H_ */
More information about the p4-projects
mailing list