}
#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_TRYLOCK(l, t, tp) \
- ({ \
- STRONG_RWLOCK_CHECK(*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) \
+#define NODE_FORCEUPGRADE(l, tp) \
({ \
STRONG_RWLOCK_CHECK(*tp == isc_rwlocktype_read); \
isc_result_t _result = isc_rwlock_tryupgrade(l); \
if (_result == ISC_R_SUCCESS) { \
*tp = isc_rwlocktype_write; \
+ } else { \
+ NODE_UNLOCK(l, tp); \
+ NODE_WRLOCK(l, tp); \
}; \
- _result; \
})
-#define NODE_FORCEUPGRADE(l, tp) \
- if (NODE_TRYUPGRADE(l, tp) != ISC_R_SUCCESS) { \
- NODE_UNLOCK(l, tp); \
- NODE_WRLOCK(l, tp); \
- }
#define TREE_INITLOCK(l) isc_rwlock_init(l)
#define TREE_DESTROYLOCK(l) isc_rwlock_destroy(l)
}
#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_TRYLOCK(l, t, tp) \
- ({ \
- STRONG_RWLOCK_CHECK(*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) \
+#define TREE_FORCEUPGRADE(l, tp) \
({ \
STRONG_RWLOCK_CHECK(*tp == isc_rwlocktype_read); \
isc_result_t _result = isc_rwlock_tryupgrade(l); \
if (_result == ISC_R_SUCCESS) { \
*tp = isc_rwlocktype_write; \
+ } else { \
+ TREE_UNLOCK(l, tp); \
+ TREE_WRLOCK(l, tp); \
}; \
- _result; \
})
-#define TREE_FORCEUPGRADE(l, tp) \
- if (TREE_TRYUPGRADE(l, tp) != ISC_R_SUCCESS) { \
- TREE_UNLOCK(l, tp); \
- TREE_WRLOCK(l, tp); \
- }
#define IS_STUB(db) (((db)->common.attributes & DNS_DBATTR_STUB) != 0)
#define IS_CACHE(db) (((db)->common.attributes & DNS_DBATTR_CACHE) != 0)
*/
static void
qpcnode_release(qpcache_t *qpdb, qpcnode_t *node, isc_rwlocktype_t *nlocktypep,
- isc_rwlocktype_t *tlocktypep, bool tryupgrade DNS__DB_FLARG) {
+ isc_rwlocktype_t *tlocktypep DNS__DB_FLARG) {
REQUIRE(*nlocktypep != isc_rwlocktype_none);
- isc_result_t result;
- bool locked = *tlocktypep != isc_rwlocktype_none;
- bool write_locked = false;
-
if (!qpcnode_erefs_decrement(qpdb, node DNS__DB_FLARG_PASS)) {
goto unref;
}
clean_cache_node(qpdb, 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.
- */
- /* We are allowed to upgrade the tree lock */
-
- switch (*tlocktypep) {
- case isc_rwlocktype_write:
- result = ISC_R_SUCCESS;
- break;
- case isc_rwlocktype_read:
- if (tryupgrade) {
- result = TREE_TRYUPGRADE(&qpdb->tree_lock, tlocktypep);
- } else {
- result = ISC_R_LOCKBUSY;
- }
- break;
- case isc_rwlocktype_none:
- result = TREE_TRYWRLOCK(&qpdb->tree_lock, tlocktypep);
- break;
- default:
- UNREACHABLE();
- }
- RUNTIME_CHECK(result == ISC_R_SUCCESS || result == ISC_R_LOCKBUSY);
- if (result == ISC_R_SUCCESS) {
- write_locked = true;
- }
-
if (node->data != NULL) {
- goto restore_locks;
+ goto unref;
}
- if (write_locked) {
+ if (*tlocktypep == isc_rwlocktype_write) {
/*
- * We can now delete the node.
+ * We can delete the node if we have the tree write lock.
*/
delete_node(qpdb, node);
} else {
+ /*
+ * If we don't have the tree lock, we will add this node to a
+ * linked list of nodes in this locking bucket which we will
+ * free later.
+ */
qpcnode_acquire(qpdb, node, *nlocktypep,
*tlocktypep DNS__DB_FLARG_PASS);
}
}
-restore_locks:
- /*
- * Unlock the tree lock if it wasn't held previously.
- */
- if (!locked && write_locked) {
- TREE_UNLOCK(&qpdb->tree_lock, tlocktypep);
- }
-
unref:
qpcnode_unref(node);
}
qpcnode_acquire(qpdb, HEADERNODE(header), *nlocktypep,
*tlocktypep DNS__DB_FLARG_PASS);
qpcnode_release(qpdb, HEADERNODE(header), nlocktypep,
- tlocktypep, true DNS__DB_FLARG_PASS);
+ tlocktypep DNS__DB_FLARG_PASS);
if (qpdb->cachestats == NULL) {
return;
}
static bool
-check_stale_header(qpcnode_t *node, dns_slabheader_t *header,
- isc_rwlocktype_t *nlocktypep, isc_rwlock_t *nlock,
- qpc_search_t *search, dns_slabheader_t **header_prev) {
+check_stale_header(dns_slabheader_t *header, qpc_search_t *search,
+ dns_slabheader_t **header_prev) {
if (ACTIVE(header, search->now)) {
*header_prev = header;
return false;
return (search->options & DNS_DBFIND_STALEOK) == 0;
}
- /*
- * This rdataset is stale. If no one else is using the
- * node, we can clean it up right now, otherwise we mark
- * it as ancient, and the node as dirty, so it will get
- * cleaned up later.
- */
- if ((header->expire < search->now - QPDB_VIRTUAL) &&
- (*nlocktypep == isc_rwlocktype_write ||
- NODE_TRYUPGRADE(nlock, nlocktypep) == ISC_R_SUCCESS))
- {
- /*
- * We update the node's status only when we can
- * get write access; otherwise, we leave others
- * to this work. Periodical cleaning will
- * eventually take the job as the last resort.
- * We won't downgrade the lock, since other
- * rdatasets are probably stale, too.
- */
- if (isc_refcount_current(&node->references) == 0) {
- clean_stale_headers(header);
- if (*header_prev != NULL) {
- (*header_prev)->next = header->next;
- } else {
- node->data = header->next;
- }
- dns_slabheader_destroy(&header);
- } else {
- mark_ancient(header);
- *header_prev = header;
- }
- } else {
- *header_prev = header;
- }
+ *header_prev = header;
return true;
}
*/
for (header = node->data; header != NULL; header = header_next) {
header_next = header->next;
- if (check_stale_header(node, header, &nlocktype, nlock, search,
- &header_prev))
- {
+ if (check_stale_header(header, search, &header_prev)) {
continue;
}
for (header = node->data; header != NULL; header = header_next)
{
header_next = header->next;
- if (check_stale_header(node, header, &nlocktype, nlock,
- search, &header_prev))
- {
+ if (check_stale_header(header, search, &header_prev)) {
continue;
}
NODE_RDLOCK(nlock, &nlocktype);
for (header = node->data; header != NULL; header = header_next) {
header_next = header->next;
- if (check_stale_header(node, header, &nlocktype, nlock, search,
- &header_prev))
- {
+ if (check_stale_header(header, search, &header_prev)) {
continue;
}
header_prev = NULL;
for (header = node->data; header != NULL; header = header_next) {
header_next = header->next;
- if (check_stale_header(node, header, &nlocktype, nlock, &search,
- &header_prev))
- {
+ if (check_stale_header(header, &search, &header_prev)) {
continue;
}
nlock = &search.qpdb->buckets[node->locknum].lock;
NODE_RDLOCK(nlock, &nlocktype);
- qpcnode_release(search.qpdb, node, &nlocktype, &tlocktype,
- true DNS__DB_FLARG_PASS);
+ qpcnode_release(search.qpdb, node, &nlocktype,
+ &tlocktype DNS__DB_FLARG_PASS);
NODE_UNLOCK(nlock, &nlocktype);
INSIST(tlocktype == isc_rwlocktype_none);
}
header_next = header->next;
bool ns = (header->type == dns_rdatatype_ns ||
header->type == DNS_SIGTYPE(dns_rdatatype_ns));
- if (check_stale_header(node, header, &nlocktype, nlock, search,
- &header_prev))
- {
+ if (check_stale_header(header, search, &header_prev)) {
if (ns) {
/*
* We found a cached NS, but was either
matchtype = DNS_TYPEPAIR_VALUE(type, covers);
negtype = DNS_TYPEPAIR_VALUE(0, type);
- if (covers == 0) {
- sigmatchtype = DNS_SIGTYPE(type);
- } else {
- sigmatchtype = 0;
- }
+ sigmatchtype = (covers == 0) ? DNS_SIGTYPE(type) : 0;
for (header = qpnode->data; header != NULL; header = header_next) {
header_next = header->next;
- if (check_stale_header(qpnode, header, &nlocktype, nlock,
- &search, &header_prev))
- {
+ if (check_stale_header(header, &search, &header_prev)) {
continue;
}
RUNTIME_CHECK(isc_queue_splice(&deadnodes,
&qpdb->buckets[locknum].deadnodes));
isc_queue_for_each_entry_safe(&deadnodes, qpnode, qpnext, deadlink) {
- qpcnode_release(qpdb, qpnode, &nlocktype, &tlocktype,
- false DNS__DB_FILELINE);
+ qpcnode_release(qpdb, qpnode, &nlocktype,
+ &tlocktype DNS__DB_FILELINE);
}
NODE_UNLOCK(nlock, &nlocktype);
rcu_read_lock();
NODE_RDLOCK(nlock, &nlocktype);
- qpcnode_release(qpdb, node, &nlocktype, &tlocktype,
- true DNS__DB_FLARG_PASS);
+ qpcnode_release(qpdb, node, &nlocktype, &tlocktype DNS__DB_FLARG_PASS);
NODE_UNLOCK(nlock, &nlocktype);
rcu_read_unlock();
nlock = &qpdb->buckets[node->locknum].lock;
NODE_RDLOCK(nlock, &nlocktype);
- qpcnode_release(qpdb, node, &nlocktype, &qpdbiter->tree_locked,
- false DNS__DB_FLARG_PASS);
+ qpcnode_release(qpdb, node, &nlocktype,
+ &qpdbiter->tree_locked DNS__DB_FLARG_PASS);
NODE_UNLOCK(nlock, &nlocktype);
INSIST(qpdbiter->tree_locked == tlocktype);