Home | History | Annotate | Line # | Download | only in dns
      1  1.1  christos /*	$NetBSD: zt.c,v 1.1 2024/02/18 20:57:34 christos Exp $	*/
      2  1.1  christos 
      3  1.1  christos /*
      4  1.1  christos  * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
      5  1.1  christos  *
      6  1.1  christos  * SPDX-License-Identifier: MPL-2.0
      7  1.1  christos  *
      8  1.1  christos  * This Source Code Form is subject to the terms of the Mozilla Public
      9  1.1  christos  * License, v. 2.0. If a copy of the MPL was not distributed with this
     10  1.1  christos  * file, you can obtain one at https://mozilla.org/MPL/2.0/.
     11  1.1  christos  *
     12  1.1  christos  * See the COPYRIGHT file distributed with this work for additional
     13  1.1  christos  * information regarding copyright ownership.
     14  1.1  christos  */
     15  1.1  christos 
     16  1.1  christos /*! \file */
     17  1.1  christos 
     18  1.1  christos #include <inttypes.h>
     19  1.1  christos #include <stdbool.h>
     20  1.1  christos 
     21  1.1  christos #include <isc/atomic.h>
     22  1.1  christos #include <isc/file.h>
     23  1.1  christos #include <isc/magic.h>
     24  1.1  christos #include <isc/mem.h>
     25  1.1  christos #include <isc/string.h>
     26  1.1  christos #include <isc/task.h>
     27  1.1  christos #include <isc/util.h>
     28  1.1  christos 
     29  1.1  christos #include <dns/log.h>
     30  1.1  christos #include <dns/name.h>
     31  1.1  christos #include <dns/rbt.h>
     32  1.1  christos #include <dns/rdataclass.h>
     33  1.1  christos #include <dns/result.h>
     34  1.1  christos #include <dns/view.h>
     35  1.1  christos #include <dns/zone.h>
     36  1.1  christos #include <dns/zt.h>
     37  1.1  christos 
     38  1.1  christos struct zt_load_params {
     39  1.1  christos 	dns_zt_zoneloaded_t dl;
     40  1.1  christos 	bool newonly;
     41  1.1  christos };
     42  1.1  christos 
     43  1.1  christos struct dns_zt {
     44  1.1  christos 	/* Unlocked. */
     45  1.1  christos 	unsigned int magic;
     46  1.1  christos 	isc_mem_t *mctx;
     47  1.1  christos 	dns_rdataclass_t rdclass;
     48  1.1  christos 	isc_rwlock_t rwlock;
     49  1.1  christos 	dns_zt_allloaded_t loaddone;
     50  1.1  christos 	void *loaddone_arg;
     51  1.1  christos 	struct zt_load_params *loadparams;
     52  1.1  christos 
     53  1.1  christos 	/* Atomic */
     54  1.1  christos 	atomic_bool flush;
     55  1.1  christos 	isc_refcount_t references;
     56  1.1  christos 	isc_refcount_t loads_pending;
     57  1.1  christos 
     58  1.1  christos 	/* Locked by lock. */
     59  1.1  christos 	dns_rbt_t *table;
     60  1.1  christos };
     61  1.1  christos 
     62  1.1  christos struct zt_freeze_params {
     63  1.1  christos 	dns_view_t *view;
     64  1.1  christos 	bool freeze;
     65  1.1  christos };
     66  1.1  christos 
     67  1.1  christos #define ZTMAGIC	     ISC_MAGIC('Z', 'T', 'b', 'l')
     68  1.1  christos #define VALID_ZT(zt) ISC_MAGIC_VALID(zt, ZTMAGIC)
     69  1.1  christos 
     70  1.1  christos static void
     71  1.1  christos auto_detach(void *, void *);
     72  1.1  christos 
     73  1.1  christos static isc_result_t
     74  1.1  christos load(dns_zone_t *zone, void *uap);
     75  1.1  christos 
     76  1.1  christos static isc_result_t
     77  1.1  christos asyncload(dns_zone_t *zone, void *callback);
     78  1.1  christos 
     79  1.1  christos static isc_result_t
     80  1.1  christos freezezones(dns_zone_t *zone, void *uap);
     81  1.1  christos 
     82  1.1  christos static isc_result_t
     83  1.1  christos doneloading(dns_zt_t *zt, dns_zone_t *zone, isc_task_t *task);
     84  1.1  christos 
     85  1.1  christos isc_result_t
     86  1.1  christos dns_zt_create(isc_mem_t *mctx, dns_rdataclass_t rdclass, dns_zt_t **ztp) {
     87  1.1  christos 	dns_zt_t *zt;
     88  1.1  christos 	isc_result_t result;
     89  1.1  christos 
     90  1.1  christos 	REQUIRE(ztp != NULL && *ztp == NULL);
     91  1.1  christos 
     92  1.1  christos 	zt = isc_mem_get(mctx, sizeof(*zt));
     93  1.1  christos 
     94  1.1  christos 	zt->table = NULL;
     95  1.1  christos 	result = dns_rbt_create(mctx, auto_detach, zt, &zt->table);
     96  1.1  christos 	if (result != ISC_R_SUCCESS) {
     97  1.1  christos 		goto cleanup_zt;
     98  1.1  christos 	}
     99  1.1  christos 
    100  1.1  christos 	isc_rwlock_init(&zt->rwlock, 0, 0);
    101  1.1  christos 	zt->mctx = NULL;
    102  1.1  christos 	isc_mem_attach(mctx, &zt->mctx);
    103  1.1  christos 	isc_refcount_init(&zt->references, 1);
    104  1.1  christos 	atomic_init(&zt->flush, false);
    105  1.1  christos 	zt->rdclass = rdclass;
    106  1.1  christos 	zt->magic = ZTMAGIC;
    107  1.1  christos 	zt->loaddone = NULL;
    108  1.1  christos 	zt->loaddone_arg = NULL;
    109  1.1  christos 	zt->loadparams = NULL;
    110  1.1  christos 	isc_refcount_init(&zt->loads_pending, 0);
    111  1.1  christos 	*ztp = zt;
    112  1.1  christos 
    113  1.1  christos 	return (ISC_R_SUCCESS);
    114  1.1  christos 
    115  1.1  christos cleanup_zt:
    116  1.1  christos 	isc_mem_put(mctx, zt, sizeof(*zt));
    117  1.1  christos 
    118  1.1  christos 	return (result);
    119  1.1  christos }
    120  1.1  christos 
    121  1.1  christos isc_result_t
    122  1.1  christos dns_zt_mount(dns_zt_t *zt, dns_zone_t *zone) {
    123  1.1  christos 	isc_result_t result;
    124  1.1  christos 	dns_zone_t *dummy = NULL;
    125  1.1  christos 	dns_name_t *name;
    126  1.1  christos 
    127  1.1  christos 	REQUIRE(VALID_ZT(zt));
    128  1.1  christos 
    129  1.1  christos 	name = dns_zone_getorigin(zone);
    130  1.1  christos 
    131  1.1  christos 	RWLOCK(&zt->rwlock, isc_rwlocktype_write);
    132  1.1  christos 
    133  1.1  christos 	result = dns_rbt_addname(zt->table, name, zone);
    134  1.1  christos 	if (result == ISC_R_SUCCESS) {
    135  1.1  christos 		dns_zone_attach(zone, &dummy);
    136  1.1  christos 	}
    137  1.1  christos 
    138  1.1  christos 	RWUNLOCK(&zt->rwlock, isc_rwlocktype_write);
    139  1.1  christos 
    140  1.1  christos 	return (result);
    141  1.1  christos }
    142  1.1  christos 
    143  1.1  christos isc_result_t
    144  1.1  christos dns_zt_unmount(dns_zt_t *zt, dns_zone_t *zone) {
    145  1.1  christos 	isc_result_t result;
    146  1.1  christos 	dns_name_t *name;
    147  1.1  christos 
    148  1.1  christos 	REQUIRE(VALID_ZT(zt));
    149  1.1  christos 
    150  1.1  christos 	name = dns_zone_getorigin(zone);
    151  1.1  christos 
    152  1.1  christos 	RWLOCK(&zt->rwlock, isc_rwlocktype_write);
    153  1.1  christos 
    154  1.1  christos 	result = dns_rbt_deletename(zt->table, name, false);
    155  1.1  christos 
    156  1.1  christos 	RWUNLOCK(&zt->rwlock, isc_rwlocktype_write);
    157  1.1  christos 
    158  1.1  christos 	return (result);
    159  1.1  christos }
    160  1.1  christos 
    161  1.1  christos isc_result_t
    162  1.1  christos dns_zt_find(dns_zt_t *zt, const dns_name_t *name, unsigned int options,
    163  1.1  christos 	    dns_name_t *foundname, dns_zone_t **zonep) {
    164  1.1  christos 	isc_result_t result;
    165  1.1  christos 	dns_zone_t *dummy = NULL;
    166  1.1  christos 	unsigned int rbtoptions = 0;
    167  1.1  christos 
    168  1.1  christos 	REQUIRE(VALID_ZT(zt));
    169  1.1  christos 
    170  1.1  christos 	if ((options & DNS_ZTFIND_NOEXACT) != 0) {
    171  1.1  christos 		rbtoptions |= DNS_RBTFIND_NOEXACT;
    172  1.1  christos 	}
    173  1.1  christos 
    174  1.1  christos 	RWLOCK(&zt->rwlock, isc_rwlocktype_read);
    175  1.1  christos 
    176  1.1  christos 	result = dns_rbt_findname(zt->table, name, rbtoptions, foundname,
    177  1.1  christos 				  (void **)(void *)&dummy);
    178  1.1  christos 	if (result == ISC_R_SUCCESS || result == DNS_R_PARTIALMATCH) {
    179  1.1  christos 		/*
    180  1.1  christos 		 * If DNS_ZTFIND_MIRROR is set and the zone which was
    181  1.1  christos 		 * determined to be the deepest match for the supplied name is
    182  1.1  christos 		 * a mirror zone which is expired or not yet loaded, treat it
    183  1.1  christos 		 * as non-existent.  This will trigger a fallback to recursion
    184  1.1  christos 		 * instead of returning a SERVFAIL.
    185  1.1  christos 		 *
    186  1.1  christos 		 * Note that currently only the deepest match in the zone table
    187  1.1  christos 		 * is checked.  Consider a server configured with two mirror
    188  1.1  christos 		 * zones: "bar" and its child, "foo.bar".  If zone data is
    189  1.1  christos 		 * available for "bar" but not for "foo.bar", a query with
    190  1.1  christos 		 * QNAME equal to or below "foo.bar" will cause ISC_R_NOTFOUND
    191  1.1  christos 		 * to be returned, not DNS_R_PARTIALMATCH, despite zone data
    192  1.1  christos 		 * being available for "bar".  This is considered to be an edge
    193  1.1  christos 		 * case, handling which more appropriately is possible, but
    194  1.1  christos 		 * arguably not worth the added complexity.
    195  1.1  christos 		 */
    196  1.1  christos 		if ((options & DNS_ZTFIND_MIRROR) != 0 &&
    197  1.1  christos 		    dns_zone_gettype(dummy) == dns_zone_mirror &&
    198  1.1  christos 		    !dns_zone_isloaded(dummy))
    199  1.1  christos 		{
    200  1.1  christos 			result = ISC_R_NOTFOUND;
    201  1.1  christos 		} else {
    202  1.1  christos 			dns_zone_attach(dummy, zonep);
    203  1.1  christos 		}
    204  1.1  christos 	}
    205  1.1  christos 
    206  1.1  christos 	RWUNLOCK(&zt->rwlock, isc_rwlocktype_read);
    207  1.1  christos 
    208  1.1  christos 	return (result);
    209  1.1  christos }
    210  1.1  christos 
    211  1.1  christos void
    212  1.1  christos dns_zt_attach(dns_zt_t *zt, dns_zt_t **ztp) {
    213  1.1  christos 	REQUIRE(VALID_ZT(zt));
    214  1.1  christos 	REQUIRE(ztp != NULL && *ztp == NULL);
    215  1.1  christos 
    216  1.1  christos 	isc_refcount_increment(&zt->references);
    217  1.1  christos 
    218  1.1  christos 	*ztp = zt;
    219  1.1  christos }
    220  1.1  christos 
    221  1.1  christos static isc_result_t
    222  1.1  christos flush(dns_zone_t *zone, void *uap) {
    223  1.1  christos 	UNUSED(uap);
    224  1.1  christos 	return (dns_zone_flush(zone));
    225  1.1  christos }
    226  1.1  christos 
    227  1.1  christos static void
    228  1.1  christos zt_destroy(dns_zt_t *zt) {
    229  1.1  christos 	if (atomic_load_acquire(&zt->flush)) {
    230  1.1  christos 		(void)dns_zt_apply(zt, isc_rwlocktype_none, false, NULL, flush,
    231  1.1  christos 				   NULL);
    232  1.1  christos 	}
    233  1.1  christos 	dns_rbt_destroy(&zt->table);
    234  1.1  christos 	isc_rwlock_destroy(&zt->rwlock);
    235  1.1  christos 	zt->magic = 0;
    236  1.1  christos 	isc_mem_putanddetach(&zt->mctx, zt, sizeof(*zt));
    237  1.1  christos }
    238  1.1  christos 
    239  1.1  christos static void
    240  1.1  christos zt_flushanddetach(dns_zt_t **ztp, bool need_flush) {
    241  1.1  christos 	dns_zt_t *zt;
    242  1.1  christos 
    243  1.1  christos 	REQUIRE(ztp != NULL && VALID_ZT(*ztp));
    244  1.1  christos 
    245  1.1  christos 	zt = *ztp;
    246  1.1  christos 	*ztp = NULL;
    247  1.1  christos 
    248  1.1  christos 	if (need_flush) {
    249  1.1  christos 		atomic_store_release(&zt->flush, true);
    250  1.1  christos 	}
    251  1.1  christos 
    252  1.1  christos 	if (isc_refcount_decrement(&zt->references) == 1) {
    253  1.1  christos 		zt_destroy(zt);
    254  1.1  christos 	}
    255  1.1  christos }
    256  1.1  christos 
    257  1.1  christos void
    258  1.1  christos dns_zt_flushanddetach(dns_zt_t **ztp) {
    259  1.1  christos 	zt_flushanddetach(ztp, true);
    260  1.1  christos }
    261  1.1  christos 
    262  1.1  christos void
    263  1.1  christos dns_zt_detach(dns_zt_t **ztp) {
    264  1.1  christos 	zt_flushanddetach(ztp, false);
    265  1.1  christos }
    266  1.1  christos 
    267  1.1  christos isc_result_t
    268  1.1  christos dns_zt_load(dns_zt_t *zt, bool stop, bool newonly) {
    269  1.1  christos 	isc_result_t result;
    270  1.1  christos 	struct zt_load_params params;
    271  1.1  christos 	REQUIRE(VALID_ZT(zt));
    272  1.1  christos 	params.newonly = newonly;
    273  1.1  christos 	result = dns_zt_apply(zt, isc_rwlocktype_read, stop, NULL, load,
    274  1.1  christos 			      &params);
    275  1.1  christos 	return (result);
    276  1.1  christos }
    277  1.1  christos 
    278  1.1  christos static isc_result_t
    279  1.1  christos load(dns_zone_t *zone, void *paramsv) {
    280  1.1  christos 	isc_result_t result;
    281  1.1  christos 	struct zt_load_params *params = (struct zt_load_params *)paramsv;
    282  1.1  christos 	result = dns_zone_load(zone, params->newonly);
    283  1.1  christos 	if (result == DNS_R_CONTINUE || result == DNS_R_UPTODATE ||
    284  1.1  christos 	    result == DNS_R_DYNAMIC)
    285  1.1  christos 	{
    286  1.1  christos 		result = ISC_R_SUCCESS;
    287  1.1  christos 	}
    288  1.1  christos 	return (result);
    289  1.1  christos }
    290  1.1  christos 
    291  1.1  christos static void
    292  1.1  christos call_loaddone(dns_zt_t *zt) {
    293  1.1  christos 	dns_zt_allloaded_t loaddone = zt->loaddone;
    294  1.1  christos 	void *loaddone_arg = zt->loaddone_arg;
    295  1.1  christos 
    296  1.1  christos 	/*
    297  1.1  christos 	 * Set zt->loaddone, zt->loaddone_arg and zt->loadparams to NULL
    298  1.1  christos 	 * before calling loaddone.
    299  1.1  christos 	 */
    300  1.1  christos 	zt->loaddone = NULL;
    301  1.1  christos 	zt->loaddone_arg = NULL;
    302  1.1  christos 
    303  1.1  christos 	isc_mem_put(zt->mctx, zt->loadparams, sizeof(struct zt_load_params));
    304  1.1  christos 	zt->loadparams = NULL;
    305  1.1  christos 
    306  1.1  christos 	/*
    307  1.1  christos 	 * Call the callback last.
    308  1.1  christos 	 */
    309  1.1  christos 	if (loaddone != NULL) {
    310  1.1  christos 		loaddone(loaddone_arg);
    311  1.1  christos 	}
    312  1.1  christos }
    313  1.1  christos 
    314  1.1  christos isc_result_t
    315  1.1  christos dns_zt_asyncload(dns_zt_t *zt, bool newonly, dns_zt_allloaded_t alldone,
    316  1.1  christos 		 void *arg) {
    317  1.1  christos 	isc_result_t result;
    318  1.1  christos 	uint_fast32_t loads_pending;
    319  1.1  christos 
    320  1.1  christos 	REQUIRE(VALID_ZT(zt));
    321  1.1  christos 
    322  1.1  christos 	/*
    323  1.1  christos 	 * Obtain a reference to zt->loads_pending so that asyncload can
    324  1.1  christos 	 * safely decrement both zt->references and zt->loads_pending
    325  1.1  christos 	 * without going to zero.
    326  1.1  christos 	 */
    327  1.1  christos 	loads_pending = isc_refcount_increment0(&zt->loads_pending);
    328  1.1  christos 	INSIST(loads_pending == 0);
    329  1.1  christos 
    330  1.1  christos 	/*
    331  1.1  christos 	 * Only one dns_zt_asyncload call at a time should be active so
    332  1.1  christos 	 * these pointers should be NULL.  They are set back to NULL
    333  1.1  christos 	 * before the zt->loaddone (alldone) is called in call_loaddone.
    334  1.1  christos 	 */
    335  1.1  christos 	INSIST(zt->loadparams == NULL);
    336  1.1  christos 	INSIST(zt->loaddone == NULL);
    337  1.1  christos 	INSIST(zt->loaddone_arg == NULL);
    338  1.1  christos 
    339  1.1  christos 	zt->loadparams = isc_mem_get(zt->mctx, sizeof(struct zt_load_params));
    340  1.1  christos 	zt->loadparams->dl = doneloading;
    341  1.1  christos 	zt->loadparams->newonly = newonly;
    342  1.1  christos 	zt->loaddone = alldone;
    343  1.1  christos 	zt->loaddone_arg = arg;
    344  1.1  christos 
    345  1.1  christos 	result = dns_zt_apply(zt, isc_rwlocktype_read, false, NULL, asyncload,
    346  1.1  christos 			      zt);
    347  1.1  christos 
    348  1.1  christos 	/*
    349  1.1  christos 	 * Have all the loads completed?
    350  1.1  christos 	 */
    351  1.1  christos 	if (isc_refcount_decrement(&zt->loads_pending) == 1) {
    352  1.1  christos 		call_loaddone(zt);
    353  1.1  christos 	}
    354  1.1  christos 
    355  1.1  christos 	return (result);
    356  1.1  christos }
    357  1.1  christos 
    358  1.1  christos /*
    359  1.1  christos  * Initiates asynchronous loading of zone 'zone'.  'callback' is a
    360  1.1  christos  * pointer to a function which will be used to inform the caller when
    361  1.1  christos  * the zone loading is complete.
    362  1.1  christos  */
    363  1.1  christos static isc_result_t
    364  1.1  christos asyncload(dns_zone_t *zone, void *zt_) {
    365  1.1  christos 	isc_result_t result;
    366  1.1  christos 	struct dns_zt *zt = (dns_zt_t *)zt_;
    367  1.1  christos 	REQUIRE(zone != NULL);
    368  1.1  christos 
    369  1.1  christos 	isc_refcount_increment(&zt->references);
    370  1.1  christos 	isc_refcount_increment(&zt->loads_pending);
    371  1.1  christos 
    372  1.1  christos 	result = dns_zone_asyncload(zone, zt->loadparams->newonly,
    373  1.1  christos 				    *zt->loadparams->dl, zt);
    374  1.1  christos 	if (result != ISC_R_SUCCESS) {
    375  1.1  christos 		/*
    376  1.1  christos 		 * Caller is holding a reference to zt->loads_pending
    377  1.1  christos 		 * and zt->references so these can't decrement to zero.
    378  1.1  christos 		 */
    379  1.1  christos 		isc_refcount_decrement1(&zt->references);
    380  1.1  christos 		isc_refcount_decrement1(&zt->loads_pending);
    381  1.1  christos 	}
    382  1.1  christos 	return (ISC_R_SUCCESS);
    383  1.1  christos }
    384  1.1  christos 
    385  1.1  christos isc_result_t
    386  1.1  christos dns_zt_freezezones(dns_zt_t *zt, dns_view_t *view, bool freeze) {
    387  1.1  christos 	isc_result_t result, tresult;
    388  1.1  christos 	struct zt_freeze_params params = { view, freeze };
    389  1.1  christos 
    390  1.1  christos 	REQUIRE(VALID_ZT(zt));
    391  1.1  christos 
    392  1.1  christos 	result = dns_zt_apply(zt, isc_rwlocktype_read, false, &tresult,
    393  1.1  christos 			      freezezones, &params);
    394  1.1  christos 	if (tresult == ISC_R_NOTFOUND) {
    395  1.1  christos 		tresult = ISC_R_SUCCESS;
    396  1.1  christos 	}
    397  1.1  christos 	return ((result == ISC_R_SUCCESS) ? tresult : result);
    398  1.1  christos }
    399  1.1  christos 
    400  1.1  christos static isc_result_t
    401  1.1  christos freezezones(dns_zone_t *zone, void *uap) {
    402  1.1  christos 	struct zt_freeze_params *params = uap;
    403  1.1  christos 	bool frozen;
    404  1.1  christos 	isc_result_t result = ISC_R_SUCCESS;
    405  1.1  christos 	char classstr[DNS_RDATACLASS_FORMATSIZE];
    406  1.1  christos 	char zonename[DNS_NAME_FORMATSIZE];
    407  1.1  christos 	dns_zone_t *raw = NULL;
    408  1.1  christos 	dns_view_t *view;
    409  1.1  christos 	const char *vname;
    410  1.1  christos 	const char *sep;
    411  1.1  christos 	int level;
    412  1.1  christos 
    413  1.1  christos 	dns_zone_getraw(zone, &raw);
    414  1.1  christos 	if (raw != NULL) {
    415  1.1  christos 		zone = raw;
    416  1.1  christos 	}
    417  1.1  christos 	if (params->view != dns_zone_getview(zone)) {
    418  1.1  christos 		if (raw != NULL) {
    419  1.1  christos 			dns_zone_detach(&raw);
    420  1.1  christos 		}
    421  1.1  christos 		return (ISC_R_SUCCESS);
    422  1.1  christos 	}
    423  1.1  christos 	if (dns_zone_gettype(zone) != dns_zone_primary) {
    424  1.1  christos 		if (raw != NULL) {
    425  1.1  christos 			dns_zone_detach(&raw);
    426  1.1  christos 		}
    427  1.1  christos 		return (ISC_R_SUCCESS);
    428  1.1  christos 	}
    429  1.1  christos 	if (!dns_zone_isdynamic(zone, true)) {
    430  1.1  christos 		if (raw != NULL) {
    431  1.1  christos 			dns_zone_detach(&raw);
    432  1.1  christos 		}
    433  1.1  christos 		return (ISC_R_SUCCESS);
    434  1.1  christos 	}
    435  1.1  christos 
    436  1.1  christos 	frozen = dns_zone_getupdatedisabled(zone);
    437  1.1  christos 	if (params->freeze) {
    438  1.1  christos 		if (frozen) {
    439  1.1  christos 			result = DNS_R_FROZEN;
    440  1.1  christos 		}
    441  1.1  christos 		if (result == ISC_R_SUCCESS) {
    442  1.1  christos 			result = dns_zone_flush(zone);
    443  1.1  christos 		}
    444  1.1  christos 		if (result == ISC_R_SUCCESS) {
    445  1.1  christos 			dns_zone_setupdatedisabled(zone, params->freeze);
    446  1.1  christos 		}
    447  1.1  christos 	} else {
    448  1.1  christos 		if (frozen) {
    449  1.1  christos 			result = dns_zone_loadandthaw(zone);
    450  1.1  christos 			if (result == DNS_R_CONTINUE ||
    451  1.1  christos 			    result == DNS_R_UPTODATE)
    452  1.1  christos 			{
    453  1.1  christos 				result = ISC_R_SUCCESS;
    454  1.1  christos 			}
    455  1.1  christos 		}
    456  1.1  christos 	}
    457  1.1  christos 	view = dns_zone_getview(zone);
    458  1.1  christos 	if (strcmp(view->name, "_bind") == 0 || strcmp(view->name, "_defaul"
    459  1.1  christos 								   "t") == 0)
    460  1.1  christos 	{
    461  1.1  christos 		vname = "";
    462  1.1  christos 		sep = "";
    463  1.1  christos 	} else {
    464  1.1  christos 		vname = view->name;
    465  1.1  christos 		sep = " ";
    466  1.1  christos 	}
    467  1.1  christos 	dns_rdataclass_format(dns_zone_getclass(zone), classstr,
    468  1.1  christos 			      sizeof(classstr));
    469  1.1  christos 	dns_name_format(dns_zone_getorigin(zone), zonename, sizeof(zonename));
    470  1.1  christos 	level = (result != ISC_R_SUCCESS) ? ISC_LOG_ERROR : ISC_LOG_DEBUG(1);
    471  1.1  christos 	isc_log_write(dns_lctx, DNS_LOGCATEGORY_GENERAL, DNS_LOGMODULE_ZONE,
    472  1.1  christos 		      level, "%s zone '%s/%s'%s%s: %s",
    473  1.1  christos 		      params->freeze ? "freezing" : "thawing", zonename,
    474  1.1  christos 		      classstr, sep, vname, isc_result_totext(result));
    475  1.1  christos 	if (raw != NULL) {
    476  1.1  christos 		dns_zone_detach(&raw);
    477  1.1  christos 	}
    478  1.1  christos 	return (result);
    479  1.1  christos }
    480  1.1  christos 
    481  1.1  christos void
    482  1.1  christos dns_zt_setviewcommit(dns_zt_t *zt) {
    483  1.1  christos 	dns_rbtnode_t *node;
    484  1.1  christos 	dns_rbtnodechain_t chain;
    485  1.1  christos 	isc_result_t result;
    486  1.1  christos 
    487  1.1  christos 	REQUIRE(VALID_ZT(zt));
    488  1.1  christos 
    489  1.1  christos 	dns_rbtnodechain_init(&chain);
    490  1.1  christos 
    491  1.1  christos 	result = dns_rbtnodechain_first(&chain, zt->table, NULL, NULL);
    492  1.1  christos 	while (result == DNS_R_NEWORIGIN || result == ISC_R_SUCCESS) {
    493  1.1  christos 		result = dns_rbtnodechain_current(&chain, NULL, NULL, &node);
    494  1.1  christos 		if (result == ISC_R_SUCCESS && node->data != NULL) {
    495  1.1  christos 			dns_zone_setviewcommit(node->data);
    496  1.1  christos 		}
    497  1.1  christos 
    498  1.1  christos 		result = dns_rbtnodechain_next(&chain, NULL, NULL);
    499  1.1  christos 	}
    500  1.1  christos 
    501  1.1  christos 	dns_rbtnodechain_invalidate(&chain);
    502  1.1  christos }
    503  1.1  christos 
    504  1.1  christos void
    505  1.1  christos dns_zt_setviewrevert(dns_zt_t *zt) {
    506  1.1  christos 	dns_rbtnode_t *node;
    507  1.1  christos 	dns_rbtnodechain_t chain;
    508  1.1  christos 	isc_result_t result;
    509  1.1  christos 
    510  1.1  christos 	REQUIRE(VALID_ZT(zt));
    511  1.1  christos 
    512  1.1  christos 	dns_rbtnodechain_init(&chain);
    513  1.1  christos 
    514  1.1  christos 	result = dns_rbtnodechain_first(&chain, zt->table, NULL, NULL);
    515  1.1  christos 	while (result == DNS_R_NEWORIGIN || result == ISC_R_SUCCESS) {
    516  1.1  christos 		result = dns_rbtnodechain_current(&chain, NULL, NULL, &node);
    517  1.1  christos 		if (result == ISC_R_SUCCESS && node->data != NULL) {
    518  1.1  christos 			dns_zone_setviewrevert(node->data);
    519  1.1  christos 		}
    520  1.1  christos 
    521  1.1  christos 		result = dns_rbtnodechain_next(&chain, NULL, NULL);
    522  1.1  christos 	}
    523  1.1  christos 
    524  1.1  christos 	dns_rbtnodechain_invalidate(&chain);
    525  1.1  christos }
    526  1.1  christos 
    527  1.1  christos isc_result_t
    528  1.1  christos dns_zt_apply(dns_zt_t *zt, isc_rwlocktype_t lock, bool stop, isc_result_t *sub,
    529  1.1  christos 	     isc_result_t (*action)(dns_zone_t *, void *), void *uap) {
    530  1.1  christos 	dns_rbtnode_t *node;
    531  1.1  christos 	dns_rbtnodechain_t chain;
    532  1.1  christos 	isc_result_t result, tresult = ISC_R_SUCCESS;
    533  1.1  christos 	dns_zone_t *zone;
    534  1.1  christos 
    535  1.1  christos 	REQUIRE(VALID_ZT(zt));
    536  1.1  christos 	REQUIRE(action != NULL);
    537  1.1  christos 
    538  1.1  christos 	if (lock != isc_rwlocktype_none) {
    539  1.1  christos 		RWLOCK(&zt->rwlock, lock);
    540  1.1  christos 	}
    541  1.1  christos 
    542  1.1  christos 	dns_rbtnodechain_init(&chain);
    543  1.1  christos 	result = dns_rbtnodechain_first(&chain, zt->table, NULL, NULL);
    544  1.1  christos 	if (result == ISC_R_NOTFOUND) {
    545  1.1  christos 		/*
    546  1.1  christos 		 * The tree is empty.
    547  1.1  christos 		 */
    548  1.1  christos 		tresult = result;
    549  1.1  christos 		result = ISC_R_NOMORE;
    550  1.1  christos 	}
    551  1.1  christos 	while (result == DNS_R_NEWORIGIN || result == ISC_R_SUCCESS) {
    552  1.1  christos 		result = dns_rbtnodechain_current(&chain, NULL, NULL, &node);
    553  1.1  christos 		if (result == ISC_R_SUCCESS) {
    554  1.1  christos 			zone = node->data;
    555  1.1  christos 			if (zone != NULL) {
    556  1.1  christos 				result = (action)(zone, uap);
    557  1.1  christos 			}
    558  1.1  christos 			if (result != ISC_R_SUCCESS && stop) {
    559  1.1  christos 				tresult = result;
    560  1.1  christos 				goto cleanup; /* don't break */
    561  1.1  christos 			} else if (result != ISC_R_SUCCESS &&
    562  1.1  christos 				   tresult == ISC_R_SUCCESS)
    563  1.1  christos 			{
    564  1.1  christos 				tresult = result;
    565  1.1  christos 			}
    566  1.1  christos 		}
    567  1.1  christos 		result = dns_rbtnodechain_next(&chain, NULL, NULL);
    568  1.1  christos 	}
    569  1.1  christos 	if (result == ISC_R_NOMORE) {
    570  1.1  christos 		result = ISC_R_SUCCESS;
    571  1.1  christos 	}
    572  1.1  christos 
    573  1.1  christos cleanup:
    574  1.1  christos 	dns_rbtnodechain_invalidate(&chain);
    575  1.1  christos 	if (sub != NULL) {
    576  1.1  christos 		*sub = tresult;
    577  1.1  christos 	}
    578  1.1  christos 
    579  1.1  christos 	if (lock != isc_rwlocktype_none) {
    580  1.1  christos 		RWUNLOCK(&zt->rwlock, lock);
    581  1.1  christos 	}
    582  1.1  christos 
    583  1.1  christos 	return (result);
    584  1.1  christos }
    585  1.1  christos 
    586  1.1  christos /*
    587  1.1  christos  * Decrement the loads_pending counter; when counter reaches
    588  1.1  christos  * zero, call the loaddone callback that was initially set by
    589  1.1  christos  * dns_zt_asyncload().
    590  1.1  christos  */
    591  1.1  christos static isc_result_t
    592  1.1  christos doneloading(dns_zt_t *zt, dns_zone_t *zone, isc_task_t *task) {
    593  1.1  christos 	UNUSED(zone);
    594  1.1  christos 	UNUSED(task);
    595  1.1  christos 
    596  1.1  christos 	REQUIRE(VALID_ZT(zt));
    597  1.1  christos 
    598  1.1  christos 	if (isc_refcount_decrement(&zt->loads_pending) == 1) {
    599  1.1  christos 		call_loaddone(zt);
    600  1.1  christos 	}
    601  1.1  christos 
    602  1.1  christos 	if (isc_refcount_decrement(&zt->references) == 1) {
    603  1.1  christos 		zt_destroy(zt);
    604  1.1  christos 	}
    605  1.1  christos 
    606  1.1  christos 	return (ISC_R_SUCCESS);
    607  1.1  christos }
    608  1.1  christos 
    609  1.1  christos /***
    610  1.1  christos  *** Private
    611  1.1  christos  ***/
    612  1.1  christos 
    613  1.1  christos static void
    614  1.1  christos auto_detach(void *data, void *arg) {
    615  1.1  christos 	dns_zone_t *zone = data;
    616  1.1  christos 
    617  1.1  christos 	UNUSED(arg);
    618  1.1  christos 	dns_zone_detach(&zone);
    619  1.1  christos }
    620