546 lines
14 KiB
C
546 lines
14 KiB
C
/*
|
|
* Copyright 2014 Tushar Gohad, Kevin M Greenan, Eric Lambert
|
|
*
|
|
* Redistribution and use in source and binary forms, with or without
|
|
* modification, are permitted provided that the following conditions are met:
|
|
*
|
|
* Redistributions of source code must retain the above copyright notice, this
|
|
* list of conditions and the following disclaimer.
|
|
*
|
|
* Redistributions in binary form must reproduce the above copyright notice, this
|
|
* list of conditions and the following disclaimer in the documentation and/or
|
|
* other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY
|
|
* THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED
|
|
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
|
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
|
|
* EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
|
|
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
|
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
|
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
|
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
|
|
* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
|
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
*
|
|
* liberasurecode API helpers implementation
|
|
*
|
|
* vi: set noai tw=79 ts=4 sw=4:
|
|
*/
|
|
#include <assert.h>
|
|
#include <stdio.h>
|
|
#include <stdarg.h>
|
|
#include "erasurecode_backend.h"
|
|
#include "erasurecode_helpers.h"
|
|
#include "erasurecode_helpers_ext.h"
|
|
#include "erasurecode_stdinc.h"
|
|
#include "erasurecode_version.h"
|
|
|
|
#include "alg_sig.h"
|
|
#include "erasurecode_log.h"
|
|
|
|
/* ==~=*=~==~=*=~==~=*=~==~=*=~==~=*=~==~=*=~==~=*=~==~=*=~==~=*=~==~=*=~== */
|
|
|
|
static bool is_fragment(char *buf)
|
|
{
|
|
fragment_header_t *header = (fragment_header_t *) buf;
|
|
|
|
assert(NULL != header);
|
|
if (header->magic == LIBERASURECODE_FRAG_HEADER_MAGIC) {
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
/**
|
|
* Memory Management Methods
|
|
*
|
|
* The following methods provide wrappers for allocating and deallocating
|
|
* memory.
|
|
*/
|
|
void *get_aligned_buffer16(int size)
|
|
{
|
|
void *buf;
|
|
|
|
/**
|
|
* Ensure all memory is aligned to 16-byte boundaries
|
|
* to support 128-bit operations
|
|
*/
|
|
if (posix_memalign(&buf, 16, size) != 0) {
|
|
return NULL;
|
|
}
|
|
|
|
memset(buf, 0, size);
|
|
|
|
return buf;
|
|
}
|
|
|
|
/**
|
|
* Allocate a zero-ed buffer of a specific size.
|
|
*
|
|
* @param size integer size in bytes of buffer to allocate
|
|
* @return pointer to start of allocated buffer or NULL on error
|
|
*/
|
|
void * alloc_zeroed_buffer(int size)
|
|
{
|
|
return alloc_and_set_buffer(size, 0);
|
|
}
|
|
|
|
/**
|
|
* Allocate a buffer of a specific size and set its' contents
|
|
* to the specified value.
|
|
*
|
|
* @param size integer size in bytes of buffer to allocate
|
|
* @param value
|
|
* @return pointer to start of allocated buffer or NULL on error
|
|
*/
|
|
void * alloc_and_set_buffer(int size, int value) {
|
|
void * buf = NULL; /* buffer to allocate and return */
|
|
|
|
/* Allocate and zero the buffer, or set the appropriate error */
|
|
buf = malloc((size_t) size);
|
|
if (buf) {
|
|
buf = memset(buf, value, (size_t) size);
|
|
}
|
|
return buf;
|
|
}
|
|
|
|
/**
|
|
* Deallocate memory buffer if it's not NULL. This methods returns NULL so
|
|
* that you can free and reset a buffer using a single line as follows:
|
|
*
|
|
* my_ptr = check_and_free_buffer(my_ptr);
|
|
*
|
|
* @return NULL
|
|
*/
|
|
void * check_and_free_buffer(void * buf)
|
|
{
|
|
if (buf)
|
|
free(buf);
|
|
return NULL;
|
|
}
|
|
|
|
char *alloc_fragment_buffer(int size)
|
|
{
|
|
char *buf;
|
|
fragment_header_t *header = NULL;
|
|
|
|
size += sizeof(fragment_header_t);
|
|
buf = get_aligned_buffer16(size);
|
|
|
|
if (buf) {
|
|
header = (fragment_header_t *) buf;
|
|
header->magic = LIBERASURECODE_FRAG_HEADER_MAGIC;
|
|
}
|
|
|
|
return buf;
|
|
}
|
|
|
|
int free_fragment_buffer(char *buf)
|
|
{
|
|
fragment_header_t *header;
|
|
|
|
if (NULL == buf) {
|
|
return -1;
|
|
}
|
|
|
|
buf -= sizeof(fragment_header_t);
|
|
|
|
header = (fragment_header_t *) buf;
|
|
if (header->magic != LIBERASURECODE_FRAG_HEADER_MAGIC) {
|
|
log_error("Invalid fragment header (free fragment)!");
|
|
return -1;
|
|
}
|
|
|
|
free(buf);
|
|
return 0;
|
|
}
|
|
|
|
/* ==~=*=~==~=*=~==~=*=~==~=*=~==~=*=~==~=*=~==~=*=~==~=*=~==~=*=~==~=*=~== */
|
|
|
|
/**
|
|
* Return total fragment length (on-disk, on-wire)
|
|
*
|
|
* @param buf - pointer to fragment buffer
|
|
*
|
|
* @return fragment size on disk
|
|
*/
|
|
uint64_t get_fragment_size(char *buf)
|
|
{
|
|
|
|
if (NULL == buf)
|
|
return -1;
|
|
|
|
return get_fragment_buffer_size(buf) + sizeof(fragment_header_t);
|
|
}
|
|
|
|
/**
|
|
* Compute a size aligned to the number of data and the underlying wordsize
|
|
* of the EC algorithm.
|
|
*
|
|
* @param instance, ec_backend_t instance (to extract args)
|
|
* @param data_len, integer length of data in bytes
|
|
* @return integer data length aligned with wordsize of EC algorithm
|
|
*/
|
|
int get_aligned_data_size(ec_backend_t instance, int data_len)
|
|
{
|
|
int k = instance->args.uargs.k;
|
|
int w = instance->args.uargs.w;
|
|
int word_size = w / 8;
|
|
int alignment_multiple;
|
|
int aligned_size = 0;
|
|
|
|
/*
|
|
* For Cauchy reed-solomon align to k*word_size*packet_size
|
|
* For Vandermonde reed-solomon and flat-XOR, align to k*word_size
|
|
*/
|
|
if (EC_BACKEND_JERASURE_RS_CAUCHY == instance->common.id) {
|
|
alignment_multiple = k * w * (sizeof(long) * 128);
|
|
} else {
|
|
alignment_multiple = k * word_size;
|
|
}
|
|
|
|
aligned_size = (int)
|
|
ceill((double) data_len / alignment_multiple) * alignment_multiple;
|
|
|
|
return aligned_size;
|
|
}
|
|
|
|
/* ==~=*=~==~=*=~==~=*=~==~=*=~==~=*=~==~=*=~==~=*=~==~=*=~==~=*=~==~=*=~== */
|
|
|
|
char *get_data_ptr_from_fragment(char *buf)
|
|
{
|
|
buf += sizeof(fragment_header_t);
|
|
|
|
return buf;
|
|
}
|
|
|
|
int get_data_ptr_array_from_fragments(char **data_array, char **fragments,
|
|
int num_fragments)
|
|
{
|
|
int i = 0, num = 0;
|
|
for (i = 0; i < num_fragments; i++) {
|
|
char *frag = fragments[i];
|
|
if (frag == NULL) {
|
|
data_array[i] = NULL;
|
|
continue;
|
|
}
|
|
data_array[i] = get_data_ptr_from_fragment(frag);
|
|
num++;
|
|
}
|
|
return num;
|
|
}
|
|
|
|
int get_fragment_ptr_array_from_data(char **frag_array, char **data,
|
|
int num_data)
|
|
{
|
|
int i = 0, num = 0;
|
|
for (i = 0; i < num_data; i++) {
|
|
char *data_ptr = frag_array[i];
|
|
if (data_ptr == NULL) {
|
|
data[i] = NULL;
|
|
continue;
|
|
}
|
|
data[i] = get_fragment_ptr_from_data(data_ptr);
|
|
num++;
|
|
}
|
|
return num;
|
|
}
|
|
|
|
char *get_fragment_ptr_from_data_novalidate(char *buf)
|
|
{
|
|
buf -= sizeof(fragment_header_t);
|
|
|
|
return buf;
|
|
}
|
|
|
|
char *get_fragment_ptr_from_data(char *buf)
|
|
{
|
|
fragment_header_t *header;
|
|
|
|
buf -= sizeof(fragment_header_t);
|
|
|
|
header = (fragment_header_t *) buf;
|
|
|
|
if (header->magic != LIBERASURECODE_FRAG_HEADER_MAGIC) {
|
|
log_error("Invalid fragment header (get header ptr)!\n");
|
|
return NULL;
|
|
}
|
|
|
|
return buf;
|
|
}
|
|
|
|
/* ==~=*=~==~=*=~==~=*=~==~=*=~==~=*=~==~=*=~==~=*=~==~=*=~==~=*=~==~=*=~== */
|
|
|
|
int set_fragment_idx(char *buf, int idx)
|
|
{
|
|
fragment_header_t *header = (fragment_header_t *) buf;
|
|
|
|
assert(NULL != header);
|
|
if (header->magic != LIBERASURECODE_FRAG_HEADER_MAGIC) {
|
|
log_error("Invalid fragment header (idx check)!\n");
|
|
return -1;
|
|
}
|
|
|
|
header->meta.idx = idx;
|
|
|
|
return 0;
|
|
}
|
|
|
|
int get_fragment_idx(char *buf)
|
|
{
|
|
fragment_header_t *header = (fragment_header_t *) buf;
|
|
|
|
assert(NULL != header);
|
|
if (header->magic != LIBERASURECODE_FRAG_HEADER_MAGIC) {
|
|
log_error("Invalid fragment header (get idx)!");
|
|
return -1;
|
|
}
|
|
|
|
return header->meta.idx;
|
|
}
|
|
|
|
int set_fragment_payload_size(char *buf, int size)
|
|
{
|
|
fragment_header_t *header = (fragment_header_t *) buf;
|
|
|
|
assert(NULL != header);
|
|
if (header->magic != LIBERASURECODE_FRAG_HEADER_MAGIC) {
|
|
log_error("Invalid fragment header (size check)!");
|
|
return -1;
|
|
}
|
|
|
|
header->meta.size = size;
|
|
|
|
return 0;
|
|
}
|
|
|
|
int get_fragment_payload_size(char *buf)
|
|
{
|
|
fragment_header_t *header = (fragment_header_t *) buf;
|
|
|
|
assert(NULL != header);
|
|
if (header->magic != LIBERASURECODE_FRAG_HEADER_MAGIC) {
|
|
log_error("Invalid fragment header (get size)!");
|
|
return -1;
|
|
}
|
|
|
|
return header->meta.size;
|
|
}
|
|
|
|
int set_fragment_backend_metadata_size(char *buf, int size)
|
|
{
|
|
fragment_header_t *header = (fragment_header_t *) buf;
|
|
|
|
assert(NULL != header);
|
|
if (header->magic != LIBERASURECODE_FRAG_HEADER_MAGIC) {
|
|
log_error("Invalid fragment header (set fragment backend metadata size)!");
|
|
return -1;
|
|
}
|
|
|
|
header->meta.frag_backend_metadata_size = size;
|
|
|
|
return 0;
|
|
}
|
|
|
|
int get_fragment_backend_metadata_size(char *buf)
|
|
{
|
|
fragment_header_t *header = (fragment_header_t *) buf;
|
|
|
|
assert(NULL != header);
|
|
if (header->magic != LIBERASURECODE_FRAG_HEADER_MAGIC) {
|
|
log_error("Invalid fragment header (get fragment backend metadata size)!");
|
|
return -1;
|
|
}
|
|
|
|
return header->meta.frag_backend_metadata_size;
|
|
}
|
|
|
|
int get_fragment_buffer_size(char *buf)
|
|
{
|
|
fragment_header_t *header = (fragment_header_t *) buf;
|
|
|
|
assert(NULL != header);
|
|
if (header->magic != LIBERASURECODE_FRAG_HEADER_MAGIC) {
|
|
log_error("Invalid fragment header (get size)!");
|
|
return -1;
|
|
}
|
|
|
|
return header->meta.size + header->meta.frag_backend_metadata_size;
|
|
}
|
|
|
|
int set_orig_data_size(char *buf, int orig_data_size)
|
|
{
|
|
fragment_header_t *header = (fragment_header_t *) buf;
|
|
|
|
assert(NULL != header);
|
|
if (header->magic != LIBERASURECODE_FRAG_HEADER_MAGIC) {
|
|
log_error("Invalid fragment header (set orig data check)!");
|
|
return -1;
|
|
}
|
|
|
|
header->meta.orig_data_size = orig_data_size;
|
|
|
|
return 0;
|
|
}
|
|
|
|
int get_orig_data_size(char *buf)
|
|
{
|
|
fragment_header_t *header = (fragment_header_t *) buf;
|
|
|
|
assert(NULL != header);
|
|
if (header->magic != LIBERASURECODE_FRAG_HEADER_MAGIC) {
|
|
log_error("Invalid fragment header (get orig data check)!");
|
|
return -1;
|
|
}
|
|
|
|
return header->meta.orig_data_size;
|
|
}
|
|
|
|
int set_libec_version(char *buf)
|
|
{
|
|
if (!is_fragment(buf)) {
|
|
return -1;
|
|
}
|
|
fragment_header_t *header = (fragment_header_t *) buf;
|
|
header->libec_version = (uint32_t)LIBERASURECODE_VERSION;
|
|
return 0;
|
|
}
|
|
|
|
int get_libec_version(char *buf, uint32_t *ver)
|
|
{
|
|
if (!is_fragment(buf)) {
|
|
return -1;
|
|
}
|
|
fragment_header_t *header = (fragment_header_t *) buf;
|
|
*ver = header->libec_version;
|
|
return 0;
|
|
}
|
|
|
|
int set_backend_id(char *buf, ec_backend_id_t id)
|
|
{
|
|
if (!is_fragment(buf)) {
|
|
return -1;
|
|
}
|
|
fragment_header_t *header = (fragment_header_t *) buf;
|
|
header->meta.backend_id = (uint8_t)id;
|
|
return 0;
|
|
}
|
|
|
|
int get_backend_id(char *buf, ec_backend_id_t *id)
|
|
{
|
|
if (!is_fragment(buf)) {
|
|
return -1;
|
|
}
|
|
fragment_header_t *header = (fragment_header_t *) buf;
|
|
*id = header->meta.backend_id;
|
|
return 0;
|
|
}
|
|
|
|
int set_backend_version(char *buf, uint32_t version)
|
|
{
|
|
if (!is_fragment(buf)) {
|
|
return -1;
|
|
}
|
|
fragment_header_t *header = (fragment_header_t *) buf;
|
|
header->meta.backend_version = version;
|
|
return 0;
|
|
}
|
|
|
|
int get_backend_version(char *buf, uint32_t *version)
|
|
{
|
|
if (!is_fragment(buf)) {
|
|
return -1;
|
|
}
|
|
fragment_header_t *header = (fragment_header_t *) buf;
|
|
*version = header->meta.backend_version;
|
|
return 0;
|
|
}
|
|
|
|
/* ==~=*=~==~=*=~==~=*=~==~=*=~==~=*=~==~=*=~==~=*=~==~=*=~==~=*=~==~=*=~== */
|
|
|
|
inline int set_checksum(ec_checksum_type_t ct, char *buf, int blocksize)
|
|
{
|
|
fragment_header_t* header = (fragment_header_t*) buf;
|
|
char *data = get_data_ptr_from_fragment(buf);
|
|
|
|
assert(NULL != header);
|
|
if (header->magic != LIBERASURECODE_FRAG_HEADER_MAGIC) {
|
|
log_error("Invalid fragment header (set chksum)!\n");
|
|
return -1;
|
|
}
|
|
|
|
header->meta.chksum_type = ct;
|
|
header->meta.chksum_mismatch = 0;
|
|
|
|
switch(header->meta.chksum_type) {
|
|
case CHKSUM_CRC32:
|
|
header->meta.chksum[0] = crc32(0, data, blocksize);
|
|
break;
|
|
case CHKSUM_MD5:
|
|
break;
|
|
case CHKSUM_NONE:
|
|
default:
|
|
break;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
inline uint32_t* get_chksum(char *buf)
|
|
{
|
|
fragment_header_t* header = (fragment_header_t*) buf;
|
|
|
|
assert(NULL != header);
|
|
if (header->magic != LIBERASURECODE_FRAG_HEADER_MAGIC) {
|
|
log_error("Invalid fragment header (get chksum)!");
|
|
return NULL;
|
|
}
|
|
|
|
return (uint32_t *) header->meta.chksum;
|
|
}
|
|
|
|
/* ==~=*=~==~=*=~==~=*=~==~=*=~==~=*=~==~=*=~==~=*=~==~=*=~==~=*=~==~=*=~== */
|
|
|
|
#if LIBERASURECODE_VERSION >= _VERSION(1,2,0)
|
|
inline int set_metadata_chksum(char *buf)
|
|
{
|
|
fragment_header_t* header = (fragment_header_t*) buf;
|
|
|
|
assert(NULL != header);
|
|
if (header->magic != LIBERASURECODE_FRAG_HEADER_MAGIC) {
|
|
log_error("Invalid fragment header (set meta chksum)!\n");
|
|
return -1;
|
|
}
|
|
|
|
header->metadata_chksum = crc32(0, &header->meta,
|
|
sizeof(fragment_metadata_t));
|
|
return 0;
|
|
}
|
|
|
|
inline uint32_t* get_metadata_chksum(char *buf)
|
|
{
|
|
fragment_header_t* header = (fragment_header_t*) buf;
|
|
|
|
assert(NULL != header);
|
|
if (header->magic != LIBERASURECODE_FRAG_HEADER_MAGIC) {
|
|
log_error("Invalid fragment header (get meta chksum)!");
|
|
return NULL;
|
|
}
|
|
|
|
return (uint32_t *) &header->metadata_chksum;
|
|
}
|
|
#else
|
|
inline int set_metadata_chksum(char *buf)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
inline uint32_t* get_metadata_chksum(char *buf)
|
|
{
|
|
return (uint32_t *) 0;
|
|
}
|
|
#endif
|
|
|
|
/* ==~=*=~==~=*=~==~=*=~==~=*=~==~=*=~==~=*=~==~=*=~==~=*=~==~=*=~==~=*=~== */
|
|
|