Index: sys/geom/geom_dev.c =================================================================== --- sys/geom/geom_dev.c +++ sys/geom/geom_dev.c @@ -336,9 +336,20 @@ 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_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 @@ 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); Index: sys/geom/geom_subr.c =================================================================== --- sys/geom/geom_subr.c +++ sys/geom/geom_subr.c @@ -652,6 +652,15 @@ sbuf_vprintf(sb, fmt, ap); va_end(ap); sbuf_finish(sb); + + LIST_FOREACH(gap, &pp->aliases, ga_next) { + if (strcmp(gap->ga_alias, sbuf_data(sb)) != 0) + continue; + /* Don't re-add the same alias. */ + sbuf_delete(sb); + return; + } + gap = g_malloc(sizeof(*gap) + sbuf_len(sb) + 1, M_WAITOK | M_ZERO); memcpy((char *)(gap + 1), sbuf_data(sb), sbuf_len(sb)); sbuf_delete(sb); Index: sys/geom/label/g_label.c =================================================================== --- sys/geom/label/g_label.c +++ sys/geom/label/g_label.c @@ -46,6 +46,7 @@ #include #include #include +#include #include #include @@ -344,18 +345,16 @@ { 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 @@ 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_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: