Skip site navigation (1)Skip section navigation (2)
Date:      Sat, 16 Nov 2013 14:31:49 +0000 (UTC)
From:      Alexander Motin <mav@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org
Subject:   svn commit: r258220 - head/sys/geom/multipath
Message-ID:  <201311161431.rAGEVneO037506@svn.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: mav
Date: Sat Nov 16 14:31:49 2013
New Revision: 258220
URL: http://svnweb.freebsd.org/changeset/base/258220

Log:
  Implement automatic live resize support for GEOM MULTIPATH class.
  
  In "manual" mode just automatically resize provider in any direction.
  In "automatic" mode allow only growth (with new metadata write); in case
  of shrinking destroy the multipath device same as before since it may be
  undesirable to write new metadata within old user area.
  
  MFC after:	1 month

Modified:
  head/sys/geom/multipath/g_multipath.c
  head/sys/geom/multipath/g_multipath.h

Modified: head/sys/geom/multipath/g_multipath.c
==============================================================================
--- head/sys/geom/multipath/g_multipath.c	Sat Nov 16 10:49:02 2013	(r258219)
+++ head/sys/geom/multipath/g_multipath.c	Sat Nov 16 14:31:49 2013	(r258220)
@@ -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>
@@ -67,6 +68,7 @@ static struct bio_queue_head gmtbq;
 static struct mtx gmtbq_mtx;
 
 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 +239,84 @@ 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_provider *pp;
+	struct g_multipath_metadata md;
+	off_t size, psize, ssize;
+	int error;
+	void *buf;
+
+	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(cp, &gp->consumer, consumer) {
+			pp = cp->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 && psize < sc->sc_pp->mediasize) {
+		g_multipath_destroy(gp);
+		return;
+	}
+	sc->sc_size = size;
+	g_resize_provider(sc->sc_pp, psize);
+
+	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) {
+			printf("GEOM_MULTIPATH: Can't open %s (%d)\n",
+			    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, sc->sc_name, sizeof(md.md_name));
+		md.md_version = G_MULTIPATH_VERSION;
+		md.md_size = size;
+		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);
+		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) {
@@ -837,7 +916,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 +925,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);

Modified: head/sys/geom/multipath/g_multipath.h
==============================================================================
--- head/sys/geom/multipath/g_multipath.h	Sat Nov 16 10:49:02 2013	(r258219)
+++ head/sys/geom/multipath/g_multipath.h	Sat Nov 16 14:31:49 2013	(r258220)
@@ -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?201311161431.rAGEVneO037506>