Date: Fri, 15 Dec 2006 06:42:06 GMT From: Matt Jacob <mjacob@FreeBSD.org> To: Perforce Change Reviews <perforce@freebsd.org> Subject: PERFORCE change 111726 for review Message-ID: <200612150642.kBF6g60A052864@repoman.freebsd.org>
next in thread | raw e-mail | index | archive | help
http://perforce.freebsd.org/chv.cgi?CH=111726 Change 111726 by mjacob@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@FreeBSD.org> for all of the + * fine geom examples, and by Poul Henning Kamp <phk@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@FreeBSD.org> for all of the + * fine geom examples, and by Poul Henning Kamp <phk@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_ */
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?200612150642.kBF6g60A052864>