recov.c 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142
  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/export.h>
  20. #include <linux/raid/pq.h>
  21. /* Recover two failed data blocks. */
  22. static void raid6_2data_recov_intx1(int disks, size_t bytes, int faila,
  23. int failb, void **ptrs)
  24. {
  25. u8 *p, *q, *dp, *dq;
  26. u8 px, qx, db;
  27. const u8 *pbmul; /* P multiplier table for B data */
  28. const u8 *qmul; /* Q multiplier table (for both) */
  29. p = (u8 *)ptrs[disks-2];
  30. q = (u8 *)ptrs[disks-1];
  31. /* Compute syndrome with zero for the missing data pages
  32. Use the dead data pages as temporary storage for
  33. delta p and delta q */
  34. dp = (u8 *)ptrs[faila];
  35. ptrs[faila] = (void *)raid6_empty_zero_page;
  36. ptrs[disks-2] = dp;
  37. dq = (u8 *)ptrs[failb];
  38. ptrs[failb] = (void *)raid6_empty_zero_page;
  39. ptrs[disks-1] = dq;
  40. raid6_call.gen_syndrome(disks, bytes, ptrs);
  41. /* Restore pointer table */
  42. ptrs[faila] = dp;
  43. ptrs[failb] = dq;
  44. ptrs[disks-2] = p;
  45. ptrs[disks-1] = q;
  46. /* Now, pick the proper data tables */
  47. pbmul = raid6_gfmul[raid6_gfexi[failb-faila]];
  48. qmul = raid6_gfmul[raid6_gfinv[raid6_gfexp[faila]^raid6_gfexp[failb]]];
  49. /* Now do it... */
  50. while ( bytes-- ) {
  51. px = *p ^ *dp;
  52. qx = qmul[*q ^ *dq];
  53. *dq++ = db = pbmul[px] ^ qx; /* Reconstructed B */
  54. *dp++ = db ^ px; /* Reconstructed A */
  55. p++; q++;
  56. }
  57. }
  58. /* Recover failure of one data block plus the P block */
  59. static void raid6_datap_recov_intx1(int disks, size_t bytes, int faila,
  60. void **ptrs)
  61. {
  62. u8 *p, *q, *dq;
  63. const u8 *qmul; /* Q multiplier table */
  64. p = (u8 *)ptrs[disks-2];
  65. q = (u8 *)ptrs[disks-1];
  66. /* Compute syndrome with zero for the missing data page
  67. Use the dead data page as temporary storage for delta q */
  68. dq = (u8 *)ptrs[faila];
  69. ptrs[faila] = (void *)raid6_empty_zero_page;
  70. ptrs[disks-1] = dq;
  71. raid6_call.gen_syndrome(disks, bytes, ptrs);
  72. /* Restore pointer table */
  73. ptrs[faila] = dq;
  74. ptrs[disks-1] = q;
  75. /* Now, pick the proper data tables */
  76. qmul = raid6_gfmul[raid6_gfinv[raid6_gfexp[faila]]];
  77. /* Now do it... */
  78. while ( bytes-- ) {
  79. *p++ ^= *dq = qmul[*q ^ *dq];
  80. q++; dq++;
  81. }
  82. }
  83. const struct raid6_recov_calls raid6_recov_intx1 = {
  84. .data2 = raid6_2data_recov_intx1,
  85. .datap = raid6_datap_recov_intx1,
  86. .valid = NULL,
  87. .name = "intx1",
  88. .priority = 0,
  89. };
  90. #ifndef __KERNEL__
  91. /* Testing only */
  92. /* Recover two failed blocks. */
  93. void raid6_dual_recov(int disks, size_t bytes, int faila, int failb, void **ptrs)
  94. {
  95. if ( faila > failb ) {
  96. int tmp = faila;
  97. faila = failb;
  98. failb = tmp;
  99. }
  100. if ( failb == disks-1 ) {
  101. if ( faila == disks-2 ) {
  102. /* P+Q failure. Just rebuild the syndrome. */
  103. raid6_call.gen_syndrome(disks, bytes, ptrs);
  104. } else {
  105. /* data+Q failure. Reconstruct data from P,
  106. then rebuild syndrome. */
  107. /* NOT IMPLEMENTED - equivalent to RAID-5 */
  108. }
  109. } else {
  110. if ( failb == disks-2 ) {
  111. /* data+P failure. */
  112. raid6_datap_recov(disks, bytes, faila, ptrs);
  113. } else {
  114. /* data+data failure. */
  115. raid6_2data_recov(disks, bytes, faila, failb, ptrs);
  116. }
  117. }
  118. }
  119. #endif