recov.c 3.3 KB

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