LCOV - code coverage report
Current view: top level - raid - module.c (source / functions) Hit Total Coverage
Test: lcov.info Lines: 159 159 100.0 %
Date: 2015-05-12 Functions: 7 7 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 "memory.h"
      17             : #include "cpu.h"
      18             : 
      19             : /*
      20             :  * Initializes and selects the best algorithm.
      21             :  */
      22         240 : void raid_init(void)
      23             : {
      24         240 :         raid_gen3_ptr = raid_gen3_int8;
      25         240 :         raid_gen_ptr[3] = raid_gen4_int8;
      26         240 :         raid_gen_ptr[4] = raid_gen5_int8;
      27         240 :         raid_gen_ptr[5] = raid_gen6_int8;
      28             : 
      29             :         if (sizeof(void *) == 4) {
      30         240 :                 raid_gen_ptr[0] = raid_gen1_int32;
      31         240 :                 raid_gen_ptr[1] = raid_gen2_int32;
      32         240 :                 raid_genz_ptr = raid_genz_int32;
      33             :         } else {
      34             :                 raid_gen_ptr[0] = raid_gen1_int64;
      35             :                 raid_gen_ptr[1] = raid_gen2_int64;
      36             :                 raid_genz_ptr = raid_genz_int64;
      37             :         }
      38             : 
      39         240 :         raid_rec_ptr[0] = raid_rec1_int8;
      40         240 :         raid_rec_ptr[1] = raid_rec2_int8;
      41         240 :         raid_rec_ptr[2] = raid_recX_int8;
      42         240 :         raid_rec_ptr[3] = raid_recX_int8;
      43         240 :         raid_rec_ptr[4] = raid_recX_int8;
      44         240 :         raid_rec_ptr[5] = raid_recX_int8;
      45             : 
      46             : #ifdef CONFIG_X86
      47             : #ifdef CONFIG_SSE2
      48         240 :         if (raid_cpu_has_sse2()) {
      49         240 :                 raid_gen_ptr[0] = raid_gen1_sse2;
      50             : #ifdef CONFIG_X86_64
      51             :                 if (raid_cpu_has_slowextendedreg()) {
      52             :                         raid_gen_ptr[1] = raid_gen2_sse2;
      53             :                         raid_genz_ptr = raid_genz_sse2;
      54             :                 } else {
      55             :                         raid_gen_ptr[1] = raid_gen2_sse2ext;
      56             :                         raid_genz_ptr = raid_genz_sse2ext;
      57             :                 }
      58             : #else
      59         240 :                 raid_gen_ptr[1] = raid_gen2_sse2;
      60         240 :                 raid_genz_ptr = raid_genz_sse2;
      61             : #endif
      62             :         }
      63             : #endif
      64             : 
      65             : #ifdef CONFIG_SSSE3
      66         240 :         if (raid_cpu_has_ssse3()) {
      67             : #ifdef CONFIG_X86_64
      68             :                 raid_gen3_ptr = raid_gen3_ssse3ext;
      69             :                 raid_gen_ptr[3] = raid_gen4_ssse3ext;
      70             :                 raid_gen_ptr[4] = raid_gen5_ssse3ext;
      71             :                 raid_gen_ptr[5] = raid_gen6_ssse3ext;
      72             : #else
      73         239 :                 raid_gen3_ptr = raid_gen3_ssse3;
      74         239 :                 raid_gen_ptr[3] = raid_gen4_ssse3;
      75         239 :                 raid_gen_ptr[4] = raid_gen5_ssse3;
      76         239 :                 raid_gen_ptr[5] = raid_gen6_ssse3;
      77             : #endif
      78         239 :                 raid_rec_ptr[0] = raid_rec1_ssse3;
      79         239 :                 raid_rec_ptr[1] = raid_rec2_ssse3;
      80         239 :                 raid_rec_ptr[2] = raid_recX_ssse3;
      81         239 :                 raid_rec_ptr[3] = raid_recX_ssse3;
      82         239 :                 raid_rec_ptr[4] = raid_recX_ssse3;
      83         239 :                 raid_rec_ptr[5] = raid_recX_ssse3;
      84             :         }
      85             : #endif
      86             : 
      87             : #ifdef CONFIG_AVX2
      88         240 :         if (raid_cpu_has_avx2()) {
      89           2 :                 raid_gen_ptr[0] = raid_gen1_avx2;
      90           2 :                 raid_gen_ptr[1] = raid_gen2_avx2;
      91             : #ifdef CONFIG_X86_64
      92             :                 raid_gen3_ptr = raid_gen3_avx2ext;
      93             :                 raid_genz_ptr = raid_genz_avx2ext;
      94             :                 raid_gen_ptr[3] = raid_gen4_avx2ext;
      95             :                 raid_gen_ptr[4] = raid_gen5_avx2ext;
      96             :                 raid_gen_ptr[5] = raid_gen6_avx2ext;
      97             : #endif
      98           2 :                 raid_rec_ptr[0] = raid_rec1_avx2;
      99           2 :                 raid_rec_ptr[1] = raid_rec2_avx2;
     100           2 :                 raid_rec_ptr[2] = raid_recX_avx2;
     101           2 :                 raid_rec_ptr[3] = raid_recX_avx2;
     102           2 :                 raid_rec_ptr[4] = raid_recX_avx2;
     103           2 :                 raid_rec_ptr[5] = raid_recX_avx2;
     104             :         }
     105             : #endif
     106             : #endif /* CONFIG_X86 */
     107             : 
     108             :         /* set the default mode */
     109         240 :         raid_mode(RAID_MODE_CAUCHY);
     110         240 : }
     111             : 
     112             : /*
     113             :  * Reference parity computation.
     114             :  */
     115           6 : void raid_gen_ref(int nd, int np, size_t size, void **vv)
     116             : {
     117           6 :         uint8_t **v = (uint8_t **)vv;
     118             :         size_t i;
     119             : 
     120        5382 :         for (i = 0; i < size; ++i) {
     121             :                 uint8_t p[RAID_PARITY_MAX];
     122             :                 int j, d;
     123             : 
     124       36096 :                 for (j = 0; j < np; ++j)
     125       30720 :                         p[j] = 0;
     126             : 
     127       93696 :                 for (d = 0; d < nd; ++d) {
     128       88320 :                         uint8_t b = v[d][i];
     129             : 
     130      584448 :                         for (j = 0; j < np; ++j)
     131      496128 :                                 p[j] ^= gfmul[b][gfgen[j][d]];
     132             :                 }
     133             : 
     134       36096 :                 for (j = 0; j < np; ++j)
     135       30720 :                         v[nd + j][i] = p[j];
     136             :         }
     137           6 : }
     138             : 
     139             : /*
     140             :  * Size of the blocks to test.
     141             :  */
     142             : #define TEST_SIZE 4096
     143             : 
     144             : /*
     145             :  * Number of data blocks to test.
     146             :  */
     147             : #define TEST_COUNT (65536 / TEST_SIZE)
     148             : 
     149             : /*
     150             :  * Parity generation test.
     151             :  */
     152           6 : static int raid_test_par(int nd, int np, size_t size, void **v, void **ref)
     153             : {
     154             :         int i;
     155             :         void *t[TEST_COUNT + RAID_PARITY_MAX];
     156             : 
     157             :         /* setup data */
     158         102 :         for (i = 0; i < nd; ++i)
     159          96 :                 t[i] = ref[i];
     160             : 
     161             :         /* setup parity */
     162          27 :         for (i = 0; i < np; ++i)
     163          21 :                 t[nd + i] = v[nd + i];
     164             : 
     165           6 :         raid_gen(nd, np, size, t);
     166             : 
     167             :         /* compare parity */
     168          27 :         for (i = 0; i < np; ++i) {
     169          21 :                 if (memcmp(t[nd + i], ref[nd + i], size) != 0) {
     170             :                         /* LCOV_EXCL_START */
     171             :                         return -1;
     172             :                         /* LCOV_EXCL_STOP */
     173             :                 }
     174             :         }
     175             : 
     176           6 :         return 0;
     177             : }
     178             : 
     179             : /*
     180             :  * Recovering test.
     181             :  */
     182          18 : static int raid_test_rec(int nr, int *ir, int nd, int np, size_t size, void **v, void **ref)
     183             : {
     184             :         int i, j;
     185             :         void *t[TEST_COUNT + RAID_PARITY_MAX];
     186             : 
     187             :         /* setup data and parity vector */
     188         369 :         for (i = 0, j = 0; i < nd + np; ++i) {
     189         351 :                 if (j < nr && ir[j] == i) {
     190             :                         /* this block has to be recovered */
     191          63 :                         t[i] = v[i];
     192          63 :                         ++j;
     193             :                 } else {
     194             :                         /* this block is used for recovering */
     195         288 :                         t[i] = ref[i];
     196             :                 }
     197             :         }
     198             : 
     199          18 :         raid_rec(nr, ir, nd, np, size, t);
     200             : 
     201             :         /* compare all data and parity */
     202         369 :         for (i = 0; i < nd + np; ++i) {
     203         351 :                 if (t[i] != ref[i]
     204          63 :                         && memcmp(t[i], ref[i], size) != 0) {
     205             :                         /* LCOV_EXCL_START */
     206             :                         return -1;
     207             :                         /* LCOV_EXCL_STOP */
     208             :                 }
     209             :         }
     210             : 
     211          18 :         return 0;
     212             : }
     213             : 
     214             : /*
     215             :  * Recovering test for data.
     216             :  */
     217          18 : static int raid_test_data(int nr, int *id, int *ip, int nd, int np, size_t size, void **v, void **ref)
     218             : {
     219             :         int i, j;
     220             :         void *t[TEST_COUNT + RAID_PARITY_MAX];
     221             : 
     222             :         /* setup data vector */
     223         306 :         for (i = 0, j = 0; i < nd; ++i) {
     224         288 :                 if (j < nr && id[j] == i) {
     225             :                         /* this block has to be recovered */
     226          39 :                         t[i] = v[i];
     227          39 :                         ++j;
     228             :                 } else {
     229             :                         /* this block is left unchanged */
     230         249 :                         t[i] = ref[i];
     231             :                 }
     232             :         }
     233             : 
     234             :         /* setup parity vector */
     235          81 :         for (i = 0, j = 0; i < np; ++i) {
     236          63 :                 if (j < nr && ip[j] == i) {
     237             :                         /* this block is used for recovering */
     238          39 :                         t[nd + i] = ref[nd + i];
     239          39 :                         ++j;
     240             :                 } else {
     241             :                         /* this block should not be read or written */
     242          24 :                         t[nd + i] = 0;
     243             :                 }
     244             :         }
     245             : 
     246          18 :         raid_data(nr, id, ip, nd, size, t);
     247             : 
     248             :         /* compare all data and parity */
     249         306 :         for (i = 0; i < nd; ++i) {
     250         288 :                 if (t[i] != ref[i]
     251          39 :                         && t[i] != 0
     252          39 :                         && memcmp(t[i], ref[i], size) != 0) {
     253             :                         /* LCOV_EXCL_START */
     254             :                         return -1;
     255             :                         /* LCOV_EXCL_STOP */
     256             :                 }
     257             :         }
     258             : 
     259          18 :         return 0;
     260             : }
     261             : 
     262             : /*
     263             :  * Scan test.
     264             :  */
     265           7 : static int raid_test_scan(int nr, int *ir, int nd, int np, size_t size, void **v, void **ref)
     266             : {
     267             :         int i, j, ret;
     268             :         void *t[TEST_COUNT + RAID_PARITY_MAX];
     269             :         int is[RAID_PARITY_MAX];
     270             : 
     271             :         /* setup data and parity vector */
     272         140 :         for (i = 0, j = 0; i < nd + np; ++i) {
     273         133 :                 if (j < nr && ir[j] == i) {
     274             :                         /* this block is bad */
     275          15 :                         t[i] = v[i];
     276          15 :                         ++j;
     277             :                 } else {
     278             :                         /* this block is used for recovering */
     279         118 :                         t[i] = ref[i];
     280             :                 }
     281             :         }
     282             : 
     283           7 :         ret = raid_scan(is, nd, np, size, t);
     284             : 
     285             :         /* compare identified bad blocks */
     286           7 :         if (ret != nr)
     287           1 :                 return -1;
     288          21 :         for (i = 0; i < nr; ++i) {
     289          15 :                 if (ir[i] != is[i]) {
     290             :                         /* LCOV_EXCL_START */
     291             :                         return -1;
     292             :                         /* LCOV_EXCL_STOP */
     293             :                 }
     294             :         }
     295             : 
     296           6 :         return 0;
     297             : }
     298             : 
     299             : /*
     300             :  * Basic functionality self test.
     301             :  */
     302           1 : int raid_selftest(void)
     303             : {
     304           1 :         const int nd = TEST_COUNT;
     305           1 :         const size_t size = TEST_SIZE;
     306           1 :         const int nv = nd + RAID_PARITY_MAX * 2 + 1;
     307             :         void *v_alloc;
     308             :         void **v;
     309           1 :         void *ref[nd + RAID_PARITY_MAX];
     310             :         int ir[RAID_PARITY_MAX];
     311             :         int ip[RAID_PARITY_MAX];
     312             :         int i, np;
     313           1 :         int ret = 0;
     314             : 
     315             :         /* ensure to have enough space for data */
     316           1 :         BUG_ON(nd * size > 65536);
     317             : 
     318           1 :         v = raid_malloc_vector(nd, nv, size, &v_alloc);
     319           1 :         if (!v) {
     320             :                 /* LCOV_EXCL_START */
     321             :                 return -1;
     322             :                 /* LCOV_EXCL_STOP */
     323             :         }
     324             : 
     325           1 :         memset(v[nv - 1], 0, size);
     326           1 :         raid_zero(v[nv - 1]);
     327             : 
     328             :         /* use the multiplication table as data */
     329          17 :         for (i = 0; i < nd; ++i)
     330          16 :                 ref[i] = ((uint8_t *)gfmul) + size * i;
     331             : 
     332             :         /* setup reference parity */
     333           7 :         for (i = 0; i < RAID_PARITY_MAX; ++i)
     334           6 :                 ref[nd + i] = v[nd + RAID_PARITY_MAX + i];
     335             : 
     336             :         /* compute reference parity */
     337           1 :         raid_gen_ref(nd, RAID_PARITY_MAX, size, ref);
     338             : 
     339             :         /* test for each parity level */
     340           7 :         for (np = 1; np <= RAID_PARITY_MAX; ++np) {
     341             :                 /* test parity generation */
     342           6 :                 ret = raid_test_par(nd, np, size, v, ref);
     343           6 :                 if (ret != 0) {
     344             :                         /* LCOV_EXCL_START */
     345             :                         goto bail;
     346             :                         /* LCOV_EXCL_STOP */
     347             :                 }
     348             : 
     349             :                 /* test recovering with broken ending data disks */
     350          27 :                 for (i = 0; i < np; ++i) {
     351             :                         /* bad data */
     352          21 :                         ir[i] = nd - np + i;
     353             : 
     354             :                         /* good parity */
     355          21 :                         ip[i] = i;
     356             :                 }
     357             : 
     358           6 :                 ret = raid_test_rec(np, ir, nd, np, size, v, ref);
     359           6 :                 if (ret != 0) {
     360             :                         /* LCOV_EXCL_START */
     361             :                         goto bail;
     362             :                         /* LCOV_EXCL_STOP */
     363             :                 }
     364             : 
     365           6 :                 ret = raid_test_data(np, ir, ip, nd, np, size, v, ref);
     366           6 :                 if (ret != 0) {
     367             :                         /* LCOV_EXCL_START */
     368             :                         goto bail;
     369             :                         /* LCOV_EXCL_STOP */
     370             :                 }
     371             : 
     372             :                 /* test recovering with broken leading data and broken leading parity */
     373          15 :                 for (i = 0; i < np / 2; ++i) {
     374             :                         /* bad data */
     375           9 :                         ir[i] = i;
     376             : 
     377             :                         /* good parity */
     378           9 :                         ip[i] = (np + 1) / 2 + i;
     379             :                 }
     380             : 
     381             :                 /* bad parity */
     382          18 :                 for (i = 0; i < (np + 1) / 2; ++i)
     383          12 :                         ir[np / 2 + i] = nd + i;
     384             : 
     385           6 :                 ret = raid_test_rec(np, ir, nd, np, size, v, ref);
     386           6 :                 if (ret != 0) {
     387             :                         /* LCOV_EXCL_START */
     388             :                         goto bail;
     389             :                         /* LCOV_EXCL_STOP */
     390             :                 }
     391             : 
     392           6 :                 ret = raid_test_data(np / 2, ir, ip, nd, np, size, v, ref);
     393           6 :                 if (ret != 0) {
     394             :                         /* LCOV_EXCL_START */
     395             :                         goto bail;
     396             :                         /* LCOV_EXCL_STOP */
     397             :                 }
     398             : 
     399             :                 /* test recovering with broken leading data and broken ending parity */
     400          15 :                 for (i = 0; i < np / 2; ++i) {
     401             :                         /* bad data */
     402           9 :                         ir[i] = i;
     403             : 
     404             :                         /* good parity */
     405           9 :                         ip[i] = i;
     406             :                 }
     407             : 
     408             :                 /* bad parity */
     409          18 :                 for (i = 0; i < (np + 1) / 2; ++i)
     410          12 :                         ir[np / 2 + i] = nd + np - (np + 1) / 2 + i;
     411             : 
     412           6 :                 ret = raid_test_rec(np, ir, nd, np, size, v, ref);
     413           6 :                 if (ret != 0) {
     414             :                         /* LCOV_EXCL_START */
     415             :                         goto bail;
     416             :                         /* LCOV_EXCL_STOP */
     417             :                 }
     418             : 
     419           6 :                 ret = raid_test_data(np / 2, ir, ip, nd, np, size, v, ref);
     420           6 :                 if (ret != 0) {
     421             :                         /* LCOV_EXCL_START */
     422             :                         goto bail;
     423             :                         /* LCOV_EXCL_STOP */
     424             :                 }
     425             : 
     426             :                 /* scan test with broken data and parity */
     427          15 :                 for (i = 0; i < np / 2; ++i) {
     428             :                         /* bad data */
     429           9 :                         ir[i] = i;
     430             :                 }
     431          12 :                 for (i = 0; i < (np - 1) / 2; ++i) {
     432             :                         /* bad parity */
     433           6 :                         ir[np / 2 + i] = nd + i;
     434             :                 }
     435          21 :                 for (i = 0; i < np - 1; ++i) {
     436             :                         /* make blocks bad */
     437             :                         /* we cannot fill them with 0, because the original */
     438             :                         /* data may be already filled with 0 */
     439          15 :                         memset(v[ir[i]], 0x55, size);
     440             :                 }
     441             : 
     442           6 :                 ret = raid_test_scan(np - 1, ir, nd, np, size, v, ref);
     443           6 :                 if (ret != 0) {
     444             :                         /* LCOV_EXCL_START */
     445             :                         goto bail;
     446             :                         /* LCOV_EXCL_STOP */
     447             :                 }
     448             :         }
     449             : 
     450             :         /* scan test with no parity */
     451           1 :         ret = raid_test_scan(0, 0, nd, 0, size, v, ref);
     452           1 :         if (ret != -1) {
     453             :                 /* LCOV_EXCL_START */
     454             :                 goto bail;
     455             :                 /* LCOV_EXCL_STOP */
     456             :         }
     457             : 
     458           1 :         ret = 0;
     459             : 
     460             : bail:
     461           1 :         free(v);
     462           1 :         free(v_alloc);
     463             : 
     464           1 :         return ret;
     465             : }
     466             : 

Generated by: LCOV version 1.10