diff options
-rw-r--r-- | xlators/cluster/ec/src/ec-heal.c | 1378 |
1 files changed, 2 insertions, 1376 deletions
diff --git a/xlators/cluster/ec/src/ec-heal.c b/xlators/cluster/ec/src/ec-heal.c index 7067ed95306..b014df25b94 100644 --- a/xlators/cluster/ec/src/ec-heal.c +++ b/xlators/cluster/ec/src/ec-heal.c @@ -84,99 +84,6 @@ ec_sh_key_match (dict_t *dict, char *key, data_t *val, void *mdata) } /* FOP: heal */ -void ec_heal_exclude(ec_heal_t * heal, uintptr_t mask) -{ - LOCK(&heal->lock); - - heal->bad &= ~mask; - - UNLOCK(&heal->lock); -} - -void ec_heal_lookup_resume(ec_fop_data_t * fop) -{ - ec_heal_t * heal = fop->data; - ec_cbk_data_t * cbk; - uintptr_t good = 0, bad = 0; - - if (heal->lookup != NULL) - { - ec_fop_data_release(heal->lookup); - } - ec_fop_data_acquire(fop); - - list_for_each_entry(cbk, &fop->cbk_list, list) - { - if ((cbk->op_ret < 0) && (cbk->op_errno == ENOTCONN)) - { - continue; - } - - if (cbk == fop->answer) - { - if (cbk->op_ret >= 0) - { - heal->iatt = cbk->iatt[0]; - heal->version[0] = cbk->version[0]; - heal->version[1] = cbk->version[1]; - heal->raw_size = cbk->size; - - GF_ASSERT(ec_set_inode_size(fop, cbk->inode, cbk->size)); - - if (ec_loc_update(heal->xl, &heal->loc, cbk->inode, - &cbk->iatt[0]) != 0) - { - fop->answer = NULL; - fop->error = EIO; - - bad |= cbk->mask; - - continue; - } - } - - good |= cbk->mask; - } - else - { - bad |= cbk->mask; - } - } - - /* Heal lookups are not executed concurrently with anything else. So, when - * a lookup finishes, it's safe to access heal->good and heal->bad without - * acquiring any lock. - */ - heal->good = good; - heal->bad = bad; - - heal->lookup = fop; - - ec_resume_parent(fop, fop->answer != NULL ? 0 : fop->error); -} - -int32_t ec_heal_entry_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_heal_lookup_resume(cookie); - - return 0; -} - -int32_t ec_heal_inode_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_heal_lookup_resume(cookie); - - return 0; -} - uintptr_t ec_heal_check(ec_fop_data_t * fop, uintptr_t * pgood) { ec_cbk_data_t * cbk; @@ -229,326 +136,6 @@ void ec_heal_avoid(ec_fop_data_t * fop) UNLOCK(&heal->lock); } -int32_t ec_heal_mkdir_cbk(call_frame_t * frame, void * cookie, xlator_t * this, - int32_t op_ret, int32_t op_errno, inode_t * inode, - struct iatt * buf, struct iatt * preparent, - struct iatt * postparent, dict_t * xdata) -{ - ec_heal_update(cookie, 0); - - return 0; -} - -int32_t ec_heal_mknod_cbk(call_frame_t * frame, void * cookie, xlator_t * this, - int32_t op_ret, int32_t op_errno, inode_t * inode, - struct iatt * buf, struct iatt * preparent, - struct iatt * postparent, dict_t * xdata) -{ - ec_heal_update(cookie, 0); - - return 0; -} - -int32_t ec_heal_symlink_cbk(call_frame_t * frame, void * cookie, - xlator_t * this, int32_t op_ret, int32_t op_errno, - inode_t * inode, struct iatt * buf, - struct iatt * preparent, struct iatt * postparent, - dict_t * xdata) -{ - ec_heal_update(cookie, 0); - - return 0; -} - -int32_t ec_heal_setattr_cbk(call_frame_t * frame, void * cookie, - xlator_t * this, int32_t op_ret, int32_t op_errno, - struct iatt * preop_stbuf, - struct iatt * postop_stbuf, - dict_t * xdata) -{ - ec_heal_update(cookie, 0); - - return 0; -} - -int32_t ec_heal_setxattr_cbk(call_frame_t * frame, void * cookie, - xlator_t * this, int32_t op_ret, int32_t op_errno, - dict_t * xdata) -{ - ec_heal_update(cookie, 0); - - return 0; -} - -int32_t ec_heal_removexattr_cbk(call_frame_t * frame, void * cookie, - xlator_t * this, int32_t op_ret, - int32_t op_errno, dict_t * xdata) -{ - ec_heal_update(cookie, 0); - - return 0; -} - -int32_t ec_heal_target_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_heal_update(cookie, 1); - - return 0; -} - -int32_t ec_heal_source_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_heal_avoid(cookie); - - return 0; -} - -int32_t ec_heal_reopen_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 = cookie; - ec_fd_t * ctx; - uintptr_t good; - - ec_heal_check(fop, &good); - - if (good != 0) - { - LOCK(&fd->lock); - - ctx = __ec_fd_get(fd, fop->xl); - if (ctx != NULL) { - ctx->bad &= ~good; - ctx->open |= good; - } - - UNLOCK(&fd->lock); - } - - return 0; -} - -int32_t ec_heal_create (ec_heal_t *heal, uintptr_t mask) -{ - dict_t * xdata; - int error = 0; - - xdata = dict_new(); - if (xdata == NULL) - return ENOMEM; - - if (dict_set_static_bin(xdata, "gfid-req", heal->iatt.ia_gfid, - sizeof(uuid_t))) { - error = ENOMEM; - goto out; - } - - switch (heal->iatt.ia_type) - { - case IA_IFDIR: - ec_mkdir(heal->fop->frame, heal->xl, mask, EC_MINIMUM_ONE, - ec_heal_mkdir_cbk, heal, &heal->loc, - st_mode_from_ia(heal->iatt.ia_prot, heal->iatt.ia_type), - 0, xdata); - - break; - - case IA_IFLNK: - ec_symlink(heal->fop->frame, heal->xl, mask, EC_MINIMUM_ONE, - ec_heal_symlink_cbk, heal, heal->symlink, &heal->loc, - 0, xdata); - - break; - - default: - /* If mknod comes with the presence of GLUSTERFS_INTERNAL_FOP_KEY - * then posix_mknod checks if there are already any gfid-links and - * does link() instead of mknod. There still can be a race where - * two posix_mknods with same gfid see that gfid-link file is not - * present and proceeds with mknods and result in two different - * files with same gfid. which is yet to be fixed in posix.*/ - if (dict_set_int32 (xdata, GLUSTERFS_INTERNAL_FOP_KEY, 1)) { - error = ENOMEM; - goto out; - } - - ec_mknod(heal->fop->frame, heal->xl, mask, EC_MINIMUM_ONE, - ec_heal_mknod_cbk, heal, &heal->loc, - st_mode_from_ia(heal->iatt.ia_prot, heal->iatt.ia_type), - heal->iatt.ia_rdev, 0, xdata); - - break; - } - error = 0; - -out: - if (xdata) - dict_unref(xdata); - - return error; -} - -int32_t ec_heal_parent_cbk(call_frame_t *frame, void *cookie, xlator_t *xl, - int32_t op_ret, int32_t op_errno, uintptr_t mask, - uintptr_t good, uintptr_t bad, dict_t *xdata) -{ - ec_fop_data_t *fop = cookie; - ec_heal_t *heal = fop->data; - - /* Even if parent self-heal has failed, we try to heal the current entry */ - ec_heal_create(heal, fop->mask); - - return 0; -} - -void ec_heal_parent(ec_heal_t *heal, uintptr_t mask) -{ - loc_t parent; - int32_t healing = 0; - - /* First we try to do a partial heal of the parent directory to avoid - * ENOENT/ENOTDIR errors caused by missing parents */ - if (ec_loc_parent(heal->xl, &heal->loc, &parent) == 0) { - if (!__is_root_gfid(parent.gfid)) { - ec_heal(heal->fop->frame, heal->xl, mask, EC_MINIMUM_ONE, - ec_heal_parent_cbk, heal, &parent, 1, NULL); - - healing = 1; - } - loc_wipe(&parent); - } - - if (!healing) { - ec_heal_create(heal, mask); - } -} - -void ec_heal_recreate(ec_fop_data_t * fop) -{ - ec_cbk_data_t * cbk; - ec_heal_t * heal = fop->data; - uintptr_t mask = 0; - - if (heal->iatt.ia_type == IA_INVAL) - { - return; - } - - list_for_each_entry(cbk, &fop->cbk_list, list) - { - if ((cbk->op_ret >= 0) || (cbk->op_errno == ENOENT) || - (cbk->op_errno == ENOTDIR)) - { - mask |= cbk->mask; - } - } - - if (mask != 0) - { - ec_heal_parent(heal, mask); - } -} - -int32_t ec_heal_rmdir_cbk(call_frame_t * frame, void * cookie, xlator_t * this, - int32_t op_ret, int32_t op_errno, - struct iatt * preparent, struct iatt * postparent, - dict_t * xdata) -{ - ec_heal_update(cookie, 0); - ec_heal_recreate(cookie); - - return 0; -} - -int32_t ec_heal_unlink_cbk(call_frame_t * frame, void * cookie, - xlator_t * this, int32_t op_ret, int32_t op_errno, - struct iatt * preparent, struct iatt * postparent, - dict_t * xdata) -{ - ec_heal_update(cookie, 0); - ec_heal_recreate(cookie); - - return 0; -} - -int32_t -ec_heal_init (ec_fop_data_t * fop) -{ - ec_t * ec = fop->xl->private; - struct iobuf_pool * pool; - inode_t * inode; - ec_inode_t * ctx; - ec_heal_t * heal = NULL; - int32_t error = 0; - - heal = GF_MALLOC(sizeof(ec_heal_t), ec_mt_ec_heal_t); - if (heal == NULL) - { - return ENOMEM; - } - - memset(heal, 0, sizeof(ec_heal_t)); - - if (ec_loc_from_loc(fop->xl, &heal->loc, &fop->loc[0]) != 0) { - error = ENOMEM; - goto out; - } - - inode = heal->loc.inode; - if (inode == NULL) { - gf_msg (fop->xl->name, GF_LOG_WARNING, ENODATA, - EC_MSG_DATA_UNAVAILABLE, "Unable to start inode healing " - "because there is not enough information"); - - error = ENODATA; - goto out; - } - - LOCK_INIT(&heal->lock); - - heal->xl = fop->xl; - heal->fop = fop; - pool = fop->xl->ctx->iobuf_pool; - heal->size = iobpool_default_pagesize(pool) * ec->fragments; - heal->partial = fop->int32; - fop->heal = heal; - - LOCK(&inode->lock); - - ctx = __ec_inode_get(inode, fop->xl); - if (ctx == NULL) - { - error = EIO; - - goto unlock; - } - - if (list_empty(&ctx->heal)) { - gf_msg ("ec", GF_LOG_INFO, 0, - EC_MSG_HEALING_INFO, - "Healing '%s', gfid %s", heal->loc.path, - uuid_utoa(heal->loc.gfid)); - } else { - ec_sleep(fop); - } - - list_add_tail(&heal->list, &ctx->heal); - heal = NULL; - -unlock: - UNLOCK(&inode->lock); - -out: - GF_FREE(heal); - - return error; -} - int32_t ec_heal_lock_cbk(call_frame_t *frame, void *cookie, xlator_t *this, int32_t op_ret, int32_t op_errno, dict_t *xdata) { @@ -601,21 +188,6 @@ void ec_heal_lock(ec_heal_t *heal, int32_t type, fd_t *fd, loc_t *loc, } } -void ec_heal_entrylk(ec_heal_t *heal, int32_t type) -{ - loc_t loc; - - if (ec_loc_parent(heal->xl, &heal->loc, &loc) != 0) { - ec_fop_set_error(heal->fop, EIO); - - return; - } - - ec_heal_lock(heal, type, NULL, &loc, 0, 0); - - loc_wipe(&loc); -} - void ec_heal_inodelk(ec_heal_t *heal, int32_t type, int32_t use_fd, off_t offset, size_t size) { @@ -623,327 +195,6 @@ void ec_heal_inodelk(ec_heal_t *heal, int32_t type, int32_t use_fd, size); } -void ec_heal_lookup(ec_heal_t *heal, uintptr_t mask) -{ - dict_t * xdata; - int32_t error = ENOMEM; - - xdata = dict_new(); - if (xdata == NULL) - { - goto out; - } - if (dict_set_uint64(xdata, "list-xattr", 0) != 0) - { - goto out; - } - - ec_lookup(heal->fop->frame, heal->xl, mask, EC_MINIMUM_MIN, - ec_heal_inode_lookup_cbk, heal, &heal->loc, xdata); - - error = 0; - -out: - if (xdata != NULL) - { - dict_unref(xdata); - } - - ec_fop_set_error(heal->fop, error); -} - -void ec_heal_remove(ec_heal_t * heal, ec_cbk_data_t * cbk) -{ - if (cbk->iatt[0].ia_type == IA_IFDIR) - { - ec_rmdir(heal->fop->frame, heal->xl, cbk->mask, EC_MINIMUM_ONE, - ec_heal_rmdir_cbk, heal, &heal->loc, 1, NULL); - } - else - { - ec_unlink(heal->fop->frame, heal->xl, cbk->mask, EC_MINIMUM_ONE, - ec_heal_unlink_cbk, heal, &heal->loc, 0, NULL); - } -} - -void ec_heal_remove_others(ec_heal_t * heal) -{ - struct list_head * item; - ec_cbk_data_t * cbk; - - item = heal->lookup->cbk_list.next; - do - { - item = item->next; - cbk = list_entry(item, ec_cbk_data_t, list); - - if (cbk->op_ret < 0) - { - if ((cbk->op_errno != ENOENT) && (cbk->op_errno != ENOTDIR) && - (cbk->op_errno != ESTALE)) - { - gf_msg (heal->xl->name, GF_LOG_WARNING, cbk->op_errno, - EC_MSG_INODE_REMOVE_FAIL, "Don't know how to " - "remove inode"); - } - - ec_heal_exclude(heal, cbk->mask); - - continue; - } - - ec_heal_remove(heal, cbk); - } while (item->next != &heal->lookup->cbk_list); -} - -void ec_heal_prepare_others(ec_heal_t * heal) -{ - struct list_head * item; - ec_cbk_data_t * cbk; - - item = heal->lookup->cbk_list.next; - while (item->next != &heal->lookup->cbk_list) - { - item = item->next; - cbk = list_entry(item, ec_cbk_data_t, list); - - if (cbk->op_ret < 0) - { - if ((cbk->op_errno == ENOENT) || (cbk->op_errno == ESTALE)) - { - ec_heal_create(heal, cbk->mask); - } - else - { - gf_msg (heal->xl->name, GF_LOG_ERROR, cbk->op_errno, - EC_MSG_HEAL_FAIL, "Don't know how to " - "heal"); - - ec_heal_exclude(heal, cbk->mask); - } - } - else - { - if ((heal->iatt.ia_type != cbk->iatt[0].ia_type) || - (gf_uuid_compare(heal->iatt.ia_gfid, cbk->iatt[0].ia_gfid) != 0)) - { - ec_heal_remove(heal, cbk); - } - } - } -} - -int32_t ec_heal_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 = cookie; - ec_heal_t * heal = fop->data; - - if (op_ret >= 0) - { - heal->symlink = gf_strdup(path); - if (heal->symlink != NULL) - { - ec_heal_prepare_others(heal); - } - else - { - ec_fop_set_error(fop, EIO); - } - } - - return 0; -} - -ec_cbk_data_t * ec_heal_lookup_check(ec_heal_t * heal, uintptr_t * pgood, - uintptr_t * pbad) -{ - ec_fop_data_t * fop = heal->lookup; - ec_cbk_data_t * cbk = NULL, * ans = NULL; - uintptr_t good = 0, bad = 0; - - list_for_each_entry(ans, &fop->cbk_list, list) - { - if ((ans->op_ret < 0) && (ans->op_errno == ENOTCONN)) - { - continue; - } - - if (ans == fop->answer) - { - good |= ans->mask; - cbk = ans; - } - else - { - bad |= ans->mask; - } - } - - *pgood = good; - *pbad = bad; - - return cbk; -} - -void ec_heal_prepare(ec_heal_t * heal) -{ - ec_cbk_data_t * cbk; - int32_t error = ENOMEM; - - heal->available = heal->good; - - cbk = heal->lookup->answer; - if (cbk->op_ret < 0) - { - if ((cbk->op_errno == ENOENT) || (cbk->op_errno == ENOTDIR)) - { - ec_heal_remove_others(heal); - } - else - { - gf_msg (heal->xl->name, GF_LOG_ERROR, cbk->op_errno, - EC_MSG_HEAL_FAIL, "Don't know how to heal "); - } - } - else - { - if (heal->iatt.ia_type == IA_IFREG) - { - heal->fd = fd_create(heal->loc.inode, heal->fop->frame->root->pid); - if (heal->fd == NULL) - { - gf_msg (heal->xl->name, GF_LOG_ERROR, errno, - EC_MSG_FD_CREATE_FAIL, "Unable to create a new " - "file descriptor"); - - goto out; - } - } - - if (heal->iatt.ia_type == IA_IFLNK) - { - ec_readlink(heal->fop->frame, heal->xl, cbk->mask, EC_MINIMUM_ONE, - ec_heal_readlink_cbk, heal, &heal->loc, - heal->iatt.ia_size, NULL); - } - else - { - ec_heal_prepare_others(heal); - } - } - - error = 0; - -out: - ec_fop_set_error(heal->fop, error); -} - -int32_t ec_heal_open_others(ec_heal_t * heal) -{ - struct list_head * item; - ec_cbk_data_t * cbk; - uintptr_t mask = 0, open = heal->open; - - item = heal->lookup->cbk_list.next; - while (item->next != &heal->lookup->cbk_list) - { - item = item->next; - cbk = list_entry(item, ec_cbk_data_t, list); - - if ((cbk->op_ret < 0) || (cbk->iatt[0].ia_type != IA_IFREG) || - (gf_uuid_compare(heal->iatt.ia_gfid, cbk->iatt[0].ia_gfid) != 0)) - { - ec_heal_exclude(heal, cbk->mask); - } - else - { - mask |= cbk->mask & ~heal->open; - } - } - - if (mask != 0) - { - ec_open(heal->fop->frame, heal->xl, mask, EC_MINIMUM_ONE, - ec_heal_target_open_cbk, heal, &heal->loc, O_RDWR | O_TRUNC, - heal->fd, NULL); - - open |= mask; - } - - return (open != 0); -} - -uintptr_t ec_heal_needs_data_rebuild(ec_heal_t *heal) -{ - ec_fop_data_t *fop = heal->lookup; - ec_cbk_data_t *cbk = NULL; - uintptr_t bad = 0; - - if ((heal->fop->error != 0) || (heal->good == 0) || - (heal->iatt.ia_type != IA_IFREG)) { - return 0; - } - - list_for_each_entry(cbk, &fop->cbk_list, list) { - if ((cbk->op_ret >= 0) && - ((cbk->size != heal->raw_size) || - (cbk->version != heal->version))) { - bad |= cbk->mask; - } - } - - return bad; -} - -void ec_heal_setxattr_others(ec_heal_t * heal) -{ - ec_cbk_data_t * cbk; - dict_t * xdata; - int32_t error = ENOMEM; - - if ((heal->good != 0) && (heal->bad != 0)) - { - cbk = heal->lookup->answer; - xdata = cbk->xdata; - - if (dict_foreach_match (xdata, ec_ignorable_key_match, NULL, - dict_remove_foreach_fn, NULL) == -1) - goto out; - - if ((cbk->iatt[0].ia_type == IA_IFREG) || - (cbk->iatt[0].ia_type == IA_IFDIR)) - { - if (ec_dict_set_array(xdata, EC_XATTR_VERSION, - cbk->version, EC_VERSION_SIZE) != 0) - { - goto out; - } - if (cbk->iatt[0].ia_type == IA_IFREG) - { - uint64_t dirty; - - dirty = ec_heal_needs_data_rebuild(heal) != 0; - if ((ec_dict_set_number(xdata, EC_XATTR_SIZE, - cbk->iatt[0].ia_size) != 0) || - (ec_dict_set_number(xdata, EC_XATTR_DIRTY, dirty) != 0)) { - goto out; - } - } - } - - ec_setxattr(heal->fop->frame, heal->xl, heal->bad, EC_MINIMUM_ONE, - ec_heal_setxattr_cbk, heal, &heal->loc, xdata, 0, NULL); - } - - error = 0; - -out: - ec_fop_set_error(heal->fop, error); -} - int32_t ec_heal_xattr_clean (dict_t *dict, char *key, data_t *data, void *arg) @@ -961,124 +212,6 @@ ec_heal_xattr_clean (dict_t *dict, char *key, data_t *data, return 0; } -void ec_heal_removexattr_others(ec_heal_t * heal) -{ - struct list_head * item; - ec_cbk_data_t * cbk; - dict_t * xdata; - - if ((heal->good == 0) || (heal->bad == 0)) - { - return; - } - - xdata = heal->lookup->answer->xdata; - item = heal->lookup->cbk_list.next; - while (item->next != &heal->lookup->cbk_list) - { - item = item->next; - cbk = list_entry(item, ec_cbk_data_t, list); - - if (cbk->op_ret >= 0) - { - if (dict_foreach(cbk->xdata, ec_heal_xattr_clean, xdata) == 0) - { - ec_removexattr(heal->fop->frame, heal->xl, cbk->mask, - EC_MINIMUM_ONE, ec_heal_removexattr_cbk, heal, - &heal->loc, "", cbk->xdata); - } - } - } -} - -void ec_heal_attr(ec_heal_t * heal) -{ - if ((heal->good != 0) && (heal->bad != 0)) - { - ec_setattr(heal->fop->frame, heal->xl, heal->bad, EC_MINIMUM_ONE, - ec_heal_setattr_cbk, heal, &heal->loc, &heal->iatt, - GF_SET_ATTR_MODE | GF_SET_ATTR_UID | GF_SET_ATTR_GID | - GF_SET_ATTR_ATIME | GF_SET_ATTR_MTIME, NULL); - } -} - -void -ec_heal_open (ec_heal_t * heal) -{ - heal->bad = ec_heal_needs_data_rebuild(heal); - if (heal->bad == 0) { - return; - } - - if (!heal->fd) { - /* name-less loc heal */ - heal->fd = fd_create (heal->loc.inode, - heal->fop->frame->root->pid); - } - - if (!heal->fd) { - ec_fop_set_error(heal->fop, ENOMEM); - return; - } - - if (ec_heal_open_others(heal)) - { - ec_open(heal->fop->frame, heal->xl, heal->good, EC_MINIMUM_MIN, - ec_heal_source_open_cbk, heal, &heal->loc, O_RDONLY, heal->fd, - NULL); - } -} - -void ec_heal_reopen_fd(ec_heal_t * heal) -{ - inode_t * inode; - fd_t * fd; - ec_fd_t *ctx_fd; - ec_inode_t *ctx_inode; - uintptr_t mask; - int32_t flags; - - inode = heal->loc.inode; - - LOCK(&inode->lock); - - ctx_inode = __ec_inode_get(inode, heal->xl); - if (ctx_inode != NULL) { - ctx_inode->bad &= ~(heal->good | heal->bad); - } - - list_for_each_entry(fd, &inode->fd_list, inode_list) - { - ctx_fd = ec_fd_get(fd, heal->xl); - if (ctx_fd != NULL) { - mask = heal->bad & ~ctx_fd->open; - if (mask != 0) - { - UNLOCK(&inode->lock); - - if (heal->iatt.ia_type == IA_IFDIR) - { - ec_opendir(heal->fop->frame, heal->xl, mask, - EC_MINIMUM_ONE, ec_heal_reopen_cbk, NULL, - &heal->loc, fd, NULL); - } - else - { - flags = ctx_fd->flags & ~(O_TRUNC | O_APPEND); - - ec_open(heal->fop->frame, heal->xl, mask, EC_MINIMUM_ONE, - ec_heal_reopen_cbk, NULL, &heal->loc, flags, fd, - NULL); - } - - LOCK(&inode->lock); - } - } - } - - UNLOCK(&inode->lock); -} - int32_t ec_heal_writev_cbk (call_frame_t *frame, void *cookie, xlator_t *this, int32_t op_ret, int32_t op_errno, @@ -1146,515 +279,8 @@ void ec_heal_data_block(ec_heal_t *heal) } } -void ec_heal_update_dirty(ec_heal_t *heal, uintptr_t mask) -{ - dict_t *dict; - - dict = dict_new(); - if (dict == NULL) { - ec_fop_set_error(heal->fop, EIO); - - return; - } - - if (ec_dict_set_number(dict, EC_XATTR_DIRTY, -1) != 0) { - dict_unref(dict); - ec_fop_set_error(heal->fop, EIO); - - return; - } - - ec_fxattrop(heal->fop->frame, heal->xl, mask, EC_MINIMUM_ONE, NULL, NULL, - heal->fd, GF_XATTROP_ADD_ARRAY64, dict, NULL); - - dict_unref(dict); -} - -void ec_heal_dispatch(ec_heal_t *heal) -{ - ec_fop_data_t *fop; - ec_cbk_data_t *cbk; - inode_t *inode; - ec_inode_t *ctx; - ec_heal_t *next = NULL; - struct list_head list; - int32_t error; - - inode = heal->loc.inode; - - INIT_LIST_HEAD(&list); - - LOCK(&inode->lock); - - /* done == 0 means that self-heal is still running (it shouldn't happen) - * done == 1 means that self-heal has just completed - * done == 2 means that self-heal has completed and reported */ - if (heal->done == 1) { - heal->done = 2; - list_del_init(&heal->list); - ctx = __ec_inode_get(inode, heal->xl); - if (ctx != NULL) { - ctx->bad &= ~heal->good; - - if (heal->partial) { - /* Collect all partial heal requests. All of them will receive - * the same answer. 'next' will contain a pointer to the first - * full request (if any) after this partial heal request.*/ - while (!list_empty(&ctx->heal)) { - next = list_entry(ctx->heal.next, ec_heal_t, list); - if (!next->partial) { - break; - } - - /* Setting 'done' to 2 avoids executing all heal logic and - * directly reports the result to the caller. */ - next->done = 2; - - list_move_tail(&next->list, &list); - } - if (list_empty(&ctx->heal)) { - next = NULL; - } - } else { - /* This is a full heal request, so take all received heal - * requests to answer them now. */ - list_splice_init(&ctx->heal, &list); - } - } - } - - UNLOCK(&inode->lock); - - fop = heal->fop; - error = fop->error; - - cbk = ec_cbk_data_allocate(fop->frame, heal->xl, fop, fop->id, 0, - error == 0 ? 0 : -1, error); - if (cbk != NULL) { - cbk->uintptr[0] = heal->available; - cbk->uintptr[1] = heal->good; - cbk->uintptr[2] = heal->fixed; - - ec_combine(cbk, NULL); - - fop->answer = cbk; - } else if (error == 0) { - error = ENOMEM; - } - - if (heal->lookup != NULL) - { - ec_fop_data_release(heal->lookup); - } - if (heal->fd != NULL) - { - fd_unref(heal->fd); - } - GF_FREE(heal->symlink); - loc_wipe(&heal->loc); - - LOCK_DESTROY(&heal->lock); - - GF_FREE(heal); - - ec_fop_set_error(fop, error); - - /* Resume all pending heal requests, setting the same data obtained by - * this heal execution. */ - while (!list_empty(&list)) { - heal = list_entry(list.next, ec_heal_t, list); - list_del_init(&heal->list); - - heal->available = cbk->uintptr[0]; - heal->good = cbk->uintptr[1]; - heal->fixed = cbk->uintptr[2]; - - ec_resume(heal->fop, error); - } - - /* If there is a pending full request, resume it. */ - if (next != NULL) { - ec_resume(next->fop, 0); - } -} - -void ec_wind_heal(ec_t * ec, ec_fop_data_t * fop, int32_t idx) -{ - ec_cbk_data_t * cbk; - ec_heal_t *heal = fop->heal; - - ec_trace("WIND", fop, "idx=%d", idx); - - cbk = ec_cbk_data_allocate(fop->frame, fop->xl, fop, EC_FOP_HEAL, idx, - fop->error == 0 ? 0 : -1, fop->error); - if (cbk != NULL) - { - cbk->uintptr[0] = heal->available; - cbk->uintptr[1] = heal->good; - cbk->uintptr[2] = heal->bad; - - ec_combine(cbk, NULL); - } - - ec_complete(fop); -} - -int32_t -ec_manager_heal (ec_fop_data_t * fop, int32_t state) -{ - ec_cbk_data_t * cbk; - ec_heal_t *heal = fop->heal; - - switch (state) - { - case EC_STATE_INIT: - ec_owner_set(fop->frame, fop->frame->root); - - fop->error = ec_heal_init(fop); - if (fop->error != 0) - { - return EC_STATE_REPORT; - } - - heal = fop->heal; - /* root loc doesn't have pargfid/parent */ - if (loc_is_root (&heal->loc) || - !gf_uuid_is_null(heal->loc.pargfid) || heal->loc.parent) { - heal->nameheal = _gf_true; - return EC_STATE_DISPATCH; - } else { - /* No need to perform 'name' heal.*/ - return EC_STATE_HEAL_PRE_INODELK_LOCK; - } - - case EC_STATE_DISPATCH: - if (heal->done != 0) { - return EC_STATE_HEAL_DISPATCH; - } - - ec_heal_entrylk(heal, F_WRLCK); - - return EC_STATE_HEAL_ENTRY_LOOKUP; - - case EC_STATE_HEAL_ENTRY_LOOKUP: - ec_lookup(fop->frame, heal->xl, fop->mask, EC_MINIMUM_MIN, - ec_heal_entry_lookup_cbk, heal, &heal->loc, NULL); - - return EC_STATE_HEAL_ENTRY_PREPARE; - - case EC_STATE_HEAL_ENTRY_PREPARE: - if (!heal->partial || (heal->iatt.ia_type == IA_IFDIR)) { - ec_heal_prepare(heal); - } - - if (heal->partial) { - return EC_STATE_HEAL_UNLOCK_ENTRY; - } - - return EC_STATE_HEAL_PRE_INODELK_LOCK; - - case EC_STATE_HEAL_PRE_INODELK_LOCK: - if (heal->done) - return EC_STATE_HEAL_DISPATCH; - - /* Only heal data/metadata if enough information is supplied. */ - if (gf_uuid_is_null(heal->loc.gfid)) - { - ec_heal_entrylk(heal, F_UNLCK); - - return EC_STATE_HEAL_DISPATCH; - } - - ec_heal_inodelk(heal, F_WRLCK, 0, 0, 0); - - return EC_STATE_HEAL_PRE_INODE_LOOKUP; - - case EC_STATE_HEAL_PRE_INODE_LOOKUP: - ec_heal_lookup(heal, heal->fop->mask); - - return EC_STATE_HEAL_XATTRIBUTES_REMOVE; - - case EC_STATE_HEAL_XATTRIBUTES_REMOVE: - ec_heal_removexattr_others(heal); - - return EC_STATE_HEAL_XATTRIBUTES_SET; - - case EC_STATE_HEAL_XATTRIBUTES_SET: - ec_heal_setxattr_others(heal); - - return EC_STATE_HEAL_ATTRIBUTES; - - case EC_STATE_HEAL_ATTRIBUTES: - ec_heal_attr(heal); - - return EC_STATE_HEAL_OPEN; - - case EC_STATE_HEAL_OPEN: - ec_heal_open(heal); - - return EC_STATE_HEAL_REOPEN_FD; - - case EC_STATE_HEAL_REOPEN_FD: - ec_heal_reopen_fd(heal); - - return EC_STATE_HEAL_UNLOCK; - - case -EC_STATE_HEAL_XATTRIBUTES_REMOVE: - case -EC_STATE_HEAL_XATTRIBUTES_SET: - case -EC_STATE_HEAL_ATTRIBUTES: - case -EC_STATE_HEAL_OPEN: - case -EC_STATE_HEAL_REOPEN_FD: - case -EC_STATE_HEAL_UNLOCK: - case EC_STATE_HEAL_UNLOCK: - ec_heal_inodelk(heal, F_UNLCK, 0, 0, 0); - - /* Fall through */ - - case -EC_STATE_HEAL_ENTRY_PREPARE: - case -EC_STATE_HEAL_PRE_INODELK_LOCK: - case -EC_STATE_HEAL_PRE_INODE_LOOKUP: - case -EC_STATE_HEAL_UNLOCK_ENTRY: - case EC_STATE_HEAL_UNLOCK_ENTRY: - if (heal->nameheal) - ec_heal_entrylk(heal, F_UNLCK); - - heal->bad = ec_heal_needs_data_rebuild(heal); - if (heal->bad != 0) - { - return EC_STATE_HEAL_DATA_LOCK; - } - - return EC_STATE_HEAL_DISPATCH; - - case EC_STATE_HEAL_DATA_LOCK: - if (heal->done != 0) - { - return EC_STATE_HEAL_POST_INODELK_LOCK; - } - - ec_heal_inodelk(heal, F_WRLCK, 1, heal->offset, heal->size); - - return EC_STATE_HEAL_DATA_COPY; - - case EC_STATE_HEAL_DATA_COPY: - ec_heal_data_block(heal); - - return EC_STATE_HEAL_DATA_UNLOCK; - - case -EC_STATE_HEAL_DATA_COPY: - case -EC_STATE_HEAL_DATA_UNLOCK: - case EC_STATE_HEAL_DATA_UNLOCK: - ec_heal_inodelk(heal, F_UNLCK, 1, heal->offset, heal->size); - - heal->offset += heal->size; - - return EC_STATE_HEAL_DATA_LOCK; - - case EC_STATE_HEAL_POST_INODELK_LOCK: - ec_heal_inodelk(heal, F_WRLCK, 1, 0, 0); - - return EC_STATE_HEAL_POST_INODE_LOOKUP; - - case EC_STATE_HEAL_POST_INODE_LOOKUP: - heal->fixed = heal->bad; - ec_heal_update_dirty(heal, heal->bad); - ec_heal_lookup(heal, heal->good); - - return EC_STATE_HEAL_SETATTR; - - case EC_STATE_HEAL_SETATTR: - ec_setattr(heal->fop->frame, heal->xl, heal->fixed, EC_MINIMUM_ONE, - ec_heal_setattr_cbk, heal, &heal->loc, &heal->iatt, - GF_SET_ATTR_MODE | GF_SET_ATTR_UID | GF_SET_ATTR_GID | - GF_SET_ATTR_ATIME | GF_SET_ATTR_MTIME, NULL); - - return EC_STATE_HEAL_POST_INODELK_UNLOCK; - - case -EC_STATE_HEAL_SETATTR: - case -EC_STATE_HEAL_POST_INODELK_UNLOCK: - case EC_STATE_HEAL_POST_INODELK_UNLOCK: - ec_heal_inodelk(heal, F_UNLCK, 1, 0, 0); - - return EC_STATE_HEAL_DISPATCH; - - case -EC_STATE_HEAL_POST_INODELK_LOCK: - case -EC_STATE_HEAL_POST_INODE_LOOKUP: - case -EC_STATE_HEAL_ENTRY_LOOKUP: - case -EC_STATE_HEAL_DATA_LOCK: - case -EC_STATE_HEAL_DISPATCH: - case EC_STATE_HEAL_DISPATCH: - ec_heal_dispatch(heal); - - 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->id == EC_FOP_HEAL) - { - if (fop->cbks.heal != NULL) - { - fop->cbks.heal(fop->req_frame, fop, fop->xl, cbk->op_ret, - cbk->op_errno, cbk->uintptr[0], - cbk->uintptr[1], cbk->uintptr[2], - cbk->xdata); - } - } - else - { - if (fop->cbks.fheal != NULL) - { - fop->cbks.fheal(fop->req_frame, fop, fop->xl, cbk->op_ret, - cbk->op_errno, cbk->uintptr[0], - cbk->uintptr[1], cbk->uintptr[2], - cbk->xdata); - } - } - - return EC_STATE_END; - - case -EC_STATE_INIT: - case -EC_STATE_DISPATCH: - case -EC_STATE_PREPARE_ANSWER: - case -EC_STATE_REPORT: - GF_ASSERT(fop->error != 0); - - if (fop->id == EC_FOP_HEAL) - { - if (fop->cbks.heal != NULL) - { - fop->cbks.heal(fop->req_frame, fop, fop->xl, -1, - fop->error, 0, 0, 0, NULL); - } - } - else - { - if (fop->cbks.fheal != NULL) - { - fop->cbks.fheal(fop->req_frame, fop, fop->xl, -1, - fop->error, 0, 0, 0, NULL); - } - } - - return EC_STATE_END; - - default: - gf_msg (fop->xl->name, GF_LOG_ERROR, 0, - EC_MSG_UNHANDLED_STATE, "Unhandled state %d for %s", - state, ec_fop_name(fop->id)); - - return EC_STATE_END; - } -} - -void ec_heal2(call_frame_t *frame, xlator_t *this, uintptr_t target, - int32_t minimum, fop_heal_cbk_t func, void *data, loc_t *loc, - int32_t partial, dict_t *xdata) -{ - ec_cbk_t callback = { .heal = func }; - ec_fop_data_t * fop = NULL; - int32_t error = EIO; - - gf_msg_trace ("ec", 0, "EC(HEAL) %p", frame); - - VALIDATE_OR_GOTO(this, out); - GF_VALIDATE_OR_GOTO(this->name, this->private, out); - - fop = ec_fop_data_allocate(frame, this, EC_FOP_HEAL, - EC_FLAG_UPDATE_LOC_INODE, target, minimum, - ec_wind_heal, ec_manager_heal, callback, data); - if (fop == NULL) - { - goto out; - } - - fop->int32 = partial; - - if (loc != NULL) - { - if (loc_copy(&fop->loc[0], loc) != 0) - { - gf_msg (this->name, GF_LOG_ERROR, 0, - EC_MSG_LOC_COPY_FAIL, "Failed to copy a location."); - - goto out; - } - } - if (xdata != NULL) - { - fop->xdata = dict_ref(xdata); - if (fop->xdata == NULL) - { - gf_msg (this->name, GF_LOG_ERROR, 0, - EC_MSG_DICT_REF_FAIL, "Failed to reference a " - "dictionary."); - - goto out; - } - } - - error = 0; - -out: - if (fop != NULL) - { - ec_manager(fop, error); - } - else - { - func(frame, NULL, this, -1, EIO, 0, 0, 0, NULL); - } -} - /* FOP: fheal */ -void ec_wind_fheal(ec_t * ec, ec_fop_data_t * fop, int32_t idx) -{ - ec_cbk_data_t * cbk; - ec_heal_t *heal = fop->heal; - - ec_trace("WIND", fop, "idx=%d", idx); - - cbk = ec_cbk_data_allocate(fop->frame, fop->xl, fop, EC_FOP_FHEAL, idx, - fop->error == 0 ? 0 : -1, fop->error); - if (cbk != NULL) - { - cbk->uintptr[0] = heal->available; - cbk->uintptr[1] = heal->good; - cbk->uintptr[2] = heal->bad; - - ec_combine(cbk, NULL); - } - - ec_complete(fop); -} - void ec_fheal(call_frame_t * frame, xlator_t * this, uintptr_t target, int32_t minimum, fop_fheal_cbk_t func, void * data, fd_t * fd, int32_t partial, dict_t *xdata) @@ -3123,7 +1749,7 @@ ec_heal_block (call_frame_t *frame, xlator_t *this, uintptr_t target, fop = ec_fop_data_allocate (frame, this, EC_FOP_HEAL, EC_FLAG_UPDATE_LOC_INODE, target, minimum, - ec_wind_heal, ec_manager_heal_block, callback, + NULL, ec_manager_heal_block, callback, heal); if (fop == NULL) goto out; @@ -3713,7 +2339,7 @@ ec_heal (call_frame_t *frame, xlator_t *this, uintptr_t target, goto fail; fop = ec_fop_data_allocate (frame, this, EC_FOP_HEAL, EC_FLAG_UPDATE_LOC_INODE, target, minimum, - ec_wind_heal, ec_manager_heal, callback, data); + NULL, NULL, callback, data); if (fop == NULL) goto fail; |