summaryrefslogtreecommitdiffstats
path: root/xlators
diff options
context:
space:
mode:
authorXavier Hernandez <xhernandez@datalab.es>2017-01-13 13:54:35 +0100
committerJeff Darcy <jdarcy@redhat.com>2017-02-02 07:02:28 -0500
commitdb80efc8d5cc24597de636d8df2e5a9ce81d670d (patch)
tree1ee68e485a8d9dc70028a7e1afc19907d75df723 /xlators
parent85d7f1d1ee24ac400d4aa223478727643532693a (diff)
cluster/ec: fix selinux issues with mmap()
EC uses mmap() to create a memory area for the dynamic code. Since the code is created on the fly and executed when needed, this region of memory needs to have write and execution privileges. This combination is not allowed by default by selinux. To solve the problem a file is used as a backend storage for the dynamic code and it's mapped into two distinct memory regions, one with write access and the other one with execution access. This approach is the recommended way to create dynamic code by a program in a more secure way, and selinux allows it. Additionally selinux requires that the backend file be stored in a directory marked with type bin_t to be able to map it in an executable area. To satisfy this condition, GLUSTERFS_LIBEXECDIR has been used. This fix also changes the error check for mmap(), that was done incorrectly (it checked against NULL instead of MAP_FAILED), and it also correctly propagates the error codes and makes sure they aren't silently ignored. Change-Id: I71c2f88be4e4d795b6cfff96ab3799c362c54291 BUG: 1402661 Signed-off-by: Xavier Hernandez <xhernandez@datalab.es> Reviewed-on: https://review.gluster.org/16405 Smoke: Gluster Build System <jenkins@build.gluster.org> NetBSD-regression: NetBSD Build System <jenkins@build.gluster.org> CentOS-regression: Gluster Build System <jenkins@build.gluster.org> Reviewed-by: Jeff Darcy <jdarcy@redhat.com>
Diffstat (limited to 'xlators')
-rw-r--r--xlators/cluster/ec/src/Makefile.am1
-rw-r--r--xlators/cluster/ec/src/ec-code.c221
-rw-r--r--xlators/cluster/ec/src/ec-galois.c9
-rw-r--r--xlators/cluster/ec/src/ec-helpers.h4
-rw-r--r--xlators/cluster/ec/src/ec-inode-read.c6
-rw-r--r--xlators/cluster/ec/src/ec-messages.h16
-rw-r--r--xlators/cluster/ec/src/ec-method.c69
-rw-r--r--xlators/cluster/ec/src/ec-method.h25
-rw-r--r--xlators/cluster/ec/src/ec-types.h3
-rw-r--r--xlators/cluster/ec/src/ec.c12
10 files changed, 272 insertions, 94 deletions
diff --git a/xlators/cluster/ec/src/Makefile.am b/xlators/cluster/ec/src/Makefile.am
index 0cd34b58f3c..406a636bbc2 100644
--- a/xlators/cluster/ec/src/Makefile.am
+++ b/xlators/cluster/ec/src/Makefile.am
@@ -70,6 +70,7 @@ AM_CPPFLAGS += -I$(top_srcdir)/xlators/lib/src
AM_CPPFLAGS += -I$(top_srcdir)/rpc/rpc-lib/src
AM_CPPFLAGS += -I$(top_srcdir)/rpc/xdr/src
AM_CPPFLAGS += -I$(top_builddir)/rpc/xdr/src
+AM_CPPFLAGS += -DGLUSTERFS_LIBEXECDIR=\"$(GLUSTERFS_LIBEXECDIR)\"
AM_CFLAGS = -Wall $(GF_CFLAGS)
diff --git a/xlators/cluster/ec/src/ec-code.c b/xlators/cluster/ec/src/ec-code.c
index a1f652779f3..9647a08287c 100644
--- a/xlators/cluster/ec/src/ec-code.c
+++ b/xlators/cluster/ec/src/ec-code.c
@@ -20,6 +20,7 @@
#include "ec-code.h"
#include "ec-messages.h"
#include "ec-code-c.h"
+#include "ec-helpers.h"
#ifdef USE_EC_DYNAMIC_X64
#include "ec-code-x64.h"
@@ -33,6 +34,11 @@
#include "ec-code-avx.h"
#endif
+#define EC_CODE_SIZE (1024 * 64)
+#define EC_CODE_ALIGN 4096
+
+#define EC_CODE_CHUNK_MIN_SIZE 512
+
#define EC_PROC_BUFFER_SIZE 4096
#define PROC_CPUINFO "/proc/cpuinfo"
@@ -282,7 +288,7 @@ ec_code_prepare(ec_code_t *code, uint32_t count, uint32_t width,
builder = GF_MALLOC(sizeof(ec_code_builder_t) +
sizeof(ec_code_op_t) * count, ec_mt_ec_code_builder_t);
if (builder == NULL) {
- return NULL;
+ return EC_ERR(ENOMEM);
}
builder->address = 0;
@@ -323,15 +329,39 @@ ec_code_chunk_from_space(ec_code_space_t *space)
}
static void *
-ec_code_func_from_chunk(ec_code_chunk_t *chunk)
+ec_code_to_executable(ec_code_space_t *space, void *addr)
+{
+ return (void *)((uintptr_t)addr - (uintptr_t)space
+ + (uintptr_t)space->exec);
+}
+
+static void *
+ec_code_from_executable(ec_code_space_t *space, void *addr)
{
- return (void *)((uintptr_t)chunk + ec_code_chunk_size());
+ return (void *)((uintptr_t)addr - (uintptr_t)space->exec
+ + (uintptr_t)space);
+}
+
+static void *
+ec_code_func_from_chunk(ec_code_chunk_t *chunk, void **exec)
+{
+ void *addr;
+
+ addr = (void *)((uintptr_t)chunk + ec_code_chunk_size());
+
+ *exec = ec_code_to_executable(chunk->space, addr);
+
+ return addr;
}
static ec_code_chunk_t *
ec_code_chunk_from_func(ec_code_func_linear_t func)
{
- return (ec_code_chunk_t *)((uintptr_t)func - ec_code_chunk_size());
+ ec_code_chunk_t *chunk;
+
+ chunk = (ec_code_chunk_t *)((uintptr_t)func - ec_code_chunk_size());
+
+ return ec_code_from_executable(chunk->space, chunk);
}
static ec_code_chunk_t *
@@ -343,6 +373,7 @@ ec_code_chunk_split(ec_code_chunk_t *chunk, size_t size)
avail = chunk->size - size - ec_code_chunk_size();
if (avail > 0) {
extra = (ec_code_chunk_t *)((uintptr_t)chunk + chunk->size - avail);
+ extra->space = chunk->space;
extra->size = avail;
list_add(&extra->list, &chunk->list);
chunk->size = size;
@@ -361,18 +392,115 @@ ec_code_chunk_touch(ec_code_chunk_t *prev, ec_code_chunk_t *next)
return (end == (uintptr_t)next);
}
+static ec_code_space_t *
+ec_code_space_create(ec_code_t *code, size_t size)
+{
+ char path[] = GLUSTERFS_LIBEXECDIR "/ec-code-dynamic.XXXXXX";
+ ec_code_space_t *space;
+ void *exec;
+ int32_t fd, err;
+
+ /* We need to create memory areas to store the generated dynamic code.
+ * Obviously these areas need to be written to be able to create the
+ * code and they also need to be executable to execute it.
+ *
+ * However it's a bad practice to have a memory region that is both
+ * writable *and* executable. In fact, selinux forbids this and causes
+ * attempts to do so to fail (unless specifically configured).
+ *
+ * To solve the problem we'll use two distinct memory areas mapped to
+ * the same physical storage. One of the memory areas will have write
+ * permission, and the other will have execute permission. Both areas
+ * will have the same contents. The physical storage will be a regular
+ * file that will be mmapped to both areas.
+ */
+
+ /* We need to create a temporary file as the backend storage for the
+ * memory mapped areas. */
+ fd = mkstemp(path);
+ if (fd < 0) {
+ err = errno;
+ gf_msg(THIS->name, GF_LOG_ERROR, err, EC_MSG_DYN_CREATE_FAILED,
+ "Unable to create a temporary file for the ec dynamic "
+ "code");
+ space = EC_ERR(err);
+ goto done;
+ }
+ /* Once created we don't need to keep it in the file system. It will
+ * still exist until we close the last file descriptor or unmap the
+ * memory areas bound to the file. */
+ sys_unlink(path);
+
+ size = (size + EC_CODE_ALIGN - 1) & ~(EC_CODE_ALIGN - 1);
+ if (sys_ftruncate(fd, size) < 0) {
+ err = errno;
+ gf_msg(THIS->name, GF_LOG_ERROR, err, EC_MSG_DYN_CREATE_FAILED,
+ "Unable to resize the file for the ec dynamic code");
+ space = EC_ERR(err);
+ goto done_close;
+ }
+
+ /* This creates an executable memory area to be able to run the
+ * generated fragments of code. */
+ exec = mmap(NULL, size, PROT_READ | PROT_EXEC, MAP_SHARED, fd, 0);
+ if (exec == MAP_FAILED) {
+ err = errno;
+ gf_msg(THIS->name, GF_LOG_ERROR, err, EC_MSG_DYN_CREATE_FAILED,
+ "Unable to map the executable area for the ec dynamic "
+ "code");
+ space = EC_ERR(err);
+ goto done_close;
+ }
+ /* It's not important to check the return value of mlock(). If it fails
+ * everything will continue to work normally. */
+ mlock(exec, size);
+
+ /* This maps a read/write memory area to be able to create the dynamici
+ * code. */
+ space = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
+ if (space == MAP_FAILED) {
+ err = errno;
+ gf_msg(THIS->name, GF_LOG_ERROR, err, EC_MSG_DYN_CREATE_FAILED,
+ "Unable to map the writable area for the ec dynamic "
+ "code");
+ space = EC_ERR(err);
+
+ munmap(exec, size);
+
+ goto done_close;
+ }
+
+ space->exec = exec;
+ space->size = size;
+ space->code = code;
+ list_add_tail(&space->list, &code->spaces);
+ INIT_LIST_HEAD(&space->chunks);
+
+done_close:
+ /* If everything has succeeded, we already have the memory areas
+ * mapped. We don't need the file descriptor anymore because the
+ * backend storage will be there until the mmaped regions are
+ * unmapped. */
+ sys_close(fd);
+done:
+ return space;
+}
+
static void
-ec_code_chunk_merge(ec_code_chunk_t *chunk)
+ec_code_space_destroy(ec_code_space_t *space)
{
- ec_code_chunk_t *item;
+ list_del_init(&space->list);
- list_for_each_entry(item, &chunk->space->chunks, list) {
- if (ec_code_chunk_touch(item, chunk)) {
- item->size += chunk->size + ec_code_chunk_size();
- chunk = item;
+ munmap(space->exec, space->size);
+ munmap(space, space->size);
+}
- goto check;
- }
+static void
+ec_code_chunk_merge(ec_code_chunk_t *chunk)
+{
+ ec_code_chunk_t *item, *tmp;
+
+ list_for_each_entry_safe(item, tmp, &chunk->space->chunks, list) {
if ((uintptr_t)item > (uintptr_t)chunk) {
list_add_tail(&chunk->list, &item->list);
if (ec_code_chunk_touch(chunk, item)) {
@@ -382,15 +510,18 @@ ec_code_chunk_merge(ec_code_chunk_t *chunk)
goto check;
}
+ if (ec_code_chunk_touch(item, chunk)) {
+ item->size += chunk->size + ec_code_chunk_size();
+ list_del_init(&item->list);
+ chunk = item;
+ }
}
list_add_tail(&chunk->list, &chunk->space->chunks);
check:
- if (chunk->size == EC_CODE_SIZE - ec_code_space_size() -
- ec_code_chunk_size()) {
- list_del_init(&chunk->space->list);
-
- munmap(chunk->space, chunk->space->size);
+ if (chunk->size == chunk->space->size - ec_code_space_size() -
+ ec_code_chunk_size()) {
+ ec_code_space_destroy(chunk->space);
}
}
@@ -401,7 +532,10 @@ ec_code_space_alloc(ec_code_t *code, size_t size)
ec_code_chunk_t *chunk;
size_t map_size;
- size = (size + 15) & ~15;
+ /* To minimize fragmentation, we only allocate chunks of sizes multiples
+ * of EC_CODE_CHUNK_MIN_SIZE. */
+ size = ((size + ec_code_chunk_size() + EC_CODE_CHUNK_MIN_SIZE - 1) &
+ ~(EC_CODE_CHUNK_MIN_SIZE - 1)) - ec_code_chunk_size();
list_for_each_entry(space, &code->spaces, list) {
list_for_each_entry(chunk, &space->chunks, list) {
if (chunk->size >= size) {
@@ -410,26 +544,17 @@ ec_code_space_alloc(ec_code_t *code, size_t size)
}
}
- map_size = EC_CODE_SIZE;
+ map_size = EC_CODE_SIZE - ec_code_space_size() - ec_code_chunk_size();
if (map_size < size) {
map_size = size;
}
- space = mmap(NULL, map_size, PROT_EXEC | PROT_READ | PROT_WRITE,
- MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
- if (space == NULL) {
- return NULL;
+ space = ec_code_space_create(code, map_size);
+ if (EC_IS_ERR(space)) {
+ return (ec_code_chunk_t *)space;
}
- /* It's not important to check the return value of mlock(). If it fails
- * everything will continue to work normally. */
- mlock(space, map_size);
-
- space->code = code;
- space->size = map_size;
- list_add_tail(&space->list, &code->spaces);
- INIT_LIST_HEAD(&space->chunks);
chunk = ec_code_chunk_from_space(space);
- chunk->size = EC_CODE_SIZE - ec_code_space_size() - ec_code_chunk_size();
+ chunk->size = map_size - ec_code_space_size() - ec_code_chunk_size();
list_add(&chunk->list, &space->chunks);
out:
@@ -465,7 +590,7 @@ ec_code_free(ec_code_chunk_t *chunk)
UNLOCK(lock);
}
-static gf_boolean_t
+static int32_t
ec_code_write(ec_code_builder_t *builder)
{
ec_code_gen_t *gen;
@@ -506,7 +631,7 @@ ec_code_write(ec_code_builder_t *builder)
}
gen->epilog(builder);
- return builder->error == 0;
+ return builder->error;
}
static void *
@@ -514,22 +639,24 @@ ec_code_compile(ec_code_builder_t *builder)
{
ec_code_chunk_t *chunk;
void *func;
+ int32_t err;
- if (!ec_code_write(builder)) {
- return NULL;
+ err = ec_code_write(builder);
+ if (err != 0) {
+ return EC_ERR(err);
}
chunk = ec_code_alloc(builder->code, builder->size);
- if (chunk == NULL) {
- return NULL;
+ if (EC_IS_ERR(chunk)) {
+ return chunk;
}
- func = ec_code_func_from_chunk(chunk);
- builder->data = (uint8_t *)func;
+ builder->data = ec_code_func_from_chunk(chunk, &func);
- if (!ec_code_write(builder)) {
+ err = ec_code_write(builder);
+ if (err != 0) {
ec_code_free(chunk);
- return NULL;
+ return EC_ERR(err);
}
GF_FREE(builder);
@@ -544,7 +671,7 @@ ec_code_create(ec_gf_t *gf, ec_code_gen_t *gen)
code = GF_MALLOC(sizeof(ec_code_t), ec_mt_ec_code_t);
if (code == NULL) {
- return NULL;
+ return EC_ERR(ENOMEM);
}
memset(code, 0, sizeof(ec_code_t));
INIT_LIST_HEAD(&code->spaces);
@@ -589,7 +716,7 @@ ec_code_value_next(uint32_t *values, uint32_t count, uint32_t *offset)
return next;
}
-void *
+static void *
ec_code_build(ec_code_t *code, uint32_t width, uint32_t *values,
uint32_t count, gf_boolean_t linear)
{
@@ -606,8 +733,8 @@ ec_code_build(ec_code_t *code, uint32_t width, uint32_t *values,
}
builder = ec_code_prepare(code, count, width, linear);
- if (builder == NULL) {
- return NULL;
+ if (EC_IS_ERR(builder)) {
+ return builder;
}
offset = -1;
@@ -659,6 +786,8 @@ void
ec_code_error(ec_code_builder_t *builder, int32_t error)
{
if (builder->error == 0) {
+ gf_msg(THIS->name, GF_LOG_ERROR, error, EC_MSG_DYN_CODEGEN_FAILED,
+ "Failed to generate dynamic code");
builder->error = error;
}
}
diff --git a/xlators/cluster/ec/src/ec-galois.c b/xlators/cluster/ec/src/ec-galois.c
index 7dbbac09713..8cb4dc2e4e3 100644
--- a/xlators/cluster/ec/src/ec-galois.c
+++ b/xlators/cluster/ec/src/ec-galois.c
@@ -15,6 +15,7 @@
#include "ec-mem-types.h"
#include "ec-gf8.h"
+#include "ec-helpers.h"
static ec_gf_t *
ec_gf_alloc(uint32_t bits, uint32_t mod)
@@ -48,7 +49,7 @@ failed_log:
failed_gf:
GF_FREE(gf);
failed:
- return NULL;
+ return EC_ERR(ENOMEM);
}
static void
@@ -79,7 +80,7 @@ ec_gf_prepare(uint32_t bits, uint32_t mod)
uint32_t i, j;
if (bits != 8) {
- return NULL;
+ return EC_ERR(EINVAL);
}
tbl = ec_gf8_mul;
@@ -88,8 +89,8 @@ ec_gf_prepare(uint32_t bits, uint32_t mod)
}
gf = ec_gf_alloc(bits, mod);
- if (gf == NULL) {
- return NULL;
+ if (EC_IS_ERR(gf)) {
+ return gf;
}
ec_gf_init_tables(gf);
diff --git a/xlators/cluster/ec/src/ec-helpers.h b/xlators/cluster/ec/src/ec-helpers.h
index dfea6fef537..0b355bd440e 100644
--- a/xlators/cluster/ec/src/ec-helpers.h
+++ b/xlators/cluster/ec/src/ec-helpers.h
@@ -13,6 +13,10 @@
#include "ec-types.h"
+#define EC_ERR(_x) ((void *)-(intptr_t)(_x))
+#define EC_IS_ERR(_x) (((uintptr_t)(_x) & ~0xfffULL) == ~0xfffULL)
+#define EC_GET_ERR(_x) ((int32_t)(intptr_t)(_x))
+
#define EC_ALIGN_CHECK(_ptr, _align) \
((((uintptr_t)(_ptr)) & ((_align) - 1)) == 0)
diff --git a/xlators/cluster/ec/src/ec-inode-read.c b/xlators/cluster/ec/src/ec-inode-read.c
index 6752b675273..775b2baa043 100644
--- a/xlators/cluster/ec/src/ec-inode-read.c
+++ b/xlators/cluster/ec/src/ec-inode-read.c
@@ -1186,7 +1186,11 @@ int32_t ec_readv_rebuild(ec_t * ec, ec_fop_data_t * fop, ec_cbk_data_t * cbk)
goto out;
}
- ec_method_decode(&ec->matrix, fsize, cbk->mask, values, blocks, ptr);
+ err = ec_method_decode(&ec->matrix, fsize, cbk->mask, values, blocks,
+ ptr);
+ if (err != 0) {
+ goto out;
+ }
vector[0].iov_base = ptr + fop->head;
vector[0].iov_len = size - fop->head;
diff --git a/xlators/cluster/ec/src/ec-messages.h b/xlators/cluster/ec/src/ec-messages.h
index dcdf50b9503..b034e9f203a 100644
--- a/xlators/cluster/ec/src/ec-messages.h
+++ b/xlators/cluster/ec/src/ec-messages.h
@@ -45,7 +45,7 @@
*/
#define GLFS_EC_COMP_BASE GLFS_MSGID_COMP_EC
-#define GLFS_NUM_MESSAGES 73
+#define GLFS_NUM_MESSAGES 75
#define GLFS_MSGID_END (GLFS_EC_COMP_BASE + GLFS_NUM_MESSAGES + 1)
/* Messaged with message IDs */
#define glfs_msg_start_x GLFS_EC_COMP_BASE, "Invalid: Start of messages"
@@ -569,6 +569,20 @@
*/
#define EC_MSG_MATRIX_FAILED (GLFS_EC_COMP_BASE + 73)
+/*!
+ * @messageid
+ * @diagnosis
+ * @recommendedaction
+ */
+#define EC_MSG_DYN_CREATE_FAILED (GLFS_EC_COMP_BASE + 74)
+
+/*!
+ * @messageid
+ * @diagnosis
+ * @recommendedaction
+ */
+#define EC_MSG_DYN_CODEGEN_FAILED (GLFS_EC_COMP_BASE + 75)
+
/*------------*/
#define glfs_msg_end_x GLFS_MSGID_END, "Invalid: End of messages"
diff --git a/xlators/cluster/ec/src/ec-method.c b/xlators/cluster/ec/src/ec-method.c
index d1b122fb6a4..41bf0406ecb 100644
--- a/xlators/cluster/ec/src/ec-method.c
+++ b/xlators/cluster/ec/src/ec-method.c
@@ -16,6 +16,7 @@
#include "ec-galois.h"
#include "ec-code.h"
#include "ec-method.h"
+#include "ec-helpers.h"
static void
ec_method_matrix_normal(ec_gf_t *gf, uint32_t *matrix, uint32_t columns,
@@ -69,11 +70,12 @@ ec_method_matrix_inverse(ec_gf_t *gf, uint32_t *matrix, uint32_t *values,
}
}
-static gf_boolean_t
+static int32_t
ec_method_matrix_init(ec_matrix_list_t *list, ec_matrix_t *matrix,
uintptr_t mask, uint32_t *rows, gf_boolean_t inverse)
{
uint32_t i;
+ int32_t err = 0;
matrix->refs = 1;
matrix->mask = mask;
@@ -92,8 +94,10 @@ ec_method_matrix_init(ec_matrix_list_t *list, ec_matrix_t *matrix,
EC_METHOD_WORD_SIZE,
matrix->row_data[i].values,
matrix->columns);
- if (matrix->row_data[i].func.interleaved == NULL) {
- return _gf_false;
+ if (EC_IS_ERR(matrix->row_data[i].func.interleaved)) {
+ err = EC_GET_ERR(matrix->row_data[i].func.interleaved);
+ matrix->row_data[i].func.interleaved = NULL;
+ break;
}
}
} else {
@@ -106,13 +110,15 @@ ec_method_matrix_init(ec_matrix_list_t *list, ec_matrix_t *matrix,
ec_code_build_linear(matrix->code, EC_METHOD_WORD_SIZE,
matrix->row_data[i].values,
matrix->columns);
- if (matrix->row_data[i].func.linear == NULL) {
- return _gf_false;
+ if (EC_IS_ERR(matrix->row_data[i].func.linear)) {
+ err = EC_GET_ERR(matrix->row_data[i].func.linear);
+ matrix->row_data[i].func.linear = NULL;
+ break;
}
}
}
- return _gf_true;
+ return err;
}
static void
@@ -212,6 +218,7 @@ ec_method_matrix_get(ec_matrix_list_t *list, uintptr_t mask, uint32_t *rows)
{
ec_matrix_t *matrix;
uint32_t pos;
+ int32_t err = 0;
LOCK(&list->lock);
@@ -233,16 +240,17 @@ ec_method_matrix_get(ec_matrix_list_t *list, uintptr_t mask, uint32_t *rows)
} else {
matrix = mem_get0(list->pool);
if (matrix == NULL) {
+ matrix = EC_ERR(ENOMEM);
goto out;
}
matrix->values = (uint32_t *)((uintptr_t)matrix + sizeof(ec_matrix_t) +
sizeof(ec_matrix_row_t) * list->columns);
}
- if (!ec_method_matrix_init(list, matrix, mask, rows, _gf_true)) {
+ err = ec_method_matrix_init(list, matrix, mask, rows, _gf_true);
+ if (err != 0) {
ec_method_matrix_unref(list, matrix);
-
- matrix = NULL;
+ matrix = EC_ERR(err);
goto out;
}
@@ -269,18 +277,20 @@ ec_method_matrix_put(ec_matrix_list_t *list, ec_matrix_t *matrix)
UNLOCK(&list->lock);
}
-static gf_boolean_t
+static int32_t
ec_method_setup(xlator_t *xl, ec_matrix_list_t *list, const char *gen)
{
ec_matrix_t *matrix;
uint32_t values[list->rows];
uint32_t i;
+ int32_t err;
matrix = GF_MALLOC(sizeof(ec_matrix_t) +
sizeof(ec_matrix_row_t) * list->rows +
sizeof(uint32_t) * list->columns * list->rows,
ec_mt_ec_matrix_t);
if (matrix == NULL) {
+ err = -ENOMEM;
goto failed;
}
memset(matrix, 0, sizeof(ec_matrix_t));
@@ -288,7 +298,9 @@ ec_method_setup(xlator_t *xl, ec_matrix_list_t *list, const char *gen)
sizeof(ec_matrix_row_t) * list->rows);
list->code = ec_code_create(list->gf, ec_code_detect(xl, gen));
- if (list->code == NULL) {
+ if (EC_IS_ERR(list->code)) {
+ err = EC_GET_ERR(list->code);
+ list->code = NULL;
goto failed_matrix;
}
list->width = list->code->width;
@@ -296,23 +308,24 @@ ec_method_setup(xlator_t *xl, ec_matrix_list_t *list, const char *gen)
for (i = 0; i < list->rows; i++) {
values[i] = i + 1;
}
- if (!ec_method_matrix_init(list, matrix, 0, values, _gf_false)) {
+ err = ec_method_matrix_init(list, matrix, 0, values, _gf_false);
+ if (err != 0) {
goto failed_code;
}
list->encode = matrix;
- return _gf_true;
+ return 0;
failed_code:
ec_code_destroy(list->code);
failed_matrix:
GF_FREE(matrix);
failed:
- return _gf_false;
+ return err;
}
-gf_boolean_t
+int32_t
ec_method_init(xlator_t *xl, ec_matrix_list_t *list, uint32_t columns,
uint32_t rows, uint32_t max, const char *gen)
{
@@ -321,32 +334,37 @@ ec_method_init(xlator_t *xl, ec_matrix_list_t *list, uint32_t columns,
list->max = max;
list->stripe = EC_METHOD_CHUNK_SIZE * list->columns;
INIT_LIST_HEAD(&list->lru);
+ int32_t err;
list->pool = mem_pool_new_fn(sizeof(ec_matrix_t) +
sizeof(ec_matrix_row_t) * columns +
sizeof(uint32_t) * columns * columns,
128, "ec_matrix_t");
if (list->pool == NULL) {
+ err = -ENOMEM;
goto failed;
}
list->objects = GF_MALLOC(sizeof(ec_matrix_t *) * max, ec_mt_ec_matrix_t);
if (list->objects == NULL) {
+ err = -ENOMEM;
goto failed_pool;
}
list->gf = ec_gf_prepare(EC_GF_BITS, EC_GF_MOD);
- if (list->gf == NULL) {
+ if (EC_IS_ERR(list->gf)) {
+ err = EC_GET_ERR(list->gf);
goto failed_objects;
}
- if (!ec_method_setup(xl, list, gen)) {
+ err = ec_method_setup(xl, list, gen);
+ if (err != 0) {
goto failed_gf;
}
LOCK_INIT(&list->lock);
- return _gf_true;
+ return 0;
failed_gf:
ec_gf_destroy(list->gf);
@@ -358,7 +376,8 @@ failed:
list->pool = NULL;
list->objects = NULL;
list->gf = NULL;
- return _gf_false;
+
+ return err;
}
void
@@ -389,12 +408,12 @@ ec_method_fini(ec_matrix_list_t *list)
mem_pool_destroy(list->pool);
}
-gf_boolean_t
+int32_t
ec_method_update(xlator_t *xl, ec_matrix_list_t *list, const char *gen)
{
/* TODO: Allow changing code generator */
- return _gf_true;
+ return 0;
}
void
@@ -415,7 +434,7 @@ ec_method_encode(ec_matrix_list_t *list, size_t size, void *in, void **out)
}
}
-gf_boolean_t
+int32_t
ec_method_decode(ec_matrix_list_t *list, size_t size, uintptr_t mask,
uint32_t *rows, void **in, void *out)
{
@@ -424,8 +443,8 @@ ec_method_decode(ec_matrix_list_t *list, size_t size, uintptr_t mask,
uint32_t i;
matrix = ec_method_matrix_get(list, mask, rows);
- if (matrix == NULL) {
- return _gf_false;
+ if (EC_IS_ERR(matrix)) {
+ return EC_GET_ERR(matrix);
}
for (pos = 0; pos < size; pos += EC_METHOD_CHUNK_SIZE) {
for (i = 0; i < matrix->rows; i++) {
@@ -438,5 +457,5 @@ ec_method_decode(ec_matrix_list_t *list, size_t size, uintptr_t mask,
ec_method_matrix_put(list, matrix);
- return _gf_true;
+ return 0;
}
diff --git a/xlators/cluster/ec/src/ec-method.h b/xlators/cluster/ec/src/ec-method.h
index 818b54de872..9ba5069ff0e 100644
--- a/xlators/cluster/ec/src/ec-method.h
+++ b/xlators/cluster/ec/src/ec-method.h
@@ -30,17 +30,20 @@
#define EC_METHOD_CHUNK_SIZE (EC_METHOD_WORD_SIZE * EC_GF_BITS)
-gf_boolean_t ec_method_init(xlator_t *xl, ec_matrix_list_t *list,
- uint32_t columns, uint32_t rows, uint32_t max,
- const char *gen);
+int32_t
+ec_method_init(xlator_t *xl, ec_matrix_list_t *list, uint32_t columns,
+ uint32_t rows, uint32_t max, const char *gen);
+
void ec_method_fini(ec_matrix_list_t *list);
-gf_boolean_t ec_method_update(xlator_t *xl, ec_matrix_list_t *list,
- const char *gen);
-
-void ec_method_encode(ec_matrix_list_t *list, size_t size, void *in,
- void **out);
-gf_boolean_t ec_method_decode(ec_matrix_list_t *list, size_t size,
- uintptr_t mask, uint32_t *rows, void **in,
- void *out);
+
+int32_t
+ec_method_update(xlator_t *xl, ec_matrix_list_t *list, const char *gen);
+
+void
+ec_method_encode(ec_matrix_list_t *list, size_t size, void *in, void **out);
+
+int32_t
+ec_method_decode(ec_matrix_list_t *list, size_t size, uintptr_t mask,
+ uint32_t *rows, void **in, void *out);
#endif /* __EC_METHOD_H__ */
diff --git a/xlators/cluster/ec/src/ec-types.h b/xlators/cluster/ec/src/ec-types.h
index de13b2562f1..751652c20b1 100644
--- a/xlators/cluster/ec/src/ec-types.h
+++ b/xlators/cluster/ec/src/ec-types.h
@@ -17,8 +17,6 @@
#define EC_GF_MAX_REGS 16
-#define EC_CODE_SIZE (1024 * 64)
-
enum _ec_read_policy;
typedef enum _ec_read_policy ec_read_policy_t;
@@ -453,6 +451,7 @@ struct _ec_code_space {
struct list_head list;
struct list_head chunks;
ec_code_t *code;
+ void *exec;
size_t size;
};
diff --git a/xlators/cluster/ec/src/ec.c b/xlators/cluster/ec/src/ec.c
index 7b16f8fd255..e467fea28b8 100644
--- a/xlators/cluster/ec/src/ec.c
+++ b/xlators/cluster/ec/src/ec.c
@@ -266,6 +266,7 @@ reconfigure (xlator_t *this, dict_t *options)
uint32_t heal_wait_qlen = 0;
uint32_t background_heals = 0;
int32_t ret = -1;
+ int32_t err;
GF_OPTION_RECONF ("cpu-extensions", extensions, options, str, failed);
@@ -295,7 +296,8 @@ reconfigure (xlator_t *this, dict_t *options)
ret = -1;
}
- if (!ec_method_update(this, &ec->matrix, extensions)) {
+ err = ec_method_update(this, &ec->matrix, extensions);
+ if (err != 0) {
ret = -1;
}
@@ -588,6 +590,7 @@ init (xlator_t *this)
ec_t *ec = NULL;
char *read_policy = NULL;
char *extensions = NULL;
+ int32_t err;
if (this->parents == NULL)
{
@@ -644,9 +647,10 @@ init (xlator_t *this)
GF_OPTION_INIT("cpu-extensions", extensions, str, failed);
- if (!ec_method_init(this, &ec->matrix, ec->fragments, ec->nodes,
- ec->nodes * 2, extensions)) {
- gf_msg (this->name, GF_LOG_ERROR, 0, EC_MSG_MATRIX_FAILED,
+ err = ec_method_init(this, &ec->matrix, ec->fragments, ec->nodes,
+ ec->nodes * 2, extensions);
+ if (err != 0) {
+ gf_msg (this->name, GF_LOG_ERROR, -err, EC_MSG_MATRIX_FAILED,
"Failed to initialize matrix management");
goto failed;