mirror of
https://gitlab.isc.org/isc-projects/bind9
synced 2025-08-31 06:25:31 +00:00
merge adb_race branch
This commit is contained in:
275
lib/dns/adb.c
275
lib/dns/adb.c
@@ -15,7 +15,7 @@
|
||||
* WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
/* $Id: adb.c,v 1.198 2002/09/12 00:28:52 marka Exp $ */
|
||||
/* $Id: adb.c,v 1.199 2002/11/13 00:07:04 explorer Exp $ */
|
||||
|
||||
/*
|
||||
* Implementation notes
|
||||
@@ -282,7 +282,7 @@ static inline void free_adbzoneinfo(dns_adb_t *, dns_adbzoneinfo_t **);
|
||||
static inline dns_adbentry_t *new_adbentry(dns_adb_t *);
|
||||
static inline void free_adbentry(dns_adb_t *, dns_adbentry_t **);
|
||||
static inline dns_adbfind_t *new_adbfind(dns_adb_t *);
|
||||
static inline void free_adbfind(dns_adb_t *, dns_adbfind_t **);
|
||||
static inline isc_boolean_t free_adbfind(dns_adb_t *, dns_adbfind_t **);
|
||||
static inline dns_adbaddrinfo_t *new_adbaddrinfo(dns_adb_t *, dns_adbentry_t *,
|
||||
in_port_t);
|
||||
static inline dns_adbfetch_t *new_adbfetch(dns_adb_t *);
|
||||
@@ -302,18 +302,19 @@ static void print_namehook_list(FILE *, const char *legend,
|
||||
isc_stdtime_t now);
|
||||
static void print_find_list(FILE *, dns_adbname_t *);
|
||||
static void print_fetch_list(FILE *, dns_adbname_t *);
|
||||
static inline void dec_adb_irefcnt(dns_adb_t *);
|
||||
static inline isc_boolean_t dec_adb_irefcnt(dns_adb_t *);
|
||||
static inline void inc_adb_irefcnt(dns_adb_t *);
|
||||
static inline void inc_adb_erefcnt(dns_adb_t *);
|
||||
static inline void inc_entry_refcnt(dns_adb_t *, dns_adbentry_t *,
|
||||
isc_boolean_t);
|
||||
static inline void dec_entry_refcnt(dns_adb_t *, dns_adbentry_t *,
|
||||
static inline isc_boolean_t dec_entry_refcnt(dns_adb_t *, dns_adbentry_t *,
|
||||
isc_boolean_t);
|
||||
static inline void violate_locking_hierarchy(isc_mutex_t *, isc_mutex_t *);
|
||||
static void clean_namehooks(dns_adb_t *, dns_adbnamehooklist_t *);
|
||||
static isc_boolean_t clean_namehooks(dns_adb_t *, dns_adbnamehooklist_t *);
|
||||
static void clean_target(dns_adb_t *, dns_name_t *);
|
||||
static void clean_finds_at_name(dns_adbname_t *, isc_eventtype_t,
|
||||
unsigned int);
|
||||
static void check_expire_namehooks(dns_adbname_t *, isc_stdtime_t,
|
||||
static isc_boolean_t check_expire_namehooks(dns_adbname_t *, isc_stdtime_t,
|
||||
isc_boolean_t);
|
||||
static void cancel_fetches_at_name(dns_adbname_t *);
|
||||
static isc_result_t dbfind_name(dns_adbname_t *, isc_stdtime_t,
|
||||
@@ -324,13 +325,13 @@ static isc_result_t fetch_name_a6(dns_adbname_t *, isc_boolean_t);
|
||||
static inline void check_exit(dns_adb_t *);
|
||||
static void timer_cleanup(isc_task_t *, isc_event_t *);
|
||||
static void destroy(dns_adb_t *);
|
||||
static void shutdown_names(dns_adb_t *);
|
||||
static void shutdown_entries(dns_adb_t *);
|
||||
static isc_boolean_t shutdown_names(dns_adb_t *);
|
||||
static isc_boolean_t shutdown_entries(dns_adb_t *);
|
||||
static inline void link_name(dns_adb_t *, int, dns_adbname_t *);
|
||||
static inline void unlink_name(dns_adb_t *, dns_adbname_t *);
|
||||
static inline isc_boolean_t unlink_name(dns_adb_t *, dns_adbname_t *);
|
||||
static inline void link_entry(dns_adb_t *, int, dns_adbentry_t *);
|
||||
static inline void unlink_entry(dns_adb_t *, dns_adbentry_t *);
|
||||
static void kill_name(dns_adbname_t **, isc_eventtype_t);
|
||||
static inline isc_boolean_t unlink_entry(dns_adb_t *, dns_adbentry_t *);
|
||||
static isc_boolean_t kill_name(dns_adbname_t **, isc_eventtype_t);
|
||||
static void fetch_callback_a6(isc_task_t *, isc_event_t *);
|
||||
static isc_result_t dbfind_a6(dns_adbname_t *, isc_stdtime_t);
|
||||
static void water(void *arg, int mark);
|
||||
@@ -677,9 +678,11 @@ import_a6(dns_a6context_t *a6ctx) {
|
||||
/*
|
||||
* Requires the name's bucket be locked.
|
||||
*/
|
||||
static void
|
||||
static isc_boolean_t
|
||||
kill_name(dns_adbname_t **n, isc_eventtype_t ev) {
|
||||
dns_adbname_t *name;
|
||||
isc_boolean_t result = ISC_FALSE;
|
||||
isc_boolean_t result4, result6;
|
||||
dns_adb_t *adb;
|
||||
|
||||
INSIST(n != NULL);
|
||||
@@ -696,9 +699,11 @@ kill_name(dns_adbname_t **n, isc_eventtype_t ev) {
|
||||
* away now or not.
|
||||
*/
|
||||
if (NAME_DEAD(name) && !NAME_FETCH(name)) {
|
||||
unlink_name(adb, name);
|
||||
result = unlink_name(adb, name);
|
||||
free_adbname(adb, &name);
|
||||
return;
|
||||
if (result)
|
||||
result = dec_adb_irefcnt(adb);
|
||||
return (result);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -706,32 +711,39 @@ kill_name(dns_adbname_t **n, isc_eventtype_t ev) {
|
||||
* in that they will always empty the list.
|
||||
*/
|
||||
clean_finds_at_name(name, ev, DNS_ADBFIND_ADDRESSMASK);
|
||||
clean_namehooks(adb, &name->v4);
|
||||
clean_namehooks(adb, &name->v6);
|
||||
result4 = clean_namehooks(adb, &name->v4);
|
||||
result6 = clean_namehooks(adb, &name->v6);
|
||||
clean_target(adb, &name->target);
|
||||
result = ISC_TF(result4 || result6);
|
||||
|
||||
/*
|
||||
* If fetches are running, cancel them. If none are running, we can
|
||||
* just kill the name here.
|
||||
*/
|
||||
if (!NAME_FETCH(name)) {
|
||||
unlink_name(adb, name);
|
||||
INSIST(result == ISC_FALSE);
|
||||
result = unlink_name(adb, name);
|
||||
free_adbname(adb, &name);
|
||||
if (result)
|
||||
result = dec_adb_irefcnt(adb);
|
||||
} else {
|
||||
name->flags |= NAME_IS_DEAD;
|
||||
cancel_fetches_at_name(name);
|
||||
}
|
||||
return (result);
|
||||
}
|
||||
|
||||
/*
|
||||
* Requires the name's bucket be locked and no entry buckets be locked.
|
||||
*/
|
||||
static void
|
||||
static isc_boolean_t
|
||||
check_expire_namehooks(dns_adbname_t *name, isc_stdtime_t now,
|
||||
isc_boolean_t overmem)
|
||||
{
|
||||
dns_adb_t *adb;
|
||||
isc_boolean_t expire;
|
||||
isc_boolean_t result4 = ISC_FALSE;
|
||||
isc_boolean_t result6 = ISC_FALSE;
|
||||
|
||||
INSIST(DNS_ADBNAME_VALID(name));
|
||||
adb = name->adb;
|
||||
@@ -753,7 +765,7 @@ check_expire_namehooks(dns_adbname_t *name, isc_stdtime_t now,
|
||||
(expire || EXPIRE_OK(name->expire_v4, now))) {
|
||||
if (NAME_HAS_V4(name)) {
|
||||
DP(DEF_LEVEL, "expiring v4 for name %p", name);
|
||||
clean_namehooks(adb, &name->v4);
|
||||
result4 = clean_namehooks(adb, &name->v4);
|
||||
name->partial_result &= ~DNS_ADBFIND_INET;
|
||||
}
|
||||
name->expire_v4 = INT_MAX;
|
||||
@@ -766,7 +778,7 @@ check_expire_namehooks(dns_adbname_t *name, isc_stdtime_t now,
|
||||
(expire || EXPIRE_OK(name->expire_v6, now))) {
|
||||
if (NAME_HAS_V6(name)) {
|
||||
DP(DEF_LEVEL, "expiring v6 for name %p", name);
|
||||
clean_namehooks(adb, &name->v6);
|
||||
result6 = clean_namehooks(adb, &name->v6);
|
||||
name->partial_result &= ~DNS_ADBFIND_INET6;
|
||||
}
|
||||
name->expire_v6 = INT_MAX;
|
||||
@@ -779,6 +791,7 @@ check_expire_namehooks(dns_adbname_t *name, isc_stdtime_t now,
|
||||
clean_target(adb, &name->target);
|
||||
name->expire_target = INT_MAX;
|
||||
}
|
||||
return (ISC_TF(result4 || result6));
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -796,9 +809,10 @@ link_name(dns_adb_t *adb, int bucket, dns_adbname_t *name) {
|
||||
/*
|
||||
* Requires the name's bucket be locked.
|
||||
*/
|
||||
static inline void
|
||||
static inline isc_boolean_t
|
||||
unlink_name(dns_adb_t *adb, dns_adbname_t *name) {
|
||||
int bucket;
|
||||
isc_boolean_t result = ISC_FALSE;
|
||||
|
||||
bucket = name->lock_bucket;
|
||||
INSIST(bucket != DNS_ADB_INVALIDBUCKET);
|
||||
@@ -808,7 +822,8 @@ unlink_name(dns_adb_t *adb, dns_adbname_t *name) {
|
||||
INSIST(adb->name_refcnt[bucket] > 0);
|
||||
adb->name_refcnt[bucket]--;
|
||||
if (adb->name_sd[bucket] && adb->name_refcnt[bucket] == 0)
|
||||
dec_adb_irefcnt(adb);
|
||||
result = ISC_TRUE;
|
||||
return (result);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -824,9 +839,10 @@ link_entry(dns_adb_t *adb, int bucket, dns_adbentry_t *entry) {
|
||||
/*
|
||||
* Requires the entry's bucket be locked.
|
||||
*/
|
||||
static inline void
|
||||
static inline isc_boolean_t
|
||||
unlink_entry(dns_adb_t *adb, dns_adbentry_t *entry) {
|
||||
int bucket;
|
||||
isc_boolean_t result = ISC_FALSE;
|
||||
|
||||
bucket = entry->lock_bucket;
|
||||
INSIST(bucket != DNS_ADB_INVALIDBUCKET);
|
||||
@@ -836,7 +852,8 @@ unlink_entry(dns_adb_t *adb, dns_adbentry_t *entry) {
|
||||
INSIST(adb->entry_refcnt[bucket] > 0);
|
||||
adb->entry_refcnt[bucket]--;
|
||||
if (adb->entry_sd[bucket] && adb->entry_refcnt[bucket] == 0)
|
||||
dec_adb_irefcnt(adb);
|
||||
result = ISC_TRUE;
|
||||
return (result);
|
||||
}
|
||||
|
||||
static inline void
|
||||
@@ -852,9 +869,10 @@ violate_locking_hierarchy(isc_mutex_t *have, isc_mutex_t *want) {
|
||||
* The ADB _MUST_ be locked before calling. Also, exit conditions must be
|
||||
* checked after calling this function.
|
||||
*/
|
||||
static void
|
||||
static isc_boolean_t
|
||||
shutdown_names(dns_adb_t *adb) {
|
||||
int bucket;
|
||||
isc_boolean_t result = ISC_FALSE;
|
||||
dns_adbname_t *name;
|
||||
dns_adbname_t *next_name;
|
||||
|
||||
@@ -869,7 +887,8 @@ shutdown_names(dns_adb_t *adb) {
|
||||
* irefcnt ourselves, since it will not be
|
||||
* automatically triggered by a name being unlinked.
|
||||
*/
|
||||
dec_adb_irefcnt(adb);
|
||||
INSIST(result == ISC_FALSE);
|
||||
result = dec_adb_irefcnt(adb);
|
||||
} else {
|
||||
/*
|
||||
* Run through the list. For each name, clean up finds
|
||||
@@ -879,22 +898,26 @@ shutdown_names(dns_adb_t *adb) {
|
||||
*/
|
||||
while (name != NULL) {
|
||||
next_name = ISC_LIST_NEXT(name, plink);
|
||||
kill_name(&name, DNS_EVENT_ADBSHUTDOWN);
|
||||
INSIST(result == ISC_FALSE);
|
||||
result = kill_name(&name,
|
||||
DNS_EVENT_ADBSHUTDOWN);
|
||||
name = next_name;
|
||||
}
|
||||
}
|
||||
|
||||
UNLOCK(&adb->namelocks[bucket]);
|
||||
}
|
||||
return (result);
|
||||
}
|
||||
|
||||
/*
|
||||
* The ADB _MUST_ be locked before calling. Also, exit conditions must be
|
||||
* checked after calling this function.
|
||||
*/
|
||||
static void
|
||||
static isc_boolean_t
|
||||
shutdown_entries(dns_adb_t *adb) {
|
||||
int bucket;
|
||||
isc_boolean_t result = ISC_FALSE;
|
||||
dns_adbentry_t *entry;
|
||||
dns_adbentry_t *next_entry;
|
||||
|
||||
@@ -909,7 +932,7 @@ shutdown_entries(dns_adb_t *adb) {
|
||||
* irefcnt ourselves, since it will not be
|
||||
* automatically triggered by an entry being unlinked.
|
||||
*/
|
||||
dec_adb_irefcnt(adb);
|
||||
result = dec_adb_irefcnt(adb);
|
||||
} else {
|
||||
/*
|
||||
* Run through the list. Cleanup any entries not
|
||||
@@ -919,8 +942,10 @@ shutdown_entries(dns_adb_t *adb) {
|
||||
next_entry = ISC_LIST_NEXT(entry, plink);
|
||||
if (entry->refcnt == 0 &&
|
||||
entry->expires != 0) {
|
||||
unlink_entry(adb, entry);
|
||||
result = unlink_entry(adb, entry);
|
||||
free_adbentry(adb, &entry);
|
||||
if (result)
|
||||
result = dec_adb_irefcnt(adb);
|
||||
}
|
||||
entry = next_entry;
|
||||
}
|
||||
@@ -928,6 +953,7 @@ shutdown_entries(dns_adb_t *adb) {
|
||||
|
||||
UNLOCK(&adb->entrylocks[bucket]);
|
||||
}
|
||||
return (result);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -955,11 +981,12 @@ cancel_fetches_at_name(dns_adbname_t *name) {
|
||||
/*
|
||||
* Assumes the name bucket is locked.
|
||||
*/
|
||||
static void
|
||||
static isc_boolean_t
|
||||
clean_namehooks(dns_adb_t *adb, dns_adbnamehooklist_t *namehooks) {
|
||||
dns_adbentry_t *entry;
|
||||
dns_adbnamehook_t *namehook;
|
||||
int addr_bucket;
|
||||
isc_boolean_t result = ISC_FALSE;
|
||||
|
||||
addr_bucket = DNS_ADB_INVALIDBUCKET;
|
||||
namehook = ISC_LIST_HEAD(*namehooks);
|
||||
@@ -980,7 +1007,7 @@ clean_namehooks(dns_adb_t *adb, dns_adbnamehooklist_t *namehooks) {
|
||||
LOCK(&adb->entrylocks[addr_bucket]);
|
||||
}
|
||||
|
||||
dec_entry_refcnt(adb, entry, ISC_FALSE);
|
||||
result = dec_entry_refcnt(adb, entry, ISC_FALSE);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -995,6 +1022,7 @@ clean_namehooks(dns_adb_t *adb, dns_adbnamehooklist_t *namehooks) {
|
||||
|
||||
if (addr_bucket != DNS_ADB_INVALIDBUCKET)
|
||||
UNLOCK(&adb->entrylocks[addr_bucket]);
|
||||
return (result);
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -1183,23 +1211,33 @@ clean_finds_at_name(dns_adbname_t *name, isc_eventtype_t evtype,
|
||||
static inline void
|
||||
check_exit(dns_adb_t *adb) {
|
||||
isc_event_t *event;
|
||||
isc_task_t *etask;
|
||||
isc_boolean_t zeroirefcnt, zeroerefcnt;
|
||||
|
||||
/*
|
||||
* The caller must be holding the adb lock.
|
||||
*/
|
||||
if (adb->shutting_down) {
|
||||
/*
|
||||
* If there aren't any external references either, we're
|
||||
* done. Send the control event to initiate shutdown.
|
||||
*/
|
||||
INSIST(!adb->cevent_sent); /* Sanity check. */
|
||||
event = &adb->cevent;
|
||||
isc_task_send(adb->task, &event);
|
||||
adb->cevent_sent = ISC_TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
static inline isc_boolean_t
|
||||
dec_adb_irefcnt(dns_adb_t *adb) {
|
||||
isc_event_t *event;
|
||||
isc_task_t *etask;
|
||||
isc_boolean_t result = ISC_FALSE;
|
||||
|
||||
LOCK(&adb->reflock);
|
||||
zeroirefcnt = ISC_TF(adb->irefcnt == 0);
|
||||
zeroerefcnt = ISC_TF(adb->erefcnt == 0);
|
||||
UNLOCK(&adb->reflock);
|
||||
|
||||
if (adb->shutting_down && zeroirefcnt &&
|
||||
isc_mempool_getallocated(adb->ahmp) == 0) {
|
||||
/*
|
||||
* We're now shutdown. Send any whenshutdown events.
|
||||
*/
|
||||
INSIST(adb->irefcnt > 0);
|
||||
adb->irefcnt--;
|
||||
|
||||
if (adb->irefcnt == 0) {
|
||||
event = ISC_LIST_HEAD(adb->whenshutdown);
|
||||
while (event != NULL) {
|
||||
ISC_LIST_UNLINK(adb->whenshutdown, event, ev_link);
|
||||
@@ -1208,27 +1246,18 @@ check_exit(dns_adb_t *adb) {
|
||||
isc_task_sendanddetach(&etask, &event);
|
||||
event = ISC_LIST_HEAD(adb->whenshutdown);
|
||||
}
|
||||
|
||||
/*
|
||||
* If there aren't any external references either, we're
|
||||
* done. Send the control event to initiate shutdown.
|
||||
*/
|
||||
if (zeroerefcnt) {
|
||||
INSIST(!adb->cevent_sent); /* Sanity check. */
|
||||
event = &adb->cevent;
|
||||
isc_task_send(adb->task, &event);
|
||||
adb->cevent_sent = ISC_TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
if (adb->irefcnt == 0 && adb->erefcnt == 0)
|
||||
result = ISC_TRUE;
|
||||
UNLOCK(&adb->reflock);
|
||||
return (result);
|
||||
}
|
||||
|
||||
static inline void
|
||||
dec_adb_irefcnt(dns_adb_t *adb) {
|
||||
inc_adb_irefcnt(dns_adb_t *adb) {
|
||||
LOCK(&adb->reflock);
|
||||
|
||||
INSIST(adb->irefcnt > 0);
|
||||
adb->irefcnt--;
|
||||
|
||||
adb->irefcnt++;
|
||||
UNLOCK(&adb->reflock);
|
||||
}
|
||||
|
||||
@@ -1254,10 +1283,11 @@ inc_entry_refcnt(dns_adb_t *adb, dns_adbentry_t *entry, isc_boolean_t lock) {
|
||||
UNLOCK(&adb->entrylocks[bucket]);
|
||||
}
|
||||
|
||||
static inline void
|
||||
static inline isc_boolean_t
|
||||
dec_entry_refcnt(dns_adb_t *adb, dns_adbentry_t *entry, isc_boolean_t lock) {
|
||||
int bucket;
|
||||
isc_boolean_t destroy_entry;
|
||||
isc_boolean_t result = ISC_FALSE;
|
||||
|
||||
bucket = entry->lock_bucket;
|
||||
|
||||
@@ -1271,18 +1301,22 @@ dec_entry_refcnt(dns_adb_t *adb, dns_adbentry_t *entry, isc_boolean_t lock) {
|
||||
if (entry->refcnt == 0 &&
|
||||
(adb->entry_sd[bucket] || entry->expires == 0)) {
|
||||
destroy_entry = ISC_TRUE;
|
||||
unlink_entry(adb, entry);
|
||||
result = unlink_entry(adb, entry);
|
||||
}
|
||||
|
||||
if (lock)
|
||||
UNLOCK(&adb->entrylocks[bucket]);
|
||||
|
||||
if (!destroy_entry)
|
||||
return;
|
||||
return (result);
|
||||
|
||||
entry->lock_bucket = DNS_ADB_INVALIDBUCKET;
|
||||
|
||||
free_adbentry(adb, &entry);
|
||||
if (result)
|
||||
result =dec_adb_irefcnt(adb);
|
||||
|
||||
return (result);
|
||||
}
|
||||
|
||||
static inline dns_adbname_t *
|
||||
@@ -1497,6 +1531,7 @@ new_adbfind(dns_adb_t *adb) {
|
||||
ISC_EVENT_INIT(&h->event, sizeof(isc_event_t), 0, 0, 0, NULL, NULL,
|
||||
NULL, NULL, h);
|
||||
|
||||
inc_adb_irefcnt(adb);
|
||||
h->magic = DNS_ADBFIND_MAGIC;
|
||||
return (h);
|
||||
}
|
||||
@@ -1686,7 +1721,7 @@ free_adbfetch6(dns_adb_t *adb, dns_adbfetch6_t **fetch) {
|
||||
isc_mempool_put(adb->af6mp, f);
|
||||
}
|
||||
|
||||
static inline void
|
||||
static inline isc_boolean_t
|
||||
free_adbfind(dns_adb_t *adb, dns_adbfind_t **findp) {
|
||||
dns_adbfind_t *find;
|
||||
|
||||
@@ -1704,6 +1739,7 @@ free_adbfind(dns_adb_t *adb, dns_adbfind_t **findp) {
|
||||
|
||||
DESTROYLOCK(&find->lock);
|
||||
isc_mempool_put(adb->ahmp, find);
|
||||
return (dec_adb_irefcnt(adb));
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -1959,50 +1995,53 @@ shutdown_task(isc_task_t *task, isc_event_t *ev) {
|
||||
/*
|
||||
* Name bucket must be locked; adb may be locked; no other locks held.
|
||||
*/
|
||||
static void
|
||||
static isc_boolean_t
|
||||
check_expire_name(dns_adbname_t **namep, isc_stdtime_t now) {
|
||||
dns_adbname_t *name;
|
||||
isc_result_t result = ISC_FALSE;
|
||||
|
||||
INSIST(namep != NULL && DNS_ADBNAME_VALID(*namep));
|
||||
name = *namep;
|
||||
|
||||
if (NAME_HAS_V4(name) || NAME_HAS_V6(name))
|
||||
return;
|
||||
return (result);
|
||||
if (NAME_FETCH(name))
|
||||
return;
|
||||
return (result);
|
||||
if (!EXPIRE_OK(name->expire_v4, now))
|
||||
return;
|
||||
return (result);
|
||||
if (!EXPIRE_OK(name->expire_v6, now))
|
||||
return;
|
||||
return (result);
|
||||
if (!EXPIRE_OK(name->expire_target, now))
|
||||
return;
|
||||
return (result);
|
||||
|
||||
/*
|
||||
* The name is empty. Delete it.
|
||||
*/
|
||||
kill_name(&name, DNS_EVENT_ADBEXPIRED);
|
||||
result = kill_name(&name, DNS_EVENT_ADBEXPIRED);
|
||||
*namep = NULL;
|
||||
|
||||
/*
|
||||
* Our caller, or one of its callers, will be calling check_exit() at
|
||||
* some point, so we don't need to do it here.
|
||||
*/
|
||||
return (result);
|
||||
}
|
||||
|
||||
/*
|
||||
* Entry bucket must be locked; adb may be locked; no other locks held.
|
||||
*/
|
||||
static void
|
||||
static isc_boolean_t
|
||||
check_expire_entry(dns_adb_t *adb, dns_adbentry_t **entryp, isc_stdtime_t now)
|
||||
{
|
||||
dns_adbentry_t *entry;
|
||||
isc_boolean_t expire;
|
||||
isc_boolean_t result = ISC_FALSE;
|
||||
|
||||
INSIST(entryp != NULL && DNS_ADBENTRY_VALID(*entryp));
|
||||
entry = *entryp;
|
||||
|
||||
if (entry->refcnt != 0)
|
||||
return;
|
||||
return (result);
|
||||
|
||||
if (adb->overmem) {
|
||||
isc_uint32_t val;
|
||||
@@ -2014,49 +2053,57 @@ check_expire_entry(dns_adb_t *adb, dns_adbentry_t **entryp, isc_stdtime_t now)
|
||||
expire = ISC_FALSE;
|
||||
|
||||
if (entry->expires == 0 || (! expire && entry->expires > now))
|
||||
return;
|
||||
return (result);
|
||||
/*
|
||||
* The entry is not in use. Delete it.
|
||||
*/
|
||||
DP(DEF_LEVEL, "killing entry %p", entry);
|
||||
INSIST(ISC_LINK_LINKED(entry, plink));
|
||||
unlink_entry(adb, entry);
|
||||
result = unlink_entry(adb, entry);
|
||||
free_adbentry(adb, &entry);
|
||||
if (result)
|
||||
dec_adb_irefcnt(adb);
|
||||
*entryp = NULL;
|
||||
return (result);
|
||||
}
|
||||
|
||||
/*
|
||||
* ADB must be locked, and no other locks held.
|
||||
*/
|
||||
static void
|
||||
static isc_boolean_t
|
||||
cleanup_names(dns_adb_t *adb, int bucket, isc_stdtime_t now) {
|
||||
dns_adbname_t *name;
|
||||
dns_adbname_t *next_name;
|
||||
isc_result_t result = ISC_FALSE;
|
||||
|
||||
DP(CLEAN_LEVEL, "cleaning name bucket %d", bucket);
|
||||
|
||||
LOCK(&adb->namelocks[bucket]);
|
||||
if (adb->name_sd[bucket]) {
|
||||
UNLOCK(&adb->namelocks[bucket]);
|
||||
return;
|
||||
return (result);
|
||||
}
|
||||
|
||||
name = ISC_LIST_HEAD(adb->names[bucket]);
|
||||
while (name != NULL) {
|
||||
next_name = ISC_LIST_NEXT(name, plink);
|
||||
check_expire_namehooks(name, now, adb->overmem);
|
||||
check_expire_name(&name, now);
|
||||
INSIST(result == ISC_FALSE);
|
||||
result = check_expire_namehooks(name, now, adb->overmem);
|
||||
if (!result)
|
||||
result = check_expire_name(&name, now);
|
||||
name = next_name;
|
||||
}
|
||||
UNLOCK(&adb->namelocks[bucket]);
|
||||
return (result);
|
||||
}
|
||||
|
||||
/*
|
||||
* ADB must be locked, and no other locks held.
|
||||
*/
|
||||
static void
|
||||
static isc_boolean_t
|
||||
cleanup_entries(dns_adb_t *adb, int bucket, isc_stdtime_t now) {
|
||||
dns_adbentry_t *entry, *next_entry;
|
||||
isc_boolean_t result = ISC_FALSE;
|
||||
|
||||
DP(CLEAN_LEVEL, "cleaning entry bucket %d", bucket);
|
||||
|
||||
@@ -2064,10 +2111,12 @@ cleanup_entries(dns_adb_t *adb, int bucket, isc_stdtime_t now) {
|
||||
entry = ISC_LIST_HEAD(adb->entries[bucket]);
|
||||
while (entry != NULL) {
|
||||
next_entry = ISC_LIST_NEXT(entry, plink);
|
||||
check_expire_entry(adb, &entry, now);
|
||||
INSIST(result == ISC_FALSE);
|
||||
result = check_expire_entry(adb, &entry, now);
|
||||
entry = next_entry;
|
||||
}
|
||||
UNLOCK(&adb->entrylocks[bucket]);
|
||||
return (result);
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -2090,8 +2139,10 @@ timer_cleanup(isc_task_t *task, isc_event_t *ev) {
|
||||
/*
|
||||
* Call our cleanup routines.
|
||||
*/
|
||||
cleanup_names(adb, adb->next_cleanbucket, now);
|
||||
cleanup_entries(adb, adb->next_cleanbucket, now);
|
||||
INSIST(cleanup_names(adb, adb->next_cleanbucket, now) ==
|
||||
ISC_FALSE);
|
||||
INSIST(cleanup_entries(adb, adb->next_cleanbucket, now) ==
|
||||
ISC_FALSE);
|
||||
|
||||
/*
|
||||
* Set the next bucket to be cleaned.
|
||||
@@ -2346,7 +2397,7 @@ dns_adb_attach(dns_adb_t *adb, dns_adb_t **adbx) {
|
||||
void
|
||||
dns_adb_detach(dns_adb_t **adbx) {
|
||||
dns_adb_t *adb;
|
||||
isc_boolean_t zeroerefcnt;
|
||||
isc_boolean_t need_exit_check;
|
||||
|
||||
REQUIRE(adbx != NULL && DNS_ADB_VALID(*adbx));
|
||||
|
||||
@@ -2357,13 +2408,13 @@ dns_adb_detach(dns_adb_t **adbx) {
|
||||
|
||||
LOCK(&adb->reflock);
|
||||
adb->erefcnt--;
|
||||
zeroerefcnt = ISC_TF(adb->erefcnt == 0);
|
||||
need_exit_check = ISC_TF(adb->erefcnt == 0 && adb->irefcnt == 0);
|
||||
UNLOCK(&adb->reflock);
|
||||
|
||||
if (zeroerefcnt) {
|
||||
if (need_exit_check) {
|
||||
LOCK(&adb->lock);
|
||||
check_exit(adb);
|
||||
INSIST(adb->shutting_down);
|
||||
check_exit(adb);
|
||||
UNLOCK(&adb->lock);
|
||||
}
|
||||
}
|
||||
@@ -2388,7 +2439,6 @@ dns_adb_whenshutdown(dns_adb_t *adb, isc_task_t *task, isc_event_t **eventp) {
|
||||
|
||||
LOCK(&adb->reflock);
|
||||
zeroirefcnt = ISC_TF(adb->irefcnt == 0);
|
||||
UNLOCK(&adb->reflock);
|
||||
|
||||
if (adb->shutting_down && zeroirefcnt &&
|
||||
isc_mempool_getallocated(adb->ahmp) == 0) {
|
||||
@@ -2404,11 +2454,13 @@ dns_adb_whenshutdown(dns_adb_t *adb, isc_task_t *task, isc_event_t **eventp) {
|
||||
ISC_LIST_APPEND(adb->whenshutdown, event, ev_link);
|
||||
}
|
||||
|
||||
UNLOCK(&adb->reflock);
|
||||
UNLOCK(&adb->lock);
|
||||
}
|
||||
|
||||
void
|
||||
dns_adb_shutdown(dns_adb_t *adb) {
|
||||
isc_boolean_t need_check_exit;
|
||||
|
||||
/*
|
||||
* Shutdown 'adb'.
|
||||
@@ -2419,9 +2471,11 @@ dns_adb_shutdown(dns_adb_t *adb) {
|
||||
if (!adb->shutting_down) {
|
||||
adb->shutting_down = ISC_TRUE;
|
||||
isc_mem_setwater(adb->mctx, water, adb, 0, 0);
|
||||
shutdown_names(adb);
|
||||
shutdown_entries(adb);
|
||||
check_exit(adb);
|
||||
need_check_exit = shutdown_names(adb);
|
||||
if (!need_check_exit)
|
||||
need_check_exit = shutdown_entries(adb);
|
||||
if (need_check_exit)
|
||||
check_exit(adb);
|
||||
}
|
||||
|
||||
UNLOCK(&adb->lock);
|
||||
@@ -2508,7 +2562,7 @@ dns_adb_createfind(dns_adb_t *adb, isc_task_t *task, isc_taskaction_t action,
|
||||
if (adb->name_sd[bucket]) {
|
||||
DP(DEF_LEVEL,
|
||||
"dns_adb_createfind: returning ISC_R_SHUTTINGDOWN");
|
||||
free_adbfind(adb, &find);
|
||||
INSIST(free_adbfind(adb, &find) == ISC_FALSE);
|
||||
result = ISC_R_SHUTTINGDOWN;
|
||||
goto out;
|
||||
}
|
||||
@@ -2519,7 +2573,7 @@ dns_adb_createfind(dns_adb_t *adb, isc_task_t *task, isc_taskaction_t action,
|
||||
if (adbname == NULL) {
|
||||
adbname = new_adbname(adb, name);
|
||||
if (adbname == NULL) {
|
||||
free_adbfind(adb, &find);
|
||||
INSIST(free_adbfind(adb, &find) == ISC_FALSE);
|
||||
result = ISC_R_NOMEMORY;
|
||||
goto out;
|
||||
}
|
||||
@@ -2535,7 +2589,7 @@ dns_adb_createfind(dns_adb_t *adb, isc_task_t *task, isc_taskaction_t action,
|
||||
/*
|
||||
* Expire old entries, etc.
|
||||
*/
|
||||
check_expire_namehooks(adbname, now, adb->overmem);
|
||||
INSIST(check_expire_namehooks(adbname, now, adb->overmem) == ISC_FALSE);
|
||||
|
||||
/*
|
||||
* Do we know that the name is an alias?
|
||||
@@ -2818,7 +2872,7 @@ dns_adb_destroyfind(dns_adbfind_t **findp) {
|
||||
entry = ai->entry;
|
||||
ai->entry = NULL;
|
||||
INSIST(DNS_ADBENTRY_VALID(entry));
|
||||
dec_entry_refcnt(adb, entry, ISC_TRUE);
|
||||
INSIST(dec_entry_refcnt(adb, entry, ISC_TRUE) == ISC_FALSE);
|
||||
free_adbaddrinfo(adb, &ai);
|
||||
ai = ISC_LIST_HEAD(find->list);
|
||||
}
|
||||
@@ -2831,8 +2885,8 @@ dns_adb_destroyfind(dns_adbfind_t **findp) {
|
||||
* lock is destroyed.
|
||||
*/
|
||||
LOCK(&adb->lock);
|
||||
free_adbfind(adb, &find);
|
||||
check_exit(adb);
|
||||
if (free_adbfind(adb, &find))
|
||||
check_exit(adb);
|
||||
UNLOCK(&adb->lock);
|
||||
}
|
||||
|
||||
@@ -3427,14 +3481,7 @@ fetch_callback(isc_task_t *task, isc_event_t *ev) {
|
||||
free_adbfetch(adb, &fetch);
|
||||
isc_event_free(&ev);
|
||||
|
||||
kill_name(&name, DNS_EVENT_ADBCANCELED);
|
||||
|
||||
/*
|
||||
* 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;
|
||||
want_check_exit = kill_name(&name, DNS_EVENT_ADBCANCELED);
|
||||
|
||||
UNLOCK(&adb->namelocks[bucket]);
|
||||
|
||||
@@ -3597,14 +3644,7 @@ fetch_callback_a6(isc_task_t *task, isc_event_t *ev) {
|
||||
free_adbfetch6(adb, &fetch);
|
||||
isc_event_free(&ev);
|
||||
|
||||
kill_name(&name, DNS_EVENT_ADBCANCELED);
|
||||
|
||||
/*
|
||||
* 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;
|
||||
want_check_exit = kill_name(&name, DNS_EVENT_ADBCANCELED);
|
||||
|
||||
UNLOCK(&adb->namelocks[bucket]);
|
||||
|
||||
@@ -4061,9 +4101,7 @@ dns_adb_freeaddrinfo(dns_adb_t *adb, dns_adbaddrinfo_t **addrp) {
|
||||
|
||||
entry->expires = now + 1800; /* XXXRTH */
|
||||
|
||||
dec_entry_refcnt(adb, entry, ISC_FALSE);
|
||||
if (adb->entry_sd[bucket] && adb->entry_refcnt[bucket] == 0)
|
||||
want_check_exit = ISC_TRUE;
|
||||
want_check_exit = dec_entry_refcnt(adb, entry, ISC_FALSE);
|
||||
|
||||
UNLOCK(&adb->entrylocks[bucket]);
|
||||
|
||||
@@ -4089,8 +4127,8 @@ dns_adb_flush(dns_adb_t *adb) {
|
||||
/*
|
||||
* Call our cleanup routines.
|
||||
*/
|
||||
cleanup_names(adb, i, INT_MAX);
|
||||
cleanup_entries(adb, i, INT_MAX);
|
||||
INSIST(cleanup_names(adb, i, INT_MAX) == ISC_FALSE);
|
||||
INSIST(cleanup_entries(adb, i, INT_MAX) == ISC_FALSE);
|
||||
}
|
||||
|
||||
#ifdef DUMP_ADB_AFTER_CLEANING
|
||||
@@ -4116,7 +4154,8 @@ dns_adb_flushname(dns_adb_t *adb, dns_name_t *name) {
|
||||
nextname = ISC_LIST_NEXT(adbname, plink);
|
||||
if (!NAME_DEAD(adbname) &&
|
||||
dns_name_equal(name, &adbname->name)) {
|
||||
kill_name(&adbname, DNS_EVENT_ADBCANCELED);
|
||||
INSIST(kill_name(&adbname, DNS_EVENT_ADBCANCELED)
|
||||
== ISC_FALSE);
|
||||
}
|
||||
adbname = nextname;
|
||||
}
|
||||
|
Reference in New Issue
Block a user