7f4c2a
From f0e823dfc224c9c3c7a1179453ef6fe087171787 Mon Sep 17 00:00:00 2001
7f4c2a
From: Pranith Kumar K <pkarampu@redhat.com>
7f4c2a
Date: Wed, 15 Jul 2015 06:16:54 +0530
7f4c2a
Subject: [PATCH 244/244] cluster/ec: Handle race between unlock-timer, new lock
7f4c2a
7f4c2a
        Backport of http://review.gluster.org/11670
7f4c2a
7f4c2a
Problem:
7f4c2a
New lock could come at the time timer is on the way to unlock. This was leading
7f4c2a
to crash in timer thread because thread executing new lock can free up the
7f4c2a
timer_link->fop and then timer thread will try to access structures already
7f4c2a
freed.
7f4c2a
7f4c2a
Fix:
7f4c2a
If the timer event is fired, set lock->release to true and wait for unlock to
7f4c2a
complete.
7f4c2a
7f4c2a
Thanks to Xavi and Bhaskar for helping in confirming that this race is the RC.
7f4c2a
Thanks to Kritika for pointing out and explaining how Avati's patch can be used
7f4c2a
to fix this bug.
7f4c2a
7f4c2a
Change-Id: I45fa5470bbc1f03b5f3d133e26d1e0ab24303378
7f4c2a
BUG: 1242423
7f4c2a
Signed-off-by: Pranith Kumar K <pkarampu@redhat.com>
7f4c2a
Reviewed-on: https://code.engineering.redhat.com/gerrit/53061
7f4c2a
---
7f4c2a
 xlators/cluster/ec/src/ec-common.c |   33 ++++++++++++++-------------------
7f4c2a
 xlators/cluster/ec/src/ec-common.h |    1 -
7f4c2a
 xlators/cluster/ec/src/ec.c        |   33 +++------------------------------
7f4c2a
 3 files changed, 17 insertions(+), 50 deletions(-)
7f4c2a
7f4c2a
diff --git a/xlators/cluster/ec/src/ec-common.c b/xlators/cluster/ec/src/ec-common.c
7f4c2a
index b2d0348..ec6a4aa 100644
7f4c2a
--- a/xlators/cluster/ec/src/ec-common.c
7f4c2a
+++ b/xlators/cluster/ec/src/ec-common.c
7f4c2a
@@ -1358,13 +1358,20 @@ void ec_lock(ec_fop_data_t *fop)
7f4c2a
         if (lock->timer != NULL) {
7f4c2a
             GF_ASSERT (lock->release == _gf_false);
7f4c2a
             timer_link = lock->timer->data;
7f4c2a
-            ec_trace("UNLOCK_CANCELLED", timer_link->fop, "lock=%p", lock);
7f4c2a
-            gf_timer_call_cancel(fop->xl->ctx, lock->timer);
7f4c2a
-            lock->timer = NULL;
7f4c2a
-
7f4c2a
-            lock->refs--;
7f4c2a
-            /* There should remain at least 1 ref, the current one. */
7f4c2a
-            GF_ASSERT(lock->refs > 0);
7f4c2a
+            if (gf_timer_call_cancel(fop->xl->ctx, lock->timer) == 0) {
7f4c2a
+                    ec_trace("UNLOCK_CANCELLED", timer_link->fop,
7f4c2a
+                             "lock=%p", lock);
7f4c2a
+                    lock->timer = NULL;
7f4c2a
+                    lock->refs--;
7f4c2a
+                    /* There should remain at least 1 ref, the current one. */
7f4c2a
+                    GF_ASSERT(lock->refs > 0);
7f4c2a
+            } else {
7f4c2a
+                    /* Timer expired and on the way to unlock.
7f4c2a
+                     * Set lock->release to _gf_true, so that this
7f4c2a
+                     * lock will be put in frozen list*/
7f4c2a
+                    timer_link = NULL;
7f4c2a
+                    lock->release = _gf_true;
7f4c2a
+            }
7f4c2a
         }
7f4c2a
 
7f4c2a
         GF_ASSERT(list_empty(&link->wait_list));
7f4c2a
@@ -1815,18 +1822,6 @@ void ec_unlock(ec_fop_data_t *fop)
7f4c2a
     }
7f4c2a
 }
7f4c2a
 
7f4c2a
-void
7f4c2a
-ec_unlock_force(ec_fop_data_t *fop)
7f4c2a
-{
7f4c2a
-        int32_t i;
7f4c2a
-
7f4c2a
-        for (i = 0; i < fop->lock_count; i++) {
7f4c2a
-                ec_trace("UNLOCK_FORCED", fop, "lock=%p", &fop->locks[i]);
7f4c2a
-
7f4c2a
-                ec_unlock_timer_del(&fop->locks[i]);
7f4c2a
-        }
7f4c2a
-}
7f4c2a
-
7f4c2a
 void ec_flush_size_version(ec_fop_data_t *fop)
7f4c2a
 {
7f4c2a
     GF_ASSERT(fop->lock_count == 1);
7f4c2a
diff --git a/xlators/cluster/ec/src/ec-common.h b/xlators/cluster/ec/src/ec-common.h
7f4c2a
index 4c7fe0c..a851fb3 100644
7f4c2a
--- a/xlators/cluster/ec/src/ec-common.h
7f4c2a
+++ b/xlators/cluster/ec/src/ec-common.h
7f4c2a
@@ -91,7 +91,6 @@ void ec_lock_prepare_fd(ec_fop_data_t *fop, fd_t *fd, uint32_t flags);
7f4c2a
 void ec_lock(ec_fop_data_t * fop);
7f4c2a
 void ec_lock_reuse(ec_fop_data_t *fop);
7f4c2a
 void ec_unlock(ec_fop_data_t * fop);
7f4c2a
-void ec_unlock_force(ec_fop_data_t *fop);
7f4c2a
 
7f4c2a
 gf_boolean_t ec_get_inode_size(ec_fop_data_t *fop, inode_t *inode,
7f4c2a
                                uint64_t *size);
7f4c2a
diff --git a/xlators/cluster/ec/src/ec.c b/xlators/cluster/ec/src/ec.c
7f4c2a
index 4673c11..2885b01 100644
7f4c2a
--- a/xlators/cluster/ec/src/ec.c
7f4c2a
+++ b/xlators/cluster/ec/src/ec.c
7f4c2a
@@ -395,38 +395,11 @@ ec_handle_down (xlator_t *this, ec_t *ec, int32_t idx)
7f4c2a
 }
7f4c2a
 
7f4c2a
 gf_boolean_t
7f4c2a
-ec_force_unlocks(ec_t *ec)
7f4c2a
+ec_disable_delays(ec_t *ec)
7f4c2a
 {
7f4c2a
-        struct list_head list;
7f4c2a
-        ec_fop_data_t *fop;
7f4c2a
-
7f4c2a
-        if (list_empty(&ec->pending_fops)) {
7f4c2a
-                return _gf_true;
7f4c2a
-        }
7f4c2a
-
7f4c2a
-        INIT_LIST_HEAD(&list);
7f4c2a
-
7f4c2a
-        /* All pending fops when GF_EVENT_PARENT_DOWN is received should only
7f4c2a
-         * be fops waiting for a delayed unlock. However the unlock can
7f4c2a
-         * generate new fops. We don't want to trverse these new fops while
7f4c2a
-         * forcing unlocks, so we move all fops to a temporal list. To process
7f4c2a
-         * them without interferences.*/
7f4c2a
-        list_splice_init(&ec->pending_fops, &list);
7f4c2a
-
7f4c2a
-        while (!list_empty(&list)) {
7f4c2a
-                fop = list_entry(list.next, ec_fop_data_t, pending_list);
7f4c2a
-                list_move_tail(&fop->pending_list, &ec->pending_fops);
7f4c2a
-
7f4c2a
-                UNLOCK(&ec->lock);
7f4c2a
-
7f4c2a
-                ec_unlock_force(fop);
7f4c2a
-
7f4c2a
-                LOCK(&ec->lock);
7f4c2a
-        }
7f4c2a
-
7f4c2a
         ec->shutdown = _gf_true;
7f4c2a
 
7f4c2a
-        return list_empty(&ec->pending_fops);
7f4c2a
+        return list_empty (&ec->pending_fops);
7f4c2a
 }
7f4c2a
 
7f4c2a
 void
7f4c2a
@@ -482,7 +455,7 @@ ec_notify (xlator_t *this, int32_t event, void *data, void *data2)
7f4c2a
         } else if (event == GF_EVENT_PARENT_DOWN) {
7f4c2a
                 /* If there aren't pending fops running after we have waken up
7f4c2a
                  * them, we immediately propagate the notification. */
7f4c2a
-                propagate = ec_force_unlocks(ec);
7f4c2a
+                propagate = ec_disable_delays(ec);
7f4c2a
                 goto unlock;
7f4c2a
         }
7f4c2a
 
7f4c2a
-- 
7f4c2a
1.7.1
7f4c2a