summaryrefslogtreecommitdiffstats
path: root/sys/geom/geom_subr.c
diff options
context:
space:
mode:
authortrasz <trasz@FreeBSD.org>2012-07-07 20:13:40 +0000
committertrasz <trasz@FreeBSD.org>2012-07-07 20:13:40 +0000
commitf2e3e9e07318ddf592e5f29fb5edce4ea8b697c8 (patch)
treec90342a24cb2236a8321bbb21302c93f83933ef8 /sys/geom/geom_subr.c
parent80dc0e94a448f0f3cfe7b699930beab72b1fa2fb (diff)
downloadFreeBSD-src-f2e3e9e07318ddf592e5f29fb5edce4ea8b697c8.zip
FreeBSD-src-f2e3e9e07318ddf592e5f29fb5edce4ea8b697c8.tar.gz
Add a new GEOM method, resize(), which is called after provider size changes.
Add a new routine, g_resize_provider(), to use to notify GEOM about provider change. Reviewed by: mav Sponsored by: FreeBSD Foundation
Diffstat (limited to 'sys/geom/geom_subr.c')
-rw-r--r--sys/geom/geom_subr.c79
1 files changed, 76 insertions, 3 deletions
diff --git a/sys/geom/geom_subr.c b/sys/geom/geom_subr.c
index 489de91..37a9ce0 100644
--- a/sys/geom/geom_subr.c
+++ b/sys/geom/geom_subr.c
@@ -68,9 +68,11 @@ static struct g_tailq_head geoms = TAILQ_HEAD_INITIALIZER(geoms);
char *g_wait_event, *g_wait_up, *g_wait_down, *g_wait_sim;
struct g_hh00 {
- struct g_class *mp;
- int error;
- int post;
+ struct g_class *mp;
+ struct g_provider *pp;
+ off_t size;
+ int error;
+ int post;
};
/*
@@ -356,6 +358,7 @@ g_new_geomf(struct g_class *mp, const char *fmt, ...)
gp->access = mp->access;
gp->orphan = mp->orphan;
gp->ioctl = mp->ioctl;
+ gp->resize = mp->resize;
return (gp);
}
@@ -601,6 +604,76 @@ g_error_provider(struct g_provider *pp, int error)
pp->error = error;
}
+static void
+g_resize_provider_event(void *arg, int flag)
+{
+ struct g_hh00 *hh;
+ struct g_class *mp;
+ struct g_geom *gp;
+ struct g_provider *pp;
+ struct g_consumer *cp, *cp2;
+ off_t size;
+
+ g_topology_assert();
+ if (flag == EV_CANCEL)
+ return;
+ if (g_shutdown)
+ return;
+
+ hh = arg;
+ pp = hh->pp;
+ size = hh->size;
+
+ G_VALID_PROVIDER(pp);
+ g_trace(G_T_TOPOLOGY, "g_resize_provider_event(%p)", pp);
+
+ LIST_FOREACH_SAFE(cp, &pp->consumers, consumers, cp2) {
+ gp = cp->geom;
+ if (gp->resize == NULL && size < pp->mediasize)
+ cp->geom->orphan(cp);
+ }
+
+ pp->mediasize = size;
+
+ LIST_FOREACH_SAFE(cp, &pp->consumers, consumers, cp2) {
+ gp = cp->geom;
+ if (gp->resize != NULL)
+ gp->resize(cp);
+ }
+
+ /*
+ * After resizing, the previously invalid GEOM class metadata
+ * might become valid. This means we should retaste.
+ */
+ LIST_FOREACH(mp, &g_classes, class) {
+ if (mp->taste == NULL)
+ continue;
+ LIST_FOREACH(cp, &pp->consumers, consumers)
+ if (cp->geom->class == mp)
+ break;
+ if (cp != NULL)
+ continue;
+ mp->taste(mp, pp, 0);
+ g_topology_assert();
+ }
+}
+
+void
+g_resize_provider(struct g_provider *pp, off_t size)
+{
+ struct g_hh00 *hh;
+
+ G_VALID_PROVIDER(pp);
+
+ if (size == pp->mediasize)
+ return;
+
+ hh = g_malloc(sizeof *hh, M_WAITOK | M_ZERO);
+ hh->pp = pp;
+ hh->size = size;
+ g_post_event(g_resize_provider_event, hh, M_WAITOK, NULL);
+}
+
struct g_provider *
g_provider_by_name(char const *arg)
{
OpenPOWER on IntegriCloud