Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-or-later
0002 /* -*- linux-c -*- ------------------------------------------------------- *
0003  *
0004  *   Copyright 2002 H. Peter Anvin - All Rights Reserved
0005  *
0006  * ----------------------------------------------------------------------- */
0007 
0008 /*
0009  * raid6/recov.c
0010  *
0011  * RAID-6 data recovery in dual failure mode.  In single failure mode,
0012  * use the RAID-5 algorithm (or, in the case of Q failure, just reconstruct
0013  * the syndrome.)
0014  */
0015 
0016 #include <linux/export.h>
0017 #include <linux/raid/pq.h>
0018 
0019 /* Recover two failed data blocks. */
0020 static void raid6_2data_recov_intx1(int disks, size_t bytes, int faila,
0021         int failb, void **ptrs)
0022 {
0023     u8 *p, *q, *dp, *dq;
0024     u8 px, qx, db;
0025     const u8 *pbmul;    /* P multiplier table for B data */
0026     const u8 *qmul;     /* Q multiplier table (for both) */
0027 
0028     p = (u8 *)ptrs[disks-2];
0029     q = (u8 *)ptrs[disks-1];
0030 
0031     /* Compute syndrome with zero for the missing data pages
0032        Use the dead data pages as temporary storage for
0033        delta p and delta q */
0034     dp = (u8 *)ptrs[faila];
0035     ptrs[faila] = (void *)raid6_empty_zero_page;
0036     ptrs[disks-2] = dp;
0037     dq = (u8 *)ptrs[failb];
0038     ptrs[failb] = (void *)raid6_empty_zero_page;
0039     ptrs[disks-1] = dq;
0040 
0041     raid6_call.gen_syndrome(disks, bytes, ptrs);
0042 
0043     /* Restore pointer table */
0044     ptrs[faila]   = dp;
0045     ptrs[failb]   = dq;
0046     ptrs[disks-2] = p;
0047     ptrs[disks-1] = q;
0048 
0049     /* Now, pick the proper data tables */
0050     pbmul = raid6_gfmul[raid6_gfexi[failb-faila]];
0051     qmul  = raid6_gfmul[raid6_gfinv[raid6_gfexp[faila]^raid6_gfexp[failb]]];
0052 
0053     /* Now do it... */
0054     while ( bytes-- ) {
0055         px    = *p ^ *dp;
0056         qx    = qmul[*q ^ *dq];
0057         *dq++ = db = pbmul[px] ^ qx; /* Reconstructed B */
0058         *dp++ = db ^ px; /* Reconstructed A */
0059         p++; q++;
0060     }
0061 }
0062 
0063 /* Recover failure of one data block plus the P block */
0064 static void raid6_datap_recov_intx1(int disks, size_t bytes, int faila,
0065         void **ptrs)
0066 {
0067     u8 *p, *q, *dq;
0068     const u8 *qmul;     /* Q multiplier table */
0069 
0070     p = (u8 *)ptrs[disks-2];
0071     q = (u8 *)ptrs[disks-1];
0072 
0073     /* Compute syndrome with zero for the missing data page
0074        Use the dead data page as temporary storage for delta q */
0075     dq = (u8 *)ptrs[faila];
0076     ptrs[faila] = (void *)raid6_empty_zero_page;
0077     ptrs[disks-1] = dq;
0078 
0079     raid6_call.gen_syndrome(disks, bytes, ptrs);
0080 
0081     /* Restore pointer table */
0082     ptrs[faila]   = dq;
0083     ptrs[disks-1] = q;
0084 
0085     /* Now, pick the proper data tables */
0086     qmul  = raid6_gfmul[raid6_gfinv[raid6_gfexp[faila]]];
0087 
0088     /* Now do it... */
0089     while ( bytes-- ) {
0090         *p++ ^= *dq = qmul[*q ^ *dq];
0091         q++; dq++;
0092     }
0093 }
0094 
0095 
0096 const struct raid6_recov_calls raid6_recov_intx1 = {
0097     .data2 = raid6_2data_recov_intx1,
0098     .datap = raid6_datap_recov_intx1,
0099     .valid = NULL,
0100     .name = "intx1",
0101     .priority = 0,
0102 };
0103 
0104 #ifndef __KERNEL__
0105 /* Testing only */
0106 
0107 /* Recover two failed blocks. */
0108 void raid6_dual_recov(int disks, size_t bytes, int faila, int failb, void **ptrs)
0109 {
0110     if ( faila > failb ) {
0111         int tmp = faila;
0112         faila = failb;
0113         failb = tmp;
0114     }
0115 
0116     if ( failb == disks-1 ) {
0117         if ( faila == disks-2 ) {
0118             /* P+Q failure.  Just rebuild the syndrome. */
0119             raid6_call.gen_syndrome(disks, bytes, ptrs);
0120         } else {
0121             /* data+Q failure.  Reconstruct data from P,
0122                then rebuild syndrome. */
0123             /* NOT IMPLEMENTED - equivalent to RAID-5 */
0124         }
0125     } else {
0126         if ( failb == disks-2 ) {
0127             /* data+P failure. */
0128             raid6_datap_recov(disks, bytes, faila, ptrs);
0129         } else {
0130             /* data+data failure. */
0131             raid6_2data_recov(disks, bytes, faila, failb, ptrs);
0132         }
0133     }
0134 }
0135 
0136 #endif