mirror of
https://github.com/isc-projects/bind9.git
synced 2026-05-21 17:41:35 -04:00
Merge branch '1443-threadsanitizer-data-race-lib-dns-rbtdb-c-1960-in-decrement_reference-2' into 'master'
Resolve "ThreadSanitizer: data race lib/dns/rbtdb.c:1960 in decrement_reference" Closes #1443 See merge request isc-projects/bind9!2703
This commit is contained in:
commit
09c2dbffb5
1 changed files with 51 additions and 36 deletions
|
|
@ -1824,6 +1824,31 @@ new_reference(dns_rbtdb_t *rbtdb, dns_rbtnode_t *node) {
|
|||
}
|
||||
}
|
||||
|
||||
/*%
|
||||
* The tree lock must be held for the result to be valid.
|
||||
*/
|
||||
static inline bool
|
||||
is_leaf(dns_rbtnode_t *node) {
|
||||
return (node->parent != NULL && node->parent->down == node &&
|
||||
node->left == NULL && node->right == NULL);
|
||||
}
|
||||
|
||||
static inline void
|
||||
send_to_prune_tree(dns_rbtdb_t *rbtdb, dns_rbtnode_t *node) {
|
||||
isc_event_t *ev;
|
||||
dns_db_t *db;
|
||||
|
||||
ev = isc_event_allocate(rbtdb->common.mctx, NULL,
|
||||
DNS_EVENT_RBTPRUNE,
|
||||
prune_tree, node,
|
||||
sizeof(isc_event_t));
|
||||
new_reference(rbtdb, node);
|
||||
db = NULL;
|
||||
attach((dns_db_t *)rbtdb, &db);
|
||||
ev->ev_sender = db;
|
||||
isc_task_send(rbtdb->task, &ev);
|
||||
}
|
||||
|
||||
/*%
|
||||
* Clean up dead nodes. These are nodes which have no references, and
|
||||
* have no data. They are dead but we could not or chose not to delete
|
||||
|
|
@ -1844,28 +1869,29 @@ cleanup_dead_nodes(dns_rbtdb_t *rbtdb, int bucketnum) {
|
|||
/*
|
||||
* 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);
|
||||
|
||||
if (node->parent != NULL &&
|
||||
node->parent->down == node && node->left == NULL &&
|
||||
node->right == NULL && rbtdb->task != NULL)
|
||||
{
|
||||
isc_event_t *ev;
|
||||
dns_db_t *db;
|
||||
|
||||
ev = isc_event_allocate(rbtdb->common.mctx, NULL,
|
||||
DNS_EVENT_RBTPRUNE,
|
||||
prune_tree, node,
|
||||
sizeof(isc_event_t));
|
||||
new_reference(rbtdb, node);
|
||||
db = NULL;
|
||||
attach((dns_db_t *)rbtdb, &db);
|
||||
ev->ev_sender = db;
|
||||
isc_task_send(rbtdb->task, &ev);
|
||||
} else {
|
||||
if (is_leaf(node) && rbtdb->task != NULL) {
|
||||
send_to_prune_tree(rbtdb, node);
|
||||
} 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--;
|
||||
|
|
@ -1945,6 +1971,7 @@ decrement_reference(dns_rbtdb_t *rbtdb, dns_rbtnode_t *node,
|
|||
{
|
||||
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;
|
||||
|
|
@ -1952,12 +1979,12 @@ decrement_reference(dns_rbtdb_t *rbtdb, dns_rbtnode_t *node,
|
|||
|
||||
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);
|
||||
|
|
@ -2024,8 +2051,9 @@ decrement_reference(dns_rbtdb_t *rbtdb, dns_rbtnode_t *node,
|
|||
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
|
||||
|
||||
|
|
@ -2050,21 +2078,8 @@ decrement_reference(dns_rbtdb_t *rbtdb, dns_rbtnode_t *node,
|
|||
* it's their responsibility to purge stale leaves (e.g. by
|
||||
* periodic walk-through).
|
||||
*/
|
||||
if (!pruning && node->parent != NULL &&
|
||||
node->parent->down == node && node->left == NULL &&
|
||||
node->right == NULL && rbtdb->task != NULL) {
|
||||
isc_event_t *ev;
|
||||
dns_db_t *db;
|
||||
|
||||
ev = isc_event_allocate(rbtdb->common.mctx, NULL,
|
||||
DNS_EVENT_RBTPRUNE,
|
||||
prune_tree, node,
|
||||
sizeof(isc_event_t));
|
||||
new_reference(rbtdb, node);
|
||||
db = NULL;
|
||||
attach((dns_db_t *)rbtdb, &db);
|
||||
ev->ev_sender = db;
|
||||
isc_task_send(rbtdb->task, &ev);
|
||||
if (!pruning && is_leaf(node) && rbtdb->task != NULL) {
|
||||
send_to_prune_tree(rbtdb, node);
|
||||
no_reference = false;
|
||||
} else {
|
||||
delete_node(rbtdb, node);
|
||||
|
|
|
|||
Loading…
Reference in a new issue