LCOV - code coverage report
Current view: top level - raid - int.c (source / functions) Hit Total Coverage
Test: lcov.info Lines: 241 241 100.0 %
Date: 2017-11-06 22:14:04 Functions: 11 11 100.0 %

          Line data    Source code
       1             : /*
       2             :  * Copyright (C) 2013 Andrea Mazzoleni
       3             :  *
       4             :  * This program is free software: you can redistribute it and/or modify
       5             :  * it under the terms of the GNU General Public License as published by
       6             :  * the Free Software Foundation, either version 2 of the License, or
       7             :  * (at your option) any later version.
       8             :  *
       9             :  * This program is distributed in the hope that it will be useful,
      10             :  * but WITHOUT ANY WARRANTY; without even the implied warranty of
      11             :  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      12             :  * GNU General Public License for more details.
      13             :  */
      14             : 
      15             : #include "internal.h"
      16             : #include "gf.h"
      17             : 
      18             : /*
      19             :  * GEN1 (RAID5 with xor) 32bit C implementation
      20             :  */
      21         129 : void raid_gen1_int32(int nd, size_t size, void **vv)
      22             : {
      23         129 :         uint8_t **v = (uint8_t **)vv;
      24             :         uint8_t *p;
      25             :         int d, l;
      26             :         size_t i;
      27             : 
      28             :         uint32_t p0;
      29             :         uint32_t p1;
      30             : 
      31         129 :         l = nd - 1;
      32         129 :         p = v[nd];
      33             : 
      34     4128993 :         for (i = 0; i < size; i += 8) {
      35     4128864 :                 p0 = v_32(v[l][i]);
      36     4128864 :                 p1 = v_32(v[l][i + 4]);
      37    33032224 :                 for (d = l - 1; d >= 0; --d) {
      38    28903360 :                         p0 ^= v_32(v[d][i]);
      39    28903360 :                         p1 ^= v_32(v[d][i + 4]);
      40             :                 }
      41     4128864 :                 v_32(p[i]) = p0;
      42     4128864 :                 v_32(p[i + 4]) = p1;
      43             :         }
      44         129 : }
      45             : 
      46             : /*
      47             :  * GEN1 (RAID5 with xor) 64bit C implementation
      48             :  */
      49         245 : void raid_gen1_int64(int nd, size_t size, void **vv)
      50             : {
      51         245 :         uint8_t **v = (uint8_t **)vv;
      52             :         uint8_t *p;
      53             :         int d, l;
      54             :         size_t i;
      55             : 
      56             :         uint64_t p0;
      57             :         uint64_t p1;
      58             : 
      59         245 :         l = nd - 1;
      60         245 :         p = v[nd];
      61             : 
      62     3965221 :         for (i = 0; i < size; i += 16) {
      63     3964976 :                 p0 = v_64(v[l][i]);
      64     3964976 :                 p1 = v_64(v[l][i + 8]);
      65    31720464 :                 for (d = l - 1; d >= 0; --d) {
      66    27755488 :                         p0 ^= v_64(v[d][i]);
      67    27755488 :                         p1 ^= v_64(v[d][i + 8]);
      68             :                 }
      69     3964976 :                 v_64(p[i]) = p0;
      70     3964976 :                 v_64(p[i + 8]) = p1;
      71             :         }
      72         245 : }
      73             : 
      74             : /*
      75             :  * GEN2 (RAID6 with powers of 2) 32bit C implementation
      76             :  */
      77          51 : void raid_gen2_int32(int nd, size_t size, void **vv)
      78             : {
      79          51 :         uint8_t **v = (uint8_t **)vv;
      80             :         uint8_t *p;
      81             :         uint8_t *q;
      82             :         int d, l;
      83             :         size_t i;
      84             : 
      85             :         uint32_t d0, q0, p0;
      86             :         uint32_t d1, q1, p1;
      87             : 
      88          51 :         l = nd - 1;
      89          51 :         p = v[nd];
      90          51 :         q = v[nd + 1];
      91             : 
      92     1573011 :         for (i = 0; i < size; i += 8) {
      93     1572960 :                 q0 = p0 = v_32(v[l][i]);
      94     1572960 :                 q1 = p1 = v_32(v[l][i + 4]);
      95    12584992 :                 for (d = l - 1; d >= 0; --d) {
      96    11012032 :                         d0 = v_32(v[d][i]);
      97    11012032 :                         d1 = v_32(v[d][i + 4]);
      98             : 
      99    11012032 :                         p0 ^= d0;
     100    11012032 :                         p1 ^= d1;
     101             : 
     102    11012032 :                         q0 = x2_32(q0);
     103    11012032 :                         q1 = x2_32(q1);
     104             : 
     105    11012032 :                         q0 ^= d0;
     106    11012032 :                         q1 ^= d1;
     107             :                 }
     108     1572960 :                 v_32(p[i]) = p0;
     109     1572960 :                 v_32(p[i + 4]) = p1;
     110     1572960 :                 v_32(q[i]) = q0;
     111     1572960 :                 v_32(q[i + 4]) = q1;
     112             :         }
     113          51 : }
     114             : 
     115             : /*
     116             :  * GEN2 (RAID6 with powers of 2) 64bit C implementation
     117             :  */
     118          95 : void raid_gen2_int64(int nd, size_t size, void **vv)
     119             : {
     120          95 :         uint8_t **v = (uint8_t **)vv;
     121             :         uint8_t *p;
     122             :         uint8_t *q;
     123             :         int d, l;
     124             :         size_t i;
     125             : 
     126             :         uint64_t d0, q0, p0;
     127             :         uint64_t d1, q1, p1;
     128             : 
     129          95 :         l = nd - 1;
     130          95 :         p = v[nd];
     131          95 :         q = v[nd + 1];
     132             : 
     133     1507471 :         for (i = 0; i < size; i += 16) {
     134     1507376 :                 q0 = p0 = v_64(v[l][i]);
     135     1507376 :                 q1 = p1 = v_64(v[l][i + 8]);
     136    12059664 :                 for (d = l - 1; d >= 0; --d) {
     137    10552288 :                         d0 = v_64(v[d][i]);
     138    10552288 :                         d1 = v_64(v[d][i + 8]);
     139             : 
     140    10552288 :                         p0 ^= d0;
     141    10552288 :                         p1 ^= d1;
     142             : 
     143    10552288 :                         q0 = x2_64(q0);
     144    10552288 :                         q1 = x2_64(q1);
     145             : 
     146    10552288 :                         q0 ^= d0;
     147    10552288 :                         q1 ^= d1;
     148             :                 }
     149     1507376 :                 v_64(p[i]) = p0;
     150     1507376 :                 v_64(p[i + 8]) = p1;
     151     1507376 :                 v_64(q[i]) = q0;
     152     1507376 :                 v_64(q[i + 8]) = q1;
     153             :         }
     154          95 : }
     155             : 
     156             : /*
     157             :  * GEN3 (triple parity with Cauchy matrix) 8bit C implementation
     158             :  *
     159             :  * Note that instead of a generic multiplication table, likely resulting
     160             :  * in multiple cache misses, a precomputed table could be used.
     161             :  * But this is only a kind of reference function, and we are not really
     162             :  * interested in speed.
     163             :  */
     164          30 : void raid_gen3_int8(int nd, size_t size, void **vv)
     165             : {
     166          30 :         uint8_t **v = (uint8_t **)vv;
     167             :         uint8_t *p;
     168             :         uint8_t *q;
     169             :         uint8_t *r;
     170             :         int d, l;
     171             :         size_t i;
     172             : 
     173             :         uint8_t d0, r0, q0, p0;
     174             : 
     175          30 :         l = nd - 1;
     176          30 :         p = v[nd];
     177          30 :         q = v[nd + 1];
     178          30 :         r = v[nd + 2];
     179             : 
     180     7340574 :         for (i = 0; i < size; i += 1) {
     181     7340544 :                 p0 = q0 = r0 = 0;
     182    58728704 :                 for (d = l; d > 0; --d) {
     183    51388160 :                         d0 = v_8(v[d][i]);
     184             : 
     185    51388160 :                         p0 ^= d0;
     186    51388160 :                         q0 ^= gfmul[d0][gfgen[1][d]];
     187    51388160 :                         r0 ^= gfmul[d0][gfgen[2][d]];
     188             :                 }
     189             : 
     190             :                 /* first disk with all coefficients at 1 */
     191     7340544 :                 d0 = v_8(v[0][i]);
     192             : 
     193     7340544 :                 p0 ^= d0;
     194     7340544 :                 q0 ^= d0;
     195     7340544 :                 r0 ^= d0;
     196             : 
     197     7340544 :                 v_8(p[i]) = p0;
     198     7340544 :                 v_8(q[i]) = q0;
     199     7340544 :                 v_8(r[i]) = r0;
     200             :         }
     201          30 : }
     202             : 
     203             : /*
     204             :  * GEN4 (quad parity with Cauchy matrix) 8bit C implementation
     205             :  *
     206             :  * Note that instead of a generic multiplication table, likely resulting
     207             :  * in multiple cache misses, a precomputed table could be used.
     208             :  * But this is only a kind of reference function, and we are not really
     209             :  * interested in speed.
     210             :  */
     211          21 : void raid_gen4_int8(int nd, size_t size, void **vv)
     212             : {
     213          21 :         uint8_t **v = (uint8_t **)vv;
     214             :         uint8_t *p;
     215             :         uint8_t *q;
     216             :         uint8_t *r;
     217             :         uint8_t *s;
     218             :         int d, l;
     219             :         size_t i;
     220             : 
     221             :         uint8_t d0, s0, r0, q0, p0;
     222             : 
     223          21 :         l = nd - 1;
     224          21 :         p = v[nd];
     225          21 :         q = v[nd + 1];
     226          21 :         r = v[nd + 2];
     227          21 :         s = v[nd + 3];
     228             : 
     229     4981269 :         for (i = 0; i < size; i += 1) {
     230     4981248 :                 p0 = q0 = r0 = s0 = 0;
     231    39854336 :                 for (d = l; d > 0; --d) {
     232    34873088 :                         d0 = v_8(v[d][i]);
     233             : 
     234    34873088 :                         p0 ^= d0;
     235    34873088 :                         q0 ^= gfmul[d0][gfgen[1][d]];
     236    34873088 :                         r0 ^= gfmul[d0][gfgen[2][d]];
     237    34873088 :                         s0 ^= gfmul[d0][gfgen[3][d]];
     238             :                 }
     239             : 
     240             :                 /* first disk with all coefficients at 1 */
     241     4981248 :                 d0 = v_8(v[0][i]);
     242             : 
     243     4981248 :                 p0 ^= d0;
     244     4981248 :                 q0 ^= d0;
     245     4981248 :                 r0 ^= d0;
     246     4981248 :                 s0 ^= d0;
     247             : 
     248     4981248 :                 v_8(p[i]) = p0;
     249     4981248 :                 v_8(q[i]) = q0;
     250     4981248 :                 v_8(r[i]) = r0;
     251     4981248 :                 v_8(s[i]) = s0;
     252             :         }
     253          21 : }
     254             : 
     255             : /*
     256             :  * GEN5 (penta parity with Cauchy matrix) 8bit C implementation
     257             :  *
     258             :  * Note that instead of a generic multiplication table, likely resulting
     259             :  * in multiple cache misses, a precomputed table could be used.
     260             :  * But this is only a kind of reference function, and we are not really
     261             :  * interested in speed.
     262             :  */
     263          18 : void raid_gen5_int8(int nd, size_t size, void **vv)
     264             : {
     265          18 :         uint8_t **v = (uint8_t **)vv;
     266             :         uint8_t *p;
     267             :         uint8_t *q;
     268             :         uint8_t *r;
     269             :         uint8_t *s;
     270             :         uint8_t *t;
     271             :         int d, l;
     272             :         size_t i;
     273             : 
     274             :         uint8_t d0, t0, s0, r0, q0, p0;
     275             : 
     276          18 :         l = nd - 1;
     277          18 :         p = v[nd];
     278          18 :         q = v[nd + 1];
     279          18 :         r = v[nd + 2];
     280          18 :         s = v[nd + 3];
     281          18 :         t = v[nd + 4];
     282             : 
     283     4194834 :         for (i = 0; i < size; i += 1) {
     284     4194816 :                 p0 = q0 = r0 = s0 = t0 = 0;
     285    33562880 :                 for (d = l; d > 0; --d) {
     286    29368064 :                         d0 = v_8(v[d][i]);
     287             : 
     288    29368064 :                         p0 ^= d0;
     289    29368064 :                         q0 ^= gfmul[d0][gfgen[1][d]];
     290    29368064 :                         r0 ^= gfmul[d0][gfgen[2][d]];
     291    29368064 :                         s0 ^= gfmul[d0][gfgen[3][d]];
     292    29368064 :                         t0 ^= gfmul[d0][gfgen[4][d]];
     293             :                 }
     294             : 
     295             :                 /* first disk with all coefficients at 1 */
     296     4194816 :                 d0 = v_8(v[0][i]);
     297             : 
     298     4194816 :                 p0 ^= d0;
     299     4194816 :                 q0 ^= d0;
     300     4194816 :                 r0 ^= d0;
     301     4194816 :                 s0 ^= d0;
     302     4194816 :                 t0 ^= d0;
     303             : 
     304     4194816 :                 v_8(p[i]) = p0;
     305     4194816 :                 v_8(q[i]) = q0;
     306     4194816 :                 v_8(r[i]) = r0;
     307     4194816 :                 v_8(s[i]) = s0;
     308     4194816 :                 v_8(t[i]) = t0;
     309             :         }
     310          18 : }
     311             : 
     312             : /*
     313             :  * GEN6 (hexa parity with Cauchy matrix) 8bit C implementation
     314             :  *
     315             :  * Note that instead of a generic multiplication table, likely resulting
     316             :  * in multiple cache misses, a precomputed table could be used.
     317             :  * But this is only a kind of reference function, and we are not really
     318             :  * interested in speed.
     319             :  */
     320          18 : void raid_gen6_int8(int nd, size_t size, void **vv)
     321             : {
     322          18 :         uint8_t **v = (uint8_t **)vv;
     323             :         uint8_t *p;
     324             :         uint8_t *q;
     325             :         uint8_t *r;
     326             :         uint8_t *s;
     327             :         uint8_t *t;
     328             :         uint8_t *u;
     329             :         int d, l;
     330             :         size_t i;
     331             : 
     332             :         uint8_t d0, u0, t0, s0, r0, q0, p0;
     333             : 
     334          18 :         l = nd - 1;
     335          18 :         p = v[nd];
     336          18 :         q = v[nd + 1];
     337          18 :         r = v[nd + 2];
     338          18 :         s = v[nd + 3];
     339          18 :         t = v[nd + 4];
     340          18 :         u = v[nd + 5];
     341             : 
     342     4194834 :         for (i = 0; i < size; i += 1) {
     343     4194816 :                 p0 = q0 = r0 = s0 = t0 = u0 = 0;
     344    33562880 :                 for (d = l; d > 0; --d) {
     345    29368064 :                         d0 = v_8(v[d][i]);
     346             : 
     347    29368064 :                         p0 ^= d0;
     348    29368064 :                         q0 ^= gfmul[d0][gfgen[1][d]];
     349    29368064 :                         r0 ^= gfmul[d0][gfgen[2][d]];
     350    29368064 :                         s0 ^= gfmul[d0][gfgen[3][d]];
     351    29368064 :                         t0 ^= gfmul[d0][gfgen[4][d]];
     352    29368064 :                         u0 ^= gfmul[d0][gfgen[5][d]];
     353             :                 }
     354             : 
     355             :                 /* first disk with all coefficients at 1 */
     356     4194816 :                 d0 = v_8(v[0][i]);
     357             : 
     358     4194816 :                 p0 ^= d0;
     359     4194816 :                 q0 ^= d0;
     360     4194816 :                 r0 ^= d0;
     361     4194816 :                 s0 ^= d0;
     362     4194816 :                 t0 ^= d0;
     363     4194816 :                 u0 ^= d0;
     364             : 
     365     4194816 :                 v_8(p[i]) = p0;
     366     4194816 :                 v_8(q[i]) = q0;
     367     4194816 :                 v_8(r[i]) = r0;
     368     4194816 :                 v_8(s[i]) = s0;
     369     4194816 :                 v_8(t[i]) = t0;
     370     4194816 :                 v_8(u[i]) = u0;
     371             :         }
     372          18 : }
     373             : 
     374             : /*
     375             :  * Recover failure of one data block at index id[0] using parity at index
     376             :  * ip[0] for any RAID level.
     377             :  *
     378             :  * Starting from the equation:
     379             :  *
     380             :  * Pd = A[ip[0],id[0]] * Dx
     381             :  *
     382             :  * and solving we get:
     383             :  *
     384             :  * Dx = A[ip[0],id[0]]^-1 * Pd
     385             :  */
     386         164 : void raid_rec1_int8(int nr, int *id, int *ip, int nd, size_t size, void **vv)
     387             : {
     388         164 :         uint8_t **v = (uint8_t **)vv;
     389             :         uint8_t *p;
     390             :         uint8_t *pa;
     391             :         const uint8_t *T;
     392             :         uint8_t G;
     393             :         uint8_t V;
     394             :         size_t i;
     395             : 
     396             :         (void)nr; /* unused, it's always 1 */
     397             : 
     398             :         /* if it's RAID5 uses the faster function */
     399         164 :         if (ip[0] == 0) {
     400          24 :                 raid_rec1of1(id, nd, size, vv);
     401          24 :                 return;
     402             :         }
     403             : 
     404             :         /* setup the coefficients matrix */
     405         280 :         G = A(ip[0], id[0]);
     406             : 
     407             :         /* invert it to solve the system of linear equations */
     408         280 :         V = inv(G);
     409             : 
     410             :         /* get multiplication tables */
     411         280 :         T = table(V);
     412             : 
     413             :         /* compute delta parity */
     414         140 :         raid_delta_gen(1, id, ip, nd, size, vv);
     415             : 
     416         140 :         p = v[nd + ip[0]];
     417         140 :         pa = v[id[0]];
     418             : 
     419    14701708 :         for (i = 0; i < size; ++i) {
     420             :                 /* delta */
     421    14701568 :                 uint8_t Pd = p[i] ^ pa[i];
     422             : 
     423             :                 /* reconstruct */
     424    14701568 :                 pa[i] = T[Pd];
     425             :         }
     426             : }
     427             : 
     428             : /*
     429             :  * Recover failure of two data blocks at indexes id[0],id[1] using parity at
     430             :  * indexes ip[0],ip[1] for any RAID level.
     431             :  *
     432             :  * Starting from the equations:
     433             :  *
     434             :  * Pd = A[ip[0],id[0]] * Dx + A[ip[0],id[1]] * Dy
     435             :  * Qd = A[ip[1],id[0]] * Dx + A[ip[1],id[1]] * Dy
     436             :  *
     437             :  * we solve inverting the coefficients matrix.
     438             :  */
     439        1220 : void raid_rec2_int8(int nr, int *id, int *ip, int nd, size_t size, void **vv)
     440        1220 : {
     441        1220 :         uint8_t **v = (uint8_t **)vv;
     442             :         uint8_t *p;
     443             :         uint8_t *pa;
     444             :         uint8_t *q;
     445             :         uint8_t *qa;
     446        1220 :         const int N = 2;
     447        1220 :         const uint8_t *T[N][N];
     448        1220 :         uint8_t G[N * N];
     449        1220 :         uint8_t V[N * N];
     450             :         size_t i;
     451             :         int j, k;
     452             : 
     453             :         (void)nr; /* unused, it's always 2 */
     454             : 
     455             :         /* if it's RAID6 recovering with P and Q uses the faster function */
     456        1220 :         if (ip[0] == 0 && ip[1] == 1) {
     457         132 :                 raid_rec2of2_int8(id, ip, nd, size, vv);
     458         132 :                 return;
     459             :         }
     460             : 
     461             :         /* setup the coefficients matrix */
     462        3264 :         for (j = 0; j < N; ++j)
     463        6528 :                 for (k = 0; k < N; ++k)
     464        8704 :                         G[j * N + k] = A(ip[j], id[k]);
     465             : 
     466             :         /* invert it to solve the system of linear equations */
     467        1088 :         raid_invert(G, V, N);
     468             : 
     469             :         /* get multiplication tables */
     470        3264 :         for (j = 0; j < N; ++j)
     471        6528 :                 for (k = 0; k < N; ++k)
     472        8704 :                         T[j][k] = table(V[j * N + k]);
     473             : 
     474             :         /* compute delta parity */
     475        1088 :         raid_delta_gen(2, id, ip, nd, size, vv);
     476             : 
     477        1088 :         p = v[nd + ip[0]];
     478        1088 :         q = v[nd + ip[1]];
     479        1088 :         pa = v[id[0]];
     480        1088 :         qa = v[id[1]];
     481             : 
     482     8660032 :         for (i = 0; i < size; ++i) {
     483             :                 /* delta */
     484     8658944 :                 uint8_t Pd = p[i] ^ pa[i];
     485     8658944 :                 uint8_t Qd = q[i] ^ qa[i];
     486             : 
     487             :                 /* reconstruct */
     488     8658944 :                 pa[i] = T[0][0][Pd] ^ T[0][1][Qd];
     489     8658944 :                 qa[i] = T[1][0][Pd] ^ T[1][1][Qd];
     490             :         }
     491             : }
     492             : 
     493             : /*
     494             :  * Recover failure of N data blocks at indexes id[N] using parity at indexes
     495             :  * ip[N] for any RAID level.
     496             :  *
     497             :  * Starting from the N equations, with 0<=i<N :
     498             :  *
     499             :  * PD[i] = sum(A[ip[i],id[j]] * D[i]) 0<=j<N
     500             :  *
     501             :  * we solve inverting the coefficients matrix.
     502             :  *
     503             :  * Note that referring at previous equations you have:
     504             :  * PD[0] = Pd, PD[1] = Qd, PD[2] = Rd, ...
     505             :  * D[0] = Dx, D[1] = Dy, D[2] = Dz, ...
     506             :  */
     507       17849 : void raid_recX_int8(int nr, int *id, int *ip, int nd, size_t size, void **vv)
     508             : {
     509       17849 :         uint8_t **v = (uint8_t **)vv;
     510             :         uint8_t *p[RAID_PARITY_MAX];
     511             :         uint8_t *pa[RAID_PARITY_MAX];
     512             :         const uint8_t *T[RAID_PARITY_MAX][RAID_PARITY_MAX];
     513             :         uint8_t G[RAID_PARITY_MAX * RAID_PARITY_MAX];
     514             :         uint8_t V[RAID_PARITY_MAX * RAID_PARITY_MAX];
     515             :         size_t i;
     516             :         int j, k;
     517             : 
     518             :         /* setup the coefficients matrix */
     519       91289 :         for (j = 0; j < nr; ++j)
     520      388636 :                 for (k = 0; k < nr; ++k)
     521      630392 :                         G[j * nr + k] = A(ip[j], id[k]);
     522             : 
     523             :         /* invert it to solve the system of linear equations */
     524       17849 :         raid_invert(G, V, nr);
     525             : 
     526             :         /* get multiplication tables */
     527       91289 :         for (j = 0; j < nr; ++j)
     528      388636 :                 for (k = 0; k < nr; ++k)
     529      630392 :                         T[j][k] = table(V[j * nr + k]);
     530             : 
     531             :         /* compute delta parity */
     532       17849 :         raid_delta_gen(nr, id, ip, nd, size, vv);
     533             : 
     534       91289 :         for (j = 0; j < nr; ++j) {
     535       73440 :                 p[j] = v[nd + ip[j]];
     536       73440 :                 pa[j] = v[id[j]];
     537             :         }
     538             : 
     539    38108857 :         for (i = 0; i < size; ++i) {
     540             :                 uint8_t PD[RAID_PARITY_MAX];
     541             : 
     542             :                 /* delta */
     543   207739136 :                 for (j = 0; j < nr; ++j)
     544   169648128 :                         PD[j] = p[j][i] ^ pa[j][i];
     545             : 
     546             :                 /* reconstruct */
     547   207739136 :                 for (j = 0; j < nr; ++j) {
     548   169648128 :                         uint8_t b = 0;
     549             : 
     550   971054080 :                         for (k = 0; k < nr; ++k)
     551   801405952 :                                 b ^= T[j][k][PD[k]];
     552   169648128 :                         pa[j][i] = b;
     553             :                 }
     554             :         }
     555       17849 : }
     556             : 

Generated by: LCOV version 1.13