4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
22 * Copyright (C) 2016 Gvozden Nešković. All rights reserved.
25 #ifndef _VDEV_RAIDZ_MATH_IMPL_H
26 #define _VDEV_RAIDZ_MATH_IMPL_H
28 #include <sys/types.h>
30 #define raidz_inline inline __attribute__((always_inline))
32 #define noinline __attribute__((noinline))
35 /* Calculate data offset in raidz column, offset is in bytes */
36 #define COL_OFF(col, off) ((v_t *)(((char *)(col)->rc_data) + (off)))
40 * An optimized function is called for a full length of data columns
41 * If RAIDZ map contains remainder columns (shorter columns) the same function
42 * is called for reminder of full columns.
44 * GEN_[P|PQ|PQR]_BLOCK() functions are designed to be efficiently in-lined by
45 * the compiler. This removes a lot of conditionals from the inside loop which
46 * makes the code faster, especially for vectorized code.
47 * They are also highly parametrized, allowing for each implementation to define
48 * most optimal stride, and register allocation.
51 static raidz_inline
void
52 GEN_P_BLOCK(raidz_map_t
* const rm
, const size_t off
, const size_t end
,
57 raidz_col_t
* const pcol
= raidz_col_p(rm
, CODE_P
);
62 for (ioff
= off
; ioff
< end
; ioff
+= (GEN_P_STRIDE
* sizeof (v_t
))) {
63 LOAD(COL_OFF(&(rm
->rm_col
[1]), ioff
), GEN_P_P
);
65 for (c
= 2; c
< ncols
; c
++) {
67 XOR_ACC(COL_OFF(col
, ioff
), GEN_P_P
);
70 STORE(COL_OFF(pcol
, ioff
), GEN_P_P
);
75 * Generate P parity (RAIDZ1)
79 static raidz_inline
void
80 raidz_generate_p_impl(raidz_map_t
* const rm
)
82 const int ncols
= raidz_ncols(rm
);
83 const size_t psize
= raidz_big_size(rm
);
84 const size_t short_size
= raidz_short_size(rm
);
89 GEN_P_BLOCK(rm
, 0, short_size
, ncols
);
92 GEN_P_BLOCK(rm
, short_size
, psize
, raidz_nbigcols(rm
));
97 static raidz_inline
void
98 GEN_PQ_BLOCK(raidz_map_t
* const rm
, const size_t off
, const size_t end
,
99 const int ncols
, const int nbigcols
)
103 raidz_col_t
* const pcol
= raidz_col_p(rm
, CODE_P
);
104 raidz_col_t
* const qcol
= raidz_col_p(rm
, CODE_Q
);
111 for (ioff
= off
; ioff
< end
; ioff
+= (GEN_PQ_STRIDE
* sizeof (v_t
))) {
112 LOAD(COL_OFF(&rm
->rm_col
[2], ioff
), GEN_PQ_P
);
113 COPY(GEN_PQ_P
, GEN_PQ_Q
);
115 for (c
= 3; c
< nbigcols
; c
++) {
116 col
= &rm
->rm_col
[c
];
117 LOAD(COL_OFF(col
, ioff
), GEN_PQ_D
);
119 XOR(GEN_PQ_D
, GEN_PQ_P
);
120 XOR(GEN_PQ_D
, GEN_PQ_Q
);
123 STORE(COL_OFF(pcol
, ioff
), GEN_PQ_P
);
125 for (; c
< ncols
; c
++)
128 STORE(COL_OFF(qcol
, ioff
), GEN_PQ_Q
);
133 * Generate PQ parity (RAIDZ2)
137 static raidz_inline
void
138 raidz_generate_pq_impl(raidz_map_t
* const rm
)
140 const int ncols
= raidz_ncols(rm
);
141 const size_t psize
= raidz_big_size(rm
);
142 const size_t short_size
= raidz_short_size(rm
);
147 GEN_PQ_BLOCK(rm
, 0, short_size
, ncols
, ncols
);
150 GEN_PQ_BLOCK(rm
, short_size
, psize
, ncols
, raidz_nbigcols(rm
));
156 static raidz_inline
void
157 GEN_PQR_BLOCK(raidz_map_t
* const rm
, const size_t off
, const size_t end
,
158 const int ncols
, const int nbigcols
)
163 raidz_col_t
* const pcol
= raidz_col_p(rm
, CODE_P
);
164 raidz_col_t
* const qcol
= raidz_col_p(rm
, CODE_Q
);
165 raidz_col_t
* const rcol
= raidz_col_p(rm
, CODE_R
);
171 for (ioff
= off
; ioff
< end
; ioff
+= (GEN_PQR_STRIDE
* sizeof (v_t
))) {
172 LOAD(COL_OFF(&rm
->rm_col
[3], ioff
), GEN_PQR_P
);
173 COPY(GEN_PQR_P
, GEN_PQR_Q
);
174 COPY(GEN_PQR_P
, GEN_PQR_R
);
176 for (c
= 4; c
< nbigcols
; c
++) {
177 col
= &rm
->rm_col
[c
];
178 LOAD(COL_OFF(col
, ioff
), GEN_PQR_D
);
181 XOR(GEN_PQR_D
, GEN_PQR_P
);
182 XOR(GEN_PQR_D
, GEN_PQR_Q
);
183 XOR(GEN_PQR_D
, GEN_PQR_R
);
186 STORE(COL_OFF(pcol
, ioff
), GEN_PQR_P
);
188 for (; c
< ncols
; c
++) {
193 STORE(COL_OFF(qcol
, ioff
), GEN_PQR_Q
);
194 STORE(COL_OFF(rcol
, ioff
), GEN_PQR_R
);
200 * Generate PQR parity (RAIDZ3)
204 static raidz_inline
void
205 raidz_generate_pqr_impl(raidz_map_t
* const rm
)
207 const int ncols
= raidz_ncols(rm
);
208 const size_t psize
= raidz_big_size(rm
);
209 const size_t short_size
= raidz_short_size(rm
);
214 GEN_PQR_BLOCK(rm
, 0, short_size
, ncols
, ncols
);
217 GEN_PQR_BLOCK(rm
, short_size
, psize
, ncols
, raidz_nbigcols(rm
));
223 * DATA RECONSTRUCTION
225 * Data reconstruction process consists of two phases:
226 * - Syndrome calculation
227 * - Data reconstruction
229 * Syndrome is calculated by generating parity using available data columns
230 * and zeros in places of erasure. Existing parity is added to corresponding
231 * syndrome value to obtain the [P|Q|R]syn values from equation:
232 * P = Psyn + Dx + Dy + Dz
233 * Q = Qsyn + 2^x * Dx + 2^y * Dy + 2^z * Dz
234 * R = Rsyn + 4^x * Dx + 4^y * Dy + 4^z * Dz
236 * For data reconstruction phase, the corresponding equations are solved
237 * for missing data (Dx, Dy, Dz). This generally involves multiplying known
238 * symbols by an coefficient and adding them together. The multiplication
239 * constant coefficients are calculated ahead of the operation in
240 * raidz_rec_[q|r|pq|pq|qr|pqr]_coeff() functions.
242 * IMPLEMENTATION NOTE: RAID-Z block can have complex geometry, with "big"
243 * and "short" columns.
244 * For this reason, reconstruction is performed in minimum of
245 * two steps. First, from offset 0 to short_size, then from short_size to
246 * short_size. Calculation functions REC_[*]_BLOCK() are implemented to work
247 * over both ranges. The split also enables removal of conditional expressions
248 * from loop bodies, improving throughput of SIMD implementations.
249 * For the best performance, all functions marked with raidz_inline attribute
250 * must be inlined by compiler.
254 * <----------> <------------------>
255 * x y <----+ missing columns (x, y)
257 * +---+---+---+---+-v-+---+-v-+---+ ^ 0
258 * | | | | | | | | | |
259 * | | | | | | | | | |
260 * | P | Q | R | D | D | D | D | D | |
261 * | | | | 0 | 1 | 2 | 3 | 4 | |
262 * | | | | | | | | | v
263 * | | | | | +---+---+---+ ^ short_size
265 * +---+---+---+---+---+ v big_size
266 * <------------------> <---------->
267 * big columns short columns
272 * Functions calculate multiplication constants for data reconstruction.
273 * Coefficients depend on RAIDZ geometry, indexes of failed child vdevs, and
274 * used parity columns for reconstruction.
276 * @tgtidx array of missing data indexes
277 * @coeff output array of coefficients. Array must be user
278 * provided and must hold minimum MUL_CNT values
281 raidz_rec_q_coeff(const raidz_map_t
*rm
, const int *tgtidx
, unsigned *coeff
)
283 const unsigned ncols
= raidz_ncols(rm
);
284 const unsigned x
= tgtidx
[TARGET_X
];
286 coeff
[MUL_Q_X
] = gf_exp2(255 - (ncols
- x
- 1));
290 raidz_rec_r_coeff(const raidz_map_t
*rm
, const int *tgtidx
, unsigned *coeff
)
292 const unsigned ncols
= raidz_ncols(rm
);
293 const unsigned x
= tgtidx
[TARGET_X
];
295 coeff
[MUL_R_X
] = gf_exp4(255 - (ncols
- x
- 1));
299 raidz_rec_pq_coeff(const raidz_map_t
*rm
, const int *tgtidx
, unsigned *coeff
)
301 const unsigned ncols
= raidz_ncols(rm
);
302 const unsigned x
= tgtidx
[TARGET_X
];
303 const unsigned y
= tgtidx
[TARGET_Y
];
306 a
= gf_exp2(x
+ 255 - y
);
307 b
= gf_exp2(255 - (ncols
- x
- 1));
310 coeff
[MUL_PQ_X
] = gf_div(a
, e
);
311 coeff
[MUL_PQ_Y
] = gf_div(b
, e
);
315 raidz_rec_pr_coeff(const raidz_map_t
*rm
, const int *tgtidx
, unsigned *coeff
)
317 const unsigned ncols
= raidz_ncols(rm
);
318 const unsigned x
= tgtidx
[TARGET_X
];
319 const unsigned y
= tgtidx
[TARGET_Y
];
323 a
= gf_exp4(x
+ 255 - y
);
324 b
= gf_exp4(255 - (ncols
- x
- 1));
327 coeff
[MUL_PR_X
] = gf_div(a
, e
);
328 coeff
[MUL_PR_Y
] = gf_div(b
, e
);
332 raidz_rec_qr_coeff(const raidz_map_t
*rm
, const int *tgtidx
, unsigned *coeff
)
334 const unsigned ncols
= raidz_ncols(rm
);
335 const unsigned x
= tgtidx
[TARGET_X
];
336 const unsigned y
= tgtidx
[TARGET_Y
];
338 gf_t nx
, ny
, nxxy
, nxyy
, d
;
340 nx
= gf_exp2(ncols
- x
- 1);
341 ny
= gf_exp2(ncols
- y
- 1);
342 nxxy
= gf_mul(gf_mul(nx
, nx
), ny
);
343 nxyy
= gf_mul(gf_mul(nx
, ny
), ny
);
346 coeff
[MUL_QR_XQ
] = ny
;
347 coeff
[MUL_QR_X
] = gf_div(ny
, d
);
348 coeff
[MUL_QR_YQ
] = nx
;
349 coeff
[MUL_QR_Y
] = gf_div(nx
, d
);
353 raidz_rec_pqr_coeff(const raidz_map_t
*rm
, const int *tgtidx
, unsigned *coeff
)
355 const unsigned ncols
= raidz_ncols(rm
);
356 const unsigned x
= tgtidx
[TARGET_X
];
357 const unsigned y
= tgtidx
[TARGET_Y
];
358 const unsigned z
= tgtidx
[TARGET_Z
];
360 gf_t nx
, ny
, nz
, nxx
, nyy
, nzz
, nyyz
, nyzz
, xd
, yd
;
362 nx
= gf_exp2(ncols
- x
- 1);
363 ny
= gf_exp2(ncols
- y
- 1);
364 nz
= gf_exp2(ncols
- z
- 1);
366 nxx
= gf_exp4(ncols
- x
- 1);
367 nyy
= gf_exp4(ncols
- y
- 1);
368 nzz
= gf_exp4(ncols
- z
- 1);
370 nyyz
= gf_mul(gf_mul(ny
, nz
), ny
);
371 nyzz
= gf_mul(nzz
, ny
);
373 xd
= gf_mul(nxx
, ny
) ^ gf_mul(nx
, nyy
) ^ nyyz
^
374 gf_mul(nxx
, nz
) ^ gf_mul(nzz
, nx
) ^ nyzz
;
376 yd
= gf_inv(ny
^ nz
);
378 coeff
[MUL_PQR_XP
] = gf_div(nyyz
^ nyzz
, xd
);
379 coeff
[MUL_PQR_XQ
] = gf_div(nyy
^ nzz
, xd
);
380 coeff
[MUL_PQR_XR
] = gf_div(ny
^ nz
, xd
);
381 coeff
[MUL_PQR_YU
] = nx
;
382 coeff
[MUL_PQR_YP
] = gf_mul(nz
, yd
);
383 coeff
[MUL_PQR_YQ
] = yd
;
388 * Reconstruction using P parity
390 * @off starting offset
392 * @x missing data column
393 * @ncols number of column
395 static raidz_inline
void
396 REC_P_BLOCK(raidz_map_t
* const rm
, const size_t off
, const size_t end
,
397 const int x
, const int ncols
)
401 const size_t firstdc
= raidz_parity(rm
);
402 raidz_col_t
* const pcol
= raidz_col_p(rm
, CODE_P
);
403 raidz_col_t
* const xcol
= raidz_col_p(rm
, x
);
408 for (ioff
= off
; ioff
< end
; ioff
+= (REC_P_STRIDE
* sizeof (v_t
))) {
409 LOAD(COL_OFF(pcol
, ioff
), REC_P_X
);
411 for (c
= firstdc
; c
< x
; c
++) {
412 col
= &rm
->rm_col
[c
];
413 XOR_ACC(COL_OFF(col
, ioff
), REC_P_X
);
416 for (c
++; c
< ncols
; c
++) {
417 col
= &rm
->rm_col
[c
];
418 XOR_ACC(COL_OFF(col
, ioff
), REC_P_X
);
421 STORE(COL_OFF(xcol
, ioff
), REC_P_X
);
426 * Reconstruct single data column using P parity
427 * @rec_method REC_P_BLOCK()
430 * @tgtidx array of missing data indexes
432 static raidz_inline
int
433 raidz_reconstruct_p_impl(raidz_map_t
*rm
, const int *tgtidx
)
435 const int x
= tgtidx
[TARGET_X
];
436 const int ncols
= raidz_ncols(rm
);
437 const int nbigcols
= raidz_nbigcols(rm
);
438 const size_t xsize
= raidz_col_size(rm
, x
);
439 const size_t short_size
= raidz_short_size(rm
);
444 REC_P_BLOCK(rm
, 0, short_size
, x
, ncols
);
446 /* short_size - xsize */
447 REC_P_BLOCK(rm
, short_size
, xsize
, x
, nbigcols
);
451 return (1 << CODE_P
);
455 * Reconstruct using Q parity
458 #define REC_Q_SYN_UPDATE() MUL2(REC_Q_X)
460 #define REC_Q_INNER_LOOP(c) \
462 col = &rm->rm_col[c]; \
463 REC_Q_SYN_UPDATE(); \
464 XOR_ACC(COL_OFF(col, ioff), REC_Q_X); \
468 * Reconstruction using Q parity
470 * @off starting offset
472 * @x missing data column
473 * @coeff multiplication coefficients
474 * @ncols number of column
475 * @nbigcols number of big columns
477 static raidz_inline
void
478 REC_Q_BLOCK(raidz_map_t
* const rm
, const size_t off
, const size_t end
,
479 const int x
, const unsigned *coeff
, const int ncols
, const int nbigcols
)
483 const size_t firstdc
= raidz_parity(rm
);
484 raidz_col_t
* const qcol
= raidz_col_p(rm
, CODE_Q
);
485 raidz_col_t
* const xcol
= raidz_col_p(rm
, x
);
490 for (ioff
= off
; ioff
< end
; ioff
+= (REC_Q_STRIDE
* sizeof (v_t
))) {
493 XOR(REC_Q_X
, REC_Q_X
);
495 if (ncols
== nbigcols
) {
496 for (c
= firstdc
; c
< x
; c
++)
500 for (c
++; c
< nbigcols
; c
++)
503 for (c
= firstdc
; c
< nbigcols
; c
++) {
506 col
= &rm
->rm_col
[c
];
507 XOR_ACC(COL_OFF(col
, ioff
), REC_Q_X
);
510 for (; c
< ncols
; c
++)
514 XOR_ACC(COL_OFF(qcol
, ioff
), REC_Q_X
);
515 MUL(coeff
[MUL_Q_X
], REC_Q_X
);
516 STORE(COL_OFF(xcol
, ioff
), REC_Q_X
);
521 * Reconstruct single data column using Q parity
522 * @rec_method REC_Q_BLOCK()
525 * @tgtidx array of missing data indexes
527 static raidz_inline
int
528 raidz_reconstruct_q_impl(raidz_map_t
*rm
, const int *tgtidx
)
530 const int x
= tgtidx
[TARGET_X
];
531 const int ncols
= raidz_ncols(rm
);
532 const int nbigcols
= raidz_nbigcols(rm
);
533 const size_t xsize
= raidz_col_size(rm
, x
);
534 const size_t short_size
= raidz_short_size(rm
);
535 unsigned coeff
[MUL_CNT
];
537 raidz_rec_q_coeff(rm
, tgtidx
, coeff
);
542 REC_Q_BLOCK(rm
, 0, short_size
, x
, coeff
, ncols
, ncols
);
544 /* short_size - xsize */
545 REC_Q_BLOCK(rm
, short_size
, xsize
, x
, coeff
, ncols
, nbigcols
);
549 return (1 << CODE_Q
);
553 * Reconstruct using R parity
556 #define REC_R_SYN_UPDATE() MUL4(REC_R_X)
557 #define REC_R_INNER_LOOP(c) \
559 col = &rm->rm_col[c]; \
560 REC_R_SYN_UPDATE(); \
561 XOR_ACC(COL_OFF(col, ioff), REC_R_X); \
565 * Reconstruction using R parity
567 * @off starting offset
569 * @x missing data column
570 * @coeff multiplication coefficients
571 * @ncols number of column
572 * @nbigcols number of big columns
574 static raidz_inline
void
575 REC_R_BLOCK(raidz_map_t
* const rm
, const size_t off
, const size_t end
,
576 const int x
, const unsigned *coeff
, const int ncols
, const int nbigcols
)
580 const size_t firstdc
= raidz_parity(rm
);
581 raidz_col_t
* const rcol
= raidz_col_p(rm
, CODE_R
);
582 raidz_col_t
* const xcol
= raidz_col_p(rm
, x
);
587 for (ioff
= off
; ioff
< end
; ioff
+= (REC_R_STRIDE
* sizeof (v_t
))) {
590 XOR(REC_R_X
, REC_R_X
);
592 if (ncols
== nbigcols
) {
593 for (c
= firstdc
; c
< x
; c
++)
597 for (c
++; c
< nbigcols
; c
++)
600 for (c
= firstdc
; c
< nbigcols
; c
++) {
603 col
= &rm
->rm_col
[c
];
604 XOR_ACC(COL_OFF(col
, ioff
), REC_R_X
);
607 for (; c
< ncols
; c
++)
611 XOR_ACC(COL_OFF(rcol
, ioff
), REC_R_X
);
612 MUL(coeff
[MUL_R_X
], REC_R_X
);
613 STORE(COL_OFF(xcol
, ioff
), REC_R_X
);
618 * Reconstruct single data column using R parity
619 * @rec_method REC_R_BLOCK()
622 * @tgtidx array of missing data indexes
624 static raidz_inline
int
625 raidz_reconstruct_r_impl(raidz_map_t
*rm
, const int *tgtidx
)
627 const int x
= tgtidx
[TARGET_X
];
628 const int ncols
= raidz_ncols(rm
);
629 const int nbigcols
= raidz_nbigcols(rm
);
630 const size_t xsize
= raidz_col_size(rm
, x
);
631 const size_t short_size
= raidz_short_size(rm
);
632 unsigned coeff
[MUL_CNT
];
634 raidz_rec_r_coeff(rm
, tgtidx
, coeff
);
639 REC_R_BLOCK(rm
, 0, short_size
, x
, coeff
, ncols
, ncols
);
641 /* short_size - xsize */
642 REC_R_BLOCK(rm
, short_size
, xsize
, x
, coeff
, ncols
, nbigcols
);
646 return (1 << CODE_R
);
650 * Reconstruct using PQ parity
653 #define REC_PQ_SYN_UPDATE() MUL2(REC_PQ_Y)
654 #define REC_PQ_INNER_LOOP(c) \
656 col = &rm->rm_col[c]; \
657 LOAD(COL_OFF(col, ioff), REC_PQ_D); \
658 REC_PQ_SYN_UPDATE(); \
659 XOR(REC_PQ_D, REC_PQ_X); \
660 XOR(REC_PQ_D, REC_PQ_Y); \
664 * Reconstruction using PQ parity
666 * @off starting offset
668 * @x missing data column
669 * @y missing data column
670 * @coeff multiplication coefficients
671 * @ncols number of column
672 * @nbigcols number of big columns
673 * @calcy calculate second data column
675 static raidz_inline
void
676 REC_PQ_BLOCK(raidz_map_t
* const rm
, const size_t off
, const size_t end
,
677 const int x
, const int y
, const unsigned *coeff
, const int ncols
,
678 const int nbigcols
, const boolean_t calcy
)
682 const size_t firstdc
= raidz_parity(rm
);
683 raidz_col_t
* const pcol
= raidz_col_p(rm
, CODE_P
);
684 raidz_col_t
* const qcol
= raidz_col_p(rm
, CODE_Q
);
685 raidz_col_t
* const xcol
= raidz_col_p(rm
, x
);
686 raidz_col_t
* const ycol
= raidz_col_p(rm
, y
);
691 for (ioff
= off
; ioff
< end
; ioff
+= (REC_PQ_STRIDE
* sizeof (v_t
))) {
692 LOAD(COL_OFF(pcol
, ioff
), REC_PQ_X
);
693 XOR(REC_PQ_Y
, REC_PQ_Y
);
696 if (ncols
== nbigcols
) {
697 for (c
= firstdc
; c
< x
; c
++)
698 REC_PQ_INNER_LOOP(c
);
701 for (c
++; c
< y
; c
++)
702 REC_PQ_INNER_LOOP(c
);
705 for (c
++; c
< nbigcols
; c
++)
706 REC_PQ_INNER_LOOP(c
);
708 for (c
= firstdc
; c
< nbigcols
; c
++) {
710 if (c
!= x
&& c
!= y
) {
711 col
= &rm
->rm_col
[c
];
712 LOAD(COL_OFF(col
, ioff
), REC_PQ_D
);
713 XOR(REC_PQ_D
, REC_PQ_X
);
714 XOR(REC_PQ_D
, REC_PQ_Y
);
717 for (; c
< ncols
; c
++)
721 XOR_ACC(COL_OFF(qcol
, ioff
), REC_PQ_Y
);
724 COPY(REC_PQ_X
, REC_PQ_D
);
727 MUL(coeff
[MUL_PQ_X
], REC_PQ_X
);
728 MUL(coeff
[MUL_PQ_Y
], REC_PQ_Y
);
729 XOR(REC_PQ_Y
, REC_PQ_X
);
730 STORE(COL_OFF(xcol
, ioff
), REC_PQ_X
);
734 XOR(REC_PQ_D
, REC_PQ_X
);
735 STORE(COL_OFF(ycol
, ioff
), REC_PQ_X
);
741 * Reconstruct two data columns using PQ parity
742 * @rec_method REC_PQ_BLOCK()
745 * @tgtidx array of missing data indexes
747 static raidz_inline
int
748 raidz_reconstruct_pq_impl(raidz_map_t
*rm
, const int *tgtidx
)
750 const int x
= tgtidx
[TARGET_X
];
751 const int y
= tgtidx
[TARGET_Y
];
752 const int ncols
= raidz_ncols(rm
);
753 const int nbigcols
= raidz_nbigcols(rm
);
754 const size_t xsize
= raidz_col_size(rm
, x
);
755 const size_t ysize
= raidz_col_size(rm
, y
);
756 const size_t short_size
= raidz_short_size(rm
);
757 unsigned coeff
[MUL_CNT
];
759 raidz_rec_pq_coeff(rm
, tgtidx
, coeff
);
764 REC_PQ_BLOCK(rm
, 0, short_size
, x
, y
, coeff
, ncols
, ncols
, B_TRUE
);
766 /* short_size - xsize */
767 REC_PQ_BLOCK(rm
, short_size
, xsize
, x
, y
, coeff
, ncols
, nbigcols
,
772 return ((1 << CODE_P
) | (1 << CODE_Q
));
776 * Reconstruct using PR parity
779 #define REC_PR_SYN_UPDATE() MUL4(REC_PR_Y)
780 #define REC_PR_INNER_LOOP(c) \
782 col = &rm->rm_col[c]; \
783 LOAD(COL_OFF(col, ioff), REC_PR_D); \
784 REC_PR_SYN_UPDATE(); \
785 XOR(REC_PR_D, REC_PR_X); \
786 XOR(REC_PR_D, REC_PR_Y); \
790 * Reconstruction using PR parity
792 * @off starting offset
794 * @x missing data column
795 * @y missing data column
796 * @coeff multiplication coefficients
797 * @ncols number of column
798 * @nbigcols number of big columns
799 * @calcy calculate second data column
801 static raidz_inline
void
802 REC_PR_BLOCK(raidz_map_t
* const rm
, const size_t off
, const size_t end
,
803 const int x
, const int y
, const unsigned *coeff
, const int ncols
,
804 const int nbigcols
, const boolean_t calcy
)
808 const size_t firstdc
= raidz_parity(rm
);
809 raidz_col_t
* const pcol
= raidz_col_p(rm
, CODE_P
);
810 raidz_col_t
* const rcol
= raidz_col_p(rm
, CODE_R
);
811 raidz_col_t
* const xcol
= raidz_col_p(rm
, x
);
812 raidz_col_t
* const ycol
= raidz_col_p(rm
, y
);
817 for (ioff
= off
; ioff
< end
; ioff
+= (REC_PR_STRIDE
* sizeof (v_t
))) {
818 LOAD(COL_OFF(pcol
, ioff
), REC_PR_X
);
819 XOR(REC_PR_Y
, REC_PR_Y
);
822 if (ncols
== nbigcols
) {
823 for (c
= firstdc
; c
< x
; c
++)
824 REC_PR_INNER_LOOP(c
);
827 for (c
++; c
< y
; c
++)
828 REC_PR_INNER_LOOP(c
);
831 for (c
++; c
< nbigcols
; c
++)
832 REC_PR_INNER_LOOP(c
);
834 for (c
= firstdc
; c
< nbigcols
; c
++) {
836 if (c
!= x
&& c
!= y
) {
837 col
= &rm
->rm_col
[c
];
838 LOAD(COL_OFF(col
, ioff
), REC_PR_D
);
839 XOR(REC_PR_D
, REC_PR_X
);
840 XOR(REC_PR_D
, REC_PR_Y
);
843 for (; c
< ncols
; c
++)
847 XOR_ACC(COL_OFF(rcol
, ioff
), REC_PR_Y
);
850 COPY(REC_PR_X
, REC_PR_D
);
853 MUL(coeff
[MUL_PR_X
], REC_PR_X
);
854 MUL(coeff
[MUL_PR_Y
], REC_PR_Y
);
855 XOR(REC_PR_Y
, REC_PR_X
);
856 STORE(COL_OFF(xcol
, ioff
), REC_PR_X
);
860 XOR(REC_PR_D
, REC_PR_X
);
861 STORE(COL_OFF(ycol
, ioff
), REC_PR_X
);
868 * Reconstruct two data columns using PR parity
869 * @rec_method REC_PR_BLOCK()
872 * @tgtidx array of missing data indexes
874 static raidz_inline
int
875 raidz_reconstruct_pr_impl(raidz_map_t
*rm
, const int *tgtidx
)
877 const int x
= tgtidx
[TARGET_X
];
878 const int y
= tgtidx
[TARGET_Y
];
879 const int ncols
= raidz_ncols(rm
);
880 const int nbigcols
= raidz_nbigcols(rm
);
881 const size_t xsize
= raidz_col_size(rm
, x
);
882 const size_t ysize
= raidz_col_size(rm
, y
);
883 const size_t short_size
= raidz_short_size(rm
);
884 unsigned coeff
[MUL_CNT
];
886 raidz_rec_pr_coeff(rm
, tgtidx
, coeff
);
891 REC_PR_BLOCK(rm
, 0, short_size
, x
, y
, coeff
, ncols
, ncols
, B_TRUE
);
893 /* short_size - xsize */
894 REC_PR_BLOCK(rm
, short_size
, xsize
, x
, y
, coeff
, ncols
, nbigcols
,
899 return ((1 << CODE_P
) | (1 << CODE_R
));
904 * Reconstruct using QR parity
907 #define REC_QR_SYN_UPDATE() \
913 #define REC_QR_INNER_LOOP(c) \
915 col = &rm->rm_col[c]; \
916 LOAD(COL_OFF(col, ioff), REC_QR_D); \
917 REC_QR_SYN_UPDATE(); \
918 XOR(REC_QR_D, REC_QR_X); \
919 XOR(REC_QR_D, REC_QR_Y); \
923 * Reconstruction using QR parity
925 * @off starting offset
927 * @x missing data column
928 * @y missing data column
929 * @coeff multiplication coefficients
930 * @ncols number of column
931 * @nbigcols number of big columns
932 * @calcy calculate second data column
934 static raidz_inline
void
935 REC_QR_BLOCK(raidz_map_t
* const rm
, const size_t off
, const size_t end
,
936 const int x
, const int y
, const unsigned *coeff
, const int ncols
,
937 const int nbigcols
, const boolean_t calcy
)
941 const size_t firstdc
= raidz_parity(rm
);
942 raidz_col_t
* const qcol
= raidz_col_p(rm
, CODE_Q
);
943 raidz_col_t
* const rcol
= raidz_col_p(rm
, CODE_R
);
944 raidz_col_t
* const xcol
= raidz_col_p(rm
, x
);
945 raidz_col_t
* const ycol
= raidz_col_p(rm
, y
);
950 for (ioff
= off
; ioff
< end
; ioff
+= (REC_QR_STRIDE
* sizeof (v_t
))) {
952 XOR(REC_QR_X
, REC_QR_X
);
953 XOR(REC_QR_Y
, REC_QR_Y
);
955 if (ncols
== nbigcols
) {
956 for (c
= firstdc
; c
< x
; c
++)
957 REC_QR_INNER_LOOP(c
);
960 for (c
++; c
< y
; c
++)
961 REC_QR_INNER_LOOP(c
);
964 for (c
++; c
< nbigcols
; c
++)
965 REC_QR_INNER_LOOP(c
);
967 for (c
= firstdc
; c
< nbigcols
; c
++) {
969 if (c
!= x
&& c
!= y
) {
970 col
= &rm
->rm_col
[c
];
971 LOAD(COL_OFF(col
, ioff
), REC_QR_D
);
972 XOR(REC_QR_D
, REC_QR_X
);
973 XOR(REC_QR_D
, REC_QR_Y
);
976 for (; c
< ncols
; c
++)
980 XOR_ACC(COL_OFF(qcol
, ioff
), REC_QR_X
);
981 XOR_ACC(COL_OFF(rcol
, ioff
), REC_QR_Y
);
984 COPY(REC_QR_X
, REC_QR_D
);
987 MUL(coeff
[MUL_QR_XQ
], REC_QR_X
); /* X = Q * xqm */
988 XOR(REC_QR_Y
, REC_QR_X
); /* X = R ^ X */
989 MUL(coeff
[MUL_QR_X
], REC_QR_X
); /* X = X * xm */
990 STORE(COL_OFF(xcol
, ioff
), REC_QR_X
);
994 MUL(coeff
[MUL_QR_YQ
], REC_QR_D
); /* X = Q * xqm */
995 XOR(REC_QR_Y
, REC_QR_D
); /* X = R ^ X */
996 MUL(coeff
[MUL_QR_Y
], REC_QR_D
); /* X = X * xm */
997 STORE(COL_OFF(ycol
, ioff
), REC_QR_D
);
1003 * Reconstruct two data columns using QR parity
1004 * @rec_method REC_QR_BLOCK()
1007 * @tgtidx array of missing data indexes
1009 static raidz_inline
int
1010 raidz_reconstruct_qr_impl(raidz_map_t
*rm
, const int *tgtidx
)
1012 const int x
= tgtidx
[TARGET_X
];
1013 const int y
= tgtidx
[TARGET_Y
];
1014 const int ncols
= raidz_ncols(rm
);
1015 const int nbigcols
= raidz_nbigcols(rm
);
1016 const size_t xsize
= raidz_col_size(rm
, x
);
1017 const size_t ysize
= raidz_col_size(rm
, y
);
1018 const size_t short_size
= raidz_short_size(rm
);
1019 unsigned coeff
[MUL_CNT
];
1021 raidz_rec_qr_coeff(rm
, tgtidx
, coeff
);
1025 /* 0 - short_size */
1026 REC_QR_BLOCK(rm
, 0, short_size
, x
, y
, coeff
, ncols
, ncols
, B_TRUE
);
1028 /* short_size - xsize */
1029 REC_QR_BLOCK(rm
, short_size
, xsize
, x
, y
, coeff
, ncols
, nbigcols
,
1034 return ((1 << CODE_Q
) | (1 << CODE_R
));
1038 * Reconstruct using PQR parity
1041 #define REC_PQR_SYN_UPDATE() \
1047 #define REC_PQR_INNER_LOOP(c) \
1049 col = &rm->rm_col[(c)]; \
1050 LOAD(COL_OFF(col, ioff), REC_PQR_D); \
1051 REC_PQR_SYN_UPDATE(); \
1052 XOR(REC_PQR_D, REC_PQR_X); \
1053 XOR(REC_PQR_D, REC_PQR_Y); \
1054 XOR(REC_PQR_D, REC_PQR_Z); \
1058 * Reconstruction using PQR parity
1060 * @off starting offset
1061 * @end ending offset
1062 * @x missing data column
1063 * @y missing data column
1064 * @z missing data column
1065 * @coeff multiplication coefficients
1066 * @ncols number of column
1067 * @nbigcols number of big columns
1068 * @calcy calculate second data column
1069 * @calcz calculate third data column
1071 static raidz_inline
void
1072 REC_PQR_BLOCK(raidz_map_t
* const rm
, const size_t off
, const size_t end
,
1073 const int x
, const int y
, const int z
, const unsigned *coeff
,
1074 const int ncols
, const int nbigcols
, const boolean_t calcy
,
1075 const boolean_t calcz
)
1079 const size_t firstdc
= raidz_parity(rm
);
1080 raidz_col_t
* const pcol
= raidz_col_p(rm
, CODE_P
);
1081 raidz_col_t
* const qcol
= raidz_col_p(rm
, CODE_Q
);
1082 raidz_col_t
* const rcol
= raidz_col_p(rm
, CODE_R
);
1083 raidz_col_t
* const xcol
= raidz_col_p(rm
, x
);
1084 raidz_col_t
* const ycol
= raidz_col_p(rm
, y
);
1085 raidz_col_t
* const zcol
= raidz_col_p(rm
, z
);
1090 for (ioff
= off
; ioff
< end
; ioff
+= (REC_PQR_STRIDE
* sizeof (v_t
))) {
1092 LOAD(COL_OFF(pcol
, ioff
), REC_PQR_X
);
1093 XOR(REC_PQR_Y
, REC_PQR_Y
);
1094 XOR(REC_PQR_Z
, REC_PQR_Z
);
1096 if (ncols
== nbigcols
) {
1097 for (c
= firstdc
; c
< x
; c
++)
1098 REC_PQR_INNER_LOOP(c
);
1100 REC_PQR_SYN_UPDATE();
1101 for (c
++; c
< y
; c
++)
1102 REC_PQR_INNER_LOOP(c
);
1104 REC_PQR_SYN_UPDATE();
1105 for (c
++; c
< z
; c
++)
1106 REC_PQR_INNER_LOOP(c
);
1108 REC_PQR_SYN_UPDATE();
1109 for (c
++; c
< nbigcols
; c
++)
1110 REC_PQR_INNER_LOOP(c
);
1112 for (c
= firstdc
; c
< nbigcols
; c
++) {
1113 REC_PQR_SYN_UPDATE();
1114 if (c
!= x
&& c
!= y
&& c
!= z
) {
1115 col
= &rm
->rm_col
[c
];
1116 LOAD(COL_OFF(col
, ioff
), REC_PQR_D
);
1117 XOR(REC_PQR_D
, REC_PQR_X
);
1118 XOR(REC_PQR_D
, REC_PQR_Y
);
1119 XOR(REC_PQR_D
, REC_PQR_Z
);
1122 for (; c
< ncols
; c
++)
1123 REC_PQR_SYN_UPDATE();
1126 XOR_ACC(COL_OFF(qcol
, ioff
), REC_PQR_Y
);
1127 XOR_ACC(COL_OFF(rcol
, ioff
), REC_PQR_Z
);
1129 /* Save Pxyz and Qxyz */
1130 COPY(REC_PQR_X
, REC_PQR_XS
);
1131 COPY(REC_PQR_Y
, REC_PQR_YS
);
1134 MUL(coeff
[MUL_PQR_XP
], REC_PQR_X
); /* Xp = Pxyz * xp */
1135 MUL(coeff
[MUL_PQR_XQ
], REC_PQR_Y
); /* Xq = Qxyz * xq */
1136 XOR(REC_PQR_Y
, REC_PQR_X
);
1137 MUL(coeff
[MUL_PQR_XR
], REC_PQR_Z
); /* Xr = Rxyz * xr */
1138 XOR(REC_PQR_Z
, REC_PQR_X
); /* X = Xp + Xq + Xr */
1139 STORE(COL_OFF(xcol
, ioff
), REC_PQR_X
);
1143 XOR(REC_PQR_X
, REC_PQR_XS
); /* Pyz = Pxyz + X */
1144 MUL(coeff
[MUL_PQR_YU
], REC_PQR_X
); /* Xq = X * upd_q */
1145 XOR(REC_PQR_X
, REC_PQR_YS
); /* Qyz = Qxyz + Xq */
1146 COPY(REC_PQR_XS
, REC_PQR_X
); /* restore Pyz */
1147 MUL(coeff
[MUL_PQR_YP
], REC_PQR_X
); /* Yp = Pyz * yp */
1148 MUL(coeff
[MUL_PQR_YQ
], REC_PQR_YS
); /* Yq = Qyz * yq */
1149 XOR(REC_PQR_X
, REC_PQR_YS
); /* Y = Yp + Yq */
1150 STORE(COL_OFF(ycol
, ioff
), REC_PQR_YS
);
1155 XOR(REC_PQR_XS
, REC_PQR_YS
); /* Z = Pz = Pyz + Y */
1156 STORE(COL_OFF(zcol
, ioff
), REC_PQR_YS
);
1162 * Reconstruct three data columns using PQR parity
1163 * @rec_method REC_PQR_BLOCK()
1166 * @tgtidx array of missing data indexes
1168 static raidz_inline
int
1169 raidz_reconstruct_pqr_impl(raidz_map_t
*rm
, const int *tgtidx
)
1171 const int x
= tgtidx
[TARGET_X
];
1172 const int y
= tgtidx
[TARGET_Y
];
1173 const int z
= tgtidx
[TARGET_Z
];
1174 const int ncols
= raidz_ncols(rm
);
1175 const int nbigcols
= raidz_nbigcols(rm
);
1176 const size_t xsize
= raidz_col_size(rm
, x
);
1177 const size_t ysize
= raidz_col_size(rm
, y
);
1178 const size_t zsize
= raidz_col_size(rm
, z
);
1179 const size_t short_size
= raidz_short_size(rm
);
1180 unsigned coeff
[MUL_CNT
];
1182 raidz_rec_pqr_coeff(rm
, tgtidx
, coeff
);
1186 /* 0 - short_size */
1187 REC_PQR_BLOCK(rm
, 0, short_size
, x
, y
, z
, coeff
, ncols
, ncols
,
1190 /* short_size - xsize */
1191 REC_PQR_BLOCK(rm
, short_size
, xsize
, x
, y
, z
, coeff
, ncols
, nbigcols
,
1192 xsize
== ysize
, xsize
== zsize
);
1196 return ((1 << CODE_P
) | (1 << CODE_Q
) | (1 << CODE_R
));
1199 #endif /* _VDEV_RAIDZ_MATH_IMPL_H */