diff options
Diffstat (limited to 'contrib/bind9/lib/dns/adb.c')
-rw-r--r-- | contrib/bind9/lib/dns/adb.c | 64 |
1 files changed, 44 insertions, 20 deletions
diff --git a/contrib/bind9/lib/dns/adb.c b/contrib/bind9/lib/dns/adb.c index c65c474..ae5dec8 100644 --- a/contrib/bind9/lib/dns/adb.c +++ b/contrib/bind9/lib/dns/adb.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2004-2007 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2004-2008 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 1999-2003 Internet Software Consortium. * * Permission to use, copy, modify, and/or distribute this software for any @@ -15,9 +15,9 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: adb.c,v 1.215.18.17 2007/09/11 02:23:26 marka Exp $ */ +/* $Id: adb.c,v 1.215.18.24 2008/10/17 03:35:14 marka Exp $ */ -/*! \file +/*! \file * * \note * In finds, if task == NULL, no events will be generated, and no events @@ -71,7 +71,7 @@ #define DNS_ADBFETCH6_MAGIC ISC_MAGIC('a', 'd', 'F', '6') #define DNS_ADBFETCH6_VALID(x) ISC_MAGIC_VALID(x, DNS_ADBFETCH6_MAGIC) -/*! +/*! * The number of buckets needs to be a prime (for good hashing). * * XXXRTH How many buckets do we need? @@ -119,6 +119,7 @@ struct dns_adb { isc_mutex_t lock; isc_mutex_t reflock; /*%< Covers irefcnt, erefcnt */ + isc_mutex_t overmemlock; /*%< Covers overmem */ isc_mem_t *mctx; dns_view_t *view; isc_timermgr_t *timermgr; @@ -494,6 +495,7 @@ import_rdataset(dns_adbname_t *adbname, dns_rdataset_t *rdataset, isc_boolean_t new_addresses_added; dns_rdatatype_t rdtype; unsigned int findoptions; + dns_adbnamehooklist_t *hookhead; INSIST(DNS_ADBNAME_VALID(adbname)); adb = adbname->adb; @@ -518,10 +520,12 @@ import_rdataset(dns_adbname_t *adbname, dns_rdataset_t *rdataset, INSIST(rdata.length == 4); memcpy(&ina.s_addr, rdata.data, 4); isc_sockaddr_fromin(&sockaddr, &ina, 0); + hookhead = &adbname->v4; } else { INSIST(rdata.length == 16); memcpy(in6a.s6_addr, rdata.data, 16); isc_sockaddr_fromin6(&sockaddr, &in6a, 0); + hookhead = &adbname->v6; } INSIST(nh == NULL); @@ -550,7 +554,7 @@ import_rdataset(dns_adbname_t *adbname, dns_rdataset_t *rdataset, link_entry(adb, addr_bucket, entry); } else { - for (anh = ISC_LIST_HEAD(adbname->v4); + for (anh = ISC_LIST_HEAD(*hookhead); anh != NULL; anh = ISC_LIST_NEXT(anh, plink)) if (anh->entry == foundentry) @@ -563,12 +567,8 @@ import_rdataset(dns_adbname_t *adbname, dns_rdataset_t *rdataset, } new_addresses_added = ISC_TRUE; - if (nh != NULL) { - if (rdtype == dns_rdatatype_a) - ISC_LIST_APPEND(adbname->v4, nh, plink); - else - ISC_LIST_APPEND(adbname->v6, nh, plink); - } + if (nh != NULL) + ISC_LIST_APPEND(*hookhead, nh, plink); nh = NULL; result = dns_rdataset_next(rdataset); } @@ -1738,8 +1738,11 @@ copy_namehook_lists(dns_adb_t *adb, dns_adbfind_t *find, dns_name_t *qname, bucket = entry->lock_bucket; LOCK(&adb->entrylocks[bucket]); - if (entry_is_lame(adb, entry, qname, qtype, now)) + if (!FIND_RETURNLAME(find) + && entry_is_lame(adb, entry, qname, qtype, now)) { + find->options |= DNS_ADBFIND_LAMEPRUNED; goto nextv6; + } addrinfo = new_adbaddrinfo(adb, entry, find->port); if (addrinfo == NULL) { find->partial_result |= DNS_ADBFIND_INET6; @@ -1773,12 +1776,15 @@ shutdown_task(isc_task_t *task, isc_event_t *ev) { INSIST(DNS_ADB_VALID(adb)); /* + * Wait for lock around check_exit() call to be released. + */ + LOCK(&adb->lock); + /* * Kill the timer, and then the ADB itself. Note that this implies * that this task was the one scheduled to get timer events. If * this is not true (and it is unfortunate there is no way to INSIST() * this) badness will occur. */ - LOCK(&adb->lock); isc_timer_detach(&adb->timer); UNLOCK(&adb->lock); isc_event_free(&ev); @@ -1990,6 +1996,7 @@ destroy(dns_adb_t *adb) { DESTROYLOCK(&adb->reflock); DESTROYLOCK(&adb->lock); DESTROYLOCK(&adb->mplock); + DESTROYLOCK(&adb->overmemlock); isc_mem_putanddetach(&adb->mctx, adb, sizeof(dns_adb_t)); } @@ -2060,6 +2067,10 @@ dns_adb_create(isc_mem_t *mem, dns_view_t *view, isc_timermgr_t *timermgr, if (result != ISC_R_SUCCESS) goto fail0d; + result = isc_mutex_init(&adb->overmemlock); + if (result != ISC_R_SUCCESS) + goto fail0e; + /* * Initialize the bucket locks for names and elements. * May as well initialize the list heads, too. @@ -2162,6 +2173,8 @@ dns_adb_create(isc_mem_t *mem, dns_view_t *view, isc_timermgr_t *timermgr, if (adb->afmp != NULL) isc_mempool_destroy(&adb->afmp); + DESTROYLOCK(&adb->overmemlock); + fail0e: DESTROYLOCK(&adb->reflock); fail0d: DESTROYLOCK(&adb->mplock); @@ -3133,8 +3146,10 @@ fetch_callback(isc_task_t *task, isc_event_t *ev) { address_type = DNS_ADBFIND_INET6; fetch = name->fetch_aaaa; name->fetch_aaaa = NULL; - } - INSIST(address_type != 0); + } else + fetch = NULL; + + INSIST(address_type != 0 && fetch != NULL); dns_resolver_destroyfetch(&fetch->fetch); dev->fetch = NULL; @@ -3582,12 +3597,21 @@ water(void *arg, int mark) { DP(ISC_LOG_DEBUG(1), "adb reached %s water mark", overmem ? "high" : "low"); - adb->overmem = overmem; - if (overmem) { - isc_interval_set(&interval, 0, 1); - (void)isc_timer_reset(adb->timer, isc_timertype_once, NULL, - &interval, ISC_TRUE); + /* + * We can't use adb->lock as there is potential for water + * to be called when adb->lock is held. + */ + LOCK(&adb->overmemlock); + if (adb->overmem != overmem) { + adb->overmem = overmem; + if (overmem) { + isc_interval_set(&interval, 0, 1); + (void)isc_timer_reset(adb->timer, isc_timertype_once, + NULL, &interval, ISC_TRUE); + } + isc_mem_waterack(adb->mctx, mark); } + UNLOCK(&adb->overmemlock); } void |