svn commit: r199633 - stable/7/sys/geom/part
Robert Noland
rnoland at FreeBSD.org
Sat Nov 21 14:54:46 UTC 2009
Author: rnoland
Date: Sat Nov 21 14:54:45 2009
New Revision: 199633
URL: http://svn.freebsd.org/changeset/base/199633
Log:
MFC r199017,199228
Fix handling of GPT headers when size is > 92 bytes.
This should address reading GPT headers written by opensolaris.
Modified:
stable/7/sys/geom/part/g_part_gpt.c
Directory Properties:
stable/7/sys/ (props changed)
stable/7/sys/contrib/pf/ (props changed)
Modified: stable/7/sys/geom/part/g_part_gpt.c
==============================================================================
--- stable/7/sys/geom/part/g_part_gpt.c Sat Nov 21 14:54:35 2009 (r199632)
+++ stable/7/sys/geom/part/g_part_gpt.c Sat Nov 21 14:54:45 2009 (r199633)
@@ -73,7 +73,7 @@ enum gpt_state {
struct g_part_gpt_table {
struct g_part_table base;
u_char mbr[MBRSIZE];
- struct gpt_hdr hdr;
+ struct gpt_hdr *hdr;
quad_t lba[GPT_ELT_COUNT];
enum gpt_state state[GPT_ELT_COUNT];
};
@@ -142,13 +142,12 @@ static struct uuid gpt_uuid_linux_swap =
static struct uuid gpt_uuid_mbr = GPT_ENT_TYPE_MBR;
static struct uuid gpt_uuid_unused = GPT_ENT_TYPE_UNUSED;
-static void
+static struct gpt_hdr *
gpt_read_hdr(struct g_part_gpt_table *table, struct g_consumer *cp,
- enum gpt_elt elt, struct gpt_hdr *hdr)
+ enum gpt_elt elt)
{
- struct uuid uuid;
+ struct gpt_hdr *buf, *hdr;
struct g_provider *pp;
- char *buf;
quad_t lba, last;
int error;
uint32_t crc, sz;
@@ -160,63 +159,75 @@ gpt_read_hdr(struct g_part_gpt_table *ta
buf = g_read_data(cp, table->lba[elt] * pp->sectorsize, pp->sectorsize,
&error);
if (buf == NULL)
- return;
- bcopy(buf, hdr, sizeof(*hdr));
- if (memcmp(hdr->hdr_sig, GPT_HDR_SIG, sizeof(hdr->hdr_sig)) != 0)
- return;
+ return (NULL);
+ hdr = NULL;
+ if (memcmp(buf->hdr_sig, GPT_HDR_SIG, sizeof(buf->hdr_sig)) != 0)
+ goto fail;
table->state[elt] = GPT_STATE_CORRUPT;
- sz = le32toh(hdr->hdr_size);
+ sz = le32toh(buf->hdr_size);
if (sz < 92 || sz > pp->sectorsize)
- return;
- crc = le32toh(hdr->hdr_crc_self);
- hdr->hdr_crc_self = 0;
- if (crc32(hdr, sz) != crc)
- return;
+ goto fail;
+
+ hdr = g_malloc(sz, M_WAITOK | M_ZERO);
+ bcopy(buf, hdr, sz);
hdr->hdr_size = sz;
+
+ crc = le32toh(buf->hdr_crc_self);
+ buf->hdr_crc_self = 0;
+ if (crc32(buf, sz) != crc)
+ goto fail;
hdr->hdr_crc_self = crc;
table->state[elt] = GPT_STATE_INVALID;
- hdr->hdr_revision = le32toh(hdr->hdr_revision);
+ hdr->hdr_revision = le32toh(buf->hdr_revision);
if (hdr->hdr_revision < 0x00010000)
- return;
- hdr->hdr_lba_self = le64toh(hdr->hdr_lba_self);
+ goto fail;
+ hdr->hdr_lba_self = le64toh(buf->hdr_lba_self);
if (hdr->hdr_lba_self != table->lba[elt])
- return;
- hdr->hdr_lba_alt = le64toh(hdr->hdr_lba_alt);
+ goto fail;
+ hdr->hdr_lba_alt = le64toh(buf->hdr_lba_alt);
/* Check the managed area. */
- hdr->hdr_lba_start = le64toh(hdr->hdr_lba_start);
+ hdr->hdr_lba_start = le64toh(buf->hdr_lba_start);
if (hdr->hdr_lba_start < 2 || hdr->hdr_lba_start >= last)
- return;
- hdr->hdr_lba_end = le64toh(hdr->hdr_lba_end);
+ goto fail;
+ hdr->hdr_lba_end = le64toh(buf->hdr_lba_end);
if (hdr->hdr_lba_end < hdr->hdr_lba_start || hdr->hdr_lba_end >= last)
- return;
+ goto fail;
/* Check the table location and size of the table. */
- hdr->hdr_entries = le32toh(hdr->hdr_entries);
- hdr->hdr_entsz = le32toh(hdr->hdr_entsz);
+ hdr->hdr_entries = le32toh(buf->hdr_entries);
+ hdr->hdr_entsz = le32toh(buf->hdr_entsz);
if (hdr->hdr_entries == 0 || hdr->hdr_entsz < 128 ||
(hdr->hdr_entsz & 7) != 0)
- return;
- hdr->hdr_lba_table = le64toh(hdr->hdr_lba_table);
+ goto fail;
+ hdr->hdr_lba_table = le64toh(buf->hdr_lba_table);
if (hdr->hdr_lba_table < 2 || hdr->hdr_lba_table >= last)
- return;
+ goto fail;
if (hdr->hdr_lba_table >= hdr->hdr_lba_start &&
hdr->hdr_lba_table <= hdr->hdr_lba_end)
- return;
+ goto fail;
lba = hdr->hdr_lba_table +
(hdr->hdr_entries * hdr->hdr_entsz + pp->sectorsize - 1) /
pp->sectorsize - 1;
if (lba >= last)
- return;
+ goto fail;
if (lba >= hdr->hdr_lba_start && lba <= hdr->hdr_lba_end)
- return;
+ goto fail;
table->state[elt] = GPT_STATE_OK;
- le_uuid_dec(&hdr->hdr_uuid, &uuid);
- hdr->hdr_uuid = uuid;
- hdr->hdr_crc_table = le32toh(hdr->hdr_crc_table);
+ le_uuid_dec(&buf->hdr_uuid, &hdr->hdr_uuid);
+ hdr->hdr_crc_table = le32toh(buf->hdr_crc_table);
+
+ g_free(buf);
+ return (hdr);
+
+ fail:
+ if (hdr != NULL)
+ g_free(hdr);
+ g_free(buf);
+ return (NULL);
}
static struct gpt_ent *
@@ -229,6 +240,9 @@ gpt_read_tbl(struct g_part_gpt_table *ta
unsigned int idx, sectors, tblsz;
int error;
+ if (hdr == NULL)
+ return (NULL);
+
pp = cp->provider;
table->lba[elt] = hdr->hdr_lba_table;
@@ -270,6 +284,9 @@ static int
gpt_matched_hdrs(struct gpt_hdr *pri, struct gpt_hdr *sec)
{
+ if (pri == NULL || sec == NULL)
+ return (0);
+
if (!EQUUID(&pri->hdr_uuid, &sec->hdr_uuid))
return (0);
return ((pri->hdr_revision == sec->hdr_revision &&
@@ -417,17 +434,20 @@ g_part_gpt_create(struct g_part_table *b
table->lba[GPT_ELT_SECHDR] = last;
table->lba[GPT_ELT_SECTBL] = last - tblsz;
- bcopy(GPT_HDR_SIG, table->hdr.hdr_sig, sizeof(table->hdr.hdr_sig));
- table->hdr.hdr_revision = GPT_HDR_REVISION;
- table->hdr.hdr_size = offsetof(struct gpt_hdr, padding);
- table->hdr.hdr_lba_start = 2 + tblsz;
- table->hdr.hdr_lba_end = last - tblsz - 1;
- kern_uuidgen(&table->hdr.hdr_uuid, 1);
- table->hdr.hdr_entries = basetable->gpt_entries;
- table->hdr.hdr_entsz = sizeof(struct gpt_ent);
+ /* Allocate space for the header */
+ table->hdr = g_malloc(sizeof(struct gpt_hdr), M_WAITOK | M_ZERO);
+
+ bcopy(GPT_HDR_SIG, table->hdr->hdr_sig, sizeof(table->hdr->hdr_sig));
+ table->hdr->hdr_revision = GPT_HDR_REVISION;
+ table->hdr->hdr_size = offsetof(struct gpt_hdr, padding);
+ table->hdr->hdr_lba_start = 2 + tblsz;
+ table->hdr->hdr_lba_end = last - tblsz - 1;
+ kern_uuidgen(&table->hdr->hdr_uuid, 1);
+ table->hdr->hdr_entries = basetable->gpt_entries;
+ table->hdr->hdr_entsz = sizeof(struct gpt_ent);
- basetable->gpt_first = table->hdr.hdr_lba_start;
- basetable->gpt_last = table->hdr.hdr_lba_end;
+ basetable->gpt_first = table->hdr->hdr_lba_start;
+ basetable->gpt_last = table->hdr->hdr_lba_end;
return (0);
}
@@ -572,7 +592,7 @@ g_part_gpt_probe(struct g_part_table *ta
static int
g_part_gpt_read(struct g_part_table *basetable, struct g_consumer *cp)
{
- struct gpt_hdr prihdr, sechdr;
+ struct gpt_hdr *prihdr, *sechdr;
struct gpt_ent *tbl, *pritbl, *sectbl;
struct g_provider *pp;
struct g_part_gpt_table *table;
@@ -591,18 +611,18 @@ g_part_gpt_read(struct g_part_table *bas
g_free(buf);
/* Read the primary header and table. */
- gpt_read_hdr(table, cp, GPT_ELT_PRIHDR, &prihdr);
+ prihdr = gpt_read_hdr(table, cp, GPT_ELT_PRIHDR);
if (table->state[GPT_ELT_PRIHDR] == GPT_STATE_OK) {
- pritbl = gpt_read_tbl(table, cp, GPT_ELT_PRITBL, &prihdr);
+ pritbl = gpt_read_tbl(table, cp, GPT_ELT_PRITBL, prihdr);
} else {
table->state[GPT_ELT_PRITBL] = GPT_STATE_MISSING;
pritbl = NULL;
}
/* Read the secondary header and table. */
- gpt_read_hdr(table, cp, GPT_ELT_SECHDR, &sechdr);
+ sechdr = gpt_read_hdr(table, cp, GPT_ELT_SECHDR);
if (table->state[GPT_ELT_SECHDR] == GPT_STATE_OK) {
- sectbl = gpt_read_tbl(table, cp, GPT_ELT_SECTBL, &sechdr);
+ sectbl = gpt_read_tbl(table, cp, GPT_ELT_SECTBL, sechdr);
} else {
table->state[GPT_ELT_SECTBL] = GPT_STATE_MISSING;
sectbl = NULL;
@@ -625,13 +645,17 @@ g_part_gpt_read(struct g_part_table *bas
*/
if (table->state[GPT_ELT_PRIHDR] == GPT_STATE_OK &&
table->state[GPT_ELT_SECHDR] == GPT_STATE_OK &&
- !gpt_matched_hdrs(&prihdr, &sechdr)) {
+ !gpt_matched_hdrs(prihdr, sechdr)) {
if (table->state[GPT_ELT_PRITBL] == GPT_STATE_OK) {
table->state[GPT_ELT_SECHDR] = GPT_STATE_INVALID;
table->state[GPT_ELT_SECTBL] = GPT_STATE_MISSING;
+ g_free(sechdr);
+ sechdr = NULL;
} else {
table->state[GPT_ELT_PRIHDR] = GPT_STATE_INVALID;
table->state[GPT_ELT_PRITBL] = GPT_STATE_MISSING;
+ g_free(prihdr);
+ prihdr = NULL;
}
}
@@ -641,6 +665,8 @@ g_part_gpt_read(struct g_part_table *bas
printf("GEOM: %s: using the secondary instead -- recovery "
"strongly advised.\n", pp->name);
table->hdr = sechdr;
+ if (prihdr != NULL)
+ g_free(prihdr);
tbl = sectbl;
if (pritbl != NULL)
g_free(pritbl);
@@ -652,14 +678,16 @@ g_part_gpt_read(struct g_part_table *bas
"suggested.\n", pp->name);
}
table->hdr = prihdr;
+ if (sechdr != NULL)
+ g_free(sechdr);
tbl = pritbl;
if (sectbl != NULL)
g_free(sectbl);
}
- basetable->gpt_first = table->hdr.hdr_lba_start;
- basetable->gpt_last = table->hdr.hdr_lba_end;
- basetable->gpt_entries = table->hdr.hdr_entries;
+ basetable->gpt_first = table->hdr->hdr_lba_start;
+ basetable->gpt_last = table->hdr->hdr_lba_end;
+ basetable->gpt_entries = table->hdr->hdr_entries;
for (index = basetable->gpt_entries - 1; index >= 0; index--) {
if (EQUUID(&tbl[index].ent_type, &gpt_uuid_unused))
@@ -717,7 +745,7 @@ g_part_gpt_write(struct g_part_table *ba
pp = cp->provider;
table = (struct g_part_gpt_table *)basetable;
- tlbsz = (table->hdr.hdr_entries * table->hdr.hdr_entsz +
+ tlbsz = (table->hdr->hdr_entries * table->hdr->hdr_entsz +
pp->sectorsize - 1) / pp->sectorsize;
/* Write the PMBR */
@@ -731,21 +759,21 @@ g_part_gpt_write(struct g_part_table *ba
/* Allocate space for the header and entries. */
buf = g_malloc((tlbsz + 1) * pp->sectorsize, M_WAITOK | M_ZERO);
- memcpy(buf, table->hdr.hdr_sig, sizeof(table->hdr.hdr_sig));
- le32enc(buf + 8, table->hdr.hdr_revision);
- le32enc(buf + 12, table->hdr.hdr_size);
- le64enc(buf + 40, table->hdr.hdr_lba_start);
- le64enc(buf + 48, table->hdr.hdr_lba_end);
- le_uuid_enc(buf + 56, &table->hdr.hdr_uuid);
- le32enc(buf + 80, table->hdr.hdr_entries);
- le32enc(buf + 84, table->hdr.hdr_entsz);
+ memcpy(buf, table->hdr->hdr_sig, sizeof(table->hdr->hdr_sig));
+ le32enc(buf + 8, table->hdr->hdr_revision);
+ le32enc(buf + 12, table->hdr->hdr_size);
+ le64enc(buf + 40, table->hdr->hdr_lba_start);
+ le64enc(buf + 48, table->hdr->hdr_lba_end);
+ le_uuid_enc(buf + 56, &table->hdr->hdr_uuid);
+ le32enc(buf + 80, table->hdr->hdr_entries);
+ le32enc(buf + 84, table->hdr->hdr_entsz);
LIST_FOREACH(baseentry, &basetable->gpt_entry, gpe_entry) {
if (baseentry->gpe_deleted)
continue;
entry = (struct g_part_gpt_entry *)baseentry;
index = baseentry->gpe_index - 1;
- bp = buf + pp->sectorsize + table->hdr.hdr_entsz * index;
+ bp = buf + pp->sectorsize + table->hdr->hdr_entsz * index;
le_uuid_enc(bp, &entry->ent.ent_type);
le_uuid_enc(bp + 16, &entry->ent.ent_uuid);
le64enc(bp + 32, entry->ent.ent_lba_start);
@@ -756,7 +784,7 @@ g_part_gpt_write(struct g_part_table *ba
}
crc = crc32(buf + pp->sectorsize,
- table->hdr.hdr_entries * table->hdr.hdr_entsz);
+ table->hdr->hdr_entries * table->hdr->hdr_entsz);
le32enc(buf + 88, crc);
/* Write primary meta-data. */
@@ -764,7 +792,7 @@ g_part_gpt_write(struct g_part_table *ba
le64enc(buf + 24, table->lba[GPT_ELT_PRIHDR]); /* hdr_lba_self. */
le64enc(buf + 32, table->lba[GPT_ELT_SECHDR]); /* hdr_lba_alt. */
le64enc(buf + 72, table->lba[GPT_ELT_PRITBL]); /* hdr_lba_table. */
- crc = crc32(buf, table->hdr.hdr_size);
+ crc = crc32(buf, table->hdr->hdr_size);
le32enc(buf + 16, crc);
error = g_write_data(cp, table->lba[GPT_ELT_PRITBL] * pp->sectorsize,
@@ -781,7 +809,7 @@ g_part_gpt_write(struct g_part_table *ba
le64enc(buf + 24, table->lba[GPT_ELT_SECHDR]); /* hdr_lba_self. */
le64enc(buf + 32, table->lba[GPT_ELT_PRIHDR]); /* hdr_lba_alt. */
le64enc(buf + 72, table->lba[GPT_ELT_SECTBL]); /* hdr_lba_table. */
- crc = crc32(buf, table->hdr.hdr_size);
+ crc = crc32(buf, table->hdr->hdr_size);
le32enc(buf + 16, crc);
error = g_write_data(cp, table->lba[GPT_ELT_SECTBL] * pp->sectorsize,
More information about the svn-src-stable
mailing list