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
This commit is contained in:
trasz 2012-07-07 20:13:40 +00:00
parent 80dc0e94a4
commit f2e3e9e073
2 changed files with 80 additions and 5 deletions

View File

@ -79,6 +79,7 @@ typedef void g_attrchanged_t (struct g_consumer *, const char *attr);
typedef void g_provgone_t (struct g_provider *);
typedef void g_dumpconf_t (struct sbuf *, const char *indent, struct g_geom *,
struct g_consumer *, struct g_provider *);
typedef void g_resize_t(struct g_consumer *cp);
/*
* The g_class structure describes a transformation class. In other words
@ -108,7 +109,7 @@ struct g_class {
g_orphan_t *orphan;
g_ioctl_t *ioctl;
g_provgone_t *providergone;
void *spare2;
g_resize_t *resize;
/*
* The remaining elements are private
*/
@ -139,7 +140,7 @@ struct g_geom {
g_orphan_t *orphan;
g_ioctl_t *ioctl;
g_provgone_t *providergone;
void *spare1;
g_resize_t *resize;
void *softc;
unsigned flags;
#define G_GEOM_WITHER 1
@ -265,6 +266,7 @@ int g_handleattr_str(struct bio *bp, const char *attribute, const char *str);
struct g_consumer * g_new_consumer(struct g_geom *gp);
struct g_geom * g_new_geomf(struct g_class *mp, const char *fmt, ...);
struct g_provider * g_new_providerf(struct g_geom *gp, const char *fmt, ...);
void g_resize_provider(struct g_provider *pp, off_t size);
int g_retaste(struct g_class *mp);
void g_spoil(struct g_provider *pp, struct g_consumer *cp);
int g_std_access(struct g_provider *pp, int dr, int dw, int de);

View File

@ -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)
{