diff options
author | trasz <trasz@FreeBSD.org> | 2012-07-07 20:13:40 +0000 |
---|---|---|
committer | trasz <trasz@FreeBSD.org> | 2012-07-07 20:13:40 +0000 |
commit | f2e3e9e07318ddf592e5f29fb5edce4ea8b697c8 (patch) | |
tree | c90342a24cb2236a8321bbb21302c93f83933ef8 /sys/geom/geom_subr.c | |
parent | 80dc0e94a448f0f3cfe7b699930beab72b1fa2fb (diff) | |
download | FreeBSD-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.c | 79 |
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) { |