diff options
author | Internet Software Consortium, Inc <@isc.org> | 2007-09-07 14:16:15 -0600 |
---|---|---|
committer | LaMont Jones <lamont@debian.org> | 2007-09-07 14:16:15 -0600 |
commit | 93d1af61eb25219ad177616d593616f5265597bb (patch) | |
tree | 4d09151ac4c4ae6de41aba3da17a19f9cc8dcdf8 /lib | |
parent | 0d2bbd9fb5842156992e1c07bd94d676c9485147 (diff) | |
download | bind9-93d1af61eb25219ad177616d593616f5265597bb.tar.gz |
9.4.0b4
Diffstat (limited to 'lib')
-rw-r--r-- | lib/dns/api | 2 | ||||
-rw-r--r-- | lib/dns/opensslrsa_link.c | 4 | ||||
-rw-r--r-- | lib/dns/rbtdb.c | 225 |
3 files changed, 108 insertions, 123 deletions
diff --git a/lib/dns/api b/lib/dns/api index 759a0518..e57948fe 100644 --- a/lib/dns/api +++ b/lib/dns/api @@ -1,3 +1,3 @@ LIBINTERFACE = 32 -LIBREVISION = 3 +LIBREVISION = 4 LIBAGE = 0 diff --git a/lib/dns/opensslrsa_link.c b/lib/dns/opensslrsa_link.c index c3507043..2609df6e 100644 --- a/lib/dns/opensslrsa_link.c +++ b/lib/dns/opensslrsa_link.c @@ -17,7 +17,7 @@ /* * Principal Author: Brian Wellington - * $Id: opensslrsa_link.c,v 1.1.6.10 2006/10/11 03:58:14 marka Exp $ + * $Id: opensslrsa_link.c,v 1.1.6.11 2006/11/07 21:28:49 marka Exp $ */ #ifdef OPENSSL @@ -49,7 +49,7 @@ */ #ifdef WIN32 #if !((OPENSSL_VERSION_NUMBER >= 0x009070cfL && \ - OPENSSL_VERSION_NUMBER < 0x009080000L) || \ + OPENSSL_VERSION_NUMBER < 0x00908000L) || \ OPENSSL_VERSION_NUMBER >= 0x0090804fL) #error Please upgrade OpenSSL to 0.9.8d/0.9.7l or greater. #endif diff --git a/lib/dns/rbtdb.c b/lib/dns/rbtdb.c index d18e89e8..cd256081 100644 --- a/lib/dns/rbtdb.c +++ b/lib/dns/rbtdb.c @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: rbtdb.c,v 1.196.18.40 2006/07/31 02:04:48 marka Exp $ */ +/* $Id: rbtdb.c,v 1.196.18.41 2006/10/26 06:04:29 marka Exp $ */ /*! \file */ @@ -158,10 +158,11 @@ typedef isc_rwlock_t nodelock_t; #define NODE_UNLOCK(l, t) RWUNLOCK((l), (t)) #define NODE_TRYUPGRADE(l) isc_rwlock_tryupgrade(l) -#define NODE_STRONGLOCK(l) -#define NODE_STRONGUNLOCK(l) +#define NODE_STRONGLOCK(l) ((void)0) +#define NODE_STRONGUNLOCK(l) ((void)0) #define NODE_WEAKLOCK(l, t) NODE_LOCK(l, t) #define NODE_WEAKUNLOCK(l, t) NODE_UNLOCK(l, t) +#define NODE_WEAKDOWNGRADE(l) isc_rwlock_downgrade(l) #else typedef isc_mutex_t nodelock_t; @@ -173,8 +174,9 @@ typedef isc_mutex_t nodelock_t; #define NODE_STRONGLOCK(l) LOCK(l) #define NODE_STRONGUNLOCK(l) UNLOCK(l) -#define NODE_WEAKLOCK(l, t) -#define NODE_WEAKUNLOCK(l, t) +#define NODE_WEAKLOCK(l, t) ((void)0) +#define NODE_WEAKUNLOCK(l, t) ((void)0) +#define NODE_WEAKDOWNGRADE(l) ((void)0) #endif /* @@ -837,8 +839,8 @@ add_changed(dns_rbtdb_t *rbtdb, rbtdb_version_t *version, REQUIRE(version->writer); if (changed != NULL) { - dns_rbtnode_refincrement0(node, &refs); - INSIST(refs > 0); + dns_rbtnode_refincrement(node, &refs); + INSIST(refs != 0); changed->node = node; changed->dirty = ISC_FALSE; ISC_LIST_INITANDAPPEND(version->changed_list, changed, link); @@ -1128,42 +1130,53 @@ new_reference(dns_rbtdb_t *rbtdb, dns_rbtnode_t *node) { INSIST(noderefs != 0); } - /* - * Caller must be holding the node lock if its reference must be protected - * by the lock. + * Caller must be holding the node lock; either the "strong", read or write + * lock. Note that the lock must be held even when node references are + * atomically modified; in that case the decrement operation itself does not + * have to be protected, but we must avoid a race condition where multiple + * threads are decreasing the reference to zero simultaneously and at least + * one of them is going to free the node. + * This function returns ISC_TRUE if and only if the node reference decreases + * to zero. */ -static void -no_references(dns_rbtdb_t *rbtdb, dns_rbtnode_t *node, - rbtdb_serial_t least_serial, isc_rwlocktype_t lock) +static isc_boolean_t +decrement_reference(dns_rbtdb_t *rbtdb, dns_rbtnode_t *node, + rbtdb_serial_t least_serial, + isc_rwlocktype_t nlock, isc_rwlocktype_t tlock) { isc_result_t result; isc_boolean_t write_locked; - unsigned int locknum; - unsigned int refs; + rbtdb_nodelock_t *nodelock; + unsigned int refs, nrefs; - /* - * We cannot request the node reference be 0 at the moment, since - * the reference counter can atomically be modified without a lock. - * It should still be safe unless we actually try to delete the node, - * at which point the condition is explicitly checked. - */ - - locknum = node->locknum; + nodelock = &rbtdb->node_locks[node->locknum]; - NODE_WEAKLOCK(&rbtdb->node_locks[locknum].lock, isc_rwlocktype_read); + /* Handle easy and typical case first. */ if (!node->dirty && (node->data != NULL || node->down != NULL)) { - /* easy and typical case first, in an efficient way. */ - isc_refcount_decrement(&rbtdb->node_locks[locknum].references, - &refs); - INSIST((int)refs >= 0); - NODE_WEAKUNLOCK(&rbtdb->node_locks[locknum].lock, - isc_rwlocktype_read); - return; + dns_rbtnode_refdecrement(node, &nrefs); + INSIST((int)nrefs >= 0); + if (nrefs == 0) { + isc_refcount_decrement(&nodelock->references, &refs); + INSIST((int)refs >= 0); + } + return ((nrefs == 0) ? ISC_TRUE : ISC_FALSE); + } + + /* Upgrade the lock? */ + if (nlock == isc_rwlocktype_read) { + NODE_WEAKUNLOCK(&nodelock->lock, isc_rwlocktype_read); + NODE_WEAKLOCK(&nodelock->lock, isc_rwlocktype_write); + } + dns_rbtnode_refdecrement(node, &nrefs); + INSIST((int)nrefs >= 0); + if (nrefs > 0) { + /* Restore the lock? */ + if (nlock == isc_rwlocktype_read) + NODE_WEAKDOWNGRADE(&nodelock->lock); + return (ISC_FALSE); } - NODE_WEAKUNLOCK(&rbtdb->node_locks[locknum].lock, isc_rwlocktype_read); - NODE_WEAKLOCK(&rbtdb->node_locks[locknum].lock, isc_rwlocktype_write); if (node->dirty && dns_rbtnode_refcurrent(node) == 0) { if (IS_CACHE(rbtdb)) clean_cache_node(rbtdb, node); @@ -1182,28 +1195,29 @@ no_references(dns_rbtdb_t *rbtdb, dns_rbtnode_t *node, } } - isc_refcount_decrement(&rbtdb->node_locks[locknum].references, &refs); + isc_refcount_decrement(&nodelock->references, &refs); INSIST((int)refs >= 0); /* * XXXDCL should this only be done for cache zones? */ if (node->data != NULL || node->down != NULL) { - NODE_WEAKUNLOCK(&rbtdb->node_locks[locknum].lock, - isc_rwlocktype_write); - return; + /* Restore the lock? */ + if (nlock == isc_rwlocktype_read) + NODE_WEAKDOWNGRADE(&nodelock->lock); + return (ISC_TRUE); } /* * XXXDCL need to add a deferred delete method for ISC_R_LOCKBUSY. */ - if (lock != isc_rwlocktype_write) { + if (tlock != isc_rwlocktype_write) { /* * Locking hierarchy notwithstanding, we don't need to free * the node lock before acquiring the tree write lock because * we only do a trylock. */ - if (lock == isc_rwlocktype_read) + if (tlock == isc_rwlocktype_read) result = isc_rwlock_tryupgrade(&rbtdb->tree_lock); else result = isc_rwlock_trylock(&rbtdb->tree_lock, @@ -1217,7 +1231,7 @@ no_references(dns_rbtdb_t *rbtdb, dns_rbtnode_t *node, if (write_locked && dns_rbtnode_refcurrent(node) == 0) { /* - * We can now delete the node if the reference counter must be + * We can now delete the node if the reference counter is * zero. This should be typically the case, but a different * thread may still gain a (new) reference just before the * current thread locks the tree (e.g., in findnode()). @@ -1228,7 +1242,8 @@ no_references(dns_rbtdb_t *rbtdb, dns_rbtnode_t *node, isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE, DNS_LOGMODULE_CACHE, ISC_LOG_DEBUG(1), - "no_references: delete from rbt: %p %s", + "decrement_reference: " + "delete from rbt: %p %s", node, dns_rbt_formatnodename(node, printname, sizeof(printname))); @@ -1238,23 +1253,27 @@ no_references(dns_rbtdb_t *rbtdb, dns_rbtnode_t *node, if (result != ISC_R_SUCCESS) isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE, DNS_LOGMODULE_CACHE, ISC_LOG_WARNING, - "no_references: dns_rbt_deletenode: %s", + "decrement_reference: " + "dns_rbt_deletenode: %s", isc_result_totext(result)); } - NODE_WEAKUNLOCK(&rbtdb->node_locks[locknum].lock, - isc_rwlocktype_write); + /* Restore the lock? */ + if (nlock == isc_rwlocktype_read) + NODE_WEAKDOWNGRADE(&nodelock->lock); /* * Relock a read lock, or unlock the write lock if no lock was held. */ - if (lock == isc_rwlocktype_none) + if (tlock == isc_rwlocktype_none) if (write_locked) RWUNLOCK(&rbtdb->tree_lock, isc_rwlocktype_write); - if (lock == isc_rwlocktype_read) + if (tlock == isc_rwlocktype_read) if (write_locked) isc_rwlock_downgrade(&rbtdb->tree_lock); + + return (ISC_TRUE); } static inline void @@ -1517,27 +1536,18 @@ closeversion(dns_db_t *db, dns_dbversion_t **versionp, isc_boolean_t commit) { changed != NULL; changed = next_changed) { nodelock_t *lock; - unsigned int refs; next_changed = NEXT(changed, link); rbtnode = changed->node; lock = &rbtdb->node_locks[rbtnode->locknum].lock; - NODE_STRONGLOCK(lock); - - dns_rbtnode_refdecrement(rbtnode, &refs); - INSIST((int)refs >= 0); - - NODE_WEAKLOCK(lock, isc_rwlocktype_write); + NODE_LOCK(lock, isc_rwlocktype_write); if (rollback) rollback_node(rbtnode, serial); - NODE_WEAKUNLOCK(lock, isc_rwlocktype_write); - - if (refs == 0) - no_references(rbtdb, rbtnode, least_serial, - isc_rwlocktype_none); - - NODE_STRONGUNLOCK(lock); + decrement_reference(rbtdb, rbtnode, least_serial, + isc_rwlocktype_write, + isc_rwlocktype_none); + NODE_UNLOCK(lock, isc_rwlocktype_write); isc_mem_put(rbtdb->common.mctx, changed, sizeof(*changed)); @@ -2906,20 +2916,13 @@ zone_find(dns_db_t *db, dns_name_t *name, dns_dbversion_t *version, * let go of it. */ if (search.need_cleanup) { - unsigned int refs; - node = search.zonecut; lock = &(search.rbtdb->node_locks[node->locknum].lock); - NODE_STRONGLOCK(lock); - - dns_rbtnode_refdecrement(node, &refs); - INSIST((int)refs >= 0); - if (refs == 0) - no_references(search.rbtdb, node, 0, - isc_rwlocktype_none); - - NODE_STRONGUNLOCK(lock); + NODE_LOCK(lock, isc_rwlocktype_read); + decrement_reference(search.rbtdb, node, 0, + isc_rwlocktype_read, isc_rwlocktype_none); + NODE_UNLOCK(lock, isc_rwlocktype_read); } if (close_version) @@ -3008,7 +3011,7 @@ cache_zonecut_callback(dns_rbtnode_t *node, dns_name_t *name, void *arg) { /* * header->down can be non-NULL if the * refcount has just decremented to 0 - * but no_references() has not + * but decrement_reference() has not * performed clean_cache_node(), in * which case we need to purge the * stale headers first. @@ -3635,21 +3638,13 @@ cache_find(dns_db_t *db, dns_name_t *name, dns_dbversion_t *version, * let go of it. */ if (search.need_cleanup) { - unsigned int refs; - node = search.zonecut; lock = &(search.rbtdb->node_locks[node->locknum].lock); - NODE_STRONGLOCK(lock); - - dns_rbtnode_refdecrement(node, &refs); - INSIST((int)refs >= 0); - - if (refs == 0) - no_references(search.rbtdb, node, 0, - isc_rwlocktype_none); - - NODE_STRONGUNLOCK(lock); + NODE_LOCK(lock, isc_rwlocktype_read); + decrement_reference(search.rbtdb, node, 0, + isc_rwlocktype_read, isc_rwlocktype_none); + NODE_UNLOCK(lock, isc_rwlocktype_read); } dns_rbtnodechain_reset(&search.chain); @@ -3824,8 +3819,8 @@ attachnode(dns_db_t *db, dns_dbnode_t *source, dns_dbnode_t **targetp) { REQUIRE(targetp != NULL && *targetp == NULL); NODE_STRONGLOCK(&rbtdb->node_locks[node->locknum].lock); - dns_rbtnode_refincrement0(node, &refs); - INSIST(refs > 1); + dns_rbtnode_refincrement(node, &refs); + INSIST(refs != 0); NODE_STRONGUNLOCK(&rbtdb->node_locks[node->locknum].lock); *targetp = source; @@ -3837,31 +3832,25 @@ detachnode(dns_db_t *db, dns_dbnode_t **targetp) { dns_rbtnode_t *node; isc_boolean_t want_free = ISC_FALSE; isc_boolean_t inactive = ISC_FALSE; - unsigned int locknum; - unsigned int refs; + rbtdb_nodelock_t *nodelock; REQUIRE(VALID_RBTDB(rbtdb)); REQUIRE(targetp != NULL && *targetp != NULL); node = (dns_rbtnode_t *)(*targetp); - locknum = node->locknum; + nodelock = &rbtdb->node_locks[node->locknum]; - NODE_STRONGLOCK(&rbtdb->node_locks[locknum].lock); + NODE_LOCK(&nodelock->lock, isc_rwlocktype_read); - dns_rbtnode_refdecrement(node, &refs); - INSIST((int)refs >= 0); - if (refs == 0) { - no_references(rbtdb, node, 0, isc_rwlocktype_none); - NODE_WEAKLOCK(&rbtdb->node_locks[locknum].lock, - isc_rwlocktype_read); - if (isc_refcount_current(&rbtdb->node_locks[locknum].references) == 0 && - rbtdb->node_locks[locknum].exiting) + if (decrement_reference(rbtdb, node, 0, isc_rwlocktype_read, + isc_rwlocktype_none)) { + if (isc_refcount_current(&nodelock->references) == 0 && + nodelock->exiting) { inactive = ISC_TRUE; - NODE_WEAKUNLOCK(&rbtdb->node_locks[locknum].lock, - isc_rwlocktype_read); + } } - NODE_STRONGUNLOCK(&rbtdb->node_locks[locknum].lock); + NODE_UNLOCK(&nodelock->lock, isc_rwlocktype_read); *targetp = NULL; @@ -4285,8 +4274,8 @@ allrdatasets(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version, NODE_STRONGLOCK(&rbtdb->node_locks[rbtnode->locknum].lock); - dns_rbtnode_refincrement0(rbtnode, &refs); - INSIST(refs > 0); + dns_rbtnode_refincrement(rbtnode, &refs); + INSIST(refs != 0); iterator->current = NULL; @@ -5984,19 +5973,16 @@ static inline void dereference_iter_node(rbtdb_dbiterator_t *rbtdbiter) { dns_rbtdb_t *rbtdb = (dns_rbtdb_t *)rbtdbiter->common.db; dns_rbtnode_t *node = rbtdbiter->node; - unsigned int refs; nodelock_t *lock; if (node == NULL) return; lock = &rbtdb->node_locks[node->locknum].lock; - NODE_STRONGLOCK(lock); - dns_rbtnode_refdecrement(node, &refs); - INSIST((int)refs >= 0); - if (refs == 0) - no_references(rbtdb, node, 0, rbtdbiter->tree_locked); - NODE_STRONGUNLOCK(lock); + NODE_LOCK(lock, isc_rwlocktype_read); + decrement_reference(rbtdb, node, 0, isc_rwlocktype_read, + rbtdbiter->tree_locked); + NODE_UNLOCK(lock, isc_rwlocktype_read); rbtdbiter->node = NULL; } @@ -6030,18 +6016,14 @@ flush_deletions(rbtdb_dbiterator_t *rbtdbiter) { rbtdbiter->tree_locked = isc_rwlocktype_write; for (i = 0; i < rbtdbiter->delete; i++) { - unsigned int refs; - node = rbtdbiter->deletions[i]; lock = &rbtdb->node_locks[node->locknum].lock; - NODE_STRONGLOCK(lock); - dns_rbtnode_refdecrement(node, &refs); - INSIST((int)refs >= 0); - if (refs == 0) - no_references(rbtdb, node, 0, - rbtdbiter->tree_locked); - NODE_STRONGUNLOCK(lock); + NODE_LOCK(lock, isc_rwlocktype_read); + decrement_reference(rbtdb, node, 0, + isc_rwlocktype_read, + rbtdbiter->tree_locked); + NODE_UNLOCK(lock, isc_rwlocktype_read); } rbtdbiter->delete = 0; @@ -6332,9 +6314,12 @@ dbiterator_current(dns_dbiterator_t *iterator, dns_dbnode_t **nodep, * expirenode() currently always returns success. */ if (expire_result == ISC_R_SUCCESS && node->down == NULL) { + unsigned int refs; + rbtdbiter->deletions[rbtdbiter->delete++] = node; NODE_STRONGLOCK(&rbtdb->node_locks[node->locknum].lock); - dns_rbtnode_refincrement0(node, NULL); + dns_rbtnode_refincrement(node, &refs); + INSIST(refs != 0); NODE_STRONGUNLOCK(&rbtdb->node_locks[node->locknum].lock); } } |