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>