+6146. [performance] Replace the zone table red-black tree and associated
+ locking with a lock-free qp-trie. [GL !7582]
+
6145. [bug] Fix a possible use-after-free bug in the
dns__catz_done_cb() function. [GL #3997]
CHECK(ns_interfacemgr_create(mctx, sctx, loopmgr, netmgr, dispatchmgr,
NULL, false, &interfacemgr));
- CHECK(dns_view_create(mctx, dns_rdataclass_in, "_default", &view));
+ CHECK(dns_view_create(mctx, loopmgr, dns_rdataclass_in, "_default",
+ &view));
CHECK(dns_cache_create(loopmgr, dns_rdataclass_in, "", &cache));
dns_view_setcache(view, cache, false);
dns_cache_detach(&cache);
goto cleanup;
}
- result = dns_zt_find(cz->view->zonetable, name, 0, NULL, &zone);
+ result = dns_view_findzone(cz->view, name, &zone);
if (cz->mod) {
dns_catz_zone_t *parentcatz;
nameb);
}
goto cleanup;
- } else if (result != ISC_R_NOTFOUND &&
- result != DNS_R_PARTIALMATCH)
- {
- isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
- NAMED_LOGMODULE_SERVER, ISC_LOG_WARNING,
- "catz: error \"%s\" while trying to "
- "add zone '%s'",
- isc_result_totext(result), nameb);
- goto cleanup;
- } else { /* this can happen in case of DNS_R_PARTIALMATCH */
- if (zone != NULL) {
- dns_zone_detach(&zone);
- }
+ } else {
+ RUNTIME_CHECK(result == ISC_R_NOTFOUND);
}
}
RUNTIME_CHECK(zone == NULL);
}
/* Is it there yet? */
- CHECK(dns_zt_find(cz->view->zonetable, name, 0, NULL, &zone));
+ CHECK(dns_view_findzone(cz->view, name, &zone));
/*
* Load the zone from the master file. If this fails, we'll
dns_name_format(dns_catz_entry_getname(cz->entry), cname,
DNS_NAME_FORMATSIZE);
- result = dns_zt_find(cz->view->zonetable,
- dns_catz_entry_getname(cz->entry), 0, NULL, &zone);
+ result = dns_view_findzone(cz->view, dns_catz_entry_getname(cz->entry),
+ &zone);
if (result != ISC_R_SUCCESS) {
isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
NAMED_LOGMODULE_SERVER, ISC_LOG_WARNING,
}
INSIST(view == NULL);
- result = dns_view_create(named_g_mctx, viewclass, viewname, &view);
+ result = dns_view_create(named_g_mctx, named_g_loopmgr, viewclass,
+ viewname, &view);
if (result != ISC_R_SUCCESS) {
return (result);
}
if (result == ISC_R_SUCCESS && strcmp(view->name, "_bind") != 0)
{
dns_view_setviewrevert(view);
- (void)dns_zt_apply(view->zonetable, isc_rwlocktype_read,
- false, NULL, removed, view);
+ (void)dns_zt_apply(view->zonetable, false, NULL,
+ removed, view);
}
dns_view_detach(&view);
}
result = ISC_R_NOTFOUND;
}
} else {
- result = dns_zt_find(view->zonetable, name, 0, NULL,
- zonep);
+ result = dns_view_findzone(view, name, zonep);
}
if (result != ISC_R_SUCCESS) {
snprintf(problem, sizeof(problem),
ISC_LIST_INIT(vle->zonelist);
ISC_LIST_APPEND(dctx->viewlist, vle, link);
if (dctx->dumpzones) {
- result = dns_zt_apply(view->zonetable, isc_rwlocktype_read,
- true, NULL, add_zone_tolist, dctx);
+ result = dns_zt_apply(view->zonetable, true, NULL,
+ add_zone_tolist, dctx);
}
return (result);
}
for (view = ISC_LIST_HEAD(server->viewlist); view != NULL;
view = ISC_LIST_NEXT(view, link))
{
- result = dns_zt_apply(view->zonetable,
- isc_rwlocktype_none, false, NULL,
+ result = dns_zt_apply(view->zonetable, false, NULL,
synczone, &cleanup);
if (result != ISC_R_SUCCESS && tresult == ISC_R_SUCCESS)
{
/* Zone shouldn't already exist */
if (redirect) {
- result = (view->redirect != NULL) ? ISC_R_SUCCESS
- : ISC_R_NOTFOUND;
+ result = (view->redirect == NULL) ? ISC_R_NOTFOUND
+ : ISC_R_EXISTS;
} else {
- result = dns_zt_find(view->zonetable, name, 0, NULL, &zone);
+ result = dns_view_findzone(view, name, &zone);
+ if (result == ISC_R_SUCCESS) {
+ result = ISC_R_EXISTS;
+ }
}
- if (result == ISC_R_SUCCESS) {
- result = ISC_R_EXISTS;
- goto cleanup;
- } else if (result == DNS_R_PARTIALMATCH) {
- /* Create our sub-zone anyway */
- dns_zone_detach(&zone);
- zone = NULL;
- } else if (result != ISC_R_NOTFOUND) {
+ if (result != ISC_R_NOTFOUND) {
goto cleanup;
}
}
dns_zone_attach(view->redirect, &zone);
} else {
- result = dns_zt_find(view->zonetable, name, 0, NULL, &zone);
+ result = dns_view_findzone(view, name, &zone);
if (result != ISC_R_SUCCESS) {
isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
result = ISC_R_NOTFOUND;
}
} else {
- result = dns_zt_find(view->zonetable, name, 0, NULL, &zone);
+ result = dns_view_findzone(view, name, &zone);
}
if (result != ISC_R_SUCCESS) {
goto cleanup;
}
dns_zone_attach(view->redirect, &zone);
} else {
- CHECK(dns_zt_find(view->zonetable, name, 0, NULL, &zone));
+ CHECK(dns_view_findzone(view, name, &zone));
}
#ifndef HAVE_LMDB
if ((flags & STATS_XML_ZONES) != 0) {
TRY0(xmlTextWriterStartElement(writer,
ISC_XMLCHAR "zones"));
- CHECK(dns_zt_apply(view->zonetable, isc_rwlocktype_read,
- true, NULL, zone_xmlrender, writer));
+ CHECK(dns_zt_apply(view->zonetable, true, NULL,
+ zone_xmlrender, writer));
TRY0(xmlTextWriterEndElement(writer)); /* /zones */
}
CHECKMEM(za);
if ((flags & STATS_JSON_ZONES) != 0) {
- CHECK(dns_zt_apply(view->zonetable,
- isc_rwlocktype_read, true,
- NULL, zone_jsonrender, za));
+ CHECK(dns_zt_apply(view->zonetable, true, NULL,
+ zone_jsonrender, za));
}
if (json_object_array_length(za) != 0) {
n=$((n+1))
echo_i "waiting for secondary to sync up ($n)"
ret=0
-wait_for_message ns2/named.run "zone_shutdown: zone dom1.example/IN/default: shutting down" || ret=1
+wait_for_message ns2/named.run "catz: catz_delzone_cb: zone 'dom1.example' deleted" || ret=1
if [ $ret -ne 0 ]; then echo_i "failed"; fi
status=$((status+ret))
n=$((n+1))
echo_i "waiting for secondary to sync up ($n)"
ret=0
-wait_for_message ns2/named.run "zone_shutdown: zone dom5.example/IN/default: shutting down" || ret=1
+wait_for_message ns2/named.run "catz: catz_delzone_cb: zone 'dom5.example' deleted" || ret=1
if [ $ret -ne 0 ]; then echo_i "failed"; fi
status=$((status+ret))
n=$((n+1))
echo_i "waiting for secondary to sync up ($n)"
ret=0
-wait_for_message ns2/named.run "zone_shutdown: zone dom6.example/IN/default: shutting down" || ret=1
+wait_for_message ns2/named.run "catz: catz_delzone_cb: zone 'dom6.example' deleted" || ret=1
if [ $ret -ne 0 ]; then echo_i "failed"; fi
status=$((status+ret))
n=$((n+1))
echo_i "waiting for secondary to sync up ($n)"
ret=0
- wait_for_message ns2/named.run "zone_shutdown: zone ${special}/IN/default: shutting down" || ret=1
+ wait_for_message ns2/named.run "catz: catz_delzone_cb: zone '${special}' deleted" || ret=1
if [ $ret -ne 0 ]; then echo_i "failed"; fi
status=$((status+ret))
n=$((n+1))
echo_i "waiting for secondary to sync up ($n)"
ret=0
-wait_for_message ns2/named.run "zone_shutdown: zone dom11.example/IN/default: shutting down" || ret=1
+wait_for_message ns2/named.run "catz: catz_delzone_cb: zone 'dom11.example' deleted" || ret=1
if [ $ret -ne 0 ]; then echo_i "failed"; fi
status=$((status+ret))
n=$((n+1))
echo_i "waiting for secondary to sync up ($n)"
ret=0
-wait_for_message ns2/named.run "zone_shutdown: zone subdomain.of.dom11.example/IN/default: shutting down" || ret=1
+wait_for_message ns2/named.run "catz: catz_delzone_cb: zone 'subdomain.of.dom11.example' deleted" || ret=1
if [ $ret -ne 0 ]; then echo_i "failed"; fi
status=$((status+ret))
n=$((n+1))
echo_i "waiting for secondary to sync up ($n)"
ret=0
-wait_for_message ns2/named.run "catz: deleting zone 'dom17.example' from catalog 'catalog1.example' - success" &&
-wait_for_message ns2/named.run "catz: deleting zone 'dom18.example' from catalog 'catalog1.example' - success" &&
-wait_for_message ns2/named.run "zone_shutdown: zone dom17.example/IN/default: shutting down" &&
-wait_for_message ns2/named.run "zone_shutdown: zone dom18.example/IN/default: shutting down" || ret=1
+wait_for_message ns2/named.run "catz: catz_delzone_cb: zone 'dom17.example' deleted" &&
+wait_for_message ns2/named.run "catz: catz_delzone_cb: zone 'dom18.example' deleted" &&
if [ $ret -ne 0 ]; then echo_i "failed"; fi
status=$((status+ret))
n=$((n+1))
echo_i "waiting for secondary to sync up ($n)"
ret=0
-wait_for_message ns2/named.run "catz: deleting zone 'dom17.example' from catalog 'catalog2.example' - success" &&
-wait_for_message ns2/named.run "catz: deleting zone 'dom18.example' from catalog 'catalog2.example' - success" &&
-wait_for_message ns2/named.run "zone_shutdown: zone dom17.example/IN/default: shutting down" &&
-wait_for_message ns2/named.run "zone_shutdown: zone dom18.example/IN/default: shutting down" || ret=1
+wait_for_message ns2/named.run "catz: catz_delzone_cb: zone 'dom17.example' deleted" &&
+wait_for_message ns2/named.run "catz: catz_delzone_cb: zone 'dom18.example' deleted" || ret=1
if [ $ret -ne 0 ]; then echo_i "failed"; fi
status=$((status+ret))
}
/* Find a zone containing owner name of the PTR record. */
- result = dns_zt_find(inst->view->zonetable, name, 0, NULL, zone);
+ result = dns_zt_find(inst->view->zonetable, name, 0, zone);
if (result == DNS_R_PARTIALMATCH) {
result = ISC_R_SUCCESS;
} else if (result != ISC_R_SUCCESS) {
RUNCHECK(dns_requestmgr_create(mctx, dispatchmgr, dispatchv4, NULL,
&requestmgr));
- RUNCHECK(dns_view_create(mctx, 0, "_test", &view));
+ RUNCHECK(dns_view_create(mctx, loopmgr, 0, "_test", &view));
isc_loopmgr_setup(loopmgr, sendqueries, NULL);
isc_loopmgr_run(loopmgr);
mctx, dispatchmgr, have_ipv4 ? dispatchvx : NULL,
have_ipv6 ? dispatchvx : NULL, &requestmgr));
- RUNCHECK(dns_view_create(mctx, 0, "_test", &view));
+ RUNCHECK(dns_view_create(mctx, loopmgr, 0, "_mdig", &view));
query = ISC_LIST_HEAD(queries);
isc_loopmgr_setup(loopmgr, sendqueries, query);
#include <isc/mem.h>
#include <isc/result.h>
#include <isc/string.h>
+#include <isc/tid.h>
#include <isc/util.h>
#include <dns/fixedname.h>
#define HMACSHA256 "\x0bhmac-sha256"
static isc_stdtime_t fuzztime = 0x622acce1;
+static isc_loopmgr_t *loopmgr = NULL;
static dns_view_t *view = NULL;
static dns_tsigkey_t *tsigkey = NULL;
static dns_tsig_keyring_t *ring = NULL;
}
destroy_dst = true;
- result = dns_view_create(mctx, dns_rdataclass_in, "view", &view);
+ isc_loopmgr_create(mctx, 1, &loopmgr);
+
+ result = dns_view_create(mctx, loopmgr, dns_rdataclass_in, "view",
+ &view);
if (result != ISC_R_SUCCESS) {
fprintf(stderr, "dns_view_create failed: %s\n",
isc_result_totext(result));
return (1);
}
+ dns_zone_setview(zone, view);
dns_view_freeze(view);
dns_zone_detach(&zone);
result = delcur ? isc_ht_iter_delcurrent_next(iter1)
: isc_ht_iter_next(iter1))
{
- isc_result_t zt_find_result;
+ isc_result_t find_result;
dns_catz_zone_t *parentcatz = NULL;
dns_catz_entry_t *nentry = NULL;
dns_catz_entry_t *oentry = NULL;
&catz->zoneoptions, &nentry->opts);
/* Try to find the zone in the view */
- zt_find_result = dns_zt_find(catz->catzs->view->zonetable,
- dns_catz_entry_getname(nentry), 0,
- NULL, &zone);
- if (zt_find_result == ISC_R_SUCCESS) {
+ find_result = dns_view_findzone(catz->catzs->view,
+ dns_catz_entry_getname(nentry),
+ &zone);
+ if (find_result == ISC_R_SUCCESS) {
dns_catz_coo_t *coo = NULL;
char pczname[DNS_NAME_FORMATSIZE];
bool parentcatz_locked = false;
UNLOCK(&parentcatz->lock);
LOCK(&catz->lock);
}
- }
- if (zt_find_result == ISC_R_SUCCESS ||
- zt_find_result == DNS_R_PARTIALMATCH)
- {
dns_zone_detach(&zone);
}
result = isc_ht_find(catz->entries, key, (uint32_t)keysize,
(void **)&oentry);
if (result != ISC_R_SUCCESS) {
- if (zt_find_result == ISC_R_SUCCESS &&
- parentcatz == catz)
+ if (find_result == ISC_R_SUCCESS && parentcatz == catz)
{
/*
* This means that the zone's unique label
continue;
}
- if (zt_find_result != ISC_R_SUCCESS) {
+ if (find_result != ISC_R_SUCCESS) {
isc_log_write(dns_lctx, DNS_LOGCATEGORY_GENERAL,
DNS_LOGMODULE_MASTER, ISC_LOG_DEBUG(3),
"catz: zone '%s' was expected to exist "
isc_result_t result;
dns_view_t *view = NULL;
- result = dns_view_create(mctx, rdclass, DNS_CLIENTVIEW_NAME, &view);
+ result = dns_view_create(mctx, loopmgr, rdclass, DNS_CLIENTVIEW_NAME,
+ &view);
if (result != ISC_R_SUCCESS) {
return (result);
}
#endif /* HAVE_LMDB */
isc_result_t
-dns_view_create(isc_mem_t *mctx, dns_rdataclass_t rdclass, const char *name,
- dns_view_t **viewp);
+dns_view_create(isc_mem_t *mctx, isc_loopmgr_t *loopmgr,
+ dns_rdataclass_t rdclass, const char *name, dns_view_t **viewp);
/*%<
* Create a view.
*
*\li *viewp is NULL.
*/
-isc_result_t
-dns_view_createzonetable(dns_view_t *view);
-/*%<
- * Create a zonetable for the view.
- *
- * Requires:
- *
- *\li 'view' is a valid, unfrozen view.
- *
- *\li 'view' does not have a zonetable already.
- *
- * Returns:
- *
- *\li #ISC_R_SUCCESS
- *
- *\li Any error that dns_zt_create() can return.
- */
-
isc_result_t
dns_view_createresolver(dns_view_t *view, isc_loopmgr_t *loopmgr,
unsigned int ndisp, isc_nm_t *netmgr,
* Returns:
*\li #ISC_R_SUCCESS A matching zone was found.
*\li #ISC_R_NOTFOUND No matching zone was found.
- *\li others An error occurred.
*/
isc_result_t
dns_view_load(dns_view_t *view, bool stop, bool newonly);
isc_result_t
-dns_view_asyncload(dns_view_t *view, bool newonly, dns_zt_allloaded_t callback,
+dns_view_asyncload(dns_view_t *view, bool newonly, dns_zt_callback_t *callback,
void *arg);
/*%<
* Load zones attached to this view. dns_view_load() loads
*/
isc_result_t
-dns_zone_asyncload(dns_zone_t *zone, bool newonly, dns_zt_zoneloaded_t done,
+dns_zone_asyncload(dns_zone_t *zone, bool newonly, dns_zt_callback_t done,
void *arg);
/*%<
* Cause the database to be loaded from its backing store asynchronously.
* Other zone maintenance functions are suspended until this is complete.
* When finished, 'done' is called to inform the caller, with 'arg' as
- * its first argument and 'zone' as its second. (Normally, 'arg' is
- * expected to point to the zone table but is left undefined for testing
- * purposes.)
+ * its argument. (Normally, 'arg' is expected to point to the zone table
+ * but is left undefined for testing purposes.)
*
* Require:
*\li 'zone' to be a valid zone.
#include <dns/types.h>
-#define DNS_ZTFIND_NOEXACT 0x01
-#define DNS_ZTFIND_MIRROR 0x02
-
ISC_LANG_BEGINDECLS
-typedef isc_result_t (*dns_zt_allloaded_t)(void *arg);
-/*%<
- * Method prototype: when all pending zone loads are complete,
- * the zone table can inform the caller via a callback function with
- * this signature.
- */
+typedef enum dns_ztfind {
+ DNS_ZTFIND_EXACT = 1 << 0,
+ DNS_ZTFIND_NOEXACT = 1 << 1,
+ DNS_ZTFIND_MIRROR = 1 << 2,
+} dns_ztfind_t;
-typedef isc_result_t (*dns_zt_zoneloaded_t)(dns_zt_t *zt, dns_zone_t *zone);
-/*%<
- * Method prototype: when a zone finishes loading, the zt object
- * can be informed via a callback function with this signature.
- */
+typedef isc_result_t
+dns_zt_callback_t(void *arg);
-isc_result_t
-dns_zt_create(isc_mem_t *mctx, dns_rdataclass_t rdclass, dns_zt_t **zt);
+void
+dns_zt_create(isc_mem_t *mctx, isc_loopmgr_t *loopmgr, dns_view_t *view,
+ dns_zt_t **ztp);
/*%<
- * Creates a new zone table.
+ * Creates a new zone table for a view.
*
* Requires:
* \li 'mctx' to be initialized.
+ * \li 'view' is non-NULL
+ * \li 'ztp' is non-NULL
+ * \li '*ztp' is NULL
+ */
+
+void
+dns_zt_compact(dns_zt_t *zt);
+/*%<
+ * Reclaim unused memory in the zone table
*
- * Returns:
- * \li #ISC_R_SUCCESS on success.
- * \li #ISC_R_NOMEMORY
+ * Requires:
+ * \li 'zt' to be valid
*/
isc_result_t
* Returns:
* \li #ISC_R_SUCCESS
* \li #ISC_R_EXISTS
- * \li #ISC_R_NOSPACE
- * \li #ISC_R_NOMEMORY
*/
isc_result_t
* Unmount the given zone from the table.
*
* Requires:
- * 'zt' to be valid
+ * 'zt' to be valid
* \li 'zone' to be valid
*
* Returns:
* \li #ISC_R_SUCCESS
* \li #ISC_R_NOTFOUND
- * \li #ISC_R_NOMEMORY
*/
isc_result_t
-dns_zt_find(dns_zt_t *zt, const dns_name_t *name, unsigned int options,
- dns_name_t *foundname, dns_zone_t **zone);
+dns_zt_find(dns_zt_t *zt, const dns_name_t *name, dns_ztfind_t options,
+ dns_zone_t **zone);
/*%<
- * Find the best match for 'name' in 'zt'. If foundname is non NULL
- * then the name of the zone found is returned.
+ * Find the best match for 'name' in 'zt'.
*
* Notes:
- * \li If the DNS_ZTFIND_NOEXACT is set, the best partial match (if any)
- * to 'name' will be returned.
+ * \li If the DNS_ZTFIND_EXACT option is set, only an exact match is
+ * returned.
+ *
+ * \li If the DNS_ZTFIND_NOEXACT option is set, the closest matching
+ * parent domain is returned, even when there is an exact match
+ * in the tree.
*
* Requires:
* \li 'zt' to be valid
* \li 'name' to be valid
- * \li 'foundname' to be initialized and associated with a fixedname or NULL
* \li 'zone' to be non NULL and '*zone' to be NULL
+ * \li DNS_ZTFIND_EXACT and DNS_ZTFIND_NOEXACT are not both set
*
* Returns:
* \li #ISC_R_SUCCESS
- * \li #DNS_R_PARTIALMATCH
+ * \li #DNS_R_PARTIALMATCH (if DNS_ZTFIND_EXACT is not set)
* \li #ISC_R_NOTFOUND
- * \li #ISC_R_NOSPACE
*/
void
dns_zt_load(dns_zt_t *zt, bool stop, bool newonly);
isc_result_t
-dns_zt_asyncload(dns_zt_t *zt, bool newonly, dns_zt_allloaded_t alldone,
+dns_zt_asyncload(dns_zt_t *zt, bool newonly, dns_zt_callback_t alldone,
void *arg);
/*%<
- * Load all zones in the table. If 'stop' is true,
- * stop on the first error and return it. If 'stop'
- * is false, ignore errors.
+ * Load all zones in the table. If 'stop' is true, stop on the first
+ * error and return it. If 'stop' is false, ignore errors.
+ *
+ * If newonly is set only zones that were never loaded are loaded.
*
- * if newonly is set only zones that were never loaded are loaded.
* dns_zt_asyncload() loads zones asynchronously; when all
* zones in the zone table have finished loaded (or failed due
* to errors), the caller is informed by calling 'alldone'
*/
isc_result_t
-dns_zt_apply(dns_zt_t *zt, isc_rwlocktype_t lock, bool stop, isc_result_t *sub,
+dns_zt_apply(dns_zt_t *zt, bool stop, isc_result_t *sub,
isc_result_t (*action)(dns_zone_t *, void *), void *uap);
/*%<
* Apply a given 'action' to all zone zones in the table.
name_external(const dns_name_t *name, dns_rdatatype_t type, fetchctx_t *fctx) {
isc_result_t result;
dns_forwarders_t *forwarders = NULL;
- dns_fixedname_t fixed, zfixed;
+ dns_fixedname_t fixed;
dns_name_t *fname = dns_fixedname_initname(&fixed);
- dns_name_t *zfname = dns_fixedname_initname(&zfixed);
dns_name_t *apex = NULL;
dns_name_t suffix;
dns_zone_t *zone = NULL;
* If there is a locally served zone between 'apex' and 'name'
* then don't cache.
*/
- LOCK(&fctx->res->view->lock);
- if (fctx->res->view->zonetable != NULL) {
- unsigned int options = DNS_ZTFIND_NOEXACT | DNS_ZTFIND_MIRROR;
- result = dns_zt_find(fctx->res->view->zonetable, name, options,
- zfname, &zone);
- if (zone != NULL) {
- dns_zone_detach(&zone);
- }
- if (result == ISC_R_SUCCESS || result == DNS_R_PARTIALMATCH) {
- if (dns_name_fullcompare(zfname, apex, &(int){ 0 },
- &(unsigned int){ 0U }) ==
- dns_namereln_subdomain)
- {
- UNLOCK(&fctx->res->view->lock);
- return (true);
- }
+ dns_ztfind_t options = DNS_ZTFIND_NOEXACT | DNS_ZTFIND_MIRROR;
+ result = dns_zt_find(fctx->res->view->zonetable, name, options, &zone);
+ if (result == ISC_R_SUCCESS || result == DNS_R_PARTIALMATCH) {
+ dns_name_t *zname = dns_zone_getorigin(zone);
+ dns_namereln_t reln = dns_name_fullcompare(
+ zname, apex, &(int){ 0 }, &(unsigned int){ 0U });
+ dns_zone_detach(&zone);
+ if (reln == dns_namereln_subdomain) {
+ return (true);
}
}
- UNLOCK(&fctx->res->view->lock);
/*
* Look for a forward declaration below 'name'.
#define DEFAULT_EDNS_BUFSIZE 1232
isc_result_t
-dns_view_create(isc_mem_t *mctx, dns_rdataclass_t rdclass, const char *name,
+dns_view_create(isc_mem_t *mctx, isc_loopmgr_t *loopmgr,
+ dns_rdataclass_t rdclass, const char *name,
dns_view_t **viewp) {
dns_view_t *view = NULL;
isc_result_t result;
isc_rwlock_init(&view->sfd_lock);
view->zonetable = NULL;
- result = dns_zt_create(mctx, rdclass, &view->zonetable);
- if (result != ISC_R_SUCCESS) {
- UNEXPECTED_ERROR("dns_zt_create() failed: %s",
- isc_result_totext(result));
- result = ISC_R_UNEXPECTED;
- goto cleanup_mutex;
- }
+ dns_zt_create(mctx, loopmgr, view, &view->zonetable);
result = dns_fwdtable_create(mctx, &view->fwdtable);
if (result != ISC_R_SUCCESS) {
}
cleanup_zt:
- if (view->zonetable != NULL) {
- dns_zt_detach(&view->zonetable);
- }
+ dns_zt_detach(&view->zonetable);
-cleanup_mutex:
isc_rwlock_destroy(&view->sfd_lock);
isc_mutex_destroy(&view->lock);
REQUIRE(DNS_VIEW_VALID(view));
REQUIRE(view->zonetable != NULL);
- (void)dns_zt_apply(view->zonetable, isc_rwlocktype_read, false, NULL,
- dialup, NULL);
+ (void)dns_zt_apply(view->zonetable, false, NULL, dialup, NULL);
}
void
}
}
-isc_result_t
-dns_view_createzonetable(dns_view_t *view) {
- REQUIRE(DNS_VIEW_VALID(view));
- REQUIRE(!view->frozen);
- REQUIRE(view->zonetable == NULL);
-
- return (dns_zt_create(view->mctx, view->rdclass, &view->zonetable));
-}
-
isc_result_t
dns_view_createresolver(dns_view_t *view, isc_loopmgr_t *loopmgr,
unsigned int ndisp, isc_nm_t *netmgr,
REQUIRE(DNS_VIEW_VALID(view));
REQUIRE(!view->frozen);
- REQUIRE(view->zonetable != NULL);
result = dns_zt_mount(view->zonetable, zone);
isc_result_t
dns_view_findzone(dns_view_t *view, const dns_name_t *name,
dns_zone_t **zonep) {
- isc_result_t result;
-
REQUIRE(DNS_VIEW_VALID(view));
- LOCK(&view->lock);
- if (view->zonetable != NULL) {
- result = dns_zt_find(view->zonetable, name, 0, NULL, zonep);
- if (result == DNS_R_PARTIALMATCH) {
- dns_zone_detach(zonep);
- result = ISC_R_NOTFOUND;
- }
- } else {
- result = ISC_R_NOTFOUND;
- }
- UNLOCK(&view->lock);
-
- return (result);
+ return (dns_zt_find(view->zonetable, name, DNS_ZTFIND_EXACT, zonep));
}
isc_result_t
dns_name_t *foundname, dns_rdataset_t *rdataset,
dns_rdataset_t *sigrdataset) {
isc_result_t result;
- dns_db_t *db, *zdb;
- dns_dbnode_t *node, *znode;
+ dns_db_t *db = NULL, *zdb = NULL;
+ dns_dbnode_t *node = NULL, *znode = NULL;
bool is_cache, is_staticstub_zone;
dns_rdataset_t zrdataset, zsigrdataset;
- dns_zone_t *zone;
+ dns_zone_t *zone = NULL;
/*
* Find an rdataset whose owner name is 'name', and whose type is
*/
dns_rdataset_init(&zrdataset);
dns_rdataset_init(&zsigrdataset);
- zdb = NULL;
- znode = NULL;
/*
* Find a database to answer the query.
*/
- db = NULL;
- node = NULL;
is_staticstub_zone = false;
- zone = NULL;
- LOCK(&view->lock);
- if (view->zonetable != NULL) {
- result = dns_zt_find(view->zonetable, name, DNS_ZTFIND_MIRROR,
- NULL, &zone);
- } else {
- result = ISC_R_NOTFOUND;
- }
- UNLOCK(&view->lock);
+ result = dns_zt_find(view->zonetable, name, DNS_ZTFIND_MIRROR, &zone);
if (zone != NULL && dns_zone_gettype(zone) == dns_zone_staticstub &&
!use_static_stub)
{
unsigned int options, bool use_hints, bool use_cache,
dns_rdataset_t *rdataset, dns_rdataset_t *sigrdataset) {
isc_result_t result;
- dns_db_t *db;
- bool is_cache, use_zone, try_hints;
- dns_zone_t *zone;
- dns_name_t *zfname;
+ dns_db_t *db = NULL;
+ bool is_cache, use_zone = false, try_hints = false;
+ dns_zone_t *zone = NULL;
+ dns_name_t *zfname = NULL;
dns_rdataset_t zrdataset, zsigrdataset;
dns_fixedname_t zfixedname;
unsigned int ztoptions = DNS_ZTFIND_MIRROR;
REQUIRE(DNS_VIEW_VALID(view));
REQUIRE(view->frozen);
- db = NULL;
- use_zone = false;
- try_hints = false;
- zfname = NULL;
-
/*
* Initialize.
*/
/*
* Find the right database.
*/
- zone = NULL;
- LOCK(&view->lock);
- if (view->zonetable != NULL) {
- if ((options & DNS_DBFIND_NOEXACT) != 0) {
- ztoptions |= DNS_ZTFIND_NOEXACT;
- }
- result = dns_zt_find(view->zonetable, name, ztoptions, NULL,
- &zone);
- } else {
- result = ISC_R_NOTFOUND;
+ if ((options & DNS_DBFIND_NOEXACT) != 0) {
+ ztoptions |= DNS_ZTFIND_NOEXACT;
}
- UNLOCK(&view->lock);
+ result = dns_zt_find(view->zonetable, name, ztoptions, &zone);
if (result == ISC_R_SUCCESS || result == DNS_R_PARTIALMATCH) {
result = dns_zone_getdb(zone, &db);
}
dns_view_t *view;
isc_result_t result;
dns_zone_t *zone1 = NULL, *zone2 = NULL;
- dns_zone_t **zp = NULL;
REQUIRE(list != NULL);
REQUIRE(zonep != NULL && *zonep == NULL);
if (!allclasses && view->rdclass != rdclass) {
continue;
}
-
- /*
- * If the zone is defined in more than one view,
- * treat it as not found.
- */
- zp = (zone1 == NULL) ? &zone1 : &zone2;
- LOCK(&view->lock);
- if (view->zonetable != NULL) {
- result = dns_zt_find(view->zonetable, name, 0, NULL,
- zp);
- } else {
- result = ISC_R_NOTFOUND;
- }
- UNLOCK(&view->lock);
- INSIST(result == ISC_R_SUCCESS || result == ISC_R_NOTFOUND ||
- result == DNS_R_PARTIALMATCH);
-
- /* Treat a partial match as no match */
- if (result == DNS_R_PARTIALMATCH) {
- dns_zone_detach(zp);
- result = ISC_R_NOTFOUND;
- POST(result);
- }
-
+ result = dns_zt_find(view->zonetable, name, DNS_ZTFIND_EXACT,
+ (zone1 == NULL) ? &zone1 : &zone2);
+ INSIST(result == ISC_R_SUCCESS || result == ISC_R_NOTFOUND);
if (zone2 != NULL) {
dns_zone_detach(&zone1);
dns_zone_detach(&zone2);
isc_result_t
dns_view_load(dns_view_t *view, bool stop, bool newonly) {
REQUIRE(DNS_VIEW_VALID(view));
- REQUIRE(view->zonetable != NULL);
-
return (dns_zt_load(view->zonetable, stop, newonly));
}
isc_result_t
-dns_view_asyncload(dns_view_t *view, bool newonly, dns_zt_allloaded_t callback,
+dns_view_asyncload(dns_view_t *view, bool newonly, dns_zt_callback_t *callback,
void *arg) {
REQUIRE(DNS_VIEW_VALID(view));
- REQUIRE(view->zonetable != NULL);
-
return (dns_zt_asyncload(view->zonetable, newonly, callback, arg));
}
struct dns_asyncload {
dns_zone_t *zone;
unsigned int flags;
- dns_zt_zoneloaded_t loaded;
+ dns_zt_callback_t *loaded;
void *loaded_arg;
};
/* Inform the zone table we've finished loading */
if (asl->loaded != NULL) {
- (asl->loaded)(asl->loaded_arg, zone);
+ asl->loaded(asl->loaded_arg);
}
isc_mem_put(zone->mctx, asl, sizeof(*asl));
}
isc_result_t
-dns_zone_asyncload(dns_zone_t *zone, bool newonly, dns_zt_zoneloaded_t done,
+dns_zone_asyncload(dns_zone_t *zone, bool newonly, dns_zt_callback_t *done,
void *arg) {
dns_asyncload_t *asl = NULL;
* This zone is unmanaged; we're probably running in
* named-checkzone or a unit test. There's no loop, so we
* need to free it immediately.
- *
- * Unmanaged zones must not have null views; we have no way
- * of detaching from the view here without causing deadlock
- * because this code is called with the view already
- * locked.
*/
- INSIST(isc_tid() == ISC_TID_UNKNOWN);
- INSIST(zone->view == NULL);
-
zone_shutdown(zone);
} else {
/*
#include <isc/mem.h>
#include <isc/result.h>
#include <isc/string.h>
+#include <isc/tid.h>
#include <isc/util.h>
#include <dns/log.h>
#include <dns/name.h>
-#include <dns/rbt.h>
+#include <dns/qp.h>
#include <dns/rdataclass.h>
#include <dns/view.h>
#include <dns/zone.h>
#include <dns/zt.h>
-struct zt_load_params {
- dns_zt_zoneloaded_t dl;
- bool newonly;
-};
+#define ZTMAGIC ISC_MAGIC('Z', 'T', 'b', 'l')
+#define VALID_ZT(zt) ISC_MAGIC_VALID(zt, ZTMAGIC)
struct dns_zt {
- /* Unlocked. */
unsigned int magic;
isc_mem_t *mctx;
- dns_rdataclass_t rdclass;
- isc_rwlock_t rwlock;
- dns_zt_allloaded_t loaddone;
- void *loaddone_arg;
- struct zt_load_params *loadparams;
+ dns_qpmulti_t *multi;
- /* Atomic */
atomic_bool flush;
isc_refcount_t references;
isc_refcount_t loads_pending;
+};
- /* Locked by lock. */
- dns_rbt_t *table;
+struct zt_load_params {
+ dns_zt_t *zt;
+ dns_zt_callback_t *loaddone;
+ void *loaddone_arg;
+ bool newonly;
};
struct zt_freeze_params {
bool freeze;
};
-#define ZTMAGIC ISC_MAGIC('Z', 'T', 'b', 'l')
-#define VALID_ZT(zt) ISC_MAGIC_VALID(zt, ZTMAGIC)
-
static void
-auto_detach(void *, void *);
+ztqpattach(void *uctx ISC_ATTR_UNUSED, void *pval,
+ uint32_t ival ISC_ATTR_UNUSED) {
+ dns_zone_t *zone = pval;
+ dns_zone_ref(zone);
+}
-static isc_result_t
-load(dns_zone_t *zone, void *uap);
+static void
+ztqpdetach(void *uctx ISC_ATTR_UNUSED, void *pval,
+ uint32_t ival ISC_ATTR_UNUSED) {
+ dns_zone_t *zone = pval;
+ dns_zone_detach(&zone);
+}
-static isc_result_t
-asyncload(dns_zone_t *zone, void *callback);
+static size_t
+ztqpmakekey(dns_qpkey_t key, void *uctx ISC_ATTR_UNUSED, void *pval,
+ uint32_t ival ISC_ATTR_UNUSED) {
+ dns_zone_t *zone = pval;
+ dns_name_t *name = dns_zone_getorigin(zone);
+ return (dns_qpkey_fromname(key, name));
+}
-static isc_result_t
-freezezones(dns_zone_t *zone, void *uap);
+static void
+ztqptriename(void *uctx, char *buf, size_t size) {
+ dns_view_t *view = uctx;
+ snprintf(buf, size, "view %s zone table", view->name);
+}
-static isc_result_t
-doneloading(dns_zt_t *zt, dns_zone_t *zone);
+static dns_qpmethods_t ztqpmethods = {
+ ztqpattach,
+ ztqpdetach,
+ ztqpmakekey,
+ ztqptriename,
+};
-isc_result_t
-dns_zt_create(isc_mem_t *mctx, dns_rdataclass_t rdclass, dns_zt_t **ztp) {
- dns_zt_t *zt;
- isc_result_t result;
+void
+dns_zt_create(isc_mem_t *mctx, isc_loopmgr_t *loopmgr, dns_view_t *view,
+ dns_zt_t **ztp) {
+ dns_qpmulti_t *multi = NULL;
+ dns_zt_t *zt = NULL;
REQUIRE(ztp != NULL && *ztp == NULL);
+ REQUIRE(view != NULL);
- zt = isc_mem_get(mctx, sizeof(*zt));
+ dns_qpmulti_create(mctx, loopmgr, &ztqpmethods, view, &multi);
- zt->table = NULL;
- result = dns_rbt_create(mctx, auto_detach, zt, &zt->table);
- if (result != ISC_R_SUCCESS) {
- goto cleanup_zt;
- }
+ zt = isc_mem_get(mctx, sizeof(*zt));
+ *zt = (dns_zt_t){
+ .magic = ZTMAGIC,
+ .multi = multi,
+ .references = 1,
+ };
- isc_rwlock_init(&zt->rwlock);
- zt->mctx = NULL;
isc_mem_attach(mctx, &zt->mctx);
- isc_refcount_init(&zt->references, 1);
- atomic_init(&zt->flush, false);
- zt->rdclass = rdclass;
- zt->magic = ZTMAGIC;
- zt->loaddone = NULL;
- zt->loaddone_arg = NULL;
- zt->loadparams = NULL;
- isc_refcount_init(&zt->loads_pending, 0);
+
*ztp = zt;
+}
- return (ISC_R_SUCCESS);
+/*
+ * XXXFANF it isn't clear whether this function will be useful. There
+ * is only one zone table per view, so it is probably enough to let
+ * the qp-trie auto-GC do its thing. However it might be problematic
+ * if a very large zone is replaced, and its database memory is
+ * retained for a long time.
+ */
+void
+dns_zt_compact(dns_zt_t *zt) {
+ dns_qp_t *qp = NULL;
-cleanup_zt:
- isc_mem_put(mctx, zt, sizeof(*zt));
+ REQUIRE(VALID_ZT(zt));
- return (result);
+ dns_qpmulti_write(zt->multi, &qp);
+ dns_qp_compact(qp, DNS_QPGC_ALL);
+ dns_qpmulti_commit(zt->multi, &qp);
}
isc_result_t
dns_zt_mount(dns_zt_t *zt, dns_zone_t *zone) {
isc_result_t result;
- dns_name_t *name = NULL;
+ dns_qp_t *qp = NULL;
REQUIRE(VALID_ZT(zt));
- name = dns_zone_getorigin(zone);
-
- RWLOCK(&zt->rwlock, isc_rwlocktype_write);
-
- result = dns_rbt_addname(zt->table, name, zone);
- if (result == ISC_R_SUCCESS) {
- dns_zone_ref(zone);
- }
-
- RWUNLOCK(&zt->rwlock, isc_rwlocktype_write);
+ dns_qpmulti_write(zt->multi, &qp);
+ result = dns_qp_insert(qp, zone, 0);
+ dns_qp_compact(qp, DNS_QPGC_MAYBE);
+ dns_qpmulti_commit(zt->multi, &qp);
return (result);
}
isc_result_t
dns_zt_unmount(dns_zt_t *zt, dns_zone_t *zone) {
isc_result_t result;
- dns_name_t *name;
+ dns_qp_t *qp = NULL;
REQUIRE(VALID_ZT(zt));
- name = dns_zone_getorigin(zone);
-
- RWLOCK(&zt->rwlock, isc_rwlocktype_write);
-
- result = dns_rbt_deletename(zt->table, name, false);
-
- RWUNLOCK(&zt->rwlock, isc_rwlocktype_write);
+ dns_qpmulti_write(zt->multi, &qp);
+ result = dns_qp_deletename(qp, dns_zone_getorigin(zone));
+ dns_qp_compact(qp, DNS_QPGC_MAYBE);
+ dns_qpmulti_commit(zt->multi, &qp);
return (result);
}
isc_result_t
-dns_zt_find(dns_zt_t *zt, const dns_name_t *name, unsigned int options,
- dns_name_t *foundname, dns_zone_t **zonep) {
+dns_zt_find(dns_zt_t *zt, const dns_name_t *name, dns_ztfind_t options,
+ dns_zone_t **zonep) {
isc_result_t result;
- dns_zone_t *dummy = NULL;
- unsigned int rbtoptions = 0;
+ dns_qpread_t qpr;
+ void *pval = NULL;
+ uint32_t ival;
+ dns_ztfind_t exactmask = DNS_ZTFIND_NOEXACT | DNS_ZTFIND_EXACT;
+ dns_ztfind_t exactopts = options & exactmask;
REQUIRE(VALID_ZT(zt));
+ REQUIRE(exactopts != exactmask);
- if ((options & DNS_ZTFIND_NOEXACT) != 0) {
- rbtoptions |= DNS_RBTFIND_NOEXACT;
+ if (isc_tid() == ISC_TID_UNKNOWN) {
+ dns_qpmulti_lockedread(zt->multi, &qpr);
+ } else {
+ dns_qpmulti_query(zt->multi, &qpr);
}
+ if (exactopts == DNS_ZTFIND_EXACT) {
+ result = dns_qp_getname(&qpr, name, &pval, &ival);
+ } else if (exactopts == DNS_ZTFIND_NOEXACT) {
+ result = dns_qp_findname_parent(&qpr, name, DNS_QPFIND_NOEXACT,
+ &pval, &ival);
+ } else {
+ result = dns_qp_findname_parent(&qpr, name, 0, &pval, &ival);
+ }
+ dns_qpread_destroy(zt->multi, &qpr);
- RWLOCK(&zt->rwlock, isc_rwlocktype_read);
-
- result = dns_rbt_findname(zt->table, name, rbtoptions, foundname,
- (void **)&dummy);
if (result == ISC_R_SUCCESS || result == DNS_R_PARTIALMATCH) {
+ dns_zone_t *zone = pval;
/*
* If DNS_ZTFIND_MIRROR is set and the zone which was
* determined to be the deepest match for the supplied name is
* arguably not worth the added complexity.
*/
if ((options & DNS_ZTFIND_MIRROR) != 0 &&
- dns_zone_gettype(dummy) == dns_zone_mirror &&
- !dns_zone_isloaded(dummy))
+ dns_zone_gettype(zone) == dns_zone_mirror &&
+ !dns_zone_isloaded(zone))
{
result = ISC_R_NOTFOUND;
} else {
- dns_zone_attach(dummy, zonep);
+ dns_zone_attach(zone, zonep);
}
}
- RWUNLOCK(&zt->rwlock, isc_rwlocktype_read);
-
return (result);
}
isc_refcount_destroy(&zt->loads_pending);
if (atomic_load_acquire(&zt->flush)) {
- (void)dns_zt_apply(zt, isc_rwlocktype_none, false, NULL, flush,
- NULL);
+ (void)dns_zt_apply(zt, false, NULL, flush, NULL);
}
- dns_rbt_destroy(&zt->table);
- isc_rwlock_destroy(&zt->rwlock);
+ dns_qpmulti_destroy(&zt->multi);
zt->magic = 0;
isc_mem_putanddetach(&zt->mctx, zt, sizeof(*zt));
}
atomic_store_release(&zt->flush, true);
}
-isc_result_t
-dns_zt_load(dns_zt_t *zt, bool stop, bool newonly) {
- isc_result_t result;
- struct zt_load_params params;
- REQUIRE(VALID_ZT(zt));
- params.newonly = newonly;
- result = dns_zt_apply(zt, isc_rwlocktype_read, stop, NULL, load,
- ¶ms);
- return (result);
-}
-
static isc_result_t
-load(dns_zone_t *zone, void *paramsv) {
+load(dns_zone_t *zone, void *uap) {
isc_result_t result;
- struct zt_load_params *params = (struct zt_load_params *)paramsv;
- result = dns_zone_load(zone, params->newonly);
+ result = dns_zone_load(zone, uap != NULL);
if (result == DNS_R_CONTINUE || result == DNS_R_UPTODATE ||
result == DNS_R_DYNAMIC)
{
return (result);
}
-static void
-call_loaddone(dns_zt_t *zt) {
- dns_zt_allloaded_t loaddone = zt->loaddone;
- void *loaddone_arg = zt->loaddone_arg;
-
- /*
- * Set zt->loaddone, zt->loaddone_arg and zt->loadparams to NULL
- * before calling loaddone.
- */
- zt->loaddone = NULL;
- zt->loaddone_arg = NULL;
-
- isc_mem_put(zt->mctx, zt->loadparams, sizeof(struct zt_load_params));
- zt->loadparams = NULL;
+isc_result_t
+dns_zt_load(dns_zt_t *zt, bool stop, bool newonly) {
+ REQUIRE(VALID_ZT(zt));
+ return (dns_zt_apply(zt, stop, NULL, load, newonly ? &newonly : NULL));
+}
- /*
- * Call the callback last.
- */
- if (loaddone != NULL) {
- loaddone(loaddone_arg);
+static void
+loaded_all(struct zt_load_params *params) {
+ if (params->loaddone != NULL) {
+ params->loaddone(params->loaddone_arg);
}
+ isc_mem_put(params->zt->mctx, params, sizeof(*params));
}
-isc_result_t
-dns_zt_asyncload(dns_zt_t *zt, bool newonly, dns_zt_allloaded_t alldone,
- void *arg) {
- isc_result_t result;
- uint_fast32_t loads_pending;
+/*
+ * Decrement the loads_pending counter; when counter reaches
+ * zero, call the loaddone callback that was initially set by
+ * dns_zt_asyncload().
+ */
+static isc_result_t
+loaded_one(void *uap) {
+ struct zt_load_params *params = uap;
+ dns_zt_t *zt = params->zt;
REQUIRE(VALID_ZT(zt));
- /*
- * Obtain a reference to zt->loads_pending so that asyncload can
- * safely decrement both zt->references and zt->loads_pending
- * without going to zero.
- */
- loads_pending = isc_refcount_increment0(&zt->loads_pending);
- INSIST(loads_pending == 0);
-
- /*
- * Only one dns_zt_asyncload call at a time should be active so
- * these pointers should be NULL. They are set back to NULL
- * before the zt->loaddone (alldone) is called in call_loaddone.
- */
- INSIST(zt->loadparams == NULL);
- INSIST(zt->loaddone == NULL);
- INSIST(zt->loaddone_arg == NULL);
-
- zt->loadparams = isc_mem_get(zt->mctx, sizeof(struct zt_load_params));
- zt->loadparams->dl = doneloading;
- zt->loadparams->newonly = newonly;
- zt->loaddone = alldone;
- zt->loaddone_arg = arg;
-
- result = dns_zt_apply(zt, isc_rwlocktype_read, false, NULL, asyncload,
- zt);
-
- /*
- * Have all the loads completed?
- */
if (isc_refcount_decrement(&zt->loads_pending) == 1) {
- call_loaddone(zt);
+ loaded_all(params);
}
- return (result);
+ if (isc_refcount_decrement(&zt->references) == 1) {
+ zt_destroy(zt);
+ }
+
+ return (ISC_R_SUCCESS);
}
/*
* the zone loading is complete.
*/
static isc_result_t
-asyncload(dns_zone_t *zone, void *zt_) {
+asyncload(dns_zone_t *zone, void *uap) {
+ struct zt_load_params *params = uap;
+ struct dns_zt *zt = params->zt;
isc_result_t result;
- struct dns_zt *zt = (dns_zt_t *)zt_;
+
+ REQUIRE(VALID_ZT(zt));
REQUIRE(zone != NULL);
isc_refcount_increment(&zt->references);
isc_refcount_increment(&zt->loads_pending);
- result = dns_zone_asyncload(zone, zt->loadparams->newonly,
- *zt->loadparams->dl, zt);
+ result = dns_zone_asyncload(zone, params->newonly, loaded_one, params);
if (result != ISC_R_SUCCESS) {
/*
* Caller is holding a reference to zt->loads_pending
}
isc_result_t
-dns_zt_freezezones(dns_zt_t *zt, dns_view_t *view, bool freeze) {
- isc_result_t result, tresult;
- struct zt_freeze_params params = { view, freeze };
+dns_zt_asyncload(dns_zt_t *zt, bool newonly, dns_zt_callback_t *loaddone,
+ void *arg) {
+ isc_result_t result;
+ uint_fast32_t loads_pending;
+ struct zt_load_params *params = NULL;
REQUIRE(VALID_ZT(zt));
- result = dns_zt_apply(zt, isc_rwlocktype_read, false, &tresult,
- freezezones, ¶ms);
- if (tresult == ISC_R_NOTFOUND) {
- tresult = ISC_R_SUCCESS;
+ /*
+ * Obtain a reference to zt->loads_pending so that asyncload can
+ * safely decrement both zt->references and zt->loads_pending
+ * without going to zero.
+ */
+ loads_pending = isc_refcount_increment0(&zt->loads_pending);
+ INSIST(loads_pending == 0);
+
+ params = isc_mem_get(zt->mctx, sizeof(*params));
+ *params = (struct zt_load_params){
+ .zt = zt,
+ .newonly = newonly,
+ .loaddone = loaddone,
+ .loaddone_arg = arg,
+ };
+
+ result = dns_zt_apply(zt, false, NULL, asyncload, params);
+
+ /*
+ * Have all the loads completed?
+ */
+ if (isc_refcount_decrement(&zt->loads_pending) == 1) {
+ loaded_all(params);
}
- return ((result == ISC_R_SUCCESS) ? tresult : result);
+
+ return (result);
}
static isc_result_t
}
}
view = dns_zone_getview(zone);
- if (strcmp(view->name, "_bind") == 0 || strcmp(view->name, "_defaul"
- "t") == 0)
+ if (strcmp(view->name, "_bind") == 0 ||
+ strcmp(view->name, "_default") == 0)
{
vname = "";
sep = "";
return (result);
}
-void
-dns_zt_setviewcommit(dns_zt_t *zt) {
- dns_rbtnode_t *node;
- dns_rbtnodechain_t chain;
- isc_result_t result;
+isc_result_t
+dns_zt_freezezones(dns_zt_t *zt, dns_view_t *view, bool freeze) {
+ isc_result_t result, tresult;
+ struct zt_freeze_params params = { view, freeze };
REQUIRE(VALID_ZT(zt));
- RWLOCK(&zt->rwlock, isc_rwlocktype_read);
- dns_rbtnodechain_init(&chain);
+ result = dns_zt_apply(zt, false, &tresult, freezezones, ¶ms);
+ if (tresult == ISC_R_NOTFOUND) {
+ tresult = ISC_R_SUCCESS;
+ }
+ return ((result == ISC_R_SUCCESS) ? tresult : result);
+}
- result = dns_rbtnodechain_first(&chain, zt->table, NULL, NULL);
- while (result == DNS_R_NEWORIGIN || result == ISC_R_SUCCESS) {
- result = dns_rbtnodechain_current(&chain, NULL, NULL, &node);
- if (result == ISC_R_SUCCESS && node->data != NULL) {
- dns_zone_setviewcommit(node->data);
- }
+typedef void
+setview_cb(dns_zone_t *zone);
- result = dns_rbtnodechain_next(&chain, NULL, NULL);
- }
+static isc_result_t
+setview(dns_zone_t *zone, void *arg) {
+ setview_cb *cb = arg;
+ cb(zone);
+ return (ISC_R_SUCCESS);
+}
- dns_rbtnodechain_invalidate(&chain);
- RWUNLOCK(&zt->rwlock, isc_rwlocktype_read);
+void
+dns_zt_setviewcommit(dns_zt_t *zt) {
+ dns_zt_apply(zt, false, NULL, setview, dns_zone_setviewcommit);
}
void
dns_zt_setviewrevert(dns_zt_t *zt) {
- dns_rbtnode_t *node;
- dns_rbtnodechain_t chain;
- isc_result_t result;
-
- REQUIRE(VALID_ZT(zt));
-
- dns_rbtnodechain_init(&chain);
-
- result = dns_rbtnodechain_first(&chain, zt->table, NULL, NULL);
- while (result == DNS_R_NEWORIGIN || result == ISC_R_SUCCESS) {
- result = dns_rbtnodechain_current(&chain, NULL, NULL, &node);
- if (result == ISC_R_SUCCESS && node->data != NULL) {
- dns_zone_setviewrevert(node->data);
- }
-
- result = dns_rbtnodechain_next(&chain, NULL, NULL);
- }
-
- dns_rbtnodechain_invalidate(&chain);
+ dns_zt_apply(zt, false, NULL, setview, dns_zone_setviewrevert);
}
isc_result_t
-dns_zt_apply(dns_zt_t *zt, isc_rwlocktype_t lock, bool stop, isc_result_t *sub,
+dns_zt_apply(dns_zt_t *zt, bool stop, isc_result_t *sub,
isc_result_t (*action)(dns_zone_t *, void *), void *uap) {
- dns_rbtnode_t *node;
- dns_rbtnodechain_t chain;
- isc_result_t result, tresult = ISC_R_SUCCESS;
- dns_zone_t *zone;
+ isc_result_t result = ISC_R_SUCCESS;
+ isc_result_t tresult = ISC_R_SUCCESS;
+ dns_qpiter_t qpi;
+ dns_qpread_t qpr;
+ void *zone = NULL;
+ uint32_t ival;
REQUIRE(VALID_ZT(zt));
REQUIRE(action != NULL);
- if (lock != isc_rwlocktype_none) {
- RWLOCK(&zt->rwlock, lock);
- }
+ dns_qpmulti_query(zt->multi, &qpr);
+ dns_qpiter_init(&qpr, &qpi);
- dns_rbtnodechain_init(&chain);
- result = dns_rbtnodechain_first(&chain, zt->table, NULL, NULL);
- if (result == ISC_R_NOTFOUND) {
- /*
- * The tree is empty.
- */
- tresult = result;
- result = ISC_R_NOMORE;
- }
- while (result == DNS_R_NEWORIGIN || result == ISC_R_SUCCESS) {
- result = dns_rbtnodechain_current(&chain, NULL, NULL, &node);
- if (result == ISC_R_SUCCESS) {
- zone = node->data;
- if (zone != NULL) {
- result = (action)(zone, uap);
- }
- if (result != ISC_R_SUCCESS && stop) {
- tresult = result;
- goto cleanup; /* don't break */
- } else if (result != ISC_R_SUCCESS &&
- tresult == ISC_R_SUCCESS)
- {
- tresult = result;
- }
+ while (dns_qpiter_next(&qpi, &zone, &ival) == ISC_R_SUCCESS) {
+ result = action(zone, uap);
+ if (tresult == ISC_R_SUCCESS) {
+ tresult = result;
+ }
+ if (result != ISC_R_SUCCESS && stop) {
+ break;
}
- result = dns_rbtnodechain_next(&chain, NULL, NULL);
- }
- if (result == ISC_R_NOMORE) {
- result = ISC_R_SUCCESS;
}
+ dns_qpread_destroy(zt->multi, &qpr);
-cleanup:
- dns_rbtnodechain_invalidate(&chain);
if (sub != NULL) {
*sub = tresult;
}
- if (lock != isc_rwlocktype_none) {
- RWUNLOCK(&zt->rwlock, lock);
- }
-
return (result);
}
-
-/*
- * Decrement the loads_pending counter; when counter reaches
- * zero, call the loaddone callback that was initially set by
- * dns_zt_asyncload().
- */
-static isc_result_t
-doneloading(dns_zt_t *zt, dns_zone_t *zone) {
- REQUIRE(VALID_ZT(zt));
-
- UNUSED(zone);
-
- if (isc_refcount_decrement(&zt->loads_pending) == 1) {
- call_loaddone(zt);
- }
-
- if (isc_refcount_decrement(&zt->references) == 1) {
- zt_destroy(zt);
- }
-
- return (ISC_R_SUCCESS);
-}
-
-/***
- *** Private
- ***/
-
-static void
-auto_detach(void *data, void *arg) {
- dns_zone_t *zone = data;
-
- UNUSED(arg);
- dns_zone_detach(&zone);
-}
}
dns_name_format(zonename, namebuf, sizeof(namebuf));
- result = dns_zt_find(client->view->zonetable, zonename, 0, NULL, &zone);
+ result = dns_view_findzone(client->view, zonename, &zone);
if (result == ISC_R_SUCCESS) {
dns_zonetype_t zonetype = dns_zone_gettype(zone);
}
}
- notify_log(client, ISC_LOG_NOTICE,
- "received notify for zone '%s'%s: not authoritative",
- namebuf, tsigbuf);
result = DNS_R_NOTAUTH;
+ notify_log(client, ISC_LOG_NOTICE,
+ "received notify for zone '%s'%s: %s", namebuf, tsigbuf,
+ isc_result_totext(result));
done:
if (zone != NULL) {
ztoptions |= DNS_ZTFIND_NOEXACT;
}
- result = dns_zt_find(client->view->zonetable, name, ztoptions, NULL,
- &zone);
+ result = dns_zt_find(client->view->zonetable, name, ztoptions, &zone);
if (result == DNS_R_PARTIALMATCH) {
partial = true;
"RRs");
}
- result = dns_zt_find(client->view->zonetable, zonename, 0, NULL, &zone);
+ result = dns_view_findzone(client->view, zonename, &zone);
if (result != ISC_R_SUCCESS) {
- /*
- * If we found a zone that is a parent of the update zonename,
- * detach it so it isn't mentioned in log - it is irrelevant.
- */
- if (zone != NULL) {
- dns_zone_detach(&zone);
- }
FAILN(DNS_R_NOTAUTH, zonename,
"not authoritative for update zone");
}
FAILC(DNS_R_FORMERR, "multiple questions");
}
- result = dns_zt_find(client->view->zonetable, question_name, 0, NULL,
- &zone);
-
+ result = dns_view_findzone(client->view, question_name, &zone);
if (result != ISC_R_SUCCESS || dns_zone_gettype(zone) == dns_zone_dlz) {
/*
* The normal zone table does not have a match, or this is
assert_non_null(view->zonetable);
assert_int_equal(nzones, 0);
- result = dns_zt_apply(view->zonetable, isc_rwlocktype_read, false, NULL,
- count_zone, &nzones);
+ result = dns_zt_apply(view->zonetable, false, NULL, count_zone,
+ &nzones);
assert_int_equal(result, ISC_R_SUCCESS);
assert_int_equal(nzones, 1);
}
static isc_result_t
-load_done_last(dns_zt_t *zt, dns_zone_t *zone) {
+load_done_last(void *uap) {
+ dns_zone_t *zone = uap;
isc_result_t result;
- UNUSED(zt);
- UNUSED(zone);
-
/* The zone should now be loaded; test it */
result = dns_zone_getdb(zone, &db);
assert_int_equal(result, ISC_R_SUCCESS);
}
static isc_result_t
-load_done_new_only(dns_zt_t *zt, dns_zone_t *zone) {
+load_done_new_only(void *uap) {
+ dns_zone_t *zone = uap;
isc_result_t result;
- UNUSED(zt);
- UNUSED(zone);
-
/* The zone should now be loaded; test it */
result = dns_zone_getdb(zone, &db);
assert_int_equal(result, ISC_R_SUCCESS);
dns_db_detach(&db);
- dns_zone_asyncload(zone, true, load_done_last, NULL);
+ dns_zone_asyncload(zone, true, load_done_last, zone);
return (ISC_R_SUCCESS);
}
static isc_result_t
-load_done_first(dns_zt_t *zt, dns_zone_t *zone) {
- atomic_bool *done = (atomic_bool *)zt;
+load_done_first(void *uap) {
+ dns_zone_t *zone = uap;
isc_result_t result;
- UNUSED(zone);
-
/* The zone should now be loaded; test it */
result = dns_zone_getdb(zone, &db);
assert_int_equal(result, ISC_R_SUCCESS);
fflush(zonefile);
fclose(zonefile);
- dns_zone_asyncload(zone, true, load_done_new_only, &done);
+ dns_zone_asyncload(zone, true, load_done_new_only, zone);
return (ISC_R_SUCCESS);
}
int n;
dns_zone_t *zone = NULL;
char buf[4096];
- atomic_bool done;
-
- atomic_init(&done, false);
result = dns_test_makezone("foo", &zone, NULL, true);
assert_int_equal(result, ISC_R_SUCCESS);
assert_non_null(view->zonetable);
assert_false(dns__zone_loadpending(zone));
- assert_false(atomic_load(&done));
zonefile = fopen("./zone.data", "wb");
assert_non_null(zonefile);
origfile = fopen(TESTS_DIR "/testdata/zt/zone1.db", "r+b");
dns_zone_setfile(zone, "./zone.data", dns_masterformat_text,
&dns_master_style_default);
- dns_zone_asyncload(zone, false, load_done_first, &done);
+ dns_zone_asyncload(zone, false, load_done_first, zone);
}
dns_zone_t *zone1 = NULL, *zone2 = NULL, *zone3 = NULL;
dns_view_t *view = NULL;
dns_cache_t *cache = NULL;
- result = dns_view_create(mctx, dns_rdataclass_in, name, &view);
+ result = dns_view_create(mctx, loopmgr, dns_rdataclass_in, name, &view);
if (result != ISC_R_SUCCESS) {
return (result);
}