diff -up bind-9.5.0b1/lib/dns/rbtdb.c.segv bind-9.5.0b1/lib/dns/rbtdb.c --- bind-9.5.0b1/lib/dns/rbtdb.c.segv 2008-02-04 12:30:36.000000000 +0100 +++ bind-9.5.0b1/lib/dns/rbtdb.c 2008-02-04 13:46:48.000000000 +0100 @@ -763,23 +763,17 @@ free_rbtdb(dns_rbtdb_t *rbtdb, isc_boole isc_mem_put(rbtdb->common.mctx, rbtdb->current_version, sizeof(rbtdb_version_t)); } - if (IS_CACHE(rbtdb)) { - /* - * We assume the number of remaining dead nodes is reasonably - * small; the overhead of unlinking all nodes here should be - * negligible. - */ - for (i = 0; i < rbtdb->node_lock_count; i++) { - dns_rbtnode_t *node; - - node = ISC_LIST_HEAD(rbtdb->deadnodes[i]); - while (node != NULL) { - ISC_LIST_UNLINK(rbtdb->deadnodes[i], node, - deadlink); - node = ISC_LIST_HEAD(rbtdb->deadnodes[i]); - } + + for (i = 0; i < rbtdb->node_lock_count; i++) { + dns_rbtnode_t *node; + + node = ISC_LIST_HEAD(rbtdb->deadnodes[i]); + while (node != NULL) { + ISC_LIST_UNLINK(rbtdb->deadnodes[i], node, deadlink); + node = ISC_LIST_HEAD(rbtdb->deadnodes[i]); } } + if (event == NULL) rbtdb->quantum = (rbtdb->task != NULL) ? 100 : 0; again: @@ -1912,6 +1906,7 @@ closeversion(dns_db_t *db, dns_dbversion } if (!EMPTY(cleanup_list)) { + RWLOCK(&rbtdb->tree_lock, isc_rwlocktype_write); for (changed = HEAD(cleanup_list); changed != NULL; changed = next_changed) { @@ -1922,16 +1917,18 @@ closeversion(dns_db_t *db, dns_dbversion lock = &rbtdb->node_locks[rbtnode->locknum].lock; NODE_LOCK(lock, isc_rwlocktype_write); + cleanup_dead_nodes(rbtdb, rbtnode->locknum); if (rollback) rollback_node(rbtnode, serial); decrement_reference(rbtdb, rbtnode, least_serial, isc_rwlocktype_write, - isc_rwlocktype_none); + isc_rwlocktype_write); NODE_UNLOCK(lock, isc_rwlocktype_write); isc_mem_put(rbtdb->common.mctx, changed, sizeof(*changed)); } + RWUNLOCK(&rbtdb->tree_lock, isc_rwlocktype_write); } end: @@ -2009,6 +2006,7 @@ findnode(dns_db_t *db, dns_name_t *name, dns_name_t nodename; isc_result_t result; isc_rwlocktype_t locktype = isc_rwlocktype_read; + isc_boolean_t need_relock; REQUIRE(VALID_RBTDB(rbtdb)); @@ -2064,29 +2062,27 @@ findnode(dns_db_t *db, dns_name_t *name, * happen to hold a write lock on the tree, it's a good chance to purge * dead nodes. */ - if (IS_CACHE(rbtdb)) { - isc_boolean_t need_relock = ISC_FALSE; + need_relock = ISC_FALSE; + NODE_WEAKLOCK(&rbtdb->node_locks[node->locknum].lock, + isc_rwlocktype_read); + if (ISC_LINK_LINKED(node, deadlink) && isc_rwlocktype_write) + need_relock = ISC_TRUE; + else if (!ISC_LIST_EMPTY(rbtdb->deadnodes[node->locknum]) && + locktype == isc_rwlocktype_write) + need_relock = ISC_TRUE; + NODE_WEAKUNLOCK(&rbtdb->node_locks[node->locknum].lock, + isc_rwlocktype_read); + if (need_relock) { NODE_WEAKLOCK(&rbtdb->node_locks[node->locknum].lock, - isc_rwlocktype_read); - if (ISC_LINK_LINKED(node, deadlink) && isc_rwlocktype_write) - need_relock = ISC_TRUE; - else if (!ISC_LIST_EMPTY(rbtdb->deadnodes[node->locknum]) && - locktype == isc_rwlocktype_write) - need_relock = ISC_TRUE; + isc_rwlocktype_write); + if (ISC_LINK_LINKED(node, deadlink)) + ISC_LIST_UNLINK(rbtdb->deadnodes[node->locknum], + node, deadlink); + if (locktype == isc_rwlocktype_write) + cleanup_dead_nodes(rbtdb, node->locknum); NODE_WEAKUNLOCK(&rbtdb->node_locks[node->locknum].lock, - isc_rwlocktype_read); - if (need_relock) { - NODE_WEAKLOCK(&rbtdb->node_locks[node->locknum].lock, - isc_rwlocktype_write); - if (ISC_LINK_LINKED(node, deadlink)) - ISC_LIST_UNLINK(rbtdb->deadnodes[node->locknum], - node, deadlink); - if (locktype == isc_rwlocktype_write) - cleanup_dead_nodes(rbtdb, node->locknum); - NODE_WEAKUNLOCK(&rbtdb->node_locks[node->locknum].lock, - isc_rwlocktype_write); - } + isc_rwlocktype_write); } NODE_STRONGUNLOCK(&rbtdb->node_locks[node->locknum].lock); @@ -6149,15 +6145,6 @@ dns_rbtdb_create for (i = 0; i < (int)rbtdb->node_lock_count; i++) ISC_LIST_INIT(rbtdb->rdatasets[i]); - rbtdb->deadnodes = isc_mem_get(mctx, rbtdb->node_lock_count * - sizeof(rbtnodelist_t)); - if (rbtdb->deadnodes == NULL) { - result = ISC_R_NOMEMORY; - goto cleanup_rdatasets; - } - for (i = 0; i < (int)rbtdb->node_lock_count; i++) - ISC_LIST_INIT(rbtdb->deadnodes[i]); - /* * Create the heaps. */ @@ -6165,7 +6152,7 @@ dns_rbtdb_create sizeof(isc_heap_t *)); if (rbtdb->heaps == NULL) { result = ISC_R_NOMEMORY; - goto cleanup_deadnodes; + goto cleanup_rdatasets; } for (i = 0; i < (int)rbtdb->node_lock_count; i++) rbtdb->heaps[i] = NULL; @@ -6178,10 +6165,18 @@ dns_rbtdb_create } } else { rbtdb->rdatasets = NULL; - rbtdb->deadnodes = NULL; rbtdb->heaps = NULL; } + rbtdb->deadnodes = isc_mem_get(mctx, rbtdb->node_lock_count * + sizeof(rbtnodelist_t)); + if (rbtdb->deadnodes == NULL) { + result = ISC_R_NOMEMORY; + goto cleanup_heaps; + } + for (i = 0; i < (int)rbtdb->node_lock_count; i++) + ISC_LIST_INIT(rbtdb->deadnodes[i]); + rbtdb->active = rbtdb->node_lock_count; for (i = 0; i < (int)(rbtdb->node_lock_count); i++) { @@ -6197,7 +6192,7 @@ dns_rbtdb_create isc_refcount_decrement(&rbtdb->node_locks[i].references, NULL); isc_refcount_destroy(&rbtdb->node_locks[i].references); } - goto cleanup_heaps; + goto cleanup_deadnodes; } rbtdb->node_locks[i].exiting = ISC_FALSE; } @@ -6310,6 +6305,10 @@ dns_rbtdb_create return (ISC_R_SUCCESS); + cleanup_deadnodes: + isc_mem_put(mctx, rbtdb->deadnodes, + rbtdb->node_lock_count * sizeof(rbtnodelist_t)); + cleanup_heaps: if (rbtdb->heaps != NULL) { for (i = 0 ; i < (int)rbtdb->node_lock_count ; i++) @@ -6319,11 +6318,6 @@ dns_rbtdb_create rbtdb->node_lock_count * sizeof(isc_heap_t *)); } - cleanup_deadnodes: - if (rbtdb->deadnodes != NULL) - isc_mem_put(mctx, rbtdb->deadnodes, - rbtdb->node_lock_count * sizeof(rbtnodelist_t)); - cleanup_rdatasets: if (rbtdb->rdatasets != NULL) isc_mem_put(mctx, rbtdb->rdatasets, rbtdb->node_lock_count *