summaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
authorInternet Software Consortium, Inc <@isc.org>2007-09-07 14:16:15 -0600
committerLaMont Jones <lamont@debian.org>2007-09-07 14:16:15 -0600
commit93d1af61eb25219ad177616d593616f5265597bb (patch)
tree4d09151ac4c4ae6de41aba3da17a19f9cc8dcdf8 /lib
parent0d2bbd9fb5842156992e1c07bd94d676c9485147 (diff)
downloadbind9-93d1af61eb25219ad177616d593616f5265597bb.tar.gz
9.4.0b4
Diffstat (limited to 'lib')
-rw-r--r--lib/dns/api2
-rw-r--r--lib/dns/opensslrsa_link.c4
-rw-r--r--lib/dns/rbtdb.c225
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);
}
}