Skip site navigation (1)Skip section navigation (2)
Date:      Wed, 2 Dec 2009 19:32:31 +0100
From:      Thomas Quinot <thomas@FreeBSD.ORG>
To:        freebsd-geom@freebsd.org
Subject:   Re: [PATCH] Forcing preferred path in geom_multipath
Message-ID:  <20091202183231.GA4362@melamine.cuivre.fr.eu.org>
In-Reply-To: <20091202133911.GA96216@melamine.cuivre.fr.eu.org>
References:  <20091202133911.GA96216@melamine.cuivre.fr.eu.org>

next in thread | previous in thread | raw e-mail | index | archive | help
* Thomas Quinot, 2009-12-02 :

> Any suggestions as to how to achieve the desired ordering of preferred
> paths for each multipath geom?

OK, here's a simple solution, add a new verb to gmultipath to allow the
user to switch to a new preferred provider. Review/comments welcome.

Thomas.

Index: sbin/geom/class/multipath/geom_multipath.c
===================================================================
--- sbin/geom/class/multipath/geom_multipath.c	(révision 200035)
+++ sbin/geom/class/multipath/geom_multipath.c	(copie de travail)
@@ -48,6 +48,7 @@
 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_prefer(struct gctl_req *);
 
 struct g_command class_commands[] = {
 	{
@@ -58,6 +59,10 @@
 		"clear", G_FLAG_VERBOSE, mp_main, G_NULL_OPTS,
 		NULL, "[-v] prov ..."
 	},
+	{
+		"prefer", G_FLAG_VERBOSE, mp_main, G_NULL_OPTS,
+		NULL, "[-v] prov ..."
+	},
 	G_CMD_SENTINEL
 };
 
@@ -75,6 +80,8 @@
 		mp_label(req);
 	} else if (strcmp(name, "clear") == 0) {
 		mp_clear(req);
+	} else if (strcmp(name, "prefer") == 0) {
+		mp_prefer(req);
 	} else {
 		gctl_error(req, "Unknown command: %s.", name);
 	}
@@ -228,3 +235,23 @@
                 }
         }
 }
+
+static void
+mp_prefer(struct gctl_req *req)
+{
+	const char *name, *comp, *errstr;
+	int nargs;
+
+	nargs = gctl_get_int(req, "nargs");
+	if (nargs != 2) {
+		gctl_error(req, "Usage: prefer GEOM PROVIDER");
+		return;
+	}
+	name = gctl_get_ascii(req, "arg0");
+	comp = gctl_get_ascii(req, "arg1");
+	errstr = gctl_issue (req);
+	if (errstr != NULL) {
+		fprintf(stderr, "Can't set %s preferred provider to %s: %s.\n",
+		    name, comp, errstr);
+	}
+}
Index: sys/geom/geom_subr.c
===================================================================
--- sys/geom/geom_subr.c	(révision 200035)
+++ sys/geom/geom_subr.c	(copie de travail)
@@ -647,7 +647,7 @@
  * can't risk that on the kernel stack.
  */
 
-static int
+int
 redo_rank(struct g_geom *gp)
 {
 	struct g_consumer *cp;
Index: sys/geom/multipath/g_multipath.c
===================================================================
--- sys/geom/multipath/g_multipath.c	(révision 200035)
+++ sys/geom/multipath/g_multipath.c	(copie de travail)
@@ -67,6 +67,8 @@
 static void g_multipath_kt(void *);
 
 static int g_multipath_destroy(struct g_geom *);
+static struct g_geom *
+g_multipath_find_geom(struct g_class *, const char *);
 static int
 g_multipath_destroy_geom(struct gctl_req *, struct g_class *, struct g_geom *);
 
@@ -706,6 +708,77 @@
 	}
 }
 
+static void
+g_multipath_ctl_prefer(struct gctl_req *req, struct g_class *mp)
+{
+	struct g_geom *gp;
+	struct g_multipath_softc *sc;
+	struct g_consumer *cp;
+	struct g_provider *pp;
+	const char *name, *mpname;
+	static const char devpf[6] = "/dev/";
+	int *nargs;
+
+	g_topology_assert();
+
+	mpname = gctl_get_asciiparam(req, "arg0");
+        if (mpname == NULL) {
+                gctl_error(req, "No 'arg0' argument");
+                return;
+        }
+	gp = g_multipath_find_geom(mp, mpname);
+	if (gp == NULL) {
+		gctl_error(req, "Device %s is invalid", mpname);
+		return;
+	}
+	sc = gp->softc;
+
+	nargs = gctl_get_paraml(req, "nargs", sizeof(*nargs));
+	if (nargs == NULL) {
+		gctl_error(req, "No 'nargs' argument");
+		return;
+	}
+	if (*nargs != 2) {
+		gctl_error(req, "missing device");
+		return;
+	}
+
+	name = gctl_get_asciiparam(req, "arg1");
+	if (name == NULL) {
+		gctl_error(req, "No 'arg1' argument");
+		return;
+	}
+	if (strncmp(name, devpf, 5) == 0) {
+		name += 5;
+	}
+	pp = g_provider_by_name(name);
+	if (pp == NULL) {
+		gctl_error(req, "Provider %s is invalid", name);
+		return;
+	}
+	g_topology_lock ();
+	LIST_FOREACH(cp, &gp->consumer, consumer) {
+		if (cp->provider == pp) {
+			/* Move cp to head of consumers list */
+			LIST_REMOVE(cp, consumers);
+			LIST_INSERT_HEAD(&pp->consumers, cp, consumers);
+			redo_rank (cp->geom);
+
+			/* Make it the active path */
+			sc->cp_active = cp;
+			printf("GEOM_MULTIPATH: %s now active path in %s\n",
+			    sc->cp_active->provider->name, sc->sc_name);
+			break;
+		}
+	}
+	g_topology_unlock ();
+	if (cp == NULL) {
+		gctl_error(req, "No consumer for %s", name);
+		return;
+	}
+
+}
+
 static struct g_geom *
 g_multipath_find_geom(struct g_class *mp, const char *name)
 {
@@ -756,6 +829,8 @@
 		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, "prefer") == 0) {
+		g_multipath_ctl_prefer(req, mp);
 	} else if (strcmp(verb, "destroy") == 0) {
 		g_multipath_ctl_destroy(req, mp);
 	} else {
Index: sys/geom/geom.h
===================================================================
--- sys/geom/geom.h	(révision 200035)
+++ sys/geom/geom.h	(copie de travail)
@@ -276,6 +276,7 @@
 #endif
 
 int g_modevent(module_t, int, void *);
+int redo_rank(struct g_geom *gp);
 
 /* geom_io.c */
 struct bio * g_clone_bio(struct bio *);



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?20091202183231.GA4362>