Index: sbin/geom/class/part/gpart.8 =================================================================== --- gpart.8 (revision 205576) +++ gpart.8 (working copy) @@ -106,6 +106,18 @@ .Op Fl t Ar type .Op Fl f Ar flags .Ar geom +.\" ==== RECOVER ==== +.Nm +.Cm recover +.Op Fl f Ar flags +.Ar geom +.\" ==== RESIZE ==== +.Nm +.Cm resize +.Fl i Ar index +.Op Fl s Ar size +.Op Fl f Ar flags +.Ar geom .\" ==== SET ==== .Nm .Cm set @@ -297,6 +309,45 @@ See the section entitled "Operational flags" below for a discussion about its use. .El +.\" ==== RECOVER ==== +.It Cm recover +Recover a corrupted metadata on geom +.Ar geom . +Currently recovering implemented only for GPT scheme. +.Pp +Additional options include: +.Bl -tag -width 10n +.It Fl f Ar flags +Additional operational flags. +See the section entitled +.Sx "OPERATIONAL FLAGS" +below for a discussion +about its use. +.El +.\" ==== RESIZE ==== +.It Cm resize +Resize a partition from geom +.Ar geom +and further identified by the +.Fl i Ar index +option. New partition size is expressed in logical block +numbers and can be given by the +.Fl s Ar size +option. If +.Fl s +option is ommited then new size is automatically calculated +to maximum available from given geom +.Ar geom . +.Pp +Additional options include: +.Bl -tag -width 10n +.It Fl f Ar flags +Additional operational flags. +See the section entitled +.Sx "OPERATIONAL FLAGS" +below for a discussion +about its use. +.El .\" ==== SET ==== .It Cm set Set the named attribute on the partition entry. Index: sbin/geom/class/part/geom_part.c =================================================================== --- geom_part.c (revision 205576) +++ geom_part.c (working copy) @@ -112,6 +112,18 @@ G_OPT_SENTINEL }, "geom", NULL }, + { "recover", 0, gpart_issue, { + { 'f', "flags", flags, G_TYPE_STRING }, + G_OPT_SENTINEL }, + "geom", NULL + }, + { "resize", 0, gpart_issue, { + { 's', "size", autofill, G_TYPE_ASCLBA }, + { 'i', index_param, NULL, G_TYPE_ASCNUM }, + { 'f', "flags", flags, G_TYPE_STRING }, + G_OPT_SENTINEL }, + "geom", NULL + }, { "set", 0, gpart_issue, { { 'a', "attrib", NULL, G_TYPE_STRING }, { 'i', index_param, NULL, G_TYPE_ASCNUM }, @@ -242,6 +254,99 @@ } static int +gpart_autofill_resize(struct gctl_req *req) +{ + struct gmesh mesh; + struct gclass *cp; + struct ggeom *gp; + struct gprovider *pp; + unsigned long long last, size, start, new_size; + unsigned long long lba, new_lba; + const char *s; + char *val; + int error, idx; + + s = gctl_get_ascii(req, "size"); + if (*s == '*') + new_size = (unsigned long long)atoll(s); + else + return (0); + + s = gctl_get_ascii(req, index_param); + idx = strtol(s, &val, 10); + if (idx < 1 || *s == '\0' || *val != '\0') + errx(EXIT_FAILURE, "invalid partition index"); + + error = geom_gettree(&mesh); + if (error) + return (error); + s = gctl_get_ascii(req, "class"); + if (s == NULL) + abort(); + cp = find_class(&mesh, s); + if (cp == NULL) + errx(EXIT_FAILURE, "Class %s not found.", s); + s = gctl_get_ascii(req, "geom"); + if (s == NULL) + abort(); + gp = find_geom(cp, s); + if (gp == NULL) + errx(EXIT_FAILURE, "No such geom: %s.", s); + last = atoll(find_geomcfg(gp, "last")); + + LIST_FOREACH(pp, &gp->lg_provider, lg_provider) { + s = find_provcfg(pp, "index"); + if (s == NULL) + continue; + if (atoi(s) == idx) + break; + } + if (pp == NULL) + errx(EXIT_FAILURE, "invalid partition index"); + + s = find_provcfg(pp, "start"); + if (s == NULL) { + s = find_provcfg(pp, "offset"); + start = atoll(s) / pp->lg_sectorsize; + } else + start = atoll(s); + s = find_provcfg(pp, "end"); + if (s == NULL) { + s = find_provcfg(pp, "length"); + lba = start + atoll(s) / pp->lg_sectorsize; + } else + lba = atoll(s) + 1; + + if (lba > last) + return (ENOSPC); + size = lba - start; + pp = find_provider(gp, lba); + if (pp == NULL) + new_size = last - start + 1; + else { + s = find_provcfg(pp, "start"); + if (s == NULL) { + s = find_provcfg(pp, "offset"); + new_lba = atoll(s) / pp->lg_sectorsize; + } else + new_lba = atoll(s); + /* Is there any free space between current and + * next providers? + */ + if (new_lba > lba) + new_size = new_lba - start; + else + return (ENOSPC); + } + asprintf(&val, "%llu", new_size); + if (val == NULL) + return (ENOMEM); + gctl_change_param(req, "size", -1, val); + + return (0); +} + +static int gpart_autofill(struct gctl_req *req) { struct gmesh mesh; @@ -256,6 +361,8 @@ int error, has_size, has_start; s = gctl_get_ascii(req, "verb"); + if (strcmp(s, "resize") == 0) + return gpart_autofill_resize(req); if (strcmp(s, "add") != 0) return (0); Index: sys/geom/part/g_part_pc98.c =================================================================== --- g_part_pc98.c (revision 204945) +++ g_part_pc98.c (working copy) @@ -77,6 +77,8 @@ static const char *g_part_pc98_type(struct g_part_table *, struct g_part_entry *, char *, size_t); 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 kobj_method_t g_part_pc98_methods[] = { KOBJMETHOD(g_part_add, g_part_pc98_add), @@ -86,6 +88,7 @@ KOBJMETHOD(g_part_dumpconf, g_part_pc98_dumpconf), KOBJMETHOD(g_part_dumpto, g_part_pc98_dumpto), KOBJMETHOD(g_part_modify, g_part_pc98_modify), + KOBJMETHOD(g_part_resize, g_part_pc98_resize), KOBJMETHOD(g_part_name, g_part_pc98_name), KOBJMETHOD(g_part_probe, g_part_pc98_probe), KOBJMETHOD(g_part_read, g_part_pc98_read), @@ -308,6 +311,31 @@ return (0); } +static int +g_part_pc98_resize(struct g_part_table *basetable, + struct g_part_entry *baseentry, struct g_part_parms *gpp) +{ + struct g_part_pc98_entry *entry; + uint32_t size, cyl; + + cyl = basetable->gpt_heads * basetable->gpt_sectors; + size = gpp->gpp_size; + + if (size < cyl) + return (EINVAL); + if (size % cyl) + size = size - (size % cyl); + if (size < cyl) + return (EINVAL); + + entry = (struct g_part_pc98_entry *)baseentry; + baseentry->gpe_end = baseentry->gpe_start + size - 1; + pc98_set_chs(basetable, baseentry->gpe_end, &entry->ent.dp_ecyl, + &entry->ent.dp_ehd, &entry->ent.dp_esect); + + return (0); +} + static const char * g_part_pc98_name(struct g_part_table *table, struct g_part_entry *baseentry, char *buf, size_t bufsz) Index: sys/geom/part/g_part_vtoc8.c =================================================================== --- g_part_vtoc8.c (revision 204945) +++ g_part_vtoc8.c (working copy) @@ -67,6 +67,8 @@ static const char *g_part_vtoc8_type(struct g_part_table *, struct g_part_entry *, char *, size_t); static int g_part_vtoc8_write(struct g_part_table *, struct g_consumer *); +static int g_part_vtoc8_resize(struct g_part_table *, struct g_part_entry *, + struct g_part_parms *); static kobj_method_t g_part_vtoc8_methods[] = { KOBJMETHOD(g_part_add, g_part_vtoc8_add), @@ -75,6 +77,7 @@ KOBJMETHOD(g_part_dumpconf, g_part_vtoc8_dumpconf), KOBJMETHOD(g_part_dumpto, g_part_vtoc8_dumpto), KOBJMETHOD(g_part_modify, g_part_vtoc8_modify), + KOBJMETHOD(g_part_resize, g_part_vtoc8_resize), KOBJMETHOD(g_part_name, g_part_vtoc8_name), KOBJMETHOD(g_part_probe, g_part_vtoc8_probe), KOBJMETHOD(g_part_read, g_part_vtoc8_read), @@ -296,6 +299,26 @@ return (0); } +static int +g_part_vtoc8_resize(struct g_part_table *basetable, + struct g_part_entry *entry, struct g_part_parms *gpp) +{ + struct g_part_vtoc8_table *table; + uint64_t size; + + table = (struct g_part_vtoc8_table *)basetable; + size = gpp->gpp_size; + if (size % table->secpercyl) + size = size - (size % table->secpercyl); + if (size < table->secpercyl) + return (EINVAL); + + entry->gpe_end = entry->gpe_start + size - 1; + be32enc(&table->vtoc.map[entry->gpe_index - 1].nblks, size); + + return (0); +} + static const char * g_part_vtoc8_name(struct g_part_table *table, struct g_part_entry *baseentry, char *buf, size_t bufsz) Index: sys/geom/part/g_part_bsd.c =================================================================== --- g_part_bsd.c (revision 204945) +++ g_part_bsd.c (working copy) @@ -73,6 +73,8 @@ static const char *g_part_bsd_type(struct g_part_table *, struct g_part_entry *, char *, size_t); static int g_part_bsd_write(struct g_part_table *, struct g_consumer *); +static int g_part_bsd_resize(struct g_part_table *, struct g_part_entry *, + struct g_part_parms *); static kobj_method_t g_part_bsd_methods[] = { KOBJMETHOD(g_part_add, g_part_bsd_add), @@ -82,6 +84,7 @@ KOBJMETHOD(g_part_dumpconf, g_part_bsd_dumpconf), KOBJMETHOD(g_part_dumpto, g_part_bsd_dumpto), KOBJMETHOD(g_part_modify, g_part_bsd_modify), + KOBJMETHOD(g_part_resize, g_part_bsd_resize), KOBJMETHOD(g_part_name, g_part_bsd_name), KOBJMETHOD(g_part_probe, g_part_bsd_probe), KOBJMETHOD(g_part_read, g_part_bsd_read), @@ -290,6 +293,19 @@ return (0); } +static int +g_part_bsd_resize(struct g_part_table *basetable, + struct g_part_entry *baseentry, struct g_part_parms *gpp) +{ + struct g_part_bsd_entry *entry; + + entry = (struct g_part_bsd_entry *)baseentry; + baseentry->gpe_end = baseentry->gpe_start + gpp->gpp_size - 1; + entry->part.p_size = gpp->gpp_size; + + return (0); +} + static const char * g_part_bsd_name(struct g_part_table *table, struct g_part_entry *baseentry, char *buf, size_t bufsz) Index: sys/geom/part/g_part_if.m =================================================================== --- g_part_if.m (revision 204945) +++ g_part_if.m (working copy) @@ -58,6 +58,20 @@ { return (0); } + + static int + default_recover(struct g_part_table *t __unused, + struct g_consumer *c __unused) + { + return (ENOSYS); + } + + static int + default_resize(struct g_part_table *t __unused, + struct g_part_entry *e __unused, struct g_part_parms *p __unused) + { + return (ENOSYS); + } }; # add() - scheme specific processing for the add verb. @@ -149,6 +163,19 @@ struct g_consumer *cp; }; +# recover() - scheme specific processing for the recover verb. +METHOD int recover { + struct g_part_table *table; + struct g_consumer *cp; +} DEFAULT default_recover; + +# resize() - scheme specific processing for the resize verb. +METHOD int resize { + struct g_part_table *table; + struct g_part_entry *entry; + struct g_part_parms *gpp; +} DEFAULT default_resize; + # setunset() - set or unset partition entry attributes. METHOD int setunset { struct g_part_table *table; Index: sys/geom/part/g_part_gpt.c =================================================================== --- g_part_gpt.c (revision 204945) +++ g_part_gpt.c (working copy) @@ -100,6 +100,9 @@ char *, size_t); static int g_part_gpt_probe(struct g_part_table *, struct g_consumer *); static int g_part_gpt_read(struct g_part_table *, struct g_consumer *); +static int g_part_gpt_recover(struct g_part_table *, struct g_consumer *); +static int g_part_gpt_resize(struct g_part_table *, struct g_part_entry *, + struct g_part_parms *); static const char *g_part_gpt_type(struct g_part_table *, struct g_part_entry *, char *, size_t); static int g_part_gpt_write(struct g_part_table *, struct g_consumer *); @@ -115,6 +118,8 @@ KOBJMETHOD(g_part_name, g_part_gpt_name), KOBJMETHOD(g_part_probe, g_part_gpt_probe), KOBJMETHOD(g_part_read, g_part_gpt_read), + KOBJMETHOD(g_part_recover, g_part_gpt_recover), + KOBJMETHOD(g_part_resize, g_part_gpt_resize), KOBJMETHOD(g_part_type, g_part_gpt_type), KOBJMETHOD(g_part_write, g_part_gpt_write), { 0, 0 } @@ -155,7 +160,14 @@ pp = cp->provider; last = (pp->mediasize / pp->sectorsize) - 1; - table->lba[elt] = (elt == GPT_ELT_PRIHDR) ? 1 : last; + if (elt == GPT_ELT_SECHDR) { + /* When the primary header is valid look for secondary + * header at AlternateLBA. Otherwise - at last medium's LBA. + */ + if (table->state[GPT_ELT_PRIHDR] != GPT_STATE_OK) + table->lba[elt] = last; + } else + table->lba[elt] = 1; table->state[elt] = GPT_STATE_MISSING; buf = g_read_data(cp, table->lba[elt] * pp->sectorsize, pp->sectorsize, &error); @@ -182,12 +194,15 @@ table->state[elt] = GPT_STATE_INVALID; hdr->hdr_revision = le32toh(buf->hdr_revision); - if (hdr->hdr_revision < 0x00010000) + if (hdr->hdr_revision < GPT_HDR_REVISION) goto fail; hdr->hdr_lba_self = le64toh(buf->hdr_lba_self); if (hdr->hdr_lba_self != table->lba[elt]) goto fail; hdr->hdr_lba_alt = le64toh(buf->hdr_lba_alt); + if (hdr->hdr_lba_alt == hdr->hdr_lba_self || + hdr->hdr_lba_alt > last) + goto fail; /* Check the managed area. */ hdr->hdr_lba_start = le64toh(buf->hdr_lba_start); @@ -221,6 +236,10 @@ le_uuid_dec(&buf->hdr_uuid, &hdr->hdr_uuid); hdr->hdr_crc_table = le32toh(buf->hdr_crc_table); + /* save LBA for secondary header */ + if (elt == GPT_ELT_PRIHDR) + table->lba[GPT_ELT_SECHDR] = hdr->hdr_lba_alt; + g_free(buf); return (hdr); @@ -528,6 +547,50 @@ return (0); } +static int +g_part_gpt_resize(struct g_part_table *basetable, + struct g_part_entry *baseentry, struct g_part_parms *gpp) +{ + struct g_part_gpt_entry *entry; + entry = (struct g_part_gpt_entry *)baseentry; + + baseentry->gpe_end = baseentry->gpe_start + gpp->gpp_size - 1; + entry->ent.ent_lba_end = baseentry->gpe_end; + + return (0); +} + +static int +g_part_gpt_recover(struct g_part_table *basetable, struct g_consumer *cp) +{ + struct g_part_gpt_table *table; + struct g_provider *pp; + size_t tblsz; + quad_t last; + + pp = cp->provider; + table = (struct g_part_gpt_table *)basetable; + last = (pp->mediasize / pp->sectorsize) - 1; + tblsz = (basetable->gpt_entries * sizeof(struct gpt_ent) + + pp->sectorsize - 1) / pp->sectorsize; + + table->lba[GPT_ELT_PRIHDR] = 1; + table->lba[GPT_ELT_PRITBL] = 2; + table->lba[GPT_ELT_SECHDR] = last; + table->lba[GPT_ELT_SECTBL] = last - tblsz; + table->state[GPT_ELT_PRIHDR] = GPT_STATE_OK; + table->state[GPT_ELT_PRITBL] = GPT_STATE_OK; + table->state[GPT_ELT_SECHDR] = GPT_STATE_OK; + table->state[GPT_ELT_SECTBL] = GPT_STATE_OK; + + table->hdr->hdr_lba_start = 2 + tblsz; + table->hdr->hdr_lba_end = last - tblsz - 1; + basetable->gpt_first = table->hdr->hdr_lba_start; + basetable->gpt_last = table->hdr->hdr_lba_end; + + return (0); +} + static const char * g_part_gpt_name(struct g_part_table *table, struct g_part_entry *baseentry, char *buf, size_t bufsz) @@ -608,10 +671,12 @@ struct g_part_gpt_table *table; struct g_part_gpt_entry *entry; u_char *buf; + quad_t last; int error, index; table = (struct g_part_gpt_table *)basetable; pp = cp->provider; + last = (pp->mediasize / pp->sectorsize) - 1; /* Read the PMBR */ buf = g_read_data(cp, 0, pp->sectorsize, &error); @@ -681,7 +746,8 @@ if (pritbl != NULL) g_free(pritbl); } else { - if (table->state[GPT_ELT_SECTBL] != GPT_STATE_OK) { + if (table->state[GPT_ELT_SECTBL] != GPT_STATE_OK || + table->lba[GPT_ELT_SECHDR] != last) { printf("GEOM: %s: the secondary GPT table is corrupt " "or invalid.\n", pp->name); printf("GEOM: %s: using the primary only -- recovery " Index: sys/geom/part/g_part_apm.c =================================================================== --- g_part_apm.c (revision 204945) +++ g_part_apm.c (working copy) @@ -74,6 +74,8 @@ static const char *g_part_apm_type(struct g_part_table *, struct g_part_entry *, char *, size_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 kobj_method_t g_part_apm_methods[] = { KOBJMETHOD(g_part_add, g_part_apm_add), @@ -82,6 +84,7 @@ KOBJMETHOD(g_part_dumpconf, g_part_apm_dumpconf), KOBJMETHOD(g_part_dumpto, g_part_apm_dumpto), KOBJMETHOD(g_part_modify, g_part_apm_modify), + KOBJMETHOD(g_part_resize, g_part_apm_resize), KOBJMETHOD(g_part_name, g_part_apm_name), KOBJMETHOD(g_part_probe, g_part_apm_probe), KOBJMETHOD(g_part_read, g_part_apm_read), @@ -318,6 +321,19 @@ return (0); } +static int +g_part_apm_resize(struct g_part_table *basetable, + struct g_part_entry *baseentry, struct g_part_parms *gpp) +{ + struct g_part_apm_entry *entry; + + entry = (struct g_part_apm_entry *)baseentry; + baseentry->gpe_end = baseentry->gpe_start + gpp->gpp_size - 1; + entry->ent.ent_size = gpp->gpp_size; + + return (0); +} + static const char * g_part_apm_name(struct g_part_table *table, struct g_part_entry *baseentry, char *buf, size_t bufsz) Index: sys/geom/part/g_part.c =================================================================== --- g_part.c (revision 204945) +++ g_part.c (working copy) @@ -939,22 +939,124 @@ { gctl_error(req, "%d verb 'move'", ENOSYS); return (ENOSYS); -} +} static int g_part_ctl_recover(struct gctl_req *req, struct g_part_parms *gpp) { - gctl_error(req, "%d verb 'recover'", ENOSYS); - return (ENOSYS); + struct g_geom *gp; + struct g_consumer *cp; + struct g_part_table *table; + struct sbuf *sb; + int error; + + gp = gpp->gpp_geom; + G_PART_TRACE((G_T_TOPOLOGY, "%s(%s)", __func__, gp->name)); + g_topology_assert(); + + cp = LIST_FIRST(&gp->consumer); + table = gp->softc; + + error = G_PART_RECOVER(table, cp); + if (error) { + gctl_error(req, "%d", error); + return (error); + } + + /* Provide feedback if so requested. */ + if (gpp->gpp_parms & G_PART_PARM_OUTPUT) { + sb = sbuf_new_auto(); + sbuf_printf(sb, "%s recovered\n", gp->name); + sbuf_finish(sb); + gctl_set_param(req, "output", sbuf_data(sb), sbuf_len(sb) + 1); + sbuf_delete(sb); + } + return (0); } static int g_part_ctl_resize(struct gctl_req *req, struct g_part_parms *gpp) { - gctl_error(req, "%d verb 'resize'", ENOSYS); - return (ENOSYS); -} + struct g_geom *gp; + struct g_provider *pp; + struct g_part_entry *pe, *entry; + struct g_part_table *table; + struct sbuf *sb; + quad_t end; + int error; + gp = gpp->gpp_geom; + G_PART_TRACE((G_T_TOPOLOGY, "%s(%s)", __func__, gp->name)); + g_topology_assert(); + table = gp->softc; + + /* check gpp_index */ + LIST_FOREACH(entry, &table->gpt_entry, gpe_entry) { + if (entry->gpe_deleted || entry->gpe_internal) + continue; + if (entry->gpe_index == gpp->gpp_index) + break; + } + if (entry == NULL) { + gctl_error(req, "%d index '%d'", ENOENT, gpp->gpp_index); + return (ENOENT); + } + + /* check gpp_size */ + end = entry->gpe_start + gpp->gpp_size - 1; + if (gpp->gpp_size < 1 || end > table->gpt_last) { + gctl_error(req, "%d size '%jd'", EINVAL, + (intmax_t)gpp->gpp_size); + return (EINVAL); + } + + LIST_FOREACH(pe, &table->gpt_entry, gpe_entry) { + if (pe->gpe_deleted || pe->gpe_internal || pe == entry) + continue; + if (end >= pe->gpe_start && end <= pe->gpe_end) { + gctl_error(req, "%d end '%jd'", ENOSPC, + (intmax_t)end); + return (ENOSPC); + } + if (entry->gpe_start < pe->gpe_start && end > pe->gpe_end) { + gctl_error(req, "%d size '%jd'", ENOSPC, + (intmax_t)gpp->gpp_size); + return (ENOSPC); + } + } + + pp = entry->gpe_pp; + if ((g_debugflags & 16) == 0 && + (pp->acr > 0 || pp->acw > 0 || pp->ace > 0)) { + gctl_error(req, "%d", EBUSY); + return (EBUSY); + } + + error = G_PART_RESIZE(table, entry, gpp); + if (error) { + gctl_error(req, "%d", error); + return (error); + } + + if (!entry->gpe_created) + entry->gpe_modified = 1; + + /* update mediasize of changed provider */ + pp->mediasize = (entry->gpe_end - entry->gpe_start + 1) * + pp->sectorsize; + + /* Provide feedback if so requested. */ + if (gpp->gpp_parms & G_PART_PARM_OUTPUT) { + sb = sbuf_new_auto(); + G_PART_FULLNAME(table, entry, sb, gp->name); + sbuf_cat(sb, " resized\n"); + sbuf_finish(sb); + gctl_set_param(req, "output", sbuf_data(sb), sbuf_len(sb) + 1); + sbuf_delete(sb); + } + return (0); +} + static int g_part_ctl_setunset(struct gctl_req *req, struct g_part_parms *gpp, unsigned int set) @@ -1174,7 +1276,8 @@ mparms |= G_PART_PARM_GEOM; } else if (!strcmp(verb, "resize")) { ctlreq = G_PART_CTL_RESIZE; - mparms |= G_PART_PARM_GEOM | G_PART_PARM_INDEX; + mparms |= G_PART_PARM_GEOM | G_PART_PARM_INDEX | + G_PART_PARM_SIZE; } break; case 's': Index: sys/geom/part/g_part_mbr.c =================================================================== --- g_part_mbr.c (revision 204945) +++ g_part_mbr.c (working copy) @@ -76,6 +76,8 @@ static const char *g_part_mbr_type(struct g_part_table *, struct g_part_entry *, char *, size_t); static int g_part_mbr_write(struct g_part_table *, struct g_consumer *); +static int g_part_mbr_resize(struct g_part_table *, struct g_part_entry *, + struct g_part_parms *); static kobj_method_t g_part_mbr_methods[] = { KOBJMETHOD(g_part_add, g_part_mbr_add), @@ -85,6 +87,7 @@ KOBJMETHOD(g_part_dumpconf, g_part_mbr_dumpconf), KOBJMETHOD(g_part_dumpto, g_part_mbr_dumpto), KOBJMETHOD(g_part_modify, g_part_mbr_modify), + KOBJMETHOD(g_part_resize, g_part_mbr_resize), KOBJMETHOD(g_part_name, g_part_mbr_name), KOBJMETHOD(g_part_probe, g_part_mbr_probe), KOBJMETHOD(g_part_read, g_part_mbr_read), @@ -302,6 +305,31 @@ return (0); } +static int +g_part_mbr_resize(struct g_part_table *basetable, + struct g_part_entry *baseentry, struct g_part_parms *gpp) +{ + struct g_part_mbr_entry *entry; + uint32_t size, sectors; + + sectors = basetable->gpt_sectors; + size = gpp->gpp_size; + + if (size < sectors) + return (EINVAL); + if (size % sectors) + size = size - (size % sectors); + if (size < sectors) + return (EINVAL); + + entry = (struct g_part_mbr_entry *)baseentry; + baseentry->gpe_end = baseentry->gpe_start + size - 1; + entry->ent.dp_size = size; + mbr_set_chs(basetable, baseentry->gpe_end, &entry->ent.dp_ecyl, + &entry->ent.dp_ehd, &entry->ent.dp_esect); + return (0); +} + static const char * g_part_mbr_name(struct g_part_table *table, struct g_part_entry *baseentry, char *buf, size_t bufsz)