From b30a15d87f13479d32965620179438f1b177bae1 Mon Sep 17 00:00:00 2001 From: Kota Tsuyuzaki Date: Thu, 5 Feb 2015 02:20:48 +0900 Subject: Add NTT backend called "shss" This introduces a new plug-able backend called "shss" made by Nippon Telegraph and Telephone corporation (NTT). Note that this produces a just plug-in to shss erasure coding binary so that users have to install a shss binary (i.e. libshss.so) aside from liberasurecode when using shss. Please contact us if you are insterested in the NTT backend (welcome!): Kota Tsuyuzaki Co-Author: Ryuta Kon --- src/Makefile.am | 9 +- src/backends/shss/shss.c | 296 +++++++++++++++++++++++++++++++++++++++++++++++ src/erasurecode.c | 66 ++++++----- 3 files changed, 337 insertions(+), 34 deletions(-) create mode 100644 src/backends/shss/shss.c (limited to 'src') diff --git a/src/Makefile.am b/src/Makefile.am index ce6ef50..fc55f66 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -4,7 +4,8 @@ lib_LTLIBRARIES = liberasurecode.la INCLUDES = \ -I$(top_srcdir)/include/erasurecode \ - -I$(top_srcdir)/include/xor_codes + -I$(top_srcdir)/include/xor_codes \ + -I$(top_srcdir)/include/shss # liberasurecode params liberasurecode_la_SOURCES = \ @@ -18,7 +19,8 @@ liberasurecode_la_SOURCES = \ backends/xor/flat_xor_hd.c \ backends/jerasure/jerasure_rs_vand.c \ backends/jerasure/jerasure_rs_cauchy.c \ - backends/isa-l/isa_l_vand.c + backends/isa-l/isa_l_vand.c \ + backends/shss/shss.c # Install additional header files liberasurecodeincludedir = $(includedir) @@ -36,4 +38,5 @@ liberasurecode_la_LDFLAGS = -rpath '$(libdir)' -version-info 9:10:9 MOSTLYCLEANFILES = *.gcda *.gcno *.gcov utils/chksum/*.gcda utils/chksum/*.gcno utils/chksum/*.gcov \ backends/null/*.gcda backends/null/*.gcno backends/null/*.gcov \ backends/xor/*.gcda backends/xor/*.gcno backends/xor/*.gcov \ - backends/jerasure/*.gcda backends/jerasure/*.gcno backends/jerasure/*.gcov + backends/jerasure/*.gcda backends/jerasure/*.gcno backends/jerasure/*.gcov \ + backends/shss/*.gcda backends/shss/*.gcno backends/shss/*.gcov diff --git a/src/backends/shss/shss.c b/src/backends/shss/shss.c new file mode 100644 index 0000000..f8ba53a --- /dev/null +++ b/src/backends/shss/shss.c @@ -0,0 +1,296 @@ +/* + * Copyright(c) 2015 NTT corp. All Rights Reserved. + * + * 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 shss backend + * + * Please contact us if you are insterested in the NTT backend (welcome!): + * Kota Tsuyuzaki + * + * vi: set noai tw=79 ts=4 sw=4: + */ + +#include +#include +#include + +#include "erasurecode.h" +#include "erasurecode_helpers.h" +#include "erasurecode_backend.h" + +/* Forward declarations */ +struct ec_backend shss; +struct ec_backend_op_stubs shss_ops; + +typedef int (*shss_encode_func)(char **, size_t, int, int, int, int, long long *); +typedef int (*shss_decode_func)(char **, size_t, int *, int, int, int, int, int, long long *); +typedef int (*shss_reconstruct_func)(char **, size_t, int *, int, int *, int, int, int, int, int, long long *); + +struct shss_descriptor { + /* calls required for init */ + shss_encode_func ssencode; + shss_decode_func ssdecode; + shss_reconstruct_func ssreconst; + + /* fields needed to hold state */ + int k; + int m; + int n; + int w; + int aes_bit_length; +}; + +#define SHSS_LIB_VER_STR "1.0" +#define SHSS_LIB_NAME "shss" +#if defined(__MACOS__) || defined(__MACOSX__) || defined(__OSX__) || defined(__APPLE__) +#define SHSS_SO_NAME "libshss.dylib" +#else +#define SHSS_SO_NAME "libshss.so" +#endif +#define DEFAULT_W 128 + +/* TODO: + metadata_adder is still in discussion. shss needs to a fixed value to allocate extra bytes + for *each* fragment. However, current liberasurecode calculates the extra bytes as + "(alined_data_size + metadata_adder) / k" so that shss has to define the METADATA as a big value + to alloc enough memory for the maximum number of k even if k is smaller than the maximum value. + + i.e. (shss specification is) + Enough Extra Bytes (for *each* fragment): 32 + The Maximum Number: 20 (k=20) +*/ +#define METADATA 32 * 20 + +static int shss_encode(void *desc, char **data, char **parity, + int blocksize) +{ + int i; + int ret = 0; + int priv_bitnum = 128; // privacy bit number 0 or 128(default) or 256 + int chksum = 0; // chksum 0 or 64 + char **encoded; + long long einfo; + struct shss_descriptor *xdesc = + (struct shss_descriptor *) desc; + + if (xdesc->aes_bit_length != -1) { + priv_bitnum = xdesc->aes_bit_length; + } + + encoded = alloca(sizeof(char*)*xdesc->n); + + for (i = 0; ik; i++) encoded[i] = (char*)data[i]; + for (i = 0; im; i++) encoded[i+xdesc->k] = (char*)parity[i]; + + ret = xdesc->ssencode((char**)encoded, (size_t)blocksize, + xdesc->k, xdesc->m, priv_bitnum, chksum, &einfo); + + if (ret > 0) { + return -ret; + } + + return 0; +} + +static int shss_decode(void *desc, char **data, char **parity, + int *missing_idxs, int blocksize) +{ + int i; + int missing_size = 0; + int ret = 0; + int priv_bitnum = 128; // privacy bit number 0 or 128(default) or 256 + int chksum = 0; // chksum 0 or 64 + char **decoded; + long long einfo; + struct shss_descriptor *xdesc = + (struct shss_descriptor *) desc; + + if (xdesc->aes_bit_length != -1) { + priv_bitnum = xdesc->aes_bit_length; + } + + decoded = alloca(sizeof(char*)*xdesc->n); + + for (i = 0; ik; i++) decoded[i] = (char*)data[i]; + for (i = 0; im; i++) decoded[i+xdesc->k] = (char*)parity[i]; + for (i = 0; in; i++) { + if (i == missing_idxs[missing_size]) { + missing_size++; + } + } + + ret = xdesc->ssdecode((char**)decoded, (size_t)blocksize, missing_idxs, missing_size, + xdesc->k, xdesc->m, priv_bitnum, chksum, &einfo); + + if (ret > 0) { + return -ret; + } + + return 0; +} + +static int shss_reconstruct(void *desc, char **data, char **parity, + int *missing_idxs, int destination_idx, int blocksize) +{ + int i; + int missing_size = 0; + int ret = 0; + int priv_bitnum = 128; // privacy bit number 0 or 128(default) or 256 + int chksum = 0; // chksum 0 or 64 + int dst_size = 1; + char **reconstructed; + long long einfo; + struct shss_descriptor *xdesc = + (struct shss_descriptor *) desc; + + if (xdesc->aes_bit_length != -1) { + priv_bitnum = xdesc->aes_bit_length; + } + + reconstructed = alloca(sizeof(char*)*xdesc->n); + + for (i = 0; ik; i++) reconstructed[i] = (char*)data[i]; + for (i = 0; im; i++) reconstructed[i+xdesc->k] = (char*)parity[i]; + for (i = 0; in; i++) { + if (i == missing_idxs[missing_size]) { + missing_size++; + } + } + + ret = xdesc->ssreconst((char**)reconstructed, (size_t)blocksize, + &destination_idx, dst_size, missing_idxs, missing_size, xdesc->k, + xdesc->m, priv_bitnum, chksum, &einfo); + + if (ret > 0) { + return -ret; + } + + return 0; +} + +static int shss_fragments_needed(void *desc, int *missing_idxs, + int *fragments_to_exclude, int *fragments_needed) +{ + struct shss_descriptor *xdesc = + (struct shss_descriptor *) desc; + uint64_t exclude_bm = convert_list_to_bitmap(fragments_to_exclude); + uint64_t missing_bm = convert_list_to_bitmap(missing_idxs) | exclude_bm; + int i; + int j = 0; + int ret = -101; + + for (i = 0; i < xdesc->n; i++) { + if (!(missing_bm & (1 << i))) { + fragments_needed[j] = i; + j++; + } + if (j == xdesc->k) { + ret = 0; + fragments_needed[j] = -1; + break; + } + } + + return ret; +} + +/** + * Return the element-size, which is the number of bits stored + * on a given device, per codeword. This is usually just 'w'. + */ +static int shss_element_size(void* desc) +{ + return DEFAULT_W; +} + +static void * shss_init(struct ec_backend_args *args, void *backend_sohandle) +{ + static struct shss_descriptor xdesc; + + xdesc.k = args->uargs.k; + xdesc.m = args->uargs.m; + xdesc.n = args->uargs.k + args->uargs.m; + xdesc.w = DEFAULT_W; + args->uargs.w = DEFAULT_W; + + /* Sample on how to pass extra args to the backend */ + // TODO: Need discussion how to pass extra args. + int *priv = (int *)args->uargs.priv_args2; + xdesc.aes_bit_length = priv[0]; // AES bit number + + union { + shss_encode_func encodep; + shss_decode_func decodep; + shss_reconstruct_func reconp; + void *vptr; + } func_handle; + + func_handle.vptr = NULL; + func_handle.vptr = dlsym(backend_sohandle, "ssencode"); + xdesc.ssencode = func_handle.encodep; + if (NULL == xdesc.ssencode) { + goto error; + } + + func_handle.vptr = NULL; + func_handle.vptr = dlsym(backend_sohandle, "ssdecode"); + xdesc.ssdecode = func_handle.decodep; + if (NULL == xdesc.ssdecode) { + goto error; + } + + func_handle.vptr = NULL; + func_handle.vptr = dlsym(backend_sohandle, "ssreconst"); + xdesc.ssreconst = func_handle.reconp; + if (NULL == xdesc.ssreconst) { + goto error; + } + + return (void *)&xdesc; + +error: + return NULL; +} + +static int shss_exit(void *desc) +{ + return 0; +} + +struct ec_backend_op_stubs shss_op_stubs = { + .INIT = shss_init, + .EXIT = shss_exit, + .ENCODE = shss_encode, + .DECODE = shss_decode, + .FRAGSNEEDED = shss_fragments_needed, + .RECONSTRUCT = shss_reconstruct, + .ELEMENTSIZE = shss_element_size, +}; + +struct ec_backend_common backend_shss = { + .id = EC_BACKEND_SHSS, + .name = SHSS_LIB_NAME, + .soname = SHSS_SO_NAME, + .soversion = SHSS_LIB_VER_STR, + .ops = &shss_op_stubs, + .metadata_adder = METADATA, +}; diff --git a/src/erasurecode.c b/src/erasurecode.c index 586e6bc..c9a32f1 100644 --- a/src/erasurecode.c +++ b/src/erasurecode.c @@ -43,6 +43,7 @@ extern struct ec_backend_common backend_flat_xor_hd; extern struct ec_backend_common backend_jerasure_rs_vand; extern struct ec_backend_common backend_jerasure_rs_cauchy; extern struct ec_backend_common backend_isa_l_rs_vand; +extern struct ec_backend_common backend_shss; ec_backend_t ec_backends_supported[] = { (ec_backend_t) &backend_null, @@ -50,6 +51,7 @@ ec_backend_t ec_backends_supported[] = { (ec_backend_t) &backend_jerasure_rs_cauchy, (ec_backend_t) &backend_flat_xor_hd, (ec_backend_t) &backend_isa_l_rs_vand, + (ec_backend_t) &backend_shss, NULL, }; @@ -136,7 +138,7 @@ exit: int liberasurecode_backend_instance_unregister(ec_backend_t instance) { int rc = 0; /* return call value */ - + rc = rwlock_wrlock(&active_instances_rwlock); if (rc == 0) { SLIST_REMOVE(&active_instances, instance, ec_backend, link); @@ -196,7 +198,7 @@ void __attribute__ ((constructor)) liberasurecode_init(void) { /* init logging */ openlog("liberasurecode", LOG_PID | LOG_CONS, LOG_USER); - + /* populate supported backends list as a string */ { int i; @@ -219,7 +221,7 @@ liberasurecode_exit(void) { /* =~=*=~==~=*=~= liberasurecode frontend API implementation =~=*=~==~=*=~== */ /** - * Create a liberasurecode instance and return a descriptor + * Create a liberasurecode instance and return a descriptor * for use with EC operations (encode, decode, reconstruct) * * @param id - one of the supported backends as @@ -313,9 +315,9 @@ int liberasurecode_instance_destroy(int desc) /** * Cleanup structures allocated by librasurecode_encode - * + * * The caller has no context, so cannot safely free memory - * allocated by liberasurecode, so it must pass the + * allocated by liberasurecode, so it must pass the * deallocation responsibility back to liberasurecode. * * @param desc - liberasurecode descriptor/handle @@ -346,12 +348,12 @@ int liberasurecode_encode_cleanup(int desc, free(encoded_data); } - - if (encoded_parity) { + + if (encoded_parity) { for (i = 0; i < m; i++) { free(encoded_parity[i]); } - + free(encoded_parity); } @@ -471,7 +473,7 @@ out: * * @param desc - liberasurecode descriptor/handle * from liberasurecode_instance_create() - * @param data - (char *) buffer of data decoded by + * @param data - (char *) buffer of data decoded by * librasurecode_decode * @return 0 in success; -error otherwise */ @@ -560,7 +562,9 @@ int liberasurecode_decode(int desc, available_fragments, num_fragments, out_data, out_data_len); - if (ret == 0) { + /* shss (ntt_backend) must force to decode */ + // TODO: Add a frag and function to handle whether the backend want to decode or not. + if (ret == 0 && instance->common.id != 5) { /* We were able to get the original data without decoding! */ goto out; } @@ -573,20 +577,20 @@ int liberasurecode_decode(int desc, log_error("Could not allocate data buffer!"); goto out; } - + parity = alloc_zeroed_buffer(sizeof(char*) * m); if (NULL == parity) { log_error("Could not allocate parity buffer!"); goto out; } - + missing_idxs = alloc_and_set_buffer(sizeof(char*) * k, -1); if (NULL == missing_idxs) { log_error("Could not allocate missing_idxs buffer!"); goto out; } - /* If metadata checks requested, check fragment integrity upfront */ + /* If metadata checks requested, check fragment integrity upfront */ if (force_metadata_checks) { int num_invalid_fragments = 0; for (i = 0; i < num_fragments; ++i) { @@ -600,7 +604,7 @@ int liberasurecode_decode(int desc, goto out; } } - + /* * Separate the fragments into data and parity. Also determine which * pieces are missing. @@ -621,7 +625,7 @@ int liberasurecode_decode(int desc, * */ ret = prepare_fragments_for_decode(k, m, - data, parity, missing_idxs, + data, parity, missing_idxs, &orig_data_size, &blocksize, fragment_len, &realloc_bm); if (ret < 0) { @@ -638,20 +642,20 @@ int liberasurecode_decode(int desc, ret = instance->common.ops->decode(instance->desc.backend_desc, data_segments, parity_segments, missing_idxs, blocksize); - + if (ret < 0) { log_error("Encountered error in backend decode function!"); goto out; } /* - * Need to fill in the missing data headers so we can generate + * Need to fill in the missing data headers so we can generate * the original string. */ j = 0; - while (missing_idxs[j] >= 0) { + while (missing_idxs[j] >= 0) { int set_chksum = 1; - int missing_idx = missing_idxs[j]; + int missing_idx = missing_idxs[j]; if (missing_idx < k) { /* Generate headers */ char *fragment_ptr = data[missing_idx]; @@ -662,7 +666,7 @@ int liberasurecode_decode(int desc, } j++; } - + /* Try to generate the original string */ ret = fragments_to_string(k, m, data, k, out_data, out_data_len); @@ -745,10 +749,10 @@ int liberasurecode_reconstruct_fragment(int desc, ret = -1; goto out; } - + k = instance->args.uargs.k; m = instance->args.uargs.m; - + /* * Allocate arrays for data, parity and missing_idxs */ @@ -757,19 +761,19 @@ int liberasurecode_reconstruct_fragment(int desc, log_error("Could not allocate data buffer!"); goto out; } - + parity = alloc_zeroed_buffer(sizeof(char*) * m); if (NULL == parity) { log_error("Could not allocate parity buffer!"); goto out; } - + missing_idxs = alloc_and_set_buffer(sizeof(int*) * k, -1); if (NULL == missing_idxs) { log_error("Could not allocate missing_idxs buffer!"); goto out; } - + /* * Separate the fragments into data and parity. Also determine which * pieces are missing. @@ -863,7 +867,7 @@ out: * @desc: liberasurecode instance descriptor (obtained with * liberasurecode_instance_create) * @fragments_to_reconstruct list of indexes to reconstruct - * @fragments_to_exclude list of indexes to exclude from + * @fragments_to_exclude list of indexes to exclude from reconstruction equation * @fragments_needed list of fragments needed to reconstruct fragments in fragments_to_reconstruct @@ -872,7 +876,7 @@ out: * from (in 'fragments_needed') */ int liberasurecode_fragments_needed(int desc, - int *fragments_to_reconstruct, + int *fragments_to_reconstruct, int *fragments_to_exclude, int *fragments_needed) { @@ -1065,10 +1069,10 @@ int liberasurecode_verify_stripe_metadata(int desc, /* =~=*=~==~=*=~==~=*=~==~=*=~===~=*=~==~=*=~===~=*=~==~=*=~===~=*=~==~=*=~= */ /** - * This computes the aligned size of a buffer passed into + * This computes the aligned size of a buffer passed into * the encode function. The encode function must pad fragments * to be algined with the word size (w) and the last fragment also - * needs to be aligned. This computes the sum of the algined fragment + * needs to be aligned. This computes the sum of the algined fragment * sizes for a given buffer to encode. */ int liberasurecode_get_aligned_data_size(int desc, uint64_t data_len) @@ -1083,7 +1087,7 @@ int liberasurecode_get_aligned_data_size(int desc, uint64_t data_len) ret = -EBACKENDNOTAVAIL; goto out; } - + k = instance->args.uargs.k; word_size = instance->common.ops->element_size( @@ -1091,7 +1095,7 @@ int liberasurecode_get_aligned_data_size(int desc, uint64_t data_len) alignment_multiple = k * word_size; - ret = (int) ceill( (double) + ret = (int) ceill( (double) data_len / alignment_multiple) * alignment_multiple; out: -- cgit v1.2.1