* Caller must be holding the node lock.
*/
static inline void
-new_reference(dns_rbtdb_t *rbtdb, dns_rbtnode_t *node) {
- INSIST(!ISC_LINK_LINKED(node, deadlink));
+new_reference(dns_rbtdb_t *rbtdb, dns_rbtnode_t *node,
+ isc_rwlocktype_t locktype) {
+ if (locktype == isc_rwlocktype_write && ISC_LINK_LINKED(node, deadlink))
+ {
+ ISC_LIST_UNLINK(rbtdb->deadnodes[node->locknum], node,
+ deadlink);
+ }
if (isc_refcount_increment0(&node->references) == 0) {
/* this is the first reference to the node */
isc_refcount_increment0(
}
static inline void
-send_to_prune_tree(dns_rbtdb_t *rbtdb, dns_rbtnode_t *node) {
+send_to_prune_tree(dns_rbtdb_t *rbtdb, dns_rbtnode_t *node,
+ isc_rwlocktype_t locktype) {
isc_event_t *ev;
dns_db_t *db;
ev = isc_event_allocate(rbtdb->common.mctx, NULL, DNS_EVENT_RBTPRUNE,
prune_tree, node, sizeof(isc_event_t));
- new_reference(rbtdb, node);
+ new_reference(rbtdb, node, locktype);
db = NULL;
attach((dns_db_t *)rbtdb, &db);
ev->ev_sender = db;
node->data == NULL);
if (is_leaf(node) && rbtdb->task != NULL) {
- send_to_prune_tree(rbtdb, node);
+ send_to_prune_tree(rbtdb, node, isc_rwlocktype_write);
} else if (node->down == NULL && node->data == NULL) {
/*
* Not a interior node and not needing to be
}
}
- new_reference(rbtdb, node);
+ new_reference(rbtdb, node, locktype);
NODE_UNLOCK(nodelock, locktype);
}
* periodic walk-through).
*/
if (!pruning && is_leaf(node) && rbtdb->task != NULL) {
- send_to_prune_tree(rbtdb, node);
+ send_to_prune_tree(rbtdb, node, isc_rwlocktype_write);
no_reference = false;
} else {
delete_node(rbtdb, node);
}
} else {
INSIST(node->data == NULL);
- INSIST(!ISC_LINK_LINKED(node, deadlink));
- ISC_LIST_APPEND(rbtdb->deadnodes[bucket], node, deadlink);
+ if (!ISC_LINK_LINKED(node, deadlink)) {
+ ISC_LIST_APPEND(rbtdb->deadnodes[bucket], node,
+ deadlink);
+ }
}
restore_locks:
/*
* We need to gain a reference to the node before
- * decrementing it in the next iteration. In addition,
- * if the node is in the dead-nodes list, extract it
- * from the list beforehand as we do in
- * reactivate_node().
+ * decrementing it in the next iteration.
*/
if (ISC_LINK_LINKED(parent, deadlink)) {
ISC_LIST_UNLINK(rbtdb->deadnodes[locknum],
parent, deadlink);
}
- new_reference(rbtdb, parent);
+ new_reference(rbtdb, parent, isc_rwlocktype_write);
} else {
parent = NULL;
}
* We increment the reference count on node to ensure that
* search->zonecut_rdataset will still be valid later.
*/
- new_reference(search->rbtdb, node);
+ new_reference(search->rbtdb, node, isc_rwlocktype_read);
search->zonecut = node;
search->zonecut_rdataset = found;
search->need_cleanup = true;
static inline void
bind_rdataset(dns_rbtdb_t *rbtdb, dns_rbtnode_t *node, rdatasetheader_t *header,
- isc_stdtime_t now, dns_rdataset_t *rdataset) {
+ isc_stdtime_t now, isc_rwlocktype_t locktype,
+ dns_rdataset_t *rdataset) {
unsigned char *raw; /* RDATASLAB */
/*
return;
}
- new_reference(rbtdb, node);
+ new_reference(rbtdb, node, locktype);
INSIST(rdataset->methods == NULL); /* We must be disassociated. */
NODE_LOCK(&(search->rbtdb->node_locks[node->locknum].lock),
isc_rwlocktype_read);
bind_rdataset(search->rbtdb, node, search->zonecut_rdataset,
- search->now, rdataset);
+ search->now, isc_rwlocktype_read, rdataset);
if (sigrdataset != NULL && search->zonecut_sigrdataset != NULL)
{
bind_rdataset(search->rbtdb, node,
search->zonecut_sigrdataset, search->now,
- sigrdataset);
+ isc_rwlocktype_read, sigrdataset);
}
NODE_UNLOCK(&(search->rbtdb->node_locks[node->locknum].lock),
isc_rwlocktype_read);
foundname, NULL);
if (result == ISC_R_SUCCESS) {
if (nodep != NULL) {
- new_reference(search->rbtdb,
- node);
+ new_reference(
+ search->rbtdb, node,
+ isc_rwlocktype_read);
*nodep = node;
}
bind_rdataset(search->rbtdb, node,
found, search->now,
+ isc_rwlocktype_read,
rdataset);
if (foundsig != NULL) {
- bind_rdataset(search->rbtdb,
- node, foundsig,
- search->now,
- sigrdataset);
+ bind_rdataset(
+ search->rbtdb, node,
+ foundsig, search->now,
+ isc_rwlocktype_read,
+ sigrdataset);
}
}
} else if (found == NULL && foundsig == NULL) {
* ensure that search->zonecut_rdataset will
* still be valid later.
*/
- new_reference(search.rbtdb, node);
+ new_reference(search.rbtdb, node,
+ isc_rwlocktype_read);
search.zonecut = node;
search.zonecut_rdataset = header;
search.zonecut_sigrdataset = NULL;
goto node_exit;
}
if (nodep != NULL) {
- new_reference(search.rbtdb, node);
+ new_reference(search.rbtdb, node, isc_rwlocktype_read);
*nodep = node;
}
if ((search.rbtversion->secure == dns_db_secure &&
(search.options & DNS_DBFIND_FORCENSEC) != 0)
{
bind_rdataset(search.rbtdb, node, nsecheader, 0,
- rdataset);
+ isc_rwlocktype_read, rdataset);
if (nsecsig != NULL) {
bind_rdataset(search.rbtdb, node, nsecsig, 0,
- sigrdataset);
+ isc_rwlocktype_read, sigrdataset);
}
}
if (wild) {
if (nodep != NULL) {
if (!at_zonecut) {
- new_reference(search.rbtdb, node);
+ new_reference(search.rbtdb, node, isc_rwlocktype_read);
} else {
search.need_cleanup = false;
}
}
if (type != dns_rdatatype_any) {
- bind_rdataset(search.rbtdb, node, found, 0, rdataset);
+ bind_rdataset(search.rbtdb, node, found, 0, isc_rwlocktype_read,
+ rdataset);
if (foundsig != NULL) {
bind_rdataset(search.rbtdb, node, foundsig, 0,
- sigrdataset);
+ isc_rwlocktype_read, sigrdataset);
}
}
* We increment the reference count on node to ensure that
* search->zonecut_rdataset will still be valid later.
*/
- new_reference(search->rbtdb, node);
- INSIST(!ISC_LINK_LINKED(node, deadlink));
+ new_reference(search->rbtdb, node, locktype);
search->zonecut = node;
search->zonecut_rdataset = dname_header;
search->zonecut_sigrdataset = sigdname_header;
}
result = DNS_R_DELEGATION;
if (nodep != NULL) {
- new_reference(search->rbtdb, node);
+ new_reference(search->rbtdb, node, locktype);
*nodep = node;
}
bind_rdataset(search->rbtdb, node, found, search->now,
- rdataset);
+ locktype, rdataset);
if (foundsig != NULL) {
bind_rdataset(search->rbtdb, node, foundsig,
- search->now, sigrdataset);
+ search->now, locktype,
+ sigrdataset);
}
if (need_headerupdate(found, search->now) ||
(foundsig != NULL &&
if (result != ISC_R_SUCCESS) {
goto unlock_node;
}
- bind_rdataset(search->rbtdb, node, found, now,
+ bind_rdataset(search->rbtdb, node, found, now, locktype,
rdataset);
if (foundsig != NULL) {
bind_rdataset(search->rbtdb, node, foundsig,
- now, sigrdataset);
+ now, locktype, sigrdataset);
}
- new_reference(search->rbtdb, node);
+ new_reference(search->rbtdb, node, locktype);
*nodep = node;
result = DNS_R_COVERINGNSEC;
} else if (!empty_node) {
if ((search.options & DNS_DBFIND_COVERINGNSEC) != 0 &&
nsecheader != NULL) {
if (nodep != NULL) {
- new_reference(search.rbtdb, node);
- INSIST(!ISC_LINK_LINKED(node, deadlink));
+ new_reference(search.rbtdb, node, locktype);
*nodep = node;
}
bind_rdataset(search.rbtdb, node, nsecheader,
- search.now, rdataset);
+ search.now, locktype, rdataset);
if (need_headerupdate(nsecheader, search.now)) {
update = nsecheader;
}
if (nsecsig != NULL) {
bind_rdataset(search.rbtdb, node, nsecsig,
- search.now, sigrdataset);
+ search.now, locktype,
+ sigrdataset);
if (need_headerupdate(nsecsig, search.now)) {
updatesig = nsecsig;
}
*/
if (nsheader != NULL) {
if (nodep != NULL) {
- new_reference(search.rbtdb, node);
- INSIST(!ISC_LINK_LINKED(node, deadlink));
+ new_reference(search.rbtdb, node, locktype);
*nodep = node;
}
bind_rdataset(search.rbtdb, node, nsheader, search.now,
- rdataset);
+ locktype, rdataset);
if (need_headerupdate(nsheader, search.now)) {
update = nsheader;
}
if (nssig != NULL) {
bind_rdataset(search.rbtdb, node, nssig,
- search.now, sigrdataset);
+ search.now, locktype,
+ sigrdataset);
if (need_headerupdate(nssig, search.now)) {
updatesig = nssig;
}
*/
if (nodep != NULL) {
- new_reference(search.rbtdb, node);
- INSIST(!ISC_LINK_LINKED(node, deadlink));
+ new_reference(search.rbtdb, node, locktype);
*nodep = node;
}
if (type != dns_rdatatype_any || result == DNS_R_NCACHENXDOMAIN ||
result == DNS_R_NCACHENXRRSET)
{
- bind_rdataset(search.rbtdb, node, found, search.now, rdataset);
+ bind_rdataset(search.rbtdb, node, found, search.now, locktype,
+ rdataset);
if (need_headerupdate(found, search.now)) {
update = found;
}
if (!NEGATIVE(found) && foundsig != NULL) {
bind_rdataset(search.rbtdb, node, foundsig, search.now,
- sigrdataset);
+ locktype, sigrdataset);
if (need_headerupdate(foundsig, search.now)) {
updatesig = foundsig;
}
}
if (nodep != NULL) {
- new_reference(search.rbtdb, node);
- INSIST(!ISC_LINK_LINKED(node, deadlink));
+ new_reference(search.rbtdb, node, locktype);
*nodep = node;
}
- bind_rdataset(search.rbtdb, node, found, search.now, rdataset);
+ bind_rdataset(search.rbtdb, node, found, search.now, locktype,
+ rdataset);
if (foundsig != NULL) {
bind_rdataset(search.rbtdb, node, foundsig, search.now,
- sigrdataset);
+ locktype, sigrdataset);
}
if (need_headerupdate(found, search.now) ||
}
}
if (found != NULL) {
- bind_rdataset(rbtdb, rbtnode, found, now, rdataset);
+ bind_rdataset(rbtdb, rbtnode, found, now, isc_rwlocktype_read,
+ rdataset);
if (foundsig != NULL) {
bind_rdataset(rbtdb, rbtnode, foundsig, now,
- sigrdataset);
+ isc_rwlocktype_read, sigrdataset);
}
}
}
}
if (found != NULL) {
- bind_rdataset(rbtdb, rbtnode, found, now, rdataset);
+ bind_rdataset(rbtdb, rbtnode, found, now, locktype, rdataset);
if (!NEGATIVE(found) && foundsig != NULL) {
- bind_rdataset(rbtdb, rbtnode, foundsig, now,
+ bind_rdataset(rbtdb, rbtnode, foundsig, now, locktype,
sigrdataset);
}
}
return (result);
}
+/*
+ * node write lock must be held.
+ */
static void
resign_delete(dns_rbtdb_t *rbtdb, rbtdb_version_t *version,
rdatasetheader_t *header) {
header->heap_index);
header->heap_index = 0;
if (version != NULL) {
- new_reference(rbtdb, header->node);
+ new_reference(rbtdb, header->node,
+ isc_rwlocktype_write);
ISC_LIST_APPEND(version->resigned_list, header, link);
}
}
RWUNLOCK(&rbtversion->rwlock, isc_rwlocktype_write);
}
+/*
+ * write lock on rbtnode must be held.
+ */
static isc_result_t
add32(dns_rbtdb_t *rbtdb, dns_rbtnode_t *rbtnode, const dns_name_t *nodename,
rbtdb_version_t *rbtversion, rdatasetheader_t *newheader,
free_rdataset(rbtdb, rbtdb->common.mctx,
newheader);
if (addedrdataset != NULL) {
- bind_rdataset(rbtdb, rbtnode,
- topheader, now,
- addedrdataset);
+ bind_rdataset(
+ rbtdb, rbtnode,
+ topheader, now,
+ isc_rwlocktype_write,
+ addedrdataset);
}
return (DNS_R_UNCHANGED);
}
free_rdataset(rbtdb, rbtdb->common.mctx, newheader);
if (addedrdataset != NULL) {
bind_rdataset(rbtdb, rbtnode, header, now,
+ isc_rwlocktype_write,
addedrdataset);
}
return (DNS_R_UNCHANGED);
free_rdataset(rbtdb, rbtdb->common.mctx, newheader);
if (addedrdataset != NULL) {
bind_rdataset(rbtdb, rbtnode, header, now,
+ isc_rwlocktype_write,
addedrdataset);
}
return (ISC_R_SUCCESS);
free_rdataset(rbtdb, rbtdb->common.mctx, newheader);
if (addedrdataset != NULL) {
bind_rdataset(rbtdb, rbtnode, header, now,
+ isc_rwlocktype_write,
addedrdataset);
}
return (ISC_R_SUCCESS);
}
if (addedrdataset != NULL) {
- bind_rdataset(rbtdb, rbtnode, newheader, now, addedrdataset);
+ bind_rdataset(rbtdb, rbtnode, newheader, now,
+ isc_rwlocktype_write, addedrdataset);
}
return (ISC_R_SUCCESS);
}
if (result == ISC_R_SUCCESS && newrdataset != NULL) {
- bind_rdataset(rbtdb, rbtnode, newheader, 0, newrdataset);
+ bind_rdataset(rbtdb, rbtnode, newheader, 0,
+ isc_rwlocktype_write, newrdataset);
}
if (result == DNS_R_NXRRSET && newrdataset != NULL &&
(options & DNS_DBSUB_WANTOLD) != 0)
{
- bind_rdataset(rbtdb, rbtnode, header, 0, newrdataset);
+ bind_rdataset(rbtdb, rbtnode, header, 0, isc_rwlocktype_write,
+ newrdataset);
}
unlock:
/* Note that the access to origin_node doesn't require a DB lock */
onode = (dns_rbtnode_t *)rbtdb->origin_node;
if (onode != NULL) {
- new_reference(rbtdb, onode);
-
+ new_reference(rbtdb, onode, isc_rwlocktype_none);
*nodep = rbtdb->origin_node;
} else {
INSIST(IS_CACHE(rbtdb));
* Found something; pass back the answer and unlock
* the bucket.
*/
- bind_rdataset(rbtdb, header->node, header, 0, rdataset);
+ bind_rdataset(rbtdb, header->node, header, 0,
+ isc_rwlocktype_read, rdataset);
if (foundname != NULL) {
dns_rbt_fullnamefromnode(header->node, foundname);
isc_rwlocktype_read);
bind_rdataset(rbtdb, rbtnode, header, rbtiterator->common.now,
- rdataset);
+ isc_rwlocktype_read, rdataset);
NODE_UNLOCK(&rbtdb->node_locks[rbtnode->locknum].lock,
isc_rwlocktype_read);
result = ISC_R_SUCCESS;
}
- new_reference(rbtdb, node);
+ new_reference(rbtdb, node, isc_rwlocktype_none);
*nodep = rbtdbiter->node;
* We first need to gain a new reference to the node to meet a
* requirement of decrement_reference().
*/
- new_reference(rbtdb, header->node);
+ new_reference(rbtdb, header->node, isc_rwlocktype_write);
decrement_reference(rbtdb, header->node, 0,
isc_rwlocktype_write,
tree_locked ? isc_rwlocktype_write