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" 76 SLIST_HEAD_INITIALIZER(active_instances);
77 rwlock_t active_instances_rwlock = RWLOCK_INITIALIZER;
80 int next_backend_desc = 0;
88 ec_backend_t liberasurecode_backend_instance_get_by_desc(
int desc)
90 struct ec_backend *b = NULL;
91 SLIST_FOREACH(b, &active_instances, link) {
107 if (++next_backend_desc <= 0)
108 next_backend_desc = 1;
109 if (!liberasurecode_backend_instance_get_by_desc(next_backend_desc))
110 return next_backend_desc;
126 rc = rwlock_wrlock(&active_instances_rwlock);
128 SLIST_INSERT_HEAD(&active_instances, instance, link);
132 instance->idesc = desc;
138 rwlock_unlock(&active_instances_rwlock);
152 rc = rwlock_wrlock(&active_instances_rwlock);
154 SLIST_REMOVE(&active_instances, instance, ec_backend, link);
158 rwlock_unlock(&active_instances_rwlock);
168 char *msg = dlerror();
170 log_error(
"%s: unknown dynamic linking error\n", caller);
172 log_error(
"%s: dynamic linking error %s\n", caller, msg);
178 if (NULL == instance)
181 return dlopen(instance->common.soname, RTLD_LAZY | RTLD_LOCAL);
186 if (NULL == instance || NULL == instance->desc.backend_sohandle)
189 dlclose(instance->desc.backend_sohandle);
192 instance->desc.backend_sohandle = NULL;
199 liberasurecode_init(
void) {
201 openlog(
"liberasurecode", LOG_PID | LOG_CONS, LOG_USER);
215 liberasurecode_exit(
void) {
232 struct ec_backend backend;
233 if (backend_id >= EC_BACKENDS_MAX)
238 if (!backend.desc.backend_sohandle) {
266 struct ec_args *args)
268 ec_backend_t instance = NULL;
269 struct ec_backend_args bargs;
271 return -EINVALIDPARAMS;
273 if (
id >= EC_BACKENDS_MAX)
274 return -EBACKENDNOTSUPP;
276 if ((args->k + args->m) > EC_MAX_FRAGMENTS) {
277 log_error(
"Total number of fragments (k + m) must be less than %d\n",
279 return -EINVALIDPARAMS;
283 instance = calloc(1,
sizeof(*instance));
284 if (NULL == instance)
289 memcpy(&(bargs.uargs), args, sizeof (
struct ec_args));
290 instance->args = bargs;
294 if (!instance->desc.backend_sohandle) {
296 if (!instance->desc.backend_sohandle) {
300 return -EBACKENDNOTAVAIL;
305 instance->desc.backend_desc = instance->common.ops->init(
306 &instance->args, instance->desc.backend_sohandle);
307 if (NULL == instance->desc.backend_desc) {
309 return -EBACKENDINITERR;
315 return instance->idesc;
325 ec_backend_t instance = NULL;
328 instance = liberasurecode_backend_instance_get_by_desc(desc);
329 if (NULL == instance)
330 return -EBACKENDNOTAVAIL;
333 instance->common.ops->exit(instance->desc.backend_desc);
364 char **encoded_parity)
368 ec_backend_t instance = liberasurecode_backend_instance_get_by_desc(desc);
369 if (NULL == instance) {
370 return -EBACKENDNOTAVAIL;
373 k = instance->args.uargs.k;
374 m = instance->args.uargs.m;
377 for (i = 0; i < k; i++) {
378 free(encoded_data[i]);
384 if (encoded_parity) {
385 for (i = 0; i < m; i++) {
386 free(encoded_parity[i]);
388 free(encoded_parity);
411 const char *orig_data, uint64_t orig_data_size,
412 char ***encoded_data,
char ***encoded_parity,
413 uint64_t *fragment_len)
420 if (orig_data == NULL) {
421 log_error(
"Pointer to data buffer is null!");
422 ret = -EINVALIDPARAMS;
426 if (encoded_data == NULL) {
427 log_error(
"Pointer to encoded data buffers is null!");
428 return -EINVALIDPARAMS;
431 if (encoded_parity == NULL) {
432 log_error(
"Pointer to encoded parity buffers is null!");
433 return -EINVALIDPARAMS;
436 if (fragment_len == NULL) {
437 log_error(
"Pointer to fragment length is null!");
438 ret = -EINVALIDPARAMS;
442 ec_backend_t instance = liberasurecode_backend_instance_get_by_desc(desc);
443 if (NULL == instance) {
444 ret = -EBACKENDNOTAVAIL;
448 k = instance->args.uargs.k;
449 m = instance->args.uargs.m;
455 if (NULL == *encoded_data) {
456 log_error(
"Could not allocate data buffer!");
461 if (NULL == *encoded_parity) {
462 log_error(
"Could not allocate parity buffer!");
467 *encoded_data, *encoded_parity, &blocksize);
476 ret = instance->common.ops->encode(instance->desc.backend_desc,
477 *encoded_data, *encoded_parity, blocksize);
486 *encoded_data, *encoded_parity);
494 log_error(
"Error in liberasurecode_encode %d", ret);
514 ec_backend_t instance = liberasurecode_backend_instance_get_by_desc(desc);
515 if (NULL == instance) {
516 return -EBACKENDNOTAVAIL;
538 char **available_fragments,
539 int num_fragments, uint64_t fragment_len,
540 int force_metadata_checks,
541 char **out_data, uint64_t *out_data_len)
547 int orig_data_size = 0;
551 char **parity = NULL;
552 char **data_segments = NULL;
553 char **parity_segments = NULL;
554 int *missing_idxs = NULL;
556 uint64_t realloc_bm = 0;
558 ec_backend_t instance = liberasurecode_backend_instance_get_by_desc(desc);
559 if (NULL == instance) {
560 ret = -EBACKENDNOTAVAIL;
564 if (NULL == available_fragments) {
565 log_error(
"Pointer to encoded fragments buffer is null!");
566 ret = -EINVALIDPARAMS;
570 if (NULL == out_data) {
571 log_error(
"Pointer to decoded data buffer is null!");
572 ret = -EINVALIDPARAMS;
576 if (NULL == out_data_len) {
577 log_error(
"Pointer to decoded data length variable is null!");
578 ret = -EINVALIDPARAMS;
582 k = instance->args.uargs.k;
583 m = instance->args.uargs.m;
585 if (num_fragments < k) {
586 log_error(
"Not enough fragments to decode, got %d, need %d!",
592 if (fragment_len <
sizeof(fragment_header_t)) {
593 log_error(
"Fragments not long enough to include headers! " 594 "Need %zu, but got %lu.",
sizeof(fragment_header_t),
595 (
unsigned long)fragment_len);
599 for (i = 0; i < num_fragments; ++i) {
602 (fragment_header_t *) available_fragments[i])) {
603 log_error(
"Invalid fragment header information!");
609 if (instance->common.id != EC_BACKEND_SHSS && instance->common.id != EC_BACKEND_LIBPHAZR) {
616 available_fragments, num_fragments,
617 out_data, out_data_len);
630 log_error(
"Could not allocate data buffer!");
635 if (NULL == parity) {
636 log_error(
"Could not allocate parity buffer!");
641 if (NULL == missing_idxs) {
642 log_error(
"Could not allocate missing_idxs buffer!");
647 if (force_metadata_checks) {
648 int num_invalid_fragments = 0;
649 for (i = 0; i < num_fragments; ++i) {
651 ++num_invalid_fragments;
654 if ((num_fragments - num_invalid_fragments) < k) {
656 log_error(
"Not enough valid fragments available for decode!");
666 data, parity, missing_idxs);
669 log_error(
"Could not properly partition the fragments!");
681 data, parity, missing_idxs,
682 &orig_data_size, &blocksize,
683 fragment_len, &realloc_bm);
685 log_error(
"Could not prepare fragments for decode!");
695 ret = instance->common.ops->decode(instance->desc.backend_desc,
696 data_segments, parity_segments,
697 missing_idxs, blocksize);
700 log_error(
"Encountered error in backend decode function!");
709 while (missing_idxs[j] >= 0) {
711 int missing_idx = missing_idxs[j];
712 if (missing_idx < k) {
714 char *fragment_ptr = data[missing_idx];
715 init_fragment_header(fragment_ptr);
717 orig_data_size, blocksize, instance->args.uargs.ct,
727 log_error(
"Could not convert decoded fragments to a string!");
732 if (realloc_bm != 0) {
733 for (i = 0; i < k; i++) {
734 if (realloc_bm & (1 << i)) {
739 for (i = 0; i < m; i++) {
740 if (realloc_bm & (1 << (i + k))) {
750 free(parity_segments);
768 char **available_fragments,
769 int num_fragments, uint64_t fragment_len,
775 int orig_data_size = 0;
777 char **parity = NULL;
778 int *missing_idxs = NULL;
779 char *fragment_ptr = NULL;
780 int is_destination_missing = 0;
784 uint64_t realloc_bm = 0;
785 char **data_segments = NULL;
786 char **parity_segments = NULL;
789 ec_backend_t instance = liberasurecode_backend_instance_get_by_desc(desc);
790 if (NULL == instance) {
791 ret = -EBACKENDNOTAVAIL;
795 if (NULL == available_fragments) {
796 log_error(
"Can not reconstruct fragment, available fragments pointer is NULL");
797 ret = -EINVALIDPARAMS;
801 if (NULL == out_fragment) {
802 log_error(
"Can not reconstruct fragment, output fragment pointer is NULL");
803 ret = -EINVALIDPARAMS;
807 k = instance->args.uargs.k;
808 m = instance->args.uargs.m;
810 for (i = 0; i < num_fragments; i++) {
813 (fragment_header_t *) available_fragments[i])) {
814 log_error(
"Invalid fragment header information!");
825 log_error(
"Could not allocate data buffer!");
831 if (NULL == parity) {
832 log_error(
"Could not allocate parity buffer!");
838 if (NULL == missing_idxs) {
839 log_error(
"Could not allocate missing_idxs buffer!");
849 data, parity, missing_idxs);
852 log_error(
"Could not properly partition the fragments!");
866 while (missing_idxs[i] > -1) {
867 if (missing_idxs[i] == destination_idx) {
868 is_destination_missing = 1;
873 if (!is_destination_missing) {
874 if (destination_idx < k) {
875 fragment_ptr = data[destination_idx];
877 fragment_ptr = parity[destination_idx - k];
879 log_warn(
"Dest idx for reconstruction was supplied as available buffer!");
880 goto destination_available;
890 &orig_data_size, &blocksize,
891 fragment_len, &realloc_bm);
893 log_error(
"Could not prepare fragments for reconstruction!");
903 ret = instance->common.ops->reconstruct(instance->desc.backend_desc,
904 data_segments, parity_segments,
905 missing_idxs, destination_idx,
908 log_error(
"Could not reconstruct fragment!");
915 if (destination_idx < k) {
916 fragment_ptr = data[destination_idx];
918 fragment_ptr = parity[destination_idx - k];
920 init_fragment_header(fragment_ptr);
922 orig_data_size, blocksize, instance->args.uargs.ct,
925 destination_available:
931 memcpy(out_fragment, fragment_ptr, fragment_len);
935 if (realloc_bm != 0) {
936 for (i = 0; i < k; i++) {
937 if (realloc_bm & (1 << i)) {
942 for (i = 0; i < m; i++) {
943 if (realloc_bm & (1 << (i + k))) {
953 free(parity_segments);
974 int *fragments_to_reconstruct,
975 int *fragments_to_exclude,
976 int *fragments_needed)
980 ec_backend_t instance = liberasurecode_backend_instance_get_by_desc(desc);
981 if (NULL == instance) {
982 ret = -EBACKENDNOTAVAIL;
985 if (NULL == fragments_to_reconstruct) {
986 log_error(
"Unable to determine list of fragments needed, pointer to list of indexes to reconstruct is NULL.");
987 ret = -EINVALIDPARAMS;
991 if (NULL == fragments_to_exclude) {
992 log_error(
"Unable to determine list of fragments needed, pointer to list of fragments to exclude is NULL.");
993 ret = -EINVALIDPARAMS;
997 if (NULL == fragments_needed) {
998 log_error(
"Unable to determine list of fragments needed, pointer to list of fragments to reconstruct is NULL.");
999 ret = -EINVALIDPARAMS;
1006 ret = instance->common.ops->fragments_needed(
1007 instance->desc.backend_desc,
1008 fragments_to_reconstruct, fragments_to_exclude, fragments_needed);
1027 fragment_metadata_t *fragment_metadata)
1030 fragment_header_t *fragment_hdr = NULL;
1032 if (NULL == fragment) {
1033 log_error(
"Need valid fragment object to get metadata for");
1034 ret = -EINVALIDPARAMS;
1038 if (NULL == fragment_metadata) {
1039 log_error(
"Need valid fragment_metadata object for return value");
1040 ret = -EINVALIDPARAMS;
1046 (fragment_header_t *) fragment)) {
1047 log_error(
"Invalid fragment header information!");
1052 memcpy(fragment_metadata, fragment,
sizeof(
struct fragment_metadata));
1053 fragment_hdr = (fragment_header_t *) fragment;
1054 if (LIBERASURECODE_FRAG_HEADER_MAGIC != fragment_hdr->magic) {
1055 log_error(
"Invalid fragment, illegal magic value");
1056 ret = -EINVALIDPARAMS;
1060 switch(fragment_hdr->meta.chksum_type) {
1061 case CHKSUM_CRC32: {
1062 uint32_t computed_chksum = 0;
1063 uint32_t stored_chksum = fragment_hdr->meta.chksum[0];
1065 uint64_t fragment_size = fragment_hdr->meta.size;
1066 computed_chksum =
crc32(0, fragment_data, fragment_size);
1067 if (stored_chksum != computed_chksum) {
1068 fragment_metadata->chksum_mismatch = 1;
1070 fragment_metadata->chksum_mismatch = 0;
1087 uint32_t *stored_csum = NULL, csum = 0;
1088 assert (NULL != header);
1089 if (header->libec_version == 0)
1092 if (header->libec_version < _VERSION(1,2,0))
1096 if (NULL == stored_csum)
1098 csum =
crc32(0, &header->meta,
sizeof(fragment_metadata_t));
1099 return (*stored_csum != csum);
1103 fragment_metadata_t *md)
1105 int k = be->args.uargs.k;
1106 int m = be->args.uargs.m;
1107 if (md->idx > (k + m)) {
1110 if (md->backend_id != be->common.id) {
1113 if (!be->common.ops->is_compatible_with(md->backend_version)) {
1121 ec_backend_t be = liberasurecode_backend_instance_get_by_desc(desc);
1123 log_error(
"Unable to verify fragment metadata: invalid backend id %d.",
1125 return -EINVALIDPARAMS;
1128 fragment_metadata) != 0) {
1131 if (!be->common.ops->is_compatible_with(fragment_metadata->backend_version)) {
1134 if (fragment_metadata->chksum_mismatch == 1) {
1143 fragment_metadata_t fragment_metadata;
1144 ec_backend_t be = liberasurecode_backend_instance_get_by_desc(desc);
1146 log_error(
"Unable to verify fragment metadata: invalid backend id %d.",
1151 log_error(
"Unable to verify fragment validity: fragments missing.");
1155 ver > LIBERASURECODE_VERSION) {
1168 char **fragments,
int num_fragments)
1172 log_error(
"Unable to verify stripe metadata: fragments missing.");
1173 return -EINVALIDPARAMS;
1175 if (num_fragments <= 0) {
1176 log_error(
"Unable to verify stripe metadata: " 1177 "number of fragments must be greater than 0.");
1178 return -EINVALIDPARAMS;
1181 for (i = 0; i < num_fragments; i++) {
1182 fragment_metadata_t *fragment_metadata = (fragment_metadata_t*)fragments[i];
1206 int alignment_multiple;
1208 ec_backend_t instance = liberasurecode_backend_instance_get_by_desc(desc);
1209 if (NULL == instance) {
1210 ret = -EBACKENDNOTAVAIL;
1214 k = instance->args.uargs.k;
1216 word_size = instance->common.ops->element_size(
1217 instance->desc.backend_desc) / 8;
1219 alignment_multiple = k * word_size;
1221 ret = ((data_len + alignment_multiple - 1) / alignment_multiple)
1222 * alignment_multiple;
1239 ec_backend_t instance = liberasurecode_backend_instance_get_by_desc(desc);
1241 if (NULL == instance)
1242 return -EBACKENDNOTAVAIL;
1244 int blocksize = aligned_data_len / instance->args.uargs.k;
1245 int metadata_size = instance->common.ops->get_backend_metadata_size(
1246 instance->desc.backend_desc,
1248 int size = blocksize + metadata_size;
1260 return LIBERASURECODE_VERSION;
1267 int liberasurecode_backend_validate(ec_backend_t backend)
1276 ec_backend_t liberasurecode_backend_get(
const char *name)
1278 ec_backend_t b = liberasurecode_backend_lookup_by_name(name);
1285 void liberasurecode_backend_put(ec_backend_t backend)
1287 if (backend->users > 0)
1292 ec_backend_t liberasurecode_backend_instance_active(ec_backend_t instance)
1296 SLIST_FOREACH(b, &active_instances, link) {
1297 if (strcmp(b->name, name) == 0)
1304 ec_backend_t liberasurecode_backend_lookup_by_soname(
const char *soname)
1308 SLIST_FOREACH(b, &active_instances, link) {
1309 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)
struct ec_backend_common backend_jerasure_rs_cauchy
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)
struct ec_backend_common backend_jerasure_rs_vand
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.
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)
struct ec_backend_common backend_isa_l_rs_vand
int liberasurecode_backend_available(const ec_backend_id_t backend_id)
Checks if a given backend is available.
struct ec_backend_common backend_null
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)
int liberasurecode_instance_destroy(int desc)
Close a liberasurecode instance.
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)
struct ec_backend_common backend_liberasurecode_rs_vand
struct ec_backend_common backend_isa_l_rs_cauchy
int liberasurecode_encode_cleanup(int desc, char **encoded_data, char **encoded_parity)
Cleanup structures allocated by librasurecode_encode.
int is_invalid_fragment_header(fragment_header_t *header)
int liberasurecode_backend_alloc_desc(void)
Allocated backend instance descriptor.
uint64_t get_fragment_size(char *buf)
Return total fragment length (on-disk, on-wire)
char * ec_backends_supported_str[EC_BACKENDS_MAX]
struct ec_backend_common backend_flat_xor_hd
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)
struct ec_backend_common backend_shss
void __attribute__((constructor))
int get_libec_version(char *buf, uint32_t *ver)
struct ec_backend_common backend_libphazr
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.