diff options
author | Xavier Hernandez <xhernandez@datalab.es> | 2014-05-05 12:57:34 +0200 |
---|---|---|
committer | Vijay Bellur <vbellur@redhat.com> | 2014-07-11 10:33:40 -0700 |
commit | ad112305a1c7452b13c92238b40ded80361838f3 (patch) | |
tree | 82dbf9aa0b77eb76d43c8b1ccb3ba58e61bc4e2a /xlators/cluster/ec/src/ec-inode-read.c | |
parent | 6b4702897bd56e29db4db06f8cf896f89df1133c (diff) |
cluster/ec: Added erasure code translator
Change-Id: I293917501d5c2ca4cdc6303df30cf0b568cea361
BUG: 1118629
Signed-off-by: Xavier Hernandez <xhernandez@datalab.es>
Reviewed-on: http://review.gluster.org/7749
Reviewed-by: Krishnan Parthasarathi <kparthas@redhat.com>
Reviewed-by: Jeff Darcy <jdarcy@redhat.com>
Tested-by: Gluster Build System <jenkins@build.gluster.com>
Reviewed-by: Vijay Bellur <vbellur@redhat.com>
Diffstat (limited to 'xlators/cluster/ec/src/ec-inode-read.c')
-rw-r--r-- | xlators/cluster/ec/src/ec-inode-read.c | 1764 |
1 files changed, 1764 insertions, 0 deletions
diff --git a/xlators/cluster/ec/src/ec-inode-read.c b/xlators/cluster/ec/src/ec-inode-read.c new file mode 100644 index 00000000000..b1db9c9fbb7 --- /dev/null +++ b/xlators/cluster/ec/src/ec-inode-read.c @@ -0,0 +1,1764 @@ + +/* + Copyright (c) 2012 DataLab, s.l. <http://www.datalab.es> + + 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 + <http://www.gnu.org/licenses/>. +*/ + +#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: access */ + +int32_t ec_access_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; + 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); + + if (!ec_dispatch_one_retry(fop, idx, op_ret, op_errno)) + { + if (fop->cbks.access != NULL) + { + fop->cbks.access(fop->req_frame, fop, this, op_ret, op_errno, + xdata); + } + } + +out: + if (fop != NULL) + { + ec_complete(fop); + } + + return 0; +} + +void ec_wind_access(ec_t * ec, ec_fop_data_t * fop, int32_t idx) +{ + ec_trace("WIND", fop, "idx=%d", idx); + + STACK_WIND_COOKIE(fop->frame, ec_access_cbk, (void *)(uintptr_t)idx, + ec->xl_list[idx], ec->xl_list[idx]->fops->access, + &fop->loc[0], fop->int32, fop->xdata); +} + +int32_t ec_manager_access(ec_fop_data_t * fop, int32_t state) +{ + switch (state) + { + case EC_STATE_INIT: + case EC_STATE_DISPATCH: + ec_dispatch_one(fop); + + return EC_STATE_PREPARE_ANSWER; + + case -EC_STATE_REPORT: + if (fop->cbks.access != NULL) + { + fop->cbks.access(fop->req_frame, fop, fop->xl, -1, fop->error, + NULL); + } + + case EC_STATE_REPORT: + 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_access(call_frame_t * frame, xlator_t * this, uintptr_t target, + int32_t minimum, fop_access_cbk_t func, void * data, + loc_t * loc, int32_t mask, dict_t * xdata) +{ + ec_cbk_t callback = { .access = func }; + ec_fop_data_t * fop = NULL; + int32_t error = EIO; + + gf_log("ec", GF_LOG_TRACE, "EC(ACCESS) %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_ACCESS, 0, target, minimum, + ec_wind_access, ec_manager_access, callback, + data); + if (fop == NULL) + { + goto out; + } + + fop->int32 = mask; + + 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); + } +} + +/* FOP: getxattr */ + +int32_t ec_combine_getxattr(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_GETXATTR'"); + + return 0; + } + + return 1; +} + +int32_t ec_getxattr_cbk(call_frame_t * frame, void * cookie, xlator_t * this, + int32_t op_ret, int32_t op_errno, dict_t * dict, + 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_GETXATTR, idx, op_ret, + op_errno); + if (cbk != NULL) + { + if (op_ret >= 0) + { + if (dict != NULL) + { + cbk->dict = dict_ref(dict); + 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_getxattr); + } + +out: + if (fop != NULL) + { + ec_complete(fop); + } + + return 0; +} + +void ec_wind_getxattr(ec_t * ec, ec_fop_data_t * fop, int32_t idx) +{ + ec_trace("WIND", fop, "idx=%d", idx); + + STACK_WIND_COOKIE(fop->frame, ec_getxattr_cbk, (void *)(uintptr_t)idx, + ec->xl_list[idx], ec->xl_list[idx]->fops->getxattr, + &fop->loc[0], fop->str[0], fop->xdata); +} + +int32_t ec_manager_getxattr(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 + { + if (cbk->xdata != NULL) + { + dict_del(cbk->xdata, EC_XATTR_SIZE); + dict_del(cbk->xdata, EC_XATTR_VERSION); + } + if (cbk->dict != NULL) + { + dict_del(cbk->dict, EC_XATTR_SIZE); + dict_del(cbk->dict, EC_XATTR_VERSION); + } + } + } + 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.getxattr != NULL) + { + fop->cbks.getxattr(fop->req_frame, fop, fop->xl, cbk->op_ret, + cbk->op_errno, cbk->dict, 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.getxattr != NULL) + { + fop->cbks.getxattr(fop->req_frame, fop, fop->xl, -1, + fop->error, 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_getxattr(call_frame_t * frame, xlator_t * this, uintptr_t target, + int32_t minimum, fop_getxattr_cbk_t func, void * data, + loc_t * loc, const char * name, dict_t * xdata) +{ + ec_cbk_t callback = { .getxattr = func }; + ec_fop_data_t * fop = NULL; + int32_t error = EIO; + + gf_log("ec", GF_LOG_TRACE, "EC(GETXATTR) %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_GETXATTR, + EC_FLAG_UPDATE_LOC_INODE, target, minimum, + ec_wind_getxattr, ec_manager_getxattr, 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 (name != NULL) + { + fop->str[0] = gf_strdup(name); + if (fop->str[0] == NULL) + { + gf_log(this->name, GF_LOG_ERROR, "Failed to duplicate a string."); + + 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: fgetxattr */ + +int32_t ec_fgetxattr_cbk(call_frame_t * frame, void * cookie, xlator_t * this, + int32_t op_ret, int32_t op_errno, dict_t * dict, + 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_FGETXATTR, idx, op_ret, + op_errno); + if (cbk != NULL) + { + if (op_ret >= 0) + { + if (dict != NULL) + { + cbk->dict = dict_ref(dict); + 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_getxattr); + } + +out: + if (fop != NULL) + { + ec_complete(fop); + } + + return 0; +} + +void ec_wind_fgetxattr(ec_t * ec, ec_fop_data_t * fop, int32_t idx) +{ + ec_trace("WIND", fop, "idx=%d", idx); + + STACK_WIND_COOKIE(fop->frame, ec_fgetxattr_cbk, (void *)(uintptr_t)idx, + ec->xl_list[idx], ec->xl_list[idx]->fops->fgetxattr, + fop->fd, fop->str[0], fop->xdata); +} + +void ec_fgetxattr(call_frame_t * frame, xlator_t * this, uintptr_t target, + int32_t minimum, fop_fgetxattr_cbk_t func, void * data, + fd_t * fd, const char * name, dict_t * xdata) +{ + ec_cbk_t callback = { .fgetxattr = func }; + ec_fop_data_t * fop = NULL; + int32_t error = EIO; + + gf_log("ec", GF_LOG_TRACE, "EC(FGETXATTR) %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_FGETXATTR, + EC_FLAG_UPDATE_FD_INODE, target, minimum, + ec_wind_fgetxattr, ec_manager_getxattr, + 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 (name != NULL) + { + fop->str[0] = gf_strdup(name); + if (fop->str[0] == NULL) + { + gf_log(this->name, GF_LOG_ERROR, "Failed to duplicate a string."); + + 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: open */ + +int32_t ec_combine_open(ec_fop_data_t * fop, ec_cbk_data_t * dst, + ec_cbk_data_t * src) +{ + if (dst->fd != src->fd) + { + gf_log(fop->xl->name, GF_LOG_NOTICE, "Mismatching fd in answers " + "of 'GF_FOP_OPEN': %p <-> %p", + dst->fd, src->fd); + + return 0; + } + + return 1; +} + +int32_t ec_open_cbk(call_frame_t * frame, void * cookie, xlator_t * this, + int32_t op_ret, int32_t op_errno, fd_t * fd, + 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_OPEN, idx, op_ret, + op_errno); + if (cbk != NULL) + { + if (op_ret >= 0) + { + if (fd != NULL) + { + cbk->fd = fd_ref(fd); + if (cbk->fd == NULL) + { + gf_log(this->name, GF_LOG_ERROR, "Failed to reference a " + "file descriptor."); + + 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_open); + } + +out: + if (fop != NULL) + { + ec_complete(fop); + } + + return 0; +} + +void ec_wind_open(ec_t * ec, ec_fop_data_t * fop, int32_t idx) +{ + ec_trace("WIND", fop, "idx=%d", idx); + + STACK_WIND_COOKIE(fop->frame, ec_open_cbk, (void *)(uintptr_t)idx, + ec->xl_list[idx], ec->xl_list[idx]->fops->open, + &fop->loc[0], fop->int32, fop->fd, fop->xdata); +} + +int32_t ec_manager_open(ec_fop_data_t * fop, int32_t state) +{ + ec_cbk_data_t * cbk; + ec_fd_t * ctx; + + switch (state) + { + case EC_STATE_INIT: + LOCK(&fop->fd->lock); + + ctx = __ec_fd_get(fop->fd, fop->xl); + if ((ctx == NULL) || !ec_loc_from_loc(fop->xl, &ctx->loc, + &fop->loc[0])) + { + UNLOCK(&fop->fd->lock); + + fop->error = EIO; + + return EC_STATE_REPORT; + } + + if (ctx->flags == 0) + { + ctx->flags = fop->int32; + } + + UNLOCK(&fop->fd->lock); + + if ((fop->int32 & O_ACCMODE) == O_WRONLY) + { + fop->int32 &= ~O_ACCMODE; + fop->int32 |= O_RDWR; + } + + 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_loc_prepare(fop->xl, &fop->loc[0], cbk->fd->inode, + NULL); + + LOCK(&fop->fd->lock); + + ctx = __ec_fd_get(fop->fd, fop->xl); + if (ctx != NULL) + { + ctx->open |= cbk->mask; + } + + UNLOCK(&fop->fd->lock); + } + } + 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.open != NULL) + { + fop->cbks.open(fop->req_frame, fop, fop->xl, cbk->op_ret, + cbk->op_errno, cbk->fd, 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.open != NULL) + { + fop->cbks.open(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_open(call_frame_t * frame, xlator_t * this, uintptr_t target, + int32_t minimum, fop_open_cbk_t func, void * data, loc_t * loc, + int32_t flags, fd_t * fd, dict_t * xdata) +{ + ec_cbk_t callback = { .open = func }; + ec_fop_data_t * fop = NULL; + int32_t error = EIO; + + gf_log("ec", GF_LOG_TRACE, "EC(OPEN) %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_OPEN, EC_FLAG_UPDATE_FD, + target, minimum, ec_wind_open, ec_manager_open, + callback, data); + if (fop == NULL) + { + goto out; + } + + fop->int32 = flags; + + 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 (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); + } +} + +/* FOP: readlink */ + +int32_t ec_combine_readlink(ec_fop_data_t * fop, ec_cbk_data_t * dst, + ec_cbk_data_t * src) +{ + if (!ec_iatt_combine(dst->iatt, src->iatt, 1)) + { + gf_log(fop->xl->name, GF_LOG_NOTICE, "Mismatching iatt in " + "answers of 'GF_FOP_READLINK'"); + + return 0; + } + + return 1; +} + +int32_t ec_readlink_cbk(call_frame_t * frame, void * cookie, xlator_t * this, + int32_t op_ret, int32_t op_errno, const char * path, + struct iatt * buf, dict_t * xdata) +{ + ec_fop_data_t * fop = 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); + + if (op_ret > 0) + { + ec_iatt_rebuild(fop->xl->private, buf, 1, 1); + } + + if (!ec_dispatch_one_retry(fop, idx, op_ret, op_errno)) + { + if (fop->cbks.readlink != NULL) + { + fop->cbks.readlink(fop->req_frame, fop, this, op_ret, op_errno, + path, buf, xdata); + } + } + +out: + if (fop != NULL) + { + ec_complete(fop); + } + + return 0; +} + +void ec_wind_readlink(ec_t * ec, ec_fop_data_t * fop, int32_t idx) +{ + ec_trace("WIND", fop, "idx=%d", idx); + + STACK_WIND_COOKIE(fop->frame, ec_readlink_cbk, (void *)(uintptr_t)idx, + ec->xl_list[idx], ec->xl_list[idx]->fops->readlink, + &fop->loc[0], fop->size, fop->xdata); +} + +int32_t ec_manager_readlink(ec_fop_data_t * fop, int32_t state) +{ + switch (state) + { + case EC_STATE_INIT: + case EC_STATE_DISPATCH: + ec_dispatch_one(fop); + + return EC_STATE_REPORT; + + case -EC_STATE_REPORT: + if (fop->cbks.readlink != NULL) + { + fop->cbks.readlink(fop->req_frame, fop, fop->xl, -1, + fop->error, NULL, NULL, NULL); + } + + case EC_STATE_REPORT: + 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_readlink(call_frame_t * frame, xlator_t * this, uintptr_t target, + int32_t minimum, fop_readlink_cbk_t func, void * data, + loc_t * loc, size_t size, dict_t * xdata) +{ + ec_cbk_t callback = { .readlink = func }; + ec_fop_data_t * fop = NULL; + int32_t error = EIO; + + gf_log("ec", GF_LOG_TRACE, "EC(READLINK) %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_READLINK, 0, target, + minimum, ec_wind_readlink, ec_manager_readlink, + callback, data); + if (fop == NULL) + { + goto out; + } + + fop->size = size; + + 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); + } +} + +/* FOP: readv */ + +int32_t ec_readv_rebuild(ec_t * ec, ec_fop_data_t * fop, ec_cbk_data_t * cbk) +{ + ec_cbk_data_t * ans = NULL; + struct iobuf_pool * pool = NULL; + struct iobref * iobref = NULL; + struct iobuf * iobuf = NULL; + uint8_t * ptr = NULL, * buff = NULL; + size_t fsize = 0, size = 0, max = 0, slice = 0; + int32_t i = 0; + + if (cbk->op_ret < 0) + { + goto out; + } + + cbk->iatt[0].ia_size = fop->pre_size; + + if (cbk->op_ret > 0) + { + struct iovec vector[cbk->int32 * cbk->count]; + uint8_t * blocks[cbk->count]; + uint32_t values[cbk->count]; + + fsize = cbk->op_ret; + size = fsize * ec->fragments; + ptr = GF_MALLOC(size + EC_BUFFER_ALIGN_SIZE - 1, gf_common_mt_char); + if (ptr == NULL) + { + goto out; + } + buff = GF_ALIGN_BUF(ptr, EC_BUFFER_ALIGN_SIZE); + + iobref = iobref_new(); + if (iobref == NULL) + { + goto out; + } + + for (i = 0, ans = cbk; ans != NULL; i++, ans = ans->next) + { + values[i] = ans->idx; + blocks[i] = buff; + buff += ec_iov_copy_to(buff, ans->vector, ans->int32, 0, fsize); + } + + pool = fop->xl->ctx->iobuf_pool; + max = iobpool_default_pagesize(pool) / ec->stripe_size; + max *= ec->fragment_size; + i = 0; + do + { + iobuf = iobuf_get(pool); + if (iobuf == NULL) + { + goto out; + } + if (iobref_add(iobref, iobuf) != 0) + { + goto out; + } + + slice = fsize; + if (slice > max) + { + slice = max; + } + fsize -= slice; + + vector[i].iov_base = iobuf->ptr; + vector[i].iov_len = ec_method_decode(slice, ec->fragments, values, + blocks, iobuf->ptr); + i++; + + iobuf_unref(iobuf); + } while (fsize > 0); + + GF_FREE(ptr); + ptr = NULL; + + vector[0].iov_base += fop->head; + vector[0].iov_len -= fop->head; + + max = fop->offset * ec->fragments + size; + if (max > cbk->iatt[0].ia_size) + { + max = cbk->iatt[0].ia_size; + } + max -= fop->offset * ec->fragments + fop->head; + if (max > fop->user_size) + { + max = fop->user_size; + } + size -= fop->head; + while (size > max) + { + if (size - max >= vector[i - 1].iov_len) + { + size -= vector[--i].iov_len; + } + else + { + vector[i - 1].iov_len -= size - max; + size = max; + } + } + + cbk->op_ret = size; + cbk->int32 = i; + + iobref_unref(cbk->buffers); + cbk->buffers = iobref; + + GF_FREE(cbk->vector); + cbk->vector = iov_dup(vector, i); + if (cbk->vector == NULL) + { + cbk->op_ret = -1; + cbk->op_errno = EIO; + + return 0; + } + } + + return 1; + +out: + if (iobuf != NULL) + { + iobuf_unref(iobuf); + } + if (iobref != NULL) + { + iobref_unref(iobref); + } + GF_FREE(ptr); + + return 0; +} + +int32_t ec_combine_readv(ec_fop_data_t * fop, ec_cbk_data_t * dst, + ec_cbk_data_t * src) +{ + if (!ec_vector_compare(dst->vector, dst->int32, src->vector, src->int32)) + { + gf_log(fop->xl->name, GF_LOG_NOTICE, "Mismatching vector in " + "answers of 'GF_FOP_READ'"); + + return 0; + } + + if (!ec_iatt_combine(dst->iatt, src->iatt, 1)) + { + gf_log(fop->xl->name, GF_LOG_NOTICE, "Mismatching iatt in " + "answers of 'GF_FOP_READ'"); + + return 0; + } + + return 1; +} + +int32_t ec_readv_cbk(call_frame_t * frame, void * cookie, xlator_t * this, + int32_t op_ret, int32_t op_errno, struct iovec * vector, + int32_t count, struct iatt * stbuf, + struct iobref * iobref, dict_t * xdata) +{ + ec_fop_data_t * fop = NULL; + ec_cbk_data_t * cbk = NULL; + ec_t * ec = this->private; + 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_READ, idx, op_ret, + op_errno); + if (cbk != NULL) + { + if (op_ret >= 0) + { + cbk->int32 = count; + + if (count > 0) + { + cbk->vector = iov_dup(vector, count); + if (cbk->vector == NULL) + { + gf_log(this->name, GF_LOG_ERROR, "Failed to duplicate a " + "vector list."); + + goto out; + } + cbk->int32 = count; + } + if (stbuf != NULL) + { + cbk->iatt[0] = *stbuf; + } + if (iobref != NULL) + { + cbk->buffers = iobref_ref(iobref); + if (cbk->buffers == NULL) + { + gf_log(this->name, GF_LOG_ERROR, "Failed to reference a " + "buffer."); + + 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; + } + } + + if ((op_ret > 0) && ((op_ret % ec->fragment_size) != 0)) + { + cbk->op_ret = -1; + cbk->op_errno = EIO; + } + + ec_combine(cbk, ec_combine_readv); + } + +out: + if (fop != NULL) + { + ec_complete(fop); + } + + return 0; +} + +void ec_wind_readv(ec_t * ec, ec_fop_data_t * fop, int32_t idx) +{ + ec_trace("WIND", fop, "idx=%d", idx); + + STACK_WIND_COOKIE(fop->frame, ec_readv_cbk, (void *)(uintptr_t)idx, + ec->xl_list[idx], ec->xl_list[idx]->fops->readv, fop->fd, + fop->size, fop->offset, fop->uint32, fop->xdata); +} + +int32_t ec_manager_readv(ec_fop_data_t * fop, int32_t state) +{ + ec_cbk_data_t * cbk; + + switch (state) + { + case EC_STATE_INIT: + fop->user_size = fop->size; + fop->head = ec_adjust_offset(fop->xl->private, &fop->offset, 1); + fop->size = ec_adjust_size(fop->xl->private, fop->size + fop->head, + 1); + + 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_min(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, 1, + cbk->count); + + if (!ec_readv_rebuild(fop->xl->private, fop, cbk)) + { + ec_fop_set_error(fop, EIO); + } + } + } + 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.readv != NULL) + { + fop->cbks.readv(fop->req_frame, fop, fop->xl, cbk->op_ret, + cbk->op_errno, cbk->vector, cbk->int32, + &cbk->iatt[0], cbk->buffers, 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.readv != NULL) + { + fop->cbks.readv(fop->req_frame, fop, fop->xl, -1, fop->error, + NULL, 0, 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_readv(call_frame_t * frame, xlator_t * this, uintptr_t target, + int32_t minimum, fop_readv_cbk_t func, void * data, fd_t * fd, + size_t size, off_t offset, uint32_t flags, dict_t * xdata) +{ + ec_cbk_t callback = { .readv = func }; + ec_fop_data_t * fop = NULL; + int32_t error = EIO; + + gf_log("ec", GF_LOG_TRACE, "EC(READ) %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_READ, EC_FLAG_UPDATE_FD, + target, minimum, ec_wind_readv, + ec_manager_readv, callback, data); + if (fop == NULL) + { + goto out; + } + + fop->size = size; + fop->offset = offset; + fop->uint32 = flags; + + 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, 0, NULL, NULL, NULL); + } +} + +/* FOP: stat */ + +int32_t ec_combine_stat(ec_fop_data_t * fop, ec_cbk_data_t * dst, + ec_cbk_data_t * src) +{ + if (!ec_iatt_combine(dst->iatt, src->iatt, 1)) + { + gf_log(fop->xl->name, GF_LOG_NOTICE, "Mismatching iatt in " + "answers of 'GF_FOP_STAT'"); + + return 0; + } + + return 1; +} + +int32_t ec_stat_cbk(call_frame_t * frame, void * cookie, xlator_t * this, + int32_t op_ret, int32_t op_errno, struct iatt * 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_STAT, idx, op_ret, + op_errno); + if (cbk != NULL) + { + if (op_ret >= 0) + { + if (buf != NULL) + { + cbk->iatt[0] = *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_stat); + } + +out: + if (fop != NULL) + { + ec_complete(fop); + } + + return 0; +} + +void ec_wind_stat(ec_t * ec, ec_fop_data_t * fop, int32_t idx) +{ + ec_trace("WIND", fop, "idx=%d", idx); + + STACK_WIND_COOKIE(fop->frame, ec_stat_cbk, (void *)(uintptr_t)idx, + ec->xl_list[idx], ec->xl_list[idx]->fops->stat, + &fop->loc[0], fop->xdata); +} + +int32_t ec_manager_stat(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_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, 1, + cbk->count); + + cbk->iatt[0].ia_size = fop->pre_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->fd == NULL) + { + if (fop->cbks.stat != NULL) + { + fop->cbks.stat(fop->req_frame, fop, fop->xl, cbk->op_ret, + cbk->op_errno, &cbk->iatt[0], cbk->xdata); + } + } + else + { + if (fop->cbks.fstat != NULL) + { + fop->cbks.fstat(fop->req_frame, fop, fop->xl, cbk->op_ret, + cbk->op_errno, &cbk->iatt[0], 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->fd == NULL) + { + if (fop->cbks.stat != NULL) + { + fop->cbks.stat(fop->req_frame, fop, fop->xl, -1, + fop->error, NULL, NULL); + } + } + else + { + if (fop->cbks.fstat != NULL) + { + fop->cbks.fstat(fop->req_frame, fop, fop->xl, -1, + fop->error, 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_stat(call_frame_t * frame, xlator_t * this, uintptr_t target, + int32_t minimum, fop_stat_cbk_t func, void * data, loc_t * loc, + dict_t * xdata) +{ + ec_cbk_t callback = { .stat = func }; + ec_fop_data_t * fop = NULL; + int32_t error = EIO; + + gf_log("ec", GF_LOG_TRACE, "EC(STAT) %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_STAT, + EC_FLAG_UPDATE_LOC_INODE, target, minimum, + ec_wind_stat, ec_manager_stat, 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: fstat */ + +int32_t ec_fstat_cbk(call_frame_t * frame, void * cookie, xlator_t * this, + int32_t op_ret, int32_t op_errno, struct iatt * 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_FSTAT, idx, op_ret, + op_errno); + if (cbk != NULL) + { + if (op_ret >= 0) + { + if (buf != NULL) + { + cbk->iatt[0] = *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_stat); + } + +out: + if (fop != NULL) + { + ec_complete(fop); + } + + return 0; +} + +void ec_wind_fstat(ec_t * ec, ec_fop_data_t * fop, int32_t idx) +{ + ec_trace("WIND", fop, "idx=%d", idx); + + STACK_WIND_COOKIE(fop->frame, ec_fstat_cbk, (void *)(uintptr_t)idx, + ec->xl_list[idx], ec->xl_list[idx]->fops->fstat, fop->fd, + fop->xdata); +} + +void ec_fstat(call_frame_t * frame, xlator_t * this, uintptr_t target, + int32_t minimum, fop_fstat_cbk_t func, void * data, fd_t * fd, + dict_t * xdata) +{ + ec_cbk_t callback = { .fstat = func }; + ec_fop_data_t * fop = NULL; + int32_t error = EIO; + + gf_log("ec", GF_LOG_TRACE, "EC(FSTAT) %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_FSTAT, + EC_FLAG_UPDATE_FD_INODE, target, minimum, + ec_wind_fstat, ec_manager_stat, 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, NULL); + } +} |