Author: rnoland
Date: Sat Nov 21 14:53:08 2009
New Revision: 199630
URL: http://svn.freebsd.org/changeset/base/199630

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/8/sys/geom/part/g_part_gpt.c
Directory Properties:
  stable/8/sys/   (props changed)
  stable/8/sys/amd64/include/xen/   (props changed)
  stable/8/sys/cddl/contrib/opensolaris/   (props changed)
  stable/8/sys/contrib/dev/acpica/   (props changed)
  stable/8/sys/contrib/pf/   (props changed)
  stable/8/sys/dev/xen/xenpci/   (props changed)

Modified: stable/8/sys/geom/part/g_part_gpt.c
==============================================================================
--- stable/8/sys/geom/part/g_part_gpt.c Sat Nov 21 14:28:32 2009        
(r199629)
+++ stable/8/sys/geom/part/g_part_gpt.c Sat Nov 21 14:53:08 2009        
(r199630)
@@ -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];
 };
@@ -143,13 +143,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;
@@ -161,63 +160,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 *
@@ -230,6 +241,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;
 
@@ -271,6 +285,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 &&
@@ -427,17 +444,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);
 }
 
@@ -582,7 +602,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;
@@ -601,18 +621,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;
@@ -635,13 +655,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;
                }
        }
 
@@ -651,6 +675,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);
@@ -662,14 +688,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))
@@ -729,7 +757,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 */
@@ -743,21 +771,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);
@@ -768,7 +796,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. */
@@ -776,7 +804,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,
@@ -793,7 +821,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,
_______________________________________________
svn-src-all@freebsd.org mailing list
http://lists.freebsd.org/mailman/listinfo/svn-src-all
To unsubscribe, send any mail to "svn-src-all-unsubscr...@freebsd.org"

Reply via email to