Skip site navigation (1)Skip section navigation (2)
Date:      Thu, 9 Jan 2014 11:11:47 +0000 (UTC)
From:      Alexander Motin <mav@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-stable@freebsd.org, svn-src-stable-10@freebsd.org
Subject:   svn commit: r260478 - stable/10/sys/geom/multipath
Message-ID:  <201401091111.s09BBlR3095030@svn.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: mav
Date: Thu Jan  9 11:11:47 2014
New Revision: 260478
URL: http://svnweb.freebsd.org/changeset/base/260478

Log:
  MFC r258220, r258251:
  Implement automatic live resize support for GEOM MULTIPATH class.
  
  In "manual" mode just automatically resize provider in any direction.
  In "automatic" mode allow growth (with new metadata write); in case of
  shrinking check if there is already valid metadata found at the new
  location.  This should allow easy transparent recovery if first resize
  was done by mistake.
  
  While there, unify metadata write code and fix minor memory leak.

Modified:
  stable/10/sys/geom/multipath/g_multipath.c
  stable/10/sys/geom/multipath/g_multipath.h
Directory Properties:
  stable/10/   (props changed)

Modified: stable/10/sys/geom/multipath/g_multipath.c
==============================================================================
--- stable/10/sys/geom/multipath/g_multipath.c	Thu Jan  9 10:59:31 2014	(r260477)
+++ stable/10/sys/geom/multipath/g_multipath.c	Thu Jan  9 11:11:47 2014	(r260478)
@@ -1,5 +1,5 @@
 /*-
- * Copyright (c) 2011 Alexander Motin <mav@FreeBSD.org>
+ * Copyright (c) 2011-2013 Alexander Motin <mav@FreeBSD.org>
  * Copyright (c) 2006-2007 Matthew Jacob <mjacob@FreeBSD.org>
  * All rights reserved.
  *
@@ -36,6 +36,7 @@ __FBSDID("$FreeBSD$");
 #include <sys/systm.h>
 #include <sys/kernel.h>
 #include <sys/module.h>
+#include <sys/limits.h>
 #include <sys/lock.h>
 #include <sys/mutex.h>
 #include <sys/bio.h>
@@ -66,7 +67,13 @@ static enum {
 static struct bio_queue_head gmtbq;
 static struct mtx gmtbq_mtx;
 
+static int g_multipath_read_metadata(struct g_consumer *cp,
+    struct g_multipath_metadata *md);
+static int g_multipath_write_metadata(struct g_consumer *cp,
+    struct g_multipath_metadata *md);
+
 static void g_multipath_orphan(struct g_consumer *);
+static void g_multipath_resize(struct g_consumer *);
 static void g_multipath_start(struct bio *);
 static void g_multipath_done(struct bio *);
 static void g_multipath_done_error(struct bio *);
@@ -237,6 +244,79 @@ g_multipath_orphan(struct g_consumer *cp
 }
 
 static void
+g_multipath_resize(struct g_consumer *cp)
+{
+	struct g_multipath_softc *sc;
+	struct g_geom *gp;
+	struct g_consumer *cp1;
+	struct g_provider *pp;
+	struct g_multipath_metadata md;
+	off_t size, psize, ssize;
+	int error;
+
+	g_topology_assert();
+
+	gp = cp->geom;
+	pp = cp->provider;
+	sc = gp->softc;
+
+	if (sc->sc_stopping)
+		return;
+
+	if (pp->mediasize < sc->sc_size) {
+		size = pp->mediasize;
+		ssize = pp->sectorsize;
+	} else {
+		size = ssize = OFF_MAX;
+		mtx_lock(&sc->sc_mtx);
+		LIST_FOREACH(cp1, &gp->consumer, consumer) {
+			pp = cp1->provider;
+			if (pp == NULL)
+				continue;
+			if (pp->mediasize < size) {
+				size = pp->mediasize;
+				ssize = pp->sectorsize;
+			}
+		}
+		mtx_unlock(&sc->sc_mtx);
+		if (size == OFF_MAX || size == sc->sc_size)
+			return;
+	}
+	psize = size - ((sc->sc_uuid[0] != 0) ? ssize : 0);
+	printf("GEOM_MULTIPATH: %s size changed from %jd to %jd\n",
+	    sc->sc_name, sc->sc_pp->mediasize, psize);
+	if (sc->sc_uuid[0] != 0 && size < sc->sc_size) {
+		error = g_multipath_read_metadata(cp, &md);
+		if (error ||
+		    (strcmp(md.md_magic, G_MULTIPATH_MAGIC) != 0) ||
+		    (memcmp(md.md_uuid, sc->sc_uuid, sizeof(sc->sc_uuid)) != 0) ||
+		    (strcmp(md.md_name, sc->sc_name) != 0) ||
+		    (md.md_size != 0 && md.md_size != size) ||
+		    (md.md_sectorsize != 0 && md.md_sectorsize != ssize)) {
+			g_multipath_destroy(gp);
+			return;
+		}
+	}
+	sc->sc_size = size;
+	g_resize_provider(sc->sc_pp, psize);
+
+	if (sc->sc_uuid[0] != 0) {
+		pp = cp->provider;
+		strlcpy(md.md_magic, G_MULTIPATH_MAGIC, sizeof(md.md_magic));
+		memcpy(md.md_uuid, sc->sc_uuid, sizeof (sc->sc_uuid));
+		strlcpy(md.md_name, sc->sc_name, sizeof(md.md_name));
+		md.md_version = G_MULTIPATH_VERSION;
+		md.md_size = size;
+		md.md_sectorsize = ssize;
+		md.md_active_active = sc->sc_active_active;
+		error = g_multipath_write_metadata(cp, &md);
+		if (error != 0)
+			printf("GEOM_MULTIPATH: Can't update metadata on %s "
+			    "(%d)\n", pp->name, error);
+	}
+}
+
+static void
 g_multipath_start(struct bio *bp)
 {
 	struct g_multipath_softc *sc;
@@ -435,9 +515,11 @@ g_multipath_create(struct g_class *mp, s
 	memcpy(sc->sc_uuid, md->md_uuid, sizeof (sc->sc_uuid));
 	memcpy(sc->sc_name, md->md_name, sizeof (sc->sc_name));
 	sc->sc_active_active = md->md_active_active;
+	sc->sc_size = md->md_size;
 	gp->softc = sc;
 	gp->start = g_multipath_start;
 	gp->orphan = g_multipath_orphan;
+	gp->resize = g_multipath_resize;
 	gp->access = g_multipath_access;
 	gp->dumpconf = g_multipath_dumpconf;
 
@@ -514,18 +596,17 @@ g_multipath_add_disk(struct g_geom *gp, 
 		g_destroy_consumer(cp);
 		return (error);
 	}
-	if (sc->sc_pp != NULL && sc->sc_pp->mediasize == 0) {
-		sc->sc_pp->mediasize = pp->mediasize -
+	if (sc->sc_size == 0) {
+		sc->sc_size = pp->mediasize -
 		    ((sc->sc_uuid[0] != 0) ? pp->sectorsize : 0);
+		sc->sc_pp->mediasize = sc->sc_size;
 		sc->sc_pp->sectorsize = pp->sectorsize;
 	}
-	if (sc->sc_pp != NULL &&
-	    sc->sc_pp->stripesize == 0 && sc->sc_pp->stripeoffset == 0) {
+	if (sc->sc_pp->stripesize == 0 && sc->sc_pp->stripeoffset == 0) {
 		sc->sc_pp->stripesize = pp->stripesize;
 		sc->sc_pp->stripeoffset = pp->stripeoffset;
 	}
-	if (sc->sc_pp != NULL)
-		sc->sc_pp->flags |= pp->flags & G_PF_ACCEPT_UNMAPPED;
+	sc->sc_pp->flags |= pp->flags & G_PF_ACCEPT_UNMAPPED;
 	mtx_lock(&sc->sc_mtx);
 	cp->index = 0;
 	sc->sc_ndisks++;
@@ -556,10 +637,8 @@ g_multipath_destroy(struct g_geom *gp)
 		sc->sc_stopping = 1;
 	}
 	if (sc->sc_opened != 0) {
-		if (sc->sc_pp != NULL) {
-			g_wither_provider(sc->sc_pp, ENXIO);
-			sc->sc_pp = NULL;
-		}
+		g_wither_provider(sc->sc_pp, ENXIO);
+		sc->sc_pp = NULL;
 		return (EINPROGRESS);
 	}
 	LIST_FOREACH_SAFE(cp, &gp->consumer, consumer, cp1) {
@@ -668,6 +747,30 @@ g_multipath_read_metadata(struct g_consu
 	return (0);
 }
 
+static int
+g_multipath_write_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, 1, 1);
+	if (error != 0)
+		return (error);
+	pp = cp->provider;
+	g_topology_unlock();
+	buf = g_malloc(pp->sectorsize, M_WAITOK | M_ZERO);
+	multipath_metadata_encode(md, buf);
+	error = g_write_data(cp, pp->mediasize - pp->sectorsize,
+	    buf, pp->sectorsize);
+	g_topology_lock();
+	g_access(cp, -1, -1, -1);
+	g_free(buf);
+	return (error);
+}
+
 static struct g_geom *
 g_multipath_taste(struct g_class *mp, struct g_provider *pp, int flags __unused)
 {
@@ -837,7 +940,7 @@ g_multipath_ctl_add_name(struct gctl_req
 			return;
 		}
 	}
-	if (sc->sc_pp != NULL && sc->sc_pp->mediasize != 0 &&
+	if (sc->sc_pp->mediasize != 0 &&
 	    sc->sc_pp->mediasize + (sc->sc_uuid[0] != 0 ? pp->sectorsize : 0)
 	     != pp->mediasize) {
 		gctl_error(req, "Providers size mismatch %jd != %jd",
@@ -846,7 +949,7 @@ g_multipath_ctl_add_name(struct gctl_req
 		    (intmax_t) pp->mediasize);
 		return;
 	}
-	if (sc->sc_pp != NULL && sc->sc_pp->sectorsize != 0 &&
+	if (sc->sc_pp->sectorsize != 0 &&
 	    sc->sc_pp->sectorsize != pp->sectorsize) {
 		gctl_error(req, "Providers sectorsize mismatch %u != %u",
 		    sc->sc_pp->sectorsize, pp->sectorsize);
@@ -1030,7 +1133,6 @@ g_multipath_ctl_configure(struct gctl_re
 	struct g_multipath_metadata md;
 	const char *name;
 	int error, *val;
-	void *buf;
 
 	g_topology_assert();
 
@@ -1057,13 +1159,6 @@ g_multipath_ctl_configure(struct gctl_re
 	if (sc->sc_uuid[0] != 0 && sc->sc_active != NULL) {
 		cp = sc->sc_active;
 		pp = cp->provider;
-		error = g_access(cp, 1, 1, 1);
-		if (error != 0) {
-			gctl_error(req, "Can't open %s (%d)", pp->name, error);
-			return;
-		}
-		g_topology_unlock();
-		buf = g_malloc(pp->sectorsize, M_WAITOK | M_ZERO);
 		strlcpy(md.md_magic, G_MULTIPATH_MAGIC, sizeof(md.md_magic));
 		memcpy(md.md_uuid, sc->sc_uuid, sizeof (sc->sc_uuid));
 		strlcpy(md.md_name, name, sizeof(md.md_name));
@@ -1071,11 +1166,7 @@ g_multipath_ctl_configure(struct gctl_re
 		md.md_size = pp->mediasize;
 		md.md_sectorsize = pp->sectorsize;
 		md.md_active_active = sc->sc_active_active;
-		multipath_metadata_encode(&md, buf);
-		error = g_write_data(cp, pp->mediasize - pp->sectorsize,
-		    buf, pp->sectorsize);
-		g_topology_lock();
-		g_access(cp, -1, -1, -1);
+		error = g_multipath_write_metadata(cp, &md);
 		if (error != 0)
 			gctl_error(req, "Can't update metadata on %s (%d)",
 			    pp->name, error);

Modified: stable/10/sys/geom/multipath/g_multipath.h
==============================================================================
--- stable/10/sys/geom/multipath/g_multipath.h	Thu Jan  9 10:59:31 2014	(r260477)
+++ stable/10/sys/geom/multipath/g_multipath.h	Thu Jan  9 11:11:47 2014	(r260478)
@@ -48,6 +48,7 @@ struct g_multipath_softc {
 	struct mtx		sc_mtx;
 	char			sc_name[16];
 	char			sc_uuid[40];
+	off_t			sc_size;
 	int			sc_opened;
 	int			sc_stopping;
 	int			sc_ndisks;



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