}
/*
- * Caller must be holding the node lock.
+ * The caller must specify its currect node and tree lock status.
+ * It's okay for neither lock to be held if there are existing external
+ * references to the node, but if this is the first external reference,
+ * then the caller must be holding at least one lock.
*/
static void
-newref(dns_qpdb_t *qpdb, dns_qpdata_t *node,
- isc_rwlocktype_t nlocktype DNS__DB_FLARG) {
+newref(dns_qpdb_t *qpdb, dns_qpdata_t *node, isc_rwlocktype_t nlocktype,
+ isc_rwlocktype_t tlocktype DNS__DB_FLARG) {
uint_fast32_t refs;
if (nlocktype == isc_rwlocktype_write &&
#if DNS_DB_NODETRACE
fprintf(stderr, "incr:node:%s:%s:%u:%p->erefs = %" PRIuFAST32 "\n",
func, file, line, node, refs + 1);
-#else
- UNUSED(refs);
#endif
if (refs == 0) {
- /* this is the first external reference to the node */
+ /*
+ * this is the first external reference to the node.
+ *
+ * we need to hold the node or tree lock to avoid
+ * incrementing the reference count while also deleting
+ * the node. delete_node() is always protected by both
+ * tree and node locks being write-locked.
+ */
+ INSIST(nlocktype != isc_rwlocktype_none ||
+ tlocktype != isc_rwlocktype_none);
+
refs = isc_refcount_increment0(
&qpdb->node_locks[node->locknum].references);
#if DNS_DB_NODETRACE
* Caller must hold the node (write) lock.
*/
static void
-expireheader(dns_slabheader_t *header, isc_rwlocktype_t *tlocktypep,
- dns_expire_t reason DNS__DB_FLARG) {
+expireheader(dns_slabheader_t *header, isc_rwlocktype_t *nlocktypep,
+ isc_rwlocktype_t *tlocktypep, dns_expire_t reason DNS__DB_FLARG) {
setttl(header, 0);
mark(header, DNS_SLABHEADERATTR_ANCIENT);
QPDB_HEADERNODE(header)->dirty = 1;
if (isc_refcount_current(&QPDB_HEADERNODE(header)->erefs) == 0) {
- isc_rwlocktype_t nlocktype = isc_rwlocktype_write;
dns_qpdb_t *qpdb = (dns_qpdb_t *)header->db;
/*
* We first need to gain a new reference to the node to meet a
* requirement of decref().
*/
- newref(qpdb, QPDB_HEADERNODE(header),
- nlocktype DNS__DB_FLARG_PASS);
- decref(qpdb, QPDB_HEADERNODE(header), 0, &nlocktype, tlocktypep,
+ newref(qpdb, QPDB_HEADERNODE(header), *nlocktypep,
+ *tlocktypep DNS__DB_FLARG_PASS);
+ decref(qpdb, QPDB_HEADERNODE(header), 0, nlocktypep, tlocktypep,
true, false DNS__DB_FLARG_PASS);
if (qpdb->cachestats == NULL) {
static void
bindrdataset(dns_qpdb_t *qpdb, dns_qpdata_t *node, dns_slabheader_t *header,
- isc_stdtime_t now, isc_rwlocktype_t locktype,
+ isc_stdtime_t now, isc_rwlocktype_t nlocktype,
+ isc_rwlocktype_t tlocktype,
dns_rdataset_t *rdataset DNS__DB_FLARG) {
bool stale = STALE(header);
bool ancient = ANCIENT(header);
return;
}
- newref(qpdb, node, locktype DNS__DB_FLARG_PASS);
+ newref(qpdb, node, nlocktype, tlocktype DNS__DB_FLARG_PASS);
INSIST(rdataset->methods == NULL); /* We must be disassociated. */
static isc_result_t
setup_delegation(qpdb_search_t *search, dns_dbnode_t **nodep,
dns_name_t *foundname, dns_rdataset_t *rdataset,
- dns_rdataset_t *sigrdataset DNS__DB_FLARG) {
+ dns_rdataset_t *sigrdataset,
+ isc_rwlocktype_t tlocktype DNS__DB_FLARG) {
dns_name_t *zcname = NULL;
dns_typepair_t type;
dns_qpdata_t *node = NULL;
NODE_RDLOCK(&(search->qpdb->node_locks[node->locknum].lock),
&nlocktype);
bindrdataset(search->qpdb, node, search->zonecut_header,
- search->now, isc_rwlocktype_read,
+ search->now, nlocktype, tlocktype,
rdataset DNS__DB_FLARG_PASS);
if (sigrdataset != NULL && search->zonecut_sigheader != NULL) {
bindrdataset(search->qpdb, node,
search->zonecut_sigheader, search->now,
- isc_rwlocktype_read,
+ nlocktype, tlocktype,
sigrdataset DNS__DB_FLARG_PASS);
}
NODE_UNLOCK(&(search->qpdb->node_locks[node->locknum].lock),
* We increment the reference count on node to ensure that
* search->zonecut_header will still be valid later.
*/
- newref(search->qpdb, node, nlocktype DNS__DB_FLARG_PASS);
+ newref(search->qpdb, node, nlocktype,
+ isc_rwlocktype_none DNS__DB_FLARG_PASS);
search->zonecut = node;
search->zonecut_header = dname_header;
search->zonecut_sigheader = sigdname_header;
}
result = DNS_R_DELEGATION;
if (nodep != NULL) {
- newref(search->qpdb, node,
- nlocktype DNS__DB_FLARG_PASS);
+ newref(search->qpdb, node, nlocktype,
+ isc_rwlocktype_none DNS__DB_FLARG_PASS);
*nodep = node;
}
bindrdataset(search->qpdb, node, found, search->now,
- nlocktype, rdataset DNS__DB_FLARG_PASS);
+ nlocktype, isc_rwlocktype_none,
+ rdataset DNS__DB_FLARG_PASS);
if (foundsig != NULL) {
bindrdataset(search->qpdb, node, foundsig,
search->now, nlocktype,
+ isc_rwlocktype_none,
sigrdataset DNS__DB_FLARG_PASS);
}
if (need_headerupdate(found, search->now) ||
}
if (found != NULL) {
bindrdataset(search->qpdb, node, found, now, nlocktype,
- rdataset DNS__DB_FLARG_PASS);
+ isc_rwlocktype_none, rdataset DNS__DB_FLARG_PASS);
if (foundsig != NULL) {
bindrdataset(search->qpdb, node, foundsig, now,
- nlocktype, sigrdataset DNS__DB_FLARG_PASS);
+ nlocktype, isc_rwlocktype_none,
+ sigrdataset DNS__DB_FLARG_PASS);
}
- newref(search->qpdb, node, nlocktype DNS__DB_FLARG_PASS);
+ newref(search->qpdb, node, nlocktype,
+ isc_rwlocktype_none DNS__DB_FLARG_PASS);
dns_name_copy(fname, foundname);
}
}
if (search.zonecut != NULL) {
- result = setup_delegation(
- &search, nodep, foundname, rdataset,
- sigrdataset DNS__DB_FLARG_PASS);
+ result = setup_delegation(&search, nodep, foundname,
+ rdataset, sigrdataset,
+ tlocktype DNS__DB_FLARG_PASS);
goto tree_exit;
} else {
find_ns:
nsecheader != NULL)
{
if (nodep != NULL) {
- newref(search.qpdb, node,
- nlocktype DNS__DB_FLARG_PASS);
+ newref(search.qpdb, node, nlocktype,
+ tlocktype DNS__DB_FLARG_PASS);
*nodep = node;
}
bindrdataset(search.qpdb, node, nsecheader, search.now,
- nlocktype, rdataset DNS__DB_FLARG_PASS);
+ nlocktype, tlocktype,
+ rdataset DNS__DB_FLARG_PASS);
if (need_headerupdate(nsecheader, search.now)) {
update = nsecheader;
}
if (nsecsig != NULL) {
bindrdataset(search.qpdb, node, nsecsig,
- search.now, nlocktype,
+ search.now, nlocktype, tlocktype,
sigrdataset DNS__DB_FLARG_PASS);
if (need_headerupdate(nsecsig, search.now)) {
updatesig = nsecsig;
*/
if (nsheader != NULL) {
if (nodep != NULL) {
- newref(search.qpdb, node,
- nlocktype DNS__DB_FLARG_PASS);
+ newref(search.qpdb, node, nlocktype,
+ tlocktype DNS__DB_FLARG_PASS);
*nodep = node;
}
bindrdataset(search.qpdb, node, nsheader, search.now,
- nlocktype, rdataset DNS__DB_FLARG_PASS);
+ nlocktype, tlocktype,
+ rdataset DNS__DB_FLARG_PASS);
if (need_headerupdate(nsheader, search.now)) {
update = nsheader;
}
if (nssig != NULL) {
bindrdataset(search.qpdb, node, nssig,
- search.now, nlocktype,
+ search.now, nlocktype, tlocktype,
sigrdataset DNS__DB_FLARG_PASS);
if (need_headerupdate(nssig, search.now)) {
updatesig = nssig;
*/
if (nodep != NULL) {
- newref(search.qpdb, node, nlocktype DNS__DB_FLARG_PASS);
+ newref(search.qpdb, node, nlocktype,
+ tlocktype DNS__DB_FLARG_PASS);
*nodep = node;
}
result == DNS_R_NCACHENXRRSET)
{
bindrdataset(search.qpdb, node, found, search.now, nlocktype,
- rdataset DNS__DB_FLARG_PASS);
+ tlocktype, rdataset DNS__DB_FLARG_PASS);
if (need_headerupdate(found, search.now)) {
update = found;
}
if (!NEGATIVE(found) && foundsig != NULL) {
bindrdataset(search.qpdb, node, foundsig, search.now,
- nlocktype, sigrdataset DNS__DB_FLARG_PASS);
+ nlocktype, tlocktype,
+ sigrdataset DNS__DB_FLARG_PASS);
if (need_headerupdate(foundsig, search.now)) {
updatesig = foundsig;
}
}
if (nodep != NULL) {
- newref(search.qpdb, node, nlocktype DNS__DB_FLARG_PASS);
+ newref(search.qpdb, node, nlocktype,
+ tlocktype DNS__DB_FLARG_PASS);
*nodep = node;
}
- bindrdataset(search.qpdb, node, found, search.now, nlocktype,
+ bindrdataset(search.qpdb, node, found, search.now, nlocktype, tlocktype,
rdataset DNS__DB_FLARG_PASS);
if (foundsig != NULL) {
bindrdataset(search.qpdb, node, foundsig, search.now, nlocktype,
- sigrdataset DNS__DB_FLARG_PASS);
+ tlocktype, sigrdataset DNS__DB_FLARG_PASS);
}
if (need_headerupdate(found, search.now) ||
}
if (found != NULL) {
bindrdataset(qpdb, qpnode, found, now, nlocktype,
- rdataset DNS__DB_FLARG_PASS);
+ isc_rwlocktype_none, rdataset DNS__DB_FLARG_PASS);
if (!NEGATIVE(found) && foundsig != NULL) {
bindrdataset(qpdb, qpnode, foundsig, now, nlocktype,
+ isc_rwlocktype_none,
sigrdataset DNS__DB_FLARG_PASS);
}
}
isc_rwlocktype_t tlocktype = isc_rwlocktype_none;
NODE_WRLOCK(&qpdb->node_locks[qpnode->locknum].lock, &nlocktype);
- expireheader(header, &tlocktype, dns_expire_flush DNS__DB_FILELINE);
+ expireheader(header, &nlocktype, &tlocktype,
+ dns_expire_flush DNS__DB_FILELINE);
NODE_UNLOCK(&qpdb->node_locks[qpnode->locknum].lock, &nlocktype);
INSIST(tlocktype == isc_rwlocktype_none);
}
static size_t
expire_lru_headers(dns_qpdb_t *qpdb, unsigned int locknum,
- isc_rwlocktype_t *tlocktypep,
+ isc_rwlocktype_t *nlocktypep, isc_rwlocktype_t *tlocktypep,
size_t purgesize DNS__DB_FLARG) {
dns_slabheader_t *header = NULL;
size_t purged = 0;
* TTL will be reset to 0.
*/
ISC_LIST_UNLINK(qpdb->lru[locknum], header, link);
- expireheader(header, tlocktypep,
+ expireheader(header, nlocktypep, tlocktypep,
dns_expire_lru DNS__DB_FLARG_PASS);
purged += header_size;
}
isc_rwlocktype_t nlocktype = isc_rwlocktype_none;
NODE_WRLOCK(&qpdb->node_locks[locknum].lock, &nlocktype);
- purged += expire_lru_headers(qpdb, locknum, tlocktypep,
- purgesize -
- purged DNS__DB_FLARG_PASS);
+ purged += expire_lru_headers(
+ qpdb, locknum, &nlocktype, tlocktypep,
+ purgesize - purged DNS__DB_FLARG_PASS);
/*
* Work out the oldest remaining last_used values of the list
}
}
- newref(qpdb, node, nlocktype DNS__DB_FLARG_PASS);
+ newref(qpdb, node, nlocktype, tlocktype DNS__DB_FLARG_PASS);
NODE_UNLOCK(nodelock, &nlocktype);
}
dns_qpdb_t *qpdb = (dns_qpdb_t *)db;
dns_qpdata_t *node = (dns_qpdata_t *)source;
- newref(qpdb, node, isc_rwlocktype_none DNS__DB_FLARG_PASS);
+ newref(qpdb, node, isc_rwlocktype_none,
+ isc_rwlocktype_none DNS__DB_FLARG_PASS);
*targetp = source;
}
iterator->common.now = now;
iterator->current = NULL;
- newref(qpdb, qpnode, isc_rwlocktype_none DNS__DB_FLARG_PASS);
+ newref(qpdb, qpnode, isc_rwlocktype_none,
+ isc_rwlocktype_none DNS__DB_FLARG_PASS);
*iteratorp = (dns_rdatasetiter_t *)iterator;
add(dns_qpdb_t *qpdb, dns_qpdata_t *qpnode,
const dns_name_t *nodename ISC_ATTR_UNUSED, dns_slabheader_t *newheader,
unsigned int options, bool loading, dns_rdataset_t *addedrdataset,
- isc_stdtime_t now DNS__DB_FLARG) {
+ isc_stdtime_t now, isc_rwlocktype_t nlocktype,
+ isc_rwlocktype_t tlocktype DNS__DB_FLARG) {
dns_slabheader_t *topheader = NULL, *topheader_prev = NULL;
dns_slabheader_t *header = NULL, *sigheader = NULL;
dns_slabheader_t *prioheader = NULL;
if (addedrdataset != NULL) {
bindrdataset(
qpdb, qpnode, topheader,
- now,
- isc_rwlocktype_write,
+ now, nlocktype,
+ tlocktype,
addedrdataset
DNS__DB_FLARG_PASS);
}
dns_slabheader_destroy(&newheader);
if (addedrdataset != NULL) {
bindrdataset(qpdb, qpnode, header, now,
- isc_rwlocktype_write,
+ nlocktype, tlocktype,
addedrdataset DNS__DB_FLARG_PASS);
}
return (DNS_R_UNCHANGED);
dns_slabheader_destroy(&newheader);
if (addedrdataset != NULL) {
bindrdataset(qpdb, qpnode, header, now,
- isc_rwlocktype_write,
+ nlocktype, tlocktype,
addedrdataset DNS__DB_FLARG_PASS);
}
return (ISC_R_SUCCESS);
dns_slabheader_destroy(&newheader);
if (addedrdataset != NULL) {
bindrdataset(qpdb, qpnode, header, now,
- isc_rwlocktype_write,
+ nlocktype, tlocktype,
addedrdataset DNS__DB_FLARG_PASS);
}
return (ISC_R_SUCCESS);
}
if (addedrdataset != NULL) {
- bindrdataset(qpdb, qpnode, newheader, now, isc_rwlocktype_write,
+ bindrdataset(qpdb, qpnode, newheader, now, nlocktype, tlocktype,
addedrdataset DNS__DB_FLARG_PASS);
}
static void
expire_ttl_headers(dns_qpdb_t *qpdb, unsigned int locknum,
- isc_rwlocktype_t *tlocktypep, isc_stdtime_t now,
- bool cache_is_overmem DNS__DB_FLARG);
+ isc_rwlocktype_t *nlocktypep, isc_rwlocktype_t *tlocktypep,
+ isc_stdtime_t now, bool cache_is_overmem DNS__DB_FLARG);
static isc_result_t
addrdataset(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version,
cleanup_dead_nodes(qpdb, qpnode->locknum DNS__DB_FLARG_PASS);
}
- expire_ttl_headers(qpdb, qpnode->locknum, &tlocktype, now,
+ expire_ttl_headers(qpdb, qpnode->locknum, &nlocktype, &tlocktype, now,
cache_is_overmem DNS__DB_FLARG_PASS);
/*
if (result == ISC_R_SUCCESS) {
result = add(qpdb, qpnode, name, newheader, options, false,
- addedrdataset, now DNS__DB_FLARG_PASS);
+ addedrdataset, now, nlocktype,
+ tlocktype DNS__DB_FLARG_PASS);
}
if (result == ISC_R_SUCCESS && delegating) {
qpnode->find_callback = 1;
NODE_WRLOCK(&qpdb->node_locks[qpnode->locknum].lock, &nlocktype);
result = add(qpdb, qpnode, NULL, newheader, DNS_DBADD_FORCE, false,
- NULL, 0 DNS__DB_FLARG_PASS);
+ NULL, 0, nlocktype,
+ isc_rwlocktype_none DNS__DB_FLARG_PASS);
NODE_UNLOCK(&qpdb->node_locks[qpnode->locknum].lock, &nlocktype);
return (result);
/* Note that the access to origin_node doesn't require a DB lock */
onode = (dns_qpdata_t *)qpdb->origin_node;
if (onode != NULL) {
- newref(qpdb, onode, isc_rwlocktype_none DNS__DB_FLARG_PASS);
+ newref(qpdb, onode, isc_rwlocktype_none,
+ isc_rwlocktype_none DNS__DB_FLARG_PASS);
*nodep = qpdb->origin_node;
} else {
result = ISC_R_NOTFOUND;
NODE_RDLOCK(&qpdb->node_locks[qpnode->locknum].lock, &nlocktype);
- bindrdataset(qpdb, qpnode, header, rbtiterator->common.now,
- isc_rwlocktype_read, rdataset DNS__DB_FLARG_PASS);
+ bindrdataset(qpdb, qpnode, header, rbtiterator->common.now, nlocktype,
+ isc_rwlocktype_none, rdataset DNS__DB_FLARG_PASS);
NODE_UNLOCK(&qpdb->node_locks[qpnode->locknum].lock, &nlocktype);
}
result = ISC_R_SUCCESS;
}
- newref(qpdb, node, isc_rwlocktype_none DNS__DB_FLARG_PASS);
+ newref(qpdb, node, isc_rwlocktype_none,
+ qpdbiter->tree_locked DNS__DB_FLARG_PASS);
*nodep = qpdbiter->node;
*/
static void
expire_ttl_headers(dns_qpdb_t *qpdb, unsigned int locknum,
- isc_rwlocktype_t *tlocktypep, isc_stdtime_t now,
- bool cache_is_overmem DNS__DB_FLARG) {
+ isc_rwlocktype_t *nlocktypep, isc_rwlocktype_t *tlocktypep,
+ isc_stdtime_t now, bool cache_is_overmem DNS__DB_FLARG) {
isc_heap_t *heap = qpdb->heaps[locknum];
for (size_t i = 0; i < DNS_QPDB_EXPIRE_TTL_COUNT; i++) {
return;
}
- expireheader(header, tlocktypep,
+ expireheader(header, tlocktypep, nlocktypep,
dns_expire_ttl DNS__DB_FLARG_PASS);
}
}