Fix error handling on gf_ivnert_matrix in isa-l backend

Current isa-l has possibility to return corrupted decoded data or
corrupted reconstructed data on decode/reconstruct without error code.

That is from the specification of isa-l rs vandermond matrix discussed
at [1]. With many # of parities cases, we may hit the case above due to
failing to get the inverse matrix from the encode matrix.

The isa-l maintener gbtucker suggests a good way to detect the failing
inverse matrix, that we should handle the return value gf_invert_matrix.
If gf_invert_matrix returns not 0, we should stop to decode/reconstruct
and return failure return code to the caller immediately. Otherwise, the
caller regards the garbage data/fragment as correct one.

And this patch adds the specific test case we can hit the issue (it
happens not so general).

1: https://github.com/01org/isa-l/issues/10

Related-Change: I6eb150d9d0c3febf233570fa7729f9f72df2e9be
Change-Id: Icee788a0931fe692fe0de31fabc4ba450e338a87
This commit is contained in:
Kota Tsuyuzaki 2016-11-03 19:49:49 -07:00 committed by Clay Gerrard
parent b96cf4b2cc
commit 74eaa374c1
2 changed files with 108 additions and 2 deletions

View File

@ -261,7 +261,10 @@ static int isa_l_rs_vand_decode(void *desc, char **data, char **parity,
goto out;
}
isa_l_desc->gf_invert_matrix(decode_matrix, decode_inverse, k);
int im_ret = isa_l_desc->gf_invert_matrix(decode_matrix, decode_inverse, k);
if (im_ret < 0) {
goto out;
}
// Generate g_tbls from computed decode matrix (k x k) matrix
g_tbls = malloc(sizeof(unsigned char) * (k * m * 32));
@ -365,7 +368,10 @@ static int isa_l_rs_vand_reconstruct(void *desc, char **data, char **parity,
goto out;
}
isa_l_desc->gf_invert_matrix(decode_matrix, decode_inverse, k);
int im_ret = isa_l_desc->gf_invert_matrix(decode_matrix, decode_inverse, k);
if (im_ret < 0) {
goto out;
}
/**
* Get the row needed to reconstruct

View File

@ -1346,6 +1346,102 @@ static void test_decode_with_missing_multi_data_parity(
}
}
static void test_decode_reconstruct_specific_error_case(
const ec_backend_id_t be_id, struct ec_args *args)
{
struct ec_args specific_1010_args = {
.k = 10,
.m = 10,
};
int rc = 0;
int desc = -1;
int orig_data_size = 1024 * 1024;
char *orig_data = create_buffer(orig_data_size, 'x');
char **encoded_data = NULL, **encoded_parity = NULL;
uint64_t encoded_fragment_len = 0;
int num_avail_frags = -1;
char **avail_frags = NULL;
char *decoded_data = NULL;
char *out_frag = NULL;
uint64_t decoded_data_len = 0;
int *skips = create_skips_array(&specific_1010_args,-1);
assert(skips != NULL);
// available frags for a bad pattern: [0, 1, 2, 3, 4, 6, 7, 10, 12, 15]
skips[5] = skips[8] = skips[9] = skips[11] = skips[13] = skips[14] =
skips[16] = skips[17] = skips[18] = skips[19] = 1;
desc = liberasurecode_instance_create(
EC_BACKEND_ISA_L_RS_VAND, &specific_1010_args);
if (-EBACKENDNOTAVAIL == desc) {
fprintf (stderr, "Backend library not available!\n");
return;
}
assert(desc > 0);
rc = liberasurecode_encode(desc, orig_data, orig_data_size,
&encoded_data, &encoded_parity, &encoded_fragment_len);
assert(rc == 0);
num_avail_frags = create_frags_array(&avail_frags, encoded_data,
encoded_parity, &specific_1010_args,
skips);
assert(num_avail_frags > 0);
rc = liberasurecode_decode(desc, avail_frags, num_avail_frags,
encoded_fragment_len, 1,
&decoded_data, &decoded_data_len);
assert(rc == -1);
free(avail_frags);
// 5 is a hole in available frags
num_avail_frags = create_frags_array(&avail_frags, encoded_data,
encoded_parity, &specific_1010_args,
skips);
out_frag = malloc(sizeof(char) * encoded_fragment_len);
rc = liberasurecode_reconstruct_fragment(
desc, avail_frags, 10, encoded_fragment_len, 5, out_frag);
assert(rc == -1);
free(out_frag);
free(avail_frags);
// sanity; [0, 1, 2, 3, 4, 6, 7, 10, 12, 14] is ok
skips[15] = 1; skips[14] = 0;
num_avail_frags = create_frags_array(&avail_frags, encoded_data,
encoded_parity, &specific_1010_args,
skips);
assert(num_avail_frags > 0);
rc = liberasurecode_decode(desc, avail_frags, num_avail_frags,
encoded_fragment_len, 1,
&decoded_data, &decoded_data_len);
assert(rc == 0);
// 5 is a hole in available frags
out_frag = malloc(sizeof(char) * encoded_fragment_len);
rc = liberasurecode_reconstruct_fragment(
desc, avail_frags, 10, encoded_fragment_len, 5, out_frag);
assert(rc == 0);
free(out_frag);
// cleanup all
rc = liberasurecode_encode_cleanup(desc, encoded_data, encoded_parity);
assert(rc == 0);
rc = liberasurecode_decode_cleanup(desc, decoded_data);
assert(rc == 0);
if (desc) {
assert(0 == liberasurecode_instance_destroy(desc));
}
free(orig_data);
free(avail_frags);
free(skips);
}
static void test_simple_encode_decode(const ec_backend_id_t be_id,
struct ec_args *args)
{
@ -1875,6 +1971,10 @@ struct testcase testcases[] = {
test_verify_stripe_metadata_frag_idx_invalid,
EC_BACKEND_ISA_L_RS_VAND, CHKSUM_CRC32,
.skip = false},
{"test_isa_l_decode_reconstruct_specific_error_case",
test_decode_reconstruct_specific_error_case,
EC_BACKENDS_MAX, 0, // note this test is using ISA-L in hard coded
.skip = false},
// shss tests
{"create_and_destroy_backend",
test_create_and_destroy_backend,