#ifdef DNS_DB_NODETRACE
#define qpcache_ref(ptr) qpcache__ref(ptr, __func__, __FILE__, __LINE__)
-#define qpcache_unref(ptr) qpcache_unref(ptr, __func__, __FILE__, __LINE__)
+#define qpcache_unref(ptr) qpcache__unref(ptr, __func__, __FILE__, __LINE__)
#define qpcache_attach(ptr, ptrp) \
qpcache__attach(ptr, ptrp, __func__, __FILE__, __LINE__)
#define qpcache_detach(ptrp) qpcache__detach(ptrp, __func__, __FILE__, __LINE__)
* acquired a reference in the meantime, so we increment
* erefs (but NOT references!), upgrade the node lock,
* decrement erefs again, and see if it's still zero.
+ *
+ * We can't really assume anything about the result code of
+ * erefs_increment. If another thread acquires reference it
+ * will be larger than 0, if it doesn't it is going to be 0.
*/
isc_rwlock_t *nlock = &qpdb->buckets[node->locknum].lock;
qpcnode_erefs_increment(qpdb, node, *nlocktypep,
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);
+ qpcnode_release(qpdb, qpnode, &nlocktype, &tlocktype,
+ false DNS__DB_FILELINE);
}
NODE_UNLOCK(nlock, &nlocktype);
nlock = &qpdb->buckets[node->locknum].lock;
/*
- * We can't destroy qpcache while holding a nodelock, so
- * we need to reference it before acquiring the lock
- * and release it afterward.
+ * We can't destroy qpcache while holding a nodelock, so we need to
+ * reference it before acquiring the lock and release it afterward.
+ * Additionally, we must ensure that we don't destroy the database while
+ * the NODE_LOCK is locked.
*/
qpcache_ref(qpdb);
+ rcu_read_lock();
NODE_RDLOCK(nlock, &nlocktype);
qpcnode_release(qpdb, node, &nlocktype, &tlocktype,
true DNS__DB_FLARG_PASS);
NODE_UNLOCK(nlock, &nlocktype);
+ rcu_read_unlock();
qpcache_detach(&qpdb);
}
void *data;
};
-typedef struct qpcache_bucket {
+typedef struct qpzone_bucket {
/* Per-bucket lock. */
isc_rwlock_t lock;
#ifdef DNS_DB_NODETRACE
#define qpzonedb_ref(ptr) qpzonedb__ref(ptr, __func__, __FILE__, __LINE__)
-#define qpzonedb_unref(ptr) qpzonedb_unref(ptr, __func__, __FILE__, __LINE__)
+#define qpzonedb_unref(ptr) qpzonedb__unref(ptr, __func__, __FILE__, __LINE__)
#define qpzonedb_attach(ptr, ptrp) \
qpzonedb__attach(ptr, ptrp, __func__, __FILE__, __LINE__)
#define qpzonedb_detach(ptrp) \
* acquired a reference in the meantime, so we increment
* erefs (but NOT references!), upgrade the node lock,
* decrement erefs again, and see if it's still zero.
+ *
+ * We can't really assume anything about the result code of
+ * erefs_increment. If another thread acquires reference it
+ * will be larger than 0, if it doesn't it is going to be 0.
*/
isc_rwlock_t *nlock = &qpdb->buckets[node->locknum].lock;
qpznode_erefs_increment(qpdb, node DNS__DB_FLARG_PASS);
}
static void
-attachnode(dns_db_t *db, dns_dbnode_t *source,
- dns_dbnode_t **targetp DNS__DB_FLARG) {
+qpzone_attachnode(dns_db_t *db, dns_dbnode_t *source,
+ dns_dbnode_t **targetp DNS__DB_FLARG) {
qpzonedb_t *qpdb = (qpzonedb_t *)db;
qpznode_t *node = (qpznode_t *)source;
}
static void
-detachnode(dns_db_t *db, dns_dbnode_t **nodep DNS__DB_FLARG) {
+qpzone_detachnode(dns_db_t *db, dns_dbnode_t **nodep DNS__DB_FLARG) {
qpzonedb_t *qpdb = (qpzonedb_t *)db;
qpznode_t *node = NULL;
isc_rwlocktype_t nlocktype = isc_rwlocktype_none;
nlock = &qpdb->buckets[node->locknum].lock;
/*
- * qpzone_destroy() uses call_rcu() API to destroy the node locks,
- * so it is safe to call it in the middle of NODE_LOCK.
+ * qpzone_destroy() uses call_rcu() API to destroy the node locks, so it
+ * is safe to call it in the middle of NODE_LOCK, but we need to acquire
+ * the database reference to prevent destroying the database while the
+ * NODE_LOCK is locked.
*/
+ qpzonedb_ref(qpdb);
+
rcu_read_lock();
NODE_RDLOCK(nlock, &nlocktype);
qpznode_release(qpdb, node, 0, &nlocktype DNS__DB_FLARG_PASS);
NODE_UNLOCK(nlock, &nlocktype);
rcu_read_unlock();
+
+ qpzonedb_unref(qpdb);
}
static unsigned int
.closeversion = closeversion,
.findnode = qpzone_findnode,
.find = qpzone_find,
- .attachnode = attachnode,
- .detachnode = detachnode,
+ .attachnode = qpzone_attachnode,
+ .detachnode = qpzone_detachnode,
.createiterator = qpzone_createiterator,
.findrdataset = qpzone_findrdataset,
.allrdatasets = qpzone_allrdatasets,