geom_label: Use provider aliasing to alias upstream geoms

For synthetic aliases (just pseudonyms inferred from metadata like GPT or
UFS labels, GPT UUIDs, etc), use the GEOM provider aliasing system to create
a symlink to the real device instead of creating an independent device.
This makes it more clear which labels and devices correspond, and we can
safely have multiple labels to a single device accessed at once.

The confusingly named geom_label on-disk construct continues to behave
identically to how it did before.

This requires teaching GEOM's provider aliasing about the possibility
that aliases might be added later in time, and GEOM's devfs interaction
layer not to worry about existing aliases during retaste.

Discussed with:	imp
Relnotes:	sure, if we don't end up reverting it
Differential Revision:	https://reviews.freebsd.org/D24968
This commit is contained in:
Conrad Meyer 2020-06-05 16:12:21 +00:00
parent c726a670df
commit 5b9b571cb3
2 changed files with 55 additions and 8 deletions

View File

@ -336,9 +336,20 @@ g_dev_taste(struct g_class *mp, struct g_provider *pp, int insist __unused)
struct cdev *dev, *adev;
char buf[SPECNAMELEN + 6];
struct make_dev_args args;
bool retaste;
g_trace(G_T_TOPOLOGY, "dev_taste(%s,%s)", mp->name, pp->name);
g_topology_assert();
/* Only one geom_dev per provider. */
LIST_FOREACH(cp, &pp->consumers, consumers) {
if (cp->geom->class != mp || (cp->flags & G_CF_SPOILED))
continue;
gp = cp->geom;
sc = cp->private;
dev = sc->sc_dev;
retaste = true;
goto aliases;
}
gp = g_new_geomf(mp, "%s", pp->name);
sc = g_malloc(sizeof(*sc), M_WAITOK | M_ZERO);
mtx_init(&sc->sc_mtx, "g_dev", NULL, MTX_DEF);
@ -380,6 +391,8 @@ g_dev_taste(struct g_class *mp, struct g_provider *pp, int insist __unused)
g_dev_attrchanged(cp, "GEOM::physpath");
snprintf(buf, sizeof(buf), "cdev=%s", gp->name);
devctl_notify_f("GEOM", "DEV", "CREATE", buf, M_WAITOK);
retaste = false;
aliases:
/*
* Now add all the aliases for this drive
*/
@ -387,8 +400,16 @@ g_dev_taste(struct g_class *mp, struct g_provider *pp, int insist __unused)
error = make_dev_alias_p(MAKEDEV_CHECKNAME | MAKEDEV_WAITOK, &adev, dev,
"%s", gap->ga_alias);
if (error) {
printf("%s: make_dev_alias_p() failed (name=%s, error=%d)\n",
__func__, gap->ga_alias, error);
/*
* With aliases added after initial taste, we don't
* know which aliases are new in this retaste, so we
* try to create all of them. EEXIST is expected and
* silently ignored or else this becomes really spammy.
*/
if (error != EEXIST || !retaste)
printf("%s: make_dev_alias_p() failed (name=%s,"
" error=%d)\n", __func__, gap->ga_alias,
error);
continue;
}
snprintf(buf, sizeof(buf), "cdev=%s", gap->ga_alias);

View File

@ -46,6 +46,7 @@ __FBSDID("$FreeBSD$");
#include <sys/sysctl.h>
#include <geom/geom.h>
#include <geom/geom_dbg.h>
#include <geom/geom_int.h>
#include <geom/geom_slice.h>
#include <geom/label/g_label.h>
@ -344,18 +345,16 @@ g_label_taste(struct g_class *mp, struct g_provider *pp, int flags __unused)
{
struct g_label_metadata md;
struct g_consumer *cp;
struct g_class *clsp;
struct g_geom *gp;
int i;
bool changed;
g_trace(G_T_TOPOLOGY, "%s(%s, %s)", __func__, mp->name, pp->name);
g_topology_assert();
G_LABEL_DEBUG(2, "Tasting %s.", pp->name);
/* Skip providers that are already open for writing. */
if (pp->acw > 0)
return (NULL);
if (strcmp(pp->geom->class->name, mp->name) == 0)
return (NULL);
@ -391,9 +390,16 @@ g_label_taste(struct g_class *mp, struct g_provider *pp, int flags __unused)
if (md.md_provsize != pp->mediasize)
break;
/* Skip providers that are already open for writing. */
if (pp->acw > 0) {
g_access(cp, -1, 0, 0);
goto end;
}
g_label_create(NULL, mp, pp, md.md_label, G_LABEL_DIR,
pp->mediasize - pp->sectorsize);
} while (0);
changed = false;
for (i = 0; g_labels[i] != NULL; i++) {
char label[128];
@ -405,8 +411,28 @@ g_label_taste(struct g_class *mp, struct g_provider *pp, int flags __unused)
g_topology_lock();
if (label[0] == '\0')
continue;
g_label_create(NULL, mp, pp, label, g_labels[i]->ld_dir,
pp->mediasize);
if (!g_label_is_name_ok(label)) {
G_LABEL_DEBUG(0,
"%s contains suspicious label, skipping.",
pp->name);
G_LABEL_DEBUG(1, "%s suspicious label is: %s",
pp->name, label);
continue;
}
g_provider_add_alias(pp, "%s/%s", g_labels[i]->ld_dir, label);
changed = true;
}
/*
* Force devfs interface to retaste the provider, to catch the new
* alias(es).
*/
if (changed) {
LIST_FOREACH(clsp, &g_classes, class) {
if (strcmp(clsp->name, "DEV") != 0)
continue;
clsp->taste(clsp, pp, 0);
break;
}
}
g_access(cp, -1, 0, 0);
end: