mirror of
https://gitlab.isc.org/isc-projects/bind9
synced 2025-08-31 14:35:26 +00:00
we sometimes were not decrementing irefcnt
This commit is contained in:
204
lib/dns/adb.c
204
lib/dns/adb.c
@@ -117,6 +117,7 @@ struct dns_adb {
|
||||
unsigned int magic;
|
||||
|
||||
isc_mutex_t lock;
|
||||
isc_mutex_t ilock;
|
||||
isc_mem_t *mctx;
|
||||
dns_view_t *view;
|
||||
isc_timermgr_t *timermgr;
|
||||
@@ -290,8 +291,7 @@ static void print_dns_name(FILE *, dns_name_t *);
|
||||
static void print_namehook_list(FILE *, dns_adbname_t *);
|
||||
static void print_find_list(FILE *, dns_adbname_t *);
|
||||
static void print_fetch_list(FILE *, dns_adbname_t *);
|
||||
static inline void inc_adb_irefcnt(dns_adb_t *, isc_boolean_t);
|
||||
static inline void dec_adb_irefcnt(dns_adb_t *, isc_boolean_t);
|
||||
static inline void dec_adb_irefcnt(dns_adb_t *);
|
||||
static inline void inc_adb_erefcnt(dns_adb_t *, isc_boolean_t);
|
||||
static inline void dec_adb_erefcnt(dns_adb_t *, isc_boolean_t);
|
||||
static inline void inc_entry_refcnt(dns_adb_t *, dns_adbentry_t *,
|
||||
@@ -722,6 +722,8 @@ unlink_name(dns_adb_t *adb, dns_adbname_t *name)
|
||||
name->lock_bucket = DNS_ADB_INVALIDBUCKET;
|
||||
INSIST(adb->name_refcnt[bucket] > 0);
|
||||
adb->name_refcnt[bucket]--;
|
||||
if (adb->name_sd[bucket] && adb->name_refcnt[bucket] == 0)
|
||||
dec_adb_irefcnt(adb);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -750,6 +752,8 @@ unlink_entry(dns_adb_t *adb, dns_adbentry_t *entry)
|
||||
entry->lock_bucket = DNS_ADB_INVALIDBUCKET;
|
||||
INSIST(adb->entry_refcnt[bucket] > 0);
|
||||
adb->entry_refcnt[bucket]--;
|
||||
if (adb->entry_sd[bucket] && adb->entry_refcnt[bucket] == 0)
|
||||
dec_adb_irefcnt(adb);
|
||||
}
|
||||
|
||||
static inline void
|
||||
@@ -777,25 +781,28 @@ shutdown_names(dns_adb_t *adb)
|
||||
LOCK(&adb->namelocks[bucket]);
|
||||
adb->name_sd[bucket] = ISC_TRUE;
|
||||
|
||||
/*
|
||||
* Run through the list. For each name, clean up finds
|
||||
* found there, and cancel any fetches running. When
|
||||
* all the fetches are canceled, the name will destroy
|
||||
* itself.
|
||||
*/
|
||||
name = ISC_LIST_HEAD(adb->names[bucket]);
|
||||
while (name != NULL) {
|
||||
next_name = ISC_LIST_NEXT(name, plink);
|
||||
|
||||
kill_name(&name, DNS_EVENT_ADBSHUTDOWN);
|
||||
|
||||
name = next_name;
|
||||
if (name == NULL) {
|
||||
/*
|
||||
* This bucket has no names. We must decrement the
|
||||
* irefcnt ourselves, since it will not be
|
||||
* automatically triggered by a name being unlinked.
|
||||
*/
|
||||
dec_adb_irefcnt(adb);
|
||||
} else {
|
||||
/*
|
||||
* Run through the list. For each name, clean up finds
|
||||
* found there, and cancel any fetches running. When
|
||||
* all the fetches are canceled, the name will destroy
|
||||
* itself.
|
||||
*/
|
||||
while (name != NULL) {
|
||||
next_name = ISC_LIST_NEXT(name, plink);
|
||||
kill_name(&name, DNS_EVENT_ADBSHUTDOWN);
|
||||
name = next_name;
|
||||
}
|
||||
}
|
||||
|
||||
/* kill_name() will decrement the refcnt. */
|
||||
if (adb->name_refcnt[bucket] == 0)
|
||||
dec_adb_irefcnt(adb, ISC_FALSE);
|
||||
|
||||
UNLOCK(&adb->namelocks[bucket]);
|
||||
}
|
||||
}
|
||||
@@ -815,23 +822,30 @@ shutdown_entries(dns_adb_t *adb)
|
||||
LOCK(&adb->entrylocks[bucket]);
|
||||
adb->entry_sd[bucket] = ISC_TRUE;
|
||||
|
||||
/*
|
||||
* Run through the list. Cleanup any entries not associated
|
||||
* with names, and which are not in use.
|
||||
*/
|
||||
entry = ISC_LIST_HEAD(adb->entries[bucket]);
|
||||
while (entry != NULL) {
|
||||
next_entry = ISC_LIST_NEXT(entry, plink);
|
||||
if (entry->refcnt == 0 && entry->expires != 0) {
|
||||
unlink_entry(adb, entry);
|
||||
free_adbentry(adb, &entry);
|
||||
if (entry == NULL) {
|
||||
/*
|
||||
* This bucket has no entries. We must decrement the
|
||||
* irefcnt ourselves, since it will not be
|
||||
* automatically triggered by an entry being unlinked.
|
||||
*/
|
||||
dec_adb_irefcnt(adb);
|
||||
} else {
|
||||
/*
|
||||
* Run through the list. Cleanup any entries not
|
||||
* associated with names, and which are not in use.
|
||||
*/
|
||||
while (entry != NULL) {
|
||||
next_entry = ISC_LIST_NEXT(entry, plink);
|
||||
if (entry->refcnt == 0 &&
|
||||
entry->expires != 0) {
|
||||
unlink_entry(adb, entry);
|
||||
free_adbentry(adb, &entry);
|
||||
}
|
||||
entry = next_entry;
|
||||
}
|
||||
entry = next_entry;
|
||||
}
|
||||
|
||||
if (adb->entry_refcnt[bucket] == 0)
|
||||
dec_adb_irefcnt(adb, ISC_FALSE);
|
||||
|
||||
UNLOCK(&adb->entrylocks[bucket]);
|
||||
}
|
||||
}
|
||||
@@ -1013,12 +1027,20 @@ check_exit(dns_adb_t *adb)
|
||||
{
|
||||
isc_event_t *event, *next_event;
|
||||
isc_task_t *etask;
|
||||
isc_boolean_t zeroirefcnt;
|
||||
|
||||
/*
|
||||
* The caller must be holding the adb lock.
|
||||
*/
|
||||
|
||||
if (adb->shutting_down && adb->irefcnt == 0 &&
|
||||
LOCK(&adb->ilock);
|
||||
if (adb->irefcnt == 0)
|
||||
zeroirefcnt = ISC_TRUE;
|
||||
else
|
||||
zeroirefcnt = ISC_FALSE;
|
||||
UNLOCK(&adb->ilock);
|
||||
|
||||
if (adb->shutting_down && zeroirefcnt &&
|
||||
isc_mempool_getallocated(adb->ahmp) == 0) {
|
||||
/*
|
||||
* We're now shutdown. Send any whenshutdown events.
|
||||
@@ -1046,30 +1068,14 @@ check_exit(dns_adb_t *adb)
|
||||
}
|
||||
|
||||
static inline void
|
||||
inc_adb_irefcnt(dns_adb_t *adb, isc_boolean_t lock)
|
||||
dec_adb_irefcnt(dns_adb_t *adb)
|
||||
{
|
||||
if (lock)
|
||||
LOCK(&adb->lock);
|
||||
|
||||
adb->irefcnt++;
|
||||
|
||||
if (lock)
|
||||
UNLOCK(&adb->lock);
|
||||
}
|
||||
|
||||
static inline void
|
||||
dec_adb_irefcnt(dns_adb_t *adb, isc_boolean_t lock)
|
||||
{
|
||||
if (lock)
|
||||
LOCK(&adb->lock);
|
||||
LOCK(&adb->ilock);
|
||||
|
||||
INSIST(adb->irefcnt > 0);
|
||||
adb->irefcnt--;
|
||||
|
||||
check_exit(adb);
|
||||
|
||||
if (lock)
|
||||
UNLOCK(&adb->lock);
|
||||
UNLOCK(&adb->ilock);
|
||||
}
|
||||
|
||||
static inline void
|
||||
@@ -1093,7 +1099,8 @@ dec_adb_erefcnt(dns_adb_t *adb, isc_boolean_t lock)
|
||||
INSIST(adb->erefcnt > 0);
|
||||
adb->erefcnt--;
|
||||
|
||||
check_exit(adb);
|
||||
if (adb->erefcnt == 0)
|
||||
check_exit(adb);
|
||||
|
||||
if (lock)
|
||||
UNLOCK(&adb->lock);
|
||||
@@ -1856,6 +1863,11 @@ check_expire_name(dns_adbname_t **namep, isc_stdtime_t now)
|
||||
* The name is empty. Delete it.
|
||||
*/
|
||||
kill_name(&name, DNS_EVENT_ADBEXPIRED);
|
||||
|
||||
/*
|
||||
* Our caller, or one of its callers, will be calling check_exit() at
|
||||
* some point, so we don't need to do it here.
|
||||
*/
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -1997,6 +2009,7 @@ destroy(dns_adb_t *adb)
|
||||
isc_mutexblock_destroy(adb->entrylocks, NBUCKETS);
|
||||
isc_mutexblock_destroy(adb->namelocks, NBUCKETS);
|
||||
|
||||
isc_mutex_destroy(&adb->ilock);
|
||||
isc_mutex_destroy(&adb->lock);
|
||||
isc_mutex_destroy(&adb->mplock);
|
||||
|
||||
@@ -2069,6 +2082,10 @@ dns_adb_create(isc_mem_t *mem, dns_view_t *view, isc_timermgr_t *timermgr,
|
||||
if (result != ISC_R_SUCCESS)
|
||||
goto fail0c;
|
||||
|
||||
result = isc_mutex_init(&adb->ilock);
|
||||
if (result != ISC_R_SUCCESS)
|
||||
goto fail0d;
|
||||
|
||||
/*
|
||||
* Initialize the bucket locks for names and elements.
|
||||
* May as well initialize the list heads, too.
|
||||
@@ -2170,6 +2187,8 @@ dns_adb_create(isc_mem_t *mem, dns_view_t *view, isc_timermgr_t *timermgr,
|
||||
if (adb->af6mp != NULL)
|
||||
isc_mempool_destroy(&adb->af6mp);
|
||||
|
||||
isc_mutex_destroy(&adb->ilock);
|
||||
fail0d:
|
||||
isc_mutex_destroy(&adb->mplock);
|
||||
fail0c:
|
||||
isc_mutex_destroy(&adb->lock);
|
||||
@@ -2203,6 +2222,7 @@ dns_adb_whenshutdown(dns_adb_t *adb, isc_task_t *task, isc_event_t **eventp)
|
||||
{
|
||||
isc_task_t *clone;
|
||||
isc_event_t *event;
|
||||
isc_boolean_t zeroirefcnt = ISC_FALSE;
|
||||
|
||||
/*
|
||||
* Send '*eventp' to 'task' when 'adb' has shutdown.
|
||||
@@ -2215,8 +2235,15 @@ dns_adb_whenshutdown(dns_adb_t *adb, isc_task_t *task, isc_event_t **eventp)
|
||||
*eventp = NULL;
|
||||
|
||||
LOCK(&adb->lock);
|
||||
|
||||
LOCK(&adb->ilock);
|
||||
if (adb->irefcnt == 0)
|
||||
zeroirefcnt = ISC_TRUE;
|
||||
else
|
||||
zeroirefcnt = ISC_FALSE;
|
||||
UNLOCK(&adb->ilock);
|
||||
|
||||
if (adb->shutting_down && adb->irefcnt == 0 &&
|
||||
if (adb->shutting_down && zeroirefcnt &&
|
||||
isc_mempool_getallocated(adb->ahmp) == 0) {
|
||||
/*
|
||||
* We're already shutdown. Send the event.
|
||||
@@ -2512,7 +2539,7 @@ dns_adb_deletename(dns_adb_t *adb, dns_name_t *host)
|
||||
{
|
||||
int name_bucket;
|
||||
dns_adbname_t *name;
|
||||
isc_boolean_t decr_adbrefcnt;
|
||||
isc_boolean_t want_check_exit = ISC_FALSE;
|
||||
|
||||
REQUIRE(DNS_ADB_VALID(adb));
|
||||
REQUIRE(host != NULL);
|
||||
@@ -2531,15 +2558,22 @@ dns_adb_deletename(dns_adb_t *adb, dns_name_t *host)
|
||||
|
||||
kill_name(&name, DNS_EVENT_ADBNAMEDELETED);
|
||||
|
||||
decr_adbrefcnt = ISC_FALSE;
|
||||
if (adb->name_sd[name_bucket] && (adb->name_refcnt[name_bucket] == 0))
|
||||
decr_adbrefcnt = ISC_TRUE;
|
||||
/*
|
||||
* If we're shutting down and this bucket is empty, we need to call
|
||||
* check_exit() to see if we're done.
|
||||
*/
|
||||
if (adb->name_sd[name_bucket] && adb->name_refcnt[name_bucket] == 0)
|
||||
want_check_exit = ISC_TRUE;
|
||||
|
||||
|
||||
if (name_bucket != DNS_ADB_INVALIDBUCKET)
|
||||
UNLOCK(&adb->namelocks[name_bucket]);
|
||||
|
||||
if (decr_adbrefcnt)
|
||||
dec_adb_irefcnt(adb, ISC_TRUE);
|
||||
if (want_check_exit) {
|
||||
LOCK(&adb->lock);
|
||||
check_exit(adb);
|
||||
UNLOCK(&adb->lock);
|
||||
}
|
||||
|
||||
return (DNS_R_SUCCESS);
|
||||
}
|
||||
@@ -3161,6 +3195,7 @@ fetch_callback(isc_task_t *task, isc_event_t *ev)
|
||||
isc_stdtime_t now;
|
||||
isc_result_t result;
|
||||
unsigned int address_type;
|
||||
isc_boolean_t want_check_exit = ISC_FALSE;
|
||||
|
||||
(void)task;
|
||||
|
||||
@@ -3206,21 +3241,25 @@ fetch_callback(isc_task_t *task, isc_event_t *ev)
|
||||
* potentially good data.
|
||||
*/
|
||||
if (NAME_DEAD(name)) {
|
||||
isc_boolean_t decr_adbrefcnt;
|
||||
|
||||
free_adbfetch(adb, &fetch);
|
||||
isc_event_free(&ev);
|
||||
|
||||
kill_name(&name, DNS_EVENT_ADBCANCELED);
|
||||
|
||||
decr_adbrefcnt = ISC_FALSE;
|
||||
if (adb->name_sd[bucket] && (adb->name_refcnt[bucket] == 0))
|
||||
decr_adbrefcnt = ISC_TRUE;
|
||||
/*
|
||||
* If we're shutting down and this bucket is empty, we need
|
||||
* to call check_exit() to see if we're done.
|
||||
*/
|
||||
if (adb->name_sd[bucket] && adb->name_refcnt[bucket] == 0)
|
||||
want_check_exit = ISC_TRUE;
|
||||
|
||||
UNLOCK(&adb->namelocks[bucket]);
|
||||
|
||||
if (decr_adbrefcnt)
|
||||
dec_adb_irefcnt(adb, ISC_TRUE);
|
||||
if (want_check_exit) {
|
||||
LOCK(&adb->lock);
|
||||
check_exit(adb);
|
||||
UNLOCK(&adb->lock);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
@@ -3300,6 +3339,7 @@ fetch_callback_a6(isc_task_t *task, isc_event_t *ev)
|
||||
int bucket;
|
||||
isc_stdtime_t now;
|
||||
isc_result_t result;
|
||||
isc_boolean_t want_check_exit = ISC_FALSE;
|
||||
|
||||
(void)task;
|
||||
|
||||
@@ -3341,21 +3381,25 @@ fetch_callback_a6(isc_task_t *task, isc_event_t *ev)
|
||||
* potentially good data.
|
||||
*/
|
||||
if (NAME_DEAD(name)) {
|
||||
isc_boolean_t decr_adbrefcnt;
|
||||
|
||||
free_adbfetch6(adb, &fetch);
|
||||
isc_event_free(&ev);
|
||||
|
||||
kill_name(&name, DNS_EVENT_ADBCANCELED);
|
||||
|
||||
decr_adbrefcnt = ISC_FALSE;
|
||||
if (adb->name_sd[bucket] && (adb->name_refcnt[bucket] == 0))
|
||||
decr_adbrefcnt = ISC_TRUE;
|
||||
/*
|
||||
* If we're shutting down and this bucket is empty, we need
|
||||
* to call check_exit() to see if we're done.
|
||||
*/
|
||||
if (adb->name_sd[bucket] && adb->name_refcnt[bucket] == 0)
|
||||
want_check_exit = ISC_TRUE;
|
||||
|
||||
UNLOCK(&adb->namelocks[bucket]);
|
||||
|
||||
if (decr_adbrefcnt)
|
||||
dec_adb_irefcnt(adb, ISC_TRUE);
|
||||
if (want_check_exit) {
|
||||
LOCK(&adb->lock);
|
||||
check_exit(adb);
|
||||
UNLOCK(&adb->lock);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
@@ -3813,8 +3857,8 @@ dns_adb_freeaddrinfo(dns_adb_t *adb, dns_adbaddrinfo_t **addrp)
|
||||
dns_adbaddrinfo_t *addr;
|
||||
dns_adbentry_t *entry;
|
||||
int bucket;
|
||||
isc_boolean_t dec_irefcnt;
|
||||
isc_stdtime_t now;
|
||||
isc_boolean_t want_check_exit = ISC_FALSE;
|
||||
|
||||
REQUIRE(DNS_ADB_VALID(adb));
|
||||
REQUIRE(addrp != NULL);
|
||||
@@ -3823,7 +3867,6 @@ dns_adb_freeaddrinfo(dns_adb_t *adb, dns_adbaddrinfo_t **addrp)
|
||||
entry = addr->entry;
|
||||
REQUIRE(DNS_ADBENTRY_VALID(entry));
|
||||
|
||||
dec_irefcnt = ISC_FALSE;
|
||||
isc_stdtime_get(&now);
|
||||
|
||||
*addrp = NULL;
|
||||
@@ -3835,14 +3878,17 @@ dns_adb_freeaddrinfo(dns_adb_t *adb, dns_adbaddrinfo_t **addrp)
|
||||
|
||||
dec_entry_refcnt(adb, entry, ISC_FALSE);
|
||||
if (adb->entry_sd[bucket] && adb->entry_refcnt[bucket] == 0)
|
||||
dec_irefcnt = ISC_TRUE;
|
||||
want_check_exit = ISC_TRUE;
|
||||
|
||||
UNLOCK(&adb->entrylocks[bucket]);
|
||||
|
||||
addr->entry = NULL;
|
||||
addr->sockaddr = NULL;
|
||||
free_adbaddrinfo(adb, &addr);
|
||||
|
||||
if (dec_irefcnt)
|
||||
dec_adb_irefcnt(adb, ISC_TRUE);
|
||||
|
||||
if (want_check_exit) {
|
||||
LOCK(&adb->lock);
|
||||
check_exit(adb);
|
||||
UNLOCK(&adb->lock);
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user