linux/crypto/async_tx/raid6test.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-only
   2/*
   3 * asynchronous raid6 recovery self test
   4 * Copyright (c) 2009, Intel Corporation.
   5 *
   6 * based on drivers/md/raid6test/test.c:
   7 *      Copyright 2002-2007 H. Peter Anvin
   8 */
   9#include <linux/async_tx.h>
  10#include <linux/gfp.h>
  11#include <linux/mm.h>
  12#include <linux/random.h>
  13#include <linux/module.h>
  14
  15#undef pr
  16#define pr(fmt, args...) pr_info("raid6test: " fmt, ##args)
  17
  18#define NDISKS 64 /* Including P and Q */
  19
  20static struct page *dataptrs[NDISKS];
  21static addr_conv_t addr_conv[NDISKS];
  22static struct page *data[NDISKS+3];
  23static struct page *spare;
  24static struct page *recovi;
  25static struct page *recovj;
  26
  27static void callback(void *param)
  28{
  29        struct completion *cmp = param;
  30
  31        complete(cmp);
  32}
  33
  34static void makedata(int disks)
  35{
  36        int i;
  37
  38        for (i = 0; i < disks; i++) {
  39                prandom_bytes(page_address(data[i]), PAGE_SIZE);
  40                dataptrs[i] = data[i];
  41        }
  42}
  43
  44static char disk_type(int d, int disks)
  45{
  46        if (d == disks - 2)
  47                return 'P';
  48        else if (d == disks - 1)
  49                return 'Q';
  50        else
  51                return 'D';
  52}
  53
  54/* Recover two failed blocks. */
  55static void raid6_dual_recov(int disks, size_t bytes, int faila, int failb, struct page **ptrs)
  56{
  57        struct async_submit_ctl submit;
  58        struct completion cmp;
  59        struct dma_async_tx_descriptor *tx = NULL;
  60        enum sum_check_flags result = ~0;
  61
  62        if (faila > failb)
  63                swap(faila, failb);
  64
  65        if (failb == disks-1) {
  66                if (faila == disks-2) {
  67                        /* P+Q failure.  Just rebuild the syndrome. */
  68                        init_async_submit(&submit, 0, NULL, NULL, NULL, addr_conv);
  69                        tx = async_gen_syndrome(ptrs, 0, disks, bytes, &submit);
  70                } else {
  71                        struct page *blocks[NDISKS];
  72                        struct page *dest;
  73                        int count = 0;
  74                        int i;
  75
  76                        BUG_ON(disks > NDISKS);
  77
  78                        /* data+Q failure.  Reconstruct data from P,
  79                         * then rebuild syndrome
  80                         */
  81                        for (i = disks; i-- ; ) {
  82                                if (i == faila || i == failb)
  83                                        continue;
  84                                blocks[count++] = ptrs[i];
  85                        }
  86                        dest = ptrs[faila];
  87                        init_async_submit(&submit, ASYNC_TX_XOR_ZERO_DST, NULL,
  88                                          NULL, NULL, addr_conv);
  89                        tx = async_xor(dest, blocks, 0, count, bytes, &submit);
  90
  91                        init_async_submit(&submit, 0, tx, NULL, NULL, addr_conv);
  92                        tx = async_gen_syndrome(ptrs, 0, disks, bytes, &submit);
  93                }
  94        } else {
  95                if (failb == disks-2) {
  96                        /* data+P failure. */
  97                        init_async_submit(&submit, 0, NULL, NULL, NULL, addr_conv);
  98                        tx = async_raid6_datap_recov(disks, bytes, faila, ptrs, &submit);
  99                } else {
 100                        /* data+data failure. */
 101                        init_async_submit(&submit, 0, NULL, NULL, NULL, addr_conv);
 102                        tx = async_raid6_2data_recov(disks, bytes, faila, failb, ptrs, &submit);
 103                }
 104        }
 105        init_completion(&cmp);
 106        init_async_submit(&submit, ASYNC_TX_ACK, tx, callback, &cmp, addr_conv);
 107        tx = async_syndrome_val(ptrs, 0, disks, bytes, &result, spare, &submit);
 108        async_tx_issue_pending(tx);
 109
 110        if (wait_for_completion_timeout(&cmp, msecs_to_jiffies(3000)) == 0)
 111                pr("%s: timeout! (faila: %d failb: %d disks: %d)\n",
 112                   __func__, faila, failb, disks);
 113
 114        if (result != 0)
 115                pr("%s: validation failure! faila: %d failb: %d sum_check_flags: %x\n",
 116                   __func__, faila, failb, result);
 117}
 118
 119static int test_disks(int i, int j, int disks)
 120{
 121        int erra, errb;
 122
 123        memset(page_address(recovi), 0xf0, PAGE_SIZE);
 124        memset(page_address(recovj), 0xba, PAGE_SIZE);
 125
 126        dataptrs[i] = recovi;
 127        dataptrs[j] = recovj;
 128
 129        raid6_dual_recov(disks, PAGE_SIZE, i, j, dataptrs);
 130
 131        erra = memcmp(page_address(data[i]), page_address(recovi), PAGE_SIZE);
 132        errb = memcmp(page_address(data[j]), page_address(recovj), PAGE_SIZE);
 133
 134        pr("%s(%d, %d): faila=%3d(%c)  failb=%3d(%c)  %s\n",
 135           __func__, i, j, i, disk_type(i, disks), j, disk_type(j, disks),
 136           (!erra && !errb) ? "OK" : !erra ? "ERRB" : !errb ? "ERRA" : "ERRAB");
 137
 138        dataptrs[i] = data[i];
 139        dataptrs[j] = data[j];
 140
 141        return erra || errb;
 142}
 143
 144static int test(int disks, int *tests)
 145{
 146        struct dma_async_tx_descriptor *tx;
 147        struct async_submit_ctl submit;
 148        struct completion cmp;
 149        int err = 0;
 150        int i, j;
 151
 152        recovi = data[disks];
 153        recovj = data[disks+1];
 154        spare  = data[disks+2];
 155
 156        makedata(disks);
 157
 158        /* Nuke syndromes */
 159        memset(page_address(data[disks-2]), 0xee, PAGE_SIZE);
 160        memset(page_address(data[disks-1]), 0xee, PAGE_SIZE);
 161
 162        /* Generate assumed good syndrome */
 163        init_completion(&cmp);
 164        init_async_submit(&submit, ASYNC_TX_ACK, NULL, callback, &cmp, addr_conv);
 165        tx = async_gen_syndrome(dataptrs, 0, disks, PAGE_SIZE, &submit);
 166        async_tx_issue_pending(tx);
 167
 168        if (wait_for_completion_timeout(&cmp, msecs_to_jiffies(3000)) == 0) {
 169                pr("error: initial gen_syndrome(%d) timed out\n", disks);
 170                return 1;
 171        }
 172
 173        pr("testing the %d-disk case...\n", disks);
 174        for (i = 0; i < disks-1; i++)
 175                for (j = i+1; j < disks; j++) {
 176                        (*tests)++;
 177                        err += test_disks(i, j, disks);
 178                }
 179
 180        return err;
 181}
 182
 183
 184static int raid6_test(void)
 185{
 186        int err = 0;
 187        int tests = 0;
 188        int i;
 189
 190        for (i = 0; i < NDISKS+3; i++) {
 191                data[i] = alloc_page(GFP_KERNEL);
 192                if (!data[i]) {
 193                        while (i--)
 194                                put_page(data[i]);
 195                        return -ENOMEM;
 196                }
 197        }
 198
 199        /* the 4-disk and 5-disk cases are special for the recovery code */
 200        if (NDISKS > 4)
 201                err += test(4, &tests);
 202        if (NDISKS > 5)
 203                err += test(5, &tests);
 204        /* the 11 and 12 disk cases are special for ioatdma (p-disabled
 205         * q-continuation without extended descriptor)
 206         */
 207        if (NDISKS > 12) {
 208                err += test(11, &tests);
 209                err += test(12, &tests);
 210        }
 211
 212        /* the 24 disk case is special for ioatdma as it is the boudary point
 213         * at which it needs to switch from 8-source ops to 16-source
 214         * ops for continuation (assumes DMA_HAS_PQ_CONTINUE is not set)
 215         */
 216        if (NDISKS > 24)
 217                err += test(24, &tests);
 218
 219        err += test(NDISKS, &tests);
 220
 221        pr("\n");
 222        pr("complete (%d tests, %d failure%s)\n",
 223           tests, err, err == 1 ? "" : "s");
 224
 225        for (i = 0; i < NDISKS+3; i++)
 226                put_page(data[i]);
 227
 228        return 0;
 229}
 230
 231static void raid6_test_exit(void)
 232{
 233}
 234
 235/* when compiled-in wait for drivers to load first (assumes dma drivers
 236 * are also compliled-in)
 237 */
 238late_initcall(raid6_test);
 239module_exit(raid6_test_exit);
 240MODULE_AUTHOR("Dan Williams <dan.j.williams@intel.com>");
 241MODULE_DESCRIPTION("asynchronous RAID-6 recovery self tests");
 242MODULE_LICENSE("GPL");
 243