2019-05-20 20:08:13 +03:00
// SPDX-License-Identifier: GPL-2.0-or-later
2005-04-17 02:20:36 +04:00
/* -*- linux-c -*- ------------------------------------------------------- *
*
* Copyright 2002 H . Peter Anvin - All Rights Reserved
*
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
/*
2010-08-12 00:44:54 +04:00
* raid6 / algos . c
2005-04-17 02:20:36 +04:00
*
* Algorithm list and algorithm selection for RAID - 6
*/
2009-03-31 08:09:39 +04:00
# include <linux/raid/pq.h>
2005-04-17 02:20:36 +04:00
# ifndef __KERNEL__
# include <sys/mman.h>
2005-09-17 06:27:29 +04:00
# include <stdio.h>
2009-03-31 08:09:39 +04:00
# else
2012-05-22 07:54:16 +04:00
# include <linux/module.h>
2010-08-12 00:38:24 +04:00
# include <linux/gfp.h>
2009-03-31 08:09:39 +04:00
# if !RAID6_USE_EMPTY_ZERO_PAGE
/* In .bss so it's zeroed */
const char raid6_empty_zero_page [ PAGE_SIZE ] __attribute__ ( ( aligned ( 256 ) ) ) ;
EXPORT_SYMBOL ( raid6_empty_zero_page ) ;
# endif
2005-04-17 02:20:36 +04:00
# endif
struct raid6_calls raid6_call ;
2009-03-31 08:09:39 +04:00
EXPORT_SYMBOL_GPL ( raid6_call ) ;
2005-04-17 02:20:36 +04:00
const struct raid6_calls * const raid6_algos [ ] = {
2007-10-29 07:31:16 +03:00
# if defined(__i386__) && !defined(__arch_um__)
2016-08-13 04:03:19 +03:00
# ifdef CONFIG_AS_AVX512
& raid6_avx512x2 ,
2018-11-13 02:26:51 +03:00
& raid6_avx512x1 ,
2016-08-13 04:03:19 +03:00
# endif
2012-12-01 01:10:39 +04:00
& raid6_avx2x2 ,
2018-11-13 02:26:51 +03:00
& raid6_avx2x1 ,
& raid6_sse2x2 ,
& raid6_sse2x1 ,
& raid6_sse1x2 ,
& raid6_sse1x1 ,
& raid6_mmxx2 ,
& raid6_mmxx1 ,
# endif
# if defined(__x86_64__) && !defined(__arch_um__)
2016-08-13 04:03:19 +03:00
# ifdef CONFIG_AS_AVX512
& raid6_avx512x4 ,
2018-11-13 02:26:51 +03:00
& raid6_avx512x2 ,
& raid6_avx512x1 ,
# endif
& raid6_avx2x4 ,
& raid6_avx2x2 ,
& raid6_avx2x1 ,
& raid6_sse2x4 ,
& raid6_sse2x2 ,
& raid6_sse2x1 ,
2005-04-17 02:20:36 +04:00
# endif
# ifdef CONFIG_ALTIVEC
2017-08-04 06:42:32 +03:00
& raid6_vpermxor8 ,
2018-11-13 02:26:51 +03:00
& raid6_vpermxor4 ,
& raid6_vpermxor2 ,
& raid6_vpermxor1 ,
& raid6_altivec8 ,
& raid6_altivec4 ,
& raid6_altivec2 ,
& raid6_altivec1 ,
2013-08-07 20:39:56 +04:00
# endif
2016-08-23 14:30:24 +03:00
# if defined(CONFIG_S390)
& raid6_s390vx8 ,
2005-04-17 02:20:36 +04:00
# endif
2013-05-16 19:20:32 +04:00
# ifdef CONFIG_KERNEL_MODE_NEON
& raid6_neonx8 ,
2018-11-13 02:26:51 +03:00
& raid6_neonx4 ,
& raid6_neonx2 ,
& raid6_neonx1 ,
# endif
# if defined(__ia64__)
& raid6_intx32 ,
& raid6_intx16 ,
2013-05-16 19:20:32 +04:00
# endif
2018-11-13 02:26:51 +03:00
& raid6_intx8 ,
& raid6_intx4 ,
& raid6_intx2 ,
& raid6_intx1 ,
2005-04-17 02:20:36 +04:00
NULL
} ;
2012-05-22 07:54:18 +04:00
void ( * raid6_2data_recov ) ( int , size_t , int , int , void * * ) ;
EXPORT_SYMBOL_GPL ( raid6_2data_recov ) ;
void ( * raid6_datap_recov ) ( int , size_t , int , void * * ) ;
EXPORT_SYMBOL_GPL ( raid6_datap_recov ) ;
const struct raid6_recov_calls * const raid6_recov_algos [ ] = {
2020-03-26 11:00:54 +03:00
# ifdef CONFIG_X86
2016-08-13 04:03:20 +03:00
# ifdef CONFIG_AS_AVX512
& raid6_recov_avx512 ,
# endif
2012-11-09 01:47:44 +04:00
& raid6_recov_avx2 ,
2012-05-22 07:54:18 +04:00
& raid6_recov_ssse3 ,
2016-08-31 10:27:35 +03:00
# endif
# ifdef CONFIG_S390
& raid6_recov_s390xc ,
2017-07-13 20:16:01 +03:00
# endif
# if defined(CONFIG_KERNEL_MODE_NEON)
& raid6_recov_neon ,
2012-05-22 07:54:18 +04:00
# endif
& raid6_recov_intx1 ,
NULL
} ;
2005-04-17 02:20:36 +04:00
# ifdef __KERNEL__
# define RAID6_TIME_JIFFIES_LG2 4
# else
/* Need more time to be stable in userspace */
# define RAID6_TIME_JIFFIES_LG2 9
2009-03-31 08:09:39 +04:00
# define time_before(x, y) ((x) < (y))
2005-04-17 02:20:36 +04:00
# endif
md/raid6: fix algorithm choice under larger PAGE_SIZE
There are several algorithms available for raid6 to generate xor and syndrome
parity, including basic int1, int2 ... int32 and SIMD optimized implementation
like sse and neon. To test and choose the best algorithms at the initial
stage, we need provide enough disk data to feed the algorithms. However, the
disk number we provided depends on page size and gfmul table, seeing bellow:
const int disks = (65536/PAGE_SIZE) + 2;
So when come to 64K PAGE_SIZE, there is only one data disk plus 2 parity disk,
as a result the chosed algorithm is not reliable. For example, on my arm64
machine with 64K page enabled, it will choose intx32 as the best one, although
the NEON implementation is better.
This patch tries to fix the problem by defining a constant raid6 disk number to
supporting arbitrary page size.
Suggested-by: H. Peter Anvin <hpa@zytor.com>
Signed-off-by: Zhengyuan Liu <liuzhengyuan@kylinos.cn>
Signed-off-by: Song Liu <songliubraving@fb.com>
2019-12-20 05:21:28 +03:00
# define RAID6_TEST_DISKS 8
# define RAID6_TEST_DISKS_ORDER 3
2012-05-22 07:54:24 +04:00
static inline const struct raid6_recov_calls * raid6_choose_recov ( void )
2012-05-22 07:54:18 +04:00
{
const struct raid6_recov_calls * const * algo ;
const struct raid6_recov_calls * best ;
for ( best = NULL , algo = raid6_recov_algos ; * algo ; algo + + )
if ( ! best | | ( * algo ) - > priority > best - > priority )
if ( ! ( * algo ) - > valid | | ( * algo ) - > valid ( ) )
best = * algo ;
if ( best ) {
raid6_2data_recov = best - > data2 ;
raid6_datap_recov = best - > datap ;
2014-10-13 16:03:16 +04:00
pr_info ( " raid6: using %s recovery algorithm \n " , best - > name ) ;
2012-05-22 07:54:18 +04:00
} else
2014-10-13 16:03:16 +04:00
pr_err ( " raid6: Yikes! No recovery algorithm found! \n " ) ;
2012-05-22 07:54:18 +04:00
2012-05-22 07:54:24 +04:00
return best ;
}
2005-04-17 02:20:36 +04:00
2012-05-22 07:54:24 +04:00
static inline const struct raid6_calls * raid6_choose_gen (
md/raid6: fix algorithm choice under larger PAGE_SIZE
There are several algorithms available for raid6 to generate xor and syndrome
parity, including basic int1, int2 ... int32 and SIMD optimized implementation
like sse and neon. To test and choose the best algorithms at the initial
stage, we need provide enough disk data to feed the algorithms. However, the
disk number we provided depends on page size and gfmul table, seeing bellow:
const int disks = (65536/PAGE_SIZE) + 2;
So when come to 64K PAGE_SIZE, there is only one data disk plus 2 parity disk,
as a result the chosed algorithm is not reliable. For example, on my arm64
machine with 64K page enabled, it will choose intx32 as the best one, although
the NEON implementation is better.
This patch tries to fix the problem by defining a constant raid6 disk number to
supporting arbitrary page size.
Suggested-by: H. Peter Anvin <hpa@zytor.com>
Signed-off-by: Zhengyuan Liu <liuzhengyuan@kylinos.cn>
Signed-off-by: Song Liu <songliubraving@fb.com>
2019-12-20 05:21:28 +03:00
void * ( * const dptrs ) [ RAID6_TEST_DISKS ] , const int disks )
2005-04-17 02:20:36 +04:00
{
2014-12-15 04:57:04 +03:00
unsigned long perf , bestgenperf , bestxorperf , j0 , j1 ;
int start = ( disks > > 1 ) - 1 , stop = disks - 3 ; /* work on the second half of the disks */
2012-05-22 07:54:24 +04:00
const struct raid6_calls * const * algo ;
const struct raid6_calls * best ;
2005-04-17 02:20:36 +04:00
2014-12-15 04:57:04 +03:00
for ( bestgenperf = 0 , bestxorperf = 0 , best = NULL , algo = raid6_algos ; * algo ; algo + + ) {
2012-05-22 07:54:24 +04:00
if ( ! best | | ( * algo ) - > prefer > = best - > prefer ) {
if ( ( * algo ) - > valid & & ! ( * algo ) - > valid ( ) )
continue ;
2005-04-17 02:20:36 +04:00
2018-11-13 02:26:52 +03:00
if ( ! IS_ENABLED ( CONFIG_RAID6_PQ_BENCHMARK ) ) {
best = * algo ;
break ;
}
2005-04-17 02:20:36 +04:00
perf = 0 ;
preempt_disable ( ) ;
j0 = jiffies ;
2012-05-22 07:54:24 +04:00
while ( ( j1 = jiffies ) = = j0 )
2005-04-17 02:20:36 +04:00
cpu_relax ( ) ;
2008-04-28 13:15:56 +04:00
while ( time_before ( jiffies ,
j1 + ( 1 < < RAID6_TIME_JIFFIES_LG2 ) ) ) {
2012-05-22 07:54:24 +04:00
( * algo ) - > gen_syndrome ( disks , PAGE_SIZE , * dptrs ) ;
2005-04-17 02:20:36 +04:00
perf + + ;
}
preempt_enable ( ) ;
2014-12-15 04:57:04 +03:00
if ( perf > bestgenperf ) {
bestgenperf = perf ;
2012-05-22 07:54:24 +04:00
best = * algo ;
2005-04-17 02:20:36 +04:00
}
2014-12-15 04:57:04 +03:00
pr_info ( " raid6: %-8s gen() %5ld MB/s \n " , ( * algo ) - > name ,
md/raid6: fix algorithm choice under larger PAGE_SIZE
There are several algorithms available for raid6 to generate xor and syndrome
parity, including basic int1, int2 ... int32 and SIMD optimized implementation
like sse and neon. To test and choose the best algorithms at the initial
stage, we need provide enough disk data to feed the algorithms. However, the
disk number we provided depends on page size and gfmul table, seeing bellow:
const int disks = (65536/PAGE_SIZE) + 2;
So when come to 64K PAGE_SIZE, there is only one data disk plus 2 parity disk,
as a result the chosed algorithm is not reliable. For example, on my arm64
machine with 64K page enabled, it will choose intx32 as the best one, although
the NEON implementation is better.
This patch tries to fix the problem by defining a constant raid6 disk number to
supporting arbitrary page size.
Suggested-by: H. Peter Anvin <hpa@zytor.com>
Signed-off-by: Zhengyuan Liu <liuzhengyuan@kylinos.cn>
Signed-off-by: Song Liu <songliubraving@fb.com>
2019-12-20 05:21:28 +03:00
( perf * HZ * ( disks - 2 ) ) > >
( 20 - PAGE_SHIFT + RAID6_TIME_JIFFIES_LG2 ) ) ;
2014-12-15 04:57:04 +03:00
if ( ! ( * algo ) - > xor_syndrome )
continue ;
perf = 0 ;
preempt_disable ( ) ;
j0 = jiffies ;
while ( ( j1 = jiffies ) = = j0 )
cpu_relax ( ) ;
while ( time_before ( jiffies ,
j1 + ( 1 < < RAID6_TIME_JIFFIES_LG2 ) ) ) {
( * algo ) - > xor_syndrome ( disks , start , stop ,
PAGE_SIZE , * dptrs ) ;
perf + + ;
}
preempt_enable ( ) ;
if ( best = = * algo )
bestxorperf = perf ;
pr_info ( " raid6: %-8s xor() %5ld MB/s \n " , ( * algo ) - > name ,
md/raid6: fix algorithm choice under larger PAGE_SIZE
There are several algorithms available for raid6 to generate xor and syndrome
parity, including basic int1, int2 ... int32 and SIMD optimized implementation
like sse and neon. To test and choose the best algorithms at the initial
stage, we need provide enough disk data to feed the algorithms. However, the
disk number we provided depends on page size and gfmul table, seeing bellow:
const int disks = (65536/PAGE_SIZE) + 2;
So when come to 64K PAGE_SIZE, there is only one data disk plus 2 parity disk,
as a result the chosed algorithm is not reliable. For example, on my arm64
machine with 64K page enabled, it will choose intx32 as the best one, although
the NEON implementation is better.
This patch tries to fix the problem by defining a constant raid6 disk number to
supporting arbitrary page size.
Suggested-by: H. Peter Anvin <hpa@zytor.com>
Signed-off-by: Zhengyuan Liu <liuzhengyuan@kylinos.cn>
Signed-off-by: Song Liu <songliubraving@fb.com>
2019-12-20 05:21:28 +03:00
( perf * HZ * ( disks - 2 ) ) > >
( 20 - PAGE_SHIFT + RAID6_TIME_JIFFIES_LG2 + 1 ) ) ;
2005-04-17 02:20:36 +04:00
}
}
2006-06-23 13:05:59 +04:00
if ( best ) {
md/raid6: fix algorithm choice under larger PAGE_SIZE
There are several algorithms available for raid6 to generate xor and syndrome
parity, including basic int1, int2 ... int32 and SIMD optimized implementation
like sse and neon. To test and choose the best algorithms at the initial
stage, we need provide enough disk data to feed the algorithms. However, the
disk number we provided depends on page size and gfmul table, seeing bellow:
const int disks = (65536/PAGE_SIZE) + 2;
So when come to 64K PAGE_SIZE, there is only one data disk plus 2 parity disk,
as a result the chosed algorithm is not reliable. For example, on my arm64
machine with 64K page enabled, it will choose intx32 as the best one, although
the NEON implementation is better.
This patch tries to fix the problem by defining a constant raid6 disk number to
supporting arbitrary page size.
Suggested-by: H. Peter Anvin <hpa@zytor.com>
Signed-off-by: Zhengyuan Liu <liuzhengyuan@kylinos.cn>
Signed-off-by: Song Liu <songliubraving@fb.com>
2019-12-20 05:21:28 +03:00
if ( IS_ENABLED ( CONFIG_RAID6_PQ_BENCHMARK ) ) {
pr_info ( " raid6: using algorithm %s gen() %ld MB/s \n " ,
best - > name ,
( bestgenperf * HZ * ( disks - 2 ) ) > >
( 20 - PAGE_SHIFT + RAID6_TIME_JIFFIES_LG2 ) ) ;
if ( best - > xor_syndrome )
pr_info ( " raid6: .... xor() %ld MB/s, rmw enabled \n " ,
( bestxorperf * HZ * ( disks - 2 ) ) > >
( 20 - PAGE_SHIFT + RAID6_TIME_JIFFIES_LG2 + 1 ) ) ;
} else
pr_info ( " raid6: skip pq benchmark and using algorithm %s \n " ,
best - > name ) ;
2006-06-23 13:05:59 +04:00
raid6_call = * best ;
} else
2014-10-13 16:03:16 +04:00
pr_err ( " raid6: Yikes! No algorithm found! \n " ) ;
2005-04-17 02:20:36 +04:00
2012-05-22 07:54:24 +04:00
return best ;
}
/* Try to pick the best algorithm */
/* This code uses the gfmul table as convenient data set to abuse */
int __init raid6_select_algo ( void )
{
md/raid6: fix algorithm choice under larger PAGE_SIZE
There are several algorithms available for raid6 to generate xor and syndrome
parity, including basic int1, int2 ... int32 and SIMD optimized implementation
like sse and neon. To test and choose the best algorithms at the initial
stage, we need provide enough disk data to feed the algorithms. However, the
disk number we provided depends on page size and gfmul table, seeing bellow:
const int disks = (65536/PAGE_SIZE) + 2;
So when come to 64K PAGE_SIZE, there is only one data disk plus 2 parity disk,
as a result the chosed algorithm is not reliable. For example, on my arm64
machine with 64K page enabled, it will choose intx32 as the best one, although
the NEON implementation is better.
This patch tries to fix the problem by defining a constant raid6 disk number to
supporting arbitrary page size.
Suggested-by: H. Peter Anvin <hpa@zytor.com>
Signed-off-by: Zhengyuan Liu <liuzhengyuan@kylinos.cn>
Signed-off-by: Song Liu <songliubraving@fb.com>
2019-12-20 05:21:28 +03:00
const int disks = RAID6_TEST_DISKS ;
2012-05-22 07:54:24 +04:00
const struct raid6_calls * gen_best ;
const struct raid6_recov_calls * rec_best ;
md/raid6: fix algorithm choice under larger PAGE_SIZE
There are several algorithms available for raid6 to generate xor and syndrome
parity, including basic int1, int2 ... int32 and SIMD optimized implementation
like sse and neon. To test and choose the best algorithms at the initial
stage, we need provide enough disk data to feed the algorithms. However, the
disk number we provided depends on page size and gfmul table, seeing bellow:
const int disks = (65536/PAGE_SIZE) + 2;
So when come to 64K PAGE_SIZE, there is only one data disk plus 2 parity disk,
as a result the chosed algorithm is not reliable. For example, on my arm64
machine with 64K page enabled, it will choose intx32 as the best one, although
the NEON implementation is better.
This patch tries to fix the problem by defining a constant raid6 disk number to
supporting arbitrary page size.
Suggested-by: H. Peter Anvin <hpa@zytor.com>
Signed-off-by: Zhengyuan Liu <liuzhengyuan@kylinos.cn>
Signed-off-by: Song Liu <songliubraving@fb.com>
2019-12-20 05:21:28 +03:00
char * disk_ptr , * p ;
void * dptrs [ RAID6_TEST_DISKS ] ;
int i , cycle ;
2012-05-22 07:54:24 +04:00
md/raid6: fix algorithm choice under larger PAGE_SIZE
There are several algorithms available for raid6 to generate xor and syndrome
parity, including basic int1, int2 ... int32 and SIMD optimized implementation
like sse and neon. To test and choose the best algorithms at the initial
stage, we need provide enough disk data to feed the algorithms. However, the
disk number we provided depends on page size and gfmul table, seeing bellow:
const int disks = (65536/PAGE_SIZE) + 2;
So when come to 64K PAGE_SIZE, there is only one data disk plus 2 parity disk,
as a result the chosed algorithm is not reliable. For example, on my arm64
machine with 64K page enabled, it will choose intx32 as the best one, although
the NEON implementation is better.
This patch tries to fix the problem by defining a constant raid6 disk number to
supporting arbitrary page size.
Suggested-by: H. Peter Anvin <hpa@zytor.com>
Signed-off-by: Zhengyuan Liu <liuzhengyuan@kylinos.cn>
Signed-off-by: Song Liu <songliubraving@fb.com>
2019-12-20 05:21:28 +03:00
/* prepare the buffer and fill it circularly with gfmul table */
disk_ptr = ( char * ) __get_free_pages ( GFP_KERNEL , RAID6_TEST_DISKS_ORDER ) ;
if ( ! disk_ptr ) {
2014-10-13 16:03:16 +04:00
pr_err ( " raid6: Yikes! No memory available. \n " ) ;
2012-05-22 07:54:24 +04:00
return - ENOMEM ;
}
md/raid6: fix algorithm choice under larger PAGE_SIZE
There are several algorithms available for raid6 to generate xor and syndrome
parity, including basic int1, int2 ... int32 and SIMD optimized implementation
like sse and neon. To test and choose the best algorithms at the initial
stage, we need provide enough disk data to feed the algorithms. However, the
disk number we provided depends on page size and gfmul table, seeing bellow:
const int disks = (65536/PAGE_SIZE) + 2;
So when come to 64K PAGE_SIZE, there is only one data disk plus 2 parity disk,
as a result the chosed algorithm is not reliable. For example, on my arm64
machine with 64K page enabled, it will choose intx32 as the best one, although
the NEON implementation is better.
This patch tries to fix the problem by defining a constant raid6 disk number to
supporting arbitrary page size.
Suggested-by: H. Peter Anvin <hpa@zytor.com>
Signed-off-by: Zhengyuan Liu <liuzhengyuan@kylinos.cn>
Signed-off-by: Song Liu <songliubraving@fb.com>
2019-12-20 05:21:28 +03:00
p = disk_ptr ;
for ( i = 0 ; i < disks ; i + + )
dptrs [ i ] = p + PAGE_SIZE * i ;
cycle = ( ( disks - 2 ) * PAGE_SIZE ) / 65536 ;
for ( i = 0 ; i < cycle ; i + + ) {
memcpy ( p , raid6_gfmul , 65536 ) ;
p + = 65536 ;
}
if ( ( disks - 2 ) * PAGE_SIZE % 65536 )
memcpy ( p , raid6_gfmul , ( disks - 2 ) * PAGE_SIZE % 65536 ) ;
2012-05-22 07:54:24 +04:00
/* select raid gen_syndrome function */
gen_best = raid6_choose_gen ( & dptrs , disks ) ;
2005-04-17 02:20:36 +04:00
2012-05-22 07:54:18 +04:00
/* select raid recover functions */
2012-05-22 07:54:24 +04:00
rec_best = raid6_choose_recov ( ) ;
md/raid6: fix algorithm choice under larger PAGE_SIZE
There are several algorithms available for raid6 to generate xor and syndrome
parity, including basic int1, int2 ... int32 and SIMD optimized implementation
like sse and neon. To test and choose the best algorithms at the initial
stage, we need provide enough disk data to feed the algorithms. However, the
disk number we provided depends on page size and gfmul table, seeing bellow:
const int disks = (65536/PAGE_SIZE) + 2;
So when come to 64K PAGE_SIZE, there is only one data disk plus 2 parity disk,
as a result the chosed algorithm is not reliable. For example, on my arm64
machine with 64K page enabled, it will choose intx32 as the best one, although
the NEON implementation is better.
This patch tries to fix the problem by defining a constant raid6 disk number to
supporting arbitrary page size.
Suggested-by: H. Peter Anvin <hpa@zytor.com>
Signed-off-by: Zhengyuan Liu <liuzhengyuan@kylinos.cn>
Signed-off-by: Song Liu <songliubraving@fb.com>
2019-12-20 05:21:28 +03:00
free_pages ( ( unsigned long ) disk_ptr , RAID6_TEST_DISKS_ORDER ) ;
2012-05-22 07:54:18 +04:00
2012-05-22 07:54:24 +04:00
return gen_best & & rec_best ? 0 : - EINVAL ;
2005-04-17 02:20:36 +04:00
}
2009-03-31 08:09:39 +04:00
static void raid6_exit ( void )
{
do { } while ( 0 ) ;
}
subsys_initcall ( raid6_select_algo ) ;
module_exit ( raid6_exit ) ;
MODULE_LICENSE ( " GPL " ) ;
2009-12-14 04:49:58 +03:00
MODULE_DESCRIPTION ( " RAID6 Q-syndrome calculations " ) ;