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
This commit is contained in:
parent
3477d65d6a
commit
e6afd72b93
@ -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 *);
|
||||
@ -236,6 +238,84 @@ g_multipath_orphan(struct g_consumer *cp)
|
||||
mtx_unlock(&sc->sc_mtx);
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
@ -435,9 +515,11 @@ g_multipath_create(struct g_class *mp, struct g_multipath_metadata *md)
|
||||
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, struct g_provider *pp)
|
||||
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 *req, struct g_class *mp,
|
||||
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 *req, struct g_class *mp,
|
||||
(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);
|
||||
|
@ -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;
|
||||
|
Loading…
Reference in New Issue
Block a user