31 #include "erasurecode.h"
32 #include "erasurecode_backend.h"
33 #include "erasurecode_helpers.h"
34 #include "erasurecode_helpers_ext.h"
35 #include "erasurecode_preprocessing.h"
36 #include "erasurecode_postprocessing.h"
37 #include "erasurecode_stdinc.h"
40 #include "erasurecode_log.h"
72 SLIST_HEAD_INITIALIZER(active_instances);
73 rwlock_t active_instances_rwlock = RWLOCK_INITIALIZER;
76 int next_backend_desc = 0;
84 ec_backend_t liberasurecode_backend_instance_get_by_desc(
int desc)
86 struct ec_backend *b = NULL;
87 SLIST_FOREACH(b, &active_instances, link) {
103 if (++next_backend_desc <= 0)
104 next_backend_desc = 1;
105 if (!liberasurecode_backend_instance_get_by_desc(next_backend_desc))
106 return next_backend_desc;
122 rc = rwlock_wrlock(&active_instances_rwlock);
124 SLIST_INSERT_HEAD(&active_instances, instance, link);
128 instance->idesc = desc;
134 rwlock_unlock(&active_instances_rwlock);
148 rc = rwlock_wrlock(&active_instances_rwlock);
150 SLIST_REMOVE(&active_instances, instance, ec_backend, link);
154 rwlock_unlock(&active_instances_rwlock);
164 char *msg = dlerror();
166 log_error(
"%s: unknown dynamic linking error\n", caller);
168 log_error(
"%s: dynamic linking error %s\n", caller, msg);
174 if (NULL == instance)
177 return dlopen(instance->common.soname, RTLD_LAZY | RTLD_LOCAL);
182 if (NULL == instance || NULL == instance->desc.backend_sohandle)
185 dlclose(instance->desc.backend_sohandle);
188 instance->desc.backend_sohandle = NULL;
195 liberasurecode_init(
void) {
197 openlog(
"liberasurecode", LOG_PID | LOG_CONS, LOG_USER);
203 ec_backends_supported_str[i] = strdup(
206 num_supported_backends = i;
211 liberasurecode_exit(
void) {
214 free(ec_backends_supported_str[i]);
228 struct ec_backend backend;
229 if (backend_id >= EC_BACKENDS_MAX)
234 if (!backend.desc.backend_sohandle) {
262 struct ec_args *args)
264 ec_backend_t instance = NULL;
265 struct ec_backend_args bargs;
267 return -EINVALIDPARAMS;
269 if (
id >= EC_BACKENDS_MAX)
270 return -EBACKENDNOTSUPP;
272 if ((args->k + args->m) > EC_MAX_FRAGMENTS) {
273 log_error(
"Total number of fragments (k + m) must be less than %d\n",
275 return -EINVALIDPARAMS;
279 instance = calloc(1,
sizeof(*instance));
280 if (NULL == instance)
285 memcpy(&(bargs.uargs), args, sizeof (
struct ec_args));
286 instance->args = bargs;
290 if (!instance->desc.backend_sohandle) {
292 if (!instance->desc.backend_sohandle) {
296 return -EBACKENDNOTAVAIL;
301 instance->desc.backend_desc = instance->common.ops->init(
302 &instance->args, instance->desc.backend_sohandle);
303 if (NULL == instance->desc.backend_desc) {
305 return -EBACKENDINITERR;
311 return instance->idesc;
321 ec_backend_t instance = NULL;
324 instance = liberasurecode_backend_instance_get_by_desc(desc);
325 if (NULL == instance)
326 return -EBACKENDNOTAVAIL;
329 instance->common.ops->exit(instance->desc.backend_desc);
360 char **encoded_parity)
364 ec_backend_t instance = liberasurecode_backend_instance_get_by_desc(desc);
365 if (NULL == instance) {
366 return -EBACKENDNOTAVAIL;
369 k = instance->args.uargs.k;
370 m = instance->args.uargs.m;
373 for (i = 0; i < k; i++) {
374 free(encoded_data[i]);
380 if (encoded_parity) {
381 for (i = 0; i < m; i++) {
382 free(encoded_parity[i]);
384 free(encoded_parity);
407 const char *orig_data, uint64_t orig_data_size,
408 char ***encoded_data,
char ***encoded_parity,
409 uint64_t *fragment_len)
416 if (orig_data == NULL) {
417 log_error(
"Pointer to data buffer is null!");
418 ret = -EINVALIDPARAMS;
422 if (encoded_data == NULL) {
423 log_error(
"Pointer to encoded data buffers is null!");
424 return -EINVALIDPARAMS;
427 if (encoded_parity == NULL) {
428 log_error(
"Pointer to encoded parity buffers is null!");
429 return -EINVALIDPARAMS;
432 if (fragment_len == NULL) {
433 log_error(
"Pointer to fragment length is null!");
434 ret = -EINVALIDPARAMS;
438 ec_backend_t instance = liberasurecode_backend_instance_get_by_desc(desc);
439 if (NULL == instance) {
440 ret = -EBACKENDNOTAVAIL;
444 k = instance->args.uargs.k;
445 m = instance->args.uargs.m;
451 if (NULL == *encoded_data) {
452 log_error(
"Could not allocate data buffer!");
457 if (NULL == *encoded_parity) {
458 log_error(
"Could not allocate parity buffer!");
463 *encoded_data, *encoded_parity, &blocksize);
472 ret = instance->common.ops->encode(instance->desc.backend_desc,
473 *encoded_data, *encoded_parity, blocksize);
482 *encoded_data, *encoded_parity);
490 log_error(
"Error in liberasurecode_encode %d", ret);
510 ec_backend_t instance = liberasurecode_backend_instance_get_by_desc(desc);
511 if (NULL == instance) {
512 return -EBACKENDNOTAVAIL;
534 char **available_fragments,
535 int num_fragments, uint64_t fragment_len,
536 int force_metadata_checks,
537 char **out_data, uint64_t *out_data_len)
543 int orig_data_size = 0;
547 char **parity = NULL;
548 char **data_segments = NULL;
549 char **parity_segments = NULL;
550 int *missing_idxs = NULL;
552 uint64_t realloc_bm = 0;
554 ec_backend_t instance = liberasurecode_backend_instance_get_by_desc(desc);
555 if (NULL == instance) {
556 ret = -EBACKENDNOTAVAIL;
560 if (NULL == available_fragments) {
561 log_error(
"Pointer to encoded fragments buffer is null!");
562 ret = -EINVALIDPARAMS;
566 if (NULL == out_data) {
567 log_error(
"Pointer to decoded data buffer is null!");
568 ret = -EINVALIDPARAMS;
572 if (NULL == out_data_len) {
573 log_error(
"Pointer to decoded data length variable is null!");
574 ret = -EINVALIDPARAMS;
578 k = instance->args.uargs.k;
579 m = instance->args.uargs.m;
581 if (num_fragments < k) {
582 log_error(
"Not enough fragments to decode, got %d, need %d!",
588 for (i = 0; i < num_fragments; ++i) {
591 (fragment_header_t *) available_fragments[i])) {
592 log_error(
"Invalid fragment header information!");
598 if (instance->common.id != EC_BACKEND_SHSS) {
605 available_fragments, num_fragments,
606 out_data, out_data_len);
619 log_error(
"Could not allocate data buffer!");
624 if (NULL == parity) {
625 log_error(
"Could not allocate parity buffer!");
630 if (NULL == missing_idxs) {
631 log_error(
"Could not allocate missing_idxs buffer!");
636 if (force_metadata_checks) {
637 int num_invalid_fragments = 0;
638 for (i = 0; i < num_fragments; ++i) {
640 ++num_invalid_fragments;
643 if ((num_fragments - num_invalid_fragments) < k) {
645 log_error(
"Not enough valid fragments available for decode!");
655 data, parity, missing_idxs);
658 log_error(
"Could not properly partition the fragments!");
670 data, parity, missing_idxs,
671 &orig_data_size, &blocksize,
672 fragment_len, &realloc_bm);
674 log_error(
"Could not prepare fragments for decode!");
684 ret = instance->common.ops->decode(instance->desc.backend_desc,
685 data_segments, parity_segments,
686 missing_idxs, blocksize);
689 log_error(
"Encountered error in backend decode function!");
698 while (missing_idxs[j] >= 0) {
700 int missing_idx = missing_idxs[j];
701 if (missing_idx < k) {
703 char *fragment_ptr = data[missing_idx];
704 init_fragment_header(fragment_ptr);
706 orig_data_size, blocksize, instance->args.uargs.ct,
716 log_error(
"Could not convert decoded fragments to a string!");
721 if (realloc_bm != 0) {
722 for (i = 0; i < k; i++) {
723 if (realloc_bm & (1 << i)) {
728 for (i = 0; i < m; i++) {
729 if (realloc_bm & (1 << (i + k))) {
739 free(parity_segments);
757 char **available_fragments,
758 int num_fragments, uint64_t fragment_len,
764 int orig_data_size = 0;
766 char **parity = NULL;
767 int *missing_idxs = NULL;
768 char *fragment_ptr = NULL;
769 int is_destination_missing = 0;
773 uint64_t realloc_bm = 0;
774 char **data_segments = NULL;
775 char **parity_segments = NULL;
778 ec_backend_t instance = liberasurecode_backend_instance_get_by_desc(desc);
779 if (NULL == instance) {
780 ret = -EBACKENDNOTAVAIL;
784 if (NULL == available_fragments) {
785 log_error(
"Can not reconstruct fragment, available fragments pointer is NULL");
786 ret = -EINVALIDPARAMS;
790 if (NULL == out_fragment) {
791 log_error(
"Can not reconstruct fragment, output fragment pointer is NULL");
792 ret = -EINVALIDPARAMS;
796 k = instance->args.uargs.k;
797 m = instance->args.uargs.m;
799 for (i = 0; i < num_fragments; i++) {
802 (fragment_header_t *) available_fragments[i])) {
803 log_error(
"Invalid fragment header information!");
814 log_error(
"Could not allocate data buffer!");
819 if (NULL == parity) {
820 log_error(
"Could not allocate parity buffer!");
825 if (NULL == missing_idxs) {
826 log_error(
"Could not allocate missing_idxs buffer!");
835 data, parity, missing_idxs);
838 log_error(
"Could not properly partition the fragments!");
852 while (missing_idxs[i] > -1) {
853 if (missing_idxs[i] == destination_idx) {
854 is_destination_missing = 1;
859 if (!is_destination_missing) {
860 if (destination_idx < k) {
861 fragment_ptr = data[destination_idx];
863 fragment_ptr = parity[destination_idx - k];
865 log_warn(
"Dest idx for reconstruction was supplied as available buffer!");
866 goto destination_available;
876 &orig_data_size, &blocksize,
877 fragment_len, &realloc_bm);
879 log_error(
"Could not prepare fragments for reconstruction!");
889 ret = instance->common.ops->reconstruct(instance->desc.backend_desc,
890 data_segments, parity_segments,
891 missing_idxs, destination_idx,
894 log_error(
"Could not reconstruct fragment!");
901 if (destination_idx < k) {
902 fragment_ptr = data[destination_idx];
904 fragment_ptr = parity[destination_idx - k];
906 init_fragment_header(fragment_ptr);
908 orig_data_size, blocksize, instance->args.uargs.ct,
911 destination_available:
917 memcpy(out_fragment, fragment_ptr, fragment_len);
921 if (realloc_bm != 0) {
922 for (i = 0; i < k; i++) {
923 if (realloc_bm & (1 << i)) {
928 for (i = 0; i < m; i++) {
929 if (realloc_bm & (1 << (i + k))) {
939 free(parity_segments);
960 int *fragments_to_reconstruct,
961 int *fragments_to_exclude,
962 int *fragments_needed)
966 ec_backend_t instance = liberasurecode_backend_instance_get_by_desc(desc);
967 if (NULL == instance) {
968 ret = -EBACKENDNOTAVAIL;
971 if (NULL == fragments_to_reconstruct) {
972 log_error(
"Unable to determine list of fragments needed, pointer to list of indexes to reconstruct is NULL.");
973 ret = -EINVALIDPARAMS;
977 if (NULL == fragments_to_exclude) {
978 log_error(
"Unable to determine list of fragments needed, pointer to list of fragments to exclude is NULL.");
979 ret = -EINVALIDPARAMS;
983 if (NULL == fragments_needed) {
984 log_error(
"Unable to determine list of fragments needed, pointer to list of fragments to reconstruct is NULL.");
985 ret = -EINVALIDPARAMS;
992 ret = instance->common.ops->fragments_needed(
993 instance->desc.backend_desc,
994 fragments_to_reconstruct, fragments_to_exclude, fragments_needed);
1013 fragment_metadata_t *fragment_metadata)
1016 fragment_header_t *fragment_hdr = NULL;
1018 if (NULL == fragment) {
1019 log_error(
"Need valid fragment object to get metadata for");
1020 ret = -EINVALIDPARAMS;
1024 if (NULL == fragment_metadata) {
1025 log_error(
"Need valid fragment_metadata object for return value");
1026 ret = -EINVALIDPARAMS;
1032 (fragment_header_t *) fragment)) {
1033 log_error(
"Invalid fragment header information!");
1038 memcpy(fragment_metadata, fragment,
sizeof(
struct fragment_metadata));
1039 fragment_hdr = (fragment_header_t *) fragment;
1040 if (LIBERASURECODE_FRAG_HEADER_MAGIC != fragment_hdr->magic) {
1041 log_error(
"Invalid fragment, illegal magic value");
1042 ret = -EINVALIDPARAMS;
1046 switch(fragment_hdr->meta.chksum_type) {
1047 case CHKSUM_CRC32: {
1048 uint32_t computed_chksum = 0;
1049 uint32_t stored_chksum = fragment_hdr->meta.chksum[0];
1051 uint64_t fragment_size = fragment_hdr->meta.size;
1052 computed_chksum =
crc32(0, fragment_data, fragment_size);
1053 if (stored_chksum != computed_chksum) {
1054 fragment_metadata->chksum_mismatch = 1;
1056 fragment_metadata->chksum_mismatch = 0;
1073 uint32_t *stored_csum = NULL, csum = 0;
1074 assert (NULL != header);
1075 if (header->libec_version < _VERSION(1,2,0))
1079 if (NULL == stored_csum)
1081 csum =
crc32(0, &header->meta,
sizeof(fragment_metadata_t));
1082 return (*stored_csum != csum);
1086 fragment_metadata_t *md)
1088 int k = be->args.uargs.k;
1089 int m = be->args.uargs.m;
1090 if (md->idx < 0 || (md->idx > (k + m))) {
1093 if (md->backend_id != be->common.id) {
1096 if (!be->common.ops->is_compatible_with(md->backend_version)) {
1104 ec_backend_t be = liberasurecode_backend_instance_get_by_desc(desc);
1106 log_error(
"Unable to verify fragment metadata: invalid backend id %d.",
1108 return -EINVALIDPARAMS;
1111 fragment_metadata) != 0) {
1114 if (!be->common.ops->is_compatible_with(fragment_metadata->backend_version)) {
1117 if (fragment_metadata->chksum_mismatch == 1) {
1126 fragment_metadata_t fragment_metadata;
1127 ec_backend_t be = liberasurecode_backend_instance_get_by_desc(desc);
1129 log_error(
"Unable to verify fragment metadata: invalid backend id %d.",
1134 log_error(
"Unable to verify fragment validity: fragments missing.");
1138 ver > LIBERASURECODE_VERSION) {
1151 char **fragments,
int num_fragments)
1155 log_error(
"Unable to verify stripe metadata: fragments missing.");
1156 return -EINVALIDPARAMS;
1158 if (num_fragments <= 0) {
1159 log_error(
"Unable to verify stripe metadata: "
1160 "number of fragments must be greater than 0.");
1161 return -EINVALIDPARAMS;
1164 for (i = 0; i < num_fragments; i++) {
1165 fragment_metadata_t *fragment_metadata = (fragment_metadata_t*)fragments[i];
1189 int alignment_multiple;
1191 ec_backend_t instance = liberasurecode_backend_instance_get_by_desc(desc);
1192 if (NULL == instance) {
1193 ret = -EBACKENDNOTAVAIL;
1197 k = instance->args.uargs.k;
1199 word_size = instance->common.ops->element_size(
1200 instance->desc.backend_desc) / 8;
1202 alignment_multiple = k * word_size;
1204 ret = (int) ceill( (
double)
1205 data_len / alignment_multiple) * alignment_multiple;
1222 ec_backend_t instance = liberasurecode_backend_instance_get_by_desc(desc);
1225 int size = (aligned_data_len / instance->args.uargs.k) + instance->common.backend_metadata_size;
1234 int liberasurecode_backend_validate(ec_backend_t backend)
1243 ec_backend_t liberasurecode_backend_get(
const char *name)
1245 ec_backend_t b = liberasurecode_backend_lookup_by_name(name);
1252 void liberasurecode_backend_put(ec_backend_t backend)
1254 if (backend->users > 0)
1259 ec_backend_t liberasurecode_backend_instance_active(ec_backend_t instance)
1263 SLIST_FOREACH(b, &active_instances, link) {
1264 if (strcmp(b->name, name) == 0)
1271 ec_backend_t liberasurecode_backend_lookup_by_soname(
const char *soname)
1275 SLIST_FOREACH(b, &active_instances, link) {
1276 if (strcmp(b->soname, soname) == 0)
void * alloc_and_set_buffer(int size, int value)
Allocate a buffer of a specific size and set its' contents to the specified value.
int get_fragment_ptr_array_from_data(char **frag_array, char **data, int num_data)
SLIST_HEAD(backend_list, ec_backend)
Look up a backend instance by descriptor.
int get_fragment_partition(int k, int m, char **fragments, int num_fragments, char **data, char **parity, int *missing)
int get_data_ptr_array_from_fragments(char **data_array, char **fragments, int num_fragments)
int liberasurecode_reconstruct_fragment(int desc, char **available_fragments, int num_fragments, uint64_t fragment_len, int destination_idx, char *out_fragment)
Reconstruct a missing fragment from a subset of available fragments.
struct ec_backend_common backend_jerasure_rs_vand
int liberasurecode_get_minimum_encode_size(int desc)
This will return the minumum encode size, which is the minimum buffer size that can be encoded...
void * liberasurecode_backend_open(ec_backend_t instance)
uint32_t * get_metadata_chksum(char *buf)
int liberasurecode_verify_fragment_metadata(ec_backend_t be, fragment_metadata_t *md)
int liberasurecode_get_aligned_data_size(int desc, uint64_t data_len)
This computes the aligned size of a buffer passed into the encode function.
int get_aligned_data_size(ec_backend_t instance, int data_len)
Compute a size aligned to the number of data and the underlying wordsize of the EC algorithm...
int liberasurecode_backend_close(ec_backend_t instance)
int liberasurecode_backend_available(const ec_backend_id_t backend_id)
Checks if a given backend is available.
char * get_data_ptr_from_fragment(char *buf)
int liberasurecode_verify_stripe_metadata(int desc, char **fragments, int num_fragments)
void * alloc_zeroed_buffer(int size)
Allocate a zero-ed buffer of a specific size.
int prepare_fragments_for_decode(int k, int m, char **data, char **parity, int *missing_idxs, int *orig_size, int *fragment_payload_size, int fragment_size, uint64_t *realloc_bm)
struct ec_backend_common backend_isa_l_rs_vand
int liberasurecode_instance_destroy(int desc)
Close a liberasurecode instance.
struct ec_backend_common backend_null
int liberasurecode_get_fragment_metadata(char *fragment, fragment_metadata_t *fragment_metadata)
Get opaque metadata for a fragment.
int is_invalid_fragment(int desc, char *fragment)
int finalize_fragments_after_encode(ec_backend_t instance, int k, int m, int blocksize, uint64_t orig_data_size, char **encoded_data, char **encoded_parity)
void add_fragment_metadata(ec_backend_t be, char *fragment, int idx, uint64_t orig_data_size, int blocksize, ec_checksum_type_t ct, int add_chksum)
int liberasurecode_encode_cleanup(int desc, char **encoded_data, char **encoded_parity)
Cleanup structures allocated by librasurecode_encode.
struct ec_backend_common backend_jerasure_rs_cauchy
int is_invalid_fragment_header(fragment_header_t *header)
int liberasurecode_backend_alloc_desc(void)
Allocated backend instance descriptor.
struct ec_backend_common backend_flat_xor_hd
uint64_t get_fragment_size(char *buf)
Return total fragment length (on-disk, on-wire)
struct ec_backend_common backend_liberasurecode_rs_vand
char * ec_backends_supported_str[EC_BACKENDS_MAX]
struct ec_backend_common backend_shss
int crc32(int crc, const void *buf, size_t size)
int liberasurecode_backend_instance_unregister(ec_backend_t instance)
Unregister a backend instance.
int liberasurecode_fragments_needed(int desc, int *fragments_to_reconstruct, int *fragments_to_exclude, int *fragments_needed)
Return a list of lists with valid rebuild indexes given a list of missing indexes.
int liberasurecode_get_fragment_size(int desc, int data_len)
ec_backend_t ec_backends_supported[]
static void print_dlerror(const char *caller)
int num_supported_backends
int liberasurecode_instance_create(const ec_backend_id_t id, struct ec_args *args)
Create a liberasurecode instance and return a descriptor for use with EC operations (encode...
int fragments_to_string(int k, int m, char **fragments, int num_fragments, char **orig_payload, uint64_t *payload_len)
void __attribute__((constructor))
int get_libec_version(char *buf, uint32_t *ver)
int is_invalid_fragment_metadata(int desc, fragment_metadata_t *fragment_metadata)
int prepare_fragments_for_encode(ec_backend_t instance, int k, int m, const char *orig_data, uint64_t orig_data_size, char **encoded_data, char **encoded_parity, int *blocksize)
int liberasurecode_decode(int desc, char **available_fragments, int num_fragments, uint64_t fragment_len, int force_metadata_checks, char **out_data, uint64_t *out_data_len)
Reconstruct original data from a set of k encoded fragments.
int liberasurecode_backend_instance_register(ec_backend_t instance)
Register a backend instance with liberasurecode.
int liberasurecode_encode(int desc, const char *orig_data, uint64_t orig_data_size, char ***encoded_data, char ***encoded_parity, uint64_t *fragment_len)
Erasure encode a data buffer.
int liberasurecode_decode_cleanup(int desc, char *data)
Cleanup structures allocated by librasurecode_decode.