32#include "erasurecode.h"
33#include "erasurecode_backend.h"
34#include "erasurecode_helpers.h"
35#include "erasurecode_helpers_ext.h"
36#include "erasurecode_preprocessing.h"
37#include "erasurecode_postprocessing.h"
38#include "erasurecode_stdinc.h"
41#include "erasurecode_log.h"
77 SLIST_HEAD_INITIALIZER(active_instances);
78rwlock_t active_instances_rwlock = RWLOCK_INITIALIZER;
81int next_backend_desc = 0;
89ec_backend_t liberasurecode_backend_instance_get_by_desc(
int desc)
91 struct ec_backend *b = NULL;
92 SLIST_FOREACH(b, &active_instances, link) {
108 if (++next_backend_desc <= 0)
109 next_backend_desc = 1;
110 if (!liberasurecode_backend_instance_get_by_desc(next_backend_desc))
111 return next_backend_desc;
127 rc = rwlock_wrlock(&active_instances_rwlock);
129 SLIST_INSERT_HEAD(&active_instances, instance, link);
133 instance->idesc = desc;
139 rwlock_unlock(&active_instances_rwlock);
153 rc = rwlock_wrlock(&active_instances_rwlock);
155 SLIST_REMOVE(&active_instances, instance, ec_backend, link);
159 rwlock_unlock(&active_instances_rwlock);
169 char *msg = dlerror();
171 log_error(
"%s: unknown dynamic linking error\n", caller);
173 log_error(
"%s: dynamic linking error %s\n", caller, msg);
179 if (NULL == instance)
182 return dlopen(instance->common.soname, RTLD_LAZY | RTLD_LOCAL);
187 if (NULL == instance || NULL == instance->desc.backend_sohandle)
190 dlclose(instance->desc.backend_sohandle);
193 instance->desc.backend_sohandle = NULL;
200liberasurecode_init(
void) {
202 openlog(
"liberasurecode", LOG_PID | LOG_CONS, LOG_USER);
216liberasurecode_exit(
void) {
233 struct ec_backend backend;
234 if (backend_id >= EC_BACKENDS_MAX)
239 if (!backend.desc.backend_sohandle) {
267 struct ec_args *args)
269 ec_backend_t instance = NULL;
270 struct ec_backend_args bargs;
272 return -EINVALIDPARAMS;
274 if (
id >= EC_BACKENDS_MAX)
275 return -EBACKENDNOTSUPP;
277 if (args->k < 0 || args->m < 0)
278 return -EINVALIDPARAMS;
279 if ((args->k + args->m) > EC_MAX_FRAGMENTS) {
280 log_error(
"Total number of fragments (k + m) must be less than %d\n",
282 return -EINVALIDPARAMS;
286 instance = calloc(1,
sizeof(*instance));
287 if (NULL == instance)
292 memcpy(&(bargs.uargs), args, sizeof (
struct ec_args));
293 instance->args = bargs;
297 if (!instance->desc.backend_sohandle) {
299 if (!instance->desc.backend_sohandle) {
303 return -EBACKENDNOTAVAIL;
308 instance->desc.backend_desc = instance->common.ops->init(
309 &instance->args, instance->desc.backend_sohandle);
310 if (NULL == instance->desc.backend_desc) {
312 return -EBACKENDINITERR;
318 return instance->idesc;
328 ec_backend_t instance = NULL;
331 instance = liberasurecode_backend_instance_get_by_desc(desc);
332 if (NULL == instance)
333 return -EBACKENDNOTAVAIL;
336 instance->common.ops->exit(instance->desc.backend_desc);
367 char **encoded_parity)
371 ec_backend_t instance = liberasurecode_backend_instance_get_by_desc(desc);
372 if (NULL == instance) {
373 return -EBACKENDNOTAVAIL;
376 k = instance->args.uargs.k;
377 m = instance->args.uargs.m;
380 for (i = 0; i < k; i++) {
381 free(encoded_data[i]);
387 if (encoded_parity) {
388 for (i = 0; i < m; i++) {
389 free(encoded_parity[i]);
391 free(encoded_parity);
414 const char *orig_data, uint64_t orig_data_size,
415 char ***encoded_data,
char ***encoded_parity,
416 uint64_t *fragment_len)
423 if (orig_data == NULL) {
424 log_error(
"Pointer to data buffer is null!");
425 ret = -EINVALIDPARAMS;
429 if (encoded_data == NULL) {
430 log_error(
"Pointer to encoded data buffers is null!");
431 return -EINVALIDPARAMS;
434 if (encoded_parity == NULL) {
435 log_error(
"Pointer to encoded parity buffers is null!");
436 return -EINVALIDPARAMS;
439 if (fragment_len == NULL) {
440 log_error(
"Pointer to fragment length is null!");
441 ret = -EINVALIDPARAMS;
445 ec_backend_t instance = liberasurecode_backend_instance_get_by_desc(desc);
446 if (NULL == instance) {
447 ret = -EBACKENDNOTAVAIL;
451 k = instance->args.uargs.k;
452 m = instance->args.uargs.m;
458 if (NULL == *encoded_data) {
459 log_error(
"Could not allocate data buffer!");
464 if (NULL == *encoded_parity) {
465 log_error(
"Could not allocate parity buffer!");
470 *encoded_data, *encoded_parity, &blocksize);
479 ret = instance->common.ops->encode(instance->desc.backend_desc,
480 *encoded_data, *encoded_parity, blocksize);
489 *encoded_data, *encoded_parity);
497 log_error(
"Error in liberasurecode_encode %d", ret);
517 ec_backend_t instance = liberasurecode_backend_instance_get_by_desc(desc);
518 if (NULL == instance) {
519 return -EBACKENDNOTAVAIL;
541 char **available_fragments,
542 int num_fragments, uint64_t fragment_len,
543 int force_metadata_checks,
544 char **out_data, uint64_t *out_data_len)
550 int orig_data_size = 0;
554 char **parity = NULL;
555 char **data_segments = NULL;
556 char **parity_segments = NULL;
557 int *missing_idxs = NULL;
559 uint64_t realloc_bm = 0;
561 ec_backend_t instance = liberasurecode_backend_instance_get_by_desc(desc);
562 if (NULL == instance) {
563 ret = -EBACKENDNOTAVAIL;
567 if (NULL == available_fragments) {
568 log_error(
"Pointer to encoded fragments buffer is null!");
569 ret = -EINVALIDPARAMS;
573 if (NULL == out_data) {
574 log_error(
"Pointer to decoded data buffer is null!");
575 ret = -EINVALIDPARAMS;
579 if (NULL == out_data_len) {
580 log_error(
"Pointer to decoded data length variable is null!");
581 ret = -EINVALIDPARAMS;
585 k = instance->args.uargs.k;
586 m = instance->args.uargs.m;
588 if (num_fragments < k) {
589 log_error(
"Not enough fragments to decode, got %d, need %d!",
595 if (fragment_len <
sizeof(fragment_header_t)) {
596 log_error(
"Fragments not long enough to include headers! "
597 "Need %zu, but got %lu.",
sizeof(fragment_header_t),
598 (
unsigned long)fragment_len);
602 for (i = 0; i < num_fragments; ++i) {
605 (fragment_header_t *) available_fragments[i])) {
606 log_error(
"Invalid fragment header information!");
612 if (instance->common.id != EC_BACKEND_SHSS && instance->common.id != EC_BACKEND_LIBPHAZR) {
619 available_fragments, num_fragments,
620 out_data, out_data_len);
633 log_error(
"Could not allocate data buffer!");
638 if (NULL == parity) {
639 log_error(
"Could not allocate parity buffer!");
644 if (NULL == missing_idxs) {
645 log_error(
"Could not allocate missing_idxs buffer!");
650 if (force_metadata_checks) {
651 int num_invalid_fragments = 0;
652 for (i = 0; i < num_fragments; ++i) {
654 ++num_invalid_fragments;
657 if ((num_fragments - num_invalid_fragments) < k) {
659 log_error(
"Not enough valid fragments available for decode!");
669 data, parity, missing_idxs);
672 log_error(
"Could not properly partition the fragments!");
684 data, parity, missing_idxs,
685 &orig_data_size, &blocksize,
686 fragment_len, &realloc_bm);
688 log_error(
"Could not prepare fragments for decode!");
698 ret = instance->common.ops->decode(instance->desc.backend_desc,
699 data_segments, parity_segments,
700 missing_idxs, blocksize);
703 log_error(
"Encountered error in backend decode function!");
712 while (missing_idxs[j] >= 0) {
714 int missing_idx = missing_idxs[j];
715 if (missing_idx < k) {
717 char *fragment_ptr = data[missing_idx];
718 init_fragment_header(fragment_ptr);
720 orig_data_size, blocksize, instance->args.uargs.ct,
730 log_error(
"Could not convert decoded fragments to a string!");
735 if (realloc_bm != 0) {
736 for (i = 0; i < k; i++) {
737 if (realloc_bm & (1 << i)) {
742 for (i = 0; i < m; i++) {
743 if (realloc_bm & (1 << (i + k))) {
753 free(parity_segments);
771 char **available_fragments,
772 int num_fragments, uint64_t fragment_len,
778 int orig_data_size = 0;
780 char **parity = NULL;
781 int *missing_idxs = NULL;
782 char *fragment_ptr = NULL;
783 int is_destination_missing = 0;
787 uint64_t realloc_bm = 0;
788 char **data_segments = NULL;
789 char **parity_segments = NULL;
792 ec_backend_t instance = liberasurecode_backend_instance_get_by_desc(desc);
793 if (NULL == instance) {
794 ret = -EBACKENDNOTAVAIL;
798 if (NULL == available_fragments) {
799 log_error(
"Can not reconstruct fragment, available fragments pointer is NULL");
800 ret = -EINVALIDPARAMS;
804 if (NULL == out_fragment) {
805 log_error(
"Can not reconstruct fragment, output fragment pointer is NULL");
806 ret = -EINVALIDPARAMS;
810 k = instance->args.uargs.k;
811 m = instance->args.uargs.m;
813 for (i = 0; i < num_fragments; i++) {
816 (fragment_header_t *) available_fragments[i])) {
817 log_error(
"Invalid fragment header information!");
828 log_error(
"Could not allocate data buffer!");
834 if (NULL == parity) {
835 log_error(
"Could not allocate parity buffer!");
841 if (NULL == missing_idxs) {
842 log_error(
"Could not allocate missing_idxs buffer!");
852 data, parity, missing_idxs);
855 log_error(
"Could not properly partition the fragments!");
869 while (missing_idxs[i] > -1) {
870 if (missing_idxs[i] == destination_idx) {
871 is_destination_missing = 1;
876 if (!is_destination_missing) {
877 if (destination_idx < k) {
878 fragment_ptr = data[destination_idx];
880 fragment_ptr = parity[destination_idx - k];
882 log_warn(
"Dest idx for reconstruction was supplied as available buffer!");
883 goto destination_available;
893 &orig_data_size, &blocksize,
894 fragment_len, &realloc_bm);
896 log_error(
"Could not prepare fragments for reconstruction!");
906 ret = instance->common.ops->reconstruct(instance->desc.backend_desc,
907 data_segments, parity_segments,
908 missing_idxs, destination_idx,
911 log_error(
"Could not reconstruct fragment!");
918 if (destination_idx < k) {
919 fragment_ptr = data[destination_idx];
921 fragment_ptr = parity[destination_idx - k];
923 init_fragment_header(fragment_ptr);
925 orig_data_size, blocksize, instance->args.uargs.ct,
928destination_available:
934 memcpy(out_fragment, fragment_ptr, fragment_len);
938 if (realloc_bm != 0) {
939 for (i = 0; i < k; i++) {
940 if (realloc_bm & (1 << i)) {
945 for (i = 0; i < m; i++) {
946 if (realloc_bm & (1 << (i + k))) {
956 free(parity_segments);
977 int *fragments_to_reconstruct,
978 int *fragments_to_exclude,
979 int *fragments_needed)
983 ec_backend_t instance = liberasurecode_backend_instance_get_by_desc(desc);
984 if (NULL == instance) {
985 ret = -EBACKENDNOTAVAIL;
988 if (NULL == fragments_to_reconstruct) {
989 log_error(
"Unable to determine list of fragments needed, pointer to list of indexes to reconstruct is NULL.");
990 ret = -EINVALIDPARAMS;
994 if (NULL == fragments_to_exclude) {
995 log_error(
"Unable to determine list of fragments needed, pointer to list of fragments to exclude is NULL.");
996 ret = -EINVALIDPARAMS;
1000 if (NULL == fragments_needed) {
1001 log_error(
"Unable to determine list of fragments needed, pointer to list of fragments to reconstruct is NULL.");
1002 ret = -EINVALIDPARAMS;
1009 ret = instance->common.ops->fragments_needed(
1010 instance->desc.backend_desc,
1011 fragments_to_reconstruct, fragments_to_exclude, fragments_needed);
1030 fragment_metadata_t *fragment_metadata)
1033 fragment_header_t *fragment_hdr = NULL;
1035 if (NULL == fragment) {
1036 log_error(
"Need valid fragment object to get metadata for");
1037 ret = -EINVALIDPARAMS;
1041 if (NULL == fragment_metadata) {
1042 log_error(
"Need valid fragment_metadata object for return value");
1043 ret = -EINVALIDPARAMS;
1049 log_error(
"Invalid fragment header information!");
1054 memcpy(fragment_metadata, fragment,
sizeof(
struct fragment_metadata));
1055 fragment_hdr = (fragment_header_t *) fragment;
1056 if (LIBERASURECODE_FRAG_HEADER_MAGIC != fragment_hdr->magic) {
1057 if (LIBERASURECODE_FRAG_HEADER_MAGIC != bswap_32(fragment_hdr->magic)) {
1058 log_error(
"Invalid fragment, illegal magic value");
1059 ret = -EINVALIDPARAMS;
1064 fragment_metadata->idx = bswap_32(fragment_metadata->idx);
1065 fragment_metadata->size = bswap_32(fragment_metadata->size);
1066 fragment_metadata->frag_backend_metadata_size =
1067 bswap_32(fragment_metadata->frag_backend_metadata_size);
1068 fragment_metadata->orig_data_size =
1069 bswap_64(fragment_metadata->orig_data_size);
1070 fragment_metadata->chksum_type =
1071 bswap_32(fragment_metadata->chksum_type);
1072 for (
int i = 0; i < LIBERASURECODE_MAX_CHECKSUM_LEN; i++) {
1073 fragment_metadata->chksum[i] =
1074 bswap_32(fragment_metadata->chksum[i]);
1076 fragment_metadata->backend_version =
1077 bswap_32(fragment_metadata->backend_version);
1081 switch(fragment_metadata->chksum_type) {
1082 case CHKSUM_CRC32: {
1083 uint32_t computed_chksum = 0;
1084 uint32_t stored_chksum = fragment_metadata->chksum[0];
1086 uint64_t fragment_size = fragment_metadata->size;
1087 computed_chksum = crc32(0, (
unsigned char *) fragment_data, fragment_size);
1088 if (stored_chksum != computed_chksum) {
1092 0, fragment_data, fragment_size);
1093 if (stored_chksum != computed_chksum) {
1094 fragment_metadata->chksum_mismatch = 1;
1096 fragment_metadata->chksum_mismatch = 0;
1099 fragment_metadata->chksum_mismatch = 0;
1116 uint32_t csum = 0, metadata_chksum = 0, libec_version = 0;
1117 assert (NULL != header);
1118 if (header->libec_version == 0)
1121 metadata_chksum = header->metadata_chksum;
1122 libec_version = header->libec_version;
1123 if (header->magic != LIBERASURECODE_FRAG_HEADER_MAGIC) {
1124 if (bswap_32(header->magic) != LIBERASURECODE_FRAG_HEADER_MAGIC) {
1125 log_error(
"Invalid fragment header (get meta chksum)!");
1132 metadata_chksum = bswap_32(metadata_chksum);
1133 libec_version = bswap_32(libec_version);
1137 if (libec_version < _VERSION(1,2,0))
1141 csum = crc32(0, (
unsigned char *) &header->meta,
sizeof(fragment_metadata_t));
1142 if (metadata_chksum == csum) {
1148 return (metadata_chksum != csum);
1152 fragment_metadata_t *md)
1154 int k = be->args.uargs.k;
1155 int m = be->args.uargs.m;
1156 if (md->idx > (k + m)) {
1159 if (md->backend_id != be->common.id) {
1162 if (!be->common.ops->is_compatible_with(md->backend_version)) {
1170 ec_backend_t be = liberasurecode_backend_instance_get_by_desc(desc);
1172 log_error(
"Unable to verify fragment metadata: invalid backend id %d.",
1174 return -EINVALIDPARAMS;
1177 fragment_metadata) != 0) {
1180 if (!be->common.ops->is_compatible_with(fragment_metadata->backend_version)) {
1183 if (fragment_metadata->chksum_mismatch == 1) {
1192 fragment_metadata_t fragment_metadata;
1193 ec_backend_t be = liberasurecode_backend_instance_get_by_desc(desc);
1195 log_error(
"Unable to verify fragment metadata: invalid backend id %d.",
1200 log_error(
"Unable to verify fragment validity: fragments missing.");
1204 ver > LIBERASURECODE_VERSION) {
1217 char **fragments,
int num_fragments)
1221 log_error(
"Unable to verify stripe metadata: fragments missing.");
1222 return -EINVALIDPARAMS;
1224 if (num_fragments <= 0) {
1225 log_error(
"Unable to verify stripe metadata: "
1226 "number of fragments must be greater than 0.");
1227 return -EINVALIDPARAMS;
1230 for (i = 0; i < num_fragments; i++) {
1231 fragment_metadata_t *fragment_metadata = (fragment_metadata_t*)fragments[i];
1255 int alignment_multiple;
1257 ec_backend_t instance = liberasurecode_backend_instance_get_by_desc(desc);
1258 if (NULL == instance) {
1259 ret = -EBACKENDNOTAVAIL;
1263 k = instance->args.uargs.k;
1265 word_size = instance->common.ops->element_size(
1266 instance->desc.backend_desc) / 8;
1268 alignment_multiple = k * word_size;
1270 ret = ((data_len + alignment_multiple - 1) / alignment_multiple)
1271 * alignment_multiple;
1288 ec_backend_t instance = liberasurecode_backend_instance_get_by_desc(desc);
1290 if (NULL == instance)
1291 return -EBACKENDNOTAVAIL;
1293 int blocksize = aligned_data_len / instance->args.uargs.k;
1294 int metadata_size = instance->common.ops->get_backend_metadata_size(
1295 instance->desc.backend_desc,
1297 int size = blocksize + metadata_size;
1309 return LIBERASURECODE_VERSION;
1316int liberasurecode_backend_validate(ec_backend_t backend)
1325ec_backend_t liberasurecode_backend_get(
const char *name)
1327 ec_backend_t b = liberasurecode_backend_lookup_by_name(name);
1334void liberasurecode_backend_put(ec_backend_t backend)
1336 if (backend->users > 0)
1341ec_backend_t liberasurecode_backend_instance_active(ec_backend_t instance)
1345 SLIST_FOREACH(b, &active_instances, link) {
1346 if (strcmp(b->name, name) == 0)
1353ec_backend_t liberasurecode_backend_lookup_by_soname(
const char *soname)
1357 SLIST_FOREACH(b, &active_instances, link) {
1358 if (strcmp(b->soname, soname) == 0)
int liberasurecode_crc32_alt(int crc, const void *buf, size_t size)
int liberasurecode_verify_fragment_metadata(ec_backend_t be, fragment_metadata_t *md)
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_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.
void * liberasurecode_backend_open(ec_backend_t instance)
int is_invalid_fragment_header(fragment_header_t *header)
struct ec_backend_common backend_flat_xor_hd
int liberasurecode_backend_close(ec_backend_t instance)
static void print_dlerror(const char *caller)
int liberasurecode_decode_cleanup(int desc, char *data)
Cleanup structures allocated by librasurecode_decode.
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.
struct ec_backend_common backend_null
struct ec_backend_common backend_shss
struct ec_backend_common backend_isa_l_rs_vand
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,...
struct ec_backend_common backend_liberasurecode_rs_vand
struct ec_backend_common backend_isa_l_rs_cauchy
uint32_t liberasurecode_get_version()
This will return the liberasurecode version for the descriptor.
ec_backend_t ec_backends_supported[]
int liberasurecode_get_fragment_metadata(char *fragment, fragment_metadata_t *fragment_metadata)
Get opaque metadata for a fragment.
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.
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.
SLIST_HEAD(backend_list, ec_backend)
Look up a backend instance by descriptor.
int is_invalid_fragment(int desc, char *fragment)
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.
char * ec_backends_supported_str[EC_BACKENDS_MAX]
int is_invalid_fragment_metadata(int desc, fragment_metadata_t *fragment_metadata)
int liberasurecode_verify_stripe_metadata(int desc, char **fragments, int num_fragments)
struct ec_backend_common backend_libphazr
int liberasurecode_backend_instance_unregister(ec_backend_t instance)
Unregister a backend instance.
int liberasurecode_encode_cleanup(int desc, char **encoded_data, char **encoded_parity)
Cleanup structures allocated by librasurecode_encode.
int num_supported_backends
int liberasurecode_backend_available(const ec_backend_id_t backend_id)
Checks if a given backend is available.
int liberasurecode_backend_alloc_desc(void)
Allocated backend instance descriptor.
struct ec_backend_common backend_jerasure_rs_cauchy
int liberasurecode_backend_instance_register(ec_backend_t instance)
Register a backend instance with liberasurecode.
int liberasurecode_instance_destroy(int desc)
Close a liberasurecode instance.
struct ec_backend_common backend_jerasure_rs_vand
int liberasurecode_get_fragment_size(int desc, int data_len)
void __attribute__((constructor))
void * alloc_zeroed_buffer(int size)
Allocate a zero-ed buffer of a specific size.
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_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 get_data_ptr_array_from_fragments(char **data_array, char **fragments, int num_fragments)
uint64_t get_fragment_size(char *buf)
Return total fragment length (on-disk, on-wire)
int get_fragment_ptr_array_from_data(char **frag_array, char **data, int num_data)
char * get_data_ptr_from_fragment(char *buf)
int get_libec_version(char *buf, uint32_t *ver)
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 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)
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 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 fragments_to_string(int k, int m, char **fragments, int num_fragments, char **orig_payload, uint64_t *payload_len)
int get_fragment_partition(int k, int m, char **fragments, int num_fragments, char **data, char **parity, int *missing)