diff --git a/CHANGES b/CHANGES index 5757e3af41..a7015559f9 100644 --- a/CHANGES +++ b/CHANGES @@ -1,3 +1,7 @@ +3211. [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] + 3211. [func] dnssec-signzone: "-f -" prints to stdout; "-O full" option prints in single-line-per-record format. [RT #20287] diff --git a/lib/dns/rbtdb.c b/lib/dns/rbtdb.c index 1571126c8e..6da85fab48 100644 --- a/lib/dns/rbtdb.c +++ b/lib/dns/rbtdb.c @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: rbtdb.c,v 1.319 2011/10/13 01:32:33 vjs Exp $ */ +/* $Id: rbtdb.c,v 1.320 2011/11/08 20:49:11 marka Exp $ */ /*! \file */ @@ -1616,6 +1616,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; @@ -1642,8 +1643,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)) @@ -1664,7 +1663,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); } @@ -1830,6 +1829,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); @@ -1853,6 +1853,7 @@ decrement_reference(dns_rbtdb_t *rbtdb, dns_rbtnode_t *node, delete_node(rbtdb, 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 @@ -1924,11 +1925,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; @@ -2500,20 +2500,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); @@ -2529,10 +2528,10 @@ 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) { #ifdef BIND9 - if (rbtdb->rpz_cidr != NULL) { + if (tree == rbtdb->tree && rbtdb->rpz_cidr != NULL) { dns_fixedname_t fnamef; dns_name_t *fname; @@ -2549,20 +2548,28 @@ 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 - add_empty_wildcards(rbtdb, name); + if (tree == rbtdb->tree) { + 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 (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 = DNS_RBT_NSEC_NSEC3; } else if (result != ISC_R_EXISTS) { RWUNLOCK(&rbtdb->tree_lock, locktype); return (result); } } + + if (tree == rbtdb->nsec3) + INSIST(node->nsec == DNS_RBT_NSEC_NSEC3); + reactivate_node(rbtdb, node, locktype); RWUNLOCK(&rbtdb->tree_lock, locktype); @@ -2571,61 +2578,26 @@ findnode(dns_db_t *db, dns_name_t *name, isc_boolean_t create, return (ISC_R_SUCCESS); } +static isc_result_t +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; + + REQUIRE(VALID_RBTDB(rbtdb)); + + return (findnodeintree(rbtdb, rbtdb->tree, name, create, nodep)); +} + 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; - 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->nsec = DNS_RBT_NSEC_NSEC3; - } else if (result != ISC_R_EXISTS) { - RWUNLOCK(&rbtdb->tree_lock, locktype); - return (result); - } - } else { - INSIST(node->nsec == DNS_RBT_NSEC_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); - - *nodep = (dns_dbnode_t *)node; - - return (ISC_R_SUCCESS); + return (findnodeintree(rbtdb, rbtdb->nsec3, name, create, nodep)); } static isc_result_t