diff options
author | Pranith Kumar K <pkarampu@redhat.com> | 2014-09-14 16:51:25 +0530 |
---|---|---|
committer | Vijay Bellur <vbellur@redhat.com> | 2014-09-15 23:02:27 -0700 |
commit | 3719996a2d31d492d8a3b3f7defe57c2108c3f45 (patch) | |
tree | a0aa972affd369f3e42fe91288b19a0588f3e13c /xlators/cluster | |
parent | cc332a8f1766562b407dcc6b9cd88a7f5adee216 (diff) |
cluster/afr: Handle EAGAIN properly in inodelk
Problem:
When one of the brick is taken down and brough back up in a replica pair, locks
on that brick will be allowed. Afr returns inodelk success even when one of the
bricks already has the lock taken.
Fix:
If any brick returns EAGAIN return failure to parent xlator.
BUG: 1142020
Change-Id: Iee3f5990be75e10f8accec9bc3856e3f76d1593c
Signed-off-by: Pranith Kumar K <pkarampu@redhat.com>
Reviewed-on: http://review.gluster.org/8744
Tested-by: Gluster Build System <jenkins@build.gluster.com>
Reviewed-by: Vijay Bellur <vbellur@redhat.com>
Diffstat (limited to 'xlators/cluster')
-rw-r--r-- | xlators/cluster/afr/src/afr-common.c | 139 | ||||
-rw-r--r-- | xlators/cluster/afr/src/afr.h | 5 |
2 files changed, 130 insertions, 14 deletions
diff --git a/xlators/cluster/afr/src/afr-common.c b/xlators/cluster/afr/src/afr-common.c index cc7df9a3ea6..3d355b307cf 100644 --- a/xlators/cluster/afr/src/afr-common.c +++ b/xlators/cluster/afr/src/afr-common.c @@ -2560,6 +2560,72 @@ out: /* }}} */ +int32_t +afr_unlock_inodelk_cbk (call_frame_t *frame, void *cookie, xlator_t *this, + int32_t op_ret, int32_t op_errno, dict_t *xdata) + +{ + afr_local_t *local = NULL; + afr_private_t *priv = NULL; + int call_count = -1; + int child_index = (long)cookie; + uuid_t gfid = {0}; + + local = frame->local; + priv = this->private; + + if (op_ret < 0 && op_errno != ENOTCONN) { + loc_gfid (&local->loc, gfid); + gf_log (this->name, GF_LOG_ERROR, "%s: Failed to unlock %s " + "with lk_owner: %s (%s)", uuid_utoa (gfid), + priv->children[child_index]->name, + lkowner_utoa (&frame->root->lk_owner), + strerror (op_errno)); + } + + call_count = afr_frame_return (frame); + if (call_count == 0) { + AFR_STACK_UNWIND (inodelk, frame, local->op_ret, + local->op_errno, local->xdata_rsp); + } + + return 0; +} + +int32_t +afr_unlock_inodelks_and_unwind (call_frame_t *frame, xlator_t *this, + int call_count) +{ + int i = 0; + afr_private_t *priv = NULL; + afr_local_t *local = NULL; + + local = frame->local; + priv = this->private; + local->call_count = call_count; + local->cont.inodelk.flock.l_type = F_UNLCK; + + for (i = 0; i < priv->child_count; i++) { + if (!local->replies[i].valid) + continue; + + if (local->replies[i].op_ret == -1) + continue; + + STACK_WIND_COOKIE (frame, afr_unlock_inodelk_cbk, + (void*) (long) i, + priv->children[i], + priv->children[i]->fops->inodelk, + local->cont.inodelk.volume, + &local->loc, local->cont.inodelk.cmd, + &local->cont.inodelk.flock, 0); + + if (!--call_count) + break; + } + + return 0; +} int32_t afr_inodelk_cbk (call_frame_t *frame, void *cookie, xlator_t *this, @@ -2567,24 +2633,63 @@ afr_inodelk_cbk (call_frame_t *frame, void *cookie, xlator_t *this, { afr_local_t *local = NULL; + afr_private_t *priv = NULL; int call_count = -1; + int child_index = (long)cookie; + int i = 0; + int lock_count = 0; local = frame->local; + priv = this->private; - LOCK (&frame->lock); - { - if (op_ret == 0) - local->op_ret = 0; - - local->op_errno = op_errno; + local->replies[child_index].valid = 1; + local->replies[child_index].op_ret = op_ret; + local->replies[child_index].op_errno = op_errno; + if (op_ret == 0 && xdata) { + local->replies[child_index].xdata = dict_ref (xdata); + LOCK (&frame->lock); + { + if (!local->xdata_rsp) + local->xdata_rsp = dict_ref (xdata); + } + UNLOCK (&frame->lock); } - UNLOCK (&frame->lock); call_count = afr_frame_return (frame); - if (call_count == 0) - AFR_STACK_UNWIND (inodelk, frame, local->op_ret, - local->op_errno, xdata); + if (call_count == 0) { + for (i = 0; i < priv->child_count; i++) { + if (!local->replies[i].valid) + continue; + + if (local->replies[i].op_ret == 0) + lock_count++; + + if (local->op_ret == -1 && local->op_errno == EAGAIN) + continue; + + if ((local->replies[i].op_ret == -1) && + (local->replies[i].op_errno == EAGAIN)) { + local->op_ret = -1; + local->op_errno = EAGAIN; + continue; + } + + if (local->replies[i].op_ret == 0) + local->op_ret = 0; + + local->op_errno = local->replies[i].op_errno; + } + + if (lock_count && local->cont.inodelk.flock.l_type != F_UNLCK && + (local->op_ret == -1 && local->op_errno == EAGAIN)) { + afr_unlock_inodelks_and_unwind (frame, this, + lock_count); + } else { + AFR_STACK_UNWIND (inodelk, frame, local->op_ret, + local->op_errno, local->xdata_rsp); + } + } return 0; } @@ -2607,6 +2712,11 @@ afr_inodelk (call_frame_t *frame, xlator_t *this, if (!local) goto out; + loc_copy (&local->loc, loc); + local->cont.inodelk.volume = volume; + local->cont.inodelk.cmd = cmd; + local->cont.inodelk.flock = *flock; + call_count = local->call_count; if (!call_count) { op_errno = ENOMEM; @@ -2615,10 +2725,11 @@ afr_inodelk (call_frame_t *frame, xlator_t *this, for (i = 0; i < priv->child_count; i++) { if (local->child_up[i]) { - STACK_WIND (frame, afr_inodelk_cbk, - priv->children[i], - priv->children[i]->fops->inodelk, - volume, loc, cmd, flock, xdata); + STACK_WIND_COOKIE (frame, afr_inodelk_cbk, + (void*) (long) i, + priv->children[i], + priv->children[i]->fops->inodelk, + volume, loc, cmd, flock, xdata); if (!--call_count) break; diff --git a/xlators/cluster/afr/src/afr.h b/xlators/cluster/afr/src/afr.h index 35d4d545bc9..ddcb2c0e177 100644 --- a/xlators/cluster/afr/src/afr.h +++ b/xlators/cluster/afr/src/afr.h @@ -604,6 +604,11 @@ typedef struct _afr_local { struct iatt postbuf; } zerofill; + struct { + const char *volume; + int32_t cmd; + struct gf_flock flock; + } inodelk; } cont; |