liberasurecode 1.8.0
Erasure Code API library
Loading...
Searching...
No Matches
erasurecode.c
Go to the documentation of this file.
1/*
2 * Copyright 2014 Tushar Gohad, Kevin M Greenan, Eric Lambert, Mark Storer
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are met:
6 *
7 * Redistributions of source code must retain the above copyright notice, this
8 * list of conditions and the following disclaimer.
9 *
10 * Redistributions in binary form must reproduce the above copyright notice, this
11 * list of conditions and the following disclaimer in the documentation and/or
12 * other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY
13 * THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED
14 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
15 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
16 * EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
17 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
18 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
19 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
20 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
21 * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
22 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
23 *
24 * liberasurecode API implementation
25 *
26 * vi: set noai tw=79 ts=4 sw=4:
27 */
28
29#include <assert.h>
30#include <zlib.h>
31#include "list.h"
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"
39
40#include "alg_sig.h"
41#include "erasurecode_log.h"
42
43/* =~=*=~==~=*=~==~=*=~= Supported EC backends =~=*=~==~=*=~==~=*=~==~=*=~== */
44
45/* EC backend references */
46extern struct ec_backend_common backend_null;
47extern struct ec_backend_common backend_flat_xor_hd;
48extern struct ec_backend_common backend_jerasure_rs_vand;
49extern struct ec_backend_common backend_jerasure_rs_cauchy;
50extern struct ec_backend_common backend_isa_l_rs_vand;
51extern struct ec_backend_common backend_shss;
52extern struct ec_backend_common backend_liberasurecode_rs_vand;
53extern struct ec_backend_common backend_isa_l_rs_cauchy;
54extern struct ec_backend_common backend_libphazr;
55extern struct ec_backend_common backend_isa_l_rs_vand_inv;
56extern struct ec_backend_common backend_isa_l_rs_lrc;
57
58static ec_backend_t ec_backends_supported[] = {
59 (ec_backend_t) &backend_null,
60 (ec_backend_t) &backend_jerasure_rs_vand,
61 (ec_backend_t) &backend_jerasure_rs_cauchy,
62 (ec_backend_t) &backend_flat_xor_hd,
63 (ec_backend_t) &backend_isa_l_rs_vand,
64 (ec_backend_t) &backend_shss,
65 (ec_backend_t) &backend_liberasurecode_rs_vand,
66 (ec_backend_t) &backend_isa_l_rs_cauchy,
67 (ec_backend_t) &backend_libphazr,
68 (ec_backend_t) &backend_isa_l_rs_vand_inv,
69 (ec_backend_t) &backend_isa_l_rs_lrc,
70 NULL,
71};
72
73/* =~=*=~==~=*=~==~=*=~= EC backend instance management =~=*=~==~=*=~==~=*= */
74
75/* Registered erasure code backend instances */
76static SLIST_HEAD(backend_list, ec_backend) active_instances =
77 SLIST_HEAD_INITIALIZER(active_instances);
86static rwlock_t active_instances_rwlock = RWLOCK_INITIALIZER;
87
88/* Backend instance id */
89static int next_backend_desc = 0;
90
97ec_backend_t liberasurecode_backend_instance_get_by_desc(int desc)
98{
99 struct ec_backend *b = NULL;
100 SLIST_FOREACH(b, &active_instances, link) {
101 if (b->idesc == desc)
102 break;
103 }
104 return b;
105}
106
114{
115 for (;;) {
116 if (++next_backend_desc <= 0)
117 next_backend_desc = 1;
118 if (!liberasurecode_backend_instance_get_by_desc(next_backend_desc))
119 return next_backend_desc;
120 }
121}
122
123/* =~=*=~==~=*=~== liberasurecode backend API helpers =~=*=~==~=*=~== */
124
125static void print_dlerror(const char *caller)
126{
127 char *msg = dlerror();
128 if (NULL == msg)
129 log_error("%s: unknown dynamic linking error\n", caller);
130 else
131 log_error("%s: dynamic linking error %s\n", caller, msg);
132}
133
134/* Generic dlopen/dlclose routines */
135static void* liberasurecode_backend_open(ec_backend_t instance)
136{
137 if (NULL == instance)
138 return NULL;
139 /* Use RTLD_LOCAL to avoid symbol collisions */
140 return dlopen(instance->common.soname, RTLD_LAZY | RTLD_LOCAL);
141}
142
143static int liberasurecode_backend_close(ec_backend_t instance)
144{
145 if (NULL == instance || NULL == instance->desc.backend_sohandle)
146 return 0;
147
148 dlclose(instance->desc.backend_sohandle);
149 dlerror(); /* Clear any existing errors */
150
151 instance->desc.backend_sohandle = NULL;
152 return 0;
153}
154
155/* =*=~==~=*=~==~=*=~= liberasurecode init/exit routines =~=*=~==~=*=~==~=*= */
156
157void __attribute__ ((constructor))
158liberasurecode_init(void) {
159 /* init logging */
160 openlog("liberasurecode", LOG_PID | LOG_CONS, LOG_USER);
161}
162
163void __attribute__ ((destructor))
164liberasurecode_exit(void) {
165 closelog();
166}
167
168/* =~=*=~==~=*=~= liberasurecode frontend API implementation =~=*=~==~=*=~== */
169
177int liberasurecode_backend_available(const ec_backend_id_t backend_id) {
178 struct ec_backend backend;
179 if (backend_id >= EC_BACKENDS_MAX)
180 return 0;
181
182 backend.desc.backend_sohandle = liberasurecode_backend_open(
183 ec_backends_supported[backend_id]);
184 if (!backend.desc.backend_sohandle) {
185 return 0;
186 }
187
189 return 1;
190}
191
211int liberasurecode_instance_create(const ec_backend_id_t id,
212 struct ec_args *args)
213{
214 ec_backend_t instance = NULL;
215 struct ec_backend_args bargs;
216 int desc = -1; /* descriptor to return */
217 int rc = 0; /* return call value */
218 if (!args)
219 return -EINVALIDPARAMS;
220
221 if (id >= EC_BACKENDS_MAX)
222 return -EBACKENDNOTSUPP;
223
224 if (args->k < 0 || args->m < 0)
225 return -EINVALIDPARAMS;
226 if ((args->k + args->m) > EC_MAX_FRAGMENTS) {
227 log_error("Total number of fragments (k + m) must be less than %d\n",
228 EC_MAX_FRAGMENTS);
229 return -EINVALIDPARAMS;
230 }
231
232 /* Allocate memory for ec_backend instance */
233 instance = calloc(1, sizeof(*instance));
234 if (NULL == instance)
235 return -ENOMEM;
236
237 /* Copy common backend, args struct */
238 instance->common = ec_backends_supported[id]->common;
239 memcpy(&(bargs.uargs), args, sizeof (struct ec_args));
240 instance->args = bargs;
241
242 /* Open backend .so if not already open */
243 /* .so handle is returned in instance->desc.backend_sohandle */
244 if (!instance->desc.backend_sohandle) {
245 instance->desc.backend_sohandle = liberasurecode_backend_open(instance);
246 if (!instance->desc.backend_sohandle) {
247 /* ignore during init, return the same handle */
248 print_dlerror(__func__);
250 free(instance);
251 return -EBACKENDNOTAVAIL;
252 }
253 }
254
255 rc = rwlock_wrlock(&active_instances_rwlock);
256 if (rc == 0) {
257 /* Call private init() for the backend */
258 instance->desc.backend_desc = instance->common.ops->init(
259 &instance->args, instance->desc.backend_sohandle);
260 if (NULL == instance->desc.backend_desc) {
261 free(instance);
262 desc = -EBACKENDINITERR;
263 goto register_out;
264 }
265
266 instance->idesc = liberasurecode_backend_alloc_desc();
267 if (instance->idesc <= 0) {
268 instance->common.ops->exit(instance->desc.backend_desc);
270 free(instance);
271 goto register_out;
272 }
273 /* Register instance and return a descriptor/instance id */
274 desc = instance->idesc;
275 SLIST_INSERT_HEAD(&active_instances, instance, link);
276 } else {
277 free(instance);
278 goto exit;
279 }
280
281register_out:
282 rwlock_unlock(&active_instances_rwlock);
283exit:
284 return desc;
285}
286
293{
294 ec_backend_t instance = NULL; /* instance to destroy */
295 int rc = 0; /* return code */
296
297 rc = rwlock_wrlock(&active_instances_rwlock);
298 if (rc == 0) {
299 instance = liberasurecode_backend_instance_get_by_desc(desc);
300 if (NULL == instance) {
301 rwlock_unlock(&active_instances_rwlock);
302 return -EBACKENDNOTAVAIL;
303 }
304
305 /* Call private exit() for the backend */
306 instance->common.ops->exit(instance->desc.backend_desc);
307
308 /* dlclose() backend library */
310
311 /* Remove instance from registry */
312 SLIST_REMOVE(&active_instances, instance, ec_backend, link);
313 free(instance);
314 rwlock_unlock(&active_instances_rwlock);
315 }
316 return rc;
317}
318
335 char **encoded_data,
336 char **encoded_parity)
337{
338 int i, k, m;
339
340 int rc = rwlock_rdlock(&active_instances_rwlock);
341 if (rc) {
342 /* Should just be EDEADLOCK */
343 return rc;
344 }
345 ec_backend_t instance = liberasurecode_backend_instance_get_by_desc(desc);
346 if (NULL == instance) {
347 rwlock_unlock(&active_instances_rwlock);
348 return -EBACKENDNOTAVAIL;
349 }
350
351 k = instance->args.uargs.k;
352 m = instance->args.uargs.m;
353 rwlock_unlock(&active_instances_rwlock);
354
355 if (encoded_data) {
356 for (i = 0; i < k; i++) {
357 free(encoded_data[i]);
358 }
359
360 free(encoded_data);
361 }
362
363 if (encoded_parity) {
364 for (i = 0; i < m; i++) {
365 free(encoded_parity[i]);
366 }
367 free(encoded_parity);
368 }
369
370 return 0;
371}
372
390 const char *orig_data, uint64_t orig_data_size, /* input */
391 char ***encoded_data, char ***encoded_parity, /* output */
392 uint64_t *fragment_len) /* output */
393{
394 int k, m;
395 int ret = 0; /* return code */
396
397 int blocksize = 0; /* length of each of k data elements */
398
399 if (orig_data == NULL) {
400 log_error("Pointer to data buffer is null!");
401 ret = -EINVALIDPARAMS;
402 goto out;
403 }
404
405 if (encoded_data == NULL) {
406 log_error("Pointer to encoded data buffers is null!");
407 return -EINVALIDPARAMS;
408 }
409
410 if (encoded_parity == NULL) {
411 log_error("Pointer to encoded parity buffers is null!");
412 return -EINVALIDPARAMS;
413 }
414
415 if (fragment_len == NULL) {
416 log_error("Pointer to fragment length is null!");
417 ret = -EINVALIDPARAMS;
418 goto out;
419 }
420
421 int rc = rwlock_rdlock(&active_instances_rwlock);
422 if (rc != 0) {
423 /* Should just be EDEADLOCK */
424 ret = rc < 0 ? rc : -rc;
425 goto out;
426 }
427 ec_backend_t instance = liberasurecode_backend_instance_get_by_desc(desc);
428 if (NULL == instance) {
429 ret = -EBACKENDNOTAVAIL;
430 goto unlock;
431 }
432
433 k = instance->args.uargs.k;
434 m = instance->args.uargs.m;
435
436 /*
437 * Allocate arrays for data, parity and missing_idxs
438 */
439 *encoded_data = (char **) alloc_zeroed_buffer(sizeof(char *) * k);
440 if (NULL == *encoded_data) {
441 log_error("Could not allocate data buffer!");
442 goto unlock;
443 }
444
445 *encoded_parity = (char **) alloc_zeroed_buffer(sizeof(char *) * m);
446 if (NULL == *encoded_parity) {
447 log_error("Could not allocate parity buffer!");
448 goto unlock;
449 }
450
451 ret = prepare_fragments_for_encode(instance, k, m, orig_data, orig_data_size,
452 *encoded_data, *encoded_parity, &blocksize);
453 if (ret < 0) {
454 // ensure encoded_data/parity point the head of fragment_ptr
455 get_fragment_ptr_array_from_data(*encoded_data, *encoded_data, k);
456 get_fragment_ptr_array_from_data(*encoded_parity, *encoded_parity, m);
457 goto unlock;
458 }
459
460 /* call the backend encode function passing it desc instance */
461 ret = instance->common.ops->encode(instance->desc.backend_desc,
462 *encoded_data, *encoded_parity, blocksize);
463 if (ret < 0) {
464 // ensure encoded_data/parity point the head of fragment_ptr
465 get_fragment_ptr_array_from_data(*encoded_data, *encoded_data, k);
466 get_fragment_ptr_array_from_data(*encoded_parity, *encoded_parity, m);
467 goto unlock;
468 }
469
470 ret = finalize_fragments_after_encode(instance, k, m, blocksize, orig_data_size,
471 *encoded_data, *encoded_parity);
472
473 *fragment_len = get_fragment_size((*encoded_data)[0]);
474
475unlock:
476 rwlock_unlock(&active_instances_rwlock);
477out:
478 if (ret) {
479 /* Cleanup the allocations we have done */
480 liberasurecode_encode_cleanup(desc, *encoded_data, *encoded_parity);
481 log_error("Error in liberasurecode_encode %d", ret);
482 }
483 return ret;
484}
485
499int liberasurecode_decode_cleanup(int desc, char *data)
500{
501 int rc = rwlock_rdlock(&active_instances_rwlock);
502 if (rc) {
503 /* Should just be EDEADLOCK */
504 return rc;
505 }
506 ec_backend_t instance = liberasurecode_backend_instance_get_by_desc(desc);
507 rwlock_unlock(&active_instances_rwlock);
508 if (NULL == instance) {
509 return -EBACKENDNOTAVAIL;
510 }
511
512 free(data);
513
514 return 0;
515}
516
531 char **available_fragments, /* input */
532 int num_fragments, uint64_t fragment_len, /* input */
533 int force_metadata_checks, /* input */
534 char **out_data, uint64_t *out_data_len) /* output */
535{
536 int i, j;
537 int ret = 0;
538
539 int k = -1, m = -1;
540 int orig_data_size = 0;
541
542 int blocksize = 0;
543 char **data = NULL;
544 char **parity = NULL;
545 char **data_segments = NULL;
546 char **parity_segments = NULL;
547 int *missing_idxs = NULL;
548
549 struct ec_bm realloc_bm = NEW_BM;
550
551 int rc = rwlock_rdlock(&active_instances_rwlock);
552 if (rc) {
553 /* Should just be EDEADLOCK */
554 return rc;
555 }
556 ec_backend_t instance = liberasurecode_backend_instance_get_by_desc(desc);
557 if (NULL == instance) {
558 ret = -EBACKENDNOTAVAIL;
559 goto out;
560 }
561
562 if (NULL == available_fragments) {
563 log_error("Pointer to encoded fragments buffer is null!");
564 ret = -EINVALIDPARAMS;
565 goto out;
566 }
567
568 if (NULL == out_data) {
569 log_error("Pointer to decoded data buffer is null!");
570 ret = -EINVALIDPARAMS;
571 goto out;
572 }
573
574 if (NULL == out_data_len) {
575 log_error("Pointer to decoded data length variable is null!");
576 ret = -EINVALIDPARAMS;
577 goto out;
578 }
579
580 k = instance->args.uargs.k;
581 m = instance->args.uargs.m;
582
583 if (num_fragments < k) {
584 log_error("Not enough fragments to decode, got %d, need %d!",
585 num_fragments, k);
586 ret = -EINSUFFFRAGS;
587 goto out;
588 }
589
590 if (fragment_len < sizeof(fragment_header_t)) {
591 log_error("Fragments not long enough to include headers! "
592 "Need %zu, but got %lu.", sizeof(fragment_header_t),
593 (unsigned long)fragment_len);
594 ret = -EBADHEADER;
595 goto out;
596 }
597 for (i = 0; i < num_fragments; ++i) {
598 /* Verify metadata checksum */
600 (fragment_header_t *) available_fragments[i])) {
601 log_error("Invalid fragment header information!");
602 ret = -EBADHEADER;
603 goto out;
604 }
605 }
606
607 if (instance->common.ops->is_systematic) {
608 /*
609 * Try to re-assebmle the original data before attempting a decode
610 */
611 ret = fragments_to_string(k, m,
612 available_fragments, num_fragments,
613 out_data, out_data_len);
614
615 if (ret == 0) {
616 /* We were able to get the original data without decoding! */
617 goto out;
618 }
619 }
620
621 /*
622 * Allocate arrays for data, parity and missing_idxs
623 */
624 data = alloc_zeroed_buffer(sizeof(char*) * k);
625 if (NULL == data) {
626 log_error("Could not allocate data buffer!");
627 goto out;
628 }
629
630 parity = alloc_zeroed_buffer(sizeof(char*) * m);
631 if (NULL == parity) {
632 log_error("Could not allocate parity buffer!");
633 goto out;
634 }
635
636 missing_idxs = alloc_and_set_buffer(sizeof(char*) * (k + m), -1);
637 if (NULL == missing_idxs) {
638 log_error("Could not allocate missing_idxs buffer!");
639 goto out;
640 }
641
642 /* If metadata checks requested, check fragment integrity upfront */
643 if (force_metadata_checks) {
644 int num_invalid_fragments = 0;
645 for (i = 0; i < num_fragments; ++i) {
646 if (is_invalid_fragment(desc, available_fragments[i])) {
647 ++num_invalid_fragments;
648 }
649 }
650 if ((num_fragments - num_invalid_fragments) < k) {
651 ret = -EINSUFFFRAGS;
652 log_error("Not enough valid fragments available for decode!");
653 goto out;
654 }
655 }
656
657 /*
658 * Separate the fragments into data and parity. Also determine which
659 * pieces are missing.
660 */
661 ret = get_fragment_partition(k, m, available_fragments, num_fragments,
662 data, parity, missing_idxs);
663
664 if (ret < 0) {
665 log_error("Could not properly partition the fragments!");
666 goto out;
667 }
668
669 /*
670 * Preparing the fragments for decode. This will alloc aligned buffers
671 * when unaligned buffers were passed in available_fragments. It passes
672 * back a bitmap telling us which buffers need to be freed by us
673 * (realloc_bm).
674 *
675 */
676 ret = prepare_fragments_for_decode(k, m,
677 data, parity, missing_idxs,
678 &orig_data_size, &blocksize,
679 fragment_len, &realloc_bm);
680 if (ret < 0) {
681 log_error("Could not prepare fragments for decode!");
682 goto out;
683 }
684
685 data_segments = alloc_zeroed_buffer(k * sizeof(char *));
686 parity_segments = alloc_zeroed_buffer(m * sizeof(char *));
687 get_data_ptr_array_from_fragments(data_segments, data, k);
688 get_data_ptr_array_from_fragments(parity_segments, parity, m);
689
690 /* call the backend decode function passing it desc instance */
691 ret = instance->common.ops->decode(instance->desc.backend_desc,
692 data_segments, parity_segments,
693 missing_idxs, blocksize);
694
695 if (ret < 0) {
696 log_error("Encountered error in backend decode function!");
697 goto out;
698 }
699
700 /*
701 * Need to fill in the missing data headers so we can generate
702 * the original string.
703 */
704 j = 0;
705 while (missing_idxs[j] >= 0) {
706 int set_chksum = 1;
707 int missing_idx = missing_idxs[j];
708 if (missing_idx < k) {
709 /* Generate headers */
710 char *fragment_ptr = data[missing_idx];
711 init_fragment_header(fragment_ptr);
712 add_fragment_metadata(instance, fragment_ptr, missing_idx,
713 orig_data_size, blocksize, instance->args.uargs.ct,
714 !set_chksum);
715 }
716 j++;
717 }
718
719 /* Try to generate the original string */
720 ret = fragments_to_string(k, m, data, k, out_data, out_data_len);
721
722 if (ret < 0) {
723 log_error("Could not convert decoded fragments to a string!");
724 }
725
726out:
727 rwlock_unlock(&active_instances_rwlock);
728 /* Free the buffers allocated in prepare_fragments_for_decode */
729 if (bm_any(&realloc_bm)) {
730 for (i = 0; i < k; i++) {
731 if (bm_get_value(&realloc_bm, i)) {
732 free(data[i]);
733 }
734 }
735
736 for (i = 0; i < m; i++) {
737 if (bm_get_value(&realloc_bm, i + k)) {
738 free(parity[i]);
739 }
740 }
741 }
742
743 free(data);
744 free(parity);
745 free(missing_idxs);
746 free(data_segments);
747 free(parity_segments);
748
749 return ret;
750}
751
765 char **available_fragments, /* input */
766 int num_fragments, uint64_t fragment_len, /* input */
767 int destination_idx, /* input */
768 char* out_fragment) /* output */
769{
770 int ret = 0;
771 int blocksize = 0;
772 int orig_data_size = 0;
773 char **data = NULL;
774 char **parity = NULL;
775 int *missing_idxs = NULL;
776 char *fragment_ptr = NULL;
777 int is_destination_missing = 0;
778 int k = -1;
779 int m = -1;
780 int i;
781 struct ec_bm realloc_bm = NEW_BM;
782 char **data_segments = NULL;
783 char **parity_segments = NULL;
784 int set_chksum = 1;
785
786 int rc = rwlock_rdlock(&active_instances_rwlock);
787 if (rc) {
788 /* Should just be EDEADLOCK */
789 return rc;
790 }
791 ec_backend_t instance = liberasurecode_backend_instance_get_by_desc(desc);
792 if (NULL == instance) {
793 ret = -EBACKENDNOTAVAIL;
794 goto out;
795 }
796
797 if (NULL == available_fragments) {
798 log_error("Can not reconstruct fragment, available fragments pointer is NULL");
799 ret = -EINVALIDPARAMS;
800 goto out;
801 }
802
803 if (NULL == out_fragment) {
804 log_error("Can not reconstruct fragment, output fragment pointer is NULL");
805 ret = -EINVALIDPARAMS;
806 goto out;
807 }
808
809 k = instance->args.uargs.k;
810 m = instance->args.uargs.m;
811
812 for (i = 0; i < num_fragments; i++) {
813 /* Verify metadata checksum */
815 (fragment_header_t *) available_fragments[i])) {
816 log_error("Invalid fragment header information!");
817 ret = -EBADHEADER;
818 goto out;
819 }
820 }
821
822 /*
823 * Allocate arrays for data, parity and missing_idxs
824 */
825 data = alloc_zeroed_buffer(sizeof(char*) * k);
826 if (NULL == data) {
827 log_error("Could not allocate data buffer!");
828 ret = -ENOMEM;
829 goto out;
830 }
831
832 parity = alloc_zeroed_buffer(sizeof(char*) * m);
833 if (NULL == parity) {
834 log_error("Could not allocate parity buffer!");
835 ret = -ENOMEM;
836 goto out;
837 }
838
839 missing_idxs = alloc_and_set_buffer(sizeof(int*) * (k + m), -1);
840 if (NULL == missing_idxs) {
841 log_error("Could not allocate missing_idxs buffer!");
842 ret = -ENOMEM;
843 goto out;
844 }
845
846 /*
847 * Separate the fragments into data and parity. Also determine which
848 * pieces are missing.
849 */
850 ret = get_fragment_partition(k, m, available_fragments, num_fragments,
851 data, parity, missing_idxs);
852
853 if (ret < 0) {
854 log_error("Could not properly partition the fragments!");
855 goto out;
856 }
857
858 /*
859 * Odd corner-case: If the caller passes in a destination_idx that
860 * is also included in the available fragments list, we should *not*
861 * try to reconstruct.
862 *
863 * For now, we will log a warning and do nothing. In the future, we
864 * should probably log and return an error.
865 *
866 */
867 i = 0;
868 while (missing_idxs[i] > -1) {
869 if (missing_idxs[i] == destination_idx) {
870 is_destination_missing = 1;
871 }
872 i++;
873 }
874
875 if (!is_destination_missing) {
876 if (destination_idx < k) {
877 fragment_ptr = data[destination_idx];
878 } else {
879 fragment_ptr = parity[destination_idx - k];
880 }
881 log_warn("Dest idx for reconstruction was supplied as available buffer!");
882 goto destination_available;
883 }
884
885 if (instance->common.ops->check_reconstruct_fragments == NULL) {
886 if (num_fragments < k) {
887 ret = -EINSUFFFRAGS;
888 goto out;
889 }
890 } else {
891 ret = instance->common.ops->check_reconstruct_fragments(
892 instance->desc.backend_desc,
893 missing_idxs,
894 destination_idx
895 );
896 if (ret < 0) {
897 goto out;
898 }
899 }
900
901 /*
902 * Preparing the fragments for reconstruction. This will alloc aligned
903 * buffers when unaligned buffers were passed in available_fragments.
904 * It passes back a bitmap telling us which buffers need to be freed by
905 * us (realloc_bm).
906 */
907 ret = prepare_fragments_for_decode(k, m, data, parity, missing_idxs,
908 &orig_data_size, &blocksize,
909 fragment_len, &realloc_bm);
910 if (ret < 0) {
911 log_error("Could not prepare fragments for reconstruction!");
912 goto out;
913 }
914 data_segments = alloc_zeroed_buffer(k * sizeof(char *));
915 parity_segments = alloc_zeroed_buffer(m * sizeof(char *));
916 get_data_ptr_array_from_fragments(data_segments, data, k);
917 get_data_ptr_array_from_fragments(parity_segments, parity, m);
918
919
920 /* call the backend reconstruct function passing it desc instance */
921 ret = instance->common.ops->reconstruct(instance->desc.backend_desc,
922 data_segments, parity_segments,
923 missing_idxs, destination_idx,
924 blocksize);
925 if (ret < 0) {
926 log_error("Could not reconstruct fragment!");
927 goto out;
928 }
929
930 /*
931 * Update the header to reflect the newly constructed fragment
932 */
933 if (destination_idx < k) {
934 fragment_ptr = data[destination_idx];
935 } else {
936 fragment_ptr = parity[destination_idx - k];
937 }
938 init_fragment_header(fragment_ptr);
939 add_fragment_metadata(instance, fragment_ptr, destination_idx,
940 orig_data_size, blocksize, instance->args.uargs.ct,
941 set_chksum);
942
943destination_available:
944 /*
945 * Copy the reconstructed fragment to the output buffer
946 *
947 * Note: the address stored in fragment_ptr will be freed below
948 */
949 memcpy(out_fragment, fragment_ptr, fragment_len);
950
951out:
952 rwlock_unlock(&active_instances_rwlock);
953 /* Free the buffers allocated in prepare_fragments_for_decode */
954 if (bm_any(&realloc_bm)) {
955 for (i = 0; i < k; i++) {
956 if (bm_get_value(&realloc_bm, i)) {
957 free(data[i]);
958 }
959 }
960
961 for (i = 0; i < m; i++) {
962 if (bm_get_value(&realloc_bm, i + k)) {
963 free(parity[i]);
964 }
965 }
966 }
967
968 free(data);
969 free(parity);
970 free(missing_idxs);
971 free(data_segments);
972 free(parity_segments);
973
974 return ret;
975}
976
992 int *fragments_to_reconstruct,
993 int *fragments_to_exclude,
994 int *fragments_needed)
995{
996 int ret = 0;
997
998 int rc = rwlock_rdlock(&active_instances_rwlock);
999 if (rc) {
1000 /* Should just be EDEADLOCK */
1001 return rc;
1002 }
1003 ec_backend_t instance = liberasurecode_backend_instance_get_by_desc(desc);
1004 if (NULL == instance) {
1005 ret = -EBACKENDNOTAVAIL;
1006 goto out_error;
1007 }
1008 if (NULL == fragments_to_reconstruct) {
1009 log_error("Unable to determine list of fragments needed, pointer to list of indexes to reconstruct is NULL.");
1010 ret = -EINVALIDPARAMS;
1011 goto out_error;
1012 }
1013
1014 if (NULL == fragments_to_exclude) {
1015 log_error("Unable to determine list of fragments needed, pointer to list of fragments to exclude is NULL.");
1016 ret = -EINVALIDPARAMS;
1017 goto out_error;
1018 }
1019
1020 if (NULL == fragments_needed) {
1021 log_error("Unable to determine list of fragments needed, pointer to list of fragments to reconstruct is NULL.");
1022 ret = -EINVALIDPARAMS;
1023 goto out_error;
1024 }
1025
1026 /* FIXME preprocessing */
1027
1028 /* call the backend fragments_needed function passing it desc instance */
1029 ret = instance->common.ops->fragments_needed(
1030 instance->desc.backend_desc,
1031 fragments_to_reconstruct, fragments_to_exclude, fragments_needed);
1032
1033out_error:
1034 rwlock_unlock(&active_instances_rwlock);
1035 return ret;
1036}
1037
1038/* =~=*=~==~=*=~==~=*=~==~=*=~===~=*=~==~=*=~===~=*=~==~=*=~===~=*=~==~=*=~= */
1039
1051 fragment_metadata_t *fragment_metadata)
1052{
1053 int ret = 0;
1054 fragment_header_t *fragment_hdr = NULL;
1055
1056 if (NULL == fragment) {
1057 log_error("Need valid fragment object to get metadata for");
1058 ret = -EINVALIDPARAMS;
1059 goto out;
1060 }
1061
1062 if (NULL == fragment_metadata) {
1063 log_error("Need valid fragment_metadata object for return value");
1064 ret = -EINVALIDPARAMS;
1065 goto out;
1066 }
1067
1068 /* Verify metadata checksum */
1069 if (is_invalid_fragment_header((fragment_header_t *) fragment)) {
1070 log_error("Invalid fragment header information!");
1071 ret = -EBADHEADER;
1072 goto out;
1073 }
1074
1075 memcpy(fragment_metadata, fragment, sizeof(struct fragment_metadata));
1076 fragment_hdr = (fragment_header_t *) fragment;
1077 if (LIBERASURECODE_FRAG_HEADER_MAGIC != fragment_hdr->magic) {
1078 if (LIBERASURECODE_FRAG_HEADER_MAGIC != bswap_32(fragment_hdr->magic)) {
1079 log_error("Invalid fragment, illegal magic value");
1080 ret = -EINVALIDPARAMS;
1081 goto out;
1082 } else {
1083 // Must've written this on an opposite-endian architecture.
1084 // Fix it in fragment_metadata
1085 fragment_metadata->idx = bswap_32(fragment_metadata->idx);
1086 fragment_metadata->size = bswap_32(fragment_metadata->size);
1087 fragment_metadata->frag_backend_metadata_size =
1088 bswap_32(fragment_metadata->frag_backend_metadata_size);
1089 fragment_metadata->orig_data_size =
1090 bswap_64(fragment_metadata->orig_data_size);
1091 fragment_metadata->chksum_type =
1092 bswap_32(fragment_metadata->chksum_type);
1093 for (int i = 0; i < LIBERASURECODE_MAX_CHECKSUM_LEN; i++) {
1094 fragment_metadata->chksum[i] =
1095 bswap_32(fragment_metadata->chksum[i]);
1096 }
1097 fragment_metadata->backend_version =
1098 bswap_32(fragment_metadata->backend_version);
1099 }
1100 }
1101
1102 switch(fragment_metadata->chksum_type) {
1103 case CHKSUM_CRC32: {
1104 uint32_t computed_chksum = 0;
1105 uint32_t stored_chksum = fragment_metadata->chksum[0];
1106 char *fragment_data = get_data_ptr_from_fragment(fragment);
1107 uint64_t fragment_size = fragment_metadata->size;
1108 computed_chksum = crc32(0, (unsigned char *) fragment_data, fragment_size);
1109 if (stored_chksum != computed_chksum) {
1110 // Try again with our "alternative" crc32; see
1111 // https://bugs.launchpad.net/liberasurecode/+bug/1666320
1112 computed_chksum = liberasurecode_crc32_alt(
1113 0, fragment_data, fragment_size);
1114 if (stored_chksum != computed_chksum) {
1115 fragment_metadata->chksum_mismatch = 1;
1116 } else {
1117 fragment_metadata->chksum_mismatch = 0;
1118 }
1119 } else {
1120 fragment_metadata->chksum_mismatch = 0;
1121 }
1122 break;
1123 }
1124 case CHKSUM_MD5:
1125 break;
1126 case CHKSUM_NONE:
1127 default:
1128 break;
1129 }
1130
1131out:
1132 return ret;
1133}
1134
1135int is_invalid_fragment_header(fragment_header_t *header)
1136{
1137 uint32_t csum = 0, metadata_chksum = 0, libec_version = 0;
1138 assert (NULL != header);
1139 if (header->libec_version == 0)
1140 /* libec_version must be bigger than 0 */
1141 return 1;
1142 metadata_chksum = header->metadata_chksum;
1143 libec_version = header->libec_version;
1144 if (header->magic != LIBERASURECODE_FRAG_HEADER_MAGIC) {
1145 if (bswap_32(header->magic) != LIBERASURECODE_FRAG_HEADER_MAGIC) {
1146 log_error("Invalid fragment header (get meta chksum)!");
1147 return 1;
1148 } else {
1149 // Must've written this on an opposite-endian architecture.
1150 // Fix our reference checksum and version, but *don't touch
1151 // the header data yet*. Leave that for when we're extracting
1152 // in liberasurecode_get_fragment_metadata
1153 metadata_chksum = bswap_32(metadata_chksum);
1154 libec_version = bswap_32(libec_version);
1155 }
1156 }
1157
1158 if (libec_version < _VERSION(1,2,0))
1159 /* no metadata checksum support */
1160 return 0;
1161
1162 csum = crc32(0, (unsigned char *) &header->meta, sizeof(fragment_metadata_t));
1163 if (metadata_chksum == csum) {
1164 return 0;
1165 }
1166 // Else, try again with our "alternative" crc32; see
1167 // https://bugs.launchpad.net/liberasurecode/+bug/1666320
1168 csum = liberasurecode_crc32_alt(0, &header->meta, sizeof(fragment_metadata_t));
1169 return (metadata_chksum != csum);
1170}
1171
1173 fragment_metadata_t *md)
1174{
1175 int k = be->args.uargs.k;
1176 int m = be->args.uargs.m;
1177 if (md->idx >= (k + m)) {
1178 return 1;
1179 }
1180 if (md->backend_id != be->common.id) {
1181 return 1;
1182 }
1183 if (!be->common.ops->is_compatible_with(md->backend_version)) {
1184 return 1;
1185 }
1186 return 0;
1187}
1188
1189static int is_invalid_fragment_metadata(int desc, fragment_metadata_t *fragment_metadata)
1190{
1191 int ret = 0;
1192 int rc = rwlock_rdlock(&active_instances_rwlock);
1193 if (rc) {
1194 /* Should just be EDEADLOCK */
1195 return rc;
1196 }
1197 ec_backend_t be = liberasurecode_backend_instance_get_by_desc(desc);
1198 if (!be) {
1199 log_error("Unable to verify fragment metadata: invalid backend id %d.",
1200 desc);
1201 ret = -EINVALIDPARAMS;
1202 goto out;
1203 }
1205 fragment_metadata) != 0) {
1206 ret = -EBADHEADER;
1207 goto out;
1208 }
1209 if (!be->common.ops->is_compatible_with(fragment_metadata->backend_version)) {
1210 ret = -EBADHEADER;
1211 goto out;
1212 }
1213 if (fragment_metadata->chksum_mismatch == 1) {
1214 ret = -EBADCHKSUM;
1215 goto out;
1216 }
1217out:
1218 rwlock_unlock(&active_instances_rwlock);
1219 return ret;
1220}
1221
1222int is_invalid_fragment(int desc, char *fragment)
1223{
1224 int ret = 0;
1225 uint32_t ver = 0;
1226 fragment_metadata_t fragment_metadata;
1227 int rc = rwlock_rdlock(&active_instances_rwlock);
1228 if (rc) {
1229 /* Should just be EDEADLOCK */
1230 return rc;
1231 }
1232 ec_backend_t be = liberasurecode_backend_instance_get_by_desc(desc);
1233 if (!be) {
1234 log_error("Unable to verify fragment metadata: invalid backend id %d.",
1235 desc);
1236 ret = 1;
1237 goto out;
1238 }
1239 if (!fragment) {
1240 log_error("Unable to verify fragment validity: fragments missing.");
1241 ret = 1;
1242 goto out;
1243 }
1244 if (get_libec_version(fragment, &ver) != 0 ||
1245 ver > LIBERASURECODE_VERSION) {
1246 ret = 1;
1247 goto out;
1248 }
1249 if (liberasurecode_get_fragment_metadata(fragment, &fragment_metadata) != 0) {
1250 ret = 1;
1251 goto out;
1252 }
1253 if (is_invalid_fragment_metadata(desc, &fragment_metadata) != 0) {
1254 ret = 1;
1255 goto out;
1256 }
1257out:
1258 rwlock_unlock(&active_instances_rwlock);
1259 return ret;
1260}
1261
1263 char **fragments, int num_fragments)
1264{
1265 int i = 0;
1266 if (!fragments) {
1267 log_error("Unable to verify stripe metadata: fragments missing.");
1268 return -EINVALIDPARAMS;
1269 }
1270 if (num_fragments <= 0) {
1271 log_error("Unable to verify stripe metadata: "
1272 "number of fragments must be greater than 0.");
1273 return -EINVALIDPARAMS;
1274 }
1275
1276 int ret = 0;
1277 int rc = rwlock_rdlock(&active_instances_rwlock);
1278 if (rc) {
1279 /* Should just be EDEADLOCK */
1280 return rc;
1281 }
1282 for (i = 0; i < num_fragments; i++) {
1283 fragment_metadata_t *fragment_metadata = (fragment_metadata_t*)fragments[i];
1284 ret = is_invalid_fragment_metadata(desc, fragment_metadata);
1285 if (ret < 0) {
1286 goto out;
1287 }
1288 }
1289out:
1290 rwlock_unlock(&active_instances_rwlock);
1291 return ret;
1292}
1293
1294/* =~=*=~==~=*=~==~=*=~==~=*=~===~=*=~==~=*=~===~=*=~==~=*=~===~=*=~==~=*=~= */
1295
1303int liberasurecode_get_aligned_data_size(int desc, uint64_t data_len)
1304{
1305 int k;
1306 int ret = 0;
1307 int word_size;
1308 int alignment_multiple;
1309
1310 int rc = rwlock_rdlock(&active_instances_rwlock);
1311 if (rc) {
1312 /* Should just be EDEADLOCK */
1313 return rc < 0 ? rc : -rc;
1314 }
1315 ec_backend_t instance = liberasurecode_backend_instance_get_by_desc(desc);
1316 if (NULL == instance) {
1317 ret = -EBACKENDNOTAVAIL;
1318 goto out;
1319 }
1320
1321 k = instance->args.uargs.k;
1322
1323 word_size = instance->common.ops->element_size(
1324 instance->desc.backend_desc) / 8;
1325
1326 alignment_multiple = k * word_size;
1327
1328 ret = ((data_len + alignment_multiple - 1) / alignment_multiple)
1329 * alignment_multiple;
1330
1331out:
1332 rwlock_unlock(&active_instances_rwlock);
1333 return ret;
1334}
1335
1341{
1343}
1344
1345int liberasurecode_get_fragment_size(int desc, int data_len)
1346{
1347 int rc = rwlock_rdlock(&active_instances_rwlock);
1348 if (rc) {
1349 /* Should just be EDEADLOCK */
1350 return rc < 0 ? rc : -rc;
1351 }
1352 ec_backend_t instance = liberasurecode_backend_instance_get_by_desc(desc);
1353 // TODO: Create a common function to calculate fragment size also for preprocessing
1354 if (NULL == instance) {
1355 rwlock_unlock(&active_instances_rwlock);
1356 return -EBACKENDNOTAVAIL;
1357 }
1358 int aligned_data_len = get_aligned_data_size(instance, data_len);
1359 int blocksize = aligned_data_len / instance->args.uargs.k;
1360 int metadata_size = instance->common.ops->get_backend_metadata_size(
1361 instance->desc.backend_desc,
1362 blocksize);
1363 int size = blocksize + metadata_size;
1364
1365 rwlock_unlock(&active_instances_rwlock);
1366 return size;
1367}
1368
1369
1375{
1376 return LIBERASURECODE_VERSION;
1377}
1378
1379/* ==~=*=~==~=*=~==~=*=~==~=*=~==~=* misc *=~==~=*=~==~=*=~==~=*=~==~=*=~== */
1380
1381#if 0
1382/* Validate backend before calling init */
1383int liberasurecode_backend_validate(ec_backend_t backend)
1384{
1385 /* Verify that the backend implements all required methods */
1386}
1387
1388/* FIXME - do we need to use reference counts if we are creating
1389* a new instance per user */
1390
1391/* Get a reference to an EC backend */
1392ec_backend_t liberasurecode_backend_get(const char *name)
1393{
1394 ec_backend_t b = liberasurecode_backend_lookup_by_name(name);
1395 if (NULL != b)
1396 ++b->users;
1397 return b;
1398}
1399
1400/* Drop an EC backend reference held */
1401void liberasurecode_backend_put(ec_backend_t backend)
1402{
1403 if (backend->users > 0)
1404 --backend->users;
1405}
1406
1407/* Query interface for active instances */
1408ec_backend_t liberasurecode_backend_instance_active(ec_backend_t instance)
1409{
1410 ec_backend_t b;
1411
1412 SLIST_FOREACH(b, &active_instances, link) {
1413 if (strcmp(b->name, name) == 0)
1414 return b;
1415 }
1416
1417 return NULL;
1418}
1419
1420ec_backend_t liberasurecode_backend_lookup_by_soname(const char *soname)
1421{
1422 ec_backend_t b;
1423
1424 SLIST_FOREACH(b, &active_instances, link) {
1425 if (strcmp(b->soname, soname) == 0)
1426 return b;
1427 }
1428
1429 return NULL;
1430}
1431#endif
1432
1433/* ==~=*=~==~=*=~==~=*=~==~=*=~==~=*=~==~=*=~==~=*=~==~=*=~==~=*=~==~=*=~== */
int liberasurecode_crc32_alt(int crc, const void *buf, size_t size)
Definition: crc32.c:92
int liberasurecode_verify_fragment_metadata(ec_backend_t be, fragment_metadata_t *md)
Definition: erasurecode.c:1172
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.
Definition: erasurecode.c:530
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.
Definition: erasurecode.c:389
int is_invalid_fragment_header(fragment_header_t *header)
Definition: erasurecode.c:1135
struct ec_backend_common backend_flat_xor_hd
Definition: flat_xor_hd.c:50
static void print_dlerror(const char *caller)
Definition: erasurecode.c:125
int liberasurecode_decode_cleanup(int desc, char *data)
Cleanup structures allocated by librasurecode_decode.
Definition: erasurecode.c:499
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.
Definition: erasurecode.c:991
struct ec_backend_common backend_null
struct ec_backend_common backend_shss
Definition: shss.c:41
static int liberasurecode_backend_close(ec_backend_t instance)
Definition: erasurecode.c:143
struct ec_backend_common backend_isa_l_rs_vand
Definition: isa_l_rs_vand.c:46
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,...
Definition: erasurecode.c:211
struct ec_backend_common backend_liberasurecode_rs_vand
struct ec_backend_common backend_isa_l_rs_cauchy
static ec_backend_t ec_backends_supported[]
Definition: erasurecode.c:58
int liberasurecode_get_fragment_metadata(char *fragment, fragment_metadata_t *fragment_metadata)
Get opaque metadata for a fragment.
Definition: erasurecode.c:1050
struct ec_backend_common backend_isa_l_rs_lrc
Definition: isa_l_rs_lrc.c:46
static int is_invalid_fragment_metadata(int desc, fragment_metadata_t *fragment_metadata)
Definition: erasurecode.c:1189
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.
Definition: erasurecode.c:1340
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.
Definition: erasurecode.c:1303
int is_invalid_fragment(int desc, char *fragment)
Definition: erasurecode.c:1222
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.
Definition: erasurecode.c:764
int liberasurecode_verify_stripe_metadata(int desc, char **fragments, int num_fragments)
Definition: erasurecode.c:1262
struct ec_backend_common backend_libphazr
Definition: libphazr.c:48
static void * liberasurecode_backend_open(ec_backend_t instance)
Definition: erasurecode.c:135
struct ec_backend_common backend_isa_l_rs_vand_inv
int liberasurecode_encode_cleanup(int desc, char **encoded_data, char **encoded_parity)
Cleanup structures allocated by librasurecode_encode.
Definition: erasurecode.c:334
static int liberasurecode_backend_alloc_desc(void)
Allocated backend instance descriptor.
Definition: erasurecode.c:113
int liberasurecode_backend_available(const ec_backend_id_t backend_id)
Checks if a given backend is available.
Definition: erasurecode.c:177
struct ec_backend_common backend_jerasure_rs_cauchy
int liberasurecode_instance_destroy(int desc)
Close a liberasurecode instance.
Definition: erasurecode.c:292
static SLIST_HEAD(backend_list, ec_backend)
Look up a backend instance by descriptor.
Definition: erasurecode.c:76
struct ec_backend_common backend_jerasure_rs_vand
int liberasurecode_get_fragment_size(int desc, int data_len)
Definition: erasurecode.c:1345
uint32_t liberasurecode_get_version(void)
This will return the liberasurecode version for the descriptor.
Definition: erasurecode.c:1374
void __attribute__((constructor))
Definition: erasurecode.c:157
void * alloc_and_set_buffer(int size, int value)
Allocate a buffer of a specific size and set its' contents to the specified value.
char * get_data_ptr_from_fragment(char *buf)
int get_libec_version(char *buf, uint32_t *ver)
int get_fragment_partition(int k, int m, char **fragments, int num_fragments, char **data, char **parity, int *missing)