mirror of
https://gitlab.isc.org/isc-projects/bind9
synced 2025-09-01 06:55:30 +00:00
Don't release the tree read lock in dereference_iter_node()
Previously, the tree read lock could be upgraded to a write lock in decrement_reference() and then downgraded back to read lock in dereference_iter_node(). When the use of isc_rwlock_downgrade() was removed, the downgrade was changed to a simple unlock+lock. This allows some delete operations to sneak in and delete nodes that the iterator expects to be in place. Expand decrement_reference() so the caller can indicate whether the tree read lock should be upgraded, and disallow the upgrade when calling from dereference_iter_node(), so there will be no need to release the lock afterward.
This commit is contained in:
committed by
Ondřej Surý
parent
cfe42dfb68
commit
96e7bf76e7
@@ -2086,7 +2086,8 @@ reactivate_node(dns_rbtdb_t *rbtdb, dns_rbtnode_t *node,
|
|||||||
static bool
|
static bool
|
||||||
decrement_reference(dns_rbtdb_t *rbtdb, dns_rbtnode_t *node,
|
decrement_reference(dns_rbtdb_t *rbtdb, dns_rbtnode_t *node,
|
||||||
rbtdb_serial_t least_serial, isc_rwlocktype_t *nlocktypep,
|
rbtdb_serial_t least_serial, isc_rwlocktype_t *nlocktypep,
|
||||||
isc_rwlocktype_t *tlocktypep, bool pruning) {
|
isc_rwlocktype_t *tlocktypep, bool tryupgrade,
|
||||||
|
bool pruning) {
|
||||||
isc_result_t result;
|
isc_result_t result;
|
||||||
bool locked = *tlocktypep != isc_rwlocktype_none;
|
bool locked = *tlocktypep != isc_rwlocktype_none;
|
||||||
bool write_locked = false;
|
bool write_locked = false;
|
||||||
@@ -2153,12 +2154,17 @@ decrement_reference(dns_rbtdb_t *rbtdb, dns_rbtnode_t *node,
|
|||||||
* the node lock before acquiring the tree write lock because
|
* the node lock before acquiring the tree write lock because
|
||||||
* we only do a trylock.
|
* we only do a trylock.
|
||||||
*/
|
*/
|
||||||
|
/* We are allowed to upgrade the tree lock */
|
||||||
switch (*tlocktypep) {
|
switch (*tlocktypep) {
|
||||||
case isc_rwlocktype_write:
|
case isc_rwlocktype_write:
|
||||||
result = ISC_R_SUCCESS;
|
result = ISC_R_SUCCESS;
|
||||||
break;
|
break;
|
||||||
case isc_rwlocktype_read:
|
case isc_rwlocktype_read:
|
||||||
result = TREE_TRYUPGRADE(&rbtdb->tree_lock, tlocktypep);
|
if (tryupgrade) {
|
||||||
|
result = TREE_TRYUPGRADE(&rbtdb->tree_lock, tlocktypep);
|
||||||
|
} else {
|
||||||
|
result = ISC_R_LOCKBUSY;
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
case isc_rwlocktype_none:
|
case isc_rwlocktype_none:
|
||||||
result = TREE_TRYWRLOCK(&rbtdb->tree_lock, tlocktypep);
|
result = TREE_TRYWRLOCK(&rbtdb->tree_lock, tlocktypep);
|
||||||
@@ -2252,7 +2258,7 @@ prune_tree(isc_task_t *task, isc_event_t *event) {
|
|||||||
do {
|
do {
|
||||||
parent = node->parent;
|
parent = node->parent;
|
||||||
decrement_reference(rbtdb, node, 0, &nlocktype, &tlocktype,
|
decrement_reference(rbtdb, node, 0, &nlocktype, &tlocktype,
|
||||||
true);
|
true, true);
|
||||||
|
|
||||||
if (parent != NULL && parent->down == NULL) {
|
if (parent != NULL && parent->down == NULL) {
|
||||||
/*
|
/*
|
||||||
@@ -2705,7 +2711,7 @@ closeversion(dns_db_t *db, dns_dbversion_t **versionp, bool commit) {
|
|||||||
resign_insert(rbtdb, header->node->locknum, header);
|
resign_insert(rbtdb, header->node->locknum, header);
|
||||||
}
|
}
|
||||||
decrement_reference(rbtdb, header->node, least_serial,
|
decrement_reference(rbtdb, header->node, least_serial,
|
||||||
&nlocktype, &tlocktype, false);
|
&nlocktype, &tlocktype, true, false);
|
||||||
NODE_UNLOCK(lock, &nlocktype);
|
NODE_UNLOCK(lock, &nlocktype);
|
||||||
INSIST(tlocktype == isc_rwlocktype_none);
|
INSIST(tlocktype == isc_rwlocktype_none);
|
||||||
}
|
}
|
||||||
@@ -2755,7 +2761,8 @@ closeversion(dns_db_t *db, dns_dbversion_t **versionp, bool commit) {
|
|||||||
rollback_node(rbtnode, serial);
|
rollback_node(rbtnode, serial);
|
||||||
}
|
}
|
||||||
decrement_reference(rbtdb, rbtnode, least_serial,
|
decrement_reference(rbtdb, rbtnode, least_serial,
|
||||||
&nlocktype, &tlocktype, false);
|
&nlocktype, &tlocktype, true,
|
||||||
|
false);
|
||||||
|
|
||||||
NODE_UNLOCK(lock, &nlocktype);
|
NODE_UNLOCK(lock, &nlocktype);
|
||||||
|
|
||||||
@@ -4532,7 +4539,7 @@ tree_exit:
|
|||||||
|
|
||||||
NODE_RDLOCK(lock, &nlocktype);
|
NODE_RDLOCK(lock, &nlocktype);
|
||||||
decrement_reference(search.rbtdb, node, 0, &nlocktype,
|
decrement_reference(search.rbtdb, node, 0, &nlocktype,
|
||||||
&tlocktype, false);
|
&tlocktype, true, false);
|
||||||
NODE_UNLOCK(lock, &nlocktype);
|
NODE_UNLOCK(lock, &nlocktype);
|
||||||
INSIST(tlocktype == isc_rwlocktype_none);
|
INSIST(tlocktype == isc_rwlocktype_none);
|
||||||
}
|
}
|
||||||
@@ -5389,7 +5396,7 @@ tree_exit:
|
|||||||
|
|
||||||
NODE_RDLOCK(lock, &nlocktype);
|
NODE_RDLOCK(lock, &nlocktype);
|
||||||
decrement_reference(search.rbtdb, node, 0, &nlocktype,
|
decrement_reference(search.rbtdb, node, 0, &nlocktype,
|
||||||
&tlocktype, false);
|
&tlocktype, true, false);
|
||||||
NODE_UNLOCK(lock, &nlocktype);
|
NODE_UNLOCK(lock, &nlocktype);
|
||||||
INSIST(tlocktype == isc_rwlocktype_none);
|
INSIST(tlocktype == isc_rwlocktype_none);
|
||||||
}
|
}
|
||||||
@@ -5605,8 +5612,8 @@ detachnode(dns_db_t *db, dns_dbnode_t **targetp) {
|
|||||||
|
|
||||||
NODE_RDLOCK(&nodelock->lock, &nlocktype);
|
NODE_RDLOCK(&nodelock->lock, &nlocktype);
|
||||||
|
|
||||||
if (decrement_reference(rbtdb, node, 0, &nlocktype, &tlocktype, false))
|
if (decrement_reference(rbtdb, node, 0, &nlocktype, &tlocktype, true,
|
||||||
{
|
false)) {
|
||||||
if (isc_refcount_current(&nodelock->references) == 0 &&
|
if (isc_refcount_current(&nodelock->references) == 0 &&
|
||||||
nodelock->exiting) {
|
nodelock->exiting) {
|
||||||
inactive = true;
|
inactive = true;
|
||||||
@@ -8958,15 +8965,9 @@ dereference_iter_node(rbtdb_dbiterator_t *rbtdbiter) {
|
|||||||
lock = &rbtdb->node_locks[node->locknum].lock;
|
lock = &rbtdb->node_locks[node->locknum].lock;
|
||||||
NODE_RDLOCK(lock, &nlocktype);
|
NODE_RDLOCK(lock, &nlocktype);
|
||||||
decrement_reference(rbtdb, node, 0, &nlocktype, &rbtdbiter->tree_locked,
|
decrement_reference(rbtdb, node, 0, &nlocktype, &rbtdbiter->tree_locked,
|
||||||
false);
|
false, false);
|
||||||
NODE_UNLOCK(lock, &nlocktype);
|
NODE_UNLOCK(lock, &nlocktype);
|
||||||
|
|
||||||
if (tlocktype != rbtdbiter->tree_locked) {
|
|
||||||
TREE_UNLOCK(&rbtdb->tree_lock, &rbtdbiter->tree_locked);
|
|
||||||
if (tlocktype == isc_rwlocktype_read) {
|
|
||||||
TREE_RDLOCK(&rbtdb->tree_lock, &rbtdbiter->tree_locked);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
INSIST(rbtdbiter->tree_locked == tlocktype);
|
INSIST(rbtdbiter->tree_locked == tlocktype);
|
||||||
|
|
||||||
rbtdbiter->node = NULL;
|
rbtdbiter->node = NULL;
|
||||||
@@ -9006,7 +9007,7 @@ flush_deletions(rbtdb_dbiterator_t *rbtdbiter) {
|
|||||||
|
|
||||||
NODE_RDLOCK(lock, &nlocktype);
|
NODE_RDLOCK(lock, &nlocktype);
|
||||||
decrement_reference(rbtdb, node, 0, &nlocktype,
|
decrement_reference(rbtdb, node, 0, &nlocktype,
|
||||||
&rbtdbiter->tree_locked, false);
|
&rbtdbiter->tree_locked, true, false);
|
||||||
NODE_UNLOCK(lock, &nlocktype);
|
NODE_UNLOCK(lock, &nlocktype);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -10192,7 +10193,7 @@ expire_header(dns_rbtdb_t *rbtdb, rdatasetheader_t *header,
|
|||||||
*/
|
*/
|
||||||
new_reference(rbtdb, header->node, nlocktype);
|
new_reference(rbtdb, header->node, nlocktype);
|
||||||
decrement_reference(rbtdb, header->node, 0, &nlocktype,
|
decrement_reference(rbtdb, header->node, 0, &nlocktype,
|
||||||
tlocktypep, false);
|
tlocktypep, true, false);
|
||||||
|
|
||||||
if (rbtdb->cachestats == NULL) {
|
if (rbtdb->cachestats == NULL) {
|
||||||
return;
|
return;
|
||||||
|
Reference in New Issue
Block a user