]> git.ipfire.org Git - thirdparty/bind9.git/commitdiff
Refactor dns_rpz unit to use single reference counting
authorOndřej Surý <ondrej@isc.org>
Wed, 5 Oct 2022 09:21:28 +0000 (11:21 +0200)
committerAram Sargsyan <aram@isc.org>
Tue, 14 Feb 2023 09:58:16 +0000 (09:58 +0000)
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.

(cherry picked from commit 77659e739274a62573a00d029a273db6f55f7125)

bin/named/server.c
lib/dns/include/dns/rpz.h
lib/dns/rpz.c
lib/dns/view.c

index 511337a691ea333a464920b6a7ce1171533e0caa..77382b2862fddb430786f0da48853f776e661789 100644 (file)
@@ -2500,9 +2500,9 @@ 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_taskmgr,
-                                  named_g_timermgr);
+       result = dns_rpz_new_zones(view->mctx, named_g_taskmgr,
+                                  named_g_timermgr, rps_cstr, rps_cstr_size,
+                                  &view->rpzs);
        if (result != ISC_R_SUCCESS) {
                return (result);
        }
@@ -2638,6 +2638,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) {
index ff46c4005ba3c403e8930240a5215fe74c8e6f86..364ad925f5db2b4566a455c5f7d0b904941a5784 100644 (file)
 
 #pragma once
 
+/*
+ * Define this for reference count tracing in the unit
+ */
+#undef DNS_RPZ_TRACE
+
 #include <inttypes.h>
 #include <stdbool.h>
 
@@ -130,7 +135,8 @@ 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;
+
        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. */
@@ -207,6 +213,13 @@ 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_taskmgr_t  *taskmgr;
+       isc_timermgr_t *timermgr;
+       isc_task_t     *updater;
+
        dns_rpz_popt_t     p;
        dns_rpz_zone_t    *zones[DNS_RPZ_MAX_ZONES];
        dns_rpz_triggers_t triggers[DNS_RPZ_MAX_ZONES];
@@ -244,12 +257,6 @@ struct dns_rpz_zones {
         */
        dns_rpz_triggers_t total_triggers;
 
-       isc_mem_t      *mctx;
-       isc_taskmgr_t  *taskmgr;
-       isc_timermgr_t *timermgr;
-       isc_task_t     *updater;
-       isc_refcount_t  refs;
-       isc_refcount_t  irefs;
        /*
         * One lock for short term read-only search that guarantees the
         * consistency of the pointers.
@@ -259,6 +266,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;
 
@@ -382,9 +391,9 @@ 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_taskmgr_t *taskmgr,
-                 isc_timermgr_t *timermgr);
+dns_rpz_new_zones(isc_mem_t *mctx, isc_taskmgr_t *taskmgr,
+                 isc_timermgr_t *timermgr, 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);
@@ -393,10 +402,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,
index 18a38a4f81662f7aa591a2e5e1836709879ce285..4cacb4f8aa43371471460e4be6b469d4a807efdc 100644 (file)
@@ -18,6 +18,7 @@
 #include <stdlib.h>
 
 #include <isc/buffer.h>
+#include <isc/magic.h>
 #include <isc/mem.h>
 #include <isc/net.h>
 #include <isc/netaddr.h>
 #include <dns/rpz.h>
 #include <dns/view.h>
 
+#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
  *
 #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(isc_task_t *task, isc_event_t *event);
+dns__rpz_timer_cb(isc_task_t *task, isc_event_t *event);
 
 /*
  * Use a private definition of IPv6 addresses because s6_addr32 is not
@@ -167,24 +173,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) {
@@ -1441,9 +1434,9 @@ 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_taskmgr_t *taskmgr,
-                 isc_timermgr_t *timermgr) {
+dns_rpz_new_zones(isc_mem_t *mctx, isc_taskmgr_t *taskmgr,
+                 isc_timermgr_t *timermgr, 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;
 
@@ -1453,14 +1446,14 @@ dns_rpz_new_zones(dns_rpz_zones_t **rpzsp, char *rps_cstr, size_t rps_cstr_size,
        *rpzs = (dns_rpz_zones_t){
                .rps_cstr = rps_cstr,
                .rps_cstr_size = rps_cstr_size,
-               .timermgr = timermgr,
                .taskmgr = taskmgr,
+               .timermgr = timermgr,
+               .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) {
@@ -1481,7 +1474,7 @@ dns_rpz_new_zones(dns_rpz_zones_t **rpzsp, char *rps_cstr, size_t rps_cstr_size,
                goto cleanup_rbt;
        }
 
-       result = isc_task_create(taskmgr, 0, &rpzs->updater);
+       result = isc_task_create_bound(taskmgr, 0, &rpzs->updater, 0);
        if (result != ISC_R_SUCCESS) {
                goto cleanup_task;
        }
@@ -1495,10 +1488,8 @@ cleanup_task:
        dns_rbt_destroy(&rpzs->rbt);
 
 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));
@@ -1508,24 +1499,30 @@ cleanup_rbt:
 
 isc_result_t
 dns_rpz_new_zone(dns_rpz_zones_t *rpzs, dns_rpz_zone_t **rpzp) {
-       dns_rpz_zone_t *rpz = NULL;
        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);
        result = isc_timer_create(rpzs->timermgr, isc_timertype_inactive, NULL,
-                                 NULL, rpzs->updater,
-                                 dns_rpz_update_taskaction, rpz,
+                                 NULL, rpzs->updater, dns__rpz_timer_cb, rpz,
                                  &rpz->updatetimer);
        if (result != ISC_R_SUCCESS) {
                goto cleanup_timer;
@@ -1533,7 +1530,7 @@ dns_rpz_new_zone(dns_rpz_zones_t *rpzs, dns_rpz_zone_t **rpzp) {
 
        /*
         * This will never be used, but costs us nothing and
-        * simplifies update_from_db().
+        * simplifies dns__rpz_timer_cb().
         */
 
        isc_ht_init(&rpz->nodes, rpzs->mctx, 1, ISC_HT_CASE_SENSITIVE);
@@ -1550,8 +1547,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);
-
        ISC_EVENT_INIT(&rpz->updateevent, sizeof(rpz->updateevent), 0, NULL, 0,
                       NULL, NULL, NULL, NULL, NULL);
 
@@ -1576,10 +1571,15 @@ dns_rpz_dbupdate_callback(dns_db_t *db, void *fn_arg) {
        char dname[DNS_NAME_FORMATSIZE];
 
        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 */
@@ -1626,9 +1626,8 @@ dns_rpz_dbupdate_callback(dns_db_t *db, void *fn_arg) {
                        INSIST(!ISC_LINK_LINKED(&rpz->updateevent, ev_link));
                        ISC_EVENT_INIT(&rpz->updateevent,
                                       sizeof(rpz->updateevent), 0, NULL,
-                                      DNS_EVENT_RPZUPDATED,
-                                      dns_rpz_update_taskaction, rpz, rpz,
-                                      NULL, NULL);
+                                      DNS_EVENT_RPZUPDATED, dns__rpz_timer_cb,
+                                      rpz, rpz, NULL, NULL);
                        event = &rpz->updateevent;
                        isc_task_send(rpz->rpzs->updater, &event);
                }
@@ -1643,42 +1642,20 @@ 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_update_taskaction(isc_task_t *task, isc_event_t *event) {
-       isc_result_t result;
-       dns_rpz_zone_t *rpz = NULL;
-
-       REQUIRE(event != NULL);
-       REQUIRE(event->ev_arg != NULL);
-
-       UNUSED(task);
-       rpz = (dns_rpz_zone_t *)event->ev_arg;
-       isc_event_free(&event);
-       LOCK(&rpz->rpzs->maint_lock);
-       rpz->updatepending = false;
-       rpz->updaterunning = true;
-       rpz->updateresult = ISC_R_UNSET;
-
-       update_from_db(rpz);
-
-       result = isc_timer_reset(rpz->updatetimer, isc_timertype_inactive, NULL,
-                                NULL, true);
-       RUNTIME_CHECK(result == ISC_R_SUCCESS);
-       result = isc_time_now(&rpz->lastupdated);
-       RUNTIME_CHECK(result == ISC_R_SUCCESS);
-       UNLOCK(&rpz->rpzs->maint_lock);
-}
-
 static void
 update_rpz_done_cb(void *data, isc_result_t result) {
        dns_rpz_zone_t *rpz = (dns_rpz_zone_t *)data;
        char dname[DNS_NAME_FORMATSIZE];
 
+       REQUIRE(DNS_RPZ_ZONE_VALID(rpz));
+
        if (result == ISC_R_SUCCESS && rpz->updateresult != ISC_R_SUCCESS) {
                result = rpz->updateresult;
        }
@@ -1688,8 +1665,8 @@ update_rpz_done_cb(void *data, isc_result_t result) {
 
        dns_name_format(&rpz->origin, dname, DNS_NAME_FORMATSIZE);
 
-       /* If there's no update pending, finish. */
-       if (!rpz->updatepending) {
+       /* If there's no update pending, or if shutting down, finish. */
+       if (!rpz->updatepending || rpz->rpzs->shuttingdown) {
                goto done;
        }
 
@@ -1711,8 +1688,8 @@ update_rpz_done_cb(void *data, isc_result_t result) {
                isc_event_t *event = NULL;
                INSIST(!ISC_LINK_LINKED(&rpz->updateevent, ev_link));
                ISC_EVENT_INIT(&rpz->updateevent, sizeof(rpz->updateevent), 0,
-                              NULL, DNS_EVENT_RPZUPDATED,
-                              dns_rpz_update_taskaction, rpz, rpz, NULL, NULL);
+                              NULL, DNS_EVENT_RPZUPDATED, dns__rpz_timer_cb,
+                              rpz, rpz, NULL, NULL);
                event = &rpz->updateevent;
                isc_task_send(rpz->rpzs->updater, &event);
        }
@@ -1723,11 +1700,11 @@ done:
 
        UNLOCK(&rpz->rpzs->maint_lock);
 
-       rpz_detach(&rpz);
-
        isc_log_write(dns_lctx, DNS_LOGCATEGORY_GENERAL, DNS_LOGMODULE_MASTER,
                      ISC_LOG_INFO, "rpz: %s: reload done: %s", dname,
                      isc_result_totext(result));
+
+       dns_rpz_unref_rpzs(rpz->rpzs);
 }
 
 static isc_result_t
@@ -1765,7 +1742,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;
@@ -1892,7 +1869,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;
                }
@@ -1917,13 +1894,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);
@@ -1940,7 +1916,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;
        }
@@ -1967,17 +1943,37 @@ cleanup:
 }
 
 static void
-update_from_db(dns_rpz_zone_t *rpz) {
+dns__rpz_timer_cb(isc_task_t *task, isc_event_t *event) {
        char domain[DNS_NAME_FORMATSIZE];
-       dns_rpz_zone_t *rpz_zone = NULL;
+       isc_result_t result;
+       dns_rpz_zone_t *rpz = NULL;
+
+       UNUSED(task);
+       REQUIRE(event != NULL);
+       REQUIRE(event->ev_arg != NULL);
+
+       rpz = (dns_rpz_zone_t *)event->ev_arg;
+       isc_event_free(&event);
 
        REQUIRE(isc_nm_tid() >= 0);
-       REQUIRE(rpz != NULL);
-       REQUIRE(DNS_DB_VALID(rpz->db));
-       REQUIRE(rpz->updb == NULL);
-       REQUIRE(rpz->updbversion == NULL);
+       REQUIRE(DNS_RPZ_ZONE_VALID(rpz));
+
+       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;
 
-       rpz_attach(rpz, &rpz_zone);
+       INSIST(rpz->updb == NULL);
+       INSIST(rpz->updbversion == NULL);
+       INSIST(rpz->dbversion != NULL);
+       INSIST(DNS_DB_VALID(rpz->db));
        dns_db_attach(rpz->db, &rpz->updb);
        rpz->updbversion = rpz->dbversion;
        rpz->dbversion = NULL;
@@ -1987,7 +1983,13 @@ update_from_db(dns_rpz_zone_t *rpz) {
                      ISC_LOG_INFO, "rpz: %s: reload start", domain);
 
        isc_nm_work_offload(isc_task_getnetmgr(rpz->rpzs->updater),
-                           update_rpz_cb, update_rpz_done_cb, rpz_zone);
+                           update_rpz_cb, update_rpz_done_cb, rpz);
+
+       result = isc_time_now(&rpz->lastupdated);
+       RUNTIME_CHECK(result == ISC_R_SUCCESS);
+
+unlock:
+       UNLOCK(&rpz->rpzs->maint_lock);
 }
 
 /*
@@ -2024,20 +2026,29 @@ 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);
-
-       isc_refcount_increment(&rpz->refs);
-       *rpzp = rpz;
+dns__rpz_shutdown(dns_rpz_zone_t *rpz) {
+       /* maint_lock must be locked */
+       if (rpz->updatetimer != NULL) {
+               isc_result_t result;
+
+               /* Don't wait for timer to trigger for shutdown */
+               result = isc_timer_reset(rpz->updatetimer,
+                                        isc_timertype_inactive, NULL, NULL,
+                                        true);
+               RUNTIME_CHECK(result == ISC_R_SUCCESS);
+       }
 }
 
 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;
 
-       isc_refcount_destroy(&rpz->refs);
+       rpz = *rpzp;
+       *rpzp = NULL;
+
+       rpzs = rpz->rpzs;
+       rpz->rpzs = NULL;
 
        if (dns_name_dynamic(&rpz->origin)) {
                dns_name_free(&rpz->origin, rpzs->mctx);
@@ -2074,7 +2085,6 @@ rpz_destroy(dns_rpz_zone_t *rpz) {
                                               dns_rpz_dbupdate_callback, rpz);
                dns_db_detach(&rpz->db);
        }
-
        INSIST(!rpz->updaterunning);
 
        isc_timer_reset(rpz->updatetimer, isc_timertype_inactive, NULL, NULL,
@@ -2084,74 +2094,23 @@ rpz_destroy(dns_rpz_zone_t *rpz) {
        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);
-       }
-}
-
-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;
-}
+dns__rpz_zones_destroy(dns_rpz_zones_t *rpzs) {
+       REQUIRE(rpzs->shuttingdown);
 
-/*
- * 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);
@@ -2166,21 +2125,41 @@ rpz_destroy_rpzs(dns_rpz_zones_t *rpzs) {
        isc_task_destroy(&rpzs->updater);
        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.
  */
index 3ee58400951d4e0f614a0041a7ba88f09640fc4c..4ef3439ce74f2e7c0995695e7f5cd9a174af6fe7 100644 (file)
@@ -419,6 +419,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) {