From 006a7f0cb647b12362f8d3dd891ee7eabbeeea23 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Sur=C3=BD?= Date: Thu, 13 Oct 2022 21:10:04 +0200 Subject: [PATCH 1/2] Remove isc_rwlock_downgrade usage in rbtdb.c The only place where isc_rwlock_downgrade was being used was the decrement_reference() where the code tries either relocks the node rwlock to write and then tries to upgrade the tree lock. When returning from the function it tries to restore the locks into a previous state which is nice, but kind of moot, because at every use of decrement_reference() the node locks is immediately or almost immeditately unlocked, and same holds for the tree lock. Instead of trying to restore the node and tree lock into the initial state, the decrement_reference now returns the state of the locks, so the caller can then use the right unlock operation (read or write). Only when the tree lock was originally unlocked, the decrement_reference unlocks the tree lock before returning to the caller. --- lib/dns/rbtdb.c | 592 +++++++++++++++++++++++++----------------------- 1 file changed, 303 insertions(+), 289 deletions(-) diff --git a/lib/dns/rbtdb.c b/lib/dns/rbtdb.c index b35ad05cc3..5d9473c17b 100644 --- a/lib/dns/rbtdb.c +++ b/lib/dns/rbtdb.c @@ -116,18 +116,6 @@ typedef uint32_t rbtdb_rdatatype_t; * high performance and small-memory reference counters, we use rwlock for * node lock and isc_refcount for node references. In this case, we don't have * to protect the access to the counters by locks. - * Otherwise, we simply use ordinary mutex lock for node locking, and use - * simple integers as reference counters which is protected by the lock. - * In most cases, we can simply use wrapper macros such as NODE_LOCK and - * NODE_UNLOCK. In some other cases, however, we need to protect reference - * counters first and then protect other parts of a node as read-only data. - * Special additional macros, NODE_STRONGLOCK(), NODE_WEAKLOCK(), etc, are also - * provided for these special cases. When we can use the efficient backend - * routines, we should only protect the "other members" by NODE_WEAKLOCK(read). - * Otherwise, we should use NODE_STRONGLOCK() to protect the entire critical - * section including the access to the reference counter. - * Note that we cannot use NODE_LOCK()/NODE_UNLOCK() wherever the protected - * section is also protected by NODE_STRONGLOCK(). */ typedef isc_rwlock_t nodelock_t; @@ -136,7 +124,6 @@ typedef isc_rwlock_t nodelock_t; #define NODE_LOCK(l, t) RWLOCK((l), (t)) #define NODE_UNLOCK(l, t) RWUNLOCK((l), (t)) #define NODE_TRYUPGRADE(l) isc_rwlock_tryupgrade(l) -#define NODE_DOWNGRADE(l) isc_rwlock_downgrade(l) /*% * Whether to rate-limit updating the LRU to avoid possible thread contention. @@ -540,11 +527,11 @@ need_headerupdate(rdatasetheader_t *header, isc_stdtime_t now); static void update_header(dns_rbtdb_t *rbtdb, rdatasetheader_t *header, isc_stdtime_t now); static void -expire_header(dns_rbtdb_t *rbtdb, rdatasetheader_t *header, bool tree_locked, - expire_t reason); +expire_header(dns_rbtdb_t *rbtdb, rdatasetheader_t *header, + isc_rwlocktype_t *tlocktypep, expire_t reason); static void overmem_purge(dns_rbtdb_t *rbtdb, unsigned int locknum_start, isc_stdtime_t now, - bool tree_locked); + isc_rwlocktype_t *tlocktypep); static void resign_insert(dns_rbtdb_t *rbtdb, int idx, rdatasetheader_t *newheader); static void @@ -1894,21 +1881,21 @@ cleanup_dead_nodes(dns_rbtdb_t *rbtdb, int bucketnum) { */ static void reactivate_node(dns_rbtdb_t *rbtdb, dns_rbtnode_t *node, - isc_rwlocktype_t treelocktype) { - isc_rwlocktype_t locktype = isc_rwlocktype_read; + isc_rwlocktype_t tlocktype) { + isc_rwlocktype_t nlocktype = isc_rwlocktype_read; nodelock_t *nodelock = &rbtdb->node_locks[node->locknum].lock; bool maybe_cleanup = false; - POST(locktype); + POST(nlocktype); - NODE_LOCK(nodelock, locktype); + NODE_LOCK(nodelock, nlocktype); /* * Check if we can possibly cleanup the dead node. If so, upgrade * the node lock below to perform the cleanup. */ if (!ISC_LIST_EMPTY(rbtdb->deadnodes[node->locknum]) && - treelocktype == isc_rwlocktype_write) + tlocktype == isc_rwlocktype_write) { maybe_cleanup = true; } @@ -1917,10 +1904,10 @@ reactivate_node(dns_rbtdb_t *rbtdb, dns_rbtnode_t *node, /* * Upgrade the lock and test if we still need to unlink. */ - NODE_UNLOCK(nodelock, locktype); - locktype = isc_rwlocktype_write; - POST(locktype); - NODE_LOCK(nodelock, locktype); + NODE_UNLOCK(nodelock, nlocktype); + nlocktype = isc_rwlocktype_write; + POST(nlocktype); + NODE_LOCK(nodelock, nlocktype); if (ISC_LINK_LINKED(node, deadlink)) { ISC_LIST_UNLINK(rbtdb->deadnodes[node->locknum], node, deadlink); @@ -1930,14 +1917,14 @@ reactivate_node(dns_rbtdb_t *rbtdb, dns_rbtnode_t *node, } } - new_reference(rbtdb, node, locktype); + new_reference(rbtdb, node, nlocktype); - NODE_UNLOCK(nodelock, locktype); + NODE_UNLOCK(nodelock, nlocktype); } /* - * 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 + * Caller must be holding the node lock; either the 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 @@ -1951,16 +1938,18 @@ reactivate_node(dns_rbtdb_t *rbtdb, dns_rbtnode_t *node, */ static bool decrement_reference(dns_rbtdb_t *rbtdb, dns_rbtnode_t *node, - rbtdb_serial_t least_serial, isc_rwlocktype_t nlock, - isc_rwlocktype_t tlock, bool pruning) { + rbtdb_serial_t least_serial, isc_rwlocktype_t *nlocktype, + isc_rwlocktype_t *tlocktype, bool pruning) { isc_result_t result; - bool write_locked; - bool locked = tlock != isc_rwlocktype_none; + bool locked = *tlocktype != isc_rwlocktype_none; + bool write_locked = false; rbtdb_nodelock_t *nodelock; int bucket = node->locknum; bool no_reference = true; uint_fast32_t refs; + REQUIRE(*nlocktype != isc_rwlocktype_none); + nodelock = &rbtdb->node_locks[bucket]; #define KEEP_NODE(n, r, l) \ @@ -1979,16 +1968,13 @@ decrement_reference(dns_rbtdb_t *rbtdb, dns_rbtnode_t *node, } /* Upgrade the lock? */ - if (nlock == isc_rwlocktype_read) { - NODE_UNLOCK(&nodelock->lock, isc_rwlocktype_read); - NODE_LOCK(&nodelock->lock, isc_rwlocktype_write); + if (*nlocktype == isc_rwlocktype_read) { + NODE_UNLOCK(&nodelock->lock, *nlocktype); + *nlocktype = isc_rwlocktype_write; + NODE_LOCK(&nodelock->lock, *nlocktype); } if (isc_refcount_decrement(&node->references) > 1) { - /* Restore the lock? */ - if (nlock == isc_rwlocktype_read) { - NODE_DOWNGRADE(&nodelock->lock); - } return (false); } @@ -2013,31 +1999,35 @@ decrement_reference(dns_rbtdb_t *rbtdb, dns_rbtnode_t *node, * Attempt to switch to a write lock on the tree. If this fails, * we will add this node to a linked list of nodes in this locking * bucket which we will free later. + * + * 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 (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 (tlock == isc_rwlocktype_read) { - result = isc_rwlock_tryupgrade(&rbtdb->tree_lock); - } else { - result = isc_rwlock_trylock(&rbtdb->tree_lock, - isc_rwlocktype_write); - } - RUNTIME_CHECK(result == ISC_R_SUCCESS || - result == ISC_R_LOCKBUSY); - - write_locked = (result == ISC_R_SUCCESS); - } else { + switch (*tlocktype) { + case isc_rwlocktype_write: + result = ISC_R_SUCCESS; + break; + case isc_rwlocktype_read: + result = isc_rwlock_tryupgrade(&rbtdb->tree_lock); + break; + case isc_rwlocktype_none: + result = isc_rwlock_trylock(&rbtdb->tree_lock, + isc_rwlocktype_write); + break; + default: + UNREACHABLE(); + } + RUNTIME_CHECK(result == ISC_R_SUCCESS || result == ISC_R_LOCKBUSY); + if (result == ISC_R_SUCCESS) { write_locked = true; + *tlocktype = isc_rwlocktype_write; } refs = isc_refcount_decrement(&nodelock->references); INSIST(refs > 0); - if (KEEP_NODE(node, rbtdb, locked || write_locked)) { + if (KEEP_NODE(node, rbtdb, (locked || write_locked))) { goto restore_locks; } @@ -2079,24 +2069,12 @@ decrement_reference(dns_rbtdb_t *rbtdb, dns_rbtnode_t *node, } restore_locks: - /* Restore the lock? */ - if (nlock == isc_rwlocktype_read) { - NODE_DOWNGRADE(&nodelock->lock); - } - /* * Relock a read lock, or unlock the write lock if no lock was held. */ - if (tlock == isc_rwlocktype_none) { - if (write_locked) { - RWUNLOCK(&rbtdb->tree_lock, isc_rwlocktype_write); - } - } - - if (tlock == isc_rwlocktype_read) { - if (write_locked) { - isc_rwlock_downgrade(&rbtdb->tree_lock); - } + if (!locked && write_locked) { + RWUNLOCK(&rbtdb->tree_lock, *tlocktype); + *tlocktype = isc_rwlocktype_none; } return (no_reference); @@ -2115,18 +2093,20 @@ prune_tree(isc_task_t *task, isc_event_t *event) { dns_rbtnode_t *node = event->ev_arg; dns_rbtnode_t *parent; unsigned int locknum; + isc_rwlocktype_t tlocktype = isc_rwlocktype_write; + isc_rwlocktype_t nlocktype = isc_rwlocktype_write; UNUSED(task); isc_event_free(&event); - RWLOCK(&rbtdb->tree_lock, isc_rwlocktype_write); + RWLOCK(&rbtdb->tree_lock, tlocktype); locknum = node->locknum; - NODE_LOCK(&rbtdb->node_locks[locknum].lock, isc_rwlocktype_write); + NODE_LOCK(&rbtdb->node_locks[locknum].lock, nlocktype); do { parent = node->parent; - decrement_reference(rbtdb, node, 0, isc_rwlocktype_write, - isc_rwlocktype_write, true); + decrement_reference(rbtdb, node, 0, &nlocktype, &tlocktype, + true); if (parent != NULL && parent->down == NULL) { /* @@ -2137,10 +2117,10 @@ prune_tree(isc_task_t *task, isc_event_t *event) { */ if (parent->locknum != locknum) { NODE_UNLOCK(&rbtdb->node_locks[locknum].lock, - isc_rwlocktype_write); + nlocktype); locknum = parent->locknum; NODE_LOCK(&rbtdb->node_locks[locknum].lock, - isc_rwlocktype_write); + nlocktype); } /* @@ -2151,15 +2131,15 @@ prune_tree(isc_task_t *task, isc_event_t *event) { ISC_LIST_UNLINK(rbtdb->deadnodes[locknum], parent, deadlink); } - new_reference(rbtdb, parent, isc_rwlocktype_write); + new_reference(rbtdb, parent, nlocktype); } else { parent = NULL; } node = parent; } while (node != NULL); - NODE_UNLOCK(&rbtdb->node_locks[locknum].lock, isc_rwlocktype_write); - RWUNLOCK(&rbtdb->tree_lock, isc_rwlocktype_write); + NODE_UNLOCK(&rbtdb->node_locks[locknum].lock, nlocktype); + RWUNLOCK(&rbtdb->tree_lock, tlocktype); detach((dns_db_t **)&rbtdb); } @@ -2568,23 +2548,25 @@ closeversion(dns_db_t *db, dns_dbversion_t **versionp, bool commit) { for (header = HEAD(resigned_list); header != NULL; header = HEAD(resigned_list)) { nodelock_t *lock; + isc_rwlocktype_t tlocktype = isc_rwlocktype_none; + isc_rwlocktype_t nlocktype = isc_rwlocktype_write; ISC_LIST_UNLINK(resigned_list, header, link); lock = &rbtdb->node_locks[header->node->locknum].lock; - NODE_LOCK(lock, isc_rwlocktype_write); + NODE_LOCK(lock, nlocktype); if (rollback && !IGNORE(header)) { resign_insert(rbtdb, header->node->locknum, header); } decrement_reference(rbtdb, header->node, least_serial, - isc_rwlocktype_write, isc_rwlocktype_none, - false); - NODE_UNLOCK(lock, isc_rwlocktype_write); + &nlocktype, &tlocktype, false); + NODE_UNLOCK(lock, nlocktype); + INSIST(tlocktype == isc_rwlocktype_none); } if (!EMPTY(cleanup_list)) { isc_event_t *event = NULL; - isc_rwlocktype_t tlock = isc_rwlocktype_none; + isc_rwlocktype_t tlocktype = isc_rwlocktype_none; if (rbtdb->task != NULL) { event = isc_event_allocate(rbtdb->common.mctx, NULL, @@ -2602,19 +2584,20 @@ closeversion(dns_db_t *db, dns_dbversion_t **versionp, bool commit) { * expensive, but this event should be rare enough * to justify the cost. */ - RWLOCK(&rbtdb->tree_lock, isc_rwlocktype_write); - tlock = isc_rwlocktype_write; + tlocktype = isc_rwlocktype_write; + RWLOCK(&rbtdb->tree_lock, tlocktype); } for (changed = HEAD(cleanup_list); changed != NULL; changed = next_changed) { nodelock_t *lock; + isc_rwlocktype_t nlocktype = isc_rwlocktype_write; next_changed = NEXT(changed, link); rbtnode = changed->node; lock = &rbtdb->node_locks[rbtnode->locknum].lock; - NODE_LOCK(lock, isc_rwlocktype_write); + NODE_LOCK(lock, nlocktype); /* * This is a good opportunity to purge any dead nodes, * so use it. @@ -2627,9 +2610,9 @@ closeversion(dns_db_t *db, dns_dbversion_t **versionp, bool commit) { rollback_node(rbtnode, serial); } decrement_reference(rbtdb, rbtnode, least_serial, - isc_rwlocktype_write, tlock, false); + &nlocktype, &tlocktype, false); - NODE_UNLOCK(lock, isc_rwlocktype_write); + NODE_UNLOCK(lock, nlocktype); isc_mem_put(rbtdb->common.mctx, changed, sizeof(*changed)); @@ -2638,8 +2621,11 @@ closeversion(dns_db_t *db, dns_dbversion_t **versionp, bool commit) { isc_refcount_increment(&rbtdb->references); isc_task_send(rbtdb->task, &event); } else { - RWUNLOCK(&rbtdb->tree_lock, isc_rwlocktype_write); + RWUNLOCK(&rbtdb->tree_lock, tlocktype); + tlocktype = isc_rwlocktype_none; } + + INSIST(tlocktype == isc_rwlocktype_none); } end: @@ -2728,28 +2714,28 @@ findnodeintree(dns_rbtdb_t *rbtdb, dns_rbt_t *tree, const dns_name_t *name, dns_rbtnode_t *node = NULL; dns_name_t nodename; isc_result_t result; - isc_rwlocktype_t locktype = isc_rwlocktype_read; + isc_rwlocktype_t tlocktype = isc_rwlocktype_read; INSIST(tree == rbtdb->tree || tree == rbtdb->nsec3); dns_name_init(&nodename, NULL); - RWLOCK(&rbtdb->tree_lock, locktype); + RWLOCK(&rbtdb->tree_lock, tlocktype); result = dns_rbt_findnode(tree, 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); + goto unlock; } /* * It would be nice to try to upgrade the lock instead of * unlocking then relocking. */ - locktype = isc_rwlocktype_write; - RWLOCK(&rbtdb->tree_lock, locktype); + RWUNLOCK(&rbtdb->tree_lock, tlocktype); + tlocktype = isc_rwlocktype_write; + RWLOCK(&rbtdb->tree_lock, tlocktype); node = NULL; result = dns_rbt_addnode(tree, name, &node); if (result == ISC_R_SUCCESS) { @@ -2762,9 +2748,7 @@ findnodeintree(dns_rbtdb_t *rbtdb, dns_rbt_t *tree, const dns_name_t *name, result = add_wildcard_magic(rbtdb, name); if (result != ISC_R_SUCCESS) { - RWUNLOCK(&rbtdb->tree_lock, - locktype); - return (result); + goto unlock; } } } @@ -2772,8 +2756,7 @@ findnodeintree(dns_rbtdb_t *rbtdb, dns_rbt_t *tree, const dns_name_t *name, node->nsec = DNS_RBT_NSEC_NSEC3; } } else if (result != ISC_R_EXISTS) { - RWUNLOCK(&rbtdb->tree_lock, locktype); - return (result); + goto unlock; } } @@ -2781,13 +2764,14 @@ findnodeintree(dns_rbtdb_t *rbtdb, dns_rbt_t *tree, const dns_name_t *name, INSIST(node->nsec == DNS_RBT_NSEC_NSEC3); } - reactivate_node(rbtdb, node, locktype); - - RWUNLOCK(&rbtdb->tree_lock, locktype); + reactivate_node(rbtdb, node, tlocktype); *nodep = (dns_dbnode_t *)node; - return (ISC_R_SUCCESS); +unlock: + RWUNLOCK(&rbtdb->tree_lock, tlocktype); + + return (result); } static isc_result_t @@ -3896,6 +3880,8 @@ zone_find(dns_db_t *db, const dns_name_t *name, dns_dbversion_t *version, bool active; nodelock_t *lock; dns_rbt_t *tree; + isc_rwlocktype_t nlocktype; + isc_rwlocktype_t tlocktype; search.rbtdb = (dns_rbtdb_t *)db; @@ -3933,7 +3919,8 @@ zone_find(dns_db_t *db, const dns_name_t *name, dns_dbversion_t *version, */ wild = false; - RWLOCK(&search.rbtdb->tree_lock, isc_rwlocktype_read); + tlocktype = isc_rwlocktype_read; + RWLOCK(&search.rbtdb->tree_lock, tlocktype); /* * Search down from the root of the tree. If, while going down, we @@ -4053,7 +4040,8 @@ found: */ lock = &search.rbtdb->node_locks[node->locknum].lock; - NODE_LOCK(lock, isc_rwlocktype_read); + nlocktype = isc_rwlocktype_read; + NODE_LOCK(lock, nlocktype); found = NULL; foundsig = NULL; @@ -4098,8 +4086,7 @@ found: * ensure that search->zonecut_rdataset will * still be valid later. */ - new_reference(search.rbtdb, node, - isc_rwlocktype_read); + new_reference(search.rbtdb, node, nlocktype); search.zonecut = node; search.zonecut_rdataset = header; search.zonecut_sigrdataset = NULL; @@ -4135,7 +4122,7 @@ found: */ if (header->type == dns_rdatatype_nsec3 && !matchparams(header, &search)) { - NODE_UNLOCK(lock, isc_rwlocktype_read); + NODE_UNLOCK(lock, nlocktype); goto partial_match; } /* @@ -4219,7 +4206,7 @@ found: * we really have a partial match. */ if (!wild) { - NODE_UNLOCK(lock, isc_rwlocktype_read); + NODE_UNLOCK(lock, nlocktype); goto partial_match; } } @@ -4235,7 +4222,7 @@ found: * * Return the delegation. */ - NODE_UNLOCK(lock, isc_rwlocktype_read); + NODE_UNLOCK(lock, nlocktype); result = setup_delegation(&search, nodep, foundname, rdataset, sigrdataset); goto tree_exit; @@ -4257,7 +4244,7 @@ found: goto node_exit; } - NODE_UNLOCK(lock, isc_rwlocktype_read); + NODE_UNLOCK(lock, nlocktype); result = find_closest_nsec(&search, nodep, foundname, rdataset, sigrdataset, search.rbtdb->tree, @@ -4277,7 +4264,7 @@ found: goto node_exit; } if (nodep != NULL) { - new_reference(search.rbtdb, node, isc_rwlocktype_read); + new_reference(search.rbtdb, node, nlocktype); *nodep = node; } if ((search.rbtversion->secure == dns_db_secure && @@ -4285,10 +4272,10 @@ found: (search.options & DNS_DBFIND_FORCENSEC) != 0) { bind_rdataset(search.rbtdb, node, nsecheader, 0, - isc_rwlocktype_read, rdataset); + nlocktype, rdataset); if (nsecsig != NULL) { bind_rdataset(search.rbtdb, node, nsecsig, 0, - isc_rwlocktype_read, sigrdataset); + nlocktype, sigrdataset); } } if (wild) { @@ -4347,7 +4334,7 @@ found: (search.options & DNS_DBFIND_VALIDATEGLUE) != 0 && !valid_glue(&search, foundname, type, node)) { - NODE_UNLOCK(lock, isc_rwlocktype_read); + NODE_UNLOCK(lock, nlocktype); result = setup_delegation(&search, nodep, foundname, rdataset, sigrdataset); goto tree_exit; @@ -4361,7 +4348,7 @@ found: if (nodep != NULL) { if (!at_zonecut) { - new_reference(search.rbtdb, node, isc_rwlocktype_read); + new_reference(search.rbtdb, node, nlocktype); } else { search.need_cleanup = false; } @@ -4369,11 +4356,11 @@ found: } if (type != dns_rdatatype_any) { - bind_rdataset(search.rbtdb, node, found, 0, isc_rwlocktype_read, + bind_rdataset(search.rbtdb, node, found, 0, nlocktype, rdataset); if (foundsig != NULL) { bind_rdataset(search.rbtdb, node, foundsig, 0, - isc_rwlocktype_read, sigrdataset); + nlocktype, sigrdataset); } } @@ -4382,24 +4369,28 @@ found: } node_exit: - NODE_UNLOCK(lock, isc_rwlocktype_read); + NODE_UNLOCK(lock, nlocktype); tree_exit: - RWUNLOCK(&search.rbtdb->tree_lock, isc_rwlocktype_read); + RWUNLOCK(&search.rbtdb->tree_lock, tlocktype); /* * If we found a zonecut but aren't going to use it, we have to * let go of it. */ if (search.need_cleanup) { + nlocktype = isc_rwlocktype_read; + tlocktype = isc_rwlocktype_none; + node = search.zonecut; INSIST(node != NULL); lock = &(search.rbtdb->node_locks[node->locknum].lock); - NODE_LOCK(lock, isc_rwlocktype_read); - decrement_reference(search.rbtdb, node, 0, isc_rwlocktype_read, - isc_rwlocktype_none, false); - NODE_UNLOCK(lock, isc_rwlocktype_read); + NODE_LOCK(lock, nlocktype); + decrement_reference(search.rbtdb, node, 0, &nlocktype, + &tlocktype, false); + NODE_UNLOCK(lock, nlocktype); + INSIST(tlocktype == isc_rwlocktype_none); } if (close_version) { @@ -4434,7 +4425,7 @@ zone_findzonecut(dns_db_t *db, const dns_name_t *name, unsigned int options, static bool check_stale_header(dns_rbtnode_t *node, rdatasetheader_t *header, - isc_rwlocktype_t *locktype, nodelock_t *lock, + isc_rwlocktype_t *nlocktype, nodelock_t *lock, rbtdb_search_t *search, rdatasetheader_t **header_prev) { if (!ACTIVE(header, search->now)) { dns_ttl_t stale = header->rdh_ttl + @@ -4495,7 +4486,7 @@ check_stale_header(dns_rbtnode_t *node, rdatasetheader_t *header, * cleaned up later. */ if ((header->rdh_ttl < search->now - RBTDB_VIRTUAL) && - (*locktype == isc_rwlocktype_write || + (*nlocktype == isc_rwlocktype_write || NODE_TRYUPGRADE(lock) == ISC_R_SUCCESS)) { /* @@ -4506,7 +4497,7 @@ check_stale_header(dns_rbtnode_t *node, rdatasetheader_t *header, * We won't downgrade the lock, since other * rdatasets are probably stale, too. */ - *locktype = isc_rwlocktype_write; + *nlocktype = isc_rwlocktype_write; if (isc_refcount_current(&node->references) == 0) { isc_mem_t *mctx; @@ -4547,7 +4538,7 @@ cache_zonecut_callback(dns_rbtnode_t *node, dns_name_t *name, void *arg) { rdatasetheader_t *dname_header, *sigdname_header; isc_result_t result; nodelock_t *lock; - isc_rwlocktype_t locktype; + isc_rwlocktype_t nlocktype; /* XXX comment */ @@ -4559,8 +4550,8 @@ cache_zonecut_callback(dns_rbtnode_t *node, dns_name_t *name, void *arg) { UNUSED(name); lock = &(search->rbtdb->node_locks[node->locknum].lock); - locktype = isc_rwlocktype_read; - NODE_LOCK(lock, locktype); + nlocktype = isc_rwlocktype_read; + NODE_LOCK(lock, nlocktype); /* * Look for a DNAME or RRSIG DNAME rdataset. @@ -4570,7 +4561,7 @@ cache_zonecut_callback(dns_rbtnode_t *node, dns_name_t *name, void *arg) { header_prev = NULL; for (header = node->data; header != NULL; header = header_next) { header_next = header->next; - if (check_stale_header(node, header, &locktype, lock, search, + if (check_stale_header(node, header, &nlocktype, lock, search, &header_prev)) { /* Do nothing. */ } else if (header->type == dns_rdatatype_dname && @@ -4596,7 +4587,7 @@ cache_zonecut_callback(dns_rbtnode_t *node, dns_name_t *name, void *arg) { * We increment the reference count on node to ensure that * search->zonecut_rdataset will still be valid later. */ - new_reference(search->rbtdb, node, locktype); + new_reference(search->rbtdb, node, nlocktype); search->zonecut = node; search->zonecut_rdataset = dname_header; search->zonecut_sigrdataset = sigdname_header; @@ -4606,7 +4597,7 @@ cache_zonecut_callback(dns_rbtnode_t *node, dns_name_t *name, void *arg) { result = DNS_R_CONTINUE; } - NODE_UNLOCK(lock, locktype); + NODE_UNLOCK(lock, nlocktype); return (result); } @@ -4624,7 +4615,7 @@ find_deepest_zonecut(rbtdb_search_t *search, dns_rbtnode_t *node, dns_rbtdb_t *rbtdb; bool done; nodelock_t *lock; - isc_rwlocktype_t locktype; + isc_rwlocktype_t nlocktype; /* * Caller must be holding the tree lock. @@ -4634,9 +4625,9 @@ find_deepest_zonecut(rbtdb_search_t *search, dns_rbtnode_t *node, i = search->chain.level_matches; done = false; do { - locktype = isc_rwlocktype_read; + nlocktype = isc_rwlocktype_read; lock = &rbtdb->node_locks[node->locknum].lock; - NODE_LOCK(lock, locktype); + NODE_LOCK(lock, nlocktype); /* * Look for NS and RRSIG NS rdatasets. @@ -4647,7 +4638,7 @@ find_deepest_zonecut(rbtdb_search_t *search, dns_rbtnode_t *node, for (header = node->data; header != NULL; header = header_next) { header_next = header->next; - if (check_stale_header(node, header, &locktype, lock, + if (check_stale_header(node, header, &nlocktype, lock, search, &header_prev)) { /* Do nothing. */ } else if (EXISTS(header) && !ANCIENT(header)) { @@ -4704,25 +4695,25 @@ find_deepest_zonecut(rbtdb_search_t *search, dns_rbtnode_t *node, } result = DNS_R_DELEGATION; if (nodep != NULL) { - new_reference(search->rbtdb, node, locktype); + new_reference(search->rbtdb, node, nlocktype); *nodep = node; } bind_rdataset(search->rbtdb, node, found, search->now, - locktype, rdataset); + nlocktype, rdataset); if (foundsig != NULL) { bind_rdataset(search->rbtdb, node, foundsig, - search->now, locktype, + search->now, nlocktype, sigrdataset); } if (need_headerupdate(found, search->now) || (foundsig != NULL && need_headerupdate(foundsig, search->now))) { - if (locktype != isc_rwlocktype_write) { - NODE_UNLOCK(lock, locktype); - NODE_LOCK(lock, isc_rwlocktype_write); - locktype = isc_rwlocktype_write; - POST(locktype); + if (nlocktype != isc_rwlocktype_write) { + NODE_UNLOCK(lock, nlocktype); + nlocktype = isc_rwlocktype_write; + NODE_LOCK(lock, nlocktype); + POST(nlocktype); } if (need_headerupdate(found, search->now)) { update_header(search->rbtdb, found, @@ -4737,7 +4728,7 @@ find_deepest_zonecut(rbtdb_search_t *search, dns_rbtnode_t *node, } node_exit: - NODE_UNLOCK(lock, locktype); + NODE_UNLOCK(lock, nlocktype); if (found == NULL && i > 0) { i--; @@ -4768,7 +4759,7 @@ find_coveringnsec(rbtdb_search_t *search, const dns_name_t *name, dns_rbtnode_t *node = NULL; dns_rbtnodechain_t chain; isc_result_t result; - isc_rwlocktype_t locktype; + isc_rwlocktype_t nlocktype; nodelock_t *lock = NULL; rbtdb_rdatatype_t matchtype, sigmatchtype; rdatasetheader_t *found = NULL, *foundsig = NULL; @@ -4792,7 +4783,7 @@ find_coveringnsec(rbtdb_search_t *search, const dns_name_t *name, target = dns_fixedname_initname(&ftarget); fname = dns_fixedname_initname(&fixed); - locktype = isc_rwlocktype_read; + nlocktype = isc_rwlocktype_read; matchtype = RBTDB_RDATATYPE_VALUE(dns_rdatatype_nsec, 0); sigmatchtype = RBTDB_RDATATYPE_VALUE(dns_rdatatype_rrsig, dns_rdatatype_nsec); @@ -4822,10 +4813,10 @@ find_coveringnsec(rbtdb_search_t *search, const dns_name_t *name, } lock = &(search->rbtdb->node_locks[node->locknum].lock); - NODE_LOCK(lock, locktype); + NODE_LOCK(lock, nlocktype); for (header = node->data; header != NULL; header = header_next) { header_next = header->next; - if (check_stale_header(node, header, &locktype, lock, search, + if (check_stale_header(node, header, &nlocktype, lock, search, &header_prev)) { continue; } @@ -4848,13 +4839,13 @@ find_coveringnsec(rbtdb_search_t *search, const dns_name_t *name, header_prev = header; } if (found != NULL) { - bind_rdataset(search->rbtdb, node, found, now, locktype, + bind_rdataset(search->rbtdb, node, found, now, nlocktype, rdataset); if (foundsig != NULL) { bind_rdataset(search->rbtdb, node, foundsig, now, - locktype, sigrdataset); + nlocktype, sigrdataset); } - new_reference(search->rbtdb, node, locktype); + new_reference(search->rbtdb, node, nlocktype); dns_name_copy(fname, foundname); @@ -4863,7 +4854,7 @@ find_coveringnsec(rbtdb_search_t *search, const dns_name_t *name, } else { result = ISC_R_NOTFOUND; } - NODE_UNLOCK(lock, locktype); + NODE_UNLOCK(lock, nlocktype); return (result); } @@ -4880,7 +4871,8 @@ cache_find(dns_db_t *db, const dns_name_t *name, dns_dbversion_t *version, bool all_negative = true; bool empty_node; nodelock_t *lock; - isc_rwlocktype_t locktype; + isc_rwlocktype_t tlocktype; + isc_rwlocktype_t nlocktype = isc_rwlocktype_read; rdatasetheader_t *header, *header_prev, *header_next; rdatasetheader_t *found, *nsheader; rdatasetheader_t *foundsig, *nssig, *cnamesig; @@ -4914,7 +4906,8 @@ cache_find(dns_db_t *db, const dns_name_t *name, dns_dbversion_t *version, update = NULL; updatesig = NULL; - RWLOCK(&search.rbtdb->tree_lock, isc_rwlocktype_read); + tlocktype = isc_rwlocktype_read; + RWLOCK(&search.rbtdb->tree_lock, tlocktype); /* * Search down from the root of the tree. If, while going down, we @@ -4972,8 +4965,7 @@ cache_find(dns_db_t *db, const dns_name_t *name, dns_dbversion_t *version, */ lock = &(search.rbtdb->node_locks[node->locknum].lock); - locktype = isc_rwlocktype_read; - NODE_LOCK(lock, locktype); + NODE_LOCK(lock, nlocktype); found = NULL; foundsig = NULL; @@ -4988,7 +4980,7 @@ cache_find(dns_db_t *db, const dns_name_t *name, dns_dbversion_t *version, header_prev = NULL; for (header = node->data; header != NULL; header = header_next) { header_next = header->next; - if (check_stale_header(node, header, &locktype, lock, &search, + if (check_stale_header(node, header, &nlocktype, lock, &search, &header_prev)) { /* Do nothing. */ } else if (EXISTS(header) && !ANCIENT(header)) { @@ -5075,7 +5067,7 @@ cache_find(dns_db_t *db, const dns_name_t *name, dns_dbversion_t *version, * extant rdatasets. That means that this node doesn't * meaningfully exist, and that we really have a partial match. */ - NODE_UNLOCK(lock, locktype); + NODE_UNLOCK(lock, nlocktype); if ((search.options & DNS_DBFIND_COVERINGNSEC) != 0) { result = find_coveringnsec(&search, name, nodep, now, foundname, rdataset, @@ -5104,17 +5096,17 @@ cache_find(dns_db_t *db, const dns_name_t *name, dns_dbversion_t *version, if ((search.options & DNS_DBFIND_COVERINGNSEC) != 0 && nsecheader != NULL) { if (nodep != NULL) { - new_reference(search.rbtdb, node, locktype); + new_reference(search.rbtdb, node, nlocktype); *nodep = node; } bind_rdataset(search.rbtdb, node, nsecheader, - search.now, locktype, rdataset); + search.now, nlocktype, rdataset); if (need_headerupdate(nsecheader, search.now)) { update = nsecheader; } if (nsecsig != NULL) { bind_rdataset(search.rbtdb, node, nsecsig, - search.now, locktype, + search.now, nlocktype, sigrdataset); if (need_headerupdate(nsecsig, search.now)) { updatesig = nsecsig; @@ -5130,7 +5122,7 @@ cache_find(dns_db_t *db, const dns_name_t *name, dns_dbversion_t *version, if (found == NULL && (found_noqname || all_negative) && (search.options & DNS_DBFIND_COVERINGNSEC) != 0) { - NODE_UNLOCK(lock, locktype); + NODE_UNLOCK(lock, nlocktype); result = find_coveringnsec(&search, name, nodep, now, foundname, rdataset, sigrdataset); @@ -5146,17 +5138,17 @@ cache_find(dns_db_t *db, const dns_name_t *name, dns_dbversion_t *version, */ if (nsheader != NULL) { if (nodep != NULL) { - new_reference(search.rbtdb, node, locktype); + new_reference(search.rbtdb, node, nlocktype); *nodep = node; } bind_rdataset(search.rbtdb, node, nsheader, search.now, - locktype, rdataset); + nlocktype, rdataset); if (need_headerupdate(nsheader, search.now)) { update = nsheader; } if (nssig != NULL) { bind_rdataset(search.rbtdb, node, nssig, - search.now, locktype, + search.now, nlocktype, sigrdataset); if (need_headerupdate(nssig, search.now)) { updatesig = nssig; @@ -5169,7 +5161,7 @@ cache_find(dns_db_t *db, const dns_name_t *name, dns_dbversion_t *version, /* * Go find the deepest zone cut. */ - NODE_UNLOCK(lock, locktype); + NODE_UNLOCK(lock, nlocktype); goto find_ns; } @@ -5178,7 +5170,7 @@ cache_find(dns_db_t *db, const dns_name_t *name, dns_dbversion_t *version, */ if (nodep != NULL) { - new_reference(search.rbtdb, node, locktype); + new_reference(search.rbtdb, node, nlocktype); *nodep = node; } @@ -5210,14 +5202,14 @@ cache_find(dns_db_t *db, const dns_name_t *name, dns_dbversion_t *version, if (type != dns_rdatatype_any || result == DNS_R_NCACHENXDOMAIN || result == DNS_R_NCACHENXRRSET) { - bind_rdataset(search.rbtdb, node, found, search.now, locktype, + bind_rdataset(search.rbtdb, node, found, search.now, nlocktype, rdataset); if (need_headerupdate(found, search.now)) { update = found; } if (!NEGATIVE(found) && foundsig != NULL) { bind_rdataset(search.rbtdb, node, foundsig, search.now, - locktype, sigrdataset); + nlocktype, sigrdataset); if (need_headerupdate(foundsig, search.now)) { updatesig = foundsig; } @@ -5226,11 +5218,11 @@ cache_find(dns_db_t *db, const dns_name_t *name, dns_dbversion_t *version, node_exit: if ((update != NULL || updatesig != NULL) && - locktype != isc_rwlocktype_write) { - NODE_UNLOCK(lock, locktype); - NODE_LOCK(lock, isc_rwlocktype_write); - locktype = isc_rwlocktype_write; - POST(locktype); + nlocktype != isc_rwlocktype_write) { + NODE_UNLOCK(lock, nlocktype); + nlocktype = isc_rwlocktype_write; + NODE_LOCK(lock, nlocktype); + POST(nlocktype); } if (update != NULL && need_headerupdate(update, search.now)) { update_header(search.rbtdb, update, search.now); @@ -5239,24 +5231,28 @@ node_exit: update_header(search.rbtdb, updatesig, search.now); } - NODE_UNLOCK(lock, locktype); + NODE_UNLOCK(lock, nlocktype); tree_exit: - RWUNLOCK(&search.rbtdb->tree_lock, isc_rwlocktype_read); + RWUNLOCK(&search.rbtdb->tree_lock, tlocktype); /* * If we found a zonecut but aren't going to use it, we have to * let go of it. */ if (search.need_cleanup) { + nlocktype = isc_rwlocktype_read; + tlocktype = isc_rwlocktype_none; + node = search.zonecut; INSIST(node != NULL); lock = &(search.rbtdb->node_locks[node->locknum].lock); - NODE_LOCK(lock, isc_rwlocktype_read); - decrement_reference(search.rbtdb, node, 0, isc_rwlocktype_read, - isc_rwlocktype_none, false); - NODE_UNLOCK(lock, isc_rwlocktype_read); + NODE_LOCK(lock, nlocktype); + decrement_reference(search.rbtdb, node, 0, &nlocktype, + &tlocktype, false); + NODE_UNLOCK(lock, nlocktype); + INSIST(tlocktype == isc_rwlocktype_none); } dns_rbtnodechain_reset(&search.chain); @@ -5277,7 +5273,8 @@ cache_findzonecut(dns_db_t *db, const dns_name_t *name, unsigned int options, rdatasetheader_t *header, *header_prev, *header_next; rdatasetheader_t *found, *foundsig; unsigned int rbtoptions = DNS_RBTFIND_EMPTYDATA; - isc_rwlocktype_t locktype; + isc_rwlocktype_t tlocktype = isc_rwlocktype_read; + isc_rwlocktype_t nlocktype = isc_rwlocktype_read; bool dcnull = (dcname == NULL); search.rbtdb = (dns_rbtdb_t *)db; @@ -5307,7 +5304,8 @@ cache_findzonecut(dns_db_t *db, const dns_name_t *name, unsigned int options, rbtoptions |= DNS_RBTFIND_NOEXACT; } - RWLOCK(&search.rbtdb->tree_lock, isc_rwlocktype_read); + tlocktype = isc_rwlocktype_read; + RWLOCK(&search.rbtdb->tree_lock, tlocktype); /* * Search down from the root of the tree. @@ -5330,15 +5328,14 @@ cache_findzonecut(dns_db_t *db, const dns_name_t *name, unsigned int options, */ lock = &(search.rbtdb->node_locks[node->locknum].lock); - locktype = isc_rwlocktype_read; - NODE_LOCK(lock, locktype); + NODE_LOCK(lock, nlocktype); found = NULL; foundsig = NULL; header_prev = NULL; for (header = node->data; header != NULL; header = header_next) { header_next = header->next; - if (check_stale_header(node, header, &locktype, lock, &search, + if (check_stale_header(node, header, &nlocktype, lock, &search, &header_prev)) { /* * The function dns_rbt_findnode found us the a matching @@ -5350,7 +5347,7 @@ cache_findzonecut(dns_db_t *db, const dns_name_t *name, unsigned int options, * zonecut we know about. If so, find the deepest * zonecut from this node up and return that instead. */ - NODE_UNLOCK(lock, locktype); + NODE_UNLOCK(lock, nlocktype); result = find_deepest_zonecut(&search, node, nodep, foundname, rdataset, sigrdataset); @@ -5385,32 +5382,32 @@ cache_findzonecut(dns_db_t *db, const dns_name_t *name, unsigned int options, /* * No NS records here. */ - NODE_UNLOCK(lock, locktype); + NODE_UNLOCK(lock, nlocktype); result = find_deepest_zonecut(&search, node, nodep, foundname, rdataset, sigrdataset); goto tree_exit; } if (nodep != NULL) { - new_reference(search.rbtdb, node, locktype); + new_reference(search.rbtdb, node, nlocktype); *nodep = node; } - bind_rdataset(search.rbtdb, node, found, search.now, locktype, + bind_rdataset(search.rbtdb, node, found, search.now, nlocktype, rdataset); if (foundsig != NULL) { bind_rdataset(search.rbtdb, node, foundsig, search.now, - locktype, sigrdataset); + nlocktype, sigrdataset); } if (need_headerupdate(found, search.now) || (foundsig != NULL && need_headerupdate(foundsig, search.now))) { - if (locktype != isc_rwlocktype_write) { - NODE_UNLOCK(lock, locktype); - NODE_LOCK(lock, isc_rwlocktype_write); - locktype = isc_rwlocktype_write; - POST(locktype); + if (nlocktype != isc_rwlocktype_write) { + NODE_UNLOCK(lock, nlocktype); + nlocktype = isc_rwlocktype_write; + NODE_LOCK(lock, nlocktype); + POST(nlocktype); } if (need_headerupdate(found, search.now)) { update_header(search.rbtdb, found, search.now); @@ -5421,10 +5418,10 @@ cache_findzonecut(dns_db_t *db, const dns_name_t *name, unsigned int options, } } - NODE_UNLOCK(lock, locktype); + NODE_UNLOCK(lock, nlocktype); tree_exit: - RWUNLOCK(&search.rbtdb->tree_lock, isc_rwlocktype_read); + RWUNLOCK(&search.rbtdb->tree_lock, tlocktype); INSIST(!search.need_cleanup); @@ -5457,6 +5454,8 @@ detachnode(dns_db_t *db, dns_dbnode_t **targetp) { bool want_free = false; bool inactive = false; rbtdb_nodelock_t *nodelock; + isc_rwlocktype_t nlocktype = isc_rwlocktype_read; + isc_rwlocktype_t tlocktype = isc_rwlocktype_none; REQUIRE(VALID_RBTDB(rbtdb)); REQUIRE(targetp != NULL && *targetp != NULL); @@ -5464,10 +5463,9 @@ detachnode(dns_db_t *db, dns_dbnode_t **targetp) { node = (dns_rbtnode_t *)(*targetp); nodelock = &rbtdb->node_locks[node->locknum]; - NODE_LOCK(&nodelock->lock, isc_rwlocktype_read); + NODE_LOCK(&nodelock->lock, nlocktype); - if (decrement_reference(rbtdb, node, 0, isc_rwlocktype_read, - isc_rwlocktype_none, false)) + if (decrement_reference(rbtdb, node, 0, &nlocktype, &tlocktype, false)) { if (isc_refcount_current(&nodelock->references) == 0 && nodelock->exiting) { @@ -5475,7 +5473,8 @@ detachnode(dns_db_t *db, dns_dbnode_t **targetp) { } } - NODE_UNLOCK(&nodelock->lock, isc_rwlocktype_read); + NODE_UNLOCK(&nodelock->lock, nlocktype); + INSIST(tlocktype == isc_rwlocktype_none); *targetp = NULL; @@ -6727,7 +6726,8 @@ addrdataset(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version, isc_result_t result; bool delegating; bool newnsec; - bool tree_locked = false; + isc_rwlocktype_t tlocktype = isc_rwlocktype_read; + isc_rwlocktype_t nlocktype = isc_rwlocktype_write; bool cache_is_overmem = false; dns_fixedname_t fixed; dns_name_t *name; @@ -6743,14 +6743,14 @@ addrdataset(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version, node != rbtdb->origin_node) { return (DNS_R_NOTZONETOP); } - RWLOCK(&rbtdb->tree_lock, isc_rwlocktype_read); + RWLOCK(&rbtdb->tree_lock, tlocktype); REQUIRE(((rbtnode->nsec == DNS_RBT_NSEC_NSEC3 && (rdataset->type == dns_rdatatype_nsec3 || rdataset->covers == dns_rdatatype_nsec3)) || (rbtnode->nsec != DNS_RBT_NSEC_NSEC3 && rdataset->type != dns_rdatatype_nsec3 && rdataset->covers != dns_rdatatype_nsec3))); - RWUNLOCK(&rbtdb->tree_lock, isc_rwlocktype_read); + RWUNLOCK(&rbtdb->tree_lock, tlocktype); } if (rbtversion == NULL) { @@ -6851,7 +6851,8 @@ addrdataset(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version, /* * Add to the auxiliary NSEC tree if we're adding an NSEC record. */ - RWLOCK(&rbtdb->tree_lock, isc_rwlocktype_read); + tlocktype = isc_rwlocktype_read; + RWLOCK(&rbtdb->tree_lock, tlocktype); if (rbtnode->nsec != DNS_RBT_NSEC_HAS_NSEC && rdataset->type == dns_rdatatype_nsec) { @@ -6859,7 +6860,7 @@ addrdataset(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version, } else { newnsec = false; } - RWUNLOCK(&rbtdb->tree_lock, isc_rwlocktype_read); + RWUNLOCK(&rbtdb->tree_lock, tlocktype); /* * If we're adding a delegation type, adding to the auxiliary NSEC @@ -6872,16 +6873,17 @@ addrdataset(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version, cache_is_overmem = true; } if (delegating || newnsec || cache_is_overmem) { - tree_locked = true; - RWLOCK(&rbtdb->tree_lock, isc_rwlocktype_write); + tlocktype = isc_rwlocktype_write; + RWLOCK(&rbtdb->tree_lock, tlocktype); + } else { + tlocktype = isc_rwlocktype_none; } if (cache_is_overmem) { - overmem_purge(rbtdb, rbtnode->locknum, now, tree_locked); + overmem_purge(rbtdb, rbtnode->locknum, now, &tlocktype); } - NODE_LOCK(&rbtdb->node_locks[rbtnode->locknum].lock, - isc_rwlocktype_write); + NODE_LOCK(&rbtdb->node_locks[rbtnode->locknum].lock, nlocktype); if (rbtdb->rrsetstats != NULL) { RDATASET_ATTR_SET(newheader, RDATASET_ATTR_STATCOUNT); @@ -6891,7 +6893,7 @@ addrdataset(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version, } if (IS_CACHE(rbtdb)) { - if (tree_locked) { + if (tlocktype == isc_rwlocktype_write) { cleanup_dead_nodes(rbtdb, rbtnode->locknum); } @@ -6900,7 +6902,7 @@ addrdataset(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version, header->rdh_ttl + STALE_TTL(header, rbtdb) < now - RBTDB_VIRTUAL) { - expire_header(rbtdb, header, tree_locked, expire_ttl); + expire_header(rbtdb, header, &tlocktype, expire_ttl); } /* @@ -6908,9 +6910,10 @@ addrdataset(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version, * cleaning, we can release it now. However, we still need the * node lock. */ - if (tree_locked && !delegating && !newnsec) { - RWUNLOCK(&rbtdb->tree_lock, isc_rwlocktype_write); - tree_locked = false; + if (tlocktype == isc_rwlocktype_write && !delegating && + !newnsec) { + RWUNLOCK(&rbtdb->tree_lock, tlocktype); + tlocktype = isc_rwlocktype_none; } } @@ -6937,11 +6940,10 @@ addrdataset(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version, rbtnode->find_callback = 1; } - NODE_UNLOCK(&rbtdb->node_locks[rbtnode->locknum].lock, - isc_rwlocktype_write); + NODE_UNLOCK(&rbtdb->node_locks[rbtnode->locknum].lock, nlocktype); - if (tree_locked) { - RWUNLOCK(&rbtdb->tree_lock, isc_rwlocktype_write); + if (tlocktype != isc_rwlocktype_none) { + RWUNLOCK(&rbtdb->tree_lock, tlocktype); } /* @@ -8814,68 +8816,83 @@ dereference_iter_node(rbtdb_dbiterator_t *rbtdbiter) { dns_rbtdb_t *rbtdb = (dns_rbtdb_t *)rbtdbiter->common.db; dns_rbtnode_t *node = rbtdbiter->node; nodelock_t *lock; + isc_rwlocktype_t nlocktype = isc_rwlocktype_read; + isc_rwlocktype_t tlocktype = rbtdbiter->tree_locked; if (node == NULL) { return; } + REQUIRE(tlocktype != isc_rwlocktype_write); + lock = &rbtdb->node_locks[node->locknum].lock; - NODE_LOCK(lock, isc_rwlocktype_read); - decrement_reference(rbtdb, node, 0, isc_rwlocktype_read, - rbtdbiter->tree_locked, false); - NODE_UNLOCK(lock, isc_rwlocktype_read); + NODE_LOCK(lock, nlocktype); + decrement_reference(rbtdb, node, 0, &nlocktype, &rbtdbiter->tree_locked, + false); + NODE_UNLOCK(lock, nlocktype); + + if (tlocktype != rbtdbiter->tree_locked) { + RWUNLOCK(&rbtdb->tree_lock, rbtdbiter->tree_locked); + rbtdbiter->tree_locked = isc_rwlocktype_none; + if (tlocktype == isc_rwlocktype_read) { + RWLOCK(&rbtdb->tree_lock, tlocktype); + rbtdbiter->tree_locked = tlocktype; + } + } + INSIST(rbtdbiter->tree_locked == tlocktype); rbtdbiter->node = NULL; } static void flush_deletions(rbtdb_dbiterator_t *rbtdbiter) { - dns_rbtnode_t *node; dns_rbtdb_t *rbtdb = (dns_rbtdb_t *)rbtdbiter->common.db; - bool was_read_locked = false; - nodelock_t *lock; - int i; + isc_rwlocktype_t tlocktype = rbtdbiter->tree_locked; - if (rbtdbiter->delcnt != 0) { - /* - * Note that "%d node of %d in tree" can report things like - * "flush_deletions: 59 nodes of 41 in tree". This means - * That some nodes appear on the deletions list more than - * once. Only the last occurrence will actually be deleted. - */ - isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE, - DNS_LOGMODULE_CACHE, ISC_LOG_DEBUG(1), - "flush_deletions: %d nodes of %d in tree", - rbtdbiter->delcnt, - dns_rbt_nodecount(rbtdb->tree)); - - if (rbtdbiter->tree_locked == isc_rwlocktype_read) { - RWUNLOCK(&rbtdb->tree_lock, isc_rwlocktype_read); - was_read_locked = true; - } - RWLOCK(&rbtdb->tree_lock, isc_rwlocktype_write); - rbtdbiter->tree_locked = isc_rwlocktype_write; - - for (i = 0; i < rbtdbiter->delcnt; i++) { - node = rbtdbiter->deletions[i]; - lock = &rbtdb->node_locks[node->locknum].lock; - - NODE_LOCK(lock, isc_rwlocktype_read); - decrement_reference(rbtdb, node, 0, isc_rwlocktype_read, - rbtdbiter->tree_locked, false); - NODE_UNLOCK(lock, isc_rwlocktype_read); - } - - rbtdbiter->delcnt = 0; - - RWUNLOCK(&rbtdb->tree_lock, isc_rwlocktype_write); - if (was_read_locked) { - RWLOCK(&rbtdb->tree_lock, isc_rwlocktype_read); - rbtdbiter->tree_locked = isc_rwlocktype_read; - } else { - rbtdbiter->tree_locked = isc_rwlocktype_none; - } + if (rbtdbiter->delcnt == 0) { + return; } + + /* + * Note that "%d node of %d in tree" can report things like + * "flush_deletions: 59 nodes of 41 in tree". This means + * That some nodes appear on the deletions list more than + * once. Only the last occurrence will actually be deleted. + */ + isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE, DNS_LOGMODULE_CACHE, + ISC_LOG_DEBUG(1), + "flush_deletions: %d nodes of %d in tree", + rbtdbiter->delcnt, dns_rbt_nodecount(rbtdb->tree)); + + if (rbtdbiter->tree_locked == isc_rwlocktype_read) { + RWUNLOCK(&rbtdb->tree_lock, tlocktype); + rbtdbiter->tree_locked = isc_rwlocktype_none; + } + INSIST(rbtdbiter->tree_locked == isc_rwlocktype_none); + + rbtdbiter->tree_locked = isc_rwlocktype_write; + RWLOCK(&rbtdb->tree_lock, rbtdbiter->tree_locked); + + for (size_t i = 0; i < (size_t)rbtdbiter->delcnt; i++) { + isc_rwlocktype_t nlocktype = isc_rwlocktype_read; + dns_rbtnode_t *node = rbtdbiter->deletions[i]; + nodelock_t *lock = &rbtdb->node_locks[node->locknum].lock; + + NODE_LOCK(lock, nlocktype); + decrement_reference(rbtdb, node, 0, &nlocktype, + &rbtdbiter->tree_locked, false); + NODE_UNLOCK(lock, nlocktype); + } + + rbtdbiter->delcnt = 0; + + RWUNLOCK(&rbtdb->tree_lock, rbtdbiter->tree_locked); + rbtdbiter->tree_locked = isc_rwlocktype_none; + if (tlocktype == isc_rwlocktype_read) { + RWLOCK(&rbtdb->tree_lock, tlocktype); + rbtdbiter->tree_locked = tlocktype; + } + INSIST(rbtdbiter->tree_locked == tlocktype); } static void @@ -8900,9 +8917,8 @@ dbiterator_destroy(dns_dbiterator_t **iteratorp) { if (rbtdbiter->tree_locked == isc_rwlocktype_read) { RWUNLOCK(&rbtdb->tree_lock, isc_rwlocktype_read); rbtdbiter->tree_locked = isc_rwlocktype_none; - } else { - INSIST(rbtdbiter->tree_locked == isc_rwlocktype_none); } + INSIST(rbtdbiter->tree_locked == isc_rwlocktype_none); dereference_iter_node(rbtdbiter); @@ -9290,11 +9306,11 @@ dbiterator_pause(dns_dbiterator_t *iterator) { rbtdbiter->paused = true; - if (rbtdbiter->tree_locked != isc_rwlocktype_none) { - INSIST(rbtdbiter->tree_locked == isc_rwlocktype_read); + if (rbtdbiter->tree_locked == isc_rwlocktype_read) { RWUNLOCK(&rbtdb->tree_lock, isc_rwlocktype_read); rbtdbiter->tree_locked = isc_rwlocktype_none; } + INSIST(rbtdbiter->tree_locked == isc_rwlocktype_none); flush_deletions(rbtdbiter); @@ -9999,7 +10015,7 @@ update_header(dns_rbtdb_t *rbtdb, rdatasetheader_t *header, isc_stdtime_t now) { */ static void overmem_purge(dns_rbtdb_t *rbtdb, unsigned int locknum_start, isc_stdtime_t now, - bool tree_locked) { + isc_rwlocktype_t *tlocktypep) { rdatasetheader_t *header, *header_prev; unsigned int locknum; int purgecount = 2; @@ -10013,7 +10029,7 @@ overmem_purge(dns_rbtdb_t *rbtdb, unsigned int locknum_start, isc_stdtime_t now, header = isc_heap_element(rbtdb->heaps[locknum], 1); if (header && header->rdh_ttl < now - RBTDB_VIRTUAL) { - expire_header(rbtdb, header, tree_locked, expire_ttl); + expire_header(rbtdb, header, tlocktypep, expire_ttl); purgecount--; } @@ -10030,7 +10046,7 @@ overmem_purge(dns_rbtdb_t *rbtdb, unsigned int locknum_start, isc_stdtime_t now, */ ISC_LIST_UNLINK(rbtdb->rdatasets[locknum], header, link); - expire_header(rbtdb, header, tree_locked, expire_lru); + expire_header(rbtdb, header, tlocktypep, expire_lru); purgecount--; } @@ -10040,8 +10056,8 @@ overmem_purge(dns_rbtdb_t *rbtdb, unsigned int locknum_start, isc_stdtime_t now, } static void -expire_header(dns_rbtdb_t *rbtdb, rdatasetheader_t *header, bool tree_locked, - expire_t reason) { +expire_header(dns_rbtdb_t *rbtdb, rdatasetheader_t *header, + isc_rwlocktype_t *tlocktypep, expire_t reason) { set_ttl(rbtdb, header, 0); mark_header_ancient(rbtdb, header); @@ -10050,17 +10066,15 @@ expire_header(dns_rbtdb_t *rbtdb, rdatasetheader_t *header, bool tree_locked, */ if (isc_refcount_current(&header->node->references) == 0) { + isc_rwlocktype_t nlocktype = isc_rwlocktype_write; /* * If no one else is using the node, we can clean it up now. * We first need to gain a new reference to the node to meet a * requirement of decrement_reference(). */ - new_reference(rbtdb, header->node, isc_rwlocktype_write); - decrement_reference(rbtdb, header->node, 0, - isc_rwlocktype_write, - tree_locked ? isc_rwlocktype_write - : isc_rwlocktype_none, - false); + new_reference(rbtdb, header->node, nlocktype); + decrement_reference(rbtdb, header->node, 0, &nlocktype, + tlocktypep, false); if (rbtdb->cachestats == NULL) { return; From e5f7fe1f654f30bc439e8297bfe10a169643dc3f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Sur=C3=BD?= Date: Fri, 14 Oct 2022 14:35:44 +0200 Subject: [PATCH 2/2] Add strong rwlock consistency checks to dns_rbtdb The dns_rbtdb unit already tracks the state of the node and tree rwlocks during the top level function and passes the states of the locks to the called functions. Add the tree locking family of macros modeled after node locking macros, and expand both to track the state of the lock in an external variable. Additionally, in developer mode, add precondition to the macros, so the lock is in required state - this should cause an assertion failure on double locking instead of the thread getting stuck. --- configure.ac | 2 +- lib/dns/rbtdb.c | 740 ++++++++++++++++++++++++++++-------------------- 2 files changed, 430 insertions(+), 312 deletions(-) diff --git a/configure.ac b/configure.ac index 2f36c47adc..e3cbb6a396 100644 --- a/configure.ac +++ b/configure.ac @@ -166,7 +166,7 @@ AC_ARG_ENABLE([developer], AS_IF([test "$enable_developer" = "yes"], [DEVELOPER_MODE=yes - STD_CPPFLAGS="$STD_CPPFLAGS -DISC_MEM_DEFAULTFILL=1 -DISC_MEM_TRACKLINES=1 -DISC_LIST_CHECKINIT=1 -DISC_STATS_CHECKUNDERFLOW=1" + STD_CPPFLAGS="$STD_CPPFLAGS -DISC_MEM_DEFAULTFILL=1 -DISC_MEM_TRACKLINES=1 -DISC_LIST_CHECKINIT=1 -DISC_STATS_CHECKUNDERFLOW=1 -DDNS_RBTDB_STRONG_RWLOCK_CHECK=1" test "${enable_fixed_rrset+set}" = set || enable_fixed_rrset=yes test "${enable_querytrace+set}" = set || enable_querytrace=yes test "${with_cmocka+set}" = set || with_cmocka=yes diff --git a/lib/dns/rbtdb.c b/lib/dns/rbtdb.c index 5d9473c17b..f446b822e9 100644 --- a/lib/dns/rbtdb.c +++ b/lib/dns/rbtdb.c @@ -110,20 +110,165 @@ typedef uint32_t rbtdb_rdatatype_t; #define RBTDB_LOCK(l, t) RWLOCK((l), (t)) #define RBTDB_UNLOCK(l, t) RWUNLOCK((l), (t)) -/* - * Since node locking is sensitive to both performance and memory footprint, - * we need some trick here. If we have both high-performance rwlock and - * high performance and small-memory reference counters, we use rwlock for - * node lock and isc_refcount for node references. In this case, we don't have - * to protect the access to the counters by locks. - */ typedef isc_rwlock_t nodelock_t; +#ifdef DNS_RBTDB_STRONG_RWLOCK_CHECK + #define NODE_INITLOCK(l) isc_rwlock_init((l), 0, 0) #define NODE_DESTROYLOCK(l) isc_rwlock_destroy(l) -#define NODE_LOCK(l, t) RWLOCK((l), (t)) -#define NODE_UNLOCK(l, t) RWUNLOCK((l), (t)) -#define NODE_TRYUPGRADE(l) isc_rwlock_tryupgrade(l) +#define NODE_LOCK(l, t, tp) \ + { \ + REQUIRE(*tp == isc_rwlocktype_none); \ + RWLOCK((l), (t)); \ + *tp = t; \ + } +#define NODE_RDLOCK(l, tp) NODE_LOCK(l, isc_rwlocktype_read, tp); +#define NODE_WRLOCK(l, tp) NODE_LOCK(l, isc_rwlocktype_write, tp); + +#define NODE_UNLOCK(l, tp) \ + { \ + REQUIRE(*tp != isc_rwlocktype_none); \ + RWUNLOCK(l, *tp); \ + *tp = isc_rwlocktype_none; \ + } +#define NODE_TRYLOCK(l, t, tp) \ + ({ \ + REQUIRE(*tp == isc_rwlocktype_none); \ + isc_result_t _result = isc_rwlock_trylock(l, t); \ + if (_result == ISC_R_SUCCESS) { \ + *tp = t; \ + }; \ + _result; \ + }) +#define NODE_TRYRDLOCK(l, tp) NODE_TRYLOCK(l, isc_rwlocktype_read, tp) +#define NODE_TRYWRLOCK(l, tp) NODE_TRYLOCK(l, isc_rwlocktype_write, tp) +#define NODE_TRYUPGRADE(l, tp) \ + ({ \ + REQUIRE(*tp == isc_rwlocktype_read); \ + isc_result_t _result = isc_rwlock_tryupgrade(l); \ + if (_result == ISC_R_SUCCESS) { \ + *tp = isc_rwlocktype_write; \ + }; \ + _result; \ + }) + +typedef isc_rwlock_t treelock_t; + +#define TREE_INITLOCK(l) isc_rwlock_init(l, 0, 0) +#define TREE_DESTROYLOCK(l) isc_rwlock_destroy(l) +#define TREE_LOCK(l, t, tp) \ + { \ + REQUIRE(*tp == isc_rwlocktype_none); \ + RWLOCK(l, t); \ + *tp = t; \ + } +#define TREE_RDLOCK(l, tp) TREE_LOCK(l, isc_rwlocktype_read, tp); +#define TREE_WRLOCK(l, tp) TREE_LOCK(l, isc_rwlocktype_write, tp); +#define TREE_UNLOCK(l, tp) \ + { \ + REQUIRE(*tp != isc_rwlocktype_none); \ + RWUNLOCK(l, *tp); \ + *tp = isc_rwlocktype_none; \ + } +#define TREE_TRYLOCK(l, t, tp) \ + ({ \ + REQUIRE(*tp == isc_rwlocktype_none); \ + isc_result_t _result = isc_rwlock_trylock(l, t); \ + if (_result == ISC_R_SUCCESS) { \ + *tp = t; \ + }; \ + _result; \ + }) +#define TREE_TRYRDLOCK(l, tp) TREE_TRYLOCK(l, isc_rwlocktype_read, tp) +#define TREE_TRYWRLOCK(l, tp) TREE_TRYLOCK(l, isc_rwlocktype_write, tp) +#define TREE_TRYUPGRADE(l, tp) \ + ({ \ + REQUIRE(*tp == isc_rwlocktype_read); \ + isc_result_t _result = isc_rwlock_tryupgrade(l); \ + if (_result == ISC_R_SUCCESS) { \ + *tp = isc_rwlocktype_write; \ + }; \ + _result; \ + }) + +#else /* DNS_RBTDB_STRONG_RWLOCK_CHECK */ + +#define NODE_INITLOCK(l) isc_rwlock_init((l), 0, 0) +#define NODE_DESTROYLOCK(l) isc_rwlock_destroy(l) +#define NODE_LOCK(l, t, tp) \ + { \ + RWLOCK((l), (t)); \ + *tp = t; \ + } +#define NODE_RDLOCK(l, tp) NODE_LOCK(l, isc_rwlocktype_read, tp); +#define NODE_WRLOCK(l, tp) NODE_LOCK(l, isc_rwlocktype_write, tp); + +#define NODE_UNLOCK(l, tp) \ + { \ + RWUNLOCK(l, *tp); \ + *tp = isc_rwlocktype_none; \ + } +#define NODE_TRYLOCK(l, t, tp) \ + ({ \ + isc_result_t _result = isc_rwlock_trylock(l, t); \ + if (_result == ISC_R_SUCCESS) { \ + *tp = t; \ + }; \ + _result; \ + }) +#define NODE_TRYRDLOCK(l, tp) NODE_TRYLOCK(l, isc_rwlocktype_read, tp) +#define NODE_TRYWRLOCK(l, tp) NODE_TRYLOCK(l, isc_rwlocktype_write, tp) +#define NODE_TRYUPGRADE(l, tp) \ + ({ \ + isc_result_t _result = isc_rwlock_tryupgrade(l); \ + if (_result == ISC_R_SUCCESS) { \ + *tp = isc_rwlocktype_write; \ + }; \ + _result; \ + }) + +typedef isc_rwlock_t treelock_t; + +#define TREE_INITLOCK(l) isc_rwlock_init(l, 0, 0) +#define TREE_DESTROYLOCK(l) isc_rwlock_destroy(l) +#define TREE_LOCK(l, t, tp) \ + { \ + RWLOCK(l, t); \ + *tp = t; \ + } +#define TREE_RDLOCK(l, tp) \ + { \ + TREE_LOCK(l, isc_rwlocktype_read, tp); \ + } +#define TREE_WRLOCK(l, tp) \ + { \ + TREE_LOCK(l, isc_rwlocktype_write, tp); \ + } +#define TREE_UNLOCK(l, tp) \ + { \ + RWUNLOCK(l, *tp); \ + *tp = isc_rwlocktype_none; \ + } +#define TREE_TRYLOCK(l, t, tp) \ + ({ \ + isc_result_t _result = isc_rwlock_trylock(l, t); \ + if (_result == ISC_R_SUCCESS) { \ + *tp = t; \ + }; \ + _result; \ + }) +#define TREE_TRYRDLOCK(l, tp) TREE_TRYLOCK(l, isc_rwlocktype_read, tp) +#define TREE_TRYWRLOCK(l, tp) TREE_TRYLOCK(l, isc_rwlocktype_write, tp) +#define TREE_TRYUPGRADE(l, tp) \ + ({ \ + isc_result_t _result = isc_rwlock_tryupgrade(l); \ + if (_result == ISC_R_SUCCESS) { \ + *tp = isc_rwlocktype_write; \ + }; \ + _result; \ + }) + +#endif /*% * Whether to rate-limit updating the LRU to avoid possible thread contention. @@ -403,7 +548,7 @@ struct dns_rbtdb { /* Locks the data in this struct */ isc_rwlock_t lock; /* Locks the tree structure (prevents nodes appearing/disappearing) */ - isc_rwlock_t tree_lock; + treelock_t tree_lock; /* Locks for individual tree nodes */ unsigned int node_lock_count; rbtdb_nodelock_t *node_locks; @@ -1106,7 +1251,7 @@ free_rbtdb(dns_rbtdb_t *rbtdb, bool log, isc_event_t *event) { isc_mem_put(rbtdb->common.mctx, rbtdb->node_locks, rbtdb->node_lock_count * sizeof(rbtdb_nodelock_t)); - isc_rwlock_destroy(&rbtdb->tree_lock); + TREE_DESTROYLOCK(&rbtdb->tree_lock); isc_refcount_destroy(&rbtdb->references); if (rbtdb->task != NULL) { isc_task_detach(&rbtdb->task); @@ -1158,13 +1303,14 @@ maybe_free_rbtdb(dns_rbtdb_t *rbtdb) { * may be nodes in use. */ for (i = 0; i < rbtdb->node_lock_count; i++) { - NODE_LOCK(&rbtdb->node_locks[i].lock, isc_rwlocktype_write); + isc_rwlocktype_t nodelock = isc_rwlocktype_none; + NODE_WRLOCK(&rbtdb->node_locks[i].lock, &nodelock); rbtdb->node_locks[i].exiting = true; if (isc_refcount_current(&rbtdb->node_locks[i].references) == 0) { inactive++; } - NODE_UNLOCK(&rbtdb->node_locks[i].lock, isc_rwlocktype_write); + NODE_UNLOCK(&rbtdb->node_locks[i].lock, &nodelock); } if (inactive != 0) { @@ -1882,13 +2028,13 @@ cleanup_dead_nodes(dns_rbtdb_t *rbtdb, int bucketnum) { static void reactivate_node(dns_rbtdb_t *rbtdb, dns_rbtnode_t *node, isc_rwlocktype_t tlocktype) { - isc_rwlocktype_t nlocktype = isc_rwlocktype_read; + isc_rwlocktype_t nlocktype = isc_rwlocktype_none; nodelock_t *nodelock = &rbtdb->node_locks[node->locknum].lock; bool maybe_cleanup = false; POST(nlocktype); - NODE_LOCK(nodelock, nlocktype); + NODE_RDLOCK(nodelock, &nlocktype); /* * Check if we can possibly cleanup the dead node. If so, upgrade @@ -1904,10 +2050,11 @@ reactivate_node(dns_rbtdb_t *rbtdb, dns_rbtnode_t *node, /* * Upgrade the lock and test if we still need to unlink. */ - NODE_UNLOCK(nodelock, nlocktype); - nlocktype = isc_rwlocktype_write; + if (NODE_TRYUPGRADE(nodelock, &nlocktype) != ISC_R_SUCCESS) { + NODE_UNLOCK(nodelock, &nlocktype); + NODE_WRLOCK(nodelock, &nlocktype); + } POST(nlocktype); - NODE_LOCK(nodelock, nlocktype); if (ISC_LINK_LINKED(node, deadlink)) { ISC_LIST_UNLINK(rbtdb->deadnodes[node->locknum], node, deadlink); @@ -1919,7 +2066,7 @@ reactivate_node(dns_rbtdb_t *rbtdb, dns_rbtnode_t *node, new_reference(rbtdb, node, nlocktype); - NODE_UNLOCK(nodelock, nlocktype); + NODE_UNLOCK(nodelock, &nlocktype); } /* @@ -1938,17 +2085,17 @@ reactivate_node(dns_rbtdb_t *rbtdb, dns_rbtnode_t *node, */ static bool decrement_reference(dns_rbtdb_t *rbtdb, dns_rbtnode_t *node, - rbtdb_serial_t least_serial, isc_rwlocktype_t *nlocktype, - isc_rwlocktype_t *tlocktype, bool pruning) { + rbtdb_serial_t least_serial, isc_rwlocktype_t *nlocktypep, + isc_rwlocktype_t *tlocktypep, bool pruning) { isc_result_t result; - bool locked = *tlocktype != isc_rwlocktype_none; + bool locked = *tlocktypep != isc_rwlocktype_none; bool write_locked = false; rbtdb_nodelock_t *nodelock; int bucket = node->locknum; bool no_reference = true; uint_fast32_t refs; - REQUIRE(*nlocktype != isc_rwlocktype_none); + REQUIRE(*nlocktypep != isc_rwlocktype_none); nodelock = &rbtdb->node_locks[bucket]; @@ -1968,10 +2115,12 @@ decrement_reference(dns_rbtdb_t *rbtdb, dns_rbtnode_t *node, } /* Upgrade the lock? */ - if (*nlocktype == isc_rwlocktype_read) { - NODE_UNLOCK(&nodelock->lock, *nlocktype); - *nlocktype = isc_rwlocktype_write; - NODE_LOCK(&nodelock->lock, *nlocktype); + if (*nlocktypep == isc_rwlocktype_read) { + if (NODE_TRYUPGRADE(&nodelock->lock, nlocktypep) != + ISC_R_SUCCESS) { + NODE_UNLOCK(&nodelock->lock, nlocktypep); + NODE_WRLOCK(&nodelock->lock, nlocktypep); + } } if (isc_refcount_decrement(&node->references) > 1) { @@ -2004,16 +2153,15 @@ decrement_reference(dns_rbtdb_t *rbtdb, dns_rbtnode_t *node, * the node lock before acquiring the tree write lock because * we only do a trylock. */ - switch (*tlocktype) { + switch (*tlocktypep) { case isc_rwlocktype_write: result = ISC_R_SUCCESS; break; case isc_rwlocktype_read: - result = isc_rwlock_tryupgrade(&rbtdb->tree_lock); + result = TREE_TRYUPGRADE(&rbtdb->tree_lock, tlocktypep); break; case isc_rwlocktype_none: - result = isc_rwlock_trylock(&rbtdb->tree_lock, - isc_rwlocktype_write); + result = TREE_TRYWRLOCK(&rbtdb->tree_lock, tlocktypep); break; default: UNREACHABLE(); @@ -2021,7 +2169,6 @@ decrement_reference(dns_rbtdb_t *rbtdb, dns_rbtnode_t *node, RUNTIME_CHECK(result == ISC_R_SUCCESS || result == ISC_R_LOCKBUSY); if (result == ISC_R_SUCCESS) { write_locked = true; - *tlocktype = isc_rwlocktype_write; } refs = isc_refcount_decrement(&nodelock->references); @@ -2073,8 +2220,7 @@ restore_locks: * Relock a read lock, or unlock the write lock if no lock was held. */ if (!locked && write_locked) { - RWUNLOCK(&rbtdb->tree_lock, *tlocktype); - *tlocktype = isc_rwlocktype_none; + TREE_UNLOCK(&rbtdb->tree_lock, tlocktypep); } return (no_reference); @@ -2093,16 +2239,16 @@ prune_tree(isc_task_t *task, isc_event_t *event) { dns_rbtnode_t *node = event->ev_arg; dns_rbtnode_t *parent; unsigned int locknum; - isc_rwlocktype_t tlocktype = isc_rwlocktype_write; - isc_rwlocktype_t nlocktype = isc_rwlocktype_write; + isc_rwlocktype_t tlocktype = isc_rwlocktype_none; + isc_rwlocktype_t nlocktype = isc_rwlocktype_none; UNUSED(task); isc_event_free(&event); - RWLOCK(&rbtdb->tree_lock, tlocktype); + TREE_WRLOCK(&rbtdb->tree_lock, &tlocktype); locknum = node->locknum; - NODE_LOCK(&rbtdb->node_locks[locknum].lock, nlocktype); + NODE_WRLOCK(&rbtdb->node_locks[locknum].lock, &nlocktype); do { parent = node->parent; decrement_reference(rbtdb, node, 0, &nlocktype, &tlocktype, @@ -2117,10 +2263,10 @@ prune_tree(isc_task_t *task, isc_event_t *event) { */ if (parent->locknum != locknum) { NODE_UNLOCK(&rbtdb->node_locks[locknum].lock, - nlocktype); + &nlocktype); locknum = parent->locknum; - NODE_LOCK(&rbtdb->node_locks[locknum].lock, - nlocktype); + NODE_WRLOCK(&rbtdb->node_locks[locknum].lock, + &nlocktype); } /* @@ -2138,7 +2284,7 @@ prune_tree(isc_task_t *task, isc_event_t *event) { node = parent; } while (node != NULL); - NODE_UNLOCK(&rbtdb->node_locks[locknum].lock, nlocktype); + NODE_UNLOCK(&rbtdb->node_locks[locknum].lock, &nlocktype); RWUNLOCK(&rbtdb->tree_lock, tlocktype); detach((dns_db_t **)&rbtdb); @@ -2254,12 +2400,13 @@ setnsec3parameters(dns_db_t *db, rbtdb_version_t *version) { unsigned char *raw; /* RDATASLAB */ unsigned int count, length; dns_rbtdb_t *rbtdb = (dns_rbtdb_t *)db; + isc_rwlocktype_t tlocktype = isc_rwlocktype_none; + isc_rwlocktype_t nlocktype = isc_rwlocktype_none; - RWLOCK(&rbtdb->tree_lock, isc_rwlocktype_read); + TREE_RDLOCK(&rbtdb->tree_lock, &tlocktype); version->havensec3 = false; node = rbtdb->origin_node; - NODE_LOCK(&(rbtdb->node_locks[node->locknum].lock), - isc_rwlocktype_read); + NODE_RDLOCK(&(rbtdb->node_locks[node->locknum].lock), &nlocktype); for (header = node->data; header != NULL; header = header_next) { header_next = header->next; do { @@ -2324,9 +2471,8 @@ setnsec3parameters(dns_db_t *db, rbtdb_version_t *version) { } } unlock: - NODE_UNLOCK(&(rbtdb->node_locks[node->locknum].lock), - isc_rwlocktype_read); - RWUNLOCK(&rbtdb->tree_lock, isc_rwlocktype_read); + NODE_UNLOCK(&(rbtdb->node_locks[node->locknum].lock), &nlocktype); + TREE_UNLOCK(&rbtdb->tree_lock, &tlocktype); } static void @@ -2334,19 +2480,19 @@ cleanup_dead_nodes_callback(isc_task_t *task, isc_event_t *event) { dns_rbtdb_t *rbtdb = event->ev_arg; bool again = false; unsigned int locknum; + isc_rwlocktype_t tlocktype = isc_rwlocktype_none; + isc_rwlocktype_t nlocktype = isc_rwlocktype_none; - RWLOCK(&rbtdb->tree_lock, isc_rwlocktype_write); + TREE_WRLOCK(&rbtdb->tree_lock, &tlocktype); for (locknum = 0; locknum < rbtdb->node_lock_count; locknum++) { - NODE_LOCK(&rbtdb->node_locks[locknum].lock, - isc_rwlocktype_write); + NODE_WRLOCK(&rbtdb->node_locks[locknum].lock, &nlocktype); cleanup_dead_nodes(rbtdb, locknum); if (ISC_LIST_HEAD(rbtdb->deadnodes[locknum]) != NULL) { again = true; } - NODE_UNLOCK(&rbtdb->node_locks[locknum].lock, - isc_rwlocktype_write); + NODE_UNLOCK(&rbtdb->node_locks[locknum].lock, &nlocktype); } - RWUNLOCK(&rbtdb->tree_lock, isc_rwlocktype_write); + TREE_UNLOCK(&rbtdb->tree_lock, &tlocktype); if (again) { isc_task_send(task, &event); } else { @@ -2549,18 +2695,18 @@ closeversion(dns_db_t *db, dns_dbversion_t **versionp, bool commit) { header = HEAD(resigned_list)) { nodelock_t *lock; isc_rwlocktype_t tlocktype = isc_rwlocktype_none; - isc_rwlocktype_t nlocktype = isc_rwlocktype_write; + isc_rwlocktype_t nlocktype = isc_rwlocktype_none; ISC_LIST_UNLINK(resigned_list, header, link); lock = &rbtdb->node_locks[header->node->locknum].lock; - NODE_LOCK(lock, nlocktype); + NODE_WRLOCK(lock, &nlocktype); if (rollback && !IGNORE(header)) { resign_insert(rbtdb, header->node->locknum, header); } decrement_reference(rbtdb, header->node, least_serial, &nlocktype, &tlocktype, false); - NODE_UNLOCK(lock, nlocktype); + NODE_UNLOCK(lock, &nlocktype); INSIST(tlocktype == isc_rwlocktype_none); } @@ -2584,20 +2730,19 @@ closeversion(dns_db_t *db, dns_dbversion_t **versionp, bool commit) { * expensive, but this event should be rare enough * to justify the cost. */ - tlocktype = isc_rwlocktype_write; - RWLOCK(&rbtdb->tree_lock, tlocktype); + TREE_WRLOCK(&rbtdb->tree_lock, &tlocktype); } for (changed = HEAD(cleanup_list); changed != NULL; changed = next_changed) { nodelock_t *lock; - isc_rwlocktype_t nlocktype = isc_rwlocktype_write; + isc_rwlocktype_t nlocktype = isc_rwlocktype_none; next_changed = NEXT(changed, link); rbtnode = changed->node; lock = &rbtdb->node_locks[rbtnode->locknum].lock; - NODE_LOCK(lock, nlocktype); + NODE_WRLOCK(lock, &nlocktype); /* * This is a good opportunity to purge any dead nodes, * so use it. @@ -2612,7 +2757,7 @@ closeversion(dns_db_t *db, dns_dbversion_t **versionp, bool commit) { decrement_reference(rbtdb, rbtnode, least_serial, &nlocktype, &tlocktype, false); - NODE_UNLOCK(lock, nlocktype); + NODE_UNLOCK(lock, &nlocktype); isc_mem_put(rbtdb->common.mctx, changed, sizeof(*changed)); @@ -2621,8 +2766,7 @@ closeversion(dns_db_t *db, dns_dbversion_t **versionp, bool commit) { isc_refcount_increment(&rbtdb->references); isc_task_send(rbtdb->task, &event); } else { - RWUNLOCK(&rbtdb->tree_lock, tlocktype); - tlocktype = isc_rwlocktype_none; + TREE_UNLOCK(&rbtdb->tree_lock, &tlocktype); } INSIST(tlocktype == isc_rwlocktype_none); @@ -2714,12 +2858,12 @@ findnodeintree(dns_rbtdb_t *rbtdb, dns_rbt_t *tree, const dns_name_t *name, dns_rbtnode_t *node = NULL; dns_name_t nodename; isc_result_t result; - isc_rwlocktype_t tlocktype = isc_rwlocktype_read; + isc_rwlocktype_t tlocktype = isc_rwlocktype_none; INSIST(tree == rbtdb->tree || tree == rbtdb->nsec3); dns_name_init(&nodename, NULL); - RWLOCK(&rbtdb->tree_lock, tlocktype); + TREE_RDLOCK(&rbtdb->tree_lock, &tlocktype); result = dns_rbt_findnode(tree, name, NULL, &node, NULL, DNS_RBTFIND_EMPTYDATA, NULL, NULL); if (result != ISC_R_SUCCESS) { @@ -2730,12 +2874,13 @@ findnodeintree(dns_rbtdb_t *rbtdb, dns_rbt_t *tree, const dns_name_t *name, goto unlock; } /* - * It would be nice to try to upgrade the lock instead of - * unlocking then relocking. + * Try to upgrade the lock and if that fails unlock then relock. */ - RWUNLOCK(&rbtdb->tree_lock, tlocktype); - tlocktype = isc_rwlocktype_write; - RWLOCK(&rbtdb->tree_lock, tlocktype); + if (TREE_TRYUPGRADE(&rbtdb->tree_lock, &tlocktype) != + ISC_R_SUCCESS) { + TREE_UNLOCK(&rbtdb->tree_lock, &tlocktype); + TREE_WRLOCK(&rbtdb->tree_lock, &tlocktype); + } node = NULL; result = dns_rbt_addnode(tree, name, &node); if (result == ISC_R_SUCCESS) { @@ -2769,7 +2914,7 @@ findnodeintree(dns_rbtdb_t *rbtdb, dns_rbt_t *tree, const dns_name_t *name, *nodep = (dns_dbnode_t *)node; unlock: - RWUNLOCK(&rbtdb->tree_lock, tlocktype); + TREE_UNLOCK(&rbtdb->tree_lock, &tlocktype); return (result); } @@ -2802,6 +2947,7 @@ zone_zonecut_callback(dns_rbtnode_t *node, dns_name_t *name, void *arg) { rdatasetheader_t *found; isc_result_t result; dns_rbtnode_t *onode; + isc_rwlocktype_t nlocktype = isc_rwlocktype_none; /* * We only want to remember the topmost zone cut, since it's the one @@ -2816,8 +2962,8 @@ zone_zonecut_callback(dns_rbtnode_t *node, dns_name_t *name, void *arg) { result = DNS_R_CONTINUE; onode = search->rbtdb->origin_node; - NODE_LOCK(&(search->rbtdb->node_locks[node->locknum].lock), - isc_rwlocktype_read); + NODE_RDLOCK(&(search->rbtdb->node_locks[node->locknum].lock), + &nlocktype); /* * Look for an NS or DNAME rdataset active in our version. @@ -2937,7 +3083,7 @@ zone_zonecut_callback(dns_rbtnode_t *node, dns_name_t *name, void *arg) { } NODE_UNLOCK(&(search->rbtdb->node_locks[node->locknum].lock), - isc_rwlocktype_read); + &nlocktype); return (result); } @@ -3105,8 +3251,9 @@ setup_delegation(rbtdb_search_t *search, dns_dbnode_t **nodep, search->need_cleanup = false; } if (rdataset != NULL) { - NODE_LOCK(&(search->rbtdb->node_locks[node->locknum].lock), - isc_rwlocktype_read); + isc_rwlocktype_t nlocktype = isc_rwlocktype_none; + NODE_RDLOCK(&(search->rbtdb->node_locks[node->locknum].lock), + &nlocktype); bind_rdataset(search->rbtdb, node, search->zonecut_rdataset, search->now, isc_rwlocktype_read, rdataset); if (sigrdataset != NULL && search->zonecut_sigrdataset != NULL) @@ -3116,7 +3263,7 @@ setup_delegation(rbtdb_search_t *search, dns_dbnode_t **nodep, isc_rwlocktype_read, sigrdataset); } NODE_UNLOCK(&(search->rbtdb->node_locks[node->locknum].lock), - isc_rwlocktype_read); + &nlocktype); } if (type == dns_rdatatype_dname) { @@ -3203,14 +3350,15 @@ activeempty(rbtdb_search_t *search, dns_rbtnodechain_t *chain, result = dns_rbtnodechain_next(chain, NULL, NULL); while (result == ISC_R_SUCCESS || result == DNS_R_NEWORIGIN) { + isc_rwlocktype_t nlocktype = isc_rwlocktype_none; node = NULL; result = dns_rbtnodechain_current(chain, &prefix, origin, &node); if (result != ISC_R_SUCCESS) { break; } - NODE_LOCK(&(rbtdb->node_locks[node->locknum].lock), - isc_rwlocktype_read); + NODE_RDLOCK(&(rbtdb->node_locks[node->locknum].lock), + &nlocktype); for (header = node->data; header != NULL; header = header->next) { if (header->serial <= search->serial && @@ -3219,7 +3367,7 @@ activeempty(rbtdb_search_t *search, dns_rbtnodechain_t *chain, } } NODE_UNLOCK(&(rbtdb->node_locks[node->locknum].lock), - isc_rwlocktype_read); + &nlocktype); if (header != NULL) { break; } @@ -3272,13 +3420,14 @@ activeemptynode(rbtdb_search_t *search, const dns_name_t *qname, chain = search->chain; do { + isc_rwlocktype_t nlocktype = isc_rwlocktype_none; node = NULL; result = dns_rbtnodechain_current(&chain, &name, origin, &node); if (result != ISC_R_SUCCESS) { break; } - NODE_LOCK(&(rbtdb->node_locks[node->locknum].lock), - isc_rwlocktype_read); + NODE_RDLOCK(&(rbtdb->node_locks[node->locknum].lock), + &nlocktype); for (header = node->data; header != NULL; header = header->next) { if (header->serial <= search->serial && @@ -3287,7 +3436,7 @@ activeemptynode(rbtdb_search_t *search, const dns_name_t *qname, } } NODE_UNLOCK(&(rbtdb->node_locks[node->locknum].lock), - isc_rwlocktype_read); + &nlocktype); if (header != NULL) { break; } @@ -3302,13 +3451,14 @@ activeemptynode(rbtdb_search_t *search, const dns_name_t *qname, result = dns_rbtnodechain_next(&chain, NULL, NULL); while (result == ISC_R_SUCCESS || result == DNS_R_NEWORIGIN) { + isc_rwlocktype_t nlocktype = isc_rwlocktype_none; node = NULL; result = dns_rbtnodechain_current(&chain, &name, origin, &node); if (result != ISC_R_SUCCESS) { break; } - NODE_LOCK(&(rbtdb->node_locks[node->locknum].lock), - isc_rwlocktype_read); + NODE_RDLOCK(&(rbtdb->node_locks[node->locknum].lock), + &nlocktype); for (header = node->data; header != NULL; header = header->next) { if (header->serial <= search->serial && @@ -3317,7 +3467,7 @@ activeemptynode(rbtdb_search_t *search, const dns_name_t *qname, } } NODE_UNLOCK(&(rbtdb->node_locks[node->locknum].lock), - isc_rwlocktype_read); + &nlocktype); if (header != NULL) { break; } @@ -3388,8 +3538,9 @@ find_wildcard(rbtdb_search_t *search, dns_rbtnode_t **nodep, done = false; node = *nodep; do { - NODE_LOCK(&(rbtdb->node_locks[node->locknum].lock), - isc_rwlocktype_read); + nodelock_t *lock = &rbtdb->node_locks[node->locknum].lock; + isc_rwlocktype_t nlocktype = isc_rwlocktype_none; + NODE_RDLOCK(lock, &nlocktype); /* * First we try to figure out if this node is active in @@ -3418,8 +3569,7 @@ find_wildcard(rbtdb_search_t *search, dns_rbtnode_t **nodep, wild = false; } - NODE_UNLOCK(&(rbtdb->node_locks[node->locknum].lock), - isc_rwlocktype_read); + NODE_UNLOCK(lock, &nlocktype); if (wild) { /* @@ -3449,15 +3599,13 @@ find_wildcard(rbtdb_search_t *search, dns_rbtnode_t **nodep, rbtdb->tree, wname, NULL, &wnode, &wchain, DNS_RBTFIND_EMPTYDATA, NULL, NULL); if (result == ISC_R_SUCCESS) { - nodelock_t *lock; - /* * We have found the wildcard node. If it * is active in the search's version, we're * done. */ lock = &rbtdb->node_locks[wnode->locknum].lock; - NODE_LOCK(lock, isc_rwlocktype_read); + NODE_RDLOCK(lock, &nlocktype); for (header = wnode->data; header != NULL; header = header->next) { if (header->serial <= search->serial && @@ -3467,7 +3615,7 @@ find_wildcard(rbtdb_search_t *search, dns_rbtnode_t **nodep, break; } } - NODE_UNLOCK(lock, isc_rwlocktype_read); + NODE_UNLOCK(lock, &nlocktype); if (header != NULL || activeempty(search, &wchain, wname)) { if (activeemptynode(search, qname, @@ -3712,8 +3860,9 @@ again: return (result); } do { - NODE_LOCK(&(search->rbtdb->node_locks[node->locknum].lock), - isc_rwlocktype_read); + isc_rwlocktype_t nlocktype = isc_rwlocktype_none; + NODE_RDLOCK(&(search->rbtdb->node_locks[node->locknum].lock), + &nlocktype); found = NULL; foundsig = NULL; empty_node = true; @@ -3830,7 +3979,7 @@ again: &nsecchain, &first); } NODE_UNLOCK(&(search->rbtdb->node_locks[node->locknum].lock), - isc_rwlocktype_read); + &nlocktype); node = prevnode; prevnode = NULL; } while (empty_node && result == ISC_R_SUCCESS); @@ -3880,8 +4029,8 @@ zone_find(dns_db_t *db, const dns_name_t *name, dns_dbversion_t *version, bool active; nodelock_t *lock; dns_rbt_t *tree; - isc_rwlocktype_t nlocktype; - isc_rwlocktype_t tlocktype; + isc_rwlocktype_t nlocktype = isc_rwlocktype_none; + isc_rwlocktype_t tlocktype = isc_rwlocktype_none; search.rbtdb = (dns_rbtdb_t *)db; @@ -3919,8 +4068,7 @@ zone_find(dns_db_t *db, const dns_name_t *name, dns_dbversion_t *version, */ wild = false; - tlocktype = isc_rwlocktype_read; - RWLOCK(&search.rbtdb->tree_lock, tlocktype); + TREE_RDLOCK(&search.rbtdb->tree_lock, &tlocktype); /* * Search down from the root of the tree. If, while going down, we @@ -4040,8 +4188,7 @@ found: */ lock = &search.rbtdb->node_locks[node->locknum].lock; - nlocktype = isc_rwlocktype_read; - NODE_LOCK(lock, nlocktype); + NODE_RDLOCK(lock, &nlocktype); found = NULL; foundsig = NULL; @@ -4122,7 +4269,7 @@ found: */ if (header->type == dns_rdatatype_nsec3 && !matchparams(header, &search)) { - NODE_UNLOCK(lock, nlocktype); + NODE_UNLOCK(lock, &nlocktype); goto partial_match; } /* @@ -4206,7 +4353,7 @@ found: * we really have a partial match. */ if (!wild) { - NODE_UNLOCK(lock, nlocktype); + NODE_UNLOCK(lock, &nlocktype); goto partial_match; } } @@ -4222,7 +4369,7 @@ found: * * Return the delegation. */ - NODE_UNLOCK(lock, nlocktype); + NODE_UNLOCK(lock, &nlocktype); result = setup_delegation(&search, nodep, foundname, rdataset, sigrdataset); goto tree_exit; @@ -4244,7 +4391,7 @@ found: goto node_exit; } - NODE_UNLOCK(lock, nlocktype); + NODE_UNLOCK(lock, &nlocktype); result = find_closest_nsec(&search, nodep, foundname, rdataset, sigrdataset, search.rbtdb->tree, @@ -4334,7 +4481,7 @@ found: (search.options & DNS_DBFIND_VALIDATEGLUE) != 0 && !valid_glue(&search, foundname, type, node)) { - NODE_UNLOCK(lock, nlocktype); + NODE_UNLOCK(lock, &nlocktype); result = setup_delegation(&search, nodep, foundname, rdataset, sigrdataset); goto tree_exit; @@ -4369,27 +4516,24 @@ found: } node_exit: - NODE_UNLOCK(lock, nlocktype); + NODE_UNLOCK(lock, &nlocktype); tree_exit: - RWUNLOCK(&search.rbtdb->tree_lock, tlocktype); + TREE_UNLOCK(&search.rbtdb->tree_lock, &tlocktype); /* * If we found a zonecut but aren't going to use it, we have to * let go of it. */ if (search.need_cleanup) { - nlocktype = isc_rwlocktype_read; - tlocktype = isc_rwlocktype_none; - node = search.zonecut; INSIST(node != NULL); lock = &(search.rbtdb->node_locks[node->locknum].lock); - NODE_LOCK(lock, nlocktype); + NODE_RDLOCK(lock, &nlocktype); decrement_reference(search.rbtdb, node, 0, &nlocktype, &tlocktype, false); - NODE_UNLOCK(lock, nlocktype); + NODE_UNLOCK(lock, &nlocktype); INSIST(tlocktype == isc_rwlocktype_none); } @@ -4425,7 +4569,7 @@ zone_findzonecut(dns_db_t *db, const dns_name_t *name, unsigned int options, static bool check_stale_header(dns_rbtnode_t *node, rdatasetheader_t *header, - isc_rwlocktype_t *nlocktype, nodelock_t *lock, + isc_rwlocktype_t *nlocktypep, nodelock_t *lock, rbtdb_search_t *search, rdatasetheader_t **header_prev) { if (!ACTIVE(header, search->now)) { dns_ttl_t stale = header->rdh_ttl + @@ -4486,8 +4630,8 @@ check_stale_header(dns_rbtnode_t *node, rdatasetheader_t *header, * cleaned up later. */ if ((header->rdh_ttl < search->now - RBTDB_VIRTUAL) && - (*nlocktype == isc_rwlocktype_write || - NODE_TRYUPGRADE(lock) == ISC_R_SUCCESS)) + (*nlocktypep == isc_rwlocktype_write || + NODE_TRYUPGRADE(lock, nlocktypep) == ISC_R_SUCCESS)) { /* * We update the node's status only when we can @@ -4497,7 +4641,6 @@ check_stale_header(dns_rbtnode_t *node, rdatasetheader_t *header, * We won't downgrade the lock, since other * rdatasets are probably stale, too. */ - *nlocktype = isc_rwlocktype_write; if (isc_refcount_current(&node->references) == 0) { isc_mem_t *mctx; @@ -4538,7 +4681,7 @@ cache_zonecut_callback(dns_rbtnode_t *node, dns_name_t *name, void *arg) { rdatasetheader_t *dname_header, *sigdname_header; isc_result_t result; nodelock_t *lock; - isc_rwlocktype_t nlocktype; + isc_rwlocktype_t nlocktype = isc_rwlocktype_none; /* XXX comment */ @@ -4550,8 +4693,7 @@ cache_zonecut_callback(dns_rbtnode_t *node, dns_name_t *name, void *arg) { UNUSED(name); lock = &(search->rbtdb->node_locks[node->locknum].lock); - nlocktype = isc_rwlocktype_read; - NODE_LOCK(lock, nlocktype); + NODE_RDLOCK(lock, &nlocktype); /* * Look for a DNAME or RRSIG DNAME rdataset. @@ -4597,7 +4739,7 @@ cache_zonecut_callback(dns_rbtnode_t *node, dns_name_t *name, void *arg) { result = DNS_R_CONTINUE; } - NODE_UNLOCK(lock, nlocktype); + NODE_UNLOCK(lock, &nlocktype); return (result); } @@ -4614,8 +4756,6 @@ find_deepest_zonecut(rbtdb_search_t *search, dns_rbtnode_t *node, dns_name_t name; dns_rbtdb_t *rbtdb; bool done; - nodelock_t *lock; - isc_rwlocktype_t nlocktype; /* * Caller must be holding the tree lock. @@ -4625,9 +4765,10 @@ find_deepest_zonecut(rbtdb_search_t *search, dns_rbtnode_t *node, i = search->chain.level_matches; done = false; do { - nlocktype = isc_rwlocktype_read; - lock = &rbtdb->node_locks[node->locknum].lock; - NODE_LOCK(lock, nlocktype); + nodelock_t *lock = &rbtdb->node_locks[node->locknum].lock; + isc_rwlocktype_t nlocktype = isc_rwlocktype_none; + + NODE_RDLOCK(lock, &nlocktype); /* * Look for NS and RRSIG NS rdatasets. @@ -4710,9 +4851,11 @@ find_deepest_zonecut(rbtdb_search_t *search, dns_rbtnode_t *node, need_headerupdate(foundsig, search->now))) { if (nlocktype != isc_rwlocktype_write) { - NODE_UNLOCK(lock, nlocktype); - nlocktype = isc_rwlocktype_write; - NODE_LOCK(lock, nlocktype); + if (NODE_TRYUPGRADE(lock, &nlocktype) != + ISC_R_SUCCESS) { + NODE_UNLOCK(lock, &nlocktype); + NODE_WRLOCK(lock, &nlocktype); + } POST(nlocktype); } if (need_headerupdate(found, search->now)) { @@ -4728,7 +4871,7 @@ find_deepest_zonecut(rbtdb_search_t *search, dns_rbtnode_t *node, } node_exit: - NODE_UNLOCK(lock, nlocktype); + NODE_UNLOCK(lock, &nlocktype); if (found == NULL && i > 0) { i--; @@ -4759,7 +4902,7 @@ find_coveringnsec(rbtdb_search_t *search, const dns_name_t *name, dns_rbtnode_t *node = NULL; dns_rbtnodechain_t chain; isc_result_t result; - isc_rwlocktype_t nlocktype; + isc_rwlocktype_t nlocktype = isc_rwlocktype_none; nodelock_t *lock = NULL; rbtdb_rdatatype_t matchtype, sigmatchtype; rdatasetheader_t *found = NULL, *foundsig = NULL; @@ -4783,7 +4926,6 @@ find_coveringnsec(rbtdb_search_t *search, const dns_name_t *name, target = dns_fixedname_initname(&ftarget); fname = dns_fixedname_initname(&fixed); - nlocktype = isc_rwlocktype_read; matchtype = RBTDB_RDATATYPE_VALUE(dns_rdatatype_nsec, 0); sigmatchtype = RBTDB_RDATATYPE_VALUE(dns_rdatatype_rrsig, dns_rdatatype_nsec); @@ -4813,7 +4955,7 @@ find_coveringnsec(rbtdb_search_t *search, const dns_name_t *name, } lock = &(search->rbtdb->node_locks[node->locknum].lock); - NODE_LOCK(lock, nlocktype); + NODE_RDLOCK(lock, &nlocktype); for (header = node->data; header != NULL; header = header_next) { header_next = header->next; if (check_stale_header(node, header, &nlocktype, lock, search, @@ -4854,7 +4996,7 @@ find_coveringnsec(rbtdb_search_t *search, const dns_name_t *name, } else { result = ISC_R_NOTFOUND; } - NODE_UNLOCK(lock, nlocktype); + NODE_UNLOCK(lock, &nlocktype); return (result); } @@ -4871,8 +5013,8 @@ cache_find(dns_db_t *db, const dns_name_t *name, dns_dbversion_t *version, bool all_negative = true; bool empty_node; nodelock_t *lock; - isc_rwlocktype_t tlocktype; - isc_rwlocktype_t nlocktype = isc_rwlocktype_read; + isc_rwlocktype_t tlocktype = isc_rwlocktype_none; + isc_rwlocktype_t nlocktype = isc_rwlocktype_none; rdatasetheader_t *header, *header_prev, *header_next; rdatasetheader_t *found, *nsheader; rdatasetheader_t *foundsig, *nssig, *cnamesig; @@ -4906,8 +5048,7 @@ cache_find(dns_db_t *db, const dns_name_t *name, dns_dbversion_t *version, update = NULL; updatesig = NULL; - tlocktype = isc_rwlocktype_read; - RWLOCK(&search.rbtdb->tree_lock, tlocktype); + TREE_RDLOCK(&search.rbtdb->tree_lock, &tlocktype); /* * Search down from the root of the tree. If, while going down, we @@ -4965,7 +5106,7 @@ cache_find(dns_db_t *db, const dns_name_t *name, dns_dbversion_t *version, */ lock = &(search.rbtdb->node_locks[node->locknum].lock); - NODE_LOCK(lock, nlocktype); + NODE_RDLOCK(lock, &nlocktype); found = NULL; foundsig = NULL; @@ -5067,7 +5208,7 @@ cache_find(dns_db_t *db, const dns_name_t *name, dns_dbversion_t *version, * extant rdatasets. That means that this node doesn't * meaningfully exist, and that we really have a partial match. */ - NODE_UNLOCK(lock, nlocktype); + NODE_UNLOCK(lock, &nlocktype); if ((search.options & DNS_DBFIND_COVERINGNSEC) != 0) { result = find_coveringnsec(&search, name, nodep, now, foundname, rdataset, @@ -5122,7 +5263,7 @@ cache_find(dns_db_t *db, const dns_name_t *name, dns_dbversion_t *version, if (found == NULL && (found_noqname || all_negative) && (search.options & DNS_DBFIND_COVERINGNSEC) != 0) { - NODE_UNLOCK(lock, nlocktype); + NODE_UNLOCK(lock, &nlocktype); result = find_coveringnsec(&search, name, nodep, now, foundname, rdataset, sigrdataset); @@ -5161,7 +5302,7 @@ cache_find(dns_db_t *db, const dns_name_t *name, dns_dbversion_t *version, /* * Go find the deepest zone cut. */ - NODE_UNLOCK(lock, nlocktype); + NODE_UNLOCK(lock, &nlocktype); goto find_ns; } @@ -5219,9 +5360,10 @@ cache_find(dns_db_t *db, const dns_name_t *name, dns_dbversion_t *version, node_exit: if ((update != NULL || updatesig != NULL) && nlocktype != isc_rwlocktype_write) { - NODE_UNLOCK(lock, nlocktype); - nlocktype = isc_rwlocktype_write; - NODE_LOCK(lock, nlocktype); + if (NODE_TRYUPGRADE(lock, &nlocktype) != ISC_R_SUCCESS) { + NODE_UNLOCK(lock, &nlocktype); + NODE_WRLOCK(lock, &nlocktype); + } POST(nlocktype); } if (update != NULL && need_headerupdate(update, search.now)) { @@ -5231,27 +5373,24 @@ node_exit: update_header(search.rbtdb, updatesig, search.now); } - NODE_UNLOCK(lock, nlocktype); + NODE_UNLOCK(lock, &nlocktype); tree_exit: - RWUNLOCK(&search.rbtdb->tree_lock, tlocktype); + TREE_UNLOCK(&search.rbtdb->tree_lock, &tlocktype); /* * If we found a zonecut but aren't going to use it, we have to * let go of it. */ if (search.need_cleanup) { - nlocktype = isc_rwlocktype_read; - tlocktype = isc_rwlocktype_none; - node = search.zonecut; INSIST(node != NULL); lock = &(search.rbtdb->node_locks[node->locknum].lock); - NODE_LOCK(lock, nlocktype); + NODE_RDLOCK(lock, &nlocktype); decrement_reference(search.rbtdb, node, 0, &nlocktype, &tlocktype, false); - NODE_UNLOCK(lock, nlocktype); + NODE_UNLOCK(lock, &nlocktype); INSIST(tlocktype == isc_rwlocktype_none); } @@ -5273,8 +5412,8 @@ cache_findzonecut(dns_db_t *db, const dns_name_t *name, unsigned int options, rdatasetheader_t *header, *header_prev, *header_next; rdatasetheader_t *found, *foundsig; unsigned int rbtoptions = DNS_RBTFIND_EMPTYDATA; - isc_rwlocktype_t tlocktype = isc_rwlocktype_read; - isc_rwlocktype_t nlocktype = isc_rwlocktype_read; + isc_rwlocktype_t tlocktype = isc_rwlocktype_none; + isc_rwlocktype_t nlocktype = isc_rwlocktype_none; bool dcnull = (dcname == NULL); search.rbtdb = (dns_rbtdb_t *)db; @@ -5304,8 +5443,7 @@ cache_findzonecut(dns_db_t *db, const dns_name_t *name, unsigned int options, rbtoptions |= DNS_RBTFIND_NOEXACT; } - tlocktype = isc_rwlocktype_read; - RWLOCK(&search.rbtdb->tree_lock, tlocktype); + TREE_RDLOCK(&search.rbtdb->tree_lock, &tlocktype); /* * Search down from the root of the tree. @@ -5328,7 +5466,7 @@ cache_findzonecut(dns_db_t *db, const dns_name_t *name, unsigned int options, */ lock = &(search.rbtdb->node_locks[node->locknum].lock); - NODE_LOCK(lock, nlocktype); + NODE_RDLOCK(lock, &nlocktype); found = NULL; foundsig = NULL; @@ -5347,7 +5485,7 @@ cache_findzonecut(dns_db_t *db, const dns_name_t *name, unsigned int options, * zonecut we know about. If so, find the deepest * zonecut from this node up and return that instead. */ - NODE_UNLOCK(lock, nlocktype); + NODE_UNLOCK(lock, &nlocktype); result = find_deepest_zonecut(&search, node, nodep, foundname, rdataset, sigrdataset); @@ -5382,7 +5520,7 @@ cache_findzonecut(dns_db_t *db, const dns_name_t *name, unsigned int options, /* * No NS records here. */ - NODE_UNLOCK(lock, nlocktype); + NODE_UNLOCK(lock, &nlocktype); result = find_deepest_zonecut(&search, node, nodep, foundname, rdataset, sigrdataset); goto tree_exit; @@ -5404,9 +5542,11 @@ cache_findzonecut(dns_db_t *db, const dns_name_t *name, unsigned int options, (foundsig != NULL && need_headerupdate(foundsig, search.now))) { if (nlocktype != isc_rwlocktype_write) { - NODE_UNLOCK(lock, nlocktype); - nlocktype = isc_rwlocktype_write; - NODE_LOCK(lock, nlocktype); + if (NODE_TRYUPGRADE(lock, &nlocktype) != ISC_R_SUCCESS) + { + NODE_UNLOCK(lock, &nlocktype); + NODE_WRLOCK(lock, &nlocktype); + } POST(nlocktype); } if (need_headerupdate(found, search.now)) { @@ -5418,10 +5558,10 @@ cache_findzonecut(dns_db_t *db, const dns_name_t *name, unsigned int options, } } - NODE_UNLOCK(lock, nlocktype); + NODE_UNLOCK(lock, &nlocktype); tree_exit: - RWUNLOCK(&search.rbtdb->tree_lock, tlocktype); + TREE_UNLOCK(&search.rbtdb->tree_lock, &tlocktype); INSIST(!search.need_cleanup); @@ -5454,7 +5594,7 @@ detachnode(dns_db_t *db, dns_dbnode_t **targetp) { bool want_free = false; bool inactive = false; rbtdb_nodelock_t *nodelock; - isc_rwlocktype_t nlocktype = isc_rwlocktype_read; + isc_rwlocktype_t nlocktype = isc_rwlocktype_none; isc_rwlocktype_t tlocktype = isc_rwlocktype_none; REQUIRE(VALID_RBTDB(rbtdb)); @@ -5463,7 +5603,7 @@ detachnode(dns_db_t *db, dns_dbnode_t **targetp) { node = (dns_rbtnode_t *)(*targetp); nodelock = &rbtdb->node_locks[node->locknum]; - NODE_LOCK(&nodelock->lock, nlocktype); + NODE_RDLOCK(&nodelock->lock, &nlocktype); if (decrement_reference(rbtdb, node, 0, &nlocktype, &tlocktype, false)) { @@ -5473,7 +5613,7 @@ detachnode(dns_db_t *db, dns_dbnode_t **targetp) { } } - NODE_UNLOCK(&nodelock->lock, nlocktype); + NODE_UNLOCK(&nodelock->lock, &nlocktype); INSIST(tlocktype == isc_rwlocktype_none); *targetp = NULL; @@ -5515,6 +5655,7 @@ expirenode(dns_db_t *db, dns_dbnode_t *node, isc_stdtime_t now) { isc_logmodule_t *module = DNS_LOGMODULE_CACHE; int level = ISC_LOG_DEBUG(2); char printname[DNS_NAME_FORMATSIZE]; + isc_rwlocktype_t nlocktype = isc_rwlocktype_none; REQUIRE(VALID_RBTDB(rbtdb)); @@ -5554,8 +5695,7 @@ expirenode(dns_db_t *db, dns_dbnode_t *node, isc_stdtime_t now) { * We may not need write access, but this code path is not performance * sensitive, so it should be okay to always lock as a writer. */ - NODE_LOCK(&rbtdb->node_locks[rbtnode->locknum].lock, - isc_rwlocktype_write); + NODE_WRLOCK(&rbtdb->node_locks[rbtnode->locknum].lock, &nlocktype); for (header = rbtnode->data; header != NULL; header = header->next) { if (header->rdh_ttl + STALE_TTL(header, rbtdb) <= @@ -5588,8 +5728,7 @@ expirenode(dns_db_t *db, dns_dbnode_t *node, isc_stdtime_t now) { } } - NODE_UNLOCK(&rbtdb->node_locks[rbtnode->locknum].lock, - isc_rwlocktype_write); + NODE_UNLOCK(&rbtdb->node_locks[rbtnode->locknum].lock, &nlocktype); return (ISC_R_SUCCESS); } @@ -5610,11 +5749,11 @@ printnode(dns_db_t *db, dns_dbnode_t *node, FILE *out) { dns_rbtnode_t *rbtnode = node; bool first; uint32_t refs; + isc_rwlocktype_t nlocktype = isc_rwlocktype_none; REQUIRE(VALID_RBTDB(rbtdb)); - NODE_LOCK(&rbtdb->node_locks[rbtnode->locknum].lock, - isc_rwlocktype_read); + NODE_RDLOCK(&rbtdb->node_locks[rbtnode->locknum].lock, &nlocktype); refs = isc_refcount_current(&rbtnode->references); fprintf(out, "node %p, %" PRIu32 " references, locknum = %u\n", rbtnode, @@ -5651,8 +5790,7 @@ printnode(dns_db_t *db, dns_dbnode_t *node, FILE *out) { fprintf(out, "(empty)\n"); } - NODE_UNLOCK(&rbtdb->node_locks[rbtnode->locknum].lock, - isc_rwlocktype_read); + NODE_UNLOCK(&rbtdb->node_locks[rbtnode->locknum].lock, &nlocktype); } static isc_result_t @@ -5707,6 +5845,7 @@ zone_findrdataset(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version, rbtdb_version_t *rbtversion = version; bool close_version = false; rbtdb_rdatatype_t matchtype, sigmatchtype; + isc_rwlocktype_t nlocktype = isc_rwlocktype_none; REQUIRE(VALID_RBTDB(rbtdb)); REQUIRE(type != dns_rdatatype_any); @@ -5719,8 +5858,7 @@ zone_findrdataset(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version, serial = rbtversion->serial; now = 0; - NODE_LOCK(&rbtdb->node_locks[rbtnode->locknum].lock, - isc_rwlocktype_read); + NODE_RDLOCK(&rbtdb->node_locks[rbtnode->locknum].lock, &nlocktype); found = NULL; foundsig = NULL; @@ -5774,8 +5912,7 @@ zone_findrdataset(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version, } } - NODE_UNLOCK(&rbtdb->node_locks[rbtnode->locknum].lock, - isc_rwlocktype_read); + NODE_UNLOCK(&rbtdb->node_locks[rbtnode->locknum].lock, &nlocktype); if (close_version) { closeversion(db, (dns_dbversion_t **)(void *)(&rbtversion), @@ -5800,7 +5937,7 @@ cache_findrdataset(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version, rbtdb_rdatatype_t matchtype, sigmatchtype, negtype; isc_result_t result; nodelock_t *lock; - isc_rwlocktype_t locktype; + isc_rwlocktype_t nlocktype = isc_rwlocktype_none; REQUIRE(VALID_RBTDB(rbtdb)); REQUIRE(type != dns_rdatatype_any); @@ -5814,8 +5951,7 @@ cache_findrdataset(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version, } lock = &rbtdb->node_locks[rbtnode->locknum].lock; - locktype = isc_rwlocktype_read; - NODE_LOCK(lock, locktype); + NODE_RDLOCK(lock, &nlocktype); found = NULL; foundsig = NULL; @@ -5832,14 +5968,14 @@ cache_findrdataset(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version, if (!ACTIVE(header, now)) { if ((header->rdh_ttl + STALE_TTL(header, rbtdb) < now - RBTDB_VIRTUAL) && - (locktype == isc_rwlocktype_write || - NODE_TRYUPGRADE(lock) == ISC_R_SUCCESS)) + (nlocktype == isc_rwlocktype_write || + NODE_TRYUPGRADE(lock, &nlocktype) == + ISC_R_SUCCESS)) { /* * We update the node's status only when we * can get write access. */ - locktype = isc_rwlocktype_write; /* * We don't check if refcurrent(rbtnode) == 0 @@ -5862,14 +5998,14 @@ cache_findrdataset(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version, } } if (found != NULL) { - bind_rdataset(rbtdb, rbtnode, found, now, locktype, rdataset); + bind_rdataset(rbtdb, rbtnode, found, now, nlocktype, rdataset); if (!NEGATIVE(found) && foundsig != NULL) { - bind_rdataset(rbtdb, rbtnode, foundsig, now, locktype, + bind_rdataset(rbtdb, rbtnode, foundsig, now, nlocktype, sigrdataset); } } - NODE_UNLOCK(lock, locktype); + NODE_UNLOCK(lock, &nlocktype); if (found == NULL) { return (ISC_R_NOTFOUND); @@ -6726,8 +6862,8 @@ addrdataset(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version, isc_result_t result; bool delegating; bool newnsec; - isc_rwlocktype_t tlocktype = isc_rwlocktype_read; - isc_rwlocktype_t nlocktype = isc_rwlocktype_write; + isc_rwlocktype_t tlocktype = isc_rwlocktype_none; + isc_rwlocktype_t nlocktype = isc_rwlocktype_none; bool cache_is_overmem = false; dns_fixedname_t fixed; dns_name_t *name; @@ -6743,14 +6879,14 @@ addrdataset(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version, node != rbtdb->origin_node) { return (DNS_R_NOTZONETOP); } - RWLOCK(&rbtdb->tree_lock, tlocktype); + TREE_RDLOCK(&rbtdb->tree_lock, &tlocktype); REQUIRE(((rbtnode->nsec == DNS_RBT_NSEC_NSEC3 && (rdataset->type == dns_rdatatype_nsec3 || rdataset->covers == dns_rdatatype_nsec3)) || (rbtnode->nsec != DNS_RBT_NSEC_NSEC3 && rdataset->type != dns_rdatatype_nsec3 && rdataset->covers != dns_rdatatype_nsec3))); - RWUNLOCK(&rbtdb->tree_lock, tlocktype); + TREE_UNLOCK(&rbtdb->tree_lock, &tlocktype); } if (rbtversion == NULL) { @@ -6851,8 +6987,7 @@ addrdataset(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version, /* * Add to the auxiliary NSEC tree if we're adding an NSEC record. */ - tlocktype = isc_rwlocktype_read; - RWLOCK(&rbtdb->tree_lock, tlocktype); + TREE_RDLOCK(&rbtdb->tree_lock, &tlocktype); if (rbtnode->nsec != DNS_RBT_NSEC_HAS_NSEC && rdataset->type == dns_rdatatype_nsec) { @@ -6860,7 +6995,7 @@ addrdataset(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version, } else { newnsec = false; } - RWUNLOCK(&rbtdb->tree_lock, tlocktype); + TREE_UNLOCK(&rbtdb->tree_lock, &tlocktype); /* * If we're adding a delegation type, adding to the auxiliary NSEC @@ -6873,17 +7008,14 @@ addrdataset(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version, cache_is_overmem = true; } if (delegating || newnsec || cache_is_overmem) { - tlocktype = isc_rwlocktype_write; - RWLOCK(&rbtdb->tree_lock, tlocktype); - } else { - tlocktype = isc_rwlocktype_none; + TREE_WRLOCK(&rbtdb->tree_lock, &tlocktype); } if (cache_is_overmem) { overmem_purge(rbtdb, rbtnode->locknum, now, &tlocktype); } - NODE_LOCK(&rbtdb->node_locks[rbtnode->locknum].lock, nlocktype); + NODE_WRLOCK(&rbtdb->node_locks[rbtnode->locknum].lock, &nlocktype); if (rbtdb->rrsetstats != NULL) { RDATASET_ATTR_SET(newheader, RDATASET_ATTR_STATCOUNT); @@ -6912,8 +7044,7 @@ addrdataset(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version, */ if (tlocktype == isc_rwlocktype_write && !delegating && !newnsec) { - RWUNLOCK(&rbtdb->tree_lock, tlocktype); - tlocktype = isc_rwlocktype_none; + TREE_UNLOCK(&rbtdb->tree_lock, &tlocktype); } } @@ -6940,11 +7071,12 @@ addrdataset(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version, rbtnode->find_callback = 1; } - NODE_UNLOCK(&rbtdb->node_locks[rbtnode->locknum].lock, nlocktype); + NODE_UNLOCK(&rbtdb->node_locks[rbtnode->locknum].lock, &nlocktype); if (tlocktype != isc_rwlocktype_none) { - RWUNLOCK(&rbtdb->tree_lock, tlocktype); + TREE_UNLOCK(&rbtdb->tree_lock, &tlocktype); } + INSIST(tlocktype == isc_rwlocktype_none); /* * Update the zone's secure status. If version is non-NULL @@ -6971,19 +7103,21 @@ subtractrdataset(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version, isc_region_t region; isc_result_t result; rbtdb_changed_t *changed; + isc_rwlocktype_t tlocktype = isc_rwlocktype_none; + isc_rwlocktype_t nlocktype = isc_rwlocktype_none; REQUIRE(VALID_RBTDB(rbtdb)); REQUIRE(rbtversion != NULL && rbtversion->rbtdb == rbtdb); if (rbtdb->common.methods == &zone_methods) { - RWLOCK(&rbtdb->tree_lock, isc_rwlocktype_read); + TREE_RDLOCK(&rbtdb->tree_lock, &tlocktype); REQUIRE(((rbtnode->nsec == DNS_RBT_NSEC_NSEC3 && (rdataset->type == dns_rdatatype_nsec3 || rdataset->covers == dns_rdatatype_nsec3)) || (rbtnode->nsec != DNS_RBT_NSEC_NSEC3 && rdataset->type != dns_rdatatype_nsec3 && rdataset->covers != dns_rdatatype_nsec3))); - RWUNLOCK(&rbtdb->tree_lock, isc_rwlocktype_read); + TREE_UNLOCK(&rbtdb->tree_lock, &tlocktype); } nodefullname(db, node, nodename); @@ -7018,14 +7152,13 @@ subtractrdataset(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version, newheader->resign_lsb = 0; } - NODE_LOCK(&rbtdb->node_locks[rbtnode->locknum].lock, - isc_rwlocktype_write); + NODE_WRLOCK(&rbtdb->node_locks[rbtnode->locknum].lock, &nlocktype); changed = add_changed(rbtdb, rbtversion, rbtnode); if (changed == NULL) { free_rdataset(rbtdb, rbtdb->common.mctx, newheader); NODE_UNLOCK(&rbtdb->node_locks[rbtnode->locknum].lock, - isc_rwlocktype_write); + &nlocktype); return (ISC_R_NOMEMORY); } @@ -7165,8 +7298,7 @@ subtractrdataset(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version, } unlock: - NODE_UNLOCK(&rbtdb->node_locks[rbtnode->locknum].lock, - isc_rwlocktype_write); + NODE_UNLOCK(&rbtdb->node_locks[rbtnode->locknum].lock, &nlocktype); /* * Update the zone's secure status. If version is non-NULL @@ -7192,6 +7324,7 @@ deleterdataset(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version, dns_name_t *nodename = dns_fixedname_initname(&fname); isc_result_t result; rdatasetheader_t *newheader; + isc_rwlocktype_t nlocktype = isc_rwlocktype_none; REQUIRE(VALID_RBTDB(rbtdb)); INSIST(rbtversion == NULL || rbtversion->rbtdb == rbtdb); @@ -7225,12 +7358,10 @@ deleterdataset(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version, nodefullname(db, node, nodename); - NODE_LOCK(&rbtdb->node_locks[rbtnode->locknum].lock, - isc_rwlocktype_write); + NODE_WRLOCK(&rbtdb->node_locks[rbtnode->locknum].lock, &nlocktype); result = add32(rbtdb, rbtnode, nodename, rbtversion, newheader, DNS_DBADD_FORCE, false, NULL, 0); - NODE_UNLOCK(&rbtdb->node_locks[rbtnode->locknum].lock, - isc_rwlocktype_write); + NODE_UNLOCK(&rbtdb->node_locks[rbtnode->locknum].lock, &nlocktype); /* * Update the zone's secure status. If version is non-NULL @@ -7334,6 +7465,7 @@ loading_addrdataset(void *arg, const dns_name_t *name, isc_result_t result; isc_region_t region; rdatasetheader_t *newheader; + isc_rwlocktype_t nlocktype = isc_rwlocktype_none; REQUIRE(rdataset->rdclass == rbtdb->common.rdclass); @@ -7424,11 +7556,10 @@ loading_addrdataset(void *arg, const dns_name_t *name, newheader->resign_lsb = 0; } - NODE_LOCK(&rbtdb->node_locks[node->locknum].lock, isc_rwlocktype_write); + NODE_WRLOCK(&rbtdb->node_locks[node->locknum].lock, &nlocktype); result = add32(rbtdb, node, name, rbtdb->current_version, newheader, DNS_DBADD_MERGE, true, NULL, 0); - NODE_UNLOCK(&rbtdb->node_locks[node->locknum].lock, - isc_rwlocktype_write); + NODE_UNLOCK(&rbtdb->node_locks[node->locknum].lock, &nlocktype); if (result == ISC_R_SUCCESS && delegating_type(rbtdb, node, rdataset->type)) { @@ -7532,16 +7663,17 @@ delete_callback(void *data, void *arg) { dns_rbtdb_t *rbtdb = arg; rdatasetheader_t *current, *next; unsigned int locknum; + isc_rwlocktype_t nlocktype = isc_rwlocktype_none; current = data; locknum = current->node->locknum; - NODE_LOCK(&rbtdb->node_locks[locknum].lock, isc_rwlocktype_write); + NODE_WRLOCK(&rbtdb->node_locks[locknum].lock, &nlocktype); while (current != NULL) { next = current->next; free_rdataset(rbtdb, rbtdb->common.mctx, current); current = next; } - NODE_UNLOCK(&rbtdb->node_locks[locknum].lock, isc_rwlocktype_write); + NODE_UNLOCK(&rbtdb->node_locks[locknum].lock, &nlocktype); } static bool @@ -7580,12 +7712,13 @@ static unsigned int nodecount(dns_db_t *db, dns_dbtree_t tree) { dns_rbtdb_t *rbtdb; unsigned int count; + isc_rwlocktype_t tlocktype = isc_rwlocktype_none; rbtdb = (dns_rbtdb_t *)db; REQUIRE(VALID_RBTDB(rbtdb)); - RWLOCK(&rbtdb->tree_lock, isc_rwlocktype_read); + TREE_RDLOCK(&rbtdb->tree_lock, &tlocktype); switch (tree) { case dns_dbtree_main: count = dns_rbt_nodecount(rbtdb->tree); @@ -7599,7 +7732,7 @@ nodecount(dns_db_t *db, dns_dbtree_t tree) { default: UNREACHABLE(); } - RWUNLOCK(&rbtdb->tree_lock, isc_rwlocktype_read); + TREE_UNLOCK(&rbtdb->tree_lock, &tlocktype); return (count); } @@ -7608,14 +7741,15 @@ static size_t hashsize(dns_db_t *db) { dns_rbtdb_t *rbtdb; size_t size; + isc_rwlocktype_t tlocktype = isc_rwlocktype_none; rbtdb = (dns_rbtdb_t *)db; REQUIRE(VALID_RBTDB(rbtdb)); - RWLOCK(&rbtdb->tree_lock, isc_rwlocktype_read); + TREE_RDLOCK(&rbtdb->tree_lock, &tlocktype); size = dns_rbt_hashsize(rbtdb->tree); - RWUNLOCK(&rbtdb->tree_lock, isc_rwlocktype_read); + TREE_UNLOCK(&rbtdb->tree_lock, &tlocktype); return (size); } @@ -7744,6 +7878,7 @@ static isc_result_t setsigningtime(dns_db_t *db, dns_rdataset_t *rdataset, isc_stdtime_t resign) { dns_rbtdb_t *rbtdb = (dns_rbtdb_t *)db; rdatasetheader_t *header, oldheader; + isc_rwlocktype_t nlocktype = isc_rwlocktype_none; REQUIRE(VALID_RBTDB(rbtdb)); REQUIRE(!IS_CACHE(rbtdb)); @@ -7752,8 +7887,7 @@ setsigningtime(dns_db_t *db, dns_rdataset_t *rdataset, isc_stdtime_t resign) { header = rdataset->private3; header--; - NODE_LOCK(&rbtdb->node_locks[header->node->locknum].lock, - isc_rwlocktype_write); + NODE_WRLOCK(&rbtdb->node_locks[header->node->locknum].lock, &nlocktype); oldheader = *header; /* @@ -7783,8 +7917,7 @@ setsigningtime(dns_db_t *db, dns_rdataset_t *rdataset, isc_stdtime_t resign) { RDATASET_ATTR_SET(header, RDATASET_ATTR_RESIGN); resign_insert(rbtdb, header->node->locknum, header); } - NODE_UNLOCK(&rbtdb->node_locks[header->node->locknum].lock, - isc_rwlocktype_write); + NODE_UNLOCK(&rbtdb->node_locks[header->node->locknum].lock, &nlocktype); return (ISC_R_SUCCESS); } @@ -7795,13 +7928,15 @@ getsigningtime(dns_db_t *db, dns_rdataset_t *rdataset, dns_name_t *foundname) { unsigned int i; isc_result_t result = ISC_R_NOTFOUND; unsigned int locknum = 0; + isc_rwlocktype_t tlocktype = isc_rwlocktype_none; + isc_rwlocktype_t nlocktype = isc_rwlocktype_none; REQUIRE(VALID_RBTDB(rbtdb)); - RWLOCK(&rbtdb->tree_lock, isc_rwlocktype_read); + TREE_RDLOCK(&rbtdb->tree_lock, &tlocktype); for (i = 0; i < rbtdb->node_lock_count; i++) { - NODE_LOCK(&rbtdb->node_locks[i].lock, isc_rwlocktype_read); + NODE_RDLOCK(&rbtdb->node_locks[i].lock, &nlocktype); /* * Find for the earliest signing time among all of the @@ -7811,8 +7946,7 @@ getsigningtime(dns_db_t *db, dns_rdataset_t *rdataset, dns_name_t *foundname) { this = isc_heap_element(rbtdb->heaps[i], 1); if (this == NULL) { /* Nothing found; unlock and try the next heap. */ - NODE_UNLOCK(&rbtdb->node_locks[i].lock, - isc_rwlocktype_read); + NODE_UNLOCK(&rbtdb->node_locks[i].lock, &nlocktype); continue; } @@ -7824,13 +7958,14 @@ getsigningtime(dns_db_t *db, dns_rdataset_t *rdataset, dns_name_t *foundname) { */ header = this; locknum = i; + nlocktype = isc_rwlocktype_none; } else if (resign_sooner(this, header)) { /* * Found an earlier signing time; release the * previous bucket lock and retain this one instead. */ NODE_UNLOCK(&rbtdb->node_locks[locknum].lock, - isc_rwlocktype_read); + &nlocktype); header = this; locknum = i; } else { @@ -7838,12 +7973,12 @@ getsigningtime(dns_db_t *db, dns_rdataset_t *rdataset, dns_name_t *foundname) { * Earliest signing time in this heap isn't * an improvement; unlock and try the next heap. */ - NODE_UNLOCK(&rbtdb->node_locks[i].lock, - isc_rwlocktype_read); + NODE_UNLOCK(&rbtdb->node_locks[i].lock, &nlocktype); } } if (header != NULL) { + nlocktype = isc_rwlocktype_read; /* * Found something; pass back the answer and unlock * the bucket. @@ -7855,13 +7990,12 @@ getsigningtime(dns_db_t *db, dns_rdataset_t *rdataset, dns_name_t *foundname) { dns_rbt_fullnamefromnode(header->node, foundname); } - NODE_UNLOCK(&rbtdb->node_locks[locknum].lock, - isc_rwlocktype_read); + NODE_UNLOCK(&rbtdb->node_locks[locknum].lock, &nlocktype); result = ISC_R_SUCCESS; } - RWUNLOCK(&rbtdb->tree_lock, isc_rwlocktype_read); + TREE_UNLOCK(&rbtdb->tree_lock, &tlocktype); return (result); } @@ -7872,6 +8006,8 @@ resigned(dns_db_t *db, dns_rdataset_t *rdataset, dns_dbversion_t *version) { dns_rbtdb_t *rbtdb = (dns_rbtdb_t *)db; dns_rbtnode_t *node; rdatasetheader_t *header; + isc_rwlocktype_t tlocktype = isc_rwlocktype_none; + isc_rwlocktype_t nlocktype = isc_rwlocktype_none; REQUIRE(VALID_RBTDB(rbtdb)); REQUIRE(rdataset != NULL); @@ -7891,16 +8027,15 @@ resigned(dns_db_t *db, dns_rdataset_t *rdataset, dns_dbversion_t *version) { return; } - RWLOCK(&rbtdb->tree_lock, isc_rwlocktype_write); - NODE_LOCK(&rbtdb->node_locks[node->locknum].lock, isc_rwlocktype_write); + TREE_WRLOCK(&rbtdb->tree_lock, &tlocktype); + NODE_WRLOCK(&rbtdb->node_locks[node->locknum].lock, &nlocktype); /* * Delete from heap and save to re-signed list so that it can * be restored if we backout of this change. */ resign_delete(rbtdb, rbtversion, header); - NODE_UNLOCK(&rbtdb->node_locks[node->locknum].lock, - isc_rwlocktype_write); - RWUNLOCK(&rbtdb->tree_lock, isc_rwlocktype_write); + NODE_UNLOCK(&rbtdb->node_locks[node->locknum].lock, &nlocktype); + TREE_UNLOCK(&rbtdb->tree_lock, &tlocktype); } static isc_result_t @@ -7942,14 +8077,15 @@ nodefullname(dns_db_t *db, dns_dbnode_t *node, dns_name_t *name) { dns_rbtdb_t *rbtdb = (dns_rbtdb_t *)db; dns_rbtnode_t *rbtnode = (dns_rbtnode_t *)node; isc_result_t result; + isc_rwlocktype_t tlocktype = isc_rwlocktype_none; REQUIRE(VALID_RBTDB(rbtdb)); REQUIRE(node != NULL); REQUIRE(name != NULL); - RWLOCK(&rbtdb->tree_lock, isc_rwlocktype_read); + TREE_RDLOCK(&rbtdb->tree_lock, &tlocktype); result = dns_rbt_fullnamefromnode(rbtnode, name); - RWUNLOCK(&rbtdb->tree_lock, isc_rwlocktype_read); + TREE_UNLOCK(&rbtdb->tree_lock, &tlocktype); return (result); } @@ -8141,7 +8277,7 @@ dns_rbtdb_create(isc_mem_t *mctx, const dns_name_t *origin, dns_dbtype_t type, RBTDB_INITLOCK(&rbtdb->lock); - isc_rwlock_init(&rbtdb->tree_lock, 0, 0); + TREE_INITLOCK(&rbtdb->tree_lock); /* * Initialize node_lock_count in a generic way to support future @@ -8352,7 +8488,7 @@ cleanup_node_locks: rbtdb->node_lock_count * sizeof(rbtdb_nodelock_t)); cleanup_tree_lock: - isc_rwlock_destroy(&rbtdb->tree_lock); + TREE_DESTROYLOCK(&rbtdb->tree_lock); RBTDB_DESTROYLOCK(&rbtdb->lock); isc_mem_put(mctx, rbtdb, sizeof(*rbtdb)); return (result); @@ -8597,13 +8733,12 @@ rdataset_settrust(dns_rdataset_t *rdataset, dns_trust_t trust) { dns_rbtdb_t *rbtdb = rdataset->private1; dns_rbtnode_t *rbtnode = rdataset->private2; rdatasetheader_t *header = rdataset->private3; + isc_rwlocktype_t nlocktype = isc_rwlocktype_none; header--; - NODE_LOCK(&rbtdb->node_locks[rbtnode->locknum].lock, - isc_rwlocktype_write); + NODE_WRLOCK(&rbtdb->node_locks[rbtnode->locknum].lock, &nlocktype); header->trust = rdataset->trust = trust; - NODE_UNLOCK(&rbtdb->node_locks[rbtnode->locknum].lock, - isc_rwlocktype_write); + NODE_UNLOCK(&rbtdb->node_locks[rbtnode->locknum].lock, &nlocktype); } static void @@ -8611,13 +8746,12 @@ rdataset_expire(dns_rdataset_t *rdataset) { dns_rbtdb_t *rbtdb = rdataset->private1; dns_rbtnode_t *rbtnode = rdataset->private2; rdatasetheader_t *header = rdataset->private3; + isc_rwlocktype_t nlocktype = isc_rwlocktype_none; header--; - NODE_LOCK(&rbtdb->node_locks[rbtnode->locknum].lock, - isc_rwlocktype_write); + NODE_WRLOCK(&rbtdb->node_locks[rbtnode->locknum].lock, &nlocktype); expire_header(rbtdb, header, false, expire_flush); - NODE_UNLOCK(&rbtdb->node_locks[rbtnode->locknum].lock, - isc_rwlocktype_write); + NODE_UNLOCK(&rbtdb->node_locks[rbtnode->locknum].lock, &nlocktype); } static void @@ -8625,13 +8759,12 @@ rdataset_clearprefetch(dns_rdataset_t *rdataset) { dns_rbtdb_t *rbtdb = rdataset->private1; dns_rbtnode_t *rbtnode = rdataset->private2; rdatasetheader_t *header = rdataset->private3; + isc_rwlocktype_t nlocktype = isc_rwlocktype_none; header--; - NODE_LOCK(&rbtdb->node_locks[rbtnode->locknum].lock, - isc_rwlocktype_write); + NODE_WRLOCK(&rbtdb->node_locks[rbtnode->locknum].lock, &nlocktype); RDATASET_ATTR_CLR(header, RDATASET_ATTR_PREFETCH); - NODE_UNLOCK(&rbtdb->node_locks[rbtnode->locknum].lock, - isc_rwlocktype_write); + NODE_UNLOCK(&rbtdb->node_locks[rbtnode->locknum].lock, &nlocktype); } /* @@ -8663,13 +8796,13 @@ rdatasetiter_first(dns_rdatasetiter_t *iterator) { rbtdb_version_t *rbtversion = rbtiterator->common.version; rdatasetheader_t *header, *top_next; rbtdb_serial_t serial = 1; + isc_rwlocktype_t nlocktype = isc_rwlocktype_none; if (!IS_CACHE(rbtdb)) { serial = rbtversion->serial; } - NODE_LOCK(&rbtdb->node_locks[rbtnode->locknum].lock, - isc_rwlocktype_read); + NODE_RDLOCK(&rbtdb->node_locks[rbtnode->locknum].lock, &nlocktype); for (header = rbtnode->data; header != NULL; header = top_next) { top_next = header->next; @@ -8692,8 +8825,7 @@ rdatasetiter_first(dns_rdatasetiter_t *iterator) { } } - NODE_UNLOCK(&rbtdb->node_locks[rbtnode->locknum].lock, - isc_rwlocktype_read); + NODE_UNLOCK(&rbtdb->node_locks[rbtnode->locknum].lock, &nlocktype); rbtiterator->current = header; @@ -8714,6 +8846,7 @@ rdatasetiter_next(dns_rdatasetiter_t *iterator) { rbtdb_rdatatype_t type, negtype; dns_rdatatype_t rdtype, covers; rbtdb_serial_t serial = 1; + isc_rwlocktype_t nlocktype = isc_rwlocktype_none; header = rbtiterator->current; if (header == NULL) { @@ -8724,8 +8857,7 @@ rdatasetiter_next(dns_rdatasetiter_t *iterator) { serial = rbtversion->serial; } - NODE_LOCK(&rbtdb->node_locks[rbtnode->locknum].lock, - isc_rwlocktype_read); + NODE_RDLOCK(&rbtdb->node_locks[rbtnode->locknum].lock, &nlocktype); type = header->type; rdtype = RBTDB_RDATATYPE_BASE(header->type); @@ -8762,8 +8894,7 @@ rdatasetiter_next(dns_rdatasetiter_t *iterator) { } } - NODE_UNLOCK(&rbtdb->node_locks[rbtnode->locknum].lock, - isc_rwlocktype_read); + NODE_UNLOCK(&rbtdb->node_locks[rbtnode->locknum].lock, &nlocktype); rbtiterator->current = header; @@ -8780,18 +8911,17 @@ rdatasetiter_current(dns_rdatasetiter_t *iterator, dns_rdataset_t *rdataset) { dns_rbtdb_t *rbtdb = (dns_rbtdb_t *)(rbtiterator->common.db); dns_rbtnode_t *rbtnode = rbtiterator->common.node; rdatasetheader_t *header; + isc_rwlocktype_t nlocktype = isc_rwlocktype_none; header = rbtiterator->current; REQUIRE(header != NULL); - NODE_LOCK(&rbtdb->node_locks[rbtnode->locknum].lock, - isc_rwlocktype_read); + NODE_RDLOCK(&rbtdb->node_locks[rbtnode->locknum].lock, &nlocktype); bind_rdataset(rbtdb, rbtnode, header, rbtiterator->common.now, isc_rwlocktype_read, rdataset); - NODE_UNLOCK(&rbtdb->node_locks[rbtnode->locknum].lock, - isc_rwlocktype_read); + NODE_UNLOCK(&rbtdb->node_locks[rbtnode->locknum].lock, &nlocktype); } /* @@ -8816,7 +8946,7 @@ dereference_iter_node(rbtdb_dbiterator_t *rbtdbiter) { dns_rbtdb_t *rbtdb = (dns_rbtdb_t *)rbtdbiter->common.db; dns_rbtnode_t *node = rbtdbiter->node; nodelock_t *lock; - isc_rwlocktype_t nlocktype = isc_rwlocktype_read; + isc_rwlocktype_t nlocktype = isc_rwlocktype_none; isc_rwlocktype_t tlocktype = rbtdbiter->tree_locked; if (node == NULL) { @@ -8826,17 +8956,15 @@ dereference_iter_node(rbtdb_dbiterator_t *rbtdbiter) { REQUIRE(tlocktype != isc_rwlocktype_write); lock = &rbtdb->node_locks[node->locknum].lock; - NODE_LOCK(lock, nlocktype); + NODE_RDLOCK(lock, &nlocktype); decrement_reference(rbtdb, node, 0, &nlocktype, &rbtdbiter->tree_locked, false); - NODE_UNLOCK(lock, nlocktype); + NODE_UNLOCK(lock, &nlocktype); if (tlocktype != rbtdbiter->tree_locked) { - RWUNLOCK(&rbtdb->tree_lock, rbtdbiter->tree_locked); - rbtdbiter->tree_locked = isc_rwlocktype_none; + TREE_UNLOCK(&rbtdb->tree_lock, &rbtdbiter->tree_locked); if (tlocktype == isc_rwlocktype_read) { - RWLOCK(&rbtdb->tree_lock, tlocktype); - rbtdbiter->tree_locked = tlocktype; + TREE_RDLOCK(&rbtdb->tree_lock, &rbtdbiter->tree_locked); } } INSIST(rbtdbiter->tree_locked == tlocktype); @@ -8865,32 +8993,28 @@ flush_deletions(rbtdb_dbiterator_t *rbtdbiter) { rbtdbiter->delcnt, dns_rbt_nodecount(rbtdb->tree)); if (rbtdbiter->tree_locked == isc_rwlocktype_read) { - RWUNLOCK(&rbtdb->tree_lock, tlocktype); - rbtdbiter->tree_locked = isc_rwlocktype_none; + TREE_UNLOCK(&rbtdb->tree_lock, &rbtdbiter->tree_locked); } INSIST(rbtdbiter->tree_locked == isc_rwlocktype_none); - rbtdbiter->tree_locked = isc_rwlocktype_write; - RWLOCK(&rbtdb->tree_lock, rbtdbiter->tree_locked); + TREE_WRLOCK(&rbtdb->tree_lock, &rbtdbiter->tree_locked); for (size_t i = 0; i < (size_t)rbtdbiter->delcnt; i++) { - isc_rwlocktype_t nlocktype = isc_rwlocktype_read; + isc_rwlocktype_t nlocktype = isc_rwlocktype_none; dns_rbtnode_t *node = rbtdbiter->deletions[i]; nodelock_t *lock = &rbtdb->node_locks[node->locknum].lock; - NODE_LOCK(lock, nlocktype); + NODE_RDLOCK(lock, &nlocktype); decrement_reference(rbtdb, node, 0, &nlocktype, &rbtdbiter->tree_locked, false); - NODE_UNLOCK(lock, nlocktype); + NODE_UNLOCK(lock, &nlocktype); } rbtdbiter->delcnt = 0; - RWUNLOCK(&rbtdb->tree_lock, rbtdbiter->tree_locked); - rbtdbiter->tree_locked = isc_rwlocktype_none; + TREE_UNLOCK(&rbtdb->tree_lock, &rbtdbiter->tree_locked); if (tlocktype == isc_rwlocktype_read) { - RWLOCK(&rbtdb->tree_lock, tlocktype); - rbtdbiter->tree_locked = tlocktype; + TREE_RDLOCK(&rbtdb->tree_lock, &rbtdbiter->tree_locked); } INSIST(rbtdbiter->tree_locked == tlocktype); } @@ -8902,8 +9026,7 @@ resume_iteration(rbtdb_dbiterator_t *rbtdbiter) { REQUIRE(rbtdbiter->paused); REQUIRE(rbtdbiter->tree_locked == isc_rwlocktype_none); - RWLOCK(&rbtdb->tree_lock, isc_rwlocktype_read); - rbtdbiter->tree_locked = isc_rwlocktype_read; + TREE_RDLOCK(&rbtdb->tree_lock, &rbtdbiter->tree_locked); rbtdbiter->paused = false; } @@ -8915,8 +9038,7 @@ dbiterator_destroy(dns_dbiterator_t **iteratorp) { dns_db_t *db = NULL; if (rbtdbiter->tree_locked == isc_rwlocktype_read) { - RWUNLOCK(&rbtdb->tree_lock, isc_rwlocktype_read); - rbtdbiter->tree_locked = isc_rwlocktype_none; + TREE_UNLOCK(&rbtdb->tree_lock, &rbtdbiter->tree_locked); } INSIST(rbtdbiter->tree_locked == isc_rwlocktype_none); @@ -9307,8 +9429,7 @@ dbiterator_pause(dns_dbiterator_t *iterator) { rbtdbiter->paused = true; if (rbtdbiter->tree_locked == isc_rwlocktype_read) { - RWUNLOCK(&rbtdb->tree_lock, isc_rwlocktype_read); - rbtdbiter->tree_locked = isc_rwlocktype_none; + TREE_UNLOCK(&rbtdb->tree_lock, &rbtdbiter->tree_locked); } INSIST(rbtdbiter->tree_locked == isc_rwlocktype_none); @@ -9359,14 +9480,13 @@ rdataset_setownercase(dns_rdataset_t *rdataset, const dns_name_t *name) { dns_rbtnode_t *rbtnode = rdataset->private2; unsigned char *raw = rdataset->private3; /* RDATASLAB */ rdatasetheader_t *header; + isc_rwlocktype_t nlocktype = isc_rwlocktype_none; header = (struct rdatasetheader *)(raw - sizeof(*header)); - NODE_LOCK(&rbtdb->node_locks[rbtnode->locknum].lock, - isc_rwlocktype_write); + NODE_WRLOCK(&rbtdb->node_locks[rbtnode->locknum].lock, &nlocktype); setownercase(header, name); - NODE_UNLOCK(&rbtdb->node_locks[rbtnode->locknum].lock, - isc_rwlocktype_write); + NODE_UNLOCK(&rbtdb->node_locks[rbtnode->locknum].lock, &nlocktype); } static void @@ -9377,11 +9497,11 @@ rdataset_getownercase(const dns_rdataset_t *rdataset, dns_name_t *name) { rdatasetheader_t *header = NULL; uint8_t mask = (1 << 7); uint8_t bits = 0; + isc_rwlocktype_t nlocktype = isc_rwlocktype_none; header = (struct rdatasetheader *)(raw - sizeof(*header)); - NODE_LOCK(&rbtdb->node_locks[rbtnode->locknum].lock, - isc_rwlocktype_read); + NODE_RDLOCK(&rbtdb->node_locks[rbtnode->locknum].lock, &nlocktype); if (!CASESET(header)) { goto unlock; @@ -9404,8 +9524,7 @@ rdataset_getownercase(const dns_rdataset_t *rdataset, dns_name_t *name) { } unlock: - NODE_UNLOCK(&rbtdb->node_locks[rbtnode->locknum].lock, - isc_rwlocktype_read); + NODE_UNLOCK(&rbtdb->node_locks[rbtnode->locknum].lock, &nlocktype); } struct rbtdb_glue { @@ -10024,8 +10143,8 @@ overmem_purge(dns_rbtdb_t *rbtdb, unsigned int locknum_start, isc_stdtime_t now, locknum != locknum_start && purgecount > 0; locknum = (locknum + 1) % rbtdb->node_lock_count) { - NODE_LOCK(&rbtdb->node_locks[locknum].lock, - isc_rwlocktype_write); + isc_rwlocktype_t nlocktype = isc_rwlocktype_none; + NODE_WRLOCK(&rbtdb->node_locks[locknum].lock, &nlocktype); header = isc_heap_element(rbtdb->heaps[locknum], 1); if (header && header->rdh_ttl < now - RBTDB_VIRTUAL) { @@ -10050,8 +10169,7 @@ overmem_purge(dns_rbtdb_t *rbtdb, unsigned int locknum_start, isc_stdtime_t now, purgecount--; } - NODE_UNLOCK(&rbtdb->node_locks[locknum].lock, - isc_rwlocktype_write); + NODE_UNLOCK(&rbtdb->node_locks[locknum].lock, &nlocktype); } }