Index: geom/geom_io.c =================================================================== --- geom/geom_io.c (revision 189933) +++ geom/geom_io.c (working copy) @@ -273,6 +273,10 @@ cp = bp->bio_from; pp = bp->bio_to; + /* Proxies are transparent, errors are caught by regular checks. */ + if (cp->geom->flags & G_GEOM_PROXY) + return (0); + /* Fail if access counters dont allow the operation */ switch(bp->bio_cmd) { case BIO_READ: @@ -343,6 +347,9 @@ bp->_bio_cflags = bp->bio_cflags; #endif + if (pp->proxy_provider != NULL && cp != pp->proxy_consumer) + pp = pp->proxy_provider; + if (bp->bio_cmd & (BIO_READ|BIO_WRITE|BIO_GETATTR)) { KASSERT(bp->bio_data != NULL, ("NULL bp->data in g_io_request(cmd=%hhu)", bp->bio_cmd)); Index: geom/geom_subr.c =================================================================== --- geom/geom_subr.c (revision 189933) +++ geom/geom_subr.c (working copy) @@ -365,6 +365,8 @@ g_cancel_event(gp); LIST_REMOVE(gp, geom); TAILQ_REMOVE(&geoms, gp, geoms); + if (gp->flags & G_GEOM_PROXY) + printf("g_destroy_geom(): destroying proxy %s", gp->name); g_free(gp->name); g_free(gp); } @@ -380,6 +382,11 @@ g_topology_assert(); G_VALID_GEOM(gp); g_trace(G_T_TOPOLOGY, "g_wither_geom(%p(%s))", gp, gp->name); + if (gp->flags & G_GEOM_PROXY) { + pp = LIST_FIRST(&gp->consumer)->provider; + pp->proxy_provider = NULL; + pp->proxy_consumer = NULL; + } if (!(gp->flags & G_GEOM_WITHER)) { gp->flags |= G_GEOM_WITHER; LIST_FOREACH(pp, &gp->provider, provider) @@ -581,7 +588,8 @@ pp->stat = devstat_new_entry(pp, -1, 0, DEVSTAT_ALL_SUPPORTED, DEVSTAT_TYPE_DIRECT, DEVSTAT_PRIORITY_MAX); LIST_INSERT_HEAD(&gp->provider, pp, provider); - g_post_event(g_new_provider_event, pp, M_WAITOK, pp, gp, NULL); + if (!(gp->flags & G_GEOM_PROXY)) + g_post_event(g_new_provider_event, pp, M_WAITOK, pp, gp, NULL); return (pp); } @@ -721,6 +729,20 @@ return (error); } +int +g_attach_proxy(struct g_consumer *cp, struct g_provider *pp, + struct g_provider *newpp) +{ + int error; + + error = g_attach(cp, pp); + if (!error) { + pp->proxy_provider = newpp; + pp->proxy_consumer = cp; + } + return (error); +} + void g_detach(struct g_consumer *cp) { Index: geom/geom.h =================================================================== --- geom/geom.h (revision 189933) +++ geom/geom.h (working copy) @@ -134,6 +134,7 @@ void *softc; unsigned flags; #define G_GEOM_WITHER 1 +#define G_GEOM_PROXY 2 }; /* @@ -190,6 +191,9 @@ #define G_PF_WITHER 0x2 #define G_PF_ORPHAN 0x4 + struct g_provider *proxy_provider; + struct g_consumer *proxy_consumer; + /* Two fields for the implementing class to use */ void *private; u_int index; @@ -219,6 +223,8 @@ /* geom_subr.c */ int g_access(struct g_consumer *cp, int nread, int nwrite, int nexcl); int g_attach(struct g_consumer *cp, struct g_provider *pp); +int g_attach_proxy(struct g_consumer *cp, struct g_provider *pp, + struct g_provider *newpp); void g_destroy_consumer(struct g_consumer *cp); void g_destroy_geom(struct g_geom *pp); void g_destroy_provider(struct g_provider *pp);