/*
* Since we're holding a tree write lock, it should be
* impossible for this node to be referenced by others.
+ *
+ * decrement_reference may not have tested node->down, as
+ * the tree_lock was not held, before adding the node to
+ * deadnodes so we test it here.
*/
INSIST(isc_refcount_current(&node->references) == 0 &&
node->data == NULL);
attach((dns_db_t *)rbtdb, &db);
ev->ev_sender = db;
isc_task_send(rbtdb->task, &ev);
- } else {
+ } else if (node->down == NULL && node->data == NULL) {
+ /*
+ * Not a interior node and not needing to be
+ * reactivated.
+ */
delete_node(rbtdb, node);
+ } else if (node->data == NULL) {
+ /*
+ * A interior node without data. Leave linked to
+ * to be cleaned up when node->down becomes NULL.
+ */
+ ISC_LIST_APPEND(rbtdb->deadnodes[bucketnum],
+ node, deadlink);
}
node = ISC_LIST_HEAD(rbtdb->deadnodes[bucketnum]);
count--;
{
isc_result_t result;
bool write_locked;
+ bool locked = tlock != isc_rwlocktype_none;
rbtdb_nodelock_t *nodelock;
int bucket = node->locknum;
bool no_reference = true;
nodelock = &rbtdb->node_locks[bucket];
-#define KEEP_NODE(n, r) \
- ((n)->data != NULL || (n)->down != NULL || \
+#define KEEP_NODE(n, r, l) \
+ ((n)->data != NULL || ((l) && (n)->down != NULL) || \
(n) == (r)->origin_node || (n) == (r)->nsec3_origin_node)
/* Handle easy and typical case first. */
- if (!node->dirty && KEEP_NODE(node, rbtdb)) {
+ if (!node->dirty && KEEP_NODE(node, rbtdb, locked)) {
if (isc_refcount_decrement(&node->references) == 1) {
refs = isc_refcount_decrement(&nodelock->references);
INSIST(refs > 0);
refs = isc_refcount_decrement(&nodelock->references);
INSIST(refs > 0);
- if (KEEP_NODE(node, rbtdb))
+ if (KEEP_NODE(node, rbtdb, locked || write_locked)) {
goto restore_locks;
+ }
#undef KEEP_NODE