Attached is a better patch that avoids the non-portable (and ugly)
recursive mutex in favor of properly releasing the lock before
reacquiring it.
>From 460c14e1db1d1cab5f405f21e4a28a39c5721a36 Mon Sep 17 00:00:00 2001
From: Eric Wong <normalper...@yhbt.net>
Date: Sat, 20 Oct 2012 04:17:43 +0000
Subject: [PATCH] avoid mutex deadlock in stat_cache_get()

stat_cache_get() could lead to pthread_mutex_lock(&stat_cache_mutex)
being called twice in the same thread without a matching
pthread_mutex_unlock:

  stat_cache_get() - locks stat_cache_mutex
    file_cache_unref()
      file_cache_sync_unlocked()
        stat_cache_invalidate() -> locks stat_cache_mutex again

By releasing stat_cache_mutex before calling file_cache_unref(),
we can ensure stat_cache_invalidate() won't attempt to lock
a mutex the current thread already holds.

ref: http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=691010
---
 src/statcache.c | 11 +++++------
 1 file changed, 5 insertions(+), 6 deletions(-)

diff --git a/src/statcache.c b/src/statcache.c
index d9e801f..83e6ca1 100644
--- a/src/statcache.c
+++ b/src/statcache.c
@@ -100,16 +100,15 @@ int stat_cache_get(const char *fn, struct stat *st) {
         time(NULL) <= ce->stat_info.dead) {
         
         *st = ce->stat_info.st;
-
-        if ((f = file_cache_get(fn))) {
-            st->st_size = file_cache_get_size(f);
-            file_cache_unref(f);
-        }
-
         r = 0;
     }
 
     pthread_mutex_unlock(&stat_cache_mutex);
+
+    if ((r == 0) && (f = file_cache_get(fn))) {
+        st->st_size = file_cache_get_size(f);
+        file_cache_unref(f);
+    }
     
     return r;
 }
-- 
1.8.0.rc3.16.g8ead1bf

Reply via email to