]> git.ipfire.org Git - thirdparty/bind9.git/commitdiff
3212. [bug] rbtdb.c: failed to remove a node from the deadnodes
authorMark Andrews <marka@isc.org>
Tue, 8 Nov 2011 21:20:57 +0000 (21:20 +0000)
committerMark Andrews <marka@isc.org>
Tue, 8 Nov 2011 21:20:57 +0000 (21:20 +0000)
                        list prior to adding a reference to it leading a
                        possible assertion failure. [RT #23219]

CHANGES
lib/dns/rbtdb.c

diff --git a/CHANGES b/CHANGES
index de822c47cc02161a5c8d1f98be1ed5d354fdb712..14c67d4427f7737bb84e15a3ffd80b9a5569522f 100644 (file)
--- a/CHANGES
+++ b/CHANGES
@@ -1,3 +1,7 @@
+3212.  [bug]           rbtdb.c: failed to remove a node from the deadnodes
+                       list prior to adding a reference to it leading a
+                       possible assertion failure. [RT #23219]
+
 3208.  [bug]           'dig -y' handle unknown tsig alorithm better.
                        [RT #25522]
 
index 93a2a32ac7d77e5e696c7572487164313691bf88..7a5a58414565fa8f3b0bb33a23604e2ff1a76c84 100644 (file)
@@ -15,7 +15,7 @@
  * PERFORMANCE OF THIS SOFTWARE.
  */
 
-/* $Id: rbtdb.c,v 1.270.12.34 2011/10/13 00:37:34 marka Exp $ */
+/* $Id: rbtdb.c,v 1.270.12.35 2011/11/08 21:20:57 marka Exp $ */
 
 /*! \file */
 
@@ -1549,6 +1549,7 @@ new_reference(dns_rbtdb_t *rbtdb, dns_rbtnode_t *node) {
        unsigned int lockrefs, noderefs;
        isc_refcount_t *lockref;
 
+       INSIST(!ISC_LINK_LINKED(node, deadlink));
        dns_rbtnode_refincrement0(node, &noderefs);
        if (noderefs == 1) {    /* this is the first reference to the node */
                lockref = &rbtdb->node_locks[node->locknum].references;
@@ -1575,8 +1576,6 @@ reactivate_node(dns_rbtdb_t *rbtdb, dns_rbtnode_t *node,
        isc_boolean_t need_relock = ISC_FALSE;
 
        NODE_STRONGLOCK(&rbtdb->node_locks[node->locknum].lock);
-       new_reference(rbtdb, node);
-
        NODE_WEAKLOCK(&rbtdb->node_locks[node->locknum].lock,
                      isc_rwlocktype_read);
        if (ISC_LINK_LINKED(node, deadlink))
@@ -1597,7 +1596,7 @@ reactivate_node(dns_rbtdb_t *rbtdb, dns_rbtnode_t *node,
                NODE_WEAKUNLOCK(&rbtdb->node_locks[node->locknum].lock,
                                isc_rwlocktype_write);
        }
-
+       new_reference(rbtdb, node);
        NODE_STRONGUNLOCK(&rbtdb->node_locks[node->locknum].lock);
 }
 
@@ -1763,6 +1762,7 @@ decrement_reference(dns_rbtdb_t *rbtdb, dns_rbtnode_t *node,
                                              ISC_LOG_INFO,
                                              "decrement_reference: failed to "
                                              "allocate pruning event");
+                               INSIST(node->data == NULL);
                                INSIST(!ISC_LINK_LINKED(node, deadlink));
                                ISC_LIST_APPEND(rbtdb->deadnodes[bucket], node,
                                                deadlink);
@@ -1801,6 +1801,7 @@ decrement_reference(dns_rbtdb_t *rbtdb, dns_rbtnode_t *node,
                        }
                }
        } else if (dns_rbtnode_refcurrent(node) == 0) {
+               INSIST(node->data == NULL);
                INSIST(!ISC_LINK_LINKED(node, deadlink));
                ISC_LIST_APPEND(rbtdb->deadnodes[bucket], node, deadlink);
        } else
@@ -1872,11 +1873,10 @@ prune_tree(isc_task_t *task, isc_event_t *event) {
                         * from the list beforehand as we do in
                         * reactivate_node().
                         */
-                       new_reference(rbtdb, parent);
-                       if (ISC_LINK_LINKED(parent, deadlink)) {
+                       if (ISC_LINK_LINKED(parent, deadlink))
                                ISC_LIST_UNLINK(rbtdb->deadnodes[locknum],
                                                parent, deadlink);
-                       }
+                       new_reference(rbtdb, parent);
                } else
                        parent = NULL;
 
@@ -2461,20 +2461,19 @@ add_empty_wildcards(dns_rbtdb_t *rbtdb, dns_name_t *name) {
 }
 
 static isc_result_t
-findnode(dns_db_t *db, dns_name_t *name, isc_boolean_t create,
-        dns_dbnode_t **nodep)
+findnodeintree(dns_rbtdb_t *rbtdb, dns_rbt_t *tree, dns_name_t *name,
+              isc_boolean_t create, dns_dbnode_t **nodep)
 {
-       dns_rbtdb_t *rbtdb = (dns_rbtdb_t *)db;
        dns_rbtnode_t *node = NULL;
        dns_name_t nodename;
        isc_result_t result;
        isc_rwlocktype_t locktype = isc_rwlocktype_read;
 
-       REQUIRE(VALID_RBTDB(rbtdb));
+       INSIST(tree == rbtdb->tree || tree == rbtdb->nsec3);
 
        dns_name_init(&nodename, NULL);
        RWLOCK(&rbtdb->tree_lock, locktype);
-       result = dns_rbt_findnode(rbtdb->tree, name, NULL, &node, NULL,
+       result = dns_rbt_findnode(tree, name, NULL, &node, NULL,
                                  DNS_RBTFIND_EMPTYDATA, NULL, NULL);
        if (result != ISC_R_SUCCESS) {
                RWUNLOCK(&rbtdb->tree_lock, locktype);
@@ -2490,7 +2489,7 @@ findnode(dns_db_t *db, dns_name_t *name, isc_boolean_t create,
                locktype = isc_rwlocktype_write;
                RWLOCK(&rbtdb->tree_lock, locktype);
                node = NULL;
-               result = dns_rbt_addnode(rbtdb->tree, name, &node);
+               result = dns_rbt_addnode(tree, name, &node);
                if (result == ISC_R_SUCCESS) {
                        dns_rbt_namefromnode(node, &nodename);
 #ifdef DNS_RBT_USEHASH
@@ -2499,21 +2498,31 @@ findnode(dns_db_t *db, dns_name_t *name, isc_boolean_t create,
                        node->locknum = dns_name_hash(&nodename, ISC_TRUE) %
                                rbtdb->node_lock_count;
 #endif
-                       node->nsec3 = 0;
-                       add_empty_wildcards(rbtdb, name);
-
-                       if (dns_name_iswildcard(name)) {
-                               result = add_wildcard_magic(rbtdb, name);
-                               if (result != ISC_R_SUCCESS) {
-                                       RWUNLOCK(&rbtdb->tree_lock, locktype);
-                                       return (result);
+                       if (tree == rbtdb->tree) {
+                               node->nsec3 = 0;
+                               add_empty_wildcards(rbtdb, name);
+
+                               if (dns_name_iswildcard(name)) {
+                                       result = add_wildcard_magic(rbtdb,
+                                                                   name);
+                                       if (result != ISC_R_SUCCESS) {
+                                               RWUNLOCK(&rbtdb->tree_lock,
+                                                        locktype);
+                                               return (result);
+                                       }
                                }
                        }
+                       if (tree == rbtdb->nsec3)
+                               node->nsec = 1;
                } else if (result != ISC_R_EXISTS) {
                        RWUNLOCK(&rbtdb->tree_lock, locktype);
                        return (result);
                }
        }
+
+       if (tree == rbtdb->nsec3)
+               INSIST(node->nsec == 1);
+
        reactivate_node(rbtdb, node, locktype);
        RWUNLOCK(&rbtdb->tree_lock, locktype);
 
@@ -2523,59 +2532,25 @@ findnode(dns_db_t *db, dns_name_t *name, isc_boolean_t create,
 }
 
 static isc_result_t
-findnsec3node(dns_db_t *db, dns_name_t *name, isc_boolean_t create,
+findnode(dns_db_t *db, dns_name_t *name, isc_boolean_t create,
              dns_dbnode_t **nodep)
 {
        dns_rbtdb_t *rbtdb = (dns_rbtdb_t *)db;
-       dns_rbtnode_t *node = NULL;
-       dns_name_t nodename;
-       isc_result_t result;
-       isc_rwlocktype_t locktype = isc_rwlocktype_read;
 
        REQUIRE(VALID_RBTDB(rbtdb));
 
-       dns_name_init(&nodename, NULL);
-       RWLOCK(&rbtdb->tree_lock, locktype);
-       result = dns_rbt_findnode(rbtdb->nsec3, name, NULL, &node, NULL,
-                                 DNS_RBTFIND_EMPTYDATA, NULL, NULL);
-       if (result != ISC_R_SUCCESS) {
-               RWUNLOCK(&rbtdb->tree_lock, locktype);
-               if (!create) {
-                       if (result == DNS_R_PARTIALMATCH)
-                               result = ISC_R_NOTFOUND;
-                       return (result);
-               }
-               /*
-                * It would be nice to try to upgrade the lock instead of
-                * unlocking then relocking.
-                */
-               locktype = isc_rwlocktype_write;
-               RWLOCK(&rbtdb->tree_lock, locktype);
-               node = NULL;
-               result = dns_rbt_addnode(rbtdb->nsec3, name, &node);
-               if (result == ISC_R_SUCCESS) {
-                       dns_rbt_namefromnode(node, &nodename);
-#ifdef DNS_RBT_USEHASH
-                       node->locknum = node->hashval % rbtdb->node_lock_count;
-#else
-                       node->locknum = dns_name_hash(&nodename, ISC_TRUE) %
-                               rbtdb->node_lock_count;
-#endif
-                       node->nsec3 = 1U;
-               } else if (result != ISC_R_EXISTS) {
-                       RWUNLOCK(&rbtdb->tree_lock, locktype);
-                       return (result);
-               }
-       } else
-               INSIST(node->nsec3);
-       NODE_STRONGLOCK(&rbtdb->node_locks[node->locknum].lock);
-       new_reference(rbtdb, node);
-       NODE_STRONGUNLOCK(&rbtdb->node_locks[node->locknum].lock);
-       RWUNLOCK(&rbtdb->tree_lock, locktype);
+       return (findnodeintree(rbtdb, rbtdb->tree, name, create, nodep));
+}
 
-       *nodep = (dns_dbnode_t *)node;
+static isc_result_t
+findnsec3node(dns_db_t *db, dns_name_t *name, isc_boolean_t create,
+             dns_dbnode_t **nodep)
+{
+       dns_rbtdb_t *rbtdb = (dns_rbtdb_t *)db;
 
-       return (ISC_R_SUCCESS);
+       REQUIRE(VALID_RBTDB(rbtdb));
+
+       return (findnodeintree(rbtdb, rbtdb->nsec3, name, create, nodep));
 }
 
 static isc_result_t