Index: head/sys/conf/files =================================================================== --- head/sys/conf/files (revision 221113) +++ head/sys/conf/files (working copy) @@ -2138,7 +2138,6 @@ geom/label/g_label_msdosfs.c optional geom_label geom/label/g_label_ntfs.c optional geom_label geom/label/g_label_reiserfs.c optional geom_label geom/label/g_label_ufs.c optional geom_label -geom/label/g_label_gpt.c optional geom_label geom/linux_lvm/g_linux_lvm.c optional geom_linux_lvm geom/mirror/g_mirror.c optional geom_mirror geom/mirror/g_mirror_ctl.c optional geom_mirror Index: head/sys/modules/geom/geom_label/Makefile =================================================================== --- head/sys/modules/geom/geom_label/Makefile (revision 221113) +++ head/sys/modules/geom/geom_label/Makefile (working copy) @@ -5,7 +5,6 @@ KMOD= geom_label SRCS= g_label.c SRCS+= g_label_ext2fs.c -SRCS+= g_label_gpt.c SRCS+= g_label_iso9660.c SRCS+= g_label_msdosfs.c SRCS+= g_label_ntfs.c Index: head/sys/geom/label/g_label.c =================================================================== --- head/sys/geom/label/g_label.c (revision 221113) +++ head/sys/geom/label/g_label.c (working copy) @@ -85,8 +85,6 @@ const struct g_label_desc *g_labels[] = { &g_label_ext2fs, &g_label_reiserfs, &g_label_ntfs, - &g_label_gpt, - &g_label_gpt_uuid, NULL }; Index: head/sys/geom/label/g_label.h =================================================================== --- head/sys/geom/label/g_label.h (revision 221113) +++ head/sys/geom/label/g_label.h (working copy) @@ -85,8 +85,6 @@ extern struct g_label_desc g_label_msdosfs; extern struct g_label_desc g_label_ext2fs; extern struct g_label_desc g_label_reiserfs; extern struct g_label_desc g_label_ntfs; -extern struct g_label_desc g_label_gpt; -extern struct g_label_desc g_label_gpt_uuid; #endif /* _KERNEL */ struct g_label_metadata { Index: head/sys/geom/part/g_part_pc98.c =================================================================== --- head/sys/geom/part/g_part_pc98.c (revision 221113) +++ head/sys/geom/part/g_part_pc98.c (working copy) @@ -48,6 +48,9 @@ __FBSDID("$FreeBSD$"); FEATURE(geom_part_pc98, "GEOM partitioning class for PC-9800 disk partitions"); +static int pc98_volume_enable = 1; +TUNABLE_INT("kern.geom.part_label.pc98.enable", &pc98_volume_enable); + #define SECSIZE 512 #define MENUSIZE 7168 #define BOOTSIZE 8192 @@ -85,6 +88,7 @@ static const char *g_part_pc98_type(struct g_part_ static int g_part_pc98_write(struct g_part_table *, struct g_consumer *); static int g_part_pc98_resize(struct g_part_table *, struct g_part_entry *, struct g_part_parms *); +static void g_part_pc98_labels(struct g_part_table *, struct g_part_entry *); static kobj_method_t g_part_pc98_methods[] = { KOBJMETHOD(g_part_add, g_part_pc98_add), @@ -93,6 +97,7 @@ static kobj_method_t g_part_pc98_methods[] = { KOBJMETHOD(g_part_destroy, g_part_pc98_destroy), KOBJMETHOD(g_part_dumpconf, g_part_pc98_dumpconf), KOBJMETHOD(g_part_dumpto, g_part_pc98_dumpto), + KOBJMETHOD(g_part_labels, g_part_pc98_labels), KOBJMETHOD(g_part_modify, g_part_pc98_modify), KOBJMETHOD(g_part_resize, g_part_pc98_resize), KOBJMETHOD(g_part_name, g_part_pc98_name), @@ -606,3 +611,26 @@ g_part_pc98_write(struct g_part_table *basetable, error = g_write_data(cp, SECSIZE*2, table->menu, MENUSIZE); return (error); } + +#define G_PART_PC98_VOLUME_DIR "pc98" + +static void +g_part_pc98_labels(struct g_part_table *basetable, + struct g_part_entry *baseentry) +{ + struct g_part_pc98_entry *entry; + char name[sizeof(entry->ent.dp_name) + 1]; + struct sbuf *sb; + + entry = (struct g_part_pc98_entry *)baseentry; + if (entry->ent.dp_name[0] == '\0' || pc98_volume_enable == 0) + return; + sb = sbuf_new_auto(); + strncpy(name, entry->ent.dp_name, sizeof(name) - 1); + name[sizeof(name) - 1] = '\0'; + sbuf_printf(sb, "%s/%s", G_PART_PC98_VOLUME_DIR, name); + sbuf_finish(sb); + g_part_label_create(baseentry, sb); + sbuf_delete(sb); +} + Index: head/sys/geom/part/g_part.h =================================================================== --- head/sys/geom/part/g_part.h (revision 221113) +++ head/sys/geom/part/g_part.h (working copy) @@ -140,6 +140,7 @@ struct g_part_table { struct g_part_entry *g_part_new_entry(struct g_part_table *, int, quad_t, quad_t); +void g_part_label_create(struct g_part_entry *, struct sbuf *); enum g_part_ctl { G_PART_CTL_NONE, Index: head/sys/geom/part/g_part_if.m =================================================================== --- head/sys/geom/part/g_part_if.m (revision 221113) +++ head/sys/geom/part/g_part_if.m (working copy) @@ -71,6 +71,13 @@ CODE { { return (ENOSYS); } + + static void + default_labels(struct g_part_table *t __unused, + struct g_part_entry *e __unused) + { + + } }; # add() - scheme specific processing for the add verb. @@ -120,6 +127,12 @@ METHOD void fullname { const char *pfx; } DEFAULT default_fullname; +# labels() - create scheme specific parition labels. +METHOD void labels { + struct g_part_table *table; + struct g_part_entry *entry; +} DEFAULT default_labels; + # modify() - scheme specific processing for the modify verb. METHOD int modify { struct g_part_table *table; Index: head/sys/geom/part/g_part_gpt.c =================================================================== --- head/sys/geom/part/g_part_gpt.c (revision 221113) +++ head/sys/geom/part/g_part_gpt.c (working copy) @@ -50,6 +50,13 @@ __FBSDID("$FreeBSD$"); FEATURE(geom_part_gpt, "GEOM partitioning class for GPT partitions support"); +static int gpt_id_enable = 1; +static int gpt_volume_enable = 1; +TUNABLE_INT("kern.geom.label.gpt.enable", &gpt_volume_enable); +TUNABLE_INT("kern.geom.label.gptid.enable", &gpt_id_enable); +TUNABLE_INT("kern.geom.part_label.gpt.enable", &gpt_volume_enable); +TUNABLE_INT("kern.geom.part_label.gptid.enable", &gpt_id_enable); + CTASSERT(offsetof(struct gpt_hdr, padding) == 92); CTASSERT(sizeof(struct gpt_ent) == 128); @@ -111,6 +118,7 @@ static int g_part_gpt_write(struct g_part_table *, static int g_part_gpt_resize(struct g_part_table *, struct g_part_entry *, struct g_part_parms *); static int g_part_gpt_recover(struct g_part_table *); +static void g_part_gpt_labels(struct g_part_table *, struct g_part_entry *); static kobj_method_t g_part_gpt_methods[] = { KOBJMETHOD(g_part_add, g_part_gpt_add), @@ -119,6 +127,7 @@ static kobj_method_t g_part_gpt_methods[] = { KOBJMETHOD(g_part_destroy, g_part_gpt_destroy), KOBJMETHOD(g_part_dumpconf, g_part_gpt_dumpconf), KOBJMETHOD(g_part_dumpto, g_part_gpt_dumpto), + KOBJMETHOD(g_part_labels, g_part_gpt_labels), KOBJMETHOD(g_part_modify, g_part_gpt_modify), KOBJMETHOD(g_part_resize, g_part_gpt_resize), KOBJMETHOD(g_part_name, g_part_gpt_name), @@ -1150,3 +1159,34 @@ g_gpt_utf8_to_utf16(const uint8_t *s8, uint16_t *s if (utfbytes != 0 && s16idx < s16len) s16[s16idx++] = htole16(0xfffd); } + +#define G_PART_GPT_VOLUME_DIR "gpt" +#define G_PART_GPT_ID_DIR "gptid" + +static void +g_part_gpt_labels(struct g_part_table *basetable, + struct g_part_entry *baseentry) +{ + struct g_part_gpt_entry *entry; + struct sbuf *sb; + + entry = (struct g_part_gpt_entry *)baseentry; + if (entry->ent.ent_name[0] != 0 && gpt_volume_enable != 0) { + sb = sbuf_new_auto(); + sbuf_printf(sb, "%s/", G_PART_GPT_VOLUME_DIR); + g_gpt_printf_utf16(sb, entry->ent.ent_name, + sizeof(entry->ent.ent_name) >> 1); + sbuf_finish(sb); + g_part_label_create(baseentry, sb); + sbuf_delete(sb); + } + if (gpt_id_enable != 0) { + sb = sbuf_new_auto(); + sbuf_printf(sb, "%s/", G_PART_GPT_ID_DIR); + sbuf_printf_uuid(sb, &entry->ent.ent_uuid); + sbuf_finish(sb); + g_part_label_create(baseentry, sb); + sbuf_delete(sb); + } +} + Index: head/sys/geom/part/g_part_apm.c =================================================================== --- head/sys/geom/part/g_part_apm.c (revision 221113) +++ head/sys/geom/part/g_part_apm.c (working copy) @@ -49,6 +49,9 @@ __FBSDID("$FreeBSD$"); FEATURE(geom_part_apm, "GEOM partitioning class for Apple-style partitions"); +static int apm_volume_enable = 1; +TUNABLE_INT("kern.geom.part_label.apm.enable", &apm_volume_enable); + struct g_part_apm_table { struct g_part_table base; struct apm_ddr ddr; @@ -79,6 +82,7 @@ static const char *g_part_apm_type(struct g_part_t static int g_part_apm_write(struct g_part_table *, struct g_consumer *); static int g_part_apm_resize(struct g_part_table *, struct g_part_entry *, struct g_part_parms *); +static void g_part_apm_labels(struct g_part_table *, struct g_part_entry *); static kobj_method_t g_part_apm_methods[] = { KOBJMETHOD(g_part_add, g_part_apm_add), @@ -86,6 +90,7 @@ static kobj_method_t g_part_apm_methods[] = { KOBJMETHOD(g_part_destroy, g_part_apm_destroy), KOBJMETHOD(g_part_dumpconf, g_part_apm_dumpconf), KOBJMETHOD(g_part_dumpto, g_part_apm_dumpto), + KOBJMETHOD(g_part_labels, g_part_apm_labels), KOBJMETHOD(g_part_modify, g_part_apm_modify), KOBJMETHOD(g_part_resize, g_part_apm_resize), KOBJMETHOD(g_part_name, g_part_apm_name), @@ -558,3 +563,26 @@ g_part_apm_write(struct g_part_table *basetable, s return (0); } + +#define G_PART_APM_VOLUME_DIR "apm" + +static void +g_part_apm_labels(struct g_part_table *basetable, + struct g_part_entry *baseentry) +{ + struct g_part_apm_entry *entry; + char name[APM_ENT_NAMELEN + 1]; + struct sbuf *sb; + + entry = (struct g_part_apm_entry *)baseentry; + if (entry->ent.ent_name[0] == '\0' || apm_volume_enable == 0) + return; + sb = sbuf_new_auto(); + strncpy(name, entry->ent.ent_name, APM_ENT_NAMELEN); + name[APM_ENT_NAMELEN] = '\0'; + sbuf_printf(sb, "%s/%s", G_PART_APM_VOLUME_DIR, name); + sbuf_finish(sb); + g_part_label_create(baseentry, sb); + sbuf_delete(sb); +} + Index: head/sys/geom/part/g_part.c =================================================================== --- head/sys/geom/part/g_part.c (revision 221113) +++ head/sys/geom/part/g_part.c (working copy) @@ -138,11 +138,29 @@ static struct g_class g_part_class = { DECLARE_GEOM_CLASS(g_part_class, g_part); +static g_ctl_destroy_geom_t g_part_label_destroy_geom; +static g_access_t g_part_label_access; +static g_orphan_t g_part_label_orphan; +static g_start_t g_part_label_start; + +static struct g_class g_part_label_class = { + .name = "PART::LABEL", + .version = G_VERSION, + /* Class methods. */ + .destroy_geom = g_part_label_destroy_geom, + /* Geom methods. */ + .access = g_part_label_access, + .orphan = g_part_label_orphan, + .start = g_part_label_start +}; + +DECLARE_GEOM_CLASS(g_part_label_class, g_part_label); /* * Support functions. */ static void g_part_wither(struct g_geom *, int); +static void g_part_spoil_labels(struct g_provider *); const char * g_part_alias_name(enum g_part_alias alias) @@ -297,6 +315,7 @@ g_part_new_provider(struct g_geom *gp, struct g_pa if (pp->stripesize > 0) entry->gpe_pp->stripeoffset %= pp->stripesize; g_error_provider(entry->gpe_pp, 0); + G_PART_LABELS(table, entry); } static struct g_geom* @@ -1047,6 +1066,10 @@ g_part_ctl_modify(struct gctl_req *req, struct g_p if (!entry->gpe_created) entry->gpe_modified = 1; + /* Update partition labels. */ + g_part_spoil_labels(entry->gpe_pp); + G_PART_LABELS(table, entry); + /* Provide feedback if so requested. */ if (gpp->gpp_parms & G_PART_PARM_OUTPUT) { sb = sbuf_new_auto(); @@ -2085,3 +2108,146 @@ g_part_modevent(module_t mod, int type, struct g_p return (error); } + +void +g_part_label_create(struct g_part_entry *entry, struct sbuf *sb) +{ + struct g_geom *gp, *tgp; + struct g_consumer *cp; + struct g_provider *pp; + const char *s; + int error; + + if (sbuf_len(sb) == 0) + return; + /* Check if the label starts from ../ */ + if (strncmp(sbuf_data(sb), "../", 3) == 0) + return; + /* Check if the label contains /../ */ + if (strstr(sbuf_data(sb), "/../") != NULL) + return; + /* Check if the label ends at ../ */ + if ((s = strstr(sbuf_data(sb), "/..")) != NULL && s[3] == '\0') + return; + + g_topology_assert(); + LIST_FOREACH(gp, &g_part_label_class.geom, geom) { + if (strcmp(entry->gpe_pp->name, gp->name) == 0) + break; + } + if (gp == NULL) { + gp = g_new_geomf(&g_part_label_class, entry->gpe_pp->name); + cp = g_new_consumer(gp); + error = g_attach(cp, entry->gpe_pp); + if (error != 0) { + g_wither_geom(gp, error); + return; + } + } +#if 0 + else { + LIST_FOREACH(pp, &gp->provider, provider) { + /* Do not create provider with existing name. + * But if this provider will be destroyed soon, + * then do not take it into account. + */ + if (strcmp(pp->name, sbuf_data(sb)) == 0 && + (pp->flags & G_PF_WITHER) == 0) + return; + } + } +#endif + /* XXX: To avoid error messages from GEOM_DEV do not create + * provider with existing name. + */ + LIST_FOREACH(tgp, &g_part_label_class.geom, geom) { + LIST_FOREACH(pp, &tgp->provider, provider) { + if (strcmp(pp->name, sbuf_data(sb)) == 0 && + (pp->flags & G_PF_WITHER) == 0) + return; + } + } + pp = g_new_providerf(gp, sbuf_data(sb)); + pp->mediasize = entry->gpe_pp->mediasize; + pp->sectorsize = entry->gpe_pp->sectorsize; + pp->stripesize = entry->gpe_pp->stripesize; + pp->stripeoffset = entry->gpe_pp->stripeoffset; + pp->flags = entry->gpe_pp->flags & G_PF_CANDELETE; + g_error_provider(pp, 0); +} + +static void +g_part_spoil_labels(struct g_provider *pp) +{ + struct g_consumer *cp; + + g_topology_assert(); + LIST_FOREACH(cp, &pp->consumers, consumers) { + if (cp->geom->class == &g_part_label_class) + break; + } + if (cp == NULL) + return; + LIST_FOREACH(pp, &cp->geom->provider, provider) { + if (pp->acr == 0 && pp->acw == 0 && pp->ace == 0) + g_wither_provider(pp, ENXIO); + else + pp->index = 1; /* mark provider as stale. */ + } +} + +static int +g_part_label_destroy_geom(struct gctl_req *req, struct g_class *mp, + struct g_geom *gp) +{ + + G_PART_TRACE((G_T_TOPOLOGY, "%s(%s,%s)", __func__, mp->name, gp->name)); + g_topology_assert(); + g_wither_geom(gp, ENXIO); + return (0); +} + +static int +g_part_label_access(struct g_provider *pp, int dr, int dw, int de) +{ + struct g_consumer *cp; + int error; + + G_PART_TRACE((G_T_ACCESS, "%s(%s,%d,%d,%d)", __func__, pp->name, dr, + dw, de)); + cp = LIST_FIRST(&pp->geom->consumer); + error = g_access(cp, dr, dw, de); + + /* Destroy stale provider. */ + if (error == 0 && pp->acr == 0 && pp->acw == 0 && pp->ace == 0 && + pp->index == 1) + g_wither_provider(pp, ENXIO); + + return (error); +} + +static void +g_part_label_orphan(struct g_consumer *cp) +{ + + G_PART_TRACE((G_T_TOPOLOGY, "%s(%s)", __func__, cp->provider->name)); + g_topology_assert(); + g_wither_geom(cp->geom, cp->provider->error); +} + +static void +g_part_label_start(struct bio *bp) +{ + struct bio *bp2; + struct g_consumer *cp; + + bp2 = g_clone_bio(bp); + if (bp2 == NULL) { + g_io_deliver(bp, ENOMEM); + return; + } + cp = LIST_FIRST(&bp->bio_to->geom->consumer); + bp2->bio_done = g_std_done; + g_io_request(bp2, cp); +} +