]> git.ipfire.org Git - thirdparty/bind9.git/commitdiff
pullup:
authorMark Andrews <marka@isc.org>
Tue, 23 Oct 2001 01:31:08 +0000 (01:31 +0000)
committerMark Andrews <marka@isc.org>
Tue, 23 Oct 2001 01:31:08 +0000 (01:31 +0000)
eliminated race condition in water() [RT #1932]

lib/dns/cache.c

index e2bad8d2be9c81c1acfc0bc9bc20b61b34a07924..e754be222ef60c2ed9779b2222d7cdfd8725f15c 100644 (file)
@@ -15,7 +15,7 @@
  * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  */
 
-/* $Id: cache.c,v 1.45.2.1 2001/10/19 00:22:26 marka Exp $ */
+/* $Id: cache.c,v 1.45.2.2 2001/10/23 01:31:08 marka Exp $ */
 
 #include <config.h>
 
@@ -76,6 +76,14 @@ typedef enum {
  * task/event serialization, or locked from the cache object.
  */
 struct cache_cleaner {
+       isc_mutex_t     lock;
+       /*
+        * Locks overmem_event, overmem.  Note: never allocate memory
+        * while holding this lock - that could lead to deadlock since
+        * the lock is take by water() which is called from the memory
+        * allocator.
+        */
+
        dns_cache_t     *cache;
        isc_task_t      *task;
        unsigned int    cleaning_interval; /* The cleaning-interval from
@@ -272,6 +280,8 @@ cache_free(dns_cache_t *cache) {
        if (cache->cleaner.iterator != NULL)
                dns_dbiterator_destroy(&cache->cleaner.iterator);
 
+       DESTROYLOCK(&cache->cleaner.lock);
+
        if (cache->filename) {
                isc_mem_free(cache->mctx, cache->filename);
                cache->filename = NULL;
@@ -459,6 +469,15 @@ cache_cleaner_init(dns_cache_t *cache, isc_taskmgr_t *taskmgr,
 {
        isc_result_t result;
 
+       result = isc_mutex_init(&cleaner->lock);
+       if (result != ISC_R_SUCCESS) {
+               UNEXPECTED_ERROR(__FILE__, __LINE__,
+                                "isc_mutex_init() failed: %s",
+                                dns_result_totext(result));
+               result = ISC_R_UNEXPECTED;
+               goto fail;
+       }
+
        cleaner->increment = DNS_CACHE_CLEANERINCREMENT;
        cleaner->state = cleaner_s_idle;
        cleaner->cache = cache;
@@ -536,7 +555,8 @@ cache_cleaner_init(dns_cache_t *cache, isc_taskmgr_t *taskmgr,
                isc_timer_detach(&cleaner->cleaning_timer);
        if (cleaner->task != NULL)
                isc_task_detach(&cleaner->task);
-
+       DESTROYLOCK(&cleaner->lock);
+ fail:
        return (result);
 }
 
@@ -635,6 +655,7 @@ cleaning_timer_action(isc_task_t *task, isc_event_t *event) {
 static void
 overmem_cleaning_action(isc_task_t *task, isc_event_t *event) {
        cache_cleaner_t *cleaner = event->ev_arg;
+       isc_boolean_t want_cleaning = ISC_FALSE;
        
        UNUSED(task);
 
@@ -642,9 +663,11 @@ overmem_cleaning_action(isc_task_t *task, isc_event_t *event) {
        INSIST(event->ev_type == DNS_EVENT_CACHEOVERMEM);
        INSIST(cleaner->overmem_event == NULL);
 
+       LOCK(&cleaner->lock);
+
        if (cleaner->overmem) {
                if (cleaner->state == cleaner_s_idle)
-                       begin_cleaning(cleaner);
+                       want_cleaning = ISC_TRUE;
        } else {
                if (cleaner->state == cleaner_s_busy)
                        /*
@@ -659,6 +682,11 @@ overmem_cleaning_action(isc_task_t *task, isc_event_t *event) {
        }
 
        cleaner->overmem_event = event;
+
+       UNLOCK(&cleaner->lock);
+
+       if (want_cleaning)
+               begin_cleaning(cleaner);
 }
 
 /*
@@ -824,12 +852,16 @@ water(void *arg, int mark) {
 
        REQUIRE(VALID_CACHE(cache));
 
+       LOCK(&cache->cleaner.lock);
+       
        dns_db_overmem(cache->db, overmem);
        cache->cleaner.overmem = overmem;
 
        if (cache->cleaner.overmem_event != NULL)
                isc_task_send(cache->cleaner.task,
                              &cache->cleaner.overmem_event);
+
+       UNLOCK(&cache->cleaner.lock);
 }
 
 void