summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--sys/geom/multipath/g_multipath.c143
-rw-r--r--sys/geom/multipath/g_multipath.h1
2 files changed, 118 insertions, 26 deletions
diff --git a/sys/geom/multipath/g_multipath.c b/sys/geom/multipath/g_multipath.c
index 6bc1d6e..88e65f8 100644
--- a/sys/geom/multipath/g_multipath.c
+++ b/sys/geom/multipath/g_multipath.c
@@ -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, 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) {
@@ -668,6 +747,30 @@ g_multipath_read_metadata(struct g_consumer *cp,
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 *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 +949,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);
@@ -1030,7 +1133,6 @@ g_multipath_ctl_configure(struct gctl_req *req, struct g_class *mp)
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_req *req, struct g_class *mp)
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_req *req, struct g_class *mp)
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);
diff --git a/sys/geom/multipath/g_multipath.h b/sys/geom/multipath/g_multipath.h
index 33c44f1..c839dc4 100644
--- a/sys/geom/multipath/g_multipath.h
+++ b/sys/geom/multipath/g_multipath.h
@@ -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;
OpenPOWER on IntegriCloud