recov.c 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133
  1. /* -*- linux-c -*- ------------------------------------------------------- *
  2. *
  3. * Copyright 2002 H. Peter Anvin - All Rights Reserved
  4. *
  5. * This program is free software; you can redistribute it and/or modify
  6. * it under the terms of the GNU General Public License as published by
  7. * the Free Software Foundation, Inc., 53 Temple Place Ste 330,
  8. * Boston MA 02111-1307, USA; either version 2 of the License, or
  9. * (at your option) any later version; incorporated herein by reference.
  10. *
  11. * ----------------------------------------------------------------------- */
  12. /*
  13. * raid6/recov.c
  14. *
  15. * RAID-6 data recovery in dual failure mode. In single failure mode,
  16. * use the RAID-5 algorithm (or, in the case of Q failure, just reconstruct
  17. * the syndrome.)
  18. */
  19. #include <linux/raid/pq.h>
  20. /* Recover two failed data blocks. */
  21. void raid6_2data_recov(int disks, size_t bytes, int faila, int failb,
  22. void **ptrs)
  23. {
  24. u8 *p, *q, *dp, *dq;
  25. u8 px, qx, db;
  26. const u8 *pbmul; /* P multiplier table for B data */
  27. const u8 *qmul; /* Q multiplier table (for both) */
  28. p = (u8 *)ptrs[disks-2];
  29. q = (u8 *)ptrs[disks-1];
  30. /* Compute syndrome with zero for the missing data pages
  31. Use the dead data pages as temporary storage for
  32. delta p and delta q */
  33. dp = (u8 *)ptrs[faila];
  34. ptrs[faila] = (void *)raid6_empty_zero_page;
  35. ptrs[disks-2] = dp;
  36. dq = (u8 *)ptrs[failb];
  37. ptrs[failb] = (void *)raid6_empty_zero_page;
  38. ptrs[disks-1] = dq;
  39. raid6_call.gen_syndrome(disks, bytes, ptrs);
  40. /* Restore pointer table */
  41. ptrs[faila] = dp;
  42. ptrs[failb] = dq;
  43. ptrs[disks-2] = p;
  44. ptrs[disks-1] = q;
  45. /* Now, pick the proper data tables */
  46. pbmul = raid6_gfmul[raid6_gfexi[failb-faila]];
  47. qmul = raid6_gfmul[raid6_gfinv[raid6_gfexp[faila]^raid6_gfexp[failb]]];
  48. /* Now do it... */
  49. while ( bytes-- ) {
  50. px = *p ^ *dp;
  51. qx = qmul[*q ^ *dq];
  52. *dq++ = db = pbmul[px] ^ qx; /* Reconstructed B */
  53. *dp++ = db ^ px; /* Reconstructed A */
  54. p++; q++;
  55. }
  56. }
  57. EXPORT_SYMBOL_GPL(raid6_2data_recov);
  58. /* Recover failure of one data block plus the P block */
  59. void raid6_datap_recov(int disks, size_t bytes, int faila, void **ptrs)
  60. {
  61. u8 *p, *q, *dq;
  62. const u8 *qmul; /* Q multiplier table */
  63. p = (u8 *)ptrs[disks-2];
  64. q = (u8 *)ptrs[disks-1];
  65. /* Compute syndrome with zero for the missing data page
  66. Use the dead data page as temporary storage for delta q */
  67. dq = (u8 *)ptrs[faila];
  68. ptrs[faila] = (void *)raid6_empty_zero_page;
  69. ptrs[disks-1] = dq;
  70. raid6_call.gen_syndrome(disks, bytes, ptrs);
  71. /* Restore pointer table */
  72. ptrs[faila] = dq;
  73. ptrs[disks-1] = q;
  74. /* Now, pick the proper data tables */
  75. qmul = raid6_gfmul[raid6_gfinv[raid6_gfexp[faila]]];
  76. /* Now do it... */
  77. while ( bytes-- ) {
  78. *p++ ^= *dq = qmul[*q ^ *dq];
  79. q++; dq++;
  80. }
  81. }
  82. EXPORT_SYMBOL_GPL(raid6_datap_recov);
  83. #ifndef __KERNEL__
  84. /* Testing only */
  85. /* Recover two failed blocks. */
  86. void raid6_dual_recov(int disks, size_t bytes, int faila, int failb, void **ptrs)
  87. {
  88. if ( faila > failb ) {
  89. int tmp = faila;
  90. faila = failb;
  91. failb = tmp;
  92. }
  93. if ( failb == disks-1 ) {
  94. if ( faila == disks-2 ) {
  95. /* P+Q failure. Just rebuild the syndrome. */
  96. raid6_call.gen_syndrome(disks, bytes, ptrs);
  97. } else {
  98. /* data+Q failure. Reconstruct data from P,
  99. then rebuild syndrome. */
  100. /* NOT IMPLEMENTED - equivalent to RAID-5 */
  101. }
  102. } else {
  103. if ( failb == disks-2 ) {
  104. /* data+P failure. */
  105. raid6_datap_recov(disks, bytes, faila, ptrs);
  106. } else {
  107. /* data+data failure. */
  108. raid6_2data_recov(disks, bytes, faila, failb, ptrs);
  109. }
  110. }
  111. }
  112. #endif