Date: Thu, 22 Apr 2010 15:35:14 +0400 From: "Andrey V. Elsukov" <bu7cher@yandex.ru> To: Andriy Gapon <avg@icyb.net.ua> Cc: Lister <lister@kawashti.org>, Marcel Moolenaar <marcel@FreeBSD.org>, freebsd-geom@FreeBSD.org Subject: [patch] resize and recover support for GPART GPT scheme (was: Re: OCE and GPT) Message-ID: <4BD03472.6030201@yandex.ru> In-Reply-To: <4BCF04C7.1050701@icyb.net.ua> References: <B814515407B5445092FD63116EA3DA6B@neo> <4BCEE9E2.6010007@yandex.ru> <4BCEEC66.1080804@yandex.ru> <4BCEEF06.8010203@icyb.net.ua> <4BCEF5F8.6090102@yandex.ru> <4BCF04C7.1050701@icyb.net.ua>
next in thread | previous in thread | raw e-mail | index | archive | help
This is a multi-part message in MIME format. --------------070101000704010802030502 Content-Type: text/plain; charset=KOI8-R; format=flowed Content-Transfer-Encoding: 8bit On 21.04.2010 17:59, Andriy Gapon wrote: > I also think that this recovery mechanism is needed. > In short: > recover - re-create secondary table based on primary table > reinit - relocate secondary table to a new position and update offsets in both > tables accordingly I implemented 'recover' verb. I changed detection algoritm in GPT scheme. Now when primary GPT header is valid reading of second header will be done from alternateLBA offset (which read from GPT header). When primary header is invalid reading of second header will be from the last medium's LBA. And now the following scenario works: ==================================================================== # dd if=/dev/zero of=./d.img bs=1m count=100 100+0 records in 100+0 records out 104857600 bytes transferred in 2.895854 secs (36209560 bytes/sec) # mdconfig -f d.img md0 # gpart create -s gpt md0 md0 created # gpart add -t freebsd-zfs md0 md0p1 added # gpart show md0 => 34 204733 md0 GPT (100M) 34 204733 1 freebsd-zfs (100M) # mdconfig -du 0 # dd if=/dev/zero of=./d.img bs=1m count=50 seek=100 50+0 records in 50+0 records out 52428800 bytes transferred in 1.175911 secs (44585689 bytes/sec) # ls -lh d.img -rw-r--r-- 1 root wheel 150M 22 Сав 14:56 d.img # mdconfig -f d.img md0 # dmesg | tail -2 GEOM: md0: the secondary GPT table is corrupt or invalid. GEOM: md0: using the primary only -- recovery suggested. # gpart show md0 => 34 204733 md0 GPT (150M) 34 204733 1 freebsd-zfs (100M) # gpart recover md0 md0 recovered # gpart show md0 => 34 307133 md0 GPT (150M) 34 204733 1 freebsd-zfs (100M) 204767 102400 - free - (50M) # gpart resize -i 1 md0 md0p1 resized # gpart show md0 => 34 307133 md0 GPT (150M) 34 307133 1 freebsd-zfs (150M) ==================================================================== There are several things that can be do where i need suggestions. 1. What code should do when user doing `gpart recover` for scheme that doesn't need recovering? 2. Probably there are needed some checks before changing metadata in g_part_gpt_recover method. So, patch attached and comments are welcome. -- WBR, Andrey V. Elsukov --------------070101000704010802030502 Content-Type: text/plain; name="gpart_recover.diff.txt" Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename="gpart_recover.diff.txt" Index: gpart.8 =================================================================== --- gpart.8 (revision 205576) +++ gpart.8 (working copy) @@ -120,6 +120,18 @@ utility: .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 @@ -325,6 +337,45 @@ See the section entitled 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: geom_part.c =================================================================== --- geom_part.c (revision 205576) +++ geom_part.c (working copy) @@ -112,6 +112,18 @@ struct g_command PUBSYM(class_commands)[] = { 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 }, @@ -243,6 +255,99 @@ fmtattrib(struct gprovider *pp) } 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; @@ -257,6 +362,8 @@ gpart_autofill(struct gctl_req *req) 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: g_part_pc98.c =================================================================== --- g_part_pc98.c (revision 204945) +++ g_part_pc98.c (working copy) @@ -77,6 +77,8 @@ static int g_part_pc98_setunset(struct g_part_tabl 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 @@ static kobj_method_t g_part_pc98_methods[] = { 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 @@ g_part_pc98_modify(struct g_part_table *basetable, 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: g_part_vtoc8.c =================================================================== --- g_part_vtoc8.c (revision 204945) +++ g_part_vtoc8.c (working copy) @@ -67,6 +67,8 @@ static int g_part_vtoc8_read(struct g_part_table * 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 @@ static kobj_method_t g_part_vtoc8_methods[] = { 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), @@ -294,6 +297,26 @@ g_part_vtoc8_modify(struct g_part_table *basetable 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: g_part_bsd.c =================================================================== --- g_part_bsd.c (revision 204945) +++ g_part_bsd.c (working copy) @@ -73,6 +73,8 @@ static int g_part_bsd_read(struct g_part_table *, 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 @@ static kobj_method_t g_part_bsd_methods[] = { 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), @@ -288,6 +291,19 @@ g_part_bsd_modify(struct g_part_table *basetable, 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: g_part_if.m =================================================================== --- g_part_if.m (revision 204945) +++ g_part_if.m (working copy) @@ -58,6 +58,20 @@ CODE { { 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 @@ METHOD int read { 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: g_part_gpt.c =================================================================== --- g_part_gpt.c (revision 204945) +++ g_part_gpt.c (working copy) @@ -100,6 +100,9 @@ static const char *g_part_gpt_name(struct g_part_t 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 @@ static kobj_method_t g_part_gpt_methods[] = { 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 } @@ -164,7 +169,7 @@ static struct uuid gpt_uuid_unused = GPT_ENT_TYPE_ static struct g_part_uuid_alias { struct uuid *uuid; - int alias; + int alias; } gpt_uuid_alias_match[] = { { &gpt_uuid_apple_boot, G_PART_ALIAS_APPLE_BOOT }, { &gpt_uuid_apple_hfs, G_PART_ALIAS_APPLE_HFS }, @@ -211,7 +216,14 @@ gpt_read_hdr(struct g_part_gpt_table *table, struc 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); @@ -238,12 +250,15 @@ gpt_read_hdr(struct g_part_gpt_table *table, struc 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); @@ -277,6 +292,10 @@ gpt_read_hdr(struct g_part_gpt_table *table, struc 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); @@ -550,6 +569,50 @@ g_part_gpt_modify(struct g_part_table *basetable, 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) @@ -630,10 +693,12 @@ g_part_gpt_read(struct g_part_table *basetable, st 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); @@ -703,7 +768,8 @@ g_part_gpt_read(struct g_part_table *basetable, st 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: g_part_apm.c =================================================================== --- g_part_apm.c (revision 204945) +++ g_part_apm.c (working copy) @@ -74,6 +74,8 @@ static int g_part_apm_read(struct g_part_table *, 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 @@ static kobj_method_t g_part_apm_methods[] = { 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 @@ g_part_apm_modify(struct g_part_table *basetable, 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: g_part.c =================================================================== --- g_part.c (revision 204945) +++ g_part.c (working copy) @@ -959,22 +959,124 @@ g_part_ctl_move(struct gctl_req *req, struct g_par { 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) @@ -1194,7 +1296,8 @@ g_part_ctlreq(struct gctl_req *req, struct g_class 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: g_part_mbr.c =================================================================== --- g_part_mbr.c (revision 204945) +++ g_part_mbr.c (working copy) @@ -76,6 +76,8 @@ static int g_part_mbr_setunset(struct g_part_table 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 @@ static kobj_method_t g_part_mbr_methods[] = { 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 @@ g_part_mbr_modify(struct g_part_table *basetable, 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) --------------070101000704010802030502--
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?4BD03472.6030201>