From ad112305a1c7452b13c92238b40ded80361838f3 Mon Sep 17 00:00:00 2001 From: Xavier Hernandez Date: Mon, 5 May 2014 12:57:34 +0200 Subject: cluster/ec: Added erasure code translator Change-Id: I293917501d5c2ca4cdc6303df30cf0b568cea361 BUG: 1118629 Signed-off-by: Xavier Hernandez Reviewed-on: http://review.gluster.org/7749 Reviewed-by: Krishnan Parthasarathi Reviewed-by: Jeff Darcy Tested-by: Gluster Build System Reviewed-by: Vijay Bellur --- xlators/cluster/ec/src/ec-generic.c | 1660 +++++++++++++++++++++++++++++++++++ 1 file changed, 1660 insertions(+) create mode 100644 xlators/cluster/ec/src/ec-generic.c (limited to 'xlators/cluster/ec/src/ec-generic.c') diff --git a/xlators/cluster/ec/src/ec-generic.c b/xlators/cluster/ec/src/ec-generic.c new file mode 100644 index 00000000000..49343388934 --- /dev/null +++ b/xlators/cluster/ec/src/ec-generic.c @@ -0,0 +1,1660 @@ +/* + Copyright (c) 2012 DataLab, s.l. + + This file is part of the cluster/ec translator for GlusterFS. + + The cluster/ec translator for GlusterFS is free software: you can + redistribute it and/or modify it under the terms of the GNU General + Public License as published by the Free Software Foundation, either + version 3 of the License, or (at your option) any later version. + + The cluster/ec translator for GlusterFS is distributed in the hope + that it will be useful, but WITHOUT ANY WARRANTY; without even the + implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with the cluster/ec translator for GlusterFS. If not, see + . +*/ + +#include "xlator.h" +#include "defaults.h" + +#include "ec-helpers.h" +#include "ec-common.h" +#include "ec-combine.h" +#include "ec-method.h" +#include "ec-fops.h" + +/* FOP: flush */ + +int32_t ec_flush_cbk(call_frame_t * frame, void * cookie, xlator_t * this, + int32_t op_ret, int32_t op_errno, dict_t * xdata) +{ + ec_fop_data_t * fop = NULL; + ec_cbk_data_t * cbk = NULL; + int32_t idx = (int32_t)(uintptr_t)cookie; + + VALIDATE_OR_GOTO(this, out); + GF_VALIDATE_OR_GOTO(this->name, frame, out); + GF_VALIDATE_OR_GOTO(this->name, frame->local, out); + GF_VALIDATE_OR_GOTO(this->name, this->private, out); + + fop = frame->local; + + ec_trace("CBK", fop, "idx=%d, frame=%p, op_ret=%d, op_errno=%d", idx, + frame, op_ret, op_errno); + + cbk = ec_cbk_data_allocate(frame, this, fop, GF_FOP_FLUSH, idx, op_ret, + op_errno); + if (cbk != NULL) + { + if (xdata != NULL) + { + cbk->xdata = dict_ref(xdata); + if (cbk->xdata == NULL) + { + gf_log(this->name, GF_LOG_ERROR, "Failed to reference a " + "dictionary."); + + goto out; + } + } + + ec_combine(cbk, NULL); + } + +out: + if (fop != NULL) + { + ec_complete(fop); + } + + return 0; +} + +void ec_wind_flush(ec_t * ec, ec_fop_data_t * fop, int32_t idx) +{ + ec_trace("WIND", fop, "idx=%d", idx); + + STACK_WIND_COOKIE(fop->frame, ec_flush_cbk, (void *)(uintptr_t)idx, + ec->xl_list[idx], ec->xl_list[idx]->fops->flush, fop->fd, + fop->xdata); +} + +int32_t ec_manager_flush(ec_fop_data_t * fop, int32_t state) +{ + ec_cbk_data_t * cbk; + + switch (state) + { + case EC_STATE_INIT: + case EC_STATE_LOCK: + ec_lock_fd(fop, fop->fd); + + return EC_STATE_DISPATCH; + + case EC_STATE_DISPATCH: + ec_dispatch_all(fop); + + return EC_STATE_PREPARE_ANSWER; + + case EC_STATE_PREPARE_ANSWER: + cbk = fop->answer; + if (cbk != NULL) + { + if (!ec_dict_combine(cbk, EC_COMBINE_XDATA)) + { + if (cbk->op_ret >= 0) + { + cbk->op_ret = -1; + cbk->op_errno = EIO; + } + } + if (cbk->op_ret < 0) + { + ec_fop_set_error(fop, cbk->op_errno); + } + } + else + { + ec_fop_set_error(fop, EIO); + } + + return EC_STATE_REPORT; + + case EC_STATE_REPORT: + cbk = fop->answer; + + GF_ASSERT(cbk != NULL); + + if (fop->cbks.flush != NULL) + { + fop->cbks.flush(fop->req_frame, fop, fop->xl, cbk->op_ret, + cbk->op_errno, cbk->xdata); + } + + return EC_STATE_UNLOCK; + + case -EC_STATE_LOCK: + case -EC_STATE_DISPATCH: + case -EC_STATE_PREPARE_ANSWER: + case -EC_STATE_REPORT: + GF_ASSERT(fop->error != 0); + + if (fop->cbks.flush != NULL) + { + fop->cbks.flush(fop->req_frame, fop, fop->xl, -1, fop->error, + NULL); + } + + return EC_STATE_UNLOCK; + + case -EC_STATE_UNLOCK: + case EC_STATE_UNLOCK: + ec_unlock(fop); + + return EC_STATE_END; + + default: + gf_log(fop->xl->name, GF_LOG_ERROR, "Unhandled state %d for %s", + state, ec_fop_name(fop->id)); + + return EC_STATE_END; + } +} + +void ec_flush(call_frame_t * frame, xlator_t * this, uintptr_t target, + int32_t minimum, fop_flush_cbk_t func, void * data, fd_t * fd, + dict_t * xdata) +{ + ec_cbk_t callback = { .flush = func }; + ec_fop_data_t * fop = NULL; + int32_t error = EIO; + + gf_log("ec", GF_LOG_TRACE, "EC(FLUSH) %p", frame); + + VALIDATE_OR_GOTO(this, out); + GF_VALIDATE_OR_GOTO(this->name, frame, out); + GF_VALIDATE_OR_GOTO(this->name, this->private, out); + + fop = ec_fop_data_allocate(frame, this, GF_FOP_FLUSH, EC_FLAG_UPDATE_FD, + target, minimum, ec_wind_flush, + ec_manager_flush, callback, data); + if (fop == NULL) + { + goto out; + } + + if (fd != NULL) + { + fop->fd = fd_ref(fd); + if (fop->fd == NULL) + { + gf_log(this->name, GF_LOG_ERROR, "Failed to reference a " + "file descriptor."); + + goto out; + } + } + if (xdata != NULL) + { + fop->xdata = dict_ref(xdata); + if (fop->xdata == NULL) + { + gf_log(this->name, GF_LOG_ERROR, "Failed to reference a " + "dictionary."); + + goto out; + } + } + + error = 0; + +out: + if (fop != NULL) + { + ec_manager(fop, error); + } + else + { + func(frame, NULL, this, -1, EIO, NULL); + } +} + +/* FOP: fsync */ + +int32_t ec_combine_fsync(ec_fop_data_t * fop, ec_cbk_data_t * dst, + ec_cbk_data_t * src) +{ + if (!ec_iatt_combine(dst->iatt, src->iatt, 2)) + { + gf_log(fop->xl->name, GF_LOG_NOTICE, "Mismatching iatt in " + "answers of 'GF_FOP_FSYNC'"); + + return 0; + } + + return 1; +} + +int32_t ec_fsync_cbk(call_frame_t * frame, void * cookie, xlator_t * this, + int32_t op_ret, int32_t op_errno, struct iatt * prebuf, + struct iatt * postbuf, dict_t * xdata) +{ + ec_fop_data_t * fop = NULL; + ec_cbk_data_t * cbk = NULL; + int32_t idx = (int32_t)(uintptr_t)cookie; + + VALIDATE_OR_GOTO(this, out); + GF_VALIDATE_OR_GOTO(this->name, frame, out); + GF_VALIDATE_OR_GOTO(this->name, frame->local, out); + GF_VALIDATE_OR_GOTO(this->name, this->private, out); + + fop = frame->local; + + ec_trace("CBK", fop, "idx=%d, frame=%p, op_ret=%d, op_errno=%d", idx, + frame, op_ret, op_errno); + + cbk = ec_cbk_data_allocate(frame, this, fop, GF_FOP_FSYNC, idx, op_ret, + op_errno); + if (cbk != NULL) + { + if (op_ret >= 0) + { + if (prebuf != NULL) + { + cbk->iatt[0] = *prebuf; + } + if (postbuf != NULL) + { + cbk->iatt[1] = *postbuf; + } + } + if (xdata != NULL) + { + cbk->xdata = dict_ref(xdata); + if (cbk->xdata == NULL) + { + gf_log(this->name, GF_LOG_ERROR, "Failed to reference a " + "dictionary."); + + goto out; + } + } + + ec_combine(cbk, ec_combine_fsync); + } + +out: + if (fop != NULL) + { + ec_complete(fop); + } + + return 0; +} + +void ec_wind_fsync(ec_t * ec, ec_fop_data_t * fop, int32_t idx) +{ + ec_trace("WIND", fop, "idx=%d", idx); + + STACK_WIND_COOKIE(fop->frame, ec_fsync_cbk, (void *)(uintptr_t)idx, + ec->xl_list[idx], ec->xl_list[idx]->fops->fsync, fop->fd, + fop->int32, fop->xdata); +} + +int32_t ec_manager_fsync(ec_fop_data_t * fop, int32_t state) +{ + ec_cbk_data_t * cbk; + + switch (state) + { + case EC_STATE_INIT: + case EC_STATE_LOCK: + ec_lock_fd(fop, fop->fd); + + return EC_STATE_GET_SIZE_AND_VERSION; + + case EC_STATE_GET_SIZE_AND_VERSION: + ec_get_size_version(fop); + + return EC_STATE_DISPATCH; + + case EC_STATE_DISPATCH: + ec_dispatch_all(fop); + + return EC_STATE_PREPARE_ANSWER; + + case EC_STATE_PREPARE_ANSWER: + cbk = fop->answer; + if (cbk != NULL) + { + if (!ec_dict_combine(cbk, EC_COMBINE_XDATA)) + { + if (cbk->op_ret >= 0) + { + cbk->op_ret = -1; + cbk->op_errno = EIO; + } + } + if (cbk->op_ret < 0) + { + ec_fop_set_error(fop, cbk->op_errno); + } + else + { + ec_iatt_rebuild(fop->xl->private, cbk->iatt, 2, + cbk->count); + + cbk->iatt[0].ia_size = fop->pre_size; + cbk->iatt[1].ia_size = fop->post_size; + } + } + else + { + ec_fop_set_error(fop, EIO); + } + + return EC_STATE_REPORT; + + case EC_STATE_REPORT: + cbk = fop->answer; + + GF_ASSERT(cbk != NULL); + + if (fop->cbks.fsync != NULL) + { + fop->cbks.fsync(fop->req_frame, fop, fop->xl, cbk->op_ret, + cbk->op_errno, &cbk->iatt[0], &cbk->iatt[1], + cbk->xdata); + } + + return EC_STATE_UNLOCK; + + case -EC_STATE_LOCK: + case -EC_STATE_GET_SIZE_AND_VERSION: + case -EC_STATE_DISPATCH: + case -EC_STATE_PREPARE_ANSWER: + case -EC_STATE_REPORT: + GF_ASSERT(fop->error != 0); + + if (fop->cbks.fsync != NULL) + { + fop->cbks.fsync(fop->req_frame, fop, fop->xl, -1, fop->error, + NULL, NULL, NULL); + } + + return EC_STATE_UNLOCK; + + case -EC_STATE_UNLOCK: + case EC_STATE_UNLOCK: + ec_unlock(fop); + + return EC_STATE_END; + + default: + gf_log(fop->xl->name, GF_LOG_ERROR, "Unhandled state %d for %s", + state, ec_fop_name(fop->id)); + + return EC_STATE_END; + } +} + +void ec_fsync(call_frame_t * frame, xlator_t * this, uintptr_t target, + int32_t minimum, fop_fsync_cbk_t func, void * data, fd_t * fd, + int32_t datasync, dict_t * xdata) +{ + ec_cbk_t callback = { .fsync = func }; + ec_fop_data_t * fop = NULL; + int32_t error = EIO; + + gf_log("ec", GF_LOG_TRACE, "EC(FSYNC) %p", frame); + + VALIDATE_OR_GOTO(this, out); + GF_VALIDATE_OR_GOTO(this->name, frame, out); + GF_VALIDATE_OR_GOTO(this->name, this->private, out); + + fop = ec_fop_data_allocate(frame, this, GF_FOP_FSYNC, EC_FLAG_UPDATE_FD, + target, minimum, ec_wind_fsync, + ec_manager_fsync, callback, data); + if (fop == NULL) + { + goto out; + } + + fop->int32 = datasync; + + if (fd != NULL) + { + fop->fd = fd_ref(fd); + if (fop->fd == NULL) + { + gf_log(this->name, GF_LOG_ERROR, "Failed to reference a " + "file descriptor."); + + goto out; + } + } + if (xdata != NULL) + { + fop->xdata = dict_ref(xdata); + if (fop->xdata == NULL) + { + gf_log(this->name, GF_LOG_ERROR, "Failed to reference a " + "dictionary."); + + goto out; + } + } + + error = 0; + +out: + if (fop != NULL) + { + ec_manager(fop, error); + } + else + { + func(frame, NULL, this, -1, EIO, NULL, NULL, NULL); + } +} + +/* FOP: fsyncdir */ + +int32_t ec_fsyncdir_cbk(call_frame_t * frame, void * cookie, xlator_t * this, + int32_t op_ret, int32_t op_errno, dict_t * xdata) +{ + ec_fop_data_t * fop = NULL; + ec_cbk_data_t * cbk = NULL; + int32_t idx = (int32_t)(uintptr_t)cookie; + + VALIDATE_OR_GOTO(this, out); + GF_VALIDATE_OR_GOTO(this->name, frame, out); + GF_VALIDATE_OR_GOTO(this->name, frame->local, out); + GF_VALIDATE_OR_GOTO(this->name, this->private, out); + + fop = frame->local; + + ec_trace("CBK", fop, "idx=%d, frame=%p, op_ret=%d, op_errno=%d", idx, + frame, op_ret, op_errno); + + cbk = ec_cbk_data_allocate(frame, this, fop, GF_FOP_FSYNCDIR, idx, op_ret, + op_errno); + if (cbk != NULL) + { + if (xdata != NULL) + { + cbk->xdata = dict_ref(xdata); + if (cbk->xdata == NULL) + { + gf_log(this->name, GF_LOG_ERROR, "Failed to reference a " + "dictionary."); + + goto out; + } + } + + ec_combine(cbk, NULL); + } + +out: + if (fop != NULL) + { + ec_complete(fop); + } + + return 0; +} + +void ec_wind_fsyncdir(ec_t * ec, ec_fop_data_t * fop, int32_t idx) +{ + ec_trace("WIND", fop, "idx=%d", idx); + + STACK_WIND_COOKIE(fop->frame, ec_fsyncdir_cbk, (void *)(uintptr_t)idx, + ec->xl_list[idx], ec->xl_list[idx]->fops->fsyncdir, + fop->fd, fop->int32, fop->xdata); +} + +int32_t ec_manager_fsyncdir(ec_fop_data_t * fop, int32_t state) +{ + ec_cbk_data_t * cbk; + + switch (state) + { + case EC_STATE_INIT: + case EC_STATE_LOCK: + ec_lock_fd(fop, fop->fd); + + return EC_STATE_DISPATCH; + + case EC_STATE_DISPATCH: + ec_dispatch_all(fop); + + return EC_STATE_PREPARE_ANSWER; + + case EC_STATE_PREPARE_ANSWER: + cbk = fop->answer; + if (cbk != NULL) + { + if (!ec_dict_combine(cbk, EC_COMBINE_XDATA)) + { + if (cbk->op_ret >= 0) + { + cbk->op_ret = -1; + cbk->op_errno = EIO; + } + } + if (cbk->op_ret < 0) + { + ec_fop_set_error(fop, cbk->op_errno); + } + } + else + { + ec_fop_set_error(fop, EIO); + } + + return EC_STATE_REPORT; + + case EC_STATE_REPORT: + cbk = fop->answer; + + GF_ASSERT(cbk != NULL); + + if (fop->cbks.fsyncdir != NULL) + { + fop->cbks.fsyncdir(fop->req_frame, fop, fop->xl, cbk->op_ret, + cbk->op_errno, cbk->xdata); + } + + return EC_STATE_UNLOCK; + + case -EC_STATE_LOCK: + case -EC_STATE_DISPATCH: + case -EC_STATE_PREPARE_ANSWER: + case -EC_STATE_REPORT: + GF_ASSERT(fop->error != 0); + + if (fop->cbks.fsyncdir != NULL) + { + fop->cbks.fsyncdir(fop->req_frame, fop, fop->xl, -1, + fop->error, NULL); + } + + return EC_STATE_UNLOCK; + + case -EC_STATE_UNLOCK: + case EC_STATE_UNLOCK: + ec_unlock(fop); + + return EC_STATE_END; + + default: + gf_log(fop->xl->name, GF_LOG_ERROR, "Unhandled state %d for %s", + state, ec_fop_name(fop->id)); + + return EC_STATE_END; + } +} + +void ec_fsyncdir(call_frame_t * frame, xlator_t * this, uintptr_t target, + int32_t minimum, fop_fsyncdir_cbk_t func, void * data, + fd_t * fd, int32_t datasync, dict_t * xdata) +{ + ec_cbk_t callback = { .fsyncdir = func }; + ec_fop_data_t * fop = NULL; + int32_t error = EIO; + + gf_log("ec", GF_LOG_TRACE, "EC(FSYNCDIR) %p", frame); + + VALIDATE_OR_GOTO(this, out); + GF_VALIDATE_OR_GOTO(this->name, frame, out); + GF_VALIDATE_OR_GOTO(this->name, this->private, out); + + fop = ec_fop_data_allocate(frame, this, GF_FOP_FSYNCDIR, EC_FLAG_UPDATE_FD, + target, minimum, ec_wind_fsyncdir, + ec_manager_fsyncdir, callback, data); + if (fop == NULL) + { + goto out; + } + + fop->int32 = datasync; + + if (fd != NULL) + { + fop->fd = fd_ref(fd); + if (fop->fd == NULL) + { + gf_log(this->name, GF_LOG_ERROR, "Failed to reference a " + "file descriptor."); + + goto out; + } + } + if (xdata != NULL) + { + fop->xdata = dict_ref(xdata); + if (fop->xdata == NULL) + { + gf_log(this->name, GF_LOG_ERROR, "Failed to reference a " + "dictionary."); + + goto out; + } + } + + error = 0; + +out: + if (fop != NULL) + { + ec_manager(fop, error); + } + else + { + func(frame, NULL, this, -1, EIO, NULL); + } +} + +/* FOP: lookup */ + +void ec_lookup_rebuild(ec_t * ec, ec_fop_data_t * fop, ec_cbk_data_t * cbk) +{ + ec_cbk_data_t * ans = NULL; + data_t * data = NULL; + uint8_t * ptr = NULL, * buff = NULL, * tmp = NULL; + size_t size = 0; + int32_t i = 0; + + if (cbk->op_ret < 0) + { + return; + } + + ec_dict_del_number(cbk->xdata, EC_XATTR_VERSION, &cbk->version); + + ec_loc_prepare(fop->xl, &fop->loc[0], cbk->inode, &cbk->iatt[0]); + + if (cbk->iatt[0].ia_type == IA_IFREG) + { + uint8_t * blocks[cbk->count]; + uint8_t * ptrs[cbk->count]; + uint32_t values[cbk->count]; + + cbk->size = cbk->iatt[0].ia_size; + ec_dict_del_number(cbk->xdata, EC_XATTR_SIZE, &cbk->iatt[0].ia_size); + + size = SIZE_MAX; + for (i = 0, ans = cbk; (ans != NULL) && (i < ec->fragments); + ans = ans->next) + { + data = dict_get(ans->xdata, GF_CONTENT_KEY); + if (data != NULL) + { + values[i] = ans->idx; + ptrs[i] = GF_MALLOC(data->len + EC_BUFFER_ALIGN_SIZE - 1, + gf_common_mt_char); + if (ptrs[i] == NULL) + { + continue; + } + + if (size > data->len) + { + size = data->len; + } + blocks[i] = GF_ALIGN_BUF(ptrs[i], EC_BUFFER_ALIGN_SIZE); + memcpy(blocks[i], data->data, size); + + i++; + } + } + + dict_del(cbk->xdata, GF_CONTENT_KEY); + + if (i >= ec->fragments) + { + size -= size % ec->fragment_size; + if (size > 0) + { + ptr = GF_MALLOC(size * ec->fragments + + EC_BUFFER_ALIGN_SIZE - 1, + gf_common_mt_char); + if (ptr != NULL) + { + buff = GF_ALIGN_BUF(ptr, EC_BUFFER_ALIGN_SIZE); + + size = ec_method_decode(size, ec->fragments, values, + blocks, buff); + if (size > fop->size) + { + size = fop->size; + } + if (size > cbk->iatt[0].ia_size) + { + size = cbk->iatt[0].ia_size; + } + + tmp = GF_MALLOC(size, gf_common_mt_char); + if (tmp != NULL) + { + memcpy(tmp, buff, size); + if (dict_set_bin(cbk->xdata, GF_CONTENT_KEY, tmp, + size) != 0) + { + GF_FREE(tmp); + + gf_log(fop->xl->name, GF_LOG_WARNING, "Lookup " + "read-ahead " + "failed"); + } + } + + GF_FREE(ptr); + } + else + { + gf_log(fop->xl->name, GF_LOG_WARNING, "Lookup read-ahead " + "failed"); + } + } + } + while (--i > 0) + { + GF_FREE(ptrs[i]); + } + } +} + +int32_t ec_combine_lookup(ec_fop_data_t * fop, ec_cbk_data_t * dst, + ec_cbk_data_t * src) +{ + if (!ec_iatt_combine(dst->iatt, src->iatt, 2)) + { + gf_log(fop->xl->name, GF_LOG_NOTICE, "Mismatching iatt in " + "answers of 'GF_FOP_LOOKUP'"); + + return 0; + } + + return 1; +} + +int32_t ec_lookup_cbk(call_frame_t * frame, void * cookie, xlator_t * this, + int32_t op_ret, int32_t op_errno, inode_t * inode, + struct iatt * buf, dict_t * xdata, + struct iatt * postparent) +{ + ec_fop_data_t * fop = NULL; + ec_cbk_data_t * cbk = NULL; + int32_t idx = (int32_t)(uintptr_t)cookie; + + VALIDATE_OR_GOTO(this, out); + GF_VALIDATE_OR_GOTO(this->name, frame, out); + GF_VALIDATE_OR_GOTO(this->name, frame->local, out); + GF_VALIDATE_OR_GOTO(this->name, this->private, out); + + fop = frame->local; + + ec_trace("CBK", fop, "idx=%d, frame=%p, op_ret=%d, op_errno=%d", idx, + frame, op_ret, op_errno); + + cbk = ec_cbk_data_allocate(frame, this, fop, GF_FOP_LOOKUP, idx, op_ret, + op_errno); + if (cbk != NULL) + { + if (op_ret >= 0) + { + if (inode != NULL) + { + cbk->inode = inode_ref(inode); + if (cbk->inode == NULL) + { + gf_log(this->name, GF_LOG_ERROR, + "Failed to reference an inode."); + + goto out; + } + } + if (buf != NULL) + { + cbk->iatt[0] = *buf; + } + if (postparent != NULL) + { + cbk->iatt[1] = *postparent; + } + } + if (xdata != NULL) + { + cbk->xdata = dict_ref(xdata); + if (cbk->xdata == NULL) + { + gf_log(this->name, GF_LOG_ERROR, "Failed to reference a " + "dictionary."); + + goto out; + } + } + + ec_combine(cbk, ec_combine_lookup); + } + +out: + if (fop != NULL) + { + ec_complete(fop); + } + + return 0; +} + +void ec_wind_lookup(ec_t * ec, ec_fop_data_t * fop, int32_t idx) +{ + ec_trace("WIND", fop, "idx=%d", idx); + + STACK_WIND_COOKIE(fop->frame, ec_lookup_cbk, (void *)(uintptr_t)idx, + ec->xl_list[idx], ec->xl_list[idx]->fops->lookup, + &fop->loc[0], fop->xdata); +} + +int32_t ec_manager_lookup(ec_fop_data_t * fop, int32_t state) +{ + ec_cbk_data_t * cbk; + + switch (state) + { + case EC_STATE_INIT: + if (fop->xdata == NULL) + { + fop->xdata = dict_new(); + if (fop->xdata == NULL) + { + gf_log(fop->xl->name, GF_LOG_ERROR, "Unable to prepare " + "lookup request"); + + fop->error = EIO; + + return EC_STATE_REPORT; + } + } + else + { + uint64_t size; + + if (dict_get_uint64(fop->xdata, GF_CONTENT_KEY, &size) == 0) + { + fop->size = size; + size = ec_adjust_size(fop->xl->private, size, 1); + if (dict_set_uint64(fop->xdata, GF_CONTENT_KEY, size) != 0) + { + gf_log("ec", GF_LOG_DEBUG, "Unable to update lookup " + "content size"); + } + } + } + if ((dict_set_uint64(fop->xdata, EC_XATTR_SIZE, 0) != 0) || + (dict_set_uint64(fop->xdata, EC_XATTR_VERSION, 0) != 0)) + { + gf_log(fop->xl->name, GF_LOG_ERROR, "Unable to prepare lookup " + "request"); + + fop->error = EIO; + + return EC_STATE_REPORT; + } + + case EC_STATE_DISPATCH: + ec_dispatch_all(fop); + + return EC_STATE_PREPARE_ANSWER; + + case EC_STATE_PREPARE_ANSWER: + cbk = fop->answer; + if (cbk != NULL) + { + if (!ec_dict_combine(cbk, EC_COMBINE_XDATA)) + { + if (cbk->op_ret >= 0) + { + cbk->op_ret = -1; + cbk->op_errno = EIO; + } + } + if (cbk->op_ret < 0) + { + ec_fop_set_error(fop, cbk->op_errno); + } + else + { + ec_iatt_rebuild(fop->xl->private, cbk->iatt, 2, + cbk->count); + + ec_lookup_rebuild(fop->xl->private, fop, cbk); + } + } + else + { + ec_fop_set_error(fop, EIO); + } + + return EC_STATE_REPORT; + + case EC_STATE_REPORT: + cbk = fop->answer; + + GF_ASSERT(cbk != NULL); + + if (fop->cbks.lookup != NULL) + { + fop->cbks.lookup(fop->req_frame, fop, fop->xl, cbk->op_ret, + cbk->op_errno, cbk->inode, &cbk->iatt[0], + cbk->xdata, &cbk->iatt[1]); + } + + return EC_STATE_END; + + case -EC_STATE_DISPATCH: + case -EC_STATE_PREPARE_ANSWER: + case -EC_STATE_REPORT: + GF_ASSERT(fop->error != 0); + + if (fop->cbks.lookup != NULL) + { + fop->cbks.lookup(fop->req_frame, fop, fop->xl, -1, fop->error, + NULL, NULL, NULL, NULL); + } + + return EC_STATE_END; + + default: + gf_log(fop->xl->name, GF_LOG_ERROR, "Unhandled state %d for %s", + state, ec_fop_name(fop->id)); + + return EC_STATE_END; + } +} + +void ec_lookup(call_frame_t * frame, xlator_t * this, uintptr_t target, + int32_t minimum, fop_lookup_cbk_t func, void * data, + loc_t * loc, dict_t * xdata) +{ + ec_cbk_t callback = { .lookup = func }; + ec_fop_data_t * fop = NULL; + int32_t error = EIO; + + gf_log("ec", GF_LOG_TRACE, "EC(LOOKUP) %p", frame); + + VALIDATE_OR_GOTO(this, out); + GF_VALIDATE_OR_GOTO(this->name, frame, out); + GF_VALIDATE_OR_GOTO(this->name, this->private, out); + + fop = ec_fop_data_allocate(frame, this, GF_FOP_LOOKUP, 0, target, minimum, + ec_wind_lookup, ec_manager_lookup, callback, + data); + if (fop == NULL) + { + goto out; + } + + if (loc != NULL) + { + if (loc_copy(&fop->loc[0], loc) != 0) + { + gf_log(this->name, GF_LOG_ERROR, "Failed to copy a location."); + + goto out; + } + } + if (xdata != NULL) + { + fop->xdata = dict_ref(xdata); + if (fop->xdata == NULL) + { + gf_log(this->name, GF_LOG_ERROR, "Failed to reference a " + "dictionary."); + + goto out; + } + } + + error = 0; + +out: + if (fop != NULL) + { + ec_manager(fop, error); + } + else + { + func(frame, NULL, this, -1, EIO, NULL, NULL, NULL, NULL); + } +} + +/* FOP: statfs */ + +int32_t ec_combine_statfs(ec_fop_data_t * fop, ec_cbk_data_t * dst, + ec_cbk_data_t * src) +{ + ec_statvfs_combine(&dst->statvfs, &src->statvfs); + + return 1; +} + +int32_t ec_statfs_cbk(call_frame_t * frame, void * cookie, xlator_t * this, + int32_t op_ret, int32_t op_errno, struct statvfs * buf, + dict_t * xdata) +{ + ec_fop_data_t * fop = NULL; + ec_cbk_data_t * cbk = NULL; + int32_t idx = (int32_t)(uintptr_t)cookie; + + VALIDATE_OR_GOTO(this, out); + GF_VALIDATE_OR_GOTO(this->name, frame, out); + GF_VALIDATE_OR_GOTO(this->name, frame->local, out); + GF_VALIDATE_OR_GOTO(this->name, this->private, out); + + fop = frame->local; + + ec_trace("CBK", fop, "idx=%d, frame=%p, op_ret=%d, op_errno=%d", idx, + frame, op_ret, op_errno); + + cbk = ec_cbk_data_allocate(frame, this, fop, GF_FOP_STATFS, idx, op_ret, + op_errno); + if (cbk != NULL) + { + if (op_ret >= 0) + { + if (buf != NULL) + { + cbk->statvfs = *buf; + } + } + if (xdata != NULL) + { + cbk->xdata = dict_ref(xdata); + if (cbk->xdata == NULL) + { + gf_log(this->name, GF_LOG_ERROR, "Failed to reference a " + "dictionary."); + + goto out; + } + } + + ec_combine(cbk, ec_combine_statfs); + } + +out: + if (fop != NULL) + { + ec_complete(fop); + } + + return 0; +} + +void ec_wind_statfs(ec_t * ec, ec_fop_data_t * fop, int32_t idx) +{ + ec_trace("WIND", fop, "idx=%d", idx); + + STACK_WIND_COOKIE(fop->frame, ec_statfs_cbk, (void *)(uintptr_t)idx, + ec->xl_list[idx], ec->xl_list[idx]->fops->statfs, + &fop->loc[0], fop->xdata); +} + +int32_t ec_manager_statfs(ec_fop_data_t * fop, int32_t state) +{ + ec_cbk_data_t * cbk; + + switch (state) + { + case EC_STATE_INIT: + case EC_STATE_DISPATCH: + ec_dispatch_all(fop); + + return EC_STATE_PREPARE_ANSWER; + + case EC_STATE_PREPARE_ANSWER: + cbk = fop->answer; + if (cbk != NULL) + { + if (!ec_dict_combine(cbk, EC_COMBINE_XDATA)) + { + if (cbk->op_ret >= 0) + { + cbk->op_ret = -1; + cbk->op_errno = EIO; + } + } + if (cbk->op_ret < 0) + { + ec_fop_set_error(fop, cbk->op_errno); + } + else + { + ec_t * ec = fop->xl->private; + + cbk->statvfs.f_blocks *= ec->fragments; + cbk->statvfs.f_bfree *= ec->fragments; + cbk->statvfs.f_bavail *= ec->fragments; + } + } + else + { + ec_fop_set_error(fop, EIO); + } + + return EC_STATE_REPORT; + + case EC_STATE_REPORT: + cbk = fop->answer; + + GF_ASSERT(cbk != NULL); + + if (fop->cbks.statfs != NULL) + { + fop->cbks.statfs(fop->req_frame, fop, fop->xl, cbk->op_ret, + cbk->op_errno, &cbk->statvfs, cbk->xdata); + } + + return EC_STATE_END; + + case -EC_STATE_DISPATCH: + case -EC_STATE_PREPARE_ANSWER: + case -EC_STATE_REPORT: + GF_ASSERT(fop->error != 0); + + if (fop->cbks.statfs != NULL) + { + fop->cbks.statfs(fop->req_frame, fop, fop->xl, -1, fop->error, + NULL, NULL); + } + + return EC_STATE_END; + + default: + gf_log(fop->xl->name, GF_LOG_ERROR, "Unhandled state %d for %s", + state, ec_fop_name(fop->id)); + + return EC_STATE_END; + } +} + +void ec_statfs(call_frame_t * frame, xlator_t * this, uintptr_t target, + int32_t minimum, fop_statfs_cbk_t func, void * data, + loc_t * loc, dict_t * xdata) +{ + ec_cbk_t callback = { .statfs = func }; + ec_fop_data_t * fop = NULL; + int32_t error = EIO; + + gf_log("ec", GF_LOG_TRACE, "EC(STATFS) %p", frame); + + VALIDATE_OR_GOTO(this, out); + GF_VALIDATE_OR_GOTO(this->name, frame, out); + GF_VALIDATE_OR_GOTO(this->name, this->private, out); + + fop = ec_fop_data_allocate(frame, this, GF_FOP_STATFS, 0, target, minimum, + ec_wind_statfs, ec_manager_statfs, callback, + data); + if (fop == NULL) + { + goto out; + } + + if (loc != NULL) + { + if (loc_copy(&fop->loc[0], loc) != 0) + { + gf_log(this->name, GF_LOG_ERROR, "Failed to copy a location."); + + goto out; + } + } + if (xdata != NULL) + { + fop->xdata = dict_ref(xdata); + if (fop->xdata == NULL) + { + gf_log(this->name, GF_LOG_ERROR, "Failed to reference a " + "dictionary."); + + goto out; + } + } + + error = 0; + +out: + if (fop != NULL) + { + ec_manager(fop, error); + } + else + { + func(frame, NULL, this, -1, EIO, NULL, NULL); + } +} + +/* FOP: xattrop */ + +int32_t ec_combine_xattrop(ec_fop_data_t * fop, ec_cbk_data_t * dst, + ec_cbk_data_t * src) +{ + if (!ec_dict_compare(dst->dict, src->dict)) + { + gf_log(fop->xl->name, GF_LOG_NOTICE, "Mismatching dictionary in " + "answers of 'GF_FOP_XATTROP'"); + + return 0; + } + + return 1; +} + +int32_t ec_xattrop_cbk(call_frame_t * frame, void * cookie, xlator_t * this, + int32_t op_ret, int32_t op_errno, dict_t * xattr, + dict_t * xdata) +{ + ec_fop_data_t * fop = NULL; + ec_cbk_data_t * cbk = NULL; + int32_t idx = (int32_t)(uintptr_t)cookie; + + VALIDATE_OR_GOTO(this, out); + GF_VALIDATE_OR_GOTO(this->name, frame, out); + GF_VALIDATE_OR_GOTO(this->name, frame->local, out); + GF_VALIDATE_OR_GOTO(this->name, this->private, out); + + fop = frame->local; + + ec_trace("CBK", fop, "idx=%d, frame=%p, op_ret=%d, op_errno=%d", idx, + frame, op_ret, op_errno); + + cbk = ec_cbk_data_allocate(frame, this, fop, GF_FOP_XATTROP, idx, op_ret, + op_errno); + if (cbk != NULL) + { + if (op_ret >= 0) + { + if (xattr != NULL) + { + cbk->dict = dict_ref(xattr); + if (cbk->dict == NULL) + { + gf_log(this->name, GF_LOG_ERROR, "Failed to reference a " + "dictionary."); + + goto out; + } + } + } + if (xdata != NULL) + { + cbk->xdata = dict_ref(xdata); + if (cbk->xdata == NULL) + { + gf_log(this->name, GF_LOG_ERROR, "Failed to reference a " + "dictionary."); + + goto out; + } + } + + ec_combine(cbk, ec_combine_xattrop); + } + +out: + if (fop != NULL) + { + ec_complete(fop); + } + + return 0; +} + +void ec_wind_xattrop(ec_t * ec, ec_fop_data_t * fop, int32_t idx) +{ + ec_trace("WIND", fop, "idx=%d", idx); + + STACK_WIND_COOKIE(fop->frame, ec_xattrop_cbk, (void *)(uintptr_t)idx, + ec->xl_list[idx], ec->xl_list[idx]->fops->xattrop, + &fop->loc[0], fop->xattrop_flags, fop->dict, fop->xdata); +} + +int32_t ec_manager_xattrop(ec_fop_data_t * fop, int32_t state) +{ + ec_cbk_data_t * cbk; + + switch (state) + { + case EC_STATE_INIT: + case EC_STATE_LOCK: + ec_lock_inode(fop, &fop->loc[0]); + + return EC_STATE_DISPATCH; + + case EC_STATE_DISPATCH: + ec_dispatch_all(fop); + + return EC_STATE_PREPARE_ANSWER; + + case EC_STATE_PREPARE_ANSWER: + cbk = fop->answer; + if (cbk != NULL) + { + if (!ec_dict_combine(cbk, EC_COMBINE_XDATA) || + ((cbk->op_ret >= 0) && !ec_dict_combine(cbk, + EC_COMBINE_DICT))) + { + if (cbk->op_ret >= 0) + { + cbk->op_ret = -1; + cbk->op_errno = EIO; + } + } + if (cbk->op_ret < 0) + { + ec_fop_set_error(fop, cbk->op_errno); + } + } + else + { + ec_fop_set_error(fop, EIO); + } + + return EC_STATE_REPORT; + + case EC_STATE_REPORT: + cbk = fop->answer; + + GF_ASSERT(cbk != NULL); + + if (fop->fd == NULL) + { + if (fop->cbks.xattrop != NULL) + { + fop->cbks.xattrop(fop->req_frame, fop, fop->xl, + cbk->op_ret, cbk->op_errno, cbk->dict, + cbk->xdata); + } + } + else + { + if (fop->cbks.fxattrop != NULL) + { + fop->cbks.fxattrop(fop->req_frame, fop, fop->xl, + cbk->op_ret, cbk->op_errno, cbk->dict, + cbk->xdata); + } + } + + if (cbk->op_ret >= 0) + { + return EC_STATE_UPDATE_SIZE_AND_VERSION; + } + return EC_STATE_UNLOCK; + + case -EC_STATE_LOCK: + case -EC_STATE_DISPATCH: + case -EC_STATE_PREPARE_ANSWER: + case -EC_STATE_REPORT: + GF_ASSERT(fop->error != 0); + + if (fop->fd == NULL) + { + if (fop->cbks.xattrop != NULL) + { + fop->cbks.xattrop(fop->req_frame, fop, fop->xl, -1, + fop->error, NULL, NULL); + } + } + else + { + if (fop->cbks.fxattrop != NULL) + { + fop->cbks.fxattrop(fop->req_frame, fop, fop->xl, -1, + fop->error, NULL, NULL); + } + } + + return EC_STATE_UNLOCK; + + case EC_STATE_UPDATE_SIZE_AND_VERSION: + ec_update_size_version(fop); + + return EC_STATE_UNLOCK; + + case -EC_STATE_UPDATE_SIZE_AND_VERSION: + case -EC_STATE_UNLOCK: + case EC_STATE_UNLOCK: + ec_unlock(fop); + + return EC_STATE_END; + + default: + gf_log(fop->xl->name, GF_LOG_ERROR, "Unhandled state %d for %s", + state, ec_fop_name(fop->id)); + + return EC_STATE_END; + } +} + +void ec_xattrop(call_frame_t * frame, xlator_t * this, uintptr_t target, + int32_t minimum, fop_xattrop_cbk_t func, void * data, + loc_t * loc, gf_xattrop_flags_t optype, dict_t * xattr, + dict_t * xdata) +{ + ec_cbk_t callback = { .xattrop = func }; + ec_fop_data_t * fop = NULL; + int32_t error = EIO; + + gf_log("ec", GF_LOG_TRACE, "EC(XATTROP) %p", frame); + + VALIDATE_OR_GOTO(this, out); + GF_VALIDATE_OR_GOTO(this->name, frame, out); + GF_VALIDATE_OR_GOTO(this->name, this->private, out); + + fop = ec_fop_data_allocate(frame, this, GF_FOP_XATTROP, + EC_FLAG_UPDATE_LOC_INODE, target, minimum, + ec_wind_xattrop, ec_manager_xattrop, callback, + data); + if (fop == NULL) + { + goto out; + } + + fop->xattrop_flags = optype; + + if (loc != NULL) + { + if (loc_copy(&fop->loc[0], loc) != 0) + { + gf_log(this->name, GF_LOG_ERROR, "Failed to copy a location."); + + goto out; + } + } + if (xattr != NULL) + { + fop->dict = dict_ref(xattr); + if (fop->dict == NULL) + { + gf_log(this->name, GF_LOG_ERROR, "Failed to reference a " + "dictionary."); + + goto out; + } + } + if (xdata != NULL) + { + fop->xdata = dict_ref(xdata); + if (fop->xdata == NULL) + { + gf_log(this->name, GF_LOG_ERROR, "Failed to reference a " + "dictionary."); + + goto out; + } + } + + error = 0; + +out: + if (fop != NULL) + { + ec_manager(fop, error); + } + else + { + func(frame, NULL, this, -1, EIO, NULL, NULL); + } +} + +/* FOP: fxattrop */ + +int32_t ec_fxattrop_cbk(call_frame_t * frame, void * cookie, xlator_t * this, + int32_t op_ret, int32_t op_errno, dict_t * xattr, + dict_t * xdata) +{ + ec_fop_data_t * fop = NULL; + ec_cbk_data_t * cbk = NULL; + int32_t idx = (int32_t)(uintptr_t)cookie; + + VALIDATE_OR_GOTO(this, out); + GF_VALIDATE_OR_GOTO(this->name, frame, out); + GF_VALIDATE_OR_GOTO(this->name, frame->local, out); + GF_VALIDATE_OR_GOTO(this->name, this->private, out); + + fop = frame->local; + + ec_trace("CBK", fop, "idx=%d, frame=%p, op_ret=%d, op_errno=%d", idx, + frame, op_ret, op_errno); + + cbk = ec_cbk_data_allocate(frame, this, fop, GF_FOP_FXATTROP, idx, op_ret, + op_errno); + if (cbk != NULL) + { + if (op_ret >= 0) + { + if (xattr != NULL) + { + cbk->dict = dict_ref(xattr); + if (cbk->dict == NULL) + { + gf_log(this->name, GF_LOG_ERROR, "Failed to reference a " + "dictionary."); + + goto out; + } + } + } + if (xdata != NULL) + { + cbk->xdata = dict_ref(xdata); + if (cbk->xdata == NULL) + { + gf_log(this->name, GF_LOG_ERROR, "Failed to reference a " + "dictionary."); + + goto out; + } + } + + ec_combine(cbk, ec_combine_xattrop); + } + +out: + if (fop != NULL) + { + ec_complete(fop); + } + + return 0; +} + +void ec_wind_fxattrop(ec_t * ec, ec_fop_data_t * fop, int32_t idx) +{ + ec_trace("WIND", fop, "idx=%d", idx); + + STACK_WIND_COOKIE(fop->frame, ec_fxattrop_cbk, (void *)(uintptr_t)idx, + ec->xl_list[idx], ec->xl_list[idx]->fops->fxattrop, + fop->fd, fop->xattrop_flags, fop->dict, fop->xdata); +} + +void ec_fxattrop(call_frame_t * frame, xlator_t * this, uintptr_t target, + int32_t minimum, fop_fxattrop_cbk_t func, void * data, + fd_t * fd, gf_xattrop_flags_t optype, dict_t * xattr, + dict_t * xdata) +{ + ec_cbk_t callback = { .fxattrop = func }; + ec_fop_data_t * fop = NULL; + int32_t error = EIO; + + gf_log("ec", GF_LOG_TRACE, "EC(FXATTROP) %p", frame); + + VALIDATE_OR_GOTO(this, out); + GF_VALIDATE_OR_GOTO(this->name, frame, out); + GF_VALIDATE_OR_GOTO(this->name, this->private, out); + + fop = ec_fop_data_allocate(frame, this, GF_FOP_FXATTROP, + EC_FLAG_UPDATE_FD_INODE, target, minimum, + ec_wind_fxattrop, ec_manager_xattrop, callback, + data); + if (fop == NULL) + { + goto out; + } + + fop->xattrop_flags = optype; + + if (fd != NULL) + { + fop->fd = fd_ref(fd); + if (fop->fd == NULL) + { + gf_log(this->name, GF_LOG_ERROR, "Failed to reference a " + "file descriptor."); + + goto out; + } + } + if (xattr != NULL) + { + fop->dict = dict_ref(xattr); + if (fop->dict == NULL) + { + gf_log(this->name, GF_LOG_ERROR, "Failed to reference a " + "dictionary."); + + goto out; + } + } + if (xdata != NULL) + { + fop->xdata = dict_ref(xdata); + if (fop->xdata == NULL) + { + gf_log(this->name, GF_LOG_ERROR, "Failed to reference a " + "dictionary."); + + goto out; + } + } + + error = 0; + +out: + if (fop != NULL) + { + ec_manager(fop, error); + } + else + { + func(frame, NULL, this, -1, EIO, NULL, NULL); + } +} -- cgit