diff options
Diffstat (limited to 'xlators/cluster/afr/src/afr-open.c')
| -rw-r--r-- | xlators/cluster/afr/src/afr-open.c | 597 |
1 files changed, 246 insertions, 351 deletions
diff --git a/xlators/cluster/afr/src/afr-open.c b/xlators/cluster/afr/src/afr-open.c index ae58eef06..643a5d692 100644 --- a/xlators/cluster/afr/src/afr-open.c +++ b/xlators/cluster/afr/src/afr-open.c @@ -1,20 +1,11 @@ /* - Copyright (c) 2007-2009 Gluster, Inc. <http://www.gluster.com> - This file is part of GlusterFS. - - 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. - - 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 this program. If not, see - <http://www.gnu.org/licenses/>. + Copyright (c) 2008-2012 Red Hat, Inc. <http://www.redhat.com> + 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 <libgen.h> @@ -52,436 +43,340 @@ #include "afr-dir-read.h" #include "afr-dir-write.h" #include "afr-transaction.h" - #include "afr-self-heal.h" - +#include "afr-self-heal-common.h" int -afr_open_ftruncate_cbk (call_frame_t *frame, void *cookie, xlator_t *this, - int32_t op_ret, int32_t op_errno, struct stat *prebuf, - struct stat *postbuf) +afr_stale_child_up (afr_local_t *local, xlator_t *this) { - afr_local_t * local = frame->local; - - AFR_STACK_UNWIND (open, frame, local->op_ret, local->op_errno, - local->fd); - return 0; -} - - -int -afr_open_cbk (call_frame_t *frame, void *cookie, - xlator_t *this, int32_t op_ret, int32_t op_errno, - fd_t *fd) -{ - afr_local_t * local = NULL; - afr_private_t * priv = NULL; - - int child_index = (long) cookie; - - uint64_t ctx; - afr_fd_ctx_t *fd_ctx; - - int ret = 0; - - int call_count = -1; - - priv = this->private; - local = frame->local; - - LOCK (&frame->lock); - { - if (op_ret == -1) { - local->op_errno = op_errno; - } - - if (op_ret >= 0) { - local->op_ret = op_ret; - local->success_count++; - - ret = afr_fd_ctx_set (this, fd); - - if (ret < 0) { - gf_log (this->name, GF_LOG_DEBUG, - "could not set fd ctx for fd=%p", - fd); - - local->op_ret = -1; - local->op_errno = -ret; - } - - ret = fd_ctx_get (fd, this, &ctx); - - if (ret < 0) { - gf_log (this->name, GF_LOG_DEBUG, - "could not get fd ctx for fd=%p", fd); - local->op_ret = -1; - local->op_errno = -ret; - } + int i = 0; + afr_private_t *priv = NULL; + int up = -1; - fd_ctx = (afr_fd_ctx_t *)(long) ctx; + priv = this->private; - fd_ctx->opened_on[child_index] = 1; - fd_ctx->flags = local->cont.open.flags; - fd_ctx->wbflags = local->cont.open.wbflags; - } - } - UNLOCK (&frame->lock); - - call_count = afr_frame_return (frame); + if (!local->fresh_children) + local->fresh_children = afr_children_create (priv->child_count); + if (!local->fresh_children) + goto out; - if (call_count == 0) { - if ((local->cont.open.flags & O_TRUNC) - && (local->op_ret >= 0)) { - STACK_WIND (frame, afr_open_ftruncate_cbk, - this, this->fops->ftruncate, - fd, 0); - } else { - AFR_STACK_UNWIND (open, frame, local->op_ret, - local->op_errno, local->fd); - } - } + afr_inode_get_read_ctx (this, local->fd->inode, local->fresh_children); + if (priv->child_count == afr_get_children_count (local->fresh_children, + priv->child_count)) + goto out; - return 0; + for (i = 0; i < priv->child_count; i++) { + if (!local->child_up[i]) + continue; + if (afr_is_child_present (local->fresh_children, + priv->child_count, i)) + continue; + up = i; + break; + } +out: + return up; } - -int -afr_open (call_frame_t *frame, xlator_t *this, loc_t *loc, int32_t flags, - fd_t *fd, int32_t wbflags) +void +afr_perform_data_self_heal (call_frame_t *frame, xlator_t *this) { - afr_private_t * priv = NULL; - afr_local_t * local = NULL; - - int i = 0; - int ret = -1; - - int32_t call_count = 0; - int32_t op_ret = -1; - int32_t op_errno = 0; - int32_t wind_flags = flags & (~O_TRUNC); - - VALIDATE_OR_GOTO (frame, out); - VALIDATE_OR_GOTO (this, out); - VALIDATE_OR_GOTO (this->private, out); - VALIDATE_OR_GOTO (loc, out); - - priv = this->private; - - if (afr_is_split_brain (this, loc->inode)) { - /* self-heal failed */ - op_errno = EIO; - goto out; - } - - ALLOC_OR_GOTO (local, afr_local_t, out); - - ret = AFR_LOCAL_INIT (local, priv); - if (ret < 0) { - op_errno = -ret; - goto out; - } - - frame->local = local; - call_count = local->call_count; - - loc_copy (&local->loc, loc); + afr_local_t *local = NULL; + afr_self_heal_t *sh = NULL; + inode_t *inode = NULL; + int st_child = -1; + char reason[64] = {0}; - local->cont.open.flags = flags; - local->cont.open.wbflags = wbflags; + local = frame->local; + sh = &local->self_heal; + inode = local->fd->inode; - local->fd = fd_ref (fd); + if (!IA_ISREG (inode->ia_type)) + goto out; - for (i = 0; i < priv->child_count; i++) { - if (local->child_up[i]) { - STACK_WIND_COOKIE (frame, afr_open_cbk, (void *) (long) i, - priv->children[i], - priv->children[i]->fops->open, - loc, wind_flags, fd, wbflags); + st_child = afr_stale_child_up (local, this); + if (st_child < 0) + goto out; - if (!--call_count) - break; - } - } + sh->do_data_self_heal = _gf_true; + sh->do_metadata_self_heal = _gf_true; + sh->do_gfid_self_heal = _gf_true; + sh->do_missing_entry_self_heal = _gf_true; - op_ret = 0; + snprintf (reason, sizeof (reason), "stale subvolume %d detected", + st_child); + afr_launch_self_heal (frame, this, inode, _gf_true, inode->ia_type, + reason, NULL, NULL); out: - if (op_ret == -1) { - AFR_STACK_UNWIND (open, frame, op_ret, op_errno, fd); - } - - return 0; + return; } - int -afr_up_down_flush_open_cbk (call_frame_t *frame, void *cookie, - xlator_t *this, int32_t op_ret, int32_t op_errno, - fd_t *fd) +afr_open_ftruncate_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) { - afr_local_t *local = NULL; + afr_local_t * local = frame->local; afr_private_t *priv = NULL; - int ret = 0; + priv = this->private; + if (afr_open_only_data_self_heal (priv->data_self_heal)) + afr_perform_data_self_heal (frame, this); + AFR_STACK_UNWIND (open, frame, local->op_ret, local->op_errno, + local->fd, xdata); + return 0; +} - uint64_t ctx; - afr_fd_ctx_t *fd_ctx; - int call_count = 0; - int child_index = (long) cookie; +int +afr_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) +{ + afr_local_t * local = NULL; + int ret = 0; + int call_count = -1; + int child_index = (long) cookie; + afr_private_t *priv = NULL; - priv = this->private; + priv = this->private; local = frame->local; LOCK (&frame->lock); { + if (op_ret == -1) { + local->op_errno = op_errno; + } + if (op_ret >= 0) { - ret = fd_ctx_get (fd, this, &ctx); + local->op_ret = op_ret; + local->success_count++; - if (ret < 0) { - goto out; + ret = afr_child_fd_ctx_set (this, fd, child_index, + local->cont.open.flags); + if (ret) { + local->op_ret = -1; + local->op_errno = -ret; + goto unlock; } - - fd_ctx = (afr_fd_ctx_t *)(long) ctx; - - fd_ctx->opened_on[child_index] = 1; - - gf_log (this->name, GF_LOG_TRACE, - "fd for %s opened successfully on subvolume %s", - local->loc.path, priv->children[child_index]->name); } } -out: +unlock: UNLOCK (&frame->lock); call_count = afr_frame_return (frame); if (call_count == 0) { - local->transaction.post_post_op (frame, this); + if ((local->cont.open.flags & O_TRUNC) + && (local->op_ret >= 0)) { + STACK_WIND (frame, afr_open_ftruncate_cbk, + this, this->fops->ftruncate, + fd, 0, NULL); + } else { + if (afr_open_only_data_self_heal (priv->data_self_heal)) + afr_perform_data_self_heal (frame, this); + AFR_STACK_UNWIND (open, frame, local->op_ret, + local->op_errno, local->fd, xdata); + } } return 0; } - -static int -__unopened_count (int child_count, unsigned char *opened_on, unsigned char *child_up) -{ - int i; - int count = 0; - - for (i = 0; i < child_count; i++) { - if (!opened_on[i] && child_up[i]) - count++; - } - - return count; -} - - int -afr_up_down_flush_sh_unwind (call_frame_t *frame, xlator_t *this) +afr_open (call_frame_t *frame, xlator_t *this, loc_t *loc, int32_t flags, + fd_t *fd, dict_t *xdata) { - afr_local_t *local = NULL; - afr_private_t *priv = NULL; - - uint64_t ctx; - afr_fd_ctx_t *fd_ctx; + afr_private_t * priv = NULL; + afr_local_t * local = NULL; + int i = 0; + int ret = -1; + int32_t call_count = 0; + int32_t op_errno = 0; + int32_t wind_flags = flags & (~O_TRUNC); + //We can't let truncation to happen outside transaction. + + VALIDATE_OR_GOTO (frame, out); + VALIDATE_OR_GOTO (this, out); + VALIDATE_OR_GOTO (this->private, out); + VALIDATE_OR_GOTO (loc, out); + + priv = this->private; + + if (flags & (O_CREAT|O_TRUNC)) { + QUORUM_CHECK(open,out); + } - int abandon = 0; - int ret = 0; - int i; - int call_count = 0; + if (afr_is_split_brain (this, loc->inode)) { + /* self-heal failed */ + gf_log (this->name, GF_LOG_WARNING, + "failed to open as split brain seen, returning EIO"); + op_errno = EIO; + goto out; + } - priv = this->private; + AFR_LOCAL_ALLOC_OR_GOTO (frame->local, out); local = frame->local; - /* - * Some subvolumes might have come up on which we never - * opened this fd in the first place. Re-open fd's on those - * subvolumes now. - */ - - ret = fd_ctx_get (local->fd, this, &ctx); - - if (ret < 0) { - abandon = 1; + ret = afr_local_init (local, priv, &op_errno); + if (ret < 0) goto out; - } - fd_ctx = (afr_fd_ctx_t *)(long) ctx; + call_count = local->call_count; + loc_copy (&local->loc, loc); - call_count = __unopened_count (priv->child_count, fd_ctx->opened_on, - local->child_up); + local->cont.open.flags = flags; - if (call_count == 0) { - abandon = 1; - goto out; - } - - local->call_count = call_count; + local->fd = fd_ref (fd); for (i = 0; i < priv->child_count; i++) { - if (!fd_ctx->opened_on[i] && local->child_up[i]) { - gf_log (this->name, GF_LOG_TRACE, - "opening fd for %s on subvolume %s", - local->loc.path, priv->children[i]->name); - - STACK_WIND_COOKIE (frame, afr_up_down_flush_open_cbk, - (void *)(long) i, + if (local->child_up[i]) { + STACK_WIND_COOKIE (frame, afr_open_cbk, (void *) (long) i, priv->children[i], priv->children[i]->fops->open, - &local->loc, fd_ctx->flags, local->fd, - fd_ctx->wbflags); + loc, wind_flags, fd, xdata); if (!--call_count) break; } } + ret = 0; out: - if (abandon) - local->transaction.post_post_op (frame, this); - - return 0; -} - - -int -afr_up_down_flush_post_post_op (call_frame_t *frame, xlator_t *this) -{ - afr_private_t *priv = NULL; - afr_local_t *local = NULL; - afr_self_heal_t *sh = NULL; - - priv = this->private; - local = frame->local; - sh = &local->self_heal; - - inode_path (local->fd->inode, NULL, (char **)&local->loc.path); - local->loc.name = strrchr (local->loc.path, '/'); - local->loc.inode = inode_ref (local->fd->inode); - local->loc.parent = inode_parent (local->fd->inode, 0, NULL); - - /* forcibly trigger missing-entries self-heal */ - - local->success_count = 1; - local->enoent_count = 1; - - sh->data_lock_held = _gf_true; - sh->need_data_self_heal = _gf_true; - sh->mode = local->fd->inode->st_mode; - sh->background = _gf_false; - sh->unwind = afr_up_down_flush_sh_unwind; - - afr_self_heal (frame, this); + if (ret < 0) + AFR_STACK_UNWIND (open, frame, -1, op_errno, fd, xdata); return 0; } - -int -afr_up_down_flush_wind (call_frame_t *frame, xlator_t *this) -{ - afr_local_t *local = NULL; - afr_private_t *priv = NULL; - - local = frame->local; - priv = this->private; - - local->transaction.resume (frame, this); - return 0; -} - - int -afr_up_down_flush_done (call_frame_t *frame, xlator_t *this) +afr_openfd_fix_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) { - afr_private_t *priv = NULL; - afr_local_t *local = NULL; - - uint64_t ctx; - afr_fd_ctx_t * fd_ctx = NULL; - - int _ret = -1; - int i = 0; + afr_local_t *local = NULL; + afr_private_t *priv = NULL; + afr_fd_ctx_t *fd_ctx = NULL; + int call_count = 0; + int child_index = (long) cookie; + + priv = this->private; + local = frame->local; + + if (op_ret >= 0) { + gf_log (this->name, GF_LOG_DEBUG, "fd for %s opened " + "successfully on subvolume %s", local->loc.path, + priv->children[child_index]->name); + } else { + gf_log (this->name, GF_LOG_ERROR, "Failed to open %s " + "on subvolume %s", local->loc.path, + priv->children[child_index]->name); + } - priv = this->private; - local = frame->local; + fd_ctx = afr_fd_ctx_get (local->fd, this); + if (!fd_ctx) { + gf_log (this->name, GF_LOG_WARNING, + "failed to get fd context, %p", local->fd); + goto out; + } LOCK (&local->fd->lock); { - _ret = __fd_ctx_get (local->fd, this, &ctx); - - if (_ret < 0) { - goto out; - } - - fd_ctx = (afr_fd_ctx_t *)(long) ctx; - - fd_ctx->down_count = priv->down_count; - fd_ctx->up_count = priv->up_count; - - for (i = 0; i < priv->child_count; i++) { - if (local->child_up[i]) - fd_ctx->pre_op_done[i] = 0; + if (op_ret >= 0) { + fd_ctx->opened_on[child_index] = AFR_FD_OPENED; + } else { + fd_ctx->opened_on[child_index] = AFR_FD_NOT_OPENED; } } -out: UNLOCK (&local->fd->lock); +out: + call_count = afr_frame_return (frame); + if (call_count == 0) + AFR_STACK_DESTROY (frame); - afr_local_transaction_cleanup (local, this); - - local->up_down_flush_cbk (frame, this); - - return 0; + return 0; } - -int -afr_up_down_flush (call_frame_t *frame, xlator_t *this, fd_t *fd, - afr_flush_type type) +void +afr_fix_open (xlator_t *this, fd_t *fd, size_t need_open_count, int *need_open) { - afr_private_t * priv = NULL; - afr_local_t * local = NULL; + afr_private_t *priv = NULL; + int i = 0; + call_frame_t *frame = NULL; + afr_local_t *local = NULL; + int ret = -1; + int32_t op_errno = 0; + afr_fd_ctx_t *fd_ctx = NULL; - int op_ret = -1; + priv = this->private; - VALIDATE_OR_GOTO (frame, out); - VALIDATE_OR_GOTO (this, out); - VALIDATE_OR_GOTO (this->private, out); + if (!afr_is_fd_fixable (fd) || !need_open || !need_open_count) + goto out; - priv = this->private; + fd_ctx = afr_fd_ctx_get (fd, this); + if (!fd_ctx) { + ret = -1; + goto out; + } - local = frame->local; + frame = create_frame (this, this->ctx->pool); + if (!frame) { + ret = -1; + goto out; + } - local->op = GF_FOP_FLUSH; + AFR_LOCAL_ALLOC_OR_GOTO (frame->local, out); + local = frame->local; + ret = afr_local_init (local, priv, &op_errno); + if (ret < 0) + goto out; -// local->fd = fd_ref (local->fd); + local->loc.inode = inode_ref (fd->inode); + ret = loc_path (&local->loc, NULL); + if (ret < 0) + goto out; - local->transaction.fop = afr_up_down_flush_wind; - local->transaction.done = afr_up_down_flush_done; + local->fd = fd_ref (fd); + local->call_count = need_open_count; - switch (type) { - case AFR_CHILD_UP_FLUSH: - local->transaction.post_post_op = afr_up_down_flush_post_post_op; - break; + gf_log (this->name, GF_LOG_DEBUG, "need open count: %zd", + need_open_count); - case AFR_CHILD_DOWN_FLUSH: - local->transaction.post_post_op = NULL; - break; - } + for (i = 0; i < priv->child_count; i++) { + if (!need_open[i]) + continue; - local->transaction.start = 0; - local->transaction.len = 0; + if (IA_IFDIR == fd->inode->ia_type) { + gf_log (this->name, GF_LOG_DEBUG, + "opening fd for dir %s on subvolume %s", + local->loc.path, priv->children[i]->name); - gf_log (this->name, GF_LOG_TRACE, - "doing up/down flush on fd=%p", - fd); + STACK_WIND_COOKIE (frame, afr_openfd_fix_open_cbk, + (void*) (long) i, + priv->children[i], + priv->children[i]->fops->opendir, + &local->loc, local->fd, + NULL); + } else { + gf_log (this->name, GF_LOG_DEBUG, + "opening fd for file %s on subvolume %s", + local->loc.path, priv->children[i]->name); - afr_transaction (frame, this, AFR_FLUSH_TRANSACTION); + STACK_WIND_COOKIE (frame, afr_openfd_fix_open_cbk, + (void *)(long) i, + priv->children[i], + priv->children[i]->fops->open, + &local->loc, + fd_ctx->flags & (~O_TRUNC), + local->fd, NULL); + } - op_ret = 0; + } + op_errno = 0; + ret = 0; out: - return 0; + if (op_errno) + ret = -1; //For handling ALLOC_OR_GOTO + if (ret && frame) + AFR_STACK_DESTROY (frame); } |
