c8cd03
From e7a2611c555e03314ac4f7960044b05cce040364 Mon Sep 17 00:00:00 2001
c8cd03
From: Mark Andrews <marka@isc.org>
c8cd03
Date: Thu, 31 Jul 2014 11:38:11 +1000
c8cd03
Subject: [PATCH] 3905. [bug] Address deadlock between view.c and adb.c. [RT
c8cd03
 #36341]
c8cd03
MIME-Version: 1.0
c8cd03
Content-Type: text/plain; charset=UTF-8
c8cd03
Content-Transfer-Encoding: 8bit
c8cd03
c8cd03
Original-commit: 5e746ab61ed8158f784b86111fef95581a08b7dd
c8cd03
Signed-off-by: Petr Menšík <pemensik@redhat.com>
c8cd03
---
c8cd03
 lib/dns/adb.c | 57 +++++++++++++++++++++++++++++++++++++++++----------------
c8cd03
 1 file changed, 41 insertions(+), 16 deletions(-)
c8cd03
c8cd03
diff --git a/lib/dns/adb.c b/lib/dns/adb.c
c8cd03
index a6da94d..ac89e66 100644
c8cd03
--- a/lib/dns/adb.c
c8cd03
+++ b/lib/dns/adb.c
c8cd03
@@ -15,8 +15,6 @@
c8cd03
  * PERFORMANCE OF THIS SOFTWARE.
c8cd03
  */
c8cd03
 
c8cd03
-/* $Id: adb.c,v 1.264 2011/12/05 17:10:51 each Exp $ */
c8cd03
-
c8cd03
 /*! \file
c8cd03
  *
c8cd03
  * \note
c8cd03
@@ -157,7 +155,7 @@ struct dns_adb {
c8cd03
 	unsigned int                    *entry_refcnt;
c8cd03
 
c8cd03
 	isc_event_t                     cevent;
c8cd03
-	isc_boolean_t                   cevent_sent;
c8cd03
+	isc_boolean_t                   cevent_out;
c8cd03
 	isc_boolean_t                   shutting_down;
c8cd03
 	isc_eventlist_t                 whenshutdown;
c8cd03
 	isc_event_t			growentries;
c8cd03
@@ -322,6 +320,7 @@ static inline isc_boolean_t unlink_entry(dns_adb_t *, dns_adbentry_t *);
c8cd03
 static isc_boolean_t kill_name(dns_adbname_t **, isc_eventtype_t);
c8cd03
 static void water(void *, int);
c8cd03
 static void dump_entry(FILE *, dns_adbentry_t *, isc_boolean_t, isc_stdtime_t);
c8cd03
+static void shutdown_task(isc_task_t *task, isc_event_t *ev);
c8cd03
 
c8cd03
 /*
c8cd03
  * MUST NOT overlap DNS_ADBFIND_* flags!
c8cd03
@@ -1499,10 +1498,13 @@ check_exit(dns_adb_t *adb) {
c8cd03
 		 * If there aren't any external references either, we're
c8cd03
 		 * done.  Send the control event to initiate shutdown.
c8cd03
 		 */
c8cd03
-		INSIST(!adb->cevent_sent);      /* Sanity check. */
c8cd03
+		INSIST(!adb->cevent_out);      /* Sanity check. */
c8cd03
+		ISC_EVENT_INIT(&adb->cevent, sizeof(adb->cevent), 0, NULL,
c8cd03
+			       DNS_EVENT_ADBCONTROL, shutdown_task, adb,
c8cd03
+			       adb, NULL, NULL);
c8cd03
 		event = &adb->cevent;
c8cd03
 		isc_task_send(adb->task, &event);
c8cd03
-		adb->cevent_sent = ISC_TRUE;
c8cd03
+		adb->cevent_out = ISC_TRUE;
c8cd03
 	}
c8cd03
 }
c8cd03
 
c8cd03
@@ -2431,10 +2433,9 @@ dns_adb_create(isc_mem_t *mem, dns_view_t *view, isc_timermgr_t *timermgr,
c8cd03
 	adb->view = view;
c8cd03
 	adb->taskmgr = taskmgr;
c8cd03
 	adb->next_cleanbucket = 0;
c8cd03
-	ISC_EVENT_INIT(&adb->cevent, sizeof(adb->cevent), 0, NULL,
c8cd03
-		       DNS_EVENT_ADBCONTROL, shutdown_task, adb,
c8cd03
-		       adb, NULL, NULL);
c8cd03
-	adb->cevent_sent = ISC_FALSE;
c8cd03
+	ISC_EVENT_INIT(&adb->cevent, sizeof(adb->cevent),
c8cd03
+		       0, NULL, 0, NULL, NULL, NULL, NULL, NULL);
c8cd03
+	adb->cevent_out = ISC_FALSE;
c8cd03
 	adb->shutting_down = ISC_FALSE;
c8cd03
 	ISC_LIST_INIT(adb->whenshutdown);
c8cd03
 
c8cd03
@@ -2468,7 +2469,7 @@ dns_adb_create(isc_mem_t *mem, dns_view_t *view, isc_timermgr_t *timermgr,
c8cd03
 				 "intializing table sizes to %u\n",
c8cd03
 				 nbuckets[11]);
c8cd03
 		adb->nentries = nbuckets[11];
c8cd03
-		adb->nnames= nbuckets[11];
c8cd03
+		adb->nnames = nbuckets[11];
c8cd03
 
c8cd03
 	}
c8cd03
 
c8cd03
@@ -2741,9 +2742,28 @@ dns_adb_whenshutdown(dns_adb_t *adb, isc_task_t *task, isc_event_t **eventp) {
c8cd03
 	UNLOCK(&adb->lock);
c8cd03
 }
c8cd03
 
c8cd03
+static void
c8cd03
+shutdown_stage2(isc_task_t *task, isc_event_t *event) {
c8cd03
+	dns_adb_t *adb;
c8cd03
+
c8cd03
+	UNUSED(task);
c8cd03
+
c8cd03
+	adb = event->ev_arg;
c8cd03
+	INSIST(DNS_ADB_VALID(adb));
c8cd03
+
c8cd03
+	LOCK(&adb->lock);
c8cd03
+	INSIST(adb->shutting_down);
c8cd03
+	adb->cevent_out = ISC_FALSE;
c8cd03
+	(void)shutdown_names(adb);
c8cd03
+	(void)shutdown_entries(adb);
c8cd03
+	if (dec_adb_irefcnt(adb))
c8cd03
+		check_exit(adb);
c8cd03
+	UNLOCK(&adb->lock);
c8cd03
+}
c8cd03
+
c8cd03
 void
c8cd03
 dns_adb_shutdown(dns_adb_t *adb) {
c8cd03
-	isc_boolean_t need_check_exit;
c8cd03
+	isc_event_t *event;
c8cd03
 
c8cd03
 	/*
c8cd03
 	 * Shutdown 'adb'.
c8cd03
@@ -2754,11 +2774,16 @@ dns_adb_shutdown(dns_adb_t *adb) {
c8cd03
 	if (!adb->shutting_down) {
c8cd03
 		adb->shutting_down = ISC_TRUE;
c8cd03
 		isc_mem_setwater(adb->mctx, water, adb, 0, 0);
c8cd03
-		need_check_exit = shutdown_names(adb);
c8cd03
-		if (!need_check_exit)
c8cd03
-			need_check_exit = shutdown_entries(adb);
c8cd03
-		if (need_check_exit)
c8cd03
-			check_exit(adb);
c8cd03
+		/*
c8cd03
+		 * Isolate shutdown_names and shutdown_entries calls.
c8cd03
+		 */
c8cd03
+		inc_adb_irefcnt(adb);
c8cd03
+		ISC_EVENT_INIT(&adb->cevent, sizeof(adb->cevent), 0, NULL,
c8cd03
+			       DNS_EVENT_ADBCONTROL, shutdown_stage2, adb,
c8cd03
+			       adb, NULL, NULL);
c8cd03
+		adb->cevent_out = ISC_TRUE;
c8cd03
+		event = &adb->cevent;
c8cd03
+		isc_task_send(adb->task, &event);
c8cd03
 	}
c8cd03
 
c8cd03
 	UNLOCK(&adb->lock);
c8cd03
-- 
c8cd03
2.9.3
c8cd03