summaryrefslogtreecommitdiff
path: root/lib/dns/zone.c
diff options
context:
space:
mode:
Diffstat (limited to 'lib/dns/zone.c')
-rw-r--r--lib/dns/zone.c73
1 files changed, 51 insertions, 22 deletions
diff --git a/lib/dns/zone.c b/lib/dns/zone.c
index d334bebc436cd..490248a689101 100644
--- a/lib/dns/zone.c
+++ b/lib/dns/zone.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2004-2015 Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (C) 2004-2016 Internet Systems Consortium, Inc. ("ISC")
* Copyright (C) 1999-2003 Internet Software Consortium.
*
* Permission to use, copy, modify, and/or distribute this software for any
@@ -1052,6 +1052,8 @@ zone_free(dns_zone_t *zone) {
isc_task_detach(&zone->task);
if (zone->loadtask != NULL)
isc_task_detach(&zone->loadtask);
+ if (zone->view != NULL)
+ dns_view_weakdetach(&zone->view);
/* Unmanaged objects */
for (signing = ISC_LIST_HEAD(zone->signing);
@@ -3408,7 +3410,8 @@ compute_tag(dns_name_t *name, dns_rdata_dnskey_t *dnskey, isc_mem_t *mctx,
*/
static void
trust_key(dns_zone_t *zone, dns_name_t *keyname,
- dns_rdata_dnskey_t *dnskey, isc_mem_t *mctx) {
+ dns_rdata_dnskey_t *dnskey, isc_mem_t *mctx)
+{
isc_result_t result;
dns_rdata_t rdata = DNS_RDATA_INIT;
unsigned char data[4096];
@@ -8540,13 +8543,12 @@ keyfetch_done(isc_task_t *task, isc_event_t *event) {
*/
deletekey = ISC_TRUE;
} else if (keydata.removehd == 0) {
- /* Remove from secroots */
+ /*
+ * Remove key from secroots.
+ */
dns_view_untrust(zone->view, keyname,
&dnskey, mctx);
- /* But ensure there's a null key */
- fail_secure(zone, keyname);
-
/* If initializing, delete now */
if (keydata.addhd == 0)
deletekey = ISC_TRUE;
@@ -8855,7 +8857,8 @@ zone_refreshkeys(dns_zone_t *zone) {
result = dns_resolver_createfetch(zone->view->resolver,
kname, dns_rdatatype_dnskey,
NULL, NULL, NULL,
- DNS_FETCHOPT_NOVALIDATE,
+ DNS_FETCHOPT_NOVALIDATE|
+ DNS_FETCHOPT_UNSHARED,
zone->task,
keyfetch_done, kfetch,
&kfetch->dnskeyset,
@@ -9303,6 +9306,7 @@ static void
dump_done(void *arg, isc_result_t result) {
const char me[] = "dump_done";
dns_zone_t *zone = arg;
+ dns_zone_t *secure = NULL;
dns_db_t *db;
dns_dbversion_t *version;
isc_boolean_t again = ISC_FALSE;
@@ -9316,30 +9320,54 @@ dump_done(void *arg, isc_result_t result) {
if (result == ISC_R_SUCCESS && zone->journal != NULL &&
zone->journalsize != -1) {
-
/*
* We don't own these, zone->dctx must stay valid.
*/
db = dns_dumpctx_db(zone->dctx);
version = dns_dumpctx_version(zone->dctx);
-
tresult = dns_db_getsoaserial(db, version, &serial);
+
+ /*
+ * Handle lock order inversion.
+ */
+ again:
+ LOCK_ZONE(zone);
+ if (inline_raw(zone)) {
+ secure = zone->secure;
+ INSIST(secure != zone);
+ TRYLOCK_ZONE(result, secure);
+ if (result != ISC_R_SUCCESS) {
+ UNLOCK_ZONE(zone);
+ secure = NULL;
+#if ISC_PLATFORM_USETHREADS
+ isc_thread_yield();
+#endif
+ goto again;
+ }
+ }
+
/*
* If there is a secure version of this zone
* use its serial if it is less than ours.
*/
- if (tresult == ISC_R_SUCCESS && inline_raw(zone) &&
- zone->secure->db != NULL)
- {
+ if (tresult == ISC_R_SUCCESS && secure != NULL) {
isc_uint32_t sserial;
isc_result_t mresult;
- mresult = dns_db_getsoaserial(zone->secure->db,
- NULL, &sserial);
- if (mresult == ISC_R_SUCCESS &&
- isc_serial_lt(sserial, serial))
- serial = sserial;
+ ZONEDB_LOCK(&secure->dblock, isc_rwlocktype_read);
+ if (secure->db != NULL) {
+ mresult = dns_db_getsoaserial(zone->secure->db,
+ NULL, &sserial);
+ if (mresult == ISC_R_SUCCESS &&
+ isc_serial_lt(sserial, serial))
+ serial = sserial;
+ }
+ ZONEDB_UNLOCK(&secure->dblock, isc_rwlocktype_read);
}
+ if (secure != NULL)
+ UNLOCK_ZONE(secure);
+ UNLOCK_ZONE(zone);
+
/*
* Note: we are task locked here so we can test
* zone->xfr safely.
@@ -10041,6 +10069,9 @@ notify_send(dns_notify_t *notify) {
REQUIRE(DNS_NOTIFY_VALID(notify));
REQUIRE(LOCKED_ZONE(notify->zone));
+ if (DNS_ZONE_FLAG(notify->zone, DNS_ZONEFLG_EXITING))
+ return;
+
for (ai = ISC_LIST_HEAD(notify->find->list);
ai != NULL;
ai = ISC_LIST_NEXT(ai, publink)) {
@@ -10116,7 +10147,8 @@ zone_notify(dns_zone_t *zone, isc_time_t *now) {
DNS_ZONE_TIME_ADD(now, zone->notifydelay, &zone->notifytime);
UNLOCK_ZONE(zone);
- if (! DNS_ZONE_FLAG(zone, DNS_ZONEFLG_LOADED))
+ if (DNS_ZONE_FLAG(zone, DNS_ZONEFLG_EXITING) ||
+ ! DNS_ZONE_FLAG(zone, DNS_ZONEFLG_LOADED))
return;
if (notifytype == dns_notifytype_no)
@@ -11644,9 +11676,6 @@ zone_shutdown(isc_task_t *task, isc_event_t *event) {
zone->irefs--;
}
- if (zone->view != NULL)
- dns_view_weakdetach(&zone->view);
-
/*
* We have now canceled everything set the flag to allow exit_check()
* to succeed. We must not unlock between setting this flag and
@@ -17428,7 +17457,7 @@ dns_zone_keydone(dns_zone_t *zone, const char *keystr) {
kd->all = ISC_TRUE;
else {
isc_textregion_t r;
- char *algstr;
+ const char *algstr;
dns_keytag_t keyid;
dns_secalg_t alg;
size_t n;