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"
74 SLIST_HEAD_INITIALIZER(active_instances);
75 rwlock_t active_instances_rwlock = RWLOCK_INITIALIZER;
78 int next_backend_desc = 0;
86 ec_backend_t liberasurecode_backend_instance_get_by_desc(
int desc)
88 struct ec_backend *b = NULL;
89 SLIST_FOREACH(b, &active_instances, link) {
105 if (++next_backend_desc <= 0)
106 next_backend_desc = 1;
107 if (!liberasurecode_backend_instance_get_by_desc(next_backend_desc))
108 return next_backend_desc;
124 rc = rwlock_wrlock(&active_instances_rwlock);
126 SLIST_INSERT_HEAD(&active_instances, instance, link);
130 instance->idesc = desc;
136 rwlock_unlock(&active_instances_rwlock);
150 rc = rwlock_wrlock(&active_instances_rwlock);
152 SLIST_REMOVE(&active_instances, instance, ec_backend, link);
156 rwlock_unlock(&active_instances_rwlock);
166 char *msg = dlerror();
168 log_error(
"%s: unknown dynamic linking error\n", caller);
170 log_error(
"%s: dynamic linking error %s\n", caller, msg);
176 if (NULL == instance)
179 return dlopen(instance->common.soname, RTLD_LAZY | RTLD_LOCAL);
184 if (NULL == instance || NULL == instance->desc.backend_sohandle)
187 dlclose(instance->desc.backend_sohandle);
190 instance->desc.backend_sohandle = NULL;
197 liberasurecode_init(
void) {
199 openlog(
"liberasurecode", LOG_PID | LOG_CONS, LOG_USER);
213 liberasurecode_exit(
void) {
230 struct ec_backend backend;
231 if (backend_id >= EC_BACKENDS_MAX)
236 if (!backend.desc.backend_sohandle) {
264 struct ec_args *args)
266 ec_backend_t instance = NULL;
267 struct ec_backend_args bargs;
269 return -EINVALIDPARAMS;
271 if (
id >= EC_BACKENDS_MAX)
272 return -EBACKENDNOTSUPP;
274 if ((args->k + args->m) > EC_MAX_FRAGMENTS) {
275 log_error(
"Total number of fragments (k + m) must be less than %d\n",
277 return -EINVALIDPARAMS;
281 instance = calloc(1,
sizeof(*instance));
282 if (NULL == instance)
287 memcpy(&(bargs.uargs), args, sizeof (
struct ec_args));
288 instance->args = bargs;
292 if (!instance->desc.backend_sohandle) {
294 if (!instance->desc.backend_sohandle) {
298 return -EBACKENDNOTAVAIL;
303 instance->desc.backend_desc = instance->common.ops->init(
304 &instance->args, instance->desc.backend_sohandle);
305 if (NULL == instance->desc.backend_desc) {
307 return -EBACKENDINITERR;
313 return instance->idesc;
323 ec_backend_t instance = NULL;
326 instance = liberasurecode_backend_instance_get_by_desc(desc);
327 if (NULL == instance)
328 return -EBACKENDNOTAVAIL;
331 instance->common.ops->exit(instance->desc.backend_desc);
362 char **encoded_parity)
366 ec_backend_t instance = liberasurecode_backend_instance_get_by_desc(desc);
367 if (NULL == instance) {
368 return -EBACKENDNOTAVAIL;
371 k = instance->args.uargs.k;
372 m = instance->args.uargs.m;
375 for (i = 0; i < k; i++) {
376 free(encoded_data[i]);
382 if (encoded_parity) {
383 for (i = 0; i < m; i++) {
384 free(encoded_parity[i]);
386 free(encoded_parity);
409 const char *orig_data, uint64_t orig_data_size,
410 char ***encoded_data,
char ***encoded_parity,
411 uint64_t *fragment_len)
418 if (orig_data == NULL) {
419 log_error(
"Pointer to data buffer is null!");
420 ret = -EINVALIDPARAMS;
424 if (encoded_data == NULL) {
425 log_error(
"Pointer to encoded data buffers is null!");
426 return -EINVALIDPARAMS;
429 if (encoded_parity == NULL) {
430 log_error(
"Pointer to encoded parity buffers is null!");
431 return -EINVALIDPARAMS;
434 if (fragment_len == NULL) {
435 log_error(
"Pointer to fragment length is null!");
436 ret = -EINVALIDPARAMS;
440 ec_backend_t instance = liberasurecode_backend_instance_get_by_desc(desc);
441 if (NULL == instance) {
442 ret = -EBACKENDNOTAVAIL;
446 k = instance->args.uargs.k;
447 m = instance->args.uargs.m;
453 if (NULL == *encoded_data) {
454 log_error(
"Could not allocate data buffer!");
459 if (NULL == *encoded_parity) {
460 log_error(
"Could not allocate parity buffer!");
465 *encoded_data, *encoded_parity, &blocksize);
474 ret = instance->common.ops->encode(instance->desc.backend_desc,
475 *encoded_data, *encoded_parity, blocksize);
484 *encoded_data, *encoded_parity);
492 log_error(
"Error in liberasurecode_encode %d", ret);
512 ec_backend_t instance = liberasurecode_backend_instance_get_by_desc(desc);
513 if (NULL == instance) {
514 return -EBACKENDNOTAVAIL;
536 char **available_fragments,
537 int num_fragments, uint64_t fragment_len,
538 int force_metadata_checks,
539 char **out_data, uint64_t *out_data_len)
545 int orig_data_size = 0;
549 char **parity = NULL;
550 char **data_segments = NULL;
551 char **parity_segments = NULL;
552 int *missing_idxs = NULL;
554 uint64_t realloc_bm = 0;
556 ec_backend_t instance = liberasurecode_backend_instance_get_by_desc(desc);
557 if (NULL == instance) {
558 ret = -EBACKENDNOTAVAIL;
562 if (NULL == available_fragments) {
563 log_error(
"Pointer to encoded fragments buffer is null!");
564 ret = -EINVALIDPARAMS;
568 if (NULL == out_data) {
569 log_error(
"Pointer to decoded data buffer is null!");
570 ret = -EINVALIDPARAMS;
574 if (NULL == out_data_len) {
575 log_error(
"Pointer to decoded data length variable is null!");
576 ret = -EINVALIDPARAMS;
580 k = instance->args.uargs.k;
581 m = instance->args.uargs.m;
583 if (num_fragments < k) {
584 log_error(
"Not enough fragments to decode, got %d, need %d!",
590 for (i = 0; i < num_fragments; ++i) {
593 (fragment_header_t *) available_fragments[i])) {
594 log_error(
"Invalid fragment header information!");
600 if (instance->common.id != EC_BACKEND_SHSS) {
607 available_fragments, num_fragments,
608 out_data, out_data_len);
621 log_error(
"Could not allocate data buffer!");
626 if (NULL == parity) {
627 log_error(
"Could not allocate parity buffer!");
632 if (NULL == missing_idxs) {
633 log_error(
"Could not allocate missing_idxs buffer!");
638 if (force_metadata_checks) {
639 int num_invalid_fragments = 0;
640 for (i = 0; i < num_fragments; ++i) {
642 ++num_invalid_fragments;
645 if ((num_fragments - num_invalid_fragments) < k) {
647 log_error(
"Not enough valid fragments available for decode!");
657 data, parity, missing_idxs);
660 log_error(
"Could not properly partition the fragments!");
672 data, parity, missing_idxs,
673 &orig_data_size, &blocksize,
674 fragment_len, &realloc_bm);
676 log_error(
"Could not prepare fragments for decode!");
686 ret = instance->common.ops->decode(instance->desc.backend_desc,
687 data_segments, parity_segments,
688 missing_idxs, blocksize);
691 log_error(
"Encountered error in backend decode function!");
700 while (missing_idxs[j] >= 0) {
702 int missing_idx = missing_idxs[j];
703 if (missing_idx < k) {
705 char *fragment_ptr = data[missing_idx];
706 init_fragment_header(fragment_ptr);
708 orig_data_size, blocksize, instance->args.uargs.ct,
718 log_error(
"Could not convert decoded fragments to a string!");
723 if (realloc_bm != 0) {
724 for (i = 0; i < k; i++) {
725 if (realloc_bm & (1 << i)) {
730 for (i = 0; i < m; i++) {
731 if (realloc_bm & (1 << (i + k))) {
741 free(parity_segments);
759 char **available_fragments,
760 int num_fragments, uint64_t fragment_len,
766 int orig_data_size = 0;
768 char **parity = NULL;
769 int *missing_idxs = NULL;
770 char *fragment_ptr = NULL;
771 int is_destination_missing = 0;
775 uint64_t realloc_bm = 0;
776 char **data_segments = NULL;
777 char **parity_segments = NULL;
780 ec_backend_t instance = liberasurecode_backend_instance_get_by_desc(desc);
781 if (NULL == instance) {
782 ret = -EBACKENDNOTAVAIL;
786 if (NULL == available_fragments) {
787 log_error(
"Can not reconstruct fragment, available fragments pointer is NULL");
788 ret = -EINVALIDPARAMS;
792 if (NULL == out_fragment) {
793 log_error(
"Can not reconstruct fragment, output fragment pointer is NULL");
794 ret = -EINVALIDPARAMS;
798 k = instance->args.uargs.k;
799 m = instance->args.uargs.m;
801 for (i = 0; i < num_fragments; i++) {
804 (fragment_header_t *) available_fragments[i])) {
805 log_error(
"Invalid fragment header information!");
816 log_error(
"Could not allocate data buffer!");
822 if (NULL == parity) {
823 log_error(
"Could not allocate parity buffer!");
829 if (NULL == missing_idxs) {
830 log_error(
"Could not allocate missing_idxs buffer!");
840 data, parity, missing_idxs);
843 log_error(
"Could not properly partition the fragments!");
857 while (missing_idxs[i] > -1) {
858 if (missing_idxs[i] == destination_idx) {
859 is_destination_missing = 1;
864 if (!is_destination_missing) {
865 if (destination_idx < k) {
866 fragment_ptr = data[destination_idx];
868 fragment_ptr = parity[destination_idx - k];
870 log_warn(
"Dest idx for reconstruction was supplied as available buffer!");
871 goto destination_available;
881 &orig_data_size, &blocksize,
882 fragment_len, &realloc_bm);
884 log_error(
"Could not prepare fragments for reconstruction!");
894 ret = instance->common.ops->reconstruct(instance->desc.backend_desc,
895 data_segments, parity_segments,
896 missing_idxs, destination_idx,
899 log_error(
"Could not reconstruct fragment!");
906 if (destination_idx < k) {
907 fragment_ptr = data[destination_idx];
909 fragment_ptr = parity[destination_idx - k];
911 init_fragment_header(fragment_ptr);
913 orig_data_size, blocksize, instance->args.uargs.ct,
916 destination_available:
922 memcpy(out_fragment, fragment_ptr, fragment_len);
926 if (realloc_bm != 0) {
927 for (i = 0; i < k; i++) {
928 if (realloc_bm & (1 << i)) {
933 for (i = 0; i < m; i++) {
934 if (realloc_bm & (1 << (i + k))) {
944 free(parity_segments);
965 int *fragments_to_reconstruct,
966 int *fragments_to_exclude,
967 int *fragments_needed)
971 ec_backend_t instance = liberasurecode_backend_instance_get_by_desc(desc);
972 if (NULL == instance) {
973 ret = -EBACKENDNOTAVAIL;
976 if (NULL == fragments_to_reconstruct) {
977 log_error(
"Unable to determine list of fragments needed, pointer to list of indexes to reconstruct is NULL.");
978 ret = -EINVALIDPARAMS;
982 if (NULL == fragments_to_exclude) {
983 log_error(
"Unable to determine list of fragments needed, pointer to list of fragments to exclude is NULL.");
984 ret = -EINVALIDPARAMS;
988 if (NULL == fragments_needed) {
989 log_error(
"Unable to determine list of fragments needed, pointer to list of fragments to reconstruct is NULL.");
990 ret = -EINVALIDPARAMS;
997 ret = instance->common.ops->fragments_needed(
998 instance->desc.backend_desc,
999 fragments_to_reconstruct, fragments_to_exclude, fragments_needed);
1018 fragment_metadata_t *fragment_metadata)
1021 fragment_header_t *fragment_hdr = NULL;
1023 if (NULL == fragment) {
1024 log_error(
"Need valid fragment object to get metadata for");
1025 ret = -EINVALIDPARAMS;
1029 if (NULL == fragment_metadata) {
1030 log_error(
"Need valid fragment_metadata object for return value");
1031 ret = -EINVALIDPARAMS;
1037 (fragment_header_t *) fragment)) {
1038 log_error(
"Invalid fragment header information!");
1043 memcpy(fragment_metadata, fragment,
sizeof(
struct fragment_metadata));
1044 fragment_hdr = (fragment_header_t *) fragment;
1045 if (LIBERASURECODE_FRAG_HEADER_MAGIC != fragment_hdr->magic) {
1046 log_error(
"Invalid fragment, illegal magic value");
1047 ret = -EINVALIDPARAMS;
1051 switch(fragment_hdr->meta.chksum_type) {
1052 case CHKSUM_CRC32: {
1053 uint32_t computed_chksum = 0;
1054 uint32_t stored_chksum = fragment_hdr->meta.chksum[0];
1056 uint64_t fragment_size = fragment_hdr->meta.size;
1057 computed_chksum =
crc32(0, fragment_data, fragment_size);
1058 if (stored_chksum != computed_chksum) {
1059 fragment_metadata->chksum_mismatch = 1;
1061 fragment_metadata->chksum_mismatch = 0;
1078 uint32_t *stored_csum = NULL, csum = 0;
1079 assert (NULL != header);
1080 if (header->libec_version == 0)
1083 if (header->libec_version < _VERSION(1,2,0))
1087 if (NULL == stored_csum)
1089 csum =
crc32(0, &header->meta,
sizeof(fragment_metadata_t));
1090 return (*stored_csum != csum);
1094 fragment_metadata_t *md)
1096 int k = be->args.uargs.k;
1097 int m = be->args.uargs.m;
1098 if (md->idx > (k + m)) {
1101 if (md->backend_id != be->common.id) {
1104 if (!be->common.ops->is_compatible_with(md->backend_version)) {
1112 ec_backend_t be = liberasurecode_backend_instance_get_by_desc(desc);
1114 log_error(
"Unable to verify fragment metadata: invalid backend id %d.",
1116 return -EINVALIDPARAMS;
1119 fragment_metadata) != 0) {
1122 if (!be->common.ops->is_compatible_with(fragment_metadata->backend_version)) {
1125 if (fragment_metadata->chksum_mismatch == 1) {
1134 fragment_metadata_t fragment_metadata;
1135 ec_backend_t be = liberasurecode_backend_instance_get_by_desc(desc);
1137 log_error(
"Unable to verify fragment metadata: invalid backend id %d.",
1142 log_error(
"Unable to verify fragment validity: fragments missing.");
1146 ver > LIBERASURECODE_VERSION) {
1159 char **fragments,
int num_fragments)
1163 log_error(
"Unable to verify stripe metadata: fragments missing.");
1164 return -EINVALIDPARAMS;
1166 if (num_fragments <= 0) {
1167 log_error(
"Unable to verify stripe metadata: "
1168 "number of fragments must be greater than 0.");
1169 return -EINVALIDPARAMS;
1172 for (i = 0; i < num_fragments; i++) {
1173 fragment_metadata_t *fragment_metadata = (fragment_metadata_t*)fragments[i];
1197 int alignment_multiple;
1199 ec_backend_t instance = liberasurecode_backend_instance_get_by_desc(desc);
1200 if (NULL == instance) {
1201 ret = -EBACKENDNOTAVAIL;
1205 k = instance->args.uargs.k;
1207 word_size = instance->common.ops->element_size(
1208 instance->desc.backend_desc) / 8;
1210 alignment_multiple = k * word_size;
1212 ret = (int) ceill( (
double)
1213 data_len / alignment_multiple) * alignment_multiple;
1230 ec_backend_t instance = liberasurecode_backend_instance_get_by_desc(desc);
1232 if (NULL == instance)
1233 return -EBACKENDNOTAVAIL;
1235 int size = (aligned_data_len / instance->args.uargs.k) + instance->common.backend_metadata_size;
1247 return LIBERASURECODE_VERSION;
1254 int liberasurecode_backend_validate(ec_backend_t backend)
1263 ec_backend_t liberasurecode_backend_get(
const char *name)
1265 ec_backend_t b = liberasurecode_backend_lookup_by_name(name);
1272 void liberasurecode_backend_put(ec_backend_t backend)
1274 if (backend->users > 0)
1279 ec_backend_t liberasurecode_backend_instance_active(ec_backend_t instance)
1283 SLIST_FOREACH(b, &active_instances, link) {
1284 if (strcmp(b->name, name) == 0)
1291 ec_backend_t liberasurecode_backend_lookup_by_soname(
const char *soname)
1295 SLIST_FOREACH(b, &active_instances, link) {
1296 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.
struct ec_backend_common backend_isa_l_rs_cauchy
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
uint32_t liberasurecode_get_version()
This will return the liberasurecode version for the descriptor.
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.