Author: mjacob
Date: Mon Mar 29 18:04:06 2010
New Revision: 205847
URL: http://svn.freebsd.org/changeset/base/205847

Log:
  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

Modified:
  head/sbin/geom/class/multipath/geom_multipath.c
  head/sys/geom/multipath/g_multipath.c

Modified: head/sbin/geom/class/multipath/geom_multipath.c
==============================================================================
--- head/sbin/geom/class/multipath/geom_multipath.c     Mon Mar 29 17:39:38 
2010        (r205846)
+++ head/sbin/geom/class/multipath/geom_multipath.c     Mon Mar 29 18:04:06 
2010        (r205847)
@@ -48,6 +48,7 @@ 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[] = {
        {
@@ -55,6 +56,10 @@ struct g_command class_commands[] = {
                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 i
        }
        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.");
        }
+}
 
-        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;
-                }
-        }
+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);
+       }
 }

Modified: head/sys/geom/multipath/g_multipath.c
==============================================================================
--- head/sys/geom/multipath/g_multipath.c       Mon Mar 29 17:39:38 2010        
(r205846)
+++ head/sys/geom/multipath/g_multipath.c       Mon Mar 29 18:04:06 2010        
(r205847)
@@ -70,6 +70,7 @@ static int g_multipath_destroy(struct g_
 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, st
 }
 
 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 *
                 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 *
        }
        if (strncmp(name, devpf, 5) == 0)
                name += 5;
-       pp0 = g_provider_by_name(name);
-       if (pp0 == 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;
-       }
-       if (strncmp(name, devpf, 5) == 0)
-               name += 5;
-       pp1 = g_provider_by_name(name);
-       if (pp1 == NULL) {
+       pp = g_provider_by_name(name);
+       if (pp == 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;
-       }
-
        /*
-        * Check to make sure parameters from the two providers are the same
+        * Check to make sure parameters match, if we already have one.
         */
-       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;
+       cp = LIST_FIRST(&gp->consumer);
+       if (cp) {
+               pp0 = cp->provider;
+       } else {
+               pp0 = NULL;
        }
-       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;
+       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;
+               }
        }
 
        /*
-        * cons up enough of a metadata structure to use.
+        * Now add....
         */
-       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,
                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) {
_______________________________________________
[email protected] mailing list
http://lists.freebsd.org/mailman/listinfo/svn-src-head
To unsubscribe, send any mail to "[email protected]"

Reply via email to