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