/* Copyright (c) 2015 Red Hat, Inc. This file is part of GlusterFS. This file is licensed to you under your choice of the GNU Lesser General Public License, version 3 or any later version (LGPLv3 or later), or the GNU General Public License, version 2 (GPLv2), in all cases as published by the Free Software Foundation. */ #include "ctr-xlator-ctx.h" #include "ctr-messages.h" #include #include #define IS_THE_ONLY_HARDLINK(ctr_hard_link)\ (ctr_hard_link->list.next == ctr_hard_link->list.prev) static inline void fini_ctr_hard_link (ctr_hard_link_t **ctr_hard_link) { GF_ASSERT (ctr_hard_link); if (*ctr_hard_link) return; GF_FREE ((*ctr_hard_link)->base_name); GF_FREE (*ctr_hard_link); *ctr_hard_link = NULL; } /* Please lock the ctr_xlator_ctx before using this function */ ctr_hard_link_t * ctr_search_hard_link_ctx (xlator_t *this, ctr_xlator_ctx_t *ctr_xlator_ctx, uuid_t pgfid, const char *base_name) { ctr_hard_link_t *_hard_link = NULL; ctr_hard_link_t *searched_hardlink = NULL; GF_ASSERT (this); GF_ASSERT (ctr_xlator_ctx); if (pgfid == NULL || base_name == NULL) goto out; /*linear search*/ list_for_each_entry (_hard_link, &ctr_xlator_ctx->hardlink_list, list) { if (gf_uuid_compare (_hard_link->pgfid, pgfid) == 0 && _hard_link->base_name && strcmp(_hard_link->base_name, base_name) == 0) { searched_hardlink = _hard_link; break; } } out: return searched_hardlink; } /* Please lock the ctr_xlator_ctx before using this function */ int ctr_add_hard_link (xlator_t *this, ctr_xlator_ctx_t *ctr_xlator_ctx, uuid_t pgfid, const char *base_name) { int ret = -1; ctr_hard_link_t *ctr_hard_link = NULL; struct timeval current_time = {0}; GF_ASSERT (this); GF_ASSERT (ctr_xlator_ctx); if (pgfid == NULL || base_name == NULL) goto out; ctr_hard_link = GF_CALLOC (1, sizeof (*ctr_hard_link), gf_ctr_mt_hard_link_t); if (!ctr_hard_link) { gf_msg (this->name, GF_LOG_ERROR, ENOMEM, CTR_MSG_CALLOC_FAILED, "Failed allocating " "ctr_hard_link"); goto out; } /*Initialize the ctr_hard_link object and * Assign the values : parent GFID and basename*/ INIT_LIST_HEAD (&ctr_hard_link->list); gf_uuid_copy (ctr_hard_link->pgfid, pgfid); ret = gf_asprintf(&ctr_hard_link->base_name, "%s", base_name); if (ret < 0) { gf_msg (this->name, GF_LOG_ERROR, 0, CTR_MSG_COPY_FAILED, "Failed copying basename" "to ctr_hard_link"); goto error; } ret = gettimeofday (¤t_time, NULL); if (ret == -1) { gf_log (this->name, GF_LOG_ERROR, "Failed to get current time"); goto error; } /*Add the hard link to the list*/ list_add_tail (&ctr_hard_link->list, &ctr_xlator_ctx->hardlink_list); ctr_hard_link->hardlink_heal_period = current_time.tv_sec; /*aal izz well!*/ ret = 0; goto out; error: GF_FREE (ctr_hard_link); out: return ret; } static void __delete_hard_link_from_list (ctr_hard_link_t **ctr_hard_link) { GF_ASSERT (ctr_hard_link); GF_ASSERT (*ctr_hard_link); /*Remove hard link from list*/ list_del(&(*ctr_hard_link)->list); fini_ctr_hard_link (ctr_hard_link); } int ctr_delete_hard_link (xlator_t *this, ctr_xlator_ctx_t *ctr_xlator_ctx, uuid_t pgfid, const char *base_name) { int ret = -1; ctr_hard_link_t *ctr_hard_link = NULL; GF_ASSERT (this); GF_ASSERT (ctr_xlator_ctx); LOCK (&ctr_xlator_ctx->lock); /*Check if the hard link is present */ ctr_hard_link = ctr_search_hard_link_ctx (this, ctr_xlator_ctx, pgfid, base_name); if (!ctr_hard_link) { gf_msg (this->name, GF_LOG_ERROR, 0, CTR_MSG_HARDLINK_MISSING_IN_LIST, "Hard link doesnt exist in the list"); goto out; } __delete_hard_link_from_list (&ctr_hard_link); ctr_hard_link = NULL; ret = 0; out: UNLOCK (&ctr_xlator_ctx->lock); return ret; } int ctr_update_hard_link (xlator_t *this, ctr_xlator_ctx_t *ctr_xlator_ctx, uuid_t pgfid, const char *base_name, uuid_t old_pgfid, const char *old_base_name) { int ret = -1; ctr_hard_link_t *ctr_hard_link = NULL; struct timeval current_time = {0}; GF_ASSERT (this); GF_ASSERT (ctr_xlator_ctx); LOCK (&ctr_xlator_ctx->lock); /*Check if the hard link is present */ ctr_hard_link = ctr_search_hard_link_ctx (this, ctr_xlator_ctx, old_pgfid, old_base_name); if (!ctr_hard_link) { gf_msg_trace (this->name, 0, "Hard link doesnt exist" " in the list"); /* Since the hard link is not present in the list * we add it to the list */ ret = ctr_add_hard_link (this, ctr_xlator_ctx, pgfid, base_name); if (ret) { gf_msg (this->name, GF_LOG_ERROR, 0, CTR_MSG_ADD_HARDLINK_TO_LIST_FAILED, "Failed adding hard link to the list"); goto out; } ret = 0; goto out; } /* update the hard link */ gf_uuid_copy (ctr_hard_link->pgfid, pgfid); GF_FREE (ctr_hard_link->base_name); ret = gf_asprintf(&ctr_hard_link->base_name, "%s", base_name); if (ret < 0) { gf_msg (this->name, GF_LOG_ERROR, 0, CTR_MSG_COPY_FAILED, "Failed copying basename" "to ctr_hard_link"); /* delete the corrupted entry */ __delete_hard_link_from_list (&ctr_hard_link); ctr_hard_link = NULL; goto out; } ret = gettimeofday (¤t_time, NULL); if (ret == -1) { gf_log (this->name, GF_LOG_ERROR, "Failed to get current time"); ctr_hard_link->hardlink_heal_period = 0; } else { ctr_hard_link->hardlink_heal_period = current_time.tv_sec; } ret = 0; out: UNLOCK (&ctr_xlator_ctx->lock); return ret; } /* Delete all hardlinks */ static inline int ctr_delete_all_hard_link (xlator_t *this, ctr_xlator_ctx_t *ctr_xlator_ctx) { int ret = -1; ctr_hard_link_t *ctr_hard_link = NULL; ctr_hard_link_t *tmp = NULL; GF_ASSERT (ctr_xlator_ctx); LOCK (&ctr_xlator_ctx->lock); list_for_each_entry_safe(ctr_hard_link, tmp, &ctr_xlator_ctx->hardlink_list, list) { /*Remove hard link from list*/ __delete_hard_link_from_list (&ctr_hard_link); ctr_hard_link = NULL; } UNLOCK (&ctr_xlator_ctx->lock); ret = 0; return ret; } /* Please lock the inode before using this function */ static inline ctr_xlator_ctx_t * __get_ctr_xlator_ctx (xlator_t *this, inode_t *inode) { int ret = 0; uint64_t _addr = 0; ctr_xlator_ctx_t *ctr_xlator_ctx = NULL; GF_ASSERT (this); GF_ASSERT (inode); ret = __inode_ctx_get (inode, this, &_addr); if (ret < 0) _addr = 0; if (_addr != 0) { ctr_xlator_ctx = (ctr_xlator_ctx_t *) (long)_addr; } return ctr_xlator_ctx; } ctr_xlator_ctx_t * init_ctr_xlator_ctx (xlator_t *this, inode_t *inode) { int ret = -1; uint64_t _addr = 0; ctr_xlator_ctx_t *ctr_xlator_ctx = NULL; struct timeval current_time = {0}; GF_ASSERT (this); GF_ASSERT (inode); LOCK (&inode->lock); { ctr_xlator_ctx = __get_ctr_xlator_ctx (this, inode); if (ctr_xlator_ctx) { ret = 0; goto out; } ctr_xlator_ctx = GF_CALLOC (1, sizeof (*ctr_xlator_ctx), gf_ctr_mt_xlator_ctx); if (!ctr_xlator_ctx) goto out; ret = LOCK_INIT (&ctr_xlator_ctx->lock); if (ret) { gf_msg (this->name, GF_LOG_ERROR, ret, CTR_MSG_INIT_LOCK_FAILED, "Failed init lock %s", strerror(ret)); goto out; } _addr = (uint64_t) ctr_xlator_ctx; ret = __inode_ctx_set (inode, this, &_addr); if (ret) { goto out; } INIT_LIST_HEAD (&ctr_xlator_ctx->hardlink_list); ret = gettimeofday (¤t_time, NULL); if (ret == -1) { gf_log (this->name, GF_LOG_ERROR, "Failed to get current time"); goto out; } ctr_xlator_ctx->inode_heal_period = current_time.tv_sec; } ret = 0; out: if (ret) { GF_FREE (ctr_xlator_ctx); ctr_xlator_ctx = NULL; } UNLOCK (&inode->lock); return ctr_xlator_ctx; } void fini_ctr_xlator_ctx (xlator_t *this, inode_t *inode) { int ret = 0; uint64_t _addr = 0; ctr_xlator_ctx_t *ctr_xlator_ctx = NULL; inode_ctx_del (inode, this, &_addr); if (!_addr) return; ctr_xlator_ctx = (ctr_xlator_ctx_t *) (long) _addr; ret = ctr_delete_all_hard_link (this, ctr_xlator_ctx); if (ret) { gf_msg (this->name, GF_LOG_WARNING , 0, CTR_MSG_DELETE_HARDLINK_FAILED, "Failed deleting all " "hard links from inode context"); } LOCK_DESTROY (&ctr_xlator_ctx->lock); GF_FREE (ctr_xlator_ctx); } ctr_xlator_ctx_t * get_ctr_xlator_ctx (xlator_t *this, inode_t *inode) { ctr_xlator_ctx_t *ctr_xlator_ctx = NULL; LOCK (&inode->lock); ctr_xlator_ctx = __get_ctr_xlator_ctx (this, inode); UNLOCK (&inode->lock); return ctr_xlator_ctx; }