From owner-svn-src-all@FreeBSD.ORG Sat Nov 16 14:31:50 2013 Return-Path: Delivered-To: svn-src-all@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [8.8.178.115]) (using TLSv1 with cipher ADH-AES256-SHA (256/256 bits)) (No client certificate requested) by hub.freebsd.org (Postfix) with ESMTPS id 30E7961B; Sat, 16 Nov 2013 14:31:50 +0000 (UTC) Received: from svn.freebsd.org (svn.freebsd.org [IPv6:2001:1900:2254:2068::e6a:0]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mx1.freebsd.org (Postfix) with ESMTPS id 20A1923DA; Sat, 16 Nov 2013 14:31:50 +0000 (UTC) Received: from svn.freebsd.org ([127.0.1.70]) by svn.freebsd.org (8.14.7/8.14.7) with ESMTP id rAGEVnDP037508; Sat, 16 Nov 2013 14:31:49 GMT (envelope-from mav@svn.freebsd.org) Received: (from mav@localhost) by svn.freebsd.org (8.14.7/8.14.5/Submit) id rAGEVneO037506; Sat, 16 Nov 2013 14:31:49 GMT (envelope-from mav@svn.freebsd.org) Message-Id: <201311161431.rAGEVneO037506@svn.freebsd.org> From: Alexander Motin Date: Sat, 16 Nov 2013 14:31:49 +0000 (UTC) To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org Subject: svn commit: r258220 - head/sys/geom/multipath X-SVN-Group: head MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit X-BeenThere: svn-src-all@freebsd.org X-Mailman-Version: 2.1.16 Precedence: list List-Id: "SVN commit messages for the entire src tree \(except for " user" and " projects" \)" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Sat, 16 Nov 2013 14:31:50 -0000 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 + * Copyright (c) 2011-2013 Alexander Motin * Copyright (c) 2006-2007 Matthew Jacob * All rights reserved. * @@ -36,6 +36,7 @@ __FBSDID("$FreeBSD$"); #include #include #include +#include #include #include #include @@ -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;