1 /*
2  * Copyright 2014 Tushar Gohad, Kevin M Greenan, Eric Lambert
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 helpers implementation
25  *
26  * vi: set noai tw=79 ts=4 sw=4:
27  */
28 #include <assert.h>
29 #include <stdio.h>
30 #include <stdarg.h>
31 #include "erasurecode_backend.h"
32 #include "erasurecode_helpers.h"
33 #include "erasurecode_helpers_ext.h"
34 #include "erasurecode_stdinc.h"
35 #include "erasurecode_version.h"
36 
37 #include "alg_sig.h"
38 #include "erasurecode_log.h"
39 
40 /* ==~=*=~==~=*=~==~=*=~==~=*=~==~=*=~==~=*=~==~=*=~==~=*=~==~=*=~==~=*=~== */
41 
is_fragment(char * buf)42 static bool is_fragment(char *buf)
43 {
44     fragment_header_t *header = (fragment_header_t *) buf;
45 
46     assert(NULL != header);
47     if (header->magic == LIBERASURECODE_FRAG_HEADER_MAGIC) {
48         return true;
49     }
50 
51     return false;
52 }
53 
54 /**
55  * Memory Management Methods
56  *
57  * The following methods provide wrappers for allocating and deallocating
58  * memory.
59  */
get_aligned_buffer16(int size)60 void *get_aligned_buffer16(int size)
61 {
62     void *buf;
63 
64     /**
65      * Ensure all memory is aligned to 16-byte boundaries
66      * to support 128-bit operations
67      */
68     if (posix_memalign(&buf, 16, size) != 0) {
69         return NULL;
70     }
71 
72     memset(buf, 0, size);
73 
74     return buf;
75 }
76 
77 /**
78  * Allocate a zero-ed buffer of a specific size.
79  *
80  * @param size integer size in bytes of buffer to allocate
81  * @return pointer to start of allocated buffer or NULL on error
82  */
alloc_zeroed_buffer(int size)83 void * alloc_zeroed_buffer(int size)
84 {
85     return alloc_and_set_buffer(size, 0);
86 }
87 
88 /**
89  * Allocate a buffer of a specific size and set its' contents
90  * to the specified value.
91  *
92  * @param size integer size in bytes of buffer to allocate
93  * @param value
94  * @return pointer to start of allocated buffer or NULL on error
95  */
alloc_and_set_buffer(int size,int value)96 void * alloc_and_set_buffer(int size, int value) {
97     void * buf = NULL;  /* buffer to allocate and return */
98 
99     /* Allocate and zero the buffer, or set the appropriate error */
100     buf = malloc((size_t) size);
101     if (buf) {
102         buf = memset(buf, value, (size_t) size);
103     }
104     return buf;
105 }
106 
107 /**
108  * Deallocate memory buffer if it's not NULL.  This methods returns NULL so
109  * that you can free and reset a buffer using a single line as follows:
110  *
111  * my_ptr = check_and_free_buffer(my_ptr);
112  *
113  * @return NULL
114  */
check_and_free_buffer(void * buf)115 void * check_and_free_buffer(void * buf)
116 {
117     if (buf)
118         free(buf);
119     return NULL;
120 }
121 
alloc_fragment_buffer(int size)122 char *alloc_fragment_buffer(int size)
123 {
124     char *buf;
125     fragment_header_t *header = NULL;
126 
127     size += sizeof(fragment_header_t);
128     buf = get_aligned_buffer16(size);
129 
130     if (buf) {
131         header = (fragment_header_t *) buf;
132         header->magic = LIBERASURECODE_FRAG_HEADER_MAGIC;
133     }
134 
135     return buf;
136 }
137 
free_fragment_buffer(char * buf)138 int free_fragment_buffer(char *buf)
139 {
140     fragment_header_t *header;
141 
142     if (NULL == buf) {
143         return -1;
144     }
145 
146     buf -= sizeof(fragment_header_t);
147 
148     header = (fragment_header_t *) buf;
149     if (header->magic != LIBERASURECODE_FRAG_HEADER_MAGIC) {
150         log_error("Invalid fragment header (free fragment)!");
151         return -1;
152     }
153 
154     free(buf);
155     return 0;
156 }
157 
158 /* ==~=*=~==~=*=~==~=*=~==~=*=~==~=*=~==~=*=~==~=*=~==~=*=~==~=*=~==~=*=~== */
159 
160 /**
161  * Return total fragment length (on-disk, on-wire)
162  *
163  * @param buf - pointer to fragment buffer
164  *
165  * @return fragment size on disk
166  */
get_fragment_size(char * buf)167 uint64_t get_fragment_size(char *buf)
168 {
169 
170     if (NULL == buf)
171         return -1;
172 
173     return get_fragment_buffer_size(buf) + sizeof(fragment_header_t);
174  }
175 
176 /**
177  * Compute a size aligned to the number of data and the underlying wordsize
178  * of the EC algorithm.
179  *
180  * @param instance, ec_backend_t instance (to extract args)
181  * @param data_len, integer length of data in bytes
182  * @return integer data length aligned with wordsize of EC algorithm
183  */
get_aligned_data_size(ec_backend_t instance,int data_len)184 int get_aligned_data_size(ec_backend_t instance, int data_len)
185 {
186     int k = instance->args.uargs.k;
187     int w = instance->args.uargs.w;
188     int word_size = w / 8;
189     int alignment_multiple;
190     int aligned_size = 0;
191 
192     /*
193      * For Cauchy reed-solomon align to k*word_size*packet_size
194      * For Vandermonde reed-solomon and flat-XOR, align to k*word_size
195      */
196     if (EC_BACKEND_JERASURE_RS_CAUCHY == instance->common.id) {
197         alignment_multiple = k * w * (sizeof(long) * 128);
198     } else {
199         alignment_multiple = k * word_size;
200     }
201 
202     aligned_size = (int)
203         ceill((double) data_len / alignment_multiple) * alignment_multiple;
204 
205     return aligned_size;
206 }
207 
208 /* ==~=*=~==~=*=~==~=*=~==~=*=~==~=*=~==~=*=~==~=*=~==~=*=~==~=*=~==~=*=~== */
209 
get_data_ptr_from_fragment(char * buf)210 char *get_data_ptr_from_fragment(char *buf)
211 {
212     buf += sizeof(fragment_header_t);
213 
214     return buf;
215 }
216 
get_data_ptr_array_from_fragments(char ** data_array,char ** fragments,int num_fragments)217 int get_data_ptr_array_from_fragments(char **data_array, char **fragments,
218                                       int num_fragments)
219 {
220     int i = 0, num = 0;
221     for (i = 0; i < num_fragments; i++) {
222         char *frag = fragments[i];
223         if (frag == NULL) {
224             data_array[i] = NULL;
225             continue;
226         }
227         data_array[i] = get_data_ptr_from_fragment(frag);
228         num++;
229     }
230     return num;
231 }
232 
get_fragment_ptr_array_from_data(char ** frag_array,char ** data,int num_data)233 int get_fragment_ptr_array_from_data(char **frag_array, char **data,
234                                      int num_data)
235 {
236     int i = 0, num = 0;
237     for (i = 0; i < num_data; i++) {
238         char *data_ptr = frag_array[i];
239         if (data_ptr == NULL) {
240             data[i] = NULL;
241             continue;
242         }
243         data[i] = get_fragment_ptr_from_data(data_ptr);
244         num++;
245     }
246     return num;
247 }
248 
get_fragment_ptr_from_data_novalidate(char * buf)249 char *get_fragment_ptr_from_data_novalidate(char *buf)
250 {
251     buf -= sizeof(fragment_header_t);
252 
253     return buf;
254 }
255 
get_fragment_ptr_from_data(char * buf)256 char *get_fragment_ptr_from_data(char *buf)
257 {
258     fragment_header_t *header;
259 
260     buf -= sizeof(fragment_header_t);
261 
262     header = (fragment_header_t *) buf;
263 
264     if (header->magic != LIBERASURECODE_FRAG_HEADER_MAGIC) {
265         log_error("Invalid fragment header (get header ptr)!\n");
266         return NULL;
267     }
268 
269     return buf;
270 }
271 
272 /* ==~=*=~==~=*=~==~=*=~==~=*=~==~=*=~==~=*=~==~=*=~==~=*=~==~=*=~==~=*=~== */
273 
set_fragment_idx(char * buf,int idx)274 int set_fragment_idx(char *buf, int idx)
275 {
276     fragment_header_t *header = (fragment_header_t *) buf;
277 
278     assert(NULL != header);
279     if (header->magic != LIBERASURECODE_FRAG_HEADER_MAGIC) {
280         log_error("Invalid fragment header (idx check)!\n");
281         return -1;
282     }
283 
284     header->meta.idx = idx;
285 
286     return 0;
287 }
288 
get_fragment_idx(char * buf)289 int get_fragment_idx(char *buf)
290 {
291     fragment_header_t *header = (fragment_header_t *) buf;
292 
293     assert(NULL != header);
294     if (header->magic != LIBERASURECODE_FRAG_HEADER_MAGIC) {
295         log_error("Invalid fragment header (get idx)!");
296         return -1;
297     }
298 
299     return header->meta.idx;
300 }
301 
set_fragment_payload_size(char * buf,int size)302 int set_fragment_payload_size(char *buf, int size)
303 {
304     fragment_header_t *header = (fragment_header_t *) buf;
305 
306     assert(NULL != header);
307     if (header->magic != LIBERASURECODE_FRAG_HEADER_MAGIC) {
308         log_error("Invalid fragment header (size check)!");
309         return -1;
310     }
311 
312     header->meta.size = size;
313 
314     return 0;
315 }
316 
get_fragment_payload_size(char * buf)317 int get_fragment_payload_size(char *buf)
318 {
319     fragment_header_t *header = (fragment_header_t *) buf;
320 
321     assert(NULL != header);
322     if (header->magic != LIBERASURECODE_FRAG_HEADER_MAGIC) {
323         log_error("Invalid fragment header (get size)!");
324         return -1;
325     }
326 
327     return header->meta.size;
328 }
329 
set_fragment_backend_metadata_size(char * buf,int size)330 int set_fragment_backend_metadata_size(char *buf, int size)
331 {
332     fragment_header_t *header = (fragment_header_t *) buf;
333 
334     assert(NULL != header);
335     if (header->magic != LIBERASURECODE_FRAG_HEADER_MAGIC) {
336         log_error("Invalid fragment header (set fragment backend metadata size)!");
337         return -1;
338     }
339 
340     header->meta.frag_backend_metadata_size = size;
341 
342     return 0;
343 }
344 
get_fragment_backend_metadata_size(char * buf)345 int get_fragment_backend_metadata_size(char *buf)
346 {
347     fragment_header_t *header = (fragment_header_t *) buf;
348 
349     assert(NULL != header);
350     if (header->magic != LIBERASURECODE_FRAG_HEADER_MAGIC) {
351         log_error("Invalid fragment header (get fragment backend metadata size)!");
352         return -1;
353     }
354 
355     return header->meta.frag_backend_metadata_size;
356 }
357 
get_fragment_buffer_size(char * buf)358 int get_fragment_buffer_size(char *buf)
359 {
360     fragment_header_t *header = (fragment_header_t *) buf;
361 
362     assert(NULL != header);
363     if (header->magic != LIBERASURECODE_FRAG_HEADER_MAGIC) {
364         log_error("Invalid fragment header (get size)!");
365         return -1;
366     }
367 
368     return header->meta.size + header->meta.frag_backend_metadata_size;
369 }
370 
set_orig_data_size(char * buf,int orig_data_size)371 int set_orig_data_size(char *buf, int orig_data_size)
372 {
373     fragment_header_t *header = (fragment_header_t *) buf;
374 
375     assert(NULL != header);
376     if (header->magic != LIBERASURECODE_FRAG_HEADER_MAGIC) {
377         log_error("Invalid fragment header (set orig data check)!");
378         return -1;
379     }
380 
381     header->meta.orig_data_size = orig_data_size;
382 
383     return 0;
384 }
385 
get_orig_data_size(char * buf)386 int get_orig_data_size(char *buf)
387 {
388     fragment_header_t *header = (fragment_header_t *) buf;
389 
390     assert(NULL != header);
391     if (header->magic != LIBERASURECODE_FRAG_HEADER_MAGIC) {
392         log_error("Invalid fragment header (get orig data check)!");
393         return -1;
394     }
395 
396     return header->meta.orig_data_size;
397 }
398 
set_libec_version(char * buf)399 int set_libec_version(char *buf)
400 {
401     if (!is_fragment(buf)) {
402             return -1;
403     }
404     fragment_header_t *header = (fragment_header_t *) buf;
405     header->libec_version = (uint32_t)LIBERASURECODE_VERSION;
406     return 0;
407 }
408 
get_libec_version(char * buf,uint32_t * ver)409 int get_libec_version(char *buf, uint32_t *ver)
410 {
411     if (!is_fragment(buf)) {
412             return -1;
413     }
414     fragment_header_t *header = (fragment_header_t *) buf;
415     *ver = header->libec_version;
416     return 0;
417 }
418 
set_backend_id(char * buf,ec_backend_id_t id)419 int set_backend_id(char *buf, ec_backend_id_t id)
420 {
421     if (!is_fragment(buf)) {
422             return -1;
423     }
424     fragment_header_t *header = (fragment_header_t *) buf;
425     header->meta.backend_id = (uint8_t)id;
426     return 0;
427 }
428 
get_backend_id(char * buf,ec_backend_id_t * id)429 int get_backend_id(char *buf, ec_backend_id_t *id)
430 {
431     if (!is_fragment(buf)) {
432             return -1;
433     }
434     fragment_header_t *header = (fragment_header_t *) buf;
435     *id = header->meta.backend_id;
436     return 0;
437 }
438 
set_backend_version(char * buf,uint32_t version)439 int set_backend_version(char *buf, uint32_t version)
440 {
441     if (!is_fragment(buf)) {
442             return -1;
443     }
444     fragment_header_t *header = (fragment_header_t *) buf;
445     header->meta.backend_version = version;
446     return 0;
447 }
448 
get_backend_version(char * buf,uint32_t * version)449 int get_backend_version(char *buf, uint32_t *version)
450 {
451     if (!is_fragment(buf)) {
452             return -1;
453     }
454     fragment_header_t *header = (fragment_header_t *) buf;
455     *version = header->meta.backend_version;
456     return 0;
457 }
458 
459 /* ==~=*=~==~=*=~==~=*=~==~=*=~==~=*=~==~=*=~==~=*=~==~=*=~==~=*=~==~=*=~== */
460 
set_checksum(ec_checksum_type_t ct,char * buf,int blocksize)461 inline int set_checksum(ec_checksum_type_t ct, char *buf, int blocksize)
462 {
463     fragment_header_t* header = (fragment_header_t*) buf;
464     char *data = get_data_ptr_from_fragment(buf);
465 
466     assert(NULL != header);
467     if (header->magic != LIBERASURECODE_FRAG_HEADER_MAGIC) {
468         log_error("Invalid fragment header (set chksum)!\n");
469         return -1;
470     }
471 
472     header->meta.chksum_type = ct;
473     header->meta.chksum_mismatch = 0;
474 
475     switch(header->meta.chksum_type) {
476         case CHKSUM_CRC32:
477             header->meta.chksum[0] = crc32(0, data, blocksize);
478             break;
479         case CHKSUM_MD5:
480             break;
481         case CHKSUM_NONE:
482         default:
483             break;
484     }
485 
486     return 0;
487 }
488 
get_chksum(char * buf)489 inline uint32_t* get_chksum(char *buf)
490 {
491     fragment_header_t* header = (fragment_header_t*) buf;
492 
493     assert(NULL != header);
494     if (header->magic != LIBERASURECODE_FRAG_HEADER_MAGIC) {
495         log_error("Invalid fragment header (get chksum)!");
496         return NULL;
497     }
498 
499     return (uint32_t *) header->meta.chksum;
500 }
501 
502 /* ==~=*=~==~=*=~==~=*=~==~=*=~==~=*=~==~=*=~==~=*=~==~=*=~==~=*=~==~=*=~== */
503 
504 #if LIBERASURECODE_VERSION >= _VERSION(1,2,0)
set_metadata_chksum(char * buf)505 inline int set_metadata_chksum(char *buf)
506 {
507     fragment_header_t* header = (fragment_header_t*) buf;
508 
509     assert(NULL != header);
510     if (header->magic != LIBERASURECODE_FRAG_HEADER_MAGIC) {
511         log_error("Invalid fragment header (set meta chksum)!\n");
512         return -1;
513     }
514 
515     header->metadata_chksum = crc32(0, &header->meta,
516                                     sizeof(fragment_metadata_t));
517     return 0;
518 }
519 
get_metadata_chksum(char * buf)520 inline uint32_t* get_metadata_chksum(char *buf)
521 {
522     fragment_header_t* header = (fragment_header_t*) buf;
523 
524     assert(NULL != header);
525     if (header->magic != LIBERASURECODE_FRAG_HEADER_MAGIC) {
526         log_error("Invalid fragment header (get meta chksum)!");
527         return NULL;
528     }
529 
530     return (uint32_t *) &header->metadata_chksum;
531 }
532 #else
set_metadata_chksum(char * buf)533 inline int set_metadata_chksum(char *buf)
534 {
535     return 0;
536 }
537 
get_metadata_chksum(char * buf)538 inline uint32_t* get_metadata_chksum(char *buf)
539 {
540     return (uint32_t *) 0;
541 }
542 #endif
543 
544 /* ==~=*=~==~=*=~==~=*=~==~=*=~==~=*=~==~=*=~==~=*=~==~=*=~==~=*=~==~=*=~== */
545 
546