From eb6ab15ac4c4bf75425d3b52a290d3fe948bc26e Mon Sep 17 00:00:00 2001 From: Fabian Keil Date: Sun, 5 Dec 2021 12:17:32 +0100 Subject: [PATCH] sys/geom/part: Ignore more errors if kern.geom.part.check_integrity is set to 0 ... and log more details about detected corruption in general. Use a bunch of ugly casts so it can be build on i386 as well. This commit was useful to recover from GPT corruption that looked like this: GEOM: hdr_lba_end (7814037127) < hdr->hdr_lba_start (40) or hrdr_lba_end >= last (7814035054) for ada1. GEOM: Reading sector 4000787029504 of size 512 from ada1. GEOM: ada1: the secondary GPT table is corrupt or invalid. GEOM: ada1: using the primary only -- recovery suggested. GEOM_PART: integrity check failed (ada1, GPT) Without this commit the partion table was complete invisble. With this commit and kern.geom.part.check_integrity=0 a corrupt GPT table was visible and looked like this: => 40 7814037088 ada1 GPT (3.6T) [CORRUPT] 40 512 1 freebsd-boot (256K) 552 1496 - free - (748K) 2048 409600 2 freebsd-zfs (200M) 411648 20971520 3 freebsd-zfs (10G) 21383168 8388608 4 freebsd-swap (4.0G) 29771776 7784263680 5 freebsd-zfs (3.6T) 7814035456 1672 - free - (836K) After deleting partition 5 and recreating it, all the data on it was available again: => 40 7814034982 ada1 GPT (3.6T) [CORRUPT] 40 512 1 freebsd-boot (256K) 552 1496 - free - (748K) 2048 409600 2 freebsd-zfs (200M) 411648 20971520 3 freebsd-zfs (10G) 21383168 8388608 4 freebsd-swap (4.0G) 29771776 7784263240 5 freebsd-zfs (3.6T) 7814035016 6 - free - (3.0K) After the next boot the [CORRUPT] marker was gone as well: => 40 7814034982 ada1 GPT (3.6T) 40 512 1 freebsd-boot (256K) 552 1496 - free - (748K) 2048 409600 2 freebsd-zfs (200M) 411648 20971520 3 freebsd-zfs (10G) 21383168 8388608 4 freebsd-swap (4.0G) 29771776 7784263240 5 freebsd-zfs (3.6T) 7814035016 6 - free - (3.0K) Unfortunately it's unclear how the GPT data got corrupted in the first place. Obtained from: ElectroBSD --- sys/geom/part/g_part_gpt.c | 132 +++++++++++++++++++++++++++++-------- 1 file changed, 103 insertions(+), 29 deletions(-) diff --git a/sys/geom/part/g_part_gpt.c b/sys/geom/part/g_part_gpt.c index 8fd3b490c4fc..97993fff5ac2 100644 --- a/sys/geom/part/g_part_gpt.c +++ b/sys/geom/part/g_part_gpt.c @@ -433,66 +433,140 @@ gpt_read_hdr(struct g_part_gpt_table *table, struct g_consumer *cp, table->lba[elt] = 1; buf = g_read_data(cp, table->lba[elt] * pp->sectorsize, pp->sectorsize, &error); - if (buf == NULL) + if (buf == NULL) { + printf("GEOM: Reading sector %llu of size %d from %s.\n", + (unsigned long long)table->lba[elt] * pp->sectorsize, + pp->sectorsize, pp->name); 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(buf->hdr_size); - if (sz < 92 || sz > pp->sectorsize) - goto fail; - + if (sz < 92 || sz > pp->sectorsize) { + printf("GEOM: Strange sector size %d for %s.\n", + sz, pp->name); + if (geom_part_check_integrity) + 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; + if (crc32(buf, sz) != crc) { + printf("GEOM: %s: Invalid crc32 detected.\n", + pp->name); + if (geom_part_check_integrity) + goto fail; + } hdr->hdr_crc_self = crc; table->state[elt] = GPT_STATE_INVALID; hdr->hdr_revision = le32toh(buf->hdr_revision); - if (hdr->hdr_revision < GPT_HDR_REVISION) - goto fail; + if (hdr->hdr_revision < GPT_HDR_REVISION) { + printf("GEOM: Strange header revision %d for %s.\n", + hdr->hdr_revision, pp->name); + if (geom_part_check_integrity) + goto fail; + } hdr->hdr_lba_self = le64toh(buf->hdr_lba_self); - if (hdr->hdr_lba_self != table->lba[elt]) - goto fail; + if (hdr->hdr_lba_self != table->lba[elt]) { + printf("GEOM: hdr_lba_self (%llu) != table->lba[elt] " + "(%llu) for %s.\n", + (unsigned long long)hdr->hdr_lba_self, + (unsigned long long)table->lba[elt], pp->name); + if (geom_part_check_integrity) + goto fail; + } hdr->hdr_lba_alt = le64toh(buf->hdr_lba_alt); - if (hdr->hdr_lba_alt == hdr->hdr_lba_self) - goto fail; - if (hdr->hdr_lba_alt > last && geom_part_check_integrity) - goto fail; - + if (hdr->hdr_lba_alt == hdr->hdr_lba_self) { + printf("GEOM: hdr_lba_alt (%llu) == " + "hdr_lba_self (%llu) for %s.\n", + (unsigned long long)hdr->hdr_lba_alt, + (unsigned long long)hdr->hdr_lba_self, pp->name); + if (geom_part_check_integrity) + goto fail; + } + if (hdr->hdr_lba_alt > last && geom_part_check_integrity) { + printf("GEOM: hdr_lba_alt (%llu) > last (%llu) for %s.\n", + (unsigned long long)hdr->hdr_lba_alt, + (unsigned long long)last, pp->name); + if (geom_part_check_integrity) + goto fail; + } /* Check the managed area. */ hdr->hdr_lba_start = le64toh(buf->hdr_lba_start); - if (hdr->hdr_lba_start < 2 || hdr->hdr_lba_start >= last) - goto fail; + if (hdr->hdr_lba_start < 2 || hdr->hdr_lba_start >= last) { + printf("GEOM: hdr_lba_start (%llu) < 2 or >= last (%llu) for %s.\n", + (unsigned long long)hdr->hdr_lba_start, + (unsigned long long)last, pp->name); + if (geom_part_check_integrity) + 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) - goto fail; + if (hdr->hdr_lba_end < hdr->hdr_lba_start || hdr->hdr_lba_end >= last) { + printf("GEOM: hdr_lba_end (%llu) < hdr->hdr_lba_start (%llu) or " + "hrdr_lba_end >= last (%llu) for %s.\n", + (unsigned long long)hdr->hdr_lba_end, + (unsigned long long)hdr->hdr_lba_start, + (unsigned long long)last, pp->name); + if (geom_part_check_integrity) + goto fail; + } /* Check the table location and size of the table. */ 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) - goto fail; + (hdr->hdr_entsz & 7) != 0) { + printf("GEOM: hdr_entries (%u) == 0 or " + "hdr_entsz (%u) < 128 or " + "hdr_entsz & 7) != 0 for %s", + hdr->hdr_entries, hdr->hdr_entsz, pp->name); + if (geom_part_check_integrity) + goto fail; + } hdr->hdr_lba_table = le64toh(buf->hdr_lba_table); - if (hdr->hdr_lba_table < 2 || hdr->hdr_lba_table >= last) - goto fail; + if (hdr->hdr_lba_table < 2 || hdr->hdr_lba_table >= last) { + printf("GEOM: hdr_lba_table (%llu) < 2 or >= last (%llu)" + "for %s.\n", (unsigned long long)hdr->hdr_lba_table, + (unsigned long long)last, pp->name); + if (geom_part_check_integrity) + goto fail; + } if (hdr->hdr_lba_table >= hdr->hdr_lba_start && - hdr->hdr_lba_table <= hdr->hdr_lba_end) - goto fail; + hdr->hdr_lba_table <= hdr->hdr_lba_end) { + printf("GEOM: hdr_lba_table (%llu) >= hdr_lba_start (%llu) " + "or hdr_lba_table <= hdr_lba_end(%llu) for %s.\n", + (unsigned long long)hdr->hdr_lba_table, + (unsigned long long)hdr->hdr_lba_start, + (unsigned long long)hdr->hdr_lba_end, + pp->name); + if (geom_part_check_integrity) + goto fail; + } lba = hdr->hdr_lba_table + howmany(hdr->hdr_entries * hdr->hdr_entsz, pp->sectorsize) - 1; - if (lba >= last) - goto fail; - if (lba >= hdr->hdr_lba_start && lba <= hdr->hdr_lba_end) - goto fail; + if (lba >= last) { + printf("GEOM: lba (%llu) >= last (%llu) for %s.\n", + (unsigned long long)lba, (unsigned long long)last, + pp->name); + if (geom_part_check_integrity) + goto fail; + } + if (lba >= hdr->hdr_lba_start && lba <= hdr->hdr_lba_end) { + printf("GEOM: lba (%llu) >= hdr_lba_start (%llu) " + "&& lba <= hdr_lba_end (%llu) for %s.\n", + (unsigned long long)lba, + (unsigned long long)hdr->hdr_lba_start, + (unsigned long long)hdr->hdr_lba_end, pp->name); + if (geom_part_check_integrity) + goto fail; + } table->state[elt] = GPT_STATE_OK; le_uuid_dec(&buf->hdr_uuid, &hdr->hdr_uuid); -- 2.32.0