Skip to content

Commit

Permalink
Merge branch 'core-rslib-for-linus' of git://git.kernel.org/pub/scm/l…
Browse files Browse the repository at this point in the history
…inux/kernel/git/tip/tip

Pull Reed-Solomon library updates from Thomas Gleixner:
 "A cleanup and fixes series from Ferdinand Blomqvist who analyzed the
  original Reed-Solomon library from Phil Karn on which the kernel
  implementation is based on.

  This comes with a test module which verifies all the various corner
  cases for correctness"

* 'core-rslib-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip:
  rslib: Make some functions static
  rslib: Fix remaining decoder flaws
  rslib: Update documentation
  rslib: Fix handling of of caller provided syndrome
  rslib: decode_rs: Code cleanup
  rslib: decode_rs: Fix length parameter check
  rslib: Fix decoding of shortened codes
  rslib: Add tests for the encoder and decoder
  • Loading branch information
torvalds committed Jul 8, 2019
2 parents 6b37754 + ede7c24 commit 568521d
Show file tree
Hide file tree
Showing 5 changed files with 624 additions and 35 deletions.
12 changes: 12 additions & 0 deletions lib/Kconfig.debug
Original file line number Diff line number Diff line change
Expand Up @@ -1754,6 +1754,18 @@ config RBTREE_TEST
A benchmark measuring the performance of the rbtree library.
Also includes rbtree invariant checks.

config REED_SOLOMON_TEST
tristate "Reed-Solomon library test"
depends on DEBUG_KERNEL || m
select REED_SOLOMON
select REED_SOLOMON_ENC16
select REED_SOLOMON_DEC16
help
This option enables the self-test function of rslib at boot,
or at module load time.

If unsure, say N.

config INTERVAL_TREE_TEST
tristate "Interval tree test"
depends on DEBUG_KERNEL
Expand Down
2 changes: 1 addition & 1 deletion lib/reed_solomon/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,4 @@
#

obj-$(CONFIG_REED_SOLOMON) += reed_solomon.o

obj-$(CONFIG_REED_SOLOMON_TEST) += test_rslib.o
115 changes: 85 additions & 30 deletions lib/reed_solomon/decode_rs.c
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
uint16_t *index_of = rs->index_of;
uint16_t u, q, tmp, num1, num2, den, discr_r, syn_error;
int count = 0;
int num_corrected;
uint16_t msk = (uint16_t) rs->nn;

/*
Expand All @@ -39,11 +40,21 @@

/* Check length parameter for validity */
pad = nn - nroots - len;
BUG_ON(pad < 0 || pad >= nn);
BUG_ON(pad < 0 || pad >= nn - nroots);

/* Does the caller provide the syndrome ? */
if (s != NULL)
goto decode;
if (s != NULL) {
for (i = 0; i < nroots; i++) {
/* The syndrome is in index form,
* so nn represents zero
*/
if (s[i] != nn)
goto decode;
}

/* syndrome is zero, no errors to correct */
return 0;
}

/* form the syndromes; i.e., evaluate data(x) at roots of
* g(x) */
Expand Down Expand Up @@ -88,8 +99,7 @@
/* if syndrome is zero, data[] is a codeword and there are no
* errors to correct. So return data[] unmodified
*/
count = 0;
goto finish;
return 0;
}

decode:
Expand All @@ -99,9 +109,9 @@
if (no_eras > 0) {
/* Init lambda to be the erasure locator polynomial */
lambda[1] = alpha_to[rs_modnn(rs,
prim * (nn - 1 - eras_pos[0]))];
prim * (nn - 1 - (eras_pos[0] + pad)))];
for (i = 1; i < no_eras; i++) {
u = rs_modnn(rs, prim * (nn - 1 - eras_pos[i]));
u = rs_modnn(rs, prim * (nn - 1 - (eras_pos[i] + pad)));
for (j = i + 1; j > 0; j--) {
tmp = index_of[lambda[j - 1]];
if (tmp != nn) {
Expand Down Expand Up @@ -175,6 +185,15 @@
if (lambda[i] != nn)
deg_lambda = i;
}

if (deg_lambda == 0) {
/*
* deg(lambda) is zero even though the syndrome is non-zero
* => uncorrectable error detected
*/
return -EBADMSG;
}

/* Find roots of error+erasure locator polynomial by Chien search */
memcpy(&reg[1], &lambda[1], nroots * sizeof(reg[0]));
count = 0; /* Number of roots of lambda(x) */
Expand All @@ -188,6 +207,12 @@
}
if (q != 0)
continue; /* Not a root */

if (k < pad) {
/* Impossible error location. Uncorrectable error. */
return -EBADMSG;
}

/* store root (index-form) and error location number */
root[count] = i;
loc[count] = k;
Expand All @@ -202,8 +227,7 @@
* deg(lambda) unequal to number of roots => uncorrectable
* error detected
*/
count = -EBADMSG;
goto finish;
return -EBADMSG;
}
/*
* Compute err+eras evaluator poly omega(x) = s(x)*lambda(x) (modulo
Expand All @@ -223,14 +247,23 @@
/*
* Compute error values in poly-form. num1 = omega(inv(X(l))), num2 =
* inv(X(l))**(fcr-1) and den = lambda_pr(inv(X(l))) all in poly-form
* Note: we reuse the buffer for b to store the correction pattern
*/
num_corrected = 0;
for (j = count - 1; j >= 0; j--) {
num1 = 0;
for (i = deg_omega; i >= 0; i--) {
if (omega[i] != nn)
num1 ^= alpha_to[rs_modnn(rs, omega[i] +
i * root[j])];
}

if (num1 == 0) {
/* Nothing to correct at this position */
b[j] = 0;
continue;
}

num2 = alpha_to[rs_modnn(rs, root[j] * (fcr - 1) + nn)];
den = 0;

Expand All @@ -242,30 +275,52 @@
i * root[j])];
}
}
/* Apply error to data */
if (num1 != 0 && loc[j] >= pad) {
uint16_t cor = alpha_to[rs_modnn(rs,index_of[num1] +
index_of[num2] +
nn - index_of[den])];
/* Store the error correction pattern, if a
* correction buffer is available */
if (corr) {
corr[j] = cor;
} else {
/* If a data buffer is given and the
* error is inside the message,
* correct it */
if (data && (loc[j] < (nn - nroots)))
data[loc[j] - pad] ^= cor;
}

b[j] = alpha_to[rs_modnn(rs, index_of[num1] +
index_of[num2] +
nn - index_of[den])];
num_corrected++;
}

/*
* We compute the syndrome of the 'error' and check that it matches
* the syndrome of the received word
*/
for (i = 0; i < nroots; i++) {
tmp = 0;
for (j = 0; j < count; j++) {
if (b[j] == 0)
continue;

k = (fcr + i) * prim * (nn-loc[j]-1);
tmp ^= alpha_to[rs_modnn(rs, index_of[b[j]] + k)];
}

if (tmp != alpha_to[s[i]])
return -EBADMSG;
}

finish:
if (eras_pos != NULL) {
for (i = 0; i < count; i++)
eras_pos[i] = loc[i] - pad;
/*
* Store the error correction pattern, if a
* correction buffer is available
*/
if (corr && eras_pos) {
j = 0;
for (i = 0; i < count; i++) {
if (b[i]) {
corr[j] = b[i];
eras_pos[j++] = loc[i] - pad;
}
}
} else if (data && par) {
/* Apply error to data and parity */
for (i = 0; i < count; i++) {
if (loc[i] < (nn - nroots))
data[loc[i] - pad] ^= b[i];
else
par[loc[i] - pad - len] ^= b[i];
}
}
return count;

return num_corrected;
}
12 changes: 8 additions & 4 deletions lib/reed_solomon/reed_solomon.c
Original file line number Diff line number Diff line change
Expand Up @@ -340,7 +340,8 @@ EXPORT_SYMBOL_GPL(encode_rs8);
* @data: data field of a given type
* @par: received parity data field
* @len: data length
* @s: syndrome data field (if NULL, syndrome is calculated)
* @s: syndrome data field, must be in index form
* (if NULL, syndrome is calculated)
* @no_eras: number of erasures
* @eras_pos: position of erasures, can be NULL
* @invmsk: invert data mask (will be xored on data, not on parity!)
Expand All @@ -354,7 +355,8 @@ EXPORT_SYMBOL_GPL(encode_rs8);
* decoding, so the caller has to ensure that decoder invocations are
* serialized.
*
* Returns the number of corrected bits or -EBADMSG for uncorrectable errors.
* Returns the number of corrected symbols or -EBADMSG for uncorrectable
* errors. The count includes errors in the parity.
*/
int decode_rs8(struct rs_control *rsc, uint8_t *data, uint16_t *par, int len,
uint16_t *s, int no_eras, int *eras_pos, uint16_t invmsk,
Expand Down Expand Up @@ -391,7 +393,8 @@ EXPORT_SYMBOL_GPL(encode_rs16);
* @data: data field of a given type
* @par: received parity data field
* @len: data length
* @s: syndrome data field (if NULL, syndrome is calculated)
* @s: syndrome data field, must be in index form
* (if NULL, syndrome is calculated)
* @no_eras: number of erasures
* @eras_pos: position of erasures, can be NULL
* @invmsk: invert data mask (will be xored on data, not on parity!)
Expand All @@ -403,7 +406,8 @@ EXPORT_SYMBOL_GPL(encode_rs16);
* decoding, so the caller has to ensure that decoder invocations are
* serialized.
*
* Returns the number of corrected bits or -EBADMSG for uncorrectable errors.
* Returns the number of corrected symbols or -EBADMSG for uncorrectable
* errors. The count includes errors in the parity.
*/
int decode_rs16(struct rs_control *rsc, uint16_t *data, uint16_t *par, int len,
uint16_t *s, int no_eras, int *eras_pos, uint16_t invmsk,
Expand Down
Loading

0 comments on commit 568521d

Please sign in to comment.