RAID-6 Support

Virtual Images (VIM files)

VIM-Support For RAID-6 Schemes

RAID Reconstructor does not directly support RAID-6 arrays, so it will not automatically retrieve a RAID-6 configuration. However, with some knowledge about your RAID-6, you can build a Virtual Image (VIM file) that allows you to rebuild the RAID-6 after the failure of up to two drives. Our entire lineup of data recovery software supports Virtual Images. Once you've made a VIM file, you can use it to mount, clone, image, or recover data from your reconstructed RAID-6. At this time, the following software versions support VIM files for RAID-6: DiskExplorer X V2.01, GetDataBack Pro V5.63, RAID Reconstructor V5.13, DriveMap V0.11 BETA, DriveDoppel V0.91 BETA.

Runtime's Virtual Images support two distinct RAID-6 schemes. The first one is a pure XOR-based scheme, where drives are XOR-ed in multiple ways to make the array resilient against the failure of up to two drives. We will look at a real-world example of a RAID-6 consisting of 4 drives on an Adaptec AIC-9405W controller.

The second scheme is a Reed-Solomon implementation using one drive for RAID-5 style XOR-parity and a second for the Reed-Solomon parity. We will look at an example of a 6-drive RAID-6 on a RocketRaid 4520SGL controller.

For both RAID-6 schemes, we will show you how to build the VIM file to reconstruct the array after the failure of 0, 1, or 2 drives.

XOR-Based RAID-6 Scheme

This scheme uses XOR only and is, therefore, easy to analyze. The RAID controller chooses data and parity blocks so that they are all scattered across the drives, horizontally and vertically, ensuring you can recover from a 2-drive failure. 

    Horizontal and Vertical XOR

  • Multiple XOR-Based
    Example: RAID-6, 4 drives, block size 128 on Adaptec AIC-9405W
    Local drive
    sector*)\
    Drive 1 Drive 2 Drive 3 Drive 4 Cycle Stripe
    0-127 B1 **) B2 B3 B4 0 0
    128-255  P1***)  P2  P3  P4 1
    256-383 B5 B6 B7 B8 1 0
    384-511  P5  P6  P7  P8 1
     :  :  :  :  :  :  :
    *) Sectors, cycles, and stripes are 0-based,
    blocks and drives are 1-based
    **) Blocks B1, B2, B3, B4, ... are data in the
    1st 128 global sectors (0-127),
    2nd 128 global sectors (128-255),
    3rd 128 global sectors (256-383),
    4th 128 global sectors (384-511), etc.
    ***) P1 is parity for the blocks B3,B4,
    P2 is parity for the blocks B1,B4,
    P3 is parity for the blocks B1,B2,
    P4 is parity for the blocks B2,B3, within the previous stripe.

    Stripes alternate between pure data blocks and parity blocks:
        B3 xor B4 => P1
        B1 xor B4 => P2
        B1 xor B2 => P3
        B2 xor B3 => P4

    These parities ensure that even the loss of any two drives can be mitigated. If, for example, drive 1 and drive 2 fail, you can rebuild B2 from B3 xor P4, and then B1 from B2 xor P3.

  • VIM for extracting the data using all drives:

  • <virtualimage>
      <loop>
        <drive>...ada_1.img:</drive>
        <drive>...ada_2.img:</drive>
        <drive>...ada_3.img:</drive>
        <drive>...ada_4.img:</drive>
        <cycle blocksize="128">
          <stripe>1,2,3,4</stripe>
          <stripe></stripe>
        </cycle>
      </loop>
    </virtualimage>

    If no drive is missing, we can simply get the data from the data blocks of each stripe.

    The first stripe retrieves 128 sectors from each drive in the order drives 1, 2, 3, and 4. The next stripe is empty, containing only the parities we do not need. The empty stripe increases the sector counter by 128 to 256, so the first stripe in the next cycle iteration returns data from drives 1, 2, 3, and 4 again.

  • VIM for extracting the data after failure of one drive:

  • <virtualimage>
      <loop>
        <drive>...ada_1.img:</drive>
        <drive>...ada_2.img:</drive>
        <drive>...ada_3.img:</drive>
        <drive>...ada_4.img:</drive>
        <cycle blocksize="128">
          <stripe>2x3(1),2,3,4</stripe>
          <stripe></stripe>
        </cycle>
      </loop>
    </virtualimage>

    Assuming drive 1 is missing, we can recreate the drive by replacing the occurrence of drive 1 with B2 xor P3.

    As P3 is in the next stripe, we must peek ahead in our stripe expression. This is realized with 3(1), which indicates "drive 3 one stripe ahead". Our stripe expression 2x3(1),2,3,4 retrieves 128 sectors from drive 2, xors this with the content of drive 3 at 128 sectors ahead, and then collects the remaining drives 2, 3, and 4. The next stripe is empty again, as we already collected what we need with the peek-ahead. The empty stripe increases the sector counter by 128 to 256, so the first stripe in the next cycle iteration returns data from 2x3(1),2,3,4 again.

  • VIM for extracting the data after the failure of two drives:

  • <virtualimage>
      <loop>
        <drive>...ada_1.img:</drive>
        <drive>...ada_2.img:</drive>
        <drive>...ada_3.img:</drive>
        <drive>...ada_4.img:</drive>
        <cycle blocksize="128">
          <stripe>3x4(1)x3(1),3x4(1),3,4
    </stripe>
          <stripe></stripe>
        </cycle>
      </loop>
    </virtualimage>

    Assuming drives 1 and 2 are missing, we can recreate the drives by replacing the occurrences of drive 2 with B3 xor P4, and drive 1 with B2 xor P3

    As P3 and P4 are in the next stripe, we must again peek ahead in our stripe expression. This is realized with 3(1) and 4(1), which indicate "drive 3 one stripe ahead" and "drive 4 one stripe ahead", respectively. Our stripe expression 3x4(1)x3(1),3x4(1),3,4 retrieves drive 2 using 3x4(1), and drive 1 using the just retrieved drive 2 xor-ed with 3x4(1).

    The next stripe is empty again, as we already collected what we need with the peek-ahead. The empty stripe increases the sector counter by 128 to 256, so the first stripe in the next cycle iteration returns data from 3x4(1)x3(1),3x4(1),3,4 again.

Reed-Solomon RAID-6 Scheme

This scheme employs two distinct parity algorithms for data blocks, XOR and Reed-Solomon error correction, allowing for a 2-drive redundancy. RS is elegant, allowing both parity blocks, P and R, to rotate across the drives without storing the parity blocks in special stripes. On the other hand, RS is more complicated to calculate than XOR. RS is not commutative, while XOR is.

    Reed-Solomon Error Correction

  • Reed-Solomon and XOR-Based
    Example: RAID-6, 6 drives, block size 128 on a RocketRaid 4520SGL controller
    Local drive
    sector*)\
    Drive 1 Drive 2 Drive 3 Drive 4 Drive 5 Drive 6 Cycle Stripe
    0-127 B1 **) B2 B3 B4  P   R  0 0
    128-255 B5 B6 B7  P   R  B8 1
    256-383 B9 B10  P   R  B11 B12 2
    384-511 B13  P   R  B14 B15 B16 3
    512-639  P   R  B17 B18 B19 B20 4
    640-767  R  B21 B22 B23 B24  P  5
    768-895 B25 B26 B27 B28  P   R  1 0
    896-1023 B29 B30 B31  P   R  B32 1
     :  :  :  :  :  :  :  :  :
    *) Sectors, cycles, and stripes are 0-based,
    blocks and drives are 1-based
    **) Blocks B1, B2, B3, B4, ... are data in the
    1st 128 global sectors (0-127),
    2nd 128 global sectors (128-255),
    3rd 128 global sectors (256-383),
    4th 128 global sectors (384-511), etc.

    All relations between data and parity blocks are expressed within the same stripe. There is no peek-ahead as in the previous scheme. Here are the relationships:

    Stripe 0
      B1 xor B2 xor B3 xor B4 => P
      B1 rs B2 rs B3 rs B4 => R
    Stripe 1
      B5 xor B6 xor B7 xor B8 => P
      B5 rs B6 rs B7 rs B8 => R
    Stripe 2
      B9 xor B10 xor B11 xor B12 => P
      B9 rs B10 rs B11 rs B12 => R
    etc.

    As you can see, single-drive failures can easily be resolved using P. If you need to recover from a two-drive loss, you will need R as well. We will later show how to incorporate both operations, XOR and RS, into a VIM file.

  • VIM for extracting the data using all drives:

  • <virtualimage>
      <loop>
        <drive>...high_1.img:</drive>
        <drive>...high_2.img:</drive>
        <drive>...high_3.img:</drive>
        <drive>...high_4.img:</drive>
        <drive>...high_5.img:</drive>
        <drive>...high_6.img:</drive>
        <cycle blocksize="128">
          <stripe>1,2,3,4</stripe>
          <stripe>1,2,3,6</stripe>
          <stripe>1,2,5,6</stripe>
          <stripe>1,4,5,6</stripe>
          <stripe>3,4,5,6</stripe>
          <stripe>2,3,4,5</stripe>
        </cycle>
      </loop>
    </virtualimage>

    If no drive is missing, we can simply get the data from the data blocks of each stripe. Refer to the Reed-Solomon rotation table to determine the data drives for each stripe: they are 1,2,3,4 for stripe 0, 1,2,3,6 for stripe 1, 1,2,5,6 for stripe 2, 1,4,5,6 for stripe 3, 3,4,5,6 for stripe 4, and 2,3,4,5 for stripe 5.

    These 6 vectors are exactly, what you see in this VIM file.

  • VIM for extracting the data after failure of one drive using parity:

  • <virtualimage>
      <loop>
        <drive>...high_1.img:</drive>
        <drive>...high_2.img:</drive>
        <drive>...high_3.img:</drive>
        <drive>...high_4.img:</drive>
        <drive>...high_5.img:</drive>
        <drive>...high_6.img:</drive>
        <cycle blocksize="128">
          <stripe>2x3x4x5,2,3,4</stripe>
          <stripe>2x3x4x6,2,3,6</stripe>
          <stripe>2x3x5x6,2,5,6</stripe>
          <stripe>2x4x5x6,4,5,6</stripe>
          <stripe>3,4,5,6</stripe>
          <stripe>2,3,4,5</stripe>
        </cycle>
      </loop>
    </virtualimage>

    If one drive is missing, we can recreate it by simply applying the parity P. In practice, we xor P with the surviving data drives

    Assuming drive 1 is missing, let's write up the 6 vectors for our stripes. Look at the rotation table, stripe 0: from drive 1 to drive 6, the data and parity drives are ordered DDDDPR. We can replace the missing drive 1 with 2x3x4x5. Drives 2, 3, and 4 are the remaining data drives and P is the XOR-parity drive of this stripe.

    Stripe 0:
        D,D,D,D,P,R -> 1,2,3,4,5,6 --(replace 1 with 2x3x4x5)-> 2x3x4x5,2,3,4
    Stripe 1:
        D,D,D,P,R,D -> 1,2,3,4,5,6 --(replace 1 with 2x3x4x6)-> 2x3x4x6,2,3,6
    Stripe 2:
        D,D,P,R,D,D -> 1,2,3,4,5,6 --(replace 1 with 2x3x5x6)-> 2x3x5x6,2,5,6
    Stripe 3:
        D,P,R,D,D,D -> 1,2,3,4,5,6 --(replace 1 with 2x4x5x6)-> 2x4x5x6,4,5,6
    Stripe 4:
        P,R,D,D,D,D -> 1,2,3,4,5,6 --(no replacement)-> 3,4,5,6
    Stripe 5:
        R,D,D,D,D,P -> 1,2,3,4,5,6 --(no replacement)-> 2,3,4,5 

    The 6 vectors on the right-hand side are our stripe descriptions in the VIM file.

  • VIM for extracting the data after failure of one drive using Reed-Solomon:

  • <virtualimage>
      <loop>
        <drive>...high_1.img:</drive>
        <drive>...high_2.img:</drive>
        <drive>...high_3.img:</drive>
        <drive>...high_4.img:</drive>
        <drive>...high_5.img:</drive>
        <drive>...high_6.img:</drive>
        <cycle blocksize="128">
          <stripe>?r2r3r4r5r6,2,3,4</stripe>
          <stripe>?r2r3r6r4r5,2,3,6</stripe>
          <stripe>?r2r5r6r3r4,2,5,6</stripe>
          <stripe>?r4r5r6r2r3,4,5,6</stripe>
          <stripe>3,4,5,6</stripe>
          <stripe>2,3,4,5</stripe>
        </cycle>
      </loop>
    </virtualimage>

    We can also recover from a single-drive failure using the Reed-Solomon algorithm RS. We define RS as a function on all drives, available or not, in the correct order:
    RS(D,D,D,D,P,R). For use in the VIM file, we write this as DrDrDrDrPrR. Look at the rotation table to replace the parameters with the correct drive number:

        Stripe 0: RS(1,2,3,4,5,6) -> 1r2r3r4r5r6
        Stripe 1: RS(1,2,3,6,4,5) -> 1r2r3r6r4r5
        Stripe 2: RS(1,2,5,6,3,4) -> 1r2r5r6r3r4
        Stripe 3: RS(1,4,5,6,2,3) -> 1r4r5r6r2r3
        Stripe 4: RS(3,4,5,6,1,2) -> 3r4r5r6r1r2
        Stripe 5: RS(2,3,4,5,6,1) -> 2r3r4r5r6r1

    Assuming drive 1 is missing, we replace the leftmost drive descriptor with the RS descriptor for the first 4 stripes. The last 2 stripes, again, do not require us to reconstruct anything. Before inserting the RS descriptor, replace the missing drive with a ?. This indicates which output we need. For stripe 0, 1r2r3r4r5r6 becomes ?r2r3r4r5r6.

  • VIM for extracting the data after the failure of two drives:

  • <virtualimage>
      <loop>
        <drive>...high_1.img:</drive>
        <drive>...high_2.img:</drive>
        <drive>...high_3.img:</drive>
        <drive>...high_4.img:</drive>
        <drive>...high_5.img:</drive>
        <drive>...high_6.img:</drive>
        <cycle blocksize="128">
          <stripe>!r?r3r4r5r6,?r!r3r4r5r6,3,4</stripe>
          <stripe>!r?r3r6r4r5,?r!r3r6r4r5,3,6</stripe>
          <stripe>!r?r5r6r3r4,?r!r5r6r3r4,5,6</stripe>
          <stripe>!r4r5r6r?r3,4,5,6</stripe>
          <stripe>3,4,5,6</stripe>
          <stripe>3x4x5x6,3,4,5</stripe>
        </cycle>
      </loop>
    </virtualimage>

    In this paragraph, we will put it all together: XOR and RS to recover after a two-drive failure.

    Assuming drives 1 and 2 are missing, we will need to replace drive descriptors 1 and 2 in stripe 0. According to the previous paragraph, the RS function for stripe 0 is 1r2r3r4r5r6. Use ? and ! for the missing drives, ! being the drive you want to calculate. For stripe 1 the RS function is 1r2r3r6r4r5 and the descriptors for drives 1 and 2 are !r?r3r6r4r5 and ?r!r3r6r4r5, respectively. Here are the complete vectors for all stripes:

        Stripe 0: 1r2r3r4r5r6 => 1,2,3,4 => !r?r3r4r5r6,?r!r3r4r5r6,3,4
        Stripe 1: 1r2r3r6r4r5 => 1,2,3,6 => !r?r3r6r4r5,?r!r3r6r4r5,3,6
        Stripe 2: 1r2r5r6r3r4 => 1,2,5,6 => !r?r5r6r3r4,?r!r5r6r3r4,5,6
        Stripe 3: 1r4r5r6r2r3 => 1,4,5,6 => !r4r5r6r?r3,4,5,6
        Stripe 4: 3r4r5r6r1r2 => 3,4,5,6 => 3,4,5,6
        Stripe 5: 2r3r4r5r6r1 => 2,3,4,5 => 3x4x5x6,3,4,5 (or !r3r4r5r6r?,3,4,5)

© 2024 Runtime Software