RFC: adding 'proxy' nodes to provider ports (with patch)

Luigi Rizzo rizzo at iet.unipi.it
Mon Mar 23 13:02:22 PDT 2009

On Mon, Mar 23, 2009 at 06:58:16AM +0000, Poul-Henning Kamp wrote:
> In message <20090323060325.GN3102 at garage.freebsd.pl>, Pawel Jakub Dawidek write
> s:
> >There is still a naming problem. pp and new_pp will end up with the same
> >name. I'd suggest instructing GEOM to expose only parent in /dev/.
> who said the new provider had to have same name ?
> >The taste is still going to be send on new class arrival and on the last
> >pp write close.
> We decide that.
> Since we are inserting in an already open path, I think it makes very
> good sense to supress tasting, at least until close.

To summarize, here is how I have implemented a node that
supports both regular "create" and the transparent "insert"
we are discussing.
Say we want to attach to an existing provider "pp" whose name is "ad0"

  BEFORE        ---> [ pp    --> old_gp ...]

Then we can do either "geom xx create ad0" which results in

  AFTER create  ---> [ newpp --> gp --> cp ] ---> [ pp    --> old_gp ... ]

or "geom xx insert ad0", which results in

  AFTER insert  ---> [ pp    --> gp --> cp ] ---> [ newpp --> old_gp ... ]

The names of the various objects are the same in both cases so

	old_gp->name	= "ad0"
	pp->name	= "ad0"
	gp->name	= "ad0.xx."
	newpp->name	= "ad0.xx."

This lets new clients connect to provider "ad0" without having to
know about any insertion.
Also, to remove the newly inserted pieces, in both cases you can
run the same command "geom xx destroy ad0.xx." (remembering that
in this case you are naming the geom, not the provider).

In terms of code, no changes to the infrastructure, and the
create/insert and destroy functions are the following (error checking
removed for clarity)

   g_xx_create(struct g_provider *pp, struct g_class *mp, int insert ...)
        snprintf(name, sizeof(name), "%s%s", pp->name, MY_SUFFIX);
        gp = g_new_geomf(mp, name);
	... allocate and fill softc and geom...
        newpp = g_new_providerf(insert ? pp->geom : gp, gp->name);
	... initialize mediasize and sectorsize
        cp = g_new_consumer(gp);
        g_attach(cp, insert ? newpp : pp);
        if (insert) {
                g_cancel_event(newpp);          /* no taste() on this*/
                /* link pp to old_gp */
                LIST_REMOVE(pp, provider);
                pp->geom = gp;
                LIST_INSERT_HEAD(&gp->provider, pp, provider);
                g_access(cp, 1, 1, 1);          /* we can move data */
                sc->sc_insert = 1;              /* remember for the destroy */
	g_error_provider(newpp, 0);

Here it is a bit inefficient to have to call g_cancel_event()
but short of changing g_new_providerf() there is no way to
avoid the g_new_provider event.

    g_xx_destroy(struct g_geom *gp)
        if (sc->sc_insert) {
                pp = LIST_FIRST(&gp->provider);
                cp = LIST_FIRST(&gp->consumer);
                newpp = cp->provider;
                /* Link provider to the original geom. */
                LIST_REMOVE(pp, provider);
                pp->geom = newpp->geom;
                LIST_INSERT_HEAD(&pp->geom->provider, pp, provider);
                g_access(cp, -1, -1, -1);
		/* I am not sure if we need the following 3 */
                LIST_REMOVE(newpp, provider);
        /* regular destroy path */

Above, I am not totally sure if we need to explicitly call g_detach()
and destroy the provider, or if it will come for free as a result of
the regular destoy code.

The block "if (sc->sc_insert) {..}" is reasonably generic
(and large, when you put in the error checking) to possibly deserve
a function in geom_subr.c -- but until there are no other clients,
it makes no sense.

As usual, feedback welcome.


More information about the freebsd-geom mailing list