From: Ondřej Surý Date: Wed, 5 Oct 2022 09:21:28 +0000 (+0200) Subject: Refactor dns_rpz unit to use single reference counting X-Git-Tag: v9.19.8~35^2 X-Git-Url: http://git.ipfire.org/gitweb/?a=commitdiff_plain;h=77659e739274a62573a00d029a273db6f55f7125;p=thirdparty%2Fbind9.git Refactor dns_rpz unit to use single reference counting The dns_rpz_zones structure was using .refs and .irefs for strong and weak reference counting. Rewrite the unit to use just a single reference counting + shutdown sequence (dns_rpz_destroy_rpzs) that must be called by the creator of the dns_rpz_zones_t object. Remove the reference counting from the dns_rpz_zone structure as it is not needed because the zone objects are fully embedded into the dns_rpz_zones structure and dns_rpz_zones_t object must never be destroyed before all dns_rpz_zone_t objects. The dns_rps_zones_t reference counting uses the new ISC_REFCOUNT_TRACE capability - enable by defining DNS_RPZ_TRACE in the dns/rpz.h header. Additionally, add magic numbers to the dns_rpz_zone and dns_rpz_zones structures. --- diff --git a/bin/named/server.c b/bin/named/server.c index 3b3a4b316d2..8d341e0b0e1 100644 --- a/bin/named/server.c +++ b/bin/named/server.c @@ -2523,9 +2523,8 @@ configure_rpz(dns_view_t *view, dns_view_t *pview, const cfg_obj_t **maps, } #endif /* ifndef USE_DNSRPS */ - result = dns_rpz_new_zones(&view->rpzs, rps_cstr, rps_cstr_size, - view->mctx, named_g_loopmgr, - named_g_taskmgr); + result = dns_rpz_new_zones(view->mctx, named_g_loopmgr, rps_cstr, + rps_cstr_size, &view->rpzs); if (result != ISC_R_SUCCESS) { return (result); } @@ -2661,6 +2660,7 @@ configure_rpz(dns_view_t *view, dns_view_t *pview, const cfg_obj_t **maps, } if (*old_rpz_okp) { + dns_rpz_shutdown_rpzs(view->rpzs); dns_rpz_detach_rpzs(&view->rpzs); dns_rpz_attach_rpzs(pview->rpzs, &view->rpzs); } else if (old != NULL && pview != NULL) { diff --git a/lib/dns/include/dns/rpz.h b/lib/dns/include/dns/rpz.h index 47d395430e2..6ccb0242efd 100644 --- a/lib/dns/include/dns/rpz.h +++ b/lib/dns/include/dns/rpz.h @@ -13,6 +13,11 @@ #pragma once +/* + * Define this for reference count tracing in the unit + */ +#undef DNS_RPZ_TRACE + #include #include @@ -130,7 +135,9 @@ typedef struct dns_rpz_zone dns_rpz_zone_t; typedef struct dns_rpz_zones dns_rpz_zones_t; struct dns_rpz_zone { - isc_refcount_t refs; + unsigned int magic; + isc_loop_t *loop; + dns_rpz_num_t num; /* ordinal in list of policy zones */ dns_name_t origin; /* Policy zone name */ dns_name_t client_ip; /* DNS_RPZ_CLIENT_IP_ZONE.origin. */ @@ -210,6 +217,11 @@ struct dns_rpz_popt { * Response policy zones known to a view. */ struct dns_rpz_zones { + unsigned int magic; + isc_refcount_t references; + isc_mem_t *mctx; + isc_loopmgr_t *loopmgr; + dns_rpz_popt_t p; dns_rpz_zone_t *zones[DNS_RPZ_MAX_ZONES]; dns_rpz_triggers_t triggers[DNS_RPZ_MAX_ZONES]; @@ -247,11 +259,6 @@ struct dns_rpz_zones { */ dns_rpz_triggers_t total_triggers; - isc_mem_t *mctx; - isc_loopmgr_t *loopmgr; - isc_taskmgr_t *taskmgr; - isc_refcount_t refs; - isc_refcount_t irefs; /* * One lock for short term read-only search that guarantees the * consistency of the pointers. @@ -261,6 +268,8 @@ struct dns_rpz_zones { isc_rwlock_t search_lock; isc_mutex_t maint_lock; + bool shuttingdown; + dns_rpz_cidr_node_t *cidr; dns_rbt_t *rbt; @@ -387,9 +396,8 @@ dns_rpz_decode_cname(dns_rpz_zone_t *rpz, dns_rdataset_t *rdataset, dns_name_t *selfname); isc_result_t -dns_rpz_new_zones(dns_rpz_zones_t **rpzsp, char *rps_cstr, size_t rps_cstr_size, - isc_mem_t *mctx, isc_loopmgr_t *loopmgr, - isc_taskmgr_t *taskmgr); +dns_rpz_new_zones(isc_mem_t *mctx, isc_loopmgr_t *loopmgr, char *rps_cstr, + size_t rps_cstr_size, dns_rpz_zones_t **rpzsp); isc_result_t dns_rpz_new_zone(dns_rpz_zones_t *rpzs, dns_rpz_zone_t **rpzp); @@ -398,10 +406,32 @@ isc_result_t dns_rpz_dbupdate_callback(dns_db_t *db, void *fn_arg); void -dns_rpz_attach_rpzs(dns_rpz_zones_t *source, dns_rpz_zones_t **target); - -void -dns_rpz_detach_rpzs(dns_rpz_zones_t **rpzsp); +dns_rpz_zones_shutdown(dns_rpz_zones_t *rpzs); + +#ifdef DNS_RPZ_TRACE +/* Compatibility macros */ +#define dns_rpz_detach_rpzs(rpzsp) \ + dns_rpz_zones__detach(rpzsp, __func__, __FILE__, __LINE__) +#define dns_rpz_attach_rpzs(rpzs, rpzsp) \ + dns_rpz_zones__attach(rpzs, rpzsp, __func__, __FILE__, __LINE__) +#define dns_rpz_ref_rpzs(ptr) \ + dns_rpz_zones__ref(ptr, __func__, __FILE__, __LINE__) +#define dns_rpz_unref_rpzs(ptr) \ + dns_rpz_zones__unref(ptr, __func__, __FILE__, __LINE__) +#define dns_rpz_shutdown_rpzs(rpzs) \ + dns_rpz_zones_shutdown(rpzs, __func__, __FILE__, __LINE__) + +ISC_REFCOUNT_TRACE_DECL(dns_rpz_zones); +#else +/* Compatibility macros */ +#define dns_rpz_detach_rpzs(rpzsp) dns_rpz_zones_detach(rpzsp) +#define dns_rpz_attach_rpzs(rpzs, rpzsp) dns_rpz_zones_attach(rpzs, rpzsp) +#define dns_rpz_shutdown_rpzs(rpzsp) dns_rpz_zones_shutdown(rpzsp) +#define dns_rpz_ref_rpzs(ptr) dns_rpz_zones_ref(ptr) +#define dns_rpz_unref_rpzs(ptr) dns_rpz_zones_unref(ptr) + +ISC_REFCOUNT_DECL(dns_rpz_zones); +#endif dns_rpz_num_t dns_rpz_find_ip(dns_rpz_zones_t *rpzs, dns_rpz_type_t rpz_type, diff --git a/lib/dns/rpz.c b/lib/dns/rpz.c index f575c8cc742..3815a59de8e 100644 --- a/lib/dns/rpz.c +++ b/lib/dns/rpz.c @@ -21,6 +21,7 @@ #include #include #include +#include #include #include #include @@ -46,6 +47,12 @@ #include #include +#define DNS_RPZ_ZONE_MAGIC ISC_MAGIC('r', 'p', 'z', ' ') +#define DNS_RPZ_ZONES_MAGIC ISC_MAGIC('r', 'p', 'z', 's') + +#define DNS_RPZ_ZONE_VALID(rpz) ISC_MAGIC_VALID(rpz, DNS_RPZ_ZONE_MAGIC) +#define DNS_RPZ_ZONES_VALID(rpzs) ISC_MAGIC_VALID(rpzs, DNS_RPZ_ZONES_MAGIC) + /* * Parallel radix trees for databases of response policy IP addresses * @@ -92,13 +99,12 @@ #define DNS_RPZ_HTSIZE_MAX 24 #define DNS_RPZ_HTSIZE_DIV 3 +static isc_result_t +dns__rpz_shuttingdown(dns_rpz_zones_t *rpzs); static void -update_from_db(dns_rpz_zone_t *rpz); - -static void -dns_rpz_update_taskaction(void *); +dns__rpz_timer_cb(void *); static void -dns_rpz_timer_start(dns_rpz_zone_t *rpz); +dns__rpz_timer_start(dns_rpz_zone_t *rpz); /* * Use a private definition of IPv6 addresses because s6_addr32 is not @@ -173,24 +179,11 @@ struct dns_rpz_nm_data { dns_rpz_nm_zbits_t wild; }; -static isc_result_t -rpz_shuttingdown(dns_rpz_zone_t *rpz); - static isc_result_t rpz_add(dns_rpz_zone_t *rpz, const dns_name_t *src_name); static void rpz_del(dns_rpz_zone_t *rpz, const dns_name_t *src_name); -static void -rpz_attach(dns_rpz_zone_t *rpz, dns_rpz_zone_t **rpzp); -static void -rpz_detach(dns_rpz_zone_t **rpzp); - -static void -rpz_attach_rpzs(dns_rpz_zones_t *rpzs, dns_rpz_zones_t **rpzsp); -static void -rpz_detach_rpzs(dns_rpz_zones_t **rpzsp); - const char * dns_rpz_type2str(dns_rpz_type_t type) { switch (type) { @@ -1473,9 +1466,8 @@ rpz_node_deleter(void *nm_data, void *mctx) { * Get ready for a new set of policy zones for a view. */ isc_result_t -dns_rpz_new_zones(dns_rpz_zones_t **rpzsp, char *rps_cstr, size_t rps_cstr_size, - isc_mem_t *mctx, isc_loopmgr_t *loopmgr, - isc_taskmgr_t *taskmgr) { +dns_rpz_new_zones(isc_mem_t *mctx, isc_loopmgr_t *loopmgr, char *rps_cstr, + size_t rps_cstr_size, dns_rpz_zones_t **rpzsp) { dns_rpz_zones_t *rpzs = NULL; isc_result_t result = ISC_R_SUCCESS; @@ -1486,13 +1478,12 @@ dns_rpz_new_zones(dns_rpz_zones_t **rpzsp, char *rps_cstr, size_t rps_cstr_size, .rps_cstr = rps_cstr, .rps_cstr_size = rps_cstr_size, .loopmgr = loopmgr, - .taskmgr = taskmgr, + .magic = DNS_RPZ_ZONES_MAGIC, }; isc_rwlock_init(&rpzs->search_lock, 0, 0); isc_mutex_init(&rpzs->maint_lock); - isc_refcount_init(&rpzs->refs, 1); - isc_refcount_init(&rpzs->irefs, 1); + isc_refcount_init(&rpzs->references, 1); #ifdef USE_DNSRPS if (rps_cstr != NULL) { @@ -1519,10 +1510,8 @@ dns_rpz_new_zones(dns_rpz_zones_t **rpzsp, char *rps_cstr, size_t rps_cstr_size, return (ISC_R_SUCCESS); cleanup_rbt: - isc_refcount_decrementz(&rpzs->irefs); - isc_refcount_destroy(&rpzs->irefs); - isc_refcount_decrementz(&rpzs->refs); - isc_refcount_destroy(&rpzs->refs); + isc_refcount_decrementz(&rpzs->references); + isc_refcount_destroy(&rpzs->references); isc_mutex_destroy(&rpzs->maint_lock); isc_rwlock_destroy(&rpzs->search_lock); isc_mem_put(mctx, rpzs, sizeof(*rpzs)); @@ -1532,21 +1521,28 @@ cleanup_rbt: isc_result_t dns_rpz_new_zone(dns_rpz_zones_t *rpzs, dns_rpz_zone_t **rpzp) { + isc_result_t result; dns_rpz_zone_t *rpz = NULL; + REQUIRE(DNS_RPZ_ZONES_VALID(rpzs)); REQUIRE(rpzp != NULL && *rpzp == NULL); - REQUIRE(rpzs != NULL); + if (rpzs->p.num_zones >= DNS_RPZ_MAX_ZONES) { return (ISC_R_NOSPACE); } + result = dns__rpz_shuttingdown(rpzs); + if (result != ISC_R_SUCCESS) { + return (result); + } + rpz = isc_mem_get(rpzs->mctx, sizeof(*rpz)); *rpz = (dns_rpz_zone_t){ .addsoa = true, + .magic = DNS_RPZ_ZONE_MAGIC, + .rpzs = rpzs, }; - isc_refcount_init(&rpz->refs, 1); - /* * This will never be used, but costs us nothing and * simplifies update_from_db(). @@ -1566,8 +1562,6 @@ dns_rpz_new_zone(dns_rpz_zones_t *rpzs, dns_rpz_zone_t **rpzp) { isc_time_settoepoch(&rpz->lastupdated); - rpz_attach_rpzs(rpzs, &rpz->rpzs); - rpz->num = rpzs->p.num_zones++; rpzs->zones[rpz->num] = rpz; @@ -1582,10 +1576,15 @@ dns_rpz_dbupdate_callback(dns_db_t *db, void *fn_arg) { isc_result_t result = ISC_R_SUCCESS; REQUIRE(DNS_DB_VALID(db)); - REQUIRE(rpz != NULL); + REQUIRE(DNS_RPZ_ZONE_VALID(rpz)); LOCK(&rpz->rpzs->maint_lock); + if (rpz->rpzs->shuttingdown) { + result = ISC_R_SHUTTINGDOWN; + goto unlock; + } + /* New zone came as AXFR */ if (rpz->db != NULL && rpz->db != db) { /* We need to clean up the old DB */ @@ -1606,7 +1605,7 @@ dns_rpz_dbupdate_callback(dns_db_t *db, void *fn_arg) { rpz->updatepending = true; dns_db_currentversion(rpz->db, &rpz->dbversion); - dns_rpz_timer_start(rpz); + dns__rpz_timer_start(rpz); } else { char dname[DNS_NAME_FORMATSIZE]; rpz->updatepending = true; @@ -1621,17 +1620,21 @@ dns_rpz_dbupdate_callback(dns_db_t *db, void *fn_arg) { } dns_db_currentversion(rpz->db, &rpz->dbversion); } + +unlock: UNLOCK(&rpz->rpzs->maint_lock); return (result); } static void -dns_rpz_timer_start(dns_rpz_zone_t *rpz) { +dns__rpz_timer_start(dns_rpz_zone_t *rpz) { uint64_t tdiff; isc_interval_t interval; isc_time_t now; + REQUIRE(DNS_RPZ_ZONE_VALID(rpz)); + isc_time_now(&now); tdiff = isc_time_microdiff(&now, &rpz->lastupdated) / 1000000; if (tdiff < rpz->min_update_interval) { @@ -1650,28 +1653,22 @@ dns_rpz_timer_start(dns_rpz_zone_t *rpz) { isc_interval_set(&interval, 0, 0); } - isc_timer_create(isc_loop_current(rpz->rpzs->loopmgr), - dns_rpz_update_taskaction, rpz, &rpz->updatetimer); + rpz->loop = isc_loop_current(rpz->rpzs->loopmgr); + + isc_timer_create(rpz->loop, dns__rpz_timer_cb, rpz, &rpz->updatetimer); isc_timer_start(rpz->updatetimer, isc_timertype_once, &interval); } static void -dns_rpz_update_taskaction(void *arg) { - isc_result_t result; - dns_rpz_zone_t *rpz = (dns_rpz_zone_t *)arg; - - LOCK(&rpz->rpzs->maint_lock); - rpz->updatepending = false; - rpz->updaterunning = true; - rpz->updateresult = ISC_R_UNSET; - - update_from_db(rpz); +dns__rpz_timer_stop(void *arg) { + dns_rpz_zone_t *rpz = arg; + REQUIRE(DNS_RPZ_ZONE_VALID(rpz)); isc_timer_stop(rpz->updatetimer); isc_timer_destroy(&rpz->updatetimer); - result = isc_time_now(&rpz->lastupdated); - RUNTIME_CHECK(result == ISC_R_SUCCESS); - UNLOCK(&rpz->rpzs->maint_lock); + rpz->loop = NULL; + + dns_rpz_unref_rpzs(rpz->rpzs); } static void @@ -1679,19 +1676,18 @@ update_rpz_done_cb(void *data) { dns_rpz_zone_t *rpz = (dns_rpz_zone_t *)data; char dname[DNS_NAME_FORMATSIZE]; + REQUIRE(DNS_RPZ_ZONE_VALID(rpz)); + LOCK(&rpz->rpzs->maint_lock); rpz->updaterunning = false; dns_name_format(&rpz->origin, dname, DNS_NAME_FORMATSIZE); - /* If there's no update pending, finish. */ - if (!rpz->updatepending) { - goto done; + if (rpz->updatepending && !rpz->rpzs->shuttingdown) { + /* Restart the timer */ + dns__rpz_timer_start(rpz); } - dns_rpz_timer_start(rpz); - -done: dns_db_closeversion(rpz->updb, &rpz->updbversion, false); dns_db_detach(&rpz->updb); @@ -1701,7 +1697,7 @@ done: ISC_LOG_INFO, "rpz: %s: reload done: %s", dname, isc_result_totext(rpz->updateresult)); - rpz_detach(&rpz); + dns_rpz_unref_rpzs(rpz->rpzs); } static isc_result_t @@ -1739,7 +1735,7 @@ update_nodes(dns_rpz_zone_t *rpz, isc_ht_t *newnodes) { dns_rdatasetiter_t *rdsiter = NULL; dns_dbnode_t *node = NULL; - result = rpz_shuttingdown(rpz); + result = dns__rpz_shuttingdown(rpz->rpzs); if (result != ISC_R_SUCCESS) { dns_db_detachnode(rpz->updb, &node); goto cleanup; @@ -1866,7 +1862,7 @@ cleanup_nodes(dns_rpz_zone_t *rpz) { unsigned char *key = NULL; size_t keysize; - result = rpz_shuttingdown(rpz); + result = dns__rpz_shuttingdown(rpz->rpzs); if (result != ISC_R_SUCCESS) { break; } @@ -1891,13 +1887,12 @@ cleanup_nodes(dns_rpz_zone_t *rpz) { } static isc_result_t -rpz_shuttingdown(dns_rpz_zone_t *rpz) { +dns__rpz_shuttingdown(dns_rpz_zones_t *rpzs) { bool shuttingdown = false; - LOCK(&rpz->rpzs->maint_lock); - /* Check that we aren't shutting down. */ - shuttingdown = (rpz->rpzs->zones[rpz->num] == NULL); - UNLOCK(&rpz->rpzs->maint_lock); + LOCK(&rpzs->maint_lock); + shuttingdown = rpzs->shuttingdown; + UNLOCK(&rpzs->maint_lock); if (shuttingdown) { return (ISC_R_SHUTTINGDOWN); @@ -1914,7 +1909,7 @@ update_rpz_cb(void *data) { REQUIRE(rpz->nodes != NULL); - result = rpz_shuttingdown(rpz); + result = dns__rpz_shuttingdown(rpz->rpzs); if (result != ISC_R_SUCCESS) { goto cleanup; } @@ -1941,17 +1936,30 @@ cleanup: } static void -update_from_db(dns_rpz_zone_t *rpz) { +dns__rpz_timer_cb(void *arg) { char domain[DNS_NAME_FORMATSIZE]; - dns_rpz_zone_t *rpz_zone = NULL; + isc_result_t result; + dns_rpz_zone_t *rpz = (dns_rpz_zone_t *)arg; - REQUIRE(rpz != NULL); + REQUIRE(DNS_RPZ_ZONE_VALID(rpz)); REQUIRE(DNS_DB_VALID(rpz->db)); REQUIRE(rpz->updb == NULL); REQUIRE(rpz->updbversion == NULL); - rpz_attach(rpz, &rpz_zone); + dns_rpz_ref_rpzs(rpz->rpzs); + + LOCK(&rpz->rpzs->maint_lock); + + if (rpz->rpzs->shuttingdown) { + goto unlock; + } + + rpz->updatepending = false; + rpz->updaterunning = true; + rpz->updateresult = ISC_R_UNSET; + dns_db_attach(rpz->db, &rpz->updb); + INSIST(rpz->dbversion != NULL); rpz->updbversion = rpz->dbversion; rpz->dbversion = NULL; @@ -1959,8 +1967,15 @@ update_from_db(dns_rpz_zone_t *rpz) { isc_log_write(dns_lctx, DNS_LOGCATEGORY_GENERAL, DNS_LOGMODULE_MASTER, ISC_LOG_INFO, "rpz: %s: reload start", domain); - isc_work_enqueue(isc_loop_current(rpz->rpzs->loopmgr), update_rpz_cb, - update_rpz_done_cb, rpz_zone); + isc_work_enqueue(rpz->loop, update_rpz_cb, update_rpz_done_cb, rpz); + + isc_timer_destroy(&rpz->updatetimer); + rpz->loop = NULL; + + result = isc_time_now(&rpz->lastupdated); + RUNTIME_CHECK(result == ISC_R_SUCCESS); +unlock: + UNLOCK(&rpz->rpzs->maint_lock); } /* @@ -1997,20 +2012,27 @@ cidr_free(dns_rpz_zones_t *rpzs) { } static void -rpz_attach(dns_rpz_zone_t *rpz, dns_rpz_zone_t **rpzp) { - REQUIRE(rpz != NULL); - REQUIRE(rpzp != NULL && *rpzp == NULL); +dns__rpz_shutdown(dns_rpz_zone_t *rpz) { + /* maint_lock must be locked */ + if (rpz->updatetimer != NULL) { + /* Don't wait for timer to trigger for shutdown */ + INSIST(rpz->loop != NULL); - isc_refcount_increment(&rpz->refs); - *rpzp = rpz; + dns_rpz_ref_rpzs(rpz->rpzs); + isc_async_run(rpz->loop, dns__rpz_timer_stop, rpz); + } } static void -rpz_destroy(dns_rpz_zone_t *rpz) { - dns_rpz_zones_t *rpzs = rpz->rpzs; - rpz->rpzs = NULL; +dns_rpz_zone_destroy(dns_rpz_zone_t **rpzp) { + dns_rpz_zone_t *rpz = NULL; + dns_rpz_zones_t *rpzs; + + rpz = *rpzp; + *rpzp = NULL; - isc_refcount_destroy(&rpz->refs); + rpzs = rpz->rpzs; + rpz->rpzs = NULL; if (dns_name_dynamic(&rpz->origin)) { dns_name_free(&rpz->origin, rpzs->mctx); @@ -2047,84 +2069,28 @@ rpz_destroy(dns_rpz_zone_t *rpz) { dns_rpz_dbupdate_callback, rpz); dns_db_detach(&rpz->db); } - INSIST(!rpz->updaterunning); - if (rpz->updatetimer != NULL) { - isc_timer_async_destroy(&rpz->updatetimer); - } - isc_ht_destroy(&rpz->nodes); isc_mem_put(rpzs->mctx, rpz, sizeof(*rpz)); - rpz_detach_rpzs(&rpzs); } -/* - * Discard a response policy zone blob - * before discarding the overall rpz structure. - */ static void -rpz_detach(dns_rpz_zone_t **rpzp) { - dns_rpz_zone_t *rpz = NULL; - - REQUIRE(rpzp != NULL && *rpzp != NULL); - - rpz = *rpzp; - *rpzp = NULL; - - if (isc_refcount_decrement(&rpz->refs) == 1) { - rpz_destroy(rpz); - } -} +dns__rpz_zones_destroy(dns_rpz_zones_t *rpzs) { + REQUIRE(rpzs->shuttingdown); -void -dns_rpz_attach_rpzs(dns_rpz_zones_t *rpzs, dns_rpz_zones_t **rpzsp) { - REQUIRE(rpzsp != NULL && *rpzsp == NULL); - isc_refcount_increment(&rpzs->refs); - *rpzsp = rpzs; -} - -/* - * Forget a view's policy zones. - */ -void -dns_rpz_detach_rpzs(dns_rpz_zones_t **rpzsp) { - REQUIRE(rpzsp != NULL && *rpzsp != NULL); - dns_rpz_zones_t *rpzs = *rpzsp; - *rpzsp = NULL; + isc_refcount_destroy(&rpzs->references); - if (isc_refcount_decrement(&rpzs->refs) == 1) { - /* - * Forget the last of the view's rpz machinery after - * the last reference. - */ - LOCK(&rpzs->maint_lock); - for (dns_rpz_num_t rpz_num = 0; rpz_num < DNS_RPZ_MAX_ZONES; - ++rpz_num) - { - if (rpzs->zones[rpz_num] != NULL) { - rpz_detach(&rpzs->zones[rpz_num]); - } + for (dns_rpz_num_t rpz_num = 0; rpz_num < DNS_RPZ_MAX_ZONES; ++rpz_num) + { + if (rpzs->zones[rpz_num] == NULL) { + continue; } - UNLOCK(&rpzs->maint_lock); - rpz_detach_rpzs(&rpzs); + dns_rpz_zone_destroy(&rpzs->zones[rpz_num]); } -} - -static void -rpz_attach_rpzs(dns_rpz_zones_t *rpzs, dns_rpz_zones_t **rpzsp) { - REQUIRE(rpzs != NULL); - REQUIRE(rpzsp != NULL && *rpzsp == NULL); - - isc_refcount_increment(&rpzs->irefs); - - *rpzsp = rpzs; -} -static void -rpz_destroy_rpzs(dns_rpz_zones_t *rpzs) { if (rpzs->rps_cstr_size != 0) { #ifdef USE_DNSRPS librpz->client_detach(&rpzs->rps_client); @@ -2138,21 +2104,41 @@ rpz_destroy_rpzs(dns_rpz_zones_t *rpzs) { } isc_mutex_destroy(&rpzs->maint_lock); isc_rwlock_destroy(&rpzs->search_lock); - isc_refcount_destroy(&rpzs->refs); isc_mem_putanddetach(&rpzs->mctx, rpzs, sizeof(*rpzs)); } -static void -rpz_detach_rpzs(dns_rpz_zones_t **rpzsp) { - REQUIRE(rpzsp != NULL && *rpzsp != NULL); - dns_rpz_zones_t *rpzs = *rpzsp; - *rpzsp = NULL; +void +dns_rpz_zones_shutdown(dns_rpz_zones_t *rpzs) { + REQUIRE(DNS_RPZ_ZONES_VALID(rpzs)); + /* + * Forget the last of the view's rpz machinery when shutting down. + */ - if (isc_refcount_decrement(&rpzs->irefs) == 1) { - rpz_destroy_rpzs(rpzs); + LOCK(&rpzs->maint_lock); + if (rpzs->shuttingdown) { + UNLOCK(&rpzs->maint_lock); + return; } + + rpzs->shuttingdown = true; + + for (dns_rpz_num_t rpz_num = 0; rpz_num < DNS_RPZ_MAX_ZONES; ++rpz_num) + { + if (rpzs->zones[rpz_num] == NULL) { + continue; + } + + dns__rpz_shutdown(rpzs->zones[rpz_num]); + } + UNLOCK(&rpzs->maint_lock); } +#ifdef DNS_RPZ_TRACE +ISC_REFCOUNT_TRACE_IMPL(dns_rpz_zones, dns__rpz_zones_destroy); +#else +ISC_REFCOUNT_IMPL(dns_rpz_zones, dns__rpz_zones_destroy); +#endif + /* * Add an IP address to the radix tree or a name to the summary database. */ diff --git a/lib/dns/view.c b/lib/dns/view.c index a4229d9e5f5..89f41f7edc6 100644 --- a/lib/dns/view.c +++ b/lib/dns/view.c @@ -299,6 +299,7 @@ destroy(dns_view_t *view) { } dns_rrl_view_destroy(view); if (view->rpzs != NULL) { + dns_rpz_shutdown_rpzs(view->rpzs); dns_rpz_detach_rpzs(&view->rpzs); } if (view->catzs != NULL) {