cb8e9e
From 11dd368eae316c3cb9a1e82e7b7213d0ee4224c6 Mon Sep 17 00:00:00 2001
cb8e9e
From: Venky Shankar <vshankar@redhat.com>
cb8e9e
Date: Thu, 4 Jun 2015 08:50:48 +0530
cb8e9e
Subject: [PATCH 159/190] features/bitrot: cleanup, v2
cb8e9e
cb8e9e
    Backport of http://review.gluster.org/11148
cb8e9e
cb8e9e
This patch uses "cleanup, v1" infrastrcuture to cleanup scrubber
cb8e9e
(data structures, threads, timers, etc..) on brick disconnection.
cb8e9e
Signer is not cleaned up yet: probably would be done as part of
cb8e9e
another patch.
cb8e9e
cb8e9e
Change-Id: I78a92b8a7f02b2f39078aa9a5a6b101fc499fd70
cb8e9e
BUG: 1232309
cb8e9e
Signed-off-by: Venky Shankar <vshankar@redhat.com>
cb8e9e
Reviewed-on: https://code.engineering.redhat.com/gerrit/51744
cb8e9e
Reviewed-by: Raghavendra Bhat <raghavendra@redhat.com>
cb8e9e
Tested-by: Raghavendra Bhat <raghavendra@redhat.com>
cb8e9e
---
cb8e9e
 contrib/timer-wheel/timer-wheel.c                  |   10 +-
cb8e9e
 contrib/timer-wheel/timer-wheel.h                  |    2 +-
cb8e9e
 libglusterfs/src/common-utils.c                    |   11 ++
cb8e9e
 libglusterfs/src/common-utils.h                    |    3 +
cb8e9e
 xlators/features/bit-rot/src/bitd/bit-rot-scrub.c  |   27 ++-
cb8e9e
 xlators/features/bit-rot/src/bitd/bit-rot.c        |  186 +++++++++++++++++---
cb8e9e
 xlators/features/bit-rot/src/bitd/bit-rot.h        |   12 +-
cb8e9e
 xlators/features/changelog/src/changelog-helpers.c |   30 +---
cb8e9e
 8 files changed, 214 insertions(+), 67 deletions(-)
cb8e9e
cb8e9e
diff --git a/contrib/timer-wheel/timer-wheel.c b/contrib/timer-wheel/timer-wheel.c
cb8e9e
index d9b2ccd..013c0f2 100644
cb8e9e
--- a/contrib/timer-wheel/timer-wheel.c
cb8e9e
+++ b/contrib/timer-wheel/timer-wheel.c
cb8e9e
@@ -218,14 +218,20 @@ void gf_tw_add_timer (struct tvec_base *base, struct gf_tw_timer_list *timer)
cb8e9e
 /**
cb8e9e
  * Remove a timer from the timer wheel
cb8e9e
  */
cb8e9e
-void gf_tw_del_timer (struct tvec_base *base, struct gf_tw_timer_list *timer)
cb8e9e
+int gf_tw_del_timer (struct tvec_base *base, struct gf_tw_timer_list *timer)
cb8e9e
 {
cb8e9e
+        int ret = 0;
cb8e9e
+
cb8e9e
         pthread_spin_lock (&base->lock);
cb8e9e
         {
cb8e9e
-                if (timer_pending (timer))
cb8e9e
+                if (timer_pending (timer)) {
cb8e9e
+                        ret = 1;
cb8e9e
                         __gf_tw_detach_timer (timer);
cb8e9e
+                }
cb8e9e
         }
cb8e9e
         pthread_spin_unlock (&base->lock);
cb8e9e
+
cb8e9e
+        return ret;
cb8e9e
 }
cb8e9e
 
cb8e9e
 int gf_tw_mod_timer_pending (struct tvec_base *base,
cb8e9e
diff --git a/contrib/timer-wheel/timer-wheel.h b/contrib/timer-wheel/timer-wheel.h
cb8e9e
index c52f2fc..faa941a 100644
cb8e9e
--- a/contrib/timer-wheel/timer-wheel.h
cb8e9e
+++ b/contrib/timer-wheel/timer-wheel.h
cb8e9e
@@ -66,7 +66,7 @@ struct gf_tw_timer_list {
cb8e9e
 struct tvec_base *gf_tw_init_timers ();
cb8e9e
 int gf_tw_cleanup_timers (struct tvec_base *);
cb8e9e
 void gf_tw_add_timer (struct tvec_base *, struct gf_tw_timer_list *);
cb8e9e
-void gf_tw_del_timer (struct tvec_base *, struct gf_tw_timer_list *);
cb8e9e
+int gf_tw_del_timer (struct tvec_base *, struct gf_tw_timer_list *);
cb8e9e
 
cb8e9e
 int gf_tw_mod_timer_pending (struct tvec_base *,
cb8e9e
                              struct gf_tw_timer_list *, unsigned long);
cb8e9e
diff --git a/libglusterfs/src/common-utils.c b/libglusterfs/src/common-utils.c
cb8e9e
index be5d897..cbc5230 100644
cb8e9e
--- a/libglusterfs/src/common-utils.c
cb8e9e
+++ b/libglusterfs/src/common-utils.c
cb8e9e
@@ -4026,3 +4026,14 @@ out:
cb8e9e
         return ret;
cb8e9e
 }
cb8e9e
 
cb8e9e
+void
cb8e9e
+_mask_cancellation (void)
cb8e9e
+{
cb8e9e
+        (void) pthread_setcancelstate (PTHREAD_CANCEL_DISABLE, NULL);
cb8e9e
+}
cb8e9e
+
cb8e9e
+void
cb8e9e
+_unmask_cancellation (void)
cb8e9e
+{
cb8e9e
+        (void) pthread_setcancelstate (PTHREAD_CANCEL_ENABLE, NULL);
cb8e9e
+}
cb8e9e
diff --git a/libglusterfs/src/common-utils.h b/libglusterfs/src/common-utils.h
cb8e9e
index ad87559..a64917f 100644
cb8e9e
--- a/libglusterfs/src/common-utils.h
cb8e9e
+++ b/libglusterfs/src/common-utils.h
cb8e9e
@@ -762,4 +762,7 @@ gf_nread (int fd, void *buf, size_t count);
cb8e9e
 ssize_t
cb8e9e
 gf_nwrite (int fd, const void *buf, size_t count);
cb8e9e
 
cb8e9e
+void _mask_cancellation (void);
cb8e9e
+void _unmask_cancellation (void);
cb8e9e
+
cb8e9e
 #endif /* _COMMON_UTILS_H */
cb8e9e
diff --git a/xlators/features/bit-rot/src/bitd/bit-rot-scrub.c b/xlators/features/bit-rot/src/bitd/bit-rot-scrub.c
cb8e9e
index 45499de..d6ee413 100644
cb8e9e
--- a/xlators/features/bit-rot/src/bitd/bit-rot-scrub.c
cb8e9e
+++ b/xlators/features/bit-rot/src/bitd/bit-rot-scrub.c
cb8e9e
@@ -393,6 +393,14 @@ br_scrubber_scrub_begin (xlator_t *this, struct br_fsscan_entry *fsentry)
cb8e9e
 }
cb8e9e
 
cb8e9e
 static void
cb8e9e
+_br_lock_cleaner (void *arg)
cb8e9e
+{
cb8e9e
+        pthread_mutex_t *mutex = arg;
cb8e9e
+
cb8e9e
+        pthread_mutex_unlock (mutex);
cb8e9e
+}
cb8e9e
+
cb8e9e
+static void
cb8e9e
 wait_for_scrubbing (xlator_t *this, struct br_scanfs *fsscan)
cb8e9e
 {
cb8e9e
         br_private_t *priv = NULL;
cb8e9e
@@ -401,8 +409,10 @@ wait_for_scrubbing (xlator_t *this, struct br_scanfs *fsscan)
cb8e9e
         priv = this->private;
cb8e9e
         fsscrub = &priv->fsscrub;
cb8e9e
 
cb8e9e
+        pthread_cleanup_push (_br_lock_cleaner, &fsscan->waitlock);
cb8e9e
         pthread_mutex_lock (&fsscan->waitlock);
cb8e9e
         {
cb8e9e
+                pthread_cleanup_push (_br_lock_cleaner, &fsscrub->mutex);
cb8e9e
                 pthread_mutex_lock (&fsscrub->mutex);
cb8e9e
                 {
cb8e9e
                         list_replace_init (&fsscan->queued, &fsscan->ready);
cb8e9e
@@ -411,12 +421,14 @@ wait_for_scrubbing (xlator_t *this, struct br_scanfs *fsscan)
cb8e9e
                         pthread_cond_broadcast (&fsscrub->cond);
cb8e9e
                 }
cb8e9e
                 pthread_mutex_unlock (&fsscrub->mutex);
cb8e9e
+                pthread_cleanup_pop (0);
cb8e9e
 
cb8e9e
                 while (fsscan->entries != 0)
cb8e9e
                         pthread_cond_wait
cb8e9e
                                     (&fsscan->waitcond, &fsscan->waitlock);
cb8e9e
         }
cb8e9e
         pthread_mutex_unlock (&fsscan->waitlock);
cb8e9e
+        pthread_cleanup_pop (0);
cb8e9e
 }
cb8e9e
 
cb8e9e
 static inline void
cb8e9e
@@ -465,6 +477,8 @@ br_fsscanner_handle_entry (xlator_t *subvol,
cb8e9e
         this = child->this;
cb8e9e
         fsscan = &child->fsscan;
cb8e9e
 
cb8e9e
+        _mask_cancellation ();
cb8e9e
+
cb8e9e
         fsentry = GF_CALLOC (1, sizeof (*fsentry), gf_br_mt_br_fsscan_entry_t);
cb8e9e
         if (!fsentry)
cb8e9e
                 goto error_return;
cb8e9e
@@ -499,6 +513,8 @@ br_fsscanner_handle_entry (xlator_t *subvol,
cb8e9e
         }
cb8e9e
         UNLOCK (&fsscan->entrylock);
cb8e9e
 
cb8e9e
+        _unmask_cancellation ();
cb8e9e
+
cb8e9e
         if (scrub)
cb8e9e
                 wait_for_scrubbing (this, fsscan);
cb8e9e
 
cb8e9e
@@ -535,6 +551,7 @@ br_fsscanner_log_time (xlator_t *this, br_child_t *child, const char *sfx)
cb8e9e
 static void
cb8e9e
 br_fsscanner_wait_until_kicked (struct br_scanfs *fsscan)
cb8e9e
 {
cb8e9e
+        pthread_cleanup_push (_br_lock_cleaner, &fsscan->wakelock);
cb8e9e
         pthread_mutex_lock (&fsscan->wakelock);
cb8e9e
         {
cb8e9e
                 while (!fsscan->kick)
cb8e9e
@@ -543,6 +560,7 @@ br_fsscanner_wait_until_kicked (struct br_scanfs *fsscan)
cb8e9e
                 fsscan->kick = _gf_false;
cb8e9e
         }
cb8e9e
         pthread_mutex_unlock (&fsscan->wakelock);
cb8e9e
+        pthread_cleanup_pop (0);
cb8e9e
 }
cb8e9e
 
cb8e9e
 void *
cb8e9e
@@ -778,13 +796,6 @@ br_scrubber_calc_scale (xlator_t *this,
cb8e9e
 
cb8e9e
 }
cb8e9e
 
cb8e9e
-static void
cb8e9e
-br_scrubber_cleanup_handler (void *arg)
cb8e9e
-{
cb8e9e
-        struct br_scrubber *fsscrub = arg;
cb8e9e
-        pthread_mutex_unlock (&fsscrub->mutex);
cb8e9e
-}
cb8e9e
-
cb8e9e
 static inline br_child_t *
cb8e9e
 _br_scrubber_get_next_child (struct br_scrubber *fsscrub)
cb8e9e
 {
cb8e9e
@@ -844,7 +855,7 @@ static void
cb8e9e
 br_scrubber_pick_entry (struct br_scrubber *fsscrub,
cb8e9e
                         struct br_fsscan_entry **fsentry)
cb8e9e
 {
cb8e9e
-        pthread_cleanup_push (br_scrubber_cleanup_handler, fsscrub);
cb8e9e
+        pthread_cleanup_push (_br_lock_cleaner, &fsscrub->mutex);
cb8e9e
 
cb8e9e
         pthread_mutex_lock (&fsscrub->mutex);
cb8e9e
         {
cb8e9e
diff --git a/xlators/features/bit-rot/src/bitd/bit-rot.c b/xlators/features/bit-rot/src/bitd/bit-rot.c
cb8e9e
index b855cd7..f2cd1d8 100644
cb8e9e
--- a/xlators/features/bit-rot/src/bitd/bit-rot.c
cb8e9e
+++ b/xlators/features/bit-rot/src/bitd/bit-rot.c
cb8e9e
@@ -1103,7 +1103,7 @@ br_set_child_state (br_child_t *child, br_child_state_t state)
cb8e9e
  * Also, we register to the changelog library to subscribe for event
cb8e9e
  * notifications.
cb8e9e
  */
cb8e9e
-static inline int32_t
cb8e9e
+static int32_t
cb8e9e
 br_enact_signer (xlator_t *this, br_child_t *child, br_stub_init_t *stub)
cb8e9e
 {
cb8e9e
         int32_t ret = 0;
cb8e9e
@@ -1145,32 +1145,16 @@ br_enact_signer (xlator_t *this, br_child_t *child, br_stub_init_t *stub)
cb8e9e
         return -1;
cb8e9e
 }
cb8e9e
 
cb8e9e
-static inline int32_t
cb8e9e
-br_enact_scrubber (xlator_t *this, br_child_t *child)
cb8e9e
+static int32_t
cb8e9e
+br_launch_scrubber (xlator_t *this, br_child_t *child,
cb8e9e
+                    struct br_scanfs *fsscan, struct br_scrubber *fsscrub)
cb8e9e
 {
cb8e9e
-        int32_t ret = 0;
cb8e9e
+        int32_t ret = -1;
cb8e9e
         br_private_t *priv = NULL;
cb8e9e
-        struct br_scanfs *fsscan = NULL;
cb8e9e
-        struct br_scrubber *fsscrub = NULL;
cb8e9e
 
cb8e9e
         priv = this->private;
cb8e9e
 
cb8e9e
-        fsscan = &child->fsscan;
cb8e9e
-        fsscrub = &priv->fsscrub;
cb8e9e
-
cb8e9e
-        LOCK_INIT (&fsscan->entrylock);
cb8e9e
-        pthread_mutex_init (&fsscan->waitlock, NULL);
cb8e9e
-        pthread_cond_init (&fsscan->waitcond, NULL);
cb8e9e
-
cb8e9e
-        fsscan->entries = 0;
cb8e9e
-        INIT_LIST_HEAD (&fsscan->queued);
cb8e9e
-        INIT_LIST_HEAD (&fsscan->ready);
cb8e9e
-
cb8e9e
-        /* init scheduler related variables */
cb8e9e
         fsscan->kick = _gf_false;
cb8e9e
-        pthread_mutex_init (&fsscan->wakelock, NULL);
cb8e9e
-        pthread_cond_init (&fsscan->wakecond, NULL);
cb8e9e
-
cb8e9e
         ret = gf_thread_create (&child->thread, NULL, br_fsscanner, child);
cb8e9e
         if (ret != 0) {
cb8e9e
                 gf_msg (this->name, GF_LOG_ALERT, 0, BRB_MSG_SPAWN_FAILED,
cb8e9e
@@ -1186,7 +1170,7 @@ br_enact_scrubber (xlator_t *this, br_child_t *child)
cb8e9e
         }
cb8e9e
         pthread_mutex_unlock (&priv->lock);
cb8e9e
         if (ret)
cb8e9e
-                goto error_return;
cb8e9e
+                goto cleanup_thread;
cb8e9e
 
cb8e9e
         /**
cb8e9e
          * Everything has been setup.. add this subvolume to scrubbers
cb8e9e
@@ -1201,6 +1185,50 @@ br_enact_scrubber (xlator_t *this, br_child_t *child)
cb8e9e
 
cb8e9e
         return 0;
cb8e9e
 
cb8e9e
+ cleanup_thread:
cb8e9e
+        (void) gf_thread_cleanup_xint (child->thread);
cb8e9e
+ error_return:
cb8e9e
+        return -1;
cb8e9e
+}
cb8e9e
+
cb8e9e
+static int32_t
cb8e9e
+br_enact_scrubber (xlator_t *this, br_child_t *child)
cb8e9e
+{
cb8e9e
+        int32_t ret = 0;
cb8e9e
+        br_private_t *priv = NULL;
cb8e9e
+        struct br_scanfs *fsscan = NULL;
cb8e9e
+        struct br_scrubber *fsscrub = NULL;
cb8e9e
+
cb8e9e
+        priv = this->private;
cb8e9e
+
cb8e9e
+        fsscan = &child->fsscan;
cb8e9e
+        fsscrub = &priv->fsscrub;
cb8e9e
+
cb8e9e
+        /**
cb8e9e
+         * if this child already witnesses a successfull connection earlier
cb8e9e
+         * there's no need to initialize mutexes, condvars, etc..
cb8e9e
+         */
cb8e9e
+        if (_br_child_witnessed_connection (child))
cb8e9e
+                return br_launch_scrubber (this, child, fsscan, fsscrub);
cb8e9e
+
cb8e9e
+        LOCK_INIT (&fsscan->entrylock);
cb8e9e
+        pthread_mutex_init (&fsscan->waitlock, NULL);
cb8e9e
+        pthread_cond_init (&fsscan->waitcond, NULL);
cb8e9e
+
cb8e9e
+        fsscan->entries = 0;
cb8e9e
+        INIT_LIST_HEAD (&fsscan->queued);
cb8e9e
+        INIT_LIST_HEAD (&fsscan->ready);
cb8e9e
+
cb8e9e
+        /* init scheduler related variables */
cb8e9e
+        pthread_mutex_init (&fsscan->wakelock, NULL);
cb8e9e
+        pthread_cond_init (&fsscan->wakecond, NULL);
cb8e9e
+
cb8e9e
+        ret = br_launch_scrubber (this, child, fsscan, fsscrub);
cb8e9e
+        if (ret)
cb8e9e
+                goto error_return;
cb8e9e
+
cb8e9e
+        return 0;
cb8e9e
+
cb8e9e
  error_return:
cb8e9e
         LOCK_DESTROY (&fsscan->entrylock);
cb8e9e
         pthread_mutex_destroy (&fsscan->waitlock);
cb8e9e
@@ -1223,6 +1251,7 @@ br_child_enaction (xlator_t *this, br_child_t *child, br_stub_init_t *stub)
cb8e9e
                         ret = br_enact_signer (this, child, stub);
cb8e9e
 
cb8e9e
                 if (!ret) {
cb8e9e
+                        child->witnessed = 1;
cb8e9e
                         _br_set_child_state (child, BR_CHILD_STATE_CONNECTED);
cb8e9e
                         gf_log (this->name, GF_LOG_INFO,
cb8e9e
                                 "Connected to brick %s..", child->brick_path);
cb8e9e
@@ -1304,6 +1333,100 @@ br_brick_connect (xlator_t *this, br_child_t *child)
cb8e9e
         return ret;
cb8e9e
 }
cb8e9e
 
cb8e9e
+/* TODO: cleanup signer */
cb8e9e
+static int32_t
cb8e9e
+br_cleanup_signer (xlator_t *this, br_child_t *child)
cb8e9e
+{
cb8e9e
+        return 0;
cb8e9e
+}
cb8e9e
+
cb8e9e
+static int32_t
cb8e9e
+br_cleanup_scrubber (xlator_t *this, br_child_t *child)
cb8e9e
+{
cb8e9e
+        int32_t ret = 0;
cb8e9e
+        br_private_t *priv = NULL;
cb8e9e
+        struct br_scanfs *fsscan = NULL;
cb8e9e
+        struct br_scrubber *fsscrub = NULL;
cb8e9e
+
cb8e9e
+        priv    = this->private;
cb8e9e
+        fsscan  = &child->fsscan;
cb8e9e
+        fsscrub = &priv->fsscrub;
cb8e9e
+
cb8e9e
+        /**
cb8e9e
+         * 0x0: child (brick) goes out of rotation
cb8e9e
+         *
cb8e9e
+         * This is fully safe w.r.t. entries for this child being actively
cb8e9e
+         * scrubbed. Each of the scrubber thread(s) would finish scrubbing
cb8e9e
+         * the entry (probably failing due to disconnection) and either
cb8e9e
+         * putting the entry back into the queue or continuing further.
cb8e9e
+         * Either way, pending entries for this child's queue need not be
cb8e9e
+         * drained; entries just sit there in the queued/ready list to be
cb8e9e
+         * consumed later upon re-connection.
cb8e9e
+         */
cb8e9e
+        pthread_mutex_lock (&fsscrub->mutex);
cb8e9e
+        {
cb8e9e
+                list_del_init (&child->list);
cb8e9e
+        }
cb8e9e
+        pthread_mutex_unlock (&fsscrub->mutex);
cb8e9e
+
cb8e9e
+        /**
cb8e9e
+         * 0x1: cleanup scanner thread
cb8e9e
+         *
cb8e9e
+         * The pending timer needs to be removed _after_ cleaning up the
cb8e9e
+         * filesystem scanner (scheduling the next scrub time is not a
cb8e9e
+         * cancellation point).
cb8e9e
+         */
cb8e9e
+        ret = gf_thread_cleanup_xint (child->thread);
cb8e9e
+        if (ret)
cb8e9e
+                gf_log (this->name, GF_LOG_ERROR,
cb8e9e
+                        "Error cleaning up scanner thread");
cb8e9e
+
cb8e9e
+        /**
cb8e9e
+         * 0x2: free()up resources
cb8e9e
+         */
cb8e9e
+        if (fsscan->timer) {
cb8e9e
+                (void) gf_tw_del_timer (priv->timer_wheel, fsscan->timer);
cb8e9e
+
cb8e9e
+                GF_FREE (fsscan->timer);
cb8e9e
+                fsscan->timer = NULL;
cb8e9e
+        }
cb8e9e
+
cb8e9e
+        gf_log (this->name, GF_LOG_INFO,
cb8e9e
+                "Cleaned up scrubber for brick [%s]", child->brick_path);
cb8e9e
+
cb8e9e
+        return 0;
cb8e9e
+}
cb8e9e
+
cb8e9e
+/**
cb8e9e
+ * OK.. this child has made it's mind to go down the drain. So,
cb8e9e
+ * let's clean up what it touched. (NOTE: there's no need to clean
cb8e9e
+ * the inode table, it's just reused taking care of stale inodes)
cb8e9e
+ */
cb8e9e
+int32_t
cb8e9e
+br_brick_disconnect (xlator_t *this, br_child_t *child)
cb8e9e
+{
cb8e9e
+        int32_t ret = 0;
cb8e9e
+        br_private_t *priv = this->private;
cb8e9e
+
cb8e9e
+        LOCK (&child->lock);
cb8e9e
+        {
cb8e9e
+                if (!_br_is_child_connected (child))
cb8e9e
+                        goto unblock;
cb8e9e
+
cb8e9e
+                /* child is on death row.. */
cb8e9e
+                _br_set_child_state (child, BR_CHILD_STATE_DISCONNECTED);
cb8e9e
+
cb8e9e
+                if (priv->iamscrubber)
cb8e9e
+                        ret = br_cleanup_scrubber (this, child);
cb8e9e
+                else
cb8e9e
+                        ret = br_cleanup_signer (this, child);
cb8e9e
+        }
cb8e9e
+ unblock:
cb8e9e
+        UNLOCK (&child->lock);
cb8e9e
+
cb8e9e
+         return ret;
cb8e9e
+}
cb8e9e
+
cb8e9e
 /**
cb8e9e
  * This function is executed in a separate thread. The thread gets the
cb8e9e
  * brick from where CHILD_UP has received from the queue and gets the
cb8e9e
@@ -1424,7 +1547,7 @@ notify (xlator_t *this, int32_t event, void *data, ...)
cb8e9e
                 {
cb8e9e
                         child = &priv->children[idx];
cb8e9e
                         if (child->child_up == 1)
cb8e9e
-                                goto unblock;
cb8e9e
+                                goto unblock_0;
cb8e9e
                         priv->up_children++;
cb8e9e
 
cb8e9e
                         child->child_up = 1;
cb8e9e
@@ -1435,7 +1558,7 @@ notify (xlator_t *this, int32_t event, void *data, ...)
cb8e9e
                         _br_qchild_event (this, child, br_brick_connect);
cb8e9e
                         pthread_cond_signal (&priv->cond);
cb8e9e
                 }
cb8e9e
-        unblock:
cb8e9e
+        unblock_0:
cb8e9e
                 pthread_mutex_unlock (&priv->lock);
cb8e9e
 
cb8e9e
                 if (priv->up_children == priv->child_count)
cb8e9e
@@ -1452,11 +1575,17 @@ notify (xlator_t *this, int32_t event, void *data, ...)
cb8e9e
 
cb8e9e
                 pthread_mutex_lock (&priv->lock);
cb8e9e
                 {
cb8e9e
-                        if (priv->children[idx].child_up == 1) {
cb8e9e
-                                priv->children[idx].child_up = 0;
cb8e9e
-                                priv->up_children--;
cb8e9e
-                        }
cb8e9e
+                        child = &priv->children[idx];
cb8e9e
+                        if (child->child_up == 0)
cb8e9e
+                                goto unblock_1;
cb8e9e
+
cb8e9e
+                        child->child_up = 0;
cb8e9e
+                        priv->up_children--;
cb8e9e
+
cb8e9e
+                        _br_qchild_event (this, child, br_brick_disconnect);
cb8e9e
+                        pthread_cond_signal (&priv->cond);
cb8e9e
                 }
cb8e9e
+        unblock_1:
cb8e9e
                 pthread_mutex_unlock (&priv->lock);
cb8e9e
 
cb8e9e
                 if (priv->up_children == 0)
cb8e9e
@@ -1649,6 +1778,7 @@ br_init_children (xlator_t *this, br_private_t *priv)
cb8e9e
                 child = &priv->children[i];
cb8e9e
 
cb8e9e
                 LOCK_INIT (&child->lock);
cb8e9e
+                child->witnessed = 0;
cb8e9e
                 br_set_child_state (child, BR_CHILD_STATE_DISCONNECTED);
cb8e9e
 
cb8e9e
                 child->this = this;
cb8e9e
diff --git a/xlators/features/bit-rot/src/bitd/bit-rot.h b/xlators/features/bit-rot/src/bitd/bit-rot.h
cb8e9e
index b8d9e3b..9a55773 100644
cb8e9e
--- a/xlators/features/bit-rot/src/bitd/bit-rot.h
cb8e9e
+++ b/xlators/features/bit-rot/src/bitd/bit-rot.h
cb8e9e
@@ -85,8 +85,10 @@ typedef enum br_child_state {
cb8e9e
 } br_child_state_t;
cb8e9e
 
cb8e9e
 struct br_child {
cb8e9e
-        gf_lock_t lock;
cb8e9e
-        br_child_state_t c_state;
cb8e9e
+        gf_lock_t lock;               /* protects child state */
cb8e9e
+        char witnessed;               /* witnessed at least one succesfull
cb8e9e
+                                         connection */
cb8e9e
+        br_child_state_t c_state;     /* current state of this child */
cb8e9e
 
cb8e9e
         char child_up;                /* Indicates whether this child is
cb8e9e
                                          up or not */
cb8e9e
@@ -236,4 +238,10 @@ _br_child_failed_conn (br_child_t *child)
cb8e9e
         return (child->c_state == BR_CHILD_STATE_CONNFAILED);
cb8e9e
 }
cb8e9e
 
cb8e9e
+static inline int
cb8e9e
+_br_child_witnessed_connection (br_child_t *child)
cb8e9e
+{
cb8e9e
+        return (child->witnessed == 1);
cb8e9e
+}
cb8e9e
+
cb8e9e
 #endif /* __BIT_ROT_H__ */
cb8e9e
diff --git a/xlators/features/changelog/src/changelog-helpers.c b/xlators/features/changelog/src/changelog-helpers.c
cb8e9e
index 2c0a645..144bf54 100644
cb8e9e
--- a/xlators/features/changelog/src/changelog-helpers.c
cb8e9e
+++ b/xlators/features/changelog/src/changelog-helpers.c
cb8e9e
@@ -27,28 +27,6 @@
cb8e9e
 #include "changelog-rpc-common.h"
cb8e9e
 #include <pthread.h>
cb8e9e
 
cb8e9e
-static inline void
cb8e9e
-__mask_cancellation (xlator_t *this)
cb8e9e
-{
cb8e9e
-        int ret = 0;
cb8e9e
-
cb8e9e
-        ret = pthread_setcancelstate (PTHREAD_CANCEL_DISABLE, NULL);
cb8e9e
-        if (ret)
cb8e9e
-                gf_log (this->name, GF_LOG_WARNING,
cb8e9e
-                        "failed to disable thread cancellation");
cb8e9e
-}
cb8e9e
-
cb8e9e
-static inline void
cb8e9e
-__unmask_cancellation (xlator_t *this)
cb8e9e
-{
cb8e9e
-        int ret = 0;
cb8e9e
-
cb8e9e
-        ret = pthread_setcancelstate (PTHREAD_CANCEL_ENABLE, NULL);
cb8e9e
-        if (ret)
cb8e9e
-                gf_log (this->name, GF_LOG_WARNING,
cb8e9e
-                        "failed to enable thread cancellation");
cb8e9e
-}
cb8e9e
-
cb8e9e
 static void
cb8e9e
 changelog_cleanup_free_mutex (void *arg_mutex)
cb8e9e
 {
cb8e9e
@@ -1338,7 +1316,7 @@ changelog_rollover (void *data)
cb8e9e
                         continue;
cb8e9e
                 }
cb8e9e
 
cb8e9e
-                __mask_cancellation (this);
cb8e9e
+                _mask_cancellation ();
cb8e9e
 
cb8e9e
                 LOCK (&priv->lock);
cb8e9e
                 {
cb8e9e
@@ -1348,7 +1326,7 @@ changelog_rollover (void *data)
cb8e9e
                 }
cb8e9e
                 UNLOCK (&priv->lock);
cb8e9e
 
cb8e9e
-                __unmask_cancellation (this);
cb8e9e
+                _unmask_cancellation ();
cb8e9e
         }
cb8e9e
 
cb8e9e
         return NULL;
cb8e9e
@@ -1376,14 +1354,14 @@ changelog_fsync_thread (void *data)
cb8e9e
                 if (ret)
cb8e9e
                         continue;
cb8e9e
 
cb8e9e
-                __mask_cancellation (this);
cb8e9e
+                _mask_cancellation ();
cb8e9e
 
cb8e9e
                 ret = changelog_inject_single_event (this, priv, &cld;;
cb8e9e
                 if (ret)
cb8e9e
                         gf_log (this->name, GF_LOG_ERROR,
cb8e9e
                                 "failed to inject fsync event");
cb8e9e
 
cb8e9e
-                __unmask_cancellation (this);
cb8e9e
+                _unmask_cancellation ();
cb8e9e
         }
cb8e9e
 
cb8e9e
         return NULL;
cb8e9e
-- 
cb8e9e
1.7.1
cb8e9e