diff options
Diffstat (limited to 'xlators/cluster/ec/src/ec-code.c')
-rw-r--r-- | xlators/cluster/ec/src/ec-code.c | 391 |
1 files changed, 198 insertions, 193 deletions
diff --git a/xlators/cluster/ec/src/ec-code.c b/xlators/cluster/ec/src/ec-code.c index e33cb42d9dc..70878d794ca 100644 --- a/xlators/cluster/ec/src/ec-code.c +++ b/xlators/cluster/ec/src/ec-code.c @@ -47,13 +47,13 @@ struct _ec_code_proc; typedef struct _ec_code_proc ec_code_proc_t; struct _ec_code_proc { - int32_t fd; + int32_t fd; gf_boolean_t eof; gf_boolean_t error; gf_boolean_t skip; - ssize_t size; - ssize_t pos; - char buffer[EC_PROC_BUFFER_SIZE]; + ssize_t size; + ssize_t pos; + char buffer[EC_PROC_BUFFER_SIZE]; }; static ec_code_gen_t *ec_code_gen_table[] = { @@ -66,8 +66,7 @@ static ec_code_gen_t *ec_code_gen_table[] = { #ifdef USE_EC_DYNAMIC_X64 &ec_code_gen_x64, #endif - NULL -}; + NULL}; static void ec_code_arg_set(ec_code_arg_t *arg, uint32_t value) @@ -84,7 +83,6 @@ ec_code_arg_assign(ec_code_builder_t *builder, ec_code_op_t *op, if (builder->regs <= reg) { builder->regs = reg + 1; } - } static void @@ -202,17 +200,17 @@ static void ec_code_dup(ec_code_builder_t *builder, ec_gf_op_t *op) { switch (op->op) { - case EC_GF_OP_COPY: - ec_code_copy(builder, op->arg1, op->arg2); - break; - case EC_GF_OP_XOR2: - ec_code_xor2(builder, op->arg1, op->arg2); - break; - case EC_GF_OP_XOR3: - ec_code_xor3(builder, op->arg1, op->arg2, op->arg3); - break; - default: - break; + case EC_GF_OP_COPY: + ec_code_copy(builder, op->arg1, op->arg2); + break; + case EC_GF_OP_XOR2: + ec_code_xor2(builder, op->arg1, op->arg2); + break; + case EC_GF_OP_XOR3: + ec_code_xor3(builder, op->arg1, op->arg2, op->arg3); + break; + default: + break; } } @@ -285,8 +283,9 @@ ec_code_prepare(ec_code_t *code, uint32_t count, uint32_t width, count *= code->gf->bits + code->gf->max_ops; count += code->gf->bits; - builder = GF_MALLOC(sizeof(ec_code_builder_t) + - sizeof(ec_code_op_t) * count, ec_mt_ec_code_builder_t); + builder = GF_MALLOC( + sizeof(ec_code_builder_t) + sizeof(ec_code_op_t) * count, + ec_mt_ec_code_builder_t); if (builder == NULL) { return EC_ERR(ENOMEM); } @@ -331,15 +330,15 @@ ec_code_chunk_from_space(ec_code_space_t *space) static void * ec_code_to_executable(ec_code_space_t *space, void *addr) { - return (void *)((uintptr_t)addr - (uintptr_t)space - + (uintptr_t)space->exec); + 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)addr - (uintptr_t)space->exec - + (uintptr_t)space); + return (void *)((uintptr_t)addr - (uintptr_t)space->exec + + (uintptr_t)space); } static void * @@ -395,105 +394,105 @@ ec_code_chunk_touch(ec_code_chunk_t *prev, ec_code_chunk_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. */ - /* coverity[secure_temp] mkstemp uses 0600 as the mode and is safe */ - 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; - } + 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. */ + /* coverity[secure_temp] mkstemp uses 0600 as the mode and is safe */ + 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; - } + /* 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); + 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 mmap()'d regions are - * unmapped. */ - sys_close(fd); + /* 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 mmap()'d regions are + * unmapped. */ + sys_close(fd); done: - return space; + return space; } static void ec_code_space_destroy(ec_code_space_t *space) { - list_del_init(&space->list); + list_del_init(&space->list); - munmap(space->exec, space->size); - munmap(space, space->size); + munmap(space->exec, space->size); + munmap(space, space->size); } static void @@ -501,7 +500,8 @@ 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) { + 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)) { @@ -520,8 +520,8 @@ ec_code_chunk_merge(ec_code_chunk_t *chunk) list_add_tail(&chunk->list, &chunk->space->chunks); check: - if (chunk->size == chunk->space->size - ec_code_space_size() - - ec_code_chunk_size()) { + if (chunk->size == + chunk->space->size - ec_code_space_size() - ec_code_chunk_size()) { ec_code_space_destroy(chunk->space); } } @@ -536,9 +536,12 @@ ec_code_space_alloc(ec_code_t *code, size_t size) /* 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) { + ~(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) { goto out; } @@ -608,26 +611,29 @@ ec_code_write(ec_code_builder_t *builder) for (i = 0; i < builder->count; i++) { op = &builder->ops[i]; switch (op->op) { - case EC_GF_OP_LOAD: - gen->load(builder, op->arg1.value, op->arg2.value, op->arg3.value); - break; - case EC_GF_OP_STORE: - gen->store(builder, op->arg1.value, op->arg3.value); - break; - case EC_GF_OP_COPY: - gen->copy(builder, op->arg1.value, op->arg2.value); - break; - case EC_GF_OP_XOR2: - gen->xor2(builder, op->arg1.value, op->arg2.value); - break; - case EC_GF_OP_XOR3: - gen->xor3(builder, op->arg1.value, op->arg2.value, op->arg3.value); - break; - case EC_GF_OP_XORM: - gen->xorm(builder, op->arg1.value, op->arg2.value, op->arg3.value); - break; - default: - break; + case EC_GF_OP_LOAD: + gen->load(builder, op->arg1.value, op->arg2.value, + op->arg3.value); + break; + case EC_GF_OP_STORE: + gen->store(builder, op->arg1.value, op->arg3.value); + break; + case EC_GF_OP_COPY: + gen->copy(builder, op->arg1.value, op->arg2.value); + break; + case EC_GF_OP_XOR2: + gen->xor2(builder, op->arg1.value, op->arg2.value); + break; + case EC_GF_OP_XOR3: + gen->xor3(builder, op->arg1.value, op->arg2.value, + op->arg3.value); + break; + case EC_GF_OP_XORM: + gen->xorm(builder, op->arg1.value, op->arg2.value, + op->arg3.value); + break; + default: + break; } } gen->epilog(builder); @@ -716,67 +722,65 @@ static void * ec_code_build_dynamic(ec_code_t *code, uint32_t width, uint32_t *values, uint32_t count, gf_boolean_t linear) { - ec_code_builder_t *builder; - uint32_t offset, val, next; + ec_code_builder_t *builder; + uint32_t offset, val, next; - builder = ec_code_prepare(code, count, width, linear); - if (EC_IS_ERR(builder)) { - return builder; - } + builder = ec_code_prepare(code, count, width, linear); + if (EC_IS_ERR(builder)) { + return builder; + } - offset = -1; - next = ec_code_value_next(values, count, &offset); - if (next != 0) { - ec_code_gf_load(builder, offset); - do { - val = next; - next = ec_code_value_next(values, count, &offset); - if (next != 0) { - ec_code_gf_mul(builder, ec_gf_div(code->gf, - val, next)); - ec_code_gf_load_xor(builder, offset); - } - } while (next != 0); - ec_code_gf_mul(builder, val); - ec_code_gf_store(builder); - } else { - ec_code_gf_clear(builder); - } + offset = -1; + next = ec_code_value_next(values, count, &offset); + if (next != 0) { + ec_code_gf_load(builder, offset); + do { + val = next; + next = ec_code_value_next(values, count, &offset); + if (next != 0) { + ec_code_gf_mul(builder, ec_gf_div(code->gf, val, next)); + ec_code_gf_load_xor(builder, offset); + } + } while (next != 0); + ec_code_gf_mul(builder, val); + ec_code_gf_store(builder); + } else { + ec_code_gf_clear(builder); + } - return ec_code_compile(builder); + return ec_code_compile(builder); } static void * -ec_code_build(ec_code_t *code, uint32_t width, uint32_t *values, - uint32_t count, gf_boolean_t linear) +ec_code_build(ec_code_t *code, uint32_t width, uint32_t *values, uint32_t count, + gf_boolean_t linear) { - void *func; + void *func; - if (code->gen != NULL) { - func = ec_code_build_dynamic(code, width, values, count, - linear); - if (!EC_IS_ERR(func)) { - return func; - } + if (code->gen != NULL) { + func = ec_code_build_dynamic(code, width, values, count, linear); + if (!EC_IS_ERR(func)) { + return func; + } - gf_msg_debug(THIS->name, GF_LOG_DEBUG, - "Unable to generate dynamic code. Falling back " - "to precompiled code"); + gf_msg_debug(THIS->name, GF_LOG_DEBUG, + "Unable to generate dynamic code. Falling back " + "to precompiled code"); - /* The dynamic code generation shouldn't fail in normal - * conditions, but if it fails at some point, it's very - * probable that it will fail again, so we completely disable - * dynamic code generation. */ - code->gen = NULL; - } + /* The dynamic code generation shouldn't fail in normal + * conditions, but if it fails at some point, it's very + * probable that it will fail again, so we completely disable + * dynamic code generation. */ + code->gen = NULL; + } - ec_code_c_prepare(code->gf, values, count); + ec_code_c_prepare(code->gf, values, count); - if (linear) { - return ec_code_c_linear; - } + if (linear) { + return ec_code_c_linear; + } - return ec_code_c_interleaved; + return ec_code_c_interleaved; } ec_code_func_linear_t @@ -791,17 +795,17 @@ ec_code_func_interleaved_t ec_code_build_interleaved(ec_code_t *code, uint32_t width, uint32_t *values, uint32_t count) { - return (ec_code_func_interleaved_t)ec_code_build(code, width, values, - count, _gf_false); + return (ec_code_func_interleaved_t)ec_code_build(code, width, values, count, + _gf_false); } void ec_code_release(ec_code_t *code, ec_code_func_t *func) { - if ((func->linear != ec_code_c_linear) && - (func->interleaved != ec_code_c_interleaved)) { - ec_code_free(ec_code_chunk_from_func(func->linear)); - } + if ((func->linear != ec_code_c_linear) && + (func->interleaved != ec_code_c_interleaved)) { + ec_code_free(ec_code_chunk_from_func(func->linear)); + } } void @@ -1003,7 +1007,8 @@ ec_code_detect(xlator_t *xl, const char *def) if (ec_code_gen_table[select] == NULL) { gf_msg(xl->name, GF_LOG_WARNING, EINVAL, EC_MSG_EXTENSION_UNKNOWN, "CPU extension '%s' is not known. Not using any cpu " - "extensions", def); + "extensions", + def); return NULL; } |