summaryrefslogtreecommitdiffstats
path: root/xlators
diff options
context:
space:
mode:
authorVenky Shankar <vshankar@redhat.com>2014-06-18 23:36:48 +0530
committerVijay Bellur <vbellur@redhat.com>2014-07-11 00:08:57 -0700
commit6532a65b56a652622612a6edcd03fff90fbeff0f (patch)
tree3b86ab6dc950160f0996ffe5d73d88f11f66c3d4 /xlators
parentc7251ebfe8e14090f9420786973c5f8232555b8e (diff)
features/changelog: prevent deadlock on thread cancellation
helper threads (fsync, rollover) wake up periodically and perform their respective operation under a lock (crt->lock). These threads are also subjected to cancellation under some circumstance such as disabling changelog. This is inherently dangerous when funtions which are cancellation points for pthread_cancel(3) are used in the locked region. Consider this pthread_mutex_lock(&mutex); { /* ... */ ret = fsync (fd); <-- cancellation point /* ... */ } pthread_mutex_unlock(&mutex); A pthread_cancel(3) by another thread just before fsync(3) but after pthread_mutex_lock(3) would result in the thread getting cancelled when fsync(3) is invoked, thereby never unlocking the mutex. Moreover, in case of changelog translator, the locked region (under crt->lock in changelog-rt.c) is also the code path for fop changelog updation. Therefore, unlocking the mutex in thread cleanup handler (pthread_cleanup_pop(3)) might prematurely release the mutex during fop updation path. This patch fixes such problems existing in fsync and rollover threads. Fix is to enter the locked region with cancellation disabled and enable it after mutex unlock. Also, test for a cancellation request early on in case none of the functions are cancellation points. Change-Id: I1795627a12827609c1da659d07fc1457ffa033de BUG: 1110917 Signed-off-by: Venky Shankar <vshankar@redhat.com> Reviewed-on: http://review.gluster.org/8106 Reviewed-by: Kotresh HR <khiremat@redhat.com> Reviewed-by: Vijay Bellur <vbellur@redhat.com> Tested-by: Gluster Build System <jenkins@build.gluster.com>
Diffstat (limited to 'xlators')
-rw-r--r--xlators/features/changelog/src/changelog-helpers.c34
1 files changed, 34 insertions, 0 deletions
diff --git a/xlators/features/changelog/src/changelog-helpers.c b/xlators/features/changelog/src/changelog-helpers.c
index b271f3f0fc0..bb8150bd719 100644
--- a/xlators/features/changelog/src/changelog-helpers.c
+++ b/xlators/features/changelog/src/changelog-helpers.c
@@ -25,6 +25,28 @@
#include "changelog-encoders.h"
#include <pthread.h>
+inline void
+__mask_cancellation (xlator_t *this)
+{
+ int ret = 0;
+
+ ret = pthread_setcancelstate (PTHREAD_CANCEL_DISABLE, NULL);
+ if (ret)
+ gf_log (this->name, GF_LOG_WARNING,
+ "failed to disable thread cancellation");
+}
+
+inline void
+__unmask_cancellation (xlator_t *this)
+{
+ int ret = 0;
+
+ ret = pthread_setcancelstate (PTHREAD_CANCEL_ENABLE, NULL);
+ if (ret)
+ gf_log (this->name, GF_LOG_WARNING,
+ "failed to enable thread cancellation");
+}
+
static void
changelog_cleanup_free_mutex (void *arg_mutex)
{
@@ -618,6 +640,8 @@ changelog_rollover (void *data)
slice = &priv->slice;
while (1) {
+ (void) pthread_testcancel();
+
tv.tv_sec = priv->rollover_time;
tv.tv_usec = 0;
FD_ZERO(&rset);
@@ -708,6 +732,8 @@ changelog_rollover (void *data)
continue;
}
+ __mask_cancellation (this);
+
LOCK (&priv->lock);
{
ret = changelog_inject_single_event (this, priv, &cld);
@@ -715,6 +741,8 @@ changelog_rollover (void *data)
SLICE_VERSION_UPDATE (slice);
}
UNLOCK (&priv->lock);
+
+ __unmask_cancellation (this);
}
return NULL;
@@ -733,6 +761,8 @@ changelog_fsync_thread (void *data)
cld.cld_type = CHANGELOG_TYPE_FSYNC;
while (1) {
+ (void) pthread_testcancel();
+
tv.tv_sec = priv->fsync_interval;
tv.tv_usec = 0;
@@ -740,10 +770,14 @@ changelog_fsync_thread (void *data)
if (ret)
continue;
+ __mask_cancellation (this);
+
ret = changelog_inject_single_event (this, priv, &cld);
if (ret)
gf_log (this->name, GF_LOG_ERROR,
"failed to inject fsync event");
+
+ __unmask_cancellation (this);
}
return NULL;