summaryrefslogtreecommitdiffstats
path: root/sys/geom
diff options
context:
space:
mode:
authormav <mav@FreeBSD.org>2014-04-24 10:22:00 +0000
committermav <mav@FreeBSD.org>2014-04-24 10:22:00 +0000
commitc2e3819ca878695957fd074a79b0f1341f57860b (patch)
tree127b24304721e31d8d1d5c5bf32c59d55c3a2195 /sys/geom
parent7f430de4a19f2abf2e18cc65a2a7ecee505d61a3 (diff)
downloadFreeBSD-src-c2e3819ca878695957fd074a79b0f1341f57860b.zip
FreeBSD-src-c2e3819ca878695957fd074a79b0f1341f57860b.tar.gz
MFC r264318:
Fix wrong sizes used to access PD_Type and PD_State DDF metadata fields. This caused incorrect behavior of arrays with big-endian DDF metadata. Little-endian (like used by Adaptec controllers) should not be harmed. Add workaround should be enough to manage compatibility.
Diffstat (limited to 'sys/geom')
-rw-r--r--sys/geom/raid/md_ddf.c56
1 files changed, 39 insertions, 17 deletions
diff --git a/sys/geom/raid/md_ddf.c b/sys/geom/raid/md_ddf.c
index 4e1545b..63d767d 100644
--- a/sys/geom/raid/md_ddf.c
+++ b/sys/geom/raid/md_ddf.c
@@ -1182,6 +1182,28 @@ hdrerror:
g_free(buf);
if (GET32(meta, pdr->Signature) != DDF_PDR_SIGNATURE)
goto hdrerror;
+ /*
+ * Workaround for reading metadata corrupted due to graid bug.
+ * XXX: Remove this before we have disks above 128PB. :)
+ */
+ if (meta->bigendian) {
+ for (i = 0; i < GET16(meta, pdr->Populated_PDEs); i++) {
+ if (isff(meta->pdr->entry[i].PD_GUID, 24))
+ continue;
+ if (GET32(meta, pdr->entry[i].PD_Reference) ==
+ 0xffffffff)
+ continue;
+ if (GET64(meta, pdr->entry[i].Configured_Size) >=
+ (1ULL << 48)) {
+ SET16(meta, pdr->entry[i].PD_State,
+ GET16(meta, pdr->entry[i].PD_State) &
+ ~DDF_PDE_FAILED);
+ SET64(meta, pdr->entry[i].Configured_Size,
+ GET64(meta, pdr->entry[i].Configured_Size) &
+ ((1ULL << 48) - 1));
+ }
+ }
+ }
/* Read virtual disk records. */
buf = g_read_data(cp, (lba + GET32(meta, hdr->vdr_section)) * ss,
@@ -1711,7 +1733,7 @@ nofit:
/* Welcome the new disk. */
if (resurrection)
g_raid_change_disk_state(disk, G_RAID_DISK_S_ACTIVE);
- else if (GET8(gmeta, pdr->entry[md_pde_pos].PD_State) & DDF_PDE_PFA)
+ else if (GET16(gmeta, pdr->entry[md_pde_pos].PD_State) & DDF_PDE_PFA)
g_raid_change_disk_state(disk, G_RAID_DISK_S_FAILED);
else
g_raid_change_disk_state(disk, G_RAID_DISK_S_ACTIVE);
@@ -1730,11 +1752,11 @@ nofit:
/* Stale disk, almost same as new. */
g_raid_change_subdisk_state(sd,
G_RAID_SUBDISK_S_NEW);
- } else if (GET8(gmeta, pdr->entry[md_pde_pos].PD_State) & DDF_PDE_PFA) {
+ } else if (GET16(gmeta, pdr->entry[md_pde_pos].PD_State) & DDF_PDE_PFA) {
/* Failed disk. */
g_raid_change_subdisk_state(sd,
G_RAID_SUBDISK_S_FAILED);
- } else if ((GET8(gmeta, pdr->entry[md_pde_pos].PD_State) &
+ } else if ((GET16(gmeta, pdr->entry[md_pde_pos].PD_State) &
(DDF_PDE_FAILED | DDF_PDE_REBUILD)) != 0) {
/* Rebuilding disk. */
g_raid_change_subdisk_state(sd,
@@ -2833,24 +2855,24 @@ g_raid_md_write_ddf(struct g_raid_md_object *md, struct g_raid_volume *tvol,
GET32(vmeta, bvdc[bvd]->Physical_Disk_Sequence[pos]));
if (j < 0)
continue;
- SET32(gmeta, pdr->entry[j].PD_Type,
- GET32(gmeta, pdr->entry[j].PD_Type) |
+ SET16(gmeta, pdr->entry[j].PD_Type,
+ GET16(gmeta, pdr->entry[j].PD_Type) |
DDF_PDE_PARTICIPATING);
if (sd->sd_state == G_RAID_SUBDISK_S_NONE)
- SET32(gmeta, pdr->entry[j].PD_State,
- GET32(gmeta, pdr->entry[j].PD_State) |
+ SET16(gmeta, pdr->entry[j].PD_State,
+ GET16(gmeta, pdr->entry[j].PD_State) |
(DDF_PDE_FAILED | DDF_PDE_MISSING));
else if (sd->sd_state == G_RAID_SUBDISK_S_FAILED)
- SET32(gmeta, pdr->entry[j].PD_State,
- GET32(gmeta, pdr->entry[j].PD_State) |
+ SET16(gmeta, pdr->entry[j].PD_State,
+ GET16(gmeta, pdr->entry[j].PD_State) |
(DDF_PDE_FAILED | DDF_PDE_PFA));
else if (sd->sd_state <= G_RAID_SUBDISK_S_REBUILD)
- SET32(gmeta, pdr->entry[j].PD_State,
- GET32(gmeta, pdr->entry[j].PD_State) |
+ SET16(gmeta, pdr->entry[j].PD_State,
+ GET16(gmeta, pdr->entry[j].PD_State) |
DDF_PDE_REBUILD);
else
- SET32(gmeta, pdr->entry[j].PD_State,
- GET32(gmeta, pdr->entry[j].PD_State) |
+ SET16(gmeta, pdr->entry[j].PD_State,
+ GET16(gmeta, pdr->entry[j].PD_State) |
DDF_PDE_ONLINE);
}
}
@@ -2863,8 +2885,8 @@ g_raid_md_write_ddf(struct g_raid_md_object *md, struct g_raid_volume *tvol,
if (i < 0)
continue;
if (disk->d_state == G_RAID_DISK_S_FAILED) {
- SET32(gmeta, pdr->entry[i].PD_State,
- GET32(gmeta, pdr->entry[i].PD_State) |
+ SET16(gmeta, pdr->entry[i].PD_State,
+ GET16(gmeta, pdr->entry[i].PD_State) |
(DDF_PDE_FAILED | DDF_PDE_PFA));
}
if (disk->d_state != G_RAID_DISK_S_SPARE)
@@ -2881,8 +2903,8 @@ g_raid_md_write_ddf(struct g_raid_md_object *md, struct g_raid_volume *tvol,
GET16(gmeta, pdr->entry[i].PD_Type) |
DDF_PDE_CONFIG_SPARE);
}
- SET32(gmeta, pdr->entry[i].PD_State,
- GET32(gmeta, pdr->entry[i].PD_State) |
+ SET16(gmeta, pdr->entry[i].PD_State,
+ GET16(gmeta, pdr->entry[i].PD_State) |
DDF_PDE_ONLINE);
}
OpenPOWER on IntegriCloud