diff options
Diffstat (limited to 'lib/dns/resolver.c')
-rw-r--r-- | lib/dns/resolver.c | 228 |
1 files changed, 124 insertions, 104 deletions
diff --git a/lib/dns/resolver.c b/lib/dns/resolver.c index 3084dd8a1c95..1ae2f16bea3f 100644 --- a/lib/dns/resolver.c +++ b/lib/dns/resolver.c @@ -180,7 +180,9 @@ struct fetchctx { dns_rdatatype_t type; unsigned int options; unsigned int bucketnum; - char * info; + char * info; + isc_mem_t * mctx; + /*% Locked by appropriate bucket lock. */ fetchstate state; isc_boolean_t want_shutdown; @@ -446,7 +448,8 @@ static void resquery_response(isc_task_t *task, isc_event_t *event); static void resquery_connected(isc_task_t *task, isc_event_t *event); static void fctx_try(fetchctx_t *fctx, isc_boolean_t retrying, isc_boolean_t badcache); -static isc_boolean_t fctx_destroy(fetchctx_t *fctx); +static void fctx_destroy(fetchctx_t *fctx); +static isc_boolean_t fctx_unlink(fetchctx_t *fctx); static isc_result_t ncache_adderesult(dns_message_t *message, dns_db_t *cache, dns_dbnode_t *node, dns_rdatatype_t covers, @@ -478,8 +481,7 @@ valcreate(fetchctx_t *fctx, dns_adbaddrinfo_t *addrinfo, dns_name_t *name, dns_valarg_t *valarg; isc_result_t result; - valarg = isc_mem_get(fctx->res->buckets[fctx->bucketnum].mctx, - sizeof(*valarg)); + valarg = isc_mem_get(fctx->mctx, sizeof(*valarg)); if (valarg == NULL) return (ISC_R_NOMEMORY); @@ -501,8 +503,7 @@ valcreate(fetchctx_t *fctx, dns_adbaddrinfo_t *addrinfo, dns_name_t *name, } ISC_LIST_APPEND(fctx->validators, validator, link); } else - isc_mem_put(fctx->res->buckets[fctx->bucketnum].mctx, - valarg, sizeof(*valarg)); + isc_mem_put(fctx->mctx, valarg, sizeof(*valarg)); return (result); } @@ -1386,13 +1387,12 @@ fctx_query(fetchctx_t *fctx, dns_adbaddrinfo_t *addrinfo, dns_message_reset(fctx->rmessage, DNS_MESSAGE_INTENTPARSE); - query = isc_mem_get(res->buckets[fctx->bucketnum].mctx, - sizeof(*query)); + query = isc_mem_get(fctx->mctx, sizeof(*query)); if (query == NULL) { result = ISC_R_NOMEMORY; goto stop_idle_timer; } - query->mctx = res->buckets[fctx->bucketnum].mctx; + query->mctx = fctx->mctx; query->options = options; query->attributes = 0; query->sends = 0; @@ -1569,8 +1569,7 @@ fctx_query(fetchctx_t *fctx, dns_adbaddrinfo_t *addrinfo, cleanup_query: if (query->connects == 0) { query->magic = 0; - isc_mem_put(res->buckets[fctx->bucketnum].mctx, - query, sizeof(*query)); + isc_mem_put(fctx->mctx, query, sizeof(*query)); } stop_idle_timer: @@ -1600,8 +1599,7 @@ add_bad_edns(fetchctx_t *fctx, isc_sockaddr_t *address) { if (bad_edns(fctx, address)) return; - sa = isc_mem_get(fctx->res->buckets[fctx->bucketnum].mctx, - sizeof(*sa)); + sa = isc_mem_get(fctx->mctx, sizeof(*sa)); if (sa == NULL) return; @@ -1630,8 +1628,7 @@ add_triededns(fetchctx_t *fctx, isc_sockaddr_t *address) { if (triededns(fctx, address)) return; - sa = isc_mem_get(fctx->res->buckets[fctx->bucketnum].mctx, - sizeof(*sa)); + sa = isc_mem_get(fctx->mctx, sizeof(*sa)); if (sa == NULL) return; @@ -1660,8 +1657,7 @@ add_triededns512(fetchctx_t *fctx, isc_sockaddr_t *address) { if (triededns512(fctx, address)) return; - sa = isc_mem_get(fctx->res->buckets[fctx->bucketnum].mctx, - sizeof(*sa)); + sa = isc_mem_get(fctx->mctx, sizeof(*sa)); if (sa == NULL) return; @@ -2166,8 +2162,8 @@ fctx_finddone(isc_task_t *task, isc_event_t *event) { isc_boolean_t want_try = ISC_FALSE; isc_boolean_t want_done = ISC_FALSE; isc_boolean_t bucket_empty = ISC_FALSE; - isc_boolean_t destroy = ISC_FALSE; unsigned int bucketnum; + isc_boolean_t destroy = ISC_FALSE; find = event->ev_sender; fctx = event->ev_arg; @@ -2205,17 +2201,14 @@ fctx_finddone(isc_task_t *task, isc_event_t *event) { } } else if (SHUTTINGDOWN(fctx) && fctx->pending == 0 && fctx->nqueries == 0 && ISC_LIST_EMPTY(fctx->validators)) { - /* - * Note that we had to wait until we had the lock before - * looking at fctx->references. - */ - if (fctx->references == 0) + + if (fctx->references == 0) { + bucket_empty = fctx_unlink(fctx); destroy = ISC_TRUE; + } } UNLOCK(&res->buckets[bucketnum].lock); - if (destroy) - bucket_empty = fctx_destroy(fctx); isc_event_free(&event); dns_adb_destroyfind(&find); @@ -2223,8 +2216,11 @@ fctx_finddone(isc_task_t *task, isc_event_t *event) { fctx_try(fctx, ISC_TRUE, ISC_FALSE); else if (want_done) fctx_done(fctx, ISC_R_FAILURE, __LINE__); - else if (bucket_empty) - empty_bucket(res); + else if (destroy) { + fctx_destroy(fctx); + if (bucket_empty) + empty_bucket(res); + } } @@ -2347,8 +2343,7 @@ add_bad(fetchctx_t *fctx, dns_adbaddrinfo_t *addrinfo, isc_result_t reason, FCTXTRACE("add_bad"); - sa = isc_mem_get(fctx->res->buckets[fctx->bucketnum].mctx, - sizeof(*sa)); + sa = isc_mem_get(fctx->mctx, sizeof(*sa)); if (sa == NULL) return; *sa = *address; @@ -2631,12 +2626,9 @@ fctx_getaddresses(fetchctx_t *fctx, isc_boolean_t badcache) { fctx->fwdpolicy = forwarders->fwdpolicy; if (fctx->fwdpolicy == dns_fwdpolicy_only && isstrictsubdomain(domain, &fctx->domain)) { - isc_mem_t *mctx; - - mctx = res->buckets[fctx->bucketnum].mctx; - dns_name_free(&fctx->domain, mctx); + dns_name_free(&fctx->domain, fctx->mctx); dns_name_init(&fctx->domain, NULL); - result = dns_name_dup(domain, mctx, + result = dns_name_dup(domain, fctx->mctx, &fctx->domain); if (result != ISC_R_SUCCESS) return (result); @@ -3075,10 +3067,9 @@ fctx_try(fetchctx_t *fctx, isc_boolean_t retrying, isc_boolean_t badcache) { } static isc_boolean_t -fctx_destroy(fetchctx_t *fctx) { +fctx_unlink(fetchctx_t *fctx) { dns_resolver_t *res; unsigned int bucketnum; - isc_sockaddr_t *sa, *next_sa; /* * Caller must be holding the bucket lock. @@ -3095,13 +3086,42 @@ fctx_destroy(fetchctx_t *fctx) { REQUIRE(fctx->references == 0); REQUIRE(ISC_LIST_EMPTY(fctx->validators)); - FCTXTRACE("destroy"); + FCTXTRACE("unlink"); res = fctx->res; bucketnum = fctx->bucketnum; ISC_LIST_UNLINK(res->buckets[bucketnum].fctxs, fctx, link); + LOCK(&res->nlock); + res->nfctx--; + UNLOCK(&res->nlock); + + if (res->buckets[bucketnum].exiting && + ISC_LIST_EMPTY(res->buckets[bucketnum].fctxs)) + return (ISC_TRUE); + + return (ISC_FALSE); +} + +static void +fctx_destroy(fetchctx_t *fctx) { + isc_sockaddr_t *sa, *next_sa; + + REQUIRE(VALID_FCTX(fctx)); + REQUIRE(fctx->state == fetchstate_done || + fctx->state == fetchstate_init); + REQUIRE(ISC_LIST_EMPTY(fctx->events)); + REQUIRE(ISC_LIST_EMPTY(fctx->queries)); + REQUIRE(ISC_LIST_EMPTY(fctx->finds)); + REQUIRE(ISC_LIST_EMPTY(fctx->altfinds)); + REQUIRE(fctx->pending == 0); + REQUIRE(fctx->references == 0); + REQUIRE(ISC_LIST_EMPTY(fctx->validators)); + REQUIRE(!ISC_LINK_LINKED(fctx, link)); + + FCTXTRACE("destroy"); + /* * Free bad. */ @@ -3110,7 +3130,7 @@ fctx_destroy(fetchctx_t *fctx) { sa = next_sa) { next_sa = ISC_LIST_NEXT(sa, link); ISC_LIST_UNLINK(fctx->bad, sa, link); - isc_mem_put(res->buckets[bucketnum].mctx, sa, sizeof(*sa)); + isc_mem_put(fctx->mctx, sa, sizeof(*sa)); } for (sa = ISC_LIST_HEAD(fctx->edns); @@ -3118,7 +3138,7 @@ fctx_destroy(fetchctx_t *fctx) { sa = next_sa) { next_sa = ISC_LIST_NEXT(sa, link); ISC_LIST_UNLINK(fctx->edns, sa, link); - isc_mem_put(res->buckets[bucketnum].mctx, sa, sizeof(*sa)); + isc_mem_put(fctx->mctx, sa, sizeof(*sa)); } for (sa = ISC_LIST_HEAD(fctx->edns512); @@ -3126,7 +3146,7 @@ fctx_destroy(fetchctx_t *fctx) { sa = next_sa) { next_sa = ISC_LIST_NEXT(sa, link); ISC_LIST_UNLINK(fctx->edns512, sa, link); - isc_mem_put(res->buckets[bucketnum].mctx, sa, sizeof(*sa)); + isc_mem_put(fctx->mctx, sa, sizeof(*sa)); } for (sa = ISC_LIST_HEAD(fctx->bad_edns); @@ -3134,31 +3154,21 @@ fctx_destroy(fetchctx_t *fctx) { sa = next_sa) { next_sa = ISC_LIST_NEXT(sa, link); ISC_LIST_UNLINK(fctx->bad_edns, sa, link); - isc_mem_put(res->buckets[bucketnum].mctx, sa, sizeof(*sa)); + isc_mem_put(fctx->mctx, sa, sizeof(*sa)); } isc_timer_detach(&fctx->timer); dns_message_destroy(&fctx->rmessage); dns_message_destroy(&fctx->qmessage); if (dns_name_countlabels(&fctx->domain) > 0) - dns_name_free(&fctx->domain, res->buckets[bucketnum].mctx); + dns_name_free(&fctx->domain, fctx->mctx); if (dns_rdataset_isassociated(&fctx->nameservers)) dns_rdataset_disassociate(&fctx->nameservers); - dns_name_free(&fctx->name, res->buckets[bucketnum].mctx); + dns_name_free(&fctx->name, fctx->mctx); dns_db_detach(&fctx->cache); dns_adb_detach(&fctx->adb); - isc_mem_free(res->buckets[bucketnum].mctx, fctx->info); - isc_mem_put(res->buckets[bucketnum].mctx, fctx, sizeof(*fctx)); - - LOCK(&res->nlock); - res->nfctx--; - UNLOCK(&res->nlock); - - if (res->buckets[bucketnum].exiting && - ISC_LIST_EMPTY(res->buckets[bucketnum].fctxs)) - return (ISC_TRUE); - - return (ISC_FALSE); + isc_mem_free(fctx->mctx, fctx->info); + isc_mem_putanddetach(&fctx->mctx, fctx, sizeof(*fctx)); } /* @@ -3258,6 +3268,7 @@ fctx_doshutdown(isc_task_t *task, isc_event_t *event) { dns_resolver_t *res; unsigned int bucketnum; dns_validator_t *validator; + isc_boolean_t destroy = ISC_FALSE; REQUIRE(VALID_FCTX(fctx)); @@ -3307,13 +3318,18 @@ fctx_doshutdown(isc_task_t *task, isc_event_t *event) { } if (fctx->references == 0 && fctx->pending == 0 && - fctx->nqueries == 0 && ISC_LIST_EMPTY(fctx->validators)) - bucket_empty = fctx_destroy(fctx); + fctx->nqueries == 0 && ISC_LIST_EMPTY(fctx->validators)) { + bucket_empty = fctx_unlink(fctx); + destroy = ISC_TRUE; + } UNLOCK(&res->buckets[bucketnum].lock); - if (bucket_empty) - empty_bucket(res); + if (destroy) { + fctx_destroy(fctx); + if (bucket_empty) + empty_bucket(res); + } } static void @@ -3322,6 +3338,7 @@ fctx_start(isc_task_t *task, isc_event_t *event) { isc_boolean_t done = ISC_FALSE, bucket_empty = ISC_FALSE; dns_resolver_t *res; unsigned int bucketnum; + isc_boolean_t destroy = ISC_FALSE; REQUIRE(VALID_FCTX(fctx)); @@ -3354,7 +3371,8 @@ fctx_start(isc_task_t *task, isc_event_t *event) { /* * It's now safe to destroy this fctx. */ - bucket_empty = fctx_destroy(fctx); + bucket_empty = fctx_unlink(fctx); + destroy = ISC_TRUE; } done = ISC_TRUE; } else { @@ -3376,6 +3394,8 @@ fctx_start(isc_task_t *task, isc_event_t *event) { if (!done) { isc_result_t result; + INSIST(!destroy); + /* * All is well. Start working on the fetch. */ @@ -3384,8 +3404,11 @@ fctx_start(isc_task_t *task, isc_event_t *event) { fctx_done(fctx, result, __LINE__); else fctx_try(fctx, ISC_FALSE, ISC_FALSE); - } else if (bucket_empty) - empty_bucket(res); + } else if (destroy) { + fctx_destroy(fctx); + if (bucket_empty) + empty_bucket(res); + } } /* @@ -3473,27 +3496,29 @@ fctx_create(dns_resolver_t *res, dns_name_t *name, dns_rdatatype_t type, char buf[DNS_NAME_FORMATSIZE + DNS_RDATATYPE_FORMATSIZE]; char typebuf[DNS_RDATATYPE_FORMATSIZE]; dns_name_t suffix; + isc_mem_t *mctx; /* * Caller must be holding the lock for bucket number 'bucketnum'. */ REQUIRE(fctxp != NULL && *fctxp == NULL); - fctx = isc_mem_get(res->buckets[bucketnum].mctx, sizeof(*fctx)); + mctx = res->buckets[bucketnum].mctx; + fctx = isc_mem_get(mctx, sizeof(*fctx)); if (fctx == NULL) return (ISC_R_NOMEMORY); dns_name_format(name, buf, sizeof(buf)); dns_rdatatype_format(type, typebuf, sizeof(typebuf)); strcat(buf, "/"); /* checked */ strcat(buf, typebuf); /* checked */ - fctx->info = isc_mem_strdup(res->buckets[bucketnum].mctx, buf); + fctx->info = isc_mem_strdup(mctx, buf); if (fctx->info == NULL) { result = ISC_R_NOMEMORY; goto cleanup_fetch; } FCTXTRACE("create"); dns_name_init(&fctx->name, NULL); - result = dns_name_dup(name, res->buckets[bucketnum].mctx, &fctx->name); + result = dns_name_dup(name, mctx, &fctx->name); if (result != ISC_R_SUCCESS) goto cleanup_info; dns_name_init(&fctx->domain, NULL); @@ -3596,9 +3621,7 @@ fctx_create(dns_resolver_t *res, dns_name_t *name, dns_rdatatype_t type, NULL); if (result != ISC_R_SUCCESS) goto cleanup_name; - result = dns_name_dup(domain, - res->buckets[bucketnum].mctx, - &fctx->domain); + result = dns_name_dup(domain, mctx, &fctx->domain); if (result != ISC_R_SUCCESS) { dns_rdataset_disassociate(&fctx->nameservers); goto cleanup_name; @@ -3609,16 +3632,12 @@ fctx_create(dns_resolver_t *res, dns_name_t *name, dns_rdatatype_t type, /* * We're in forward-only mode. Set the query domain. */ - result = dns_name_dup(domain, - res->buckets[bucketnum].mctx, - &fctx->domain); + result = dns_name_dup(domain, mctx, &fctx->domain); if (result != ISC_R_SUCCESS) goto cleanup_name; } } else { - result = dns_name_dup(domain, - res->buckets[bucketnum].mctx, - &fctx->domain); + result = dns_name_dup(domain, mctx, &fctx->domain); if (result != ISC_R_SUCCESS) goto cleanup_name; dns_rdataset_clone(nameservers, &fctx->nameservers); @@ -3631,16 +3650,14 @@ fctx_create(dns_resolver_t *res, dns_name_t *name, dns_rdatatype_t type, INSIST(dns_name_issubdomain(&fctx->name, &fctx->domain)); fctx->qmessage = NULL; - result = dns_message_create(res->buckets[bucketnum].mctx, - DNS_MESSAGE_INTENTRENDER, + result = dns_message_create(mctx, DNS_MESSAGE_INTENTRENDER, &fctx->qmessage); if (result != ISC_R_SUCCESS) goto cleanup_domain; fctx->rmessage = NULL; - result = dns_message_create(res->buckets[bucketnum].mctx, - DNS_MESSAGE_INTENTPARSE, + result = dns_message_create(mctx, DNS_MESSAGE_INTENTPARSE, &fctx->rmessage); if (result != ISC_R_SUCCESS) @@ -3690,6 +3707,8 @@ fctx_create(dns_resolver_t *res, dns_name_t *name, dns_rdatatype_t type, dns_db_attach(res->view->cachedb, &fctx->cache); fctx->adb = NULL; dns_adb_attach(res->view->adb, &fctx->adb); + fctx->mctx = NULL; + isc_mem_attach(mctx, &fctx->mctx); ISC_LIST_INIT(fctx->events); ISC_LINK_INIT(fctx, link); @@ -3713,18 +3732,18 @@ fctx_create(dns_resolver_t *res, dns_name_t *name, dns_rdatatype_t type, cleanup_domain: if (dns_name_countlabels(&fctx->domain) > 0) - dns_name_free(&fctx->domain, res->buckets[bucketnum].mctx); + dns_name_free(&fctx->domain, mctx); if (dns_rdataset_isassociated(&fctx->nameservers)) dns_rdataset_disassociate(&fctx->nameservers); cleanup_name: - dns_name_free(&fctx->name, res->buckets[bucketnum].mctx); + dns_name_free(&fctx->name, mctx); cleanup_info: - isc_mem_free(res->buckets[bucketnum].mctx, fctx->info); + isc_mem_free(mctx, fctx->info); cleanup_fetch: - isc_mem_put(res->buckets[bucketnum].mctx, fctx, sizeof(*fctx)); + isc_mem_put(mctx, fctx, sizeof(*fctx)); return (result); } @@ -3934,6 +3953,7 @@ maybe_destroy(fetchctx_t *fctx, isc_boolean_t locked) { isc_boolean_t bucket_empty = ISC_FALSE; dns_resolver_t *res = fctx->res; dns_validator_t *validator, *next_validator; + isc_boolean_t destroy = ISC_FALSE; REQUIRE(SHUTTINGDOWN(fctx)); @@ -3949,11 +3969,15 @@ maybe_destroy(fetchctx_t *fctx, isc_boolean_t locked) { dns_validator_cancel(validator); } - if (fctx->references == 0 && ISC_LIST_EMPTY(fctx->validators)) - bucket_empty = fctx_destroy(fctx); + if (fctx->references == 0 && ISC_LIST_EMPTY(fctx->validators)) { + bucket_empty = fctx_unlink(fctx); + destroy = ISC_TRUE; + } unlock: if (!locked) UNLOCK(&res->buckets[bucketnum].lock); + if (destroy) + fctx_destroy(fctx); return (bucket_empty); } @@ -4008,8 +4032,7 @@ validated(isc_task_t *task, isc_event_t *event) { * destroy the fctx if necessary. */ dns_validator_destroy(&vevent->validator); - isc_mem_put(res->buckets[fctx->bucketnum].mctx, - valarg, sizeof(*valarg)); + isc_mem_put(fctx->mctx, valarg, sizeof(*valarg)); negative = ISC_TF(vevent->rdataset == NULL); @@ -5723,14 +5746,11 @@ noanswer_response(fetchctx_t *fctx, dns_name_t *oqname, * if so we should bail out. */ INSIST(dns_name_countlabels(&fctx->domain) > 0); - dns_name_free(&fctx->domain, - fctx->res->buckets[fctx->bucketnum].mctx); + dns_name_free(&fctx->domain, fctx->mctx); if (dns_rdataset_isassociated(&fctx->nameservers)) dns_rdataset_disassociate(&fctx->nameservers); dns_name_init(&fctx->domain, NULL); - result = dns_name_dup(ns_name, - fctx->res->buckets[fctx->bucketnum].mctx, - &fctx->domain); + result = dns_name_dup(ns_name, fctx->mctx, &fctx->domain); if (result != ISC_R_SUCCESS) return (result); fctx->attributes |= FCTX_ATTR_WANTCACHE; @@ -6232,7 +6252,8 @@ fctx_decreference(fetchctx_t *fctx) { * This fctx is already shutdown; we were just * waiting for the last reference to go away. */ - bucket_empty = fctx_destroy(fctx); + bucket_empty = fctx_unlink(fctx); + fctx_destroy(fctx); } else { /* * Initiate shutdown. @@ -6287,12 +6308,9 @@ resume_dslookup(isc_task_t *task, isc_event_t *event) { fctx->ns_ttl = fctx->nameservers.ttl; fctx->ns_ttl_ok = ISC_TRUE; log_ns_ttl(fctx, "resume_dslookup"); - dns_name_free(&fctx->domain, - fctx->res->buckets[bucketnum].mctx); + dns_name_free(&fctx->domain, fctx->mctx); dns_name_init(&fctx->domain, NULL); - result = dns_name_dup(&fctx->nsname, - fctx->res->buckets[bucketnum].mctx, - &fctx->domain); + result = dns_name_dup(&fctx->nsname, fctx->mctx, &fctx->domain); if (result != ISC_R_SUCCESS) { fctx_done(fctx, DNS_R_SERVFAIL, __LINE__); goto cleanup; @@ -7210,12 +7228,9 @@ resquery_response(isc_task_t *task, isc_event_t *event) { fctx_done(fctx, DNS_R_SERVFAIL, __LINE__); return; } - dns_name_free(&fctx->domain, - fctx->res->buckets[fctx->bucketnum].mctx); + dns_name_free(&fctx->domain, fctx->mctx); dns_name_init(&fctx->domain, NULL); - result = dns_name_dup(fname, - fctx->res->buckets[fctx->bucketnum].mctx, - &fctx->domain); + result = dns_name_dup(fname, fctx->mctx, &fctx->domain); if (result != ISC_R_SUCCESS) { fctx_done(fctx, DNS_R_SERVFAIL, __LINE__); return; @@ -7955,6 +7970,7 @@ dns_resolver_createfetch2(dns_resolver_t *res, dns_name_t *name, unsigned int count = 0; unsigned int spillat; unsigned int spillatmin; + isc_boolean_t destroy = ISC_FALSE; UNUSED(forwarders); @@ -8052,16 +8068,20 @@ dns_resolver_createfetch2(dns_resolver_t *res, dns_name_t *name, isc_task_send(res->buckets[bucketnum].task, &event); } else { /* - * We don't care about the result of fctx_destroy() + * We don't care about the result of fctx_unlink() * since we know we're not exiting. */ - (void)fctx_destroy(fctx); + (void)fctx_unlink(fctx); + destroy = ISC_TRUE; } } unlock: UNLOCK(&res->buckets[bucketnum].lock); + if (destroy) + fctx_destroy(fctx); + if (result == ISC_R_SUCCESS) { FTRACE("created"); *fetchp = fetch; |