Author: mav
Date: Thu Apr 24 10:23:11 2014
New Revision: 264869
URL: http://svnweb.freebsd.org/changeset/base/264869

Log:
  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.

Modified:
  stable/9/sys/geom/raid/md_ddf.c
Directory Properties:
  stable/9/   (props changed)
  stable/9/sys/   (props changed)

Modified: stable/9/sys/geom/raid/md_ddf.c
==============================================================================
--- stable/9/sys/geom/raid/md_ddf.c     Thu Apr 24 10:22:00 2014        
(r264868)
+++ stable/9/sys/geom/raid/md_ddf.c     Thu Apr 24 10:23:11 2014        
(r264869)
@@ -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,
@@ -2832,24 +2854,24 @@ g_raid_md_write_ddf(struct g_raid_md_obj
                            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);
                }
        }
@@ -2862,8 +2884,8 @@ g_raid_md_write_ddf(struct g_raid_md_obj
                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)
@@ -2880,8 +2902,8 @@ g_raid_md_write_ddf(struct g_raid_md_obj
                            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);
        }
 
_______________________________________________
svn-src-stable-9@freebsd.org mailing list
http://lists.freebsd.org/mailman/listinfo/svn-src-stable-9
To unsubscribe, send any mail to "svn-src-stable-9-unsubscr...@freebsd.org"

Reply via email to