Index: share/man/man9/disk.9 =================================================================== --- share/man/man9/disk.9 +++ share/man/man9/disk.9 @@ -27,7 +27,7 @@ .\" .\" $FreeBSD$ .\" -.Dd October 30, 2012 +.Dd August 3, 2017 .Dt DISK 9 .Os .Sh NAME @@ -45,6 +45,8 @@ .Fn disk_destroy "struct disk *disk" .Ft int .Fn disk_resize "struct disk *disk" "int flags" +.Ft void +.Fn disk_add_alias "struct disk *disk" "const char *alias" .Sh DESCRIPTION The disk storage API permits kernel device drivers providing access to disk-like storage devices to advertise the device to other kernel @@ -69,6 +71,20 @@ fill in the fields and call .Fn disk_create when the device is ready to service requests. +.Fn disk_add_alias +adds an alias for the disk and must be called before +.Fn disk_create , +but may be called multiple times. +For each alias added, a device node will be created with +.Xr make_dev_alias 9 +in the same way primary device nodes are created with +.Xr make_dev 9 +for +.Va d_name +and +.Va d_unit . +Care should be taken to ensure that only one driver creates aliases +for any given name. .Fn disk_resize can be called by the driver after modifying .Va d_mediasize @@ -227,7 +243,13 @@ .El .Sh SEE ALSO .Xr GEOM 4 , -.Xr devfs 5 +.Xr devfs 5 , +.Xr MAKE_DEV 9 .Sh AUTHORS This manual page was written by .An Robert Watson . +.Sh BUGS +Disk aliases are not a general purpose aliasing mechanism, but are +intended only to ease the transition from one name to another. +They can be used to ensure that nvd0 and nda0 are the same thing. +They cannot be used to implement diskX concept from macOS. Index: sys/cam/nvme/nvme_da.c =================================================================== --- sys/cam/nvme/nvme_da.c +++ sys/cam/nvme/nvme_da.c @@ -808,6 +808,7 @@ DEVSTAT_ALL_SUPPORTED, DEVSTAT_TYPE_DIRECT | XPORT_DEVSTAT_TYPE(cpi.transport), DEVSTAT_PRIORITY_DISK); + disk_add_alias(disk, "nvd"); /* * Acquire a reference to the periph before we register with GEOM. Index: sys/geom/geom.h =================================================================== --- sys/geom/geom.h +++ sys/geom/geom.h @@ -120,6 +120,15 @@ LIST_HEAD(,g_geom) geom; }; +/* + * The g_geom_alias is a list node for aliases for the geom name + * for device node creation. + */ +struct g_geom_alias { + LIST_ENTRY(g_geom_alias) ga_next; + const char *ga_alias; +}; + #define G_VERSION_00 0x19950323 #define G_VERSION_01 0x20041207 /* add fflag to g_ioctl_t */ #define G_VERSION G_VERSION_01 @@ -150,6 +159,7 @@ unsigned flags; #define G_GEOM_WITHER 1 #define G_GEOM_VOLATILE_BIO 2 + LIST_HEAD(,g_geom_alias) aliases; }; /* @@ -269,6 +279,7 @@ void g_detach(struct g_consumer *cp); void g_error_provider(struct g_provider *pp, int error); struct g_provider *g_provider_by_name(char const *arg); +void g_geom_add_alias(struct g_geom *gp, const char *alias); int g_getattr__(const char *attr, struct g_consumer *cp, void *var, int len); #define g_getattr(a, c, v) g_getattr__((a), (c), (v), sizeof *(v)) int g_handleattr(struct bio *bp, const char *attribute, const void *val, Index: sys/geom/geom_dev.c =================================================================== --- sys/geom/geom_dev.c +++ sys/geom/geom_dev.c @@ -315,10 +315,11 @@ g_dev_taste(struct g_class *mp, struct g_provider *pp, int insist __unused) { struct g_geom *gp; + struct g_geom_alias *gap; struct g_consumer *cp; struct g_dev_softc *sc; int error; - struct cdev *dev; + struct cdev *dev, *adev; char buf[SPECNAMELEN + 6]; g_trace(G_T_TOPOLOGY, "dev_taste(%s,%s)", mp->name, pp->name); @@ -357,6 +358,23 @@ g_dev_attrchanged(cp, "GEOM::physpath"); snprintf(buf, sizeof(buf), "cdev=%s", gp->name); devctl_notify_f("GEOM", "DEV", "CREATE", buf, M_WAITOK); + /* + * Now add all the aliases for this drive + */ + LIST_FOREACH(gap, &pp->geom->aliases, ga_next) { + 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); + continue; + } + adev->si_flags |= SI_UNMAPPED; + adev->si_iosize_max = dev->si_iosize_max; + adev->si_drv2 = dev->si_drv2; + snprintf(buf, sizeof(buf), "cdev=%s", gap->ga_alias); + devctl_notify_f("GEOM", "DEV", "CREATE", buf, M_WAITOK); + } return (gp); } Index: sys/geom/geom_disk.h =================================================================== --- sys/geom/geom_disk.h +++ sys/geom/geom_disk.h @@ -66,6 +66,11 @@ DISK_INIT_DONE } disk_init_level; +struct disk_alias { + LIST_ENTRY(disk_alias) da_next; + const char *da_alias; +}; + struct disk { /* Fields which are private to geom_disk */ struct g_geom *d_geom; @@ -109,6 +114,9 @@ /* Fields private to the driver */ void *d_drv1; + + /* Fields private to geom_disk, to be moved on next version bump */ + LIST_HEAD(,disk_alias) d_aliases; }; #define DISKFLAG_RESERVED 0x1 /* Was NEEDSGIANT */ @@ -132,6 +140,7 @@ void disk_media_changed(struct disk *dp, int flag); void disk_media_gone(struct disk *dp, int flag); int disk_resize(struct disk *dp, int flag); +void disk_add_alias(struct disk *disk, const char *); #define DISK_VERSION_00 0x58561059 #define DISK_VERSION_01 0x5856105a Index: sys/geom/geom_disk.c =================================================================== --- sys/geom/geom_disk.c +++ sys/geom/geom_disk.c @@ -676,6 +676,7 @@ struct g_provider *pp; struct disk *dp; struct g_disk_softc *sc; + struct disk_alias *dap; char tmpstr[80]; if (flag == EV_CANCEL) @@ -704,6 +705,10 @@ sc->dp = dp; gp = g_new_geomf(&g_disk_class, "%s%d", dp->d_name, dp->d_unit); gp->softc = sc; + LIST_FOREACH(dap, &dp->d_aliases, da_next) { + snprintf(tmpstr, sizeof(tmpstr), "%s%d", dap->da_alias, dp->d_unit); + g_geom_add_alias(gp, tmpstr); + } pp = g_new_providerf(gp, "%s", gp->name); devstat_remove_entry(pp->stat); pp->stat = NULL; @@ -791,6 +796,7 @@ struct disk *dp; struct g_geom *gp; struct g_disk_softc *sc; + struct disk_alias *dap, *daptmp; g_topology_assert(); dp = ptr; @@ -802,6 +808,8 @@ dp->d_geom = NULL; g_wither_geom(gp, ENXIO); } + LIST_FOREACH_SAFE(dap, &dp->d_aliases, da_next, daptmp) + g_free(dap); g_free(dp); } @@ -834,8 +842,11 @@ struct disk * disk_alloc(void) { + struct disk *dp; - return (g_malloc(sizeof(struct disk), M_WAITOK | M_ZERO)); + dp = g_malloc(sizeof(struct disk), M_WAITOK | M_ZERO); + LIST_INIT(&dp->d_aliases); + return (dp); } void @@ -885,6 +896,18 @@ } void +disk_add_alias(struct disk *dp, const char *name) +{ + struct disk_alias *dap; + + dap = (struct disk_alias *)g_malloc( + sizeof(struct disk_alias) + strlen(name) + 1, M_WAITOK); + strcpy((char *)(dap + 1), name); + dap->da_alias = (const char *)(dap + 1); + LIST_INSERT_HEAD(&dp->d_aliases, dap, da_next); +} + +void disk_gone(struct disk *dp) { struct g_geom *gp; Index: sys/geom/geom_dump.c =================================================================== --- sys/geom/geom_dump.c +++ sys/geom/geom_dump.c @@ -234,6 +234,7 @@ { struct g_consumer *cp2; struct g_provider *pp2; + struct g_geom_alias *gap; sbuf_printf(sb, " \n", gp); sbuf_printf(sb, " \n", gp->class); @@ -259,6 +260,11 @@ continue; g_conf_provider(sb, pp2); } + LIST_FOREACH(gap, &gp->aliases, ga_next) { + sbuf_printf(sb, " \n"); + g_conf_printf_escaped(sb, "%s", gap->ga_alias); + sbuf_printf(sb, " \n"); + } sbuf_printf(sb, " \n"); } Index: sys/geom/geom_subr.c =================================================================== --- sys/geom/geom_subr.c +++ sys/geom/geom_subr.c @@ -347,6 +347,7 @@ gp->rank = 1; LIST_INIT(&gp->consumer); LIST_INIT(&gp->provider); + LIST_INIT(&gp->aliases); LIST_INSERT_HEAD(&mp->geom, gp, geom); TAILQ_INSERT_HEAD(&geoms, gp, geoms); strcpy(gp->name, sbuf_data(sb)); @@ -367,6 +368,7 @@ void g_destroy_geom(struct g_geom *gp) { + struct g_geom_alias *gap, *gaptmp; g_topology_assert(); G_VALID_GEOM(gp); @@ -380,6 +382,8 @@ g_cancel_event(gp); LIST_REMOVE(gp, geom); TAILQ_REMOVE(&geoms, gp, geoms); + LIST_FOREACH_SAFE(gap, &gp->aliases, ga_next, gaptmp) + g_free(gap); g_free(gp->name); g_free(gp); } @@ -1212,6 +1216,18 @@ return (0); } +void +g_geom_add_alias(struct g_geom *gp, const char *alias) +{ + struct g_geom_alias *gap; + + gap = (struct g_geom_alias *)g_malloc( + sizeof(struct g_geom_alias) + strlen(alias) + 1, M_WAITOK); + strcpy((char *)(gap + 1), alias); + gap->ga_alias = (const char *)(gap + 1); + LIST_INSERT_HEAD(&gp->aliases, gap, ga_next); +} + #if defined(DIAGNOSTIC) || defined(DDB) /* * This function walks the mesh and returns a non-zero integer if it Index: sys/geom/part/g_part.c =================================================================== --- sys/geom/part/g_part.c +++ sys/geom/part/g_part.c @@ -429,6 +429,7 @@ struct g_consumer *cp; struct g_provider *pp; struct sbuf *sb; + struct g_geom_alias *gap; off_t offset; cp = LIST_FIRST(&gp->consumer); @@ -439,6 +440,19 @@ entry->gpe_offset = offset; if (entry->gpe_pp == NULL) { + /* + * Add aliases to the geom before we create the provider so that + * geom_dev can taste it with all the aliases in place so all + * the aliased dev_t instances get created for each partition + * (eg foo5p7 gets cerated for bar5p7 when foo is an alias of bar). + */ + LIST_FOREACH(gap, &table->gpt_gp->aliases, ga_next) { + sb = sbuf_new_auto(); + G_PART_FULLNAME(table, entry, sb, gap->ga_alias); + sbuf_finish(sb); + g_geom_add_alias(gp, sbuf_data(sb)); + sbuf_delete(sb); + } sb = sbuf_new_auto(); G_PART_FULLNAME(table, entry, sb, gp->name); sbuf_finish(sb); @@ -1901,6 +1915,7 @@ struct g_part_entry *entry; struct g_part_table *table; struct root_hold_token *rht; + struct g_geom_alias *gap; int attr, depth; int error; @@ -1913,10 +1928,12 @@ /* * Create a GEOM with consumer and hook it up to the provider. - * With that we become part of the topology. Optain read access + * With that we become part of the topology. Obtain read access * to the provider. */ gp = g_new_geomf(mp, "%s", pp->name); + LIST_FOREACH(gap, &pp->geom->aliases, ga_next) + g_geom_add_alias(gp, gap->ga_alias); cp = g_new_consumer(gp); cp->flags |= G_CF_DIRECT_SEND | G_CF_DIRECT_RECEIVE; error = g_attach(cp, pp);