diff options
Diffstat (limited to 'xlators/storage/posix/src/posix-helpers.c')
-rw-r--r-- | xlators/storage/posix/src/posix-helpers.c | 482 |
1 files changed, 482 insertions, 0 deletions
diff --git a/xlators/storage/posix/src/posix-helpers.c b/xlators/storage/posix/src/posix-helpers.c index 6d7d8c512db..0ff94df944e 100644 --- a/xlators/storage/posix/src/posix-helpers.c +++ b/xlators/storage/posix/src/posix-helpers.c @@ -2774,3 +2774,485 @@ out: UNLOCK (&fd->inode->lock); return ret; } + +gf_cs_obj_state +posix_cs_heal_state (xlator_t *this, const char *realpath, int *fd, + struct iatt *buf) +{ + gf_boolean_t remote = _gf_false; + gf_boolean_t downloading = _gf_false; + int ret = 0; + gf_cs_obj_state state = GF_CS_ERROR; + size_t xattrsize = 0; + + if (!buf) { + ret = -1; + goto out; + } + + if (fd) { + xattrsize = sys_fgetxattr (*fd, GF_CS_OBJECT_REMOTE, NULL, 0); + if ((xattrsize == -1) && ((errno == ENOATTR) || + (errno == ENODATA))) { + remote = _gf_false; + } else if (xattrsize == -1) { + ret = -1; + gf_msg (this->name, GF_LOG_ERROR, 0, errno, "fgetxattr" + " failed"); + state = GF_CS_ERROR; + goto out; + } else { + remote = _gf_true; + } + + xattrsize = sys_fgetxattr (*fd, GF_CS_OBJECT_DOWNLOADING, NULL, + 0); + if ((xattrsize == -1) && ((errno == ENOATTR) || + (errno == ENODATA))) { + downloading = _gf_false; + } else if (xattrsize == -1) { + ret = -1; + gf_msg (this->name, GF_LOG_ERROR, 0, errno, "fgetxattr" + " failed"); + state = GF_CS_ERROR; + goto out; + } else { + downloading = _gf_true; + } + } else { + xattrsize = sys_lgetxattr (realpath, GF_CS_OBJECT_REMOTE, NULL, + 0); + if ((xattrsize == -1) && ((errno == ENOATTR) || + (errno == ENODATA))) { + remote = _gf_false; + } else if (xattrsize == -1) { + ret = -1; + gf_msg (this->name, GF_LOG_ERROR, 0, errno, "getxattr" + " failed"); + state = GF_CS_ERROR; + goto out; + } else { + remote = _gf_true; + } + + xattrsize = sys_lgetxattr (realpath, GF_CS_OBJECT_DOWNLOADING, + NULL, 0); + if ((xattrsize == -1) && ((errno == ENOATTR) || + (errno == ENODATA))) { + downloading = _gf_false; + } else if (xattrsize == -1) { + ret = -1; + gf_msg (this->name, GF_LOG_ERROR, 0, errno, "getxattr" + " failed"); + state = GF_CS_ERROR; + goto out; + } else { + downloading = _gf_true; + } + } + + if (remote && downloading) { + if (fd) { + ret = sys_fremovexattr (*fd, GF_CS_OBJECT_DOWNLOADING); + } else { + ret = sys_lremovexattr (realpath, GF_CS_OBJECT_DOWNLOADING); + } + + if (ret) { + gf_msg (this->name, GF_LOG_ERROR, 0, errno, + "failed to remove xattr, repair failed"); + state = GF_CS_ERROR; + goto out; + } + + if (buf->ia_size) { + if (fd) { + ret = sys_ftruncate (*fd, 0); + } else { + ret = sys_truncate (realpath, 0); + } + + if (ret) { + gf_msg (this->name, GF_LOG_ERROR, 0, errno, + "truncate failed. File is in inconsistent" + " state"); + state = GF_CS_ERROR; + goto out; + } + } + + state = GF_CS_REMOTE; + goto out; + + } else if (remote) { + if (buf->ia_size) { + if (fd) { + ret = sys_ftruncate (*fd, 0); + } else { + ret = sys_truncate (realpath, 0); + } + if (ret) { + gf_msg (this->name, GF_LOG_ERROR, 0, errno, + "truncate failed. File is in inconsistent" + " state"); + state = GF_CS_ERROR; + goto out; + } + } + + state = GF_CS_REMOTE; + goto out; + } else if (downloading) { + if (buf->ia_size) { + if (fd) { + ret = sys_fremovexattr (*fd, GF_CS_OBJECT_DOWNLOADING); + } else { + ret = sys_lremovexattr (realpath, GF_CS_OBJECT_DOWNLOADING); + } + + if (ret) { + gf_msg (this->name, GF_LOG_ERROR, 0, errno, + "failed to remove xattr, repair failed"); + state = GF_CS_ERROR; + goto out; + } + + state = GF_CS_LOCAL; + goto out; + } + } + + state = GF_CS_LOCAL; +out: + gf_msg_debug (this->name, 0, "heal state returned %d", state); + return state; +} + +gf_cs_obj_state +posix_cs_check_status (xlator_t *this, const char *realpath, int *fd, + struct iatt *buf) +{ + gf_boolean_t remote = _gf_false; + gf_boolean_t downloading = _gf_false; + int ret = 0; + gf_cs_obj_state state = GF_CS_LOCAL; + size_t xattrsize = 0; + int op_errno = 0; + + if (fd) { + xattrsize = sys_fgetxattr (*fd, GF_CS_OBJECT_REMOTE, NULL, 0); + if ((xattrsize == -1) && ((errno == ENOATTR) || + (errno == ENODATA))) { + remote = _gf_false; + } else if (xattrsize == -1) { + ret = -1; + op_errno = errno; + gf_msg (this->name, GF_LOG_ERROR, 0, 0, "getxattr " + "failed err %d", errno); + goto out; + } else { + remote = _gf_true; + } + + xattrsize = sys_fgetxattr (*fd, GF_CS_OBJECT_DOWNLOADING, NULL, + 0); + if ((xattrsize == -1) && ((errno == ENOATTR) || + (errno == ENODATA))) { + downloading = _gf_false; + } else if (xattrsize == -1) { + ret = -1; + op_errno = errno; + gf_msg (this->name, GF_LOG_ERROR, 0, 0, "getxattr " + "failed err : %d", errno); + + goto out; + } else { + downloading = _gf_true; + } + + } + + if (realpath) { + xattrsize = sys_lgetxattr (realpath, GF_CS_OBJECT_REMOTE, NULL, + 0); + if ((xattrsize == -1) && ((errno == ENOATTR) || + (errno == ENODATA))) { + remote = _gf_false; + } else if (xattrsize == -1) { + ret = -1; + op_errno = errno; + gf_msg (this->name, GF_LOG_ERROR, 0, 0, "getxattr " + "failed err : %d", errno); + goto out; + } else { + remote = _gf_true; + } + + xattrsize = sys_lgetxattr (realpath, GF_CS_OBJECT_DOWNLOADING, + NULL, 0); + if ((xattrsize == -1) && ((errno == ENOATTR) || + (errno == ENODATA))) { + downloading = _gf_false; + } else if (xattrsize == -1) { + ret = -1; + op_errno = errno; + gf_msg (this->name, GF_LOG_ERROR, 0, 0, "getxattr " + "failed err : %d", errno); + goto out; + } else { + downloading = _gf_true; + } + } + +out: + if (ret) { + gf_msg ("POSIX", GF_LOG_ERROR, 0, op_errno, "getxattr failed " + "with %d", op_errno); + state = GF_CS_ERROR; + return state; + } + + if ((remote && downloading) || (remote && buf && buf->ia_size)) { + state = GF_CS_REPAIR; + gf_msg_debug (this->name, 0, "status is REPAIR"); + return state; + } + + if (remote) + state = GF_CS_REMOTE; + else if (downloading) + state = GF_CS_DOWNLOADING; + else + state = GF_CS_LOCAL; + + gf_msg_debug (this->name, 0, "state returned is %d", state); + return state; + +} + +int +posix_cs_set_state (xlator_t *this, dict_t **rsp, gf_cs_obj_state state, + char const *path, int *fd) +{ + int ret = 0; + char *value = NULL; + size_t xattrsize = 0; + + if (!(*rsp)) { + *rsp = dict_new (); + if (!(*rsp)) { + gf_msg (this->name, GF_LOG_ERROR, 0, ENOMEM, "failed to" + " create dict"); + ret = -1; + goto out; + } + } + + ret = dict_set_uint64 (*rsp, GF_CS_OBJECT_STATUS, state); + if (ret) { + gf_msg (this->name, GF_LOG_ERROR, 0, ENOMEM, "failed to set " + "dict"); + ret = -1; + goto out; + } + + if (fd) { + xattrsize = sys_fgetxattr (*fd, GF_CS_OBJECT_REMOTE, NULL, 0); + if (xattrsize != -1) { + value = GF_CALLOC (1, xattrsize + 1, gf_posix_mt_char); + if (!value) { + gf_msg (this->name, GF_LOG_ERROR, 0, 0, + "no memory for value"); + ret = -1; + goto out; + } + /* TODO: Add check for ENODATA */ + xattrsize = sys_fgetxattr (*fd, GF_CS_OBJECT_REMOTE, + value, xattrsize + 1); + if (xattrsize == -1) { + gf_msg (this->name, GF_LOG_ERROR, 0, errno, + " getxattr failed for key %s", + GF_CS_OBJECT_REMOTE); + goto out; + } else { + value[xattrsize] = '\0'; + } + } else { + gf_msg (this->name, GF_LOG_ERROR, 0, errno, + " getxattr failed for key %s", + GF_CS_OBJECT_REMOTE); + goto out; + } + } else { + xattrsize = sys_lgetxattr (path, GF_CS_OBJECT_REMOTE, NULL, 0); + if (xattrsize != -1) { + value = GF_CALLOC (1, xattrsize + 1, gf_posix_mt_char); + if (!value) { + ret = -1; + goto out; + } + + xattrsize = sys_lgetxattr (path, GF_CS_OBJECT_REMOTE, + value, xattrsize + 1); + if (xattrsize == -1) { + gf_msg (this->name, GF_LOG_ERROR, 0, errno, + " getxattr failed for key %s", + GF_CS_OBJECT_REMOTE); + goto out; + } else { + value[xattrsize] = '\0'; + } + } else { + gf_msg (this->name, GF_LOG_ERROR, 0, errno, + " getxattr failed for key %s", + GF_CS_OBJECT_REMOTE); + goto out; + } + } + + if (ret == 0) { + ret = dict_set_str (*rsp, GF_CS_OBJECT_REMOTE, value); + if (ret) { + gf_msg (this->name, GF_LOG_ERROR, 0, 0, "failed to set" + "value"); + } + } + +out: + return ret; +} + + +/* This function checks the status of the file and updates the xattr response. + * Also it repairs the state of the file which could have been resulted from a + * crash or transient failures. + */ +int +posix_cs_maintenance (xlator_t *this, fd_t *fd, loc_t *loc, int *pfd, + struct iatt *buf, const char *realpath, dict_t *xattr_req, + dict_t **xattr_rsp, gf_boolean_t ignore_failure) +{ + gf_cs_obj_state state = GF_CS_ERROR; + int ret = 0; + + if (!(dict_get (xattr_req, GF_CS_OBJECT_STATUS) || + dict_get (xattr_req, GF_CS_OBJECT_REPAIR))) + return 0; + + + if (fd) { + LOCK (&fd->inode->lock); + if (dict_get (xattr_req, GF_CS_OBJECT_STATUS)) { + state = posix_cs_check_status (this, NULL, pfd, buf); + gf_msg_debug (this->name, 0, "state : %d", state); + ret = posix_cs_set_state (this, xattr_rsp, + state, NULL, pfd); + if (ret) { + gf_msg (this->name, GF_LOG_ERROR, 0, 0, + "posix_cs_set_state failed"); + } + + if (ignore_failure) { + ret = 0; + goto unlock; + } else { + if (state != GF_CS_LOCAL || ret != 0) { + ret = -1; + goto unlock; + } + } + } + + if (dict_get (xattr_req, GF_CS_OBJECT_REPAIR)) { + state = posix_cs_check_status (this, NULL, pfd, + buf); + gf_msg_debug (this->name, 0, "state : %d", state); + + if (state == GF_CS_REPAIR) { + state = posix_cs_heal_state (this, NULL, + pfd, buf); + + if (state == GF_CS_ERROR) { + gf_msg (this->name, GF_LOG_ERROR, 0, 0, + "repair check failed"); + } + } + + ret = posix_cs_set_state (this, xattr_rsp, + state, NULL, pfd); + if (ret) { + gf_msg (this->name, GF_LOG_ERROR, 0, 0, + "posix_cs_set_state failed"); + if (ignore_failure) + ret = 0; + else + ret = -1; + goto unlock; + } + } + } else { + if (!loc->inode) { + ret = 0; + goto unlock; + } + + LOCK (&loc->inode->lock); + if (dict_get (xattr_req, GF_CS_OBJECT_STATUS)) { + state = posix_cs_check_status (this, realpath, NULL, + buf); + gf_msg_debug (this->name, 0, "state : %d", state); + ret = posix_cs_set_state (this, xattr_rsp, state, + realpath, NULL); + if (ret) { + gf_msg (this->name, GF_LOG_ERROR, 0, 0, + "posix_cs_set_state failed"); + } + + if (ignore_failure) { + ret = 0; + goto unlock; + } else { + if (state != GF_CS_LOCAL || ret != 0) { + ret = -1; + goto unlock; + } + } + } + + if (dict_get (xattr_req, GF_CS_OBJECT_REPAIR)) { + state = posix_cs_check_status (this, realpath, NULL, + buf); + gf_msg_debug (this->name, 0, "state : %d", state); + + if (state == GF_CS_REPAIR) { + state = posix_cs_heal_state (this, realpath, + NULL, buf); + + if (state == GF_CS_ERROR) { + gf_msg (this->name, GF_LOG_ERROR, 0, 0, + "repair check failed"); + } + } + + ret = posix_cs_set_state (this, xattr_rsp, + state, realpath, NULL); + if (ret) { + gf_msg (this->name, GF_LOG_ERROR, 0, 0, + "posix_cs_set_state failed"); + if (ignore_failure) + ret = 0; + else + ret = -1; + goto unlock; + } + } + } + +unlock: + if (fd) + UNLOCK (&fd->inode->lock); + else + UNLOCK (&loc->inode->lock); + + return ret; +} |