summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authormarcel <marcel@FreeBSD.org>2006-08-09 20:53:01 +0000
committermarcel <marcel@FreeBSD.org>2006-08-09 20:53:01 +0000
commit52f0123d8d942ca90e4c373f24453d26a5f28126 (patch)
tree06d636d8373dfb18c974043645e7da6d92f50956
parent50f9d9396bdc77c4f6fd0d9fd239468731059258 (diff)
downloadFreeBSD-src-52f0123d8d942ca90e4c373f24453d26a5f28126.zip
FreeBSD-src-52f0123d8d942ca90e4c373f24453d26a5f28126.tar.gz
Strengthen the check for a PMBR:
o PMBR partitions count to the number of partitions on the disk, which means that if a PMBR entry is invalid we will not treat the MBR as a PMBR by virtue of it not describing any partitions. Previously the checks were inconsistent in that an invalid PMBR entry would be harmless when no other partitions exist (we would treat the MBR as a PMBR by virtue of it being empty), but it would be fatal when there is at least one other partition. o The partition size of a PMBR partition is one less than the media size because the GPT starts at the second sector (LBA 1) and extends to the end of the media. For backward bug-compatibility we accept a size that's exactly the media size (FreeBSD bug). Also, when the partition size can not be represented in a 32-bit integral, the partition size in the MBR is to be set to 0xFFFFFFFF. Accept this as a valid size, even if the size can be represented.
-rw-r--r--sys/geom/geom_gpt.c53
1 files changed, 35 insertions, 18 deletions
diff --git a/sys/geom/geom_gpt.c b/sys/geom/geom_gpt.c
index 92b8371..06ab0b8 100644
--- a/sys/geom/geom_gpt.c
+++ b/sys/geom/geom_gpt.c
@@ -360,16 +360,17 @@ g_gpt_has_pmbr(struct g_consumer *cp, int *error)
{
char *buf;
uint8_t *typ;
- int i, pmbr, vmbr;
- uint16_t magic;
+ uint64_t mediasize;
+ int i, pmbr, parts;
uint32_t dp_start, dp_size;
+ uint16_t magic;
buf = g_read_data(cp, 0L, cp->provider->sectorsize, error);
if (buf == NULL)
return (0);
pmbr = 0;
- vmbr = 0;
+ *error = 0;
magic = le16toh(*(uint16_t *)(uintptr_t)(buf + DOSMAGICOFFSET));
if (magic != DOSMAGIC)
@@ -379,31 +380,45 @@ g_gpt_has_pmbr(struct g_consumer *cp, int *error)
* Check that there are at least one partition of type
* DOSPTYP_PMBR that covers the whole unit.
*/
+ parts = 0;
+ mediasize = cp->provider->mediasize / cp->provider->sectorsize;
for (i = 0; i < 4; i++) {
typ = buf + DOSPARTOFF + i * sizeof(struct dos_partition) +
offsetof(struct dos_partition, dp_typ);
+ if (*typ != 0)
+ parts++;
+ if (*typ != DOSPTYP_PMBR)
+ continue;
+
bcopy(buf + DOSPARTOFF + i * sizeof(struct dos_partition) +
- offsetof(struct dos_partition, dp_start), &dp_start, sizeof(dp_start));
+ offsetof(struct dos_partition, dp_start), &dp_start,
+ sizeof(dp_start));
+ if (le32toh(dp_start) != 1)
+ break;
+
bcopy(buf + DOSPARTOFF + i * sizeof(struct dos_partition) +
- offsetof(struct dos_partition, dp_size), &dp_size, sizeof(dp_size));
- if ((*typ == DOSPTYP_PMBR) &&
- (le32toh(dp_start) == 1) &&
- (cp->provider->mediasize ==
- (le32toh(dp_size) * 512ULL))) {
- pmbr = 1;
+ offsetof(struct dos_partition, dp_size), &dp_size,
+ sizeof(dp_size));
+ if (le32toh(dp_size) != ~0U &&
+ le32toh(dp_size) != mediasize - 1 &&
+ /* Catch old FreeBSD bug for backward compatibility. */
+ le32toh(dp_size) != mediasize)
break;
- }
- if (*typ != 0 && *typ != DOSPTYP_PMBR)
- vmbr = 1;
+
+ pmbr = 1;
}
-out:
- g_free(buf);
/*
- * Return true if protective MBR is detected or if MBR has
- * no valid entries at all.
+ * Treat empty MBRs as PMBRs for increased flexibility. Note that an
+ * invalid entry of type DOSPTYP_PMBR counts towards the number of
+ * partitions and will prevent the MBR from being treated as a PMBR.
*/
- return (pmbr || !vmbr);
+ if (!pmbr && parts == 0)
+ pmbr = 1;
+
+out:
+ g_free(buf);
+ return (pmbr);
}
static void
@@ -1013,6 +1028,8 @@ g_gpt_taste(struct g_class *mp, struct g_provider *pp, int insist __unused)
* is none and fail.
*/
if (!g_gpt_has_pmbr(cp, &error)) {
+ if (error != 0)
+ goto fail;
printf("GEOM: %s: GPT detected, but no protective MBR.\n",
pp->name);
error = ENXIO;
OpenPOWER on IntegriCloud