diff --git a/lib/dns/catz.c b/lib/dns/catz.c index 39c1b55c80..ef1beb7b39 100644 --- a/lib/dns/catz.c +++ b/lib/dns/catz.c @@ -69,6 +69,7 @@ struct dns_catz_entry { */ struct dns_catz_zone { unsigned int magic; + isc_loop_t *loop; dns_name_t name; dns_catz_zones_t *catzs; dns_rdata_t soa; @@ -101,6 +102,8 @@ struct dns_catz_zone { static void dns__catz_timer_start(dns_catz_zone_t *catz); +static void +dns__catz_timer_stop(void *arg); static isc_result_t catz_process_zones_entry(dns_catz_zone_t *catz, dns_rdataset_t *value, @@ -126,6 +129,7 @@ struct dns_catz_zones { dns_catz_zonemodmethods_t *zmm; isc_loopmgr_t *loopmgr; dns_view_t *view; + atomic_bool shuttingdown; }; void @@ -820,11 +824,26 @@ dns__catz_timer_start(dns_catz_zone_t *catz) { isc_interval_set(&interval, 0, 0); } - isc_timer_create(isc_loop_current(catz->catzs->loopmgr), - dns_catz_update_action, catz, &catz->updatetimer); + catz->loop = isc_loop_current(catz->catzs->loopmgr); + + isc_timer_create(catz->loop, dns_catz_update_action, catz, + &catz->updatetimer); isc_timer_start(catz->updatetimer, isc_timertype_once, &interval); } +static void +dns__catz_timer_stop(void *arg) { + dns_catz_zone_t *catz = arg; + REQUIRE(DNS_CATZ_ZONE_VALID(catz)); + + isc_timer_stop(catz->updatetimer); + isc_timer_destroy(&catz->updatetimer); + catz->loop = NULL; + + dns_catz_unref_catzs(catz->catzs); + dns_catz_detach_catz(&catz); +} + isc_result_t dns_catz_add_zone(dns_catz_zones_t *catzs, const dns_name_t *name, dns_catz_zone_t **catzp) { @@ -888,6 +907,20 @@ dns_catz_get_zone(dns_catz_zones_t *catzs, const dns_name_t *name) { return (found); } +static void +dns__catz_shutdown(dns_catz_zone_t *catz) { + /* lock must be locked */ + if (catz->updatetimer != NULL) { + /* Don't wait for timer to trigger for shutdown */ + INSIST(catz->loop != NULL); + + dns_catz_ref_catzs(catz->catzs); + isc_async_run(catz->loop, dns__catz_timer_stop, catz); + } else { + dns_catz_detach_catz(&catz); + } +} + static void dns__catz_zone_destroy(dns_catz_zone_t *catz) { isc_mem_t *mctx = catz->catzs->mctx; @@ -959,27 +992,44 @@ dns__catz_zone_destroy(dns_catz_zone_t *catz) { static void dns__catz_zones_destroy(dns_catz_zones_t *catzs) { + REQUIRE(atomic_load(&catzs->shuttingdown)); + REQUIRE(catzs->zones == NULL); + + catzs->magic = 0; + isc_mutex_destroy(&catzs->lock); + isc_refcount_destroy(&catzs->references); + + isc_mem_putanddetach(&catzs->mctx, catzs, sizeof(*catzs)); +} + +void +dns_catz_shutdown_catzs(dns_catz_zones_t *catzs) { + REQUIRE(DNS_CATZ_ZONES_VALID(catzs)); + + if (!atomic_compare_exchange_strong(&catzs->shuttingdown, + &(bool){ false }, true)) + { + return; + } + + LOCK(&catzs->lock); if (catzs->zones != NULL) { isc_ht_iter_t *iter = NULL; isc_result_t result; isc_ht_iter_create(catzs->zones, &iter); for (result = isc_ht_iter_first(iter); result == ISC_R_SUCCESS;) { - dns_catz_zone_t *zone = NULL; - isc_ht_iter_current(iter, (void **)&zone); + dns_catz_zone_t *catz = NULL; + isc_ht_iter_current(iter, (void **)&catz); result = isc_ht_iter_delcurrent_next(iter); - dns_catz_detach_catz(&zone); + dns__catz_shutdown(catz); } INSIST(result == ISC_R_NOMORE); isc_ht_iter_destroy(&iter); INSIST(isc_ht_count(catzs->zones) == 0); isc_ht_destroy(&catzs->zones); } - catzs->magic = 0; - isc_mutex_destroy(&catzs->lock); - isc_refcount_destroy(&catzs->references); - - isc_mem_putanddetach(&catzs->mctx, catzs, sizeof(*catzs)); + UNLOCK(&catzs->lock); } #ifdef DNS_CATZ_TRACE @@ -1991,6 +2041,7 @@ dns_catz_update_action(void *arg) { dns_catz_update_from_db(catz->db, catz->catzs); isc_timer_stop(catz->updatetimer); isc_timer_destroy(&catz->updatetimer); + catz->loop = NULL; result = isc_time_now(&catz->lastupdated); RUNTIME_CHECK(result == ISC_R_SUCCESS); UNLOCK(&catz->catzs->lock); @@ -2083,6 +2134,10 @@ dns_catz_update_from_db(dns_db_t *db, dns_catz_zones_t *catzs) { REQUIRE(DNS_DB_VALID(db)); REQUIRE(DNS_CATZ_ZONES_VALID(catzs)); + if (atomic_load(&catzs->shuttingdown)) { + return; + } + dns_name_format(&db->origin, bname, DNS_NAME_FORMATSIZE); /* diff --git a/lib/dns/include/dns/catz.h b/lib/dns/include/dns/catz.h index 97ee94d56f..67f96e2d21 100644 --- a/lib/dns/include/dns/catz.h +++ b/lib/dns/include/dns/catz.h @@ -438,6 +438,16 @@ dns_catz_get_iterator(dns_catz_zone_t *catz, isc_ht_iter_t **itp); * */ +void +dns_catz_shutdown_catzs(dns_catz_zones_t *catzs); +/*%< + * Shut down the catalog zones. + * + * Requires: + * \li 'catzs' is a valid dns_catz_zones_t. + * + */ + #ifdef DNS_CATZ_TRACE /* Compatibility macros */ #define dns_catz_attach_catz(catz, catzp) \ diff --git a/lib/dns/view.c b/lib/dns/view.c index 0d3580adc6..0cf2a4802e 100644 --- a/lib/dns/view.c +++ b/lib/dns/view.c @@ -300,6 +300,7 @@ destroy(dns_view_t *view) { dns_rpz_detach_rpzs(&view->rpzs); } if (view->catzs != NULL) { + dns_catz_shutdown_catzs(view->catzs); dns_catz_detach_catzs(&view->catzs); } for (dlzdb = ISC_LIST_HEAD(view->dlz_searched); dlzdb != NULL; @@ -548,6 +549,7 @@ dns_view_detach(dns_view_t **viewp) { } } if (view->catzs != NULL) { + dns_catz_shutdown_catzs(view->catzs); dns_catz_detach_catzs(&view->catzs); } if (view->ntatable_priv != NULL) {