xref: /minix3/external/bsd/bind/dist/lib/dns/zt.c (revision 00b67f09dd46474d133c95011a48590a8e8f94c7)
1*00b67f09SDavid van Moolenbroek /*	$NetBSD: zt.c,v 1.8 2015/07/08 17:28:59 christos Exp $	*/
2*00b67f09SDavid van Moolenbroek 
3*00b67f09SDavid van Moolenbroek /*
4*00b67f09SDavid van Moolenbroek  * Copyright (C) 2004-2007, 2011-2015  Internet Systems Consortium, Inc. ("ISC")
5*00b67f09SDavid van Moolenbroek  * Copyright (C) 1999-2002  Internet Software Consortium.
6*00b67f09SDavid van Moolenbroek  *
7*00b67f09SDavid van Moolenbroek  * Permission to use, copy, modify, and/or distribute this software for any
8*00b67f09SDavid van Moolenbroek  * purpose with or without fee is hereby granted, provided that the above
9*00b67f09SDavid van Moolenbroek  * copyright notice and this permission notice appear in all copies.
10*00b67f09SDavid van Moolenbroek  *
11*00b67f09SDavid van Moolenbroek  * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
12*00b67f09SDavid van Moolenbroek  * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
13*00b67f09SDavid van Moolenbroek  * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
14*00b67f09SDavid van Moolenbroek  * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
15*00b67f09SDavid van Moolenbroek  * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
16*00b67f09SDavid van Moolenbroek  * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
17*00b67f09SDavid van Moolenbroek  * PERFORMANCE OF THIS SOFTWARE.
18*00b67f09SDavid van Moolenbroek  */
19*00b67f09SDavid van Moolenbroek 
20*00b67f09SDavid van Moolenbroek /* Id */
21*00b67f09SDavid van Moolenbroek 
22*00b67f09SDavid van Moolenbroek /*! \file */
23*00b67f09SDavid van Moolenbroek 
24*00b67f09SDavid van Moolenbroek #include <config.h>
25*00b67f09SDavid van Moolenbroek 
26*00b67f09SDavid van Moolenbroek #include <isc/file.h>
27*00b67f09SDavid van Moolenbroek #include <isc/magic.h>
28*00b67f09SDavid van Moolenbroek #include <isc/mem.h>
29*00b67f09SDavid van Moolenbroek #include <isc/string.h>
30*00b67f09SDavid van Moolenbroek #include <isc/task.h>
31*00b67f09SDavid van Moolenbroek #include <isc/util.h>
32*00b67f09SDavid van Moolenbroek 
33*00b67f09SDavid van Moolenbroek #include <dns/log.h>
34*00b67f09SDavid van Moolenbroek #include <dns/name.h>
35*00b67f09SDavid van Moolenbroek #include <dns/rbt.h>
36*00b67f09SDavid van Moolenbroek #include <dns/rdataclass.h>
37*00b67f09SDavid van Moolenbroek #include <dns/result.h>
38*00b67f09SDavid van Moolenbroek #include <dns/view.h>
39*00b67f09SDavid van Moolenbroek #include <dns/zone.h>
40*00b67f09SDavid van Moolenbroek #include <dns/zt.h>
41*00b67f09SDavid van Moolenbroek 
42*00b67f09SDavid van Moolenbroek struct dns_zt {
43*00b67f09SDavid van Moolenbroek 	/* Unlocked. */
44*00b67f09SDavid van Moolenbroek 	unsigned int		magic;
45*00b67f09SDavid van Moolenbroek 	isc_mem_t		*mctx;
46*00b67f09SDavid van Moolenbroek 	dns_rdataclass_t	rdclass;
47*00b67f09SDavid van Moolenbroek 	isc_rwlock_t		rwlock;
48*00b67f09SDavid van Moolenbroek 	dns_zt_allloaded_t	loaddone;
49*00b67f09SDavid van Moolenbroek 	void *			loaddone_arg;
50*00b67f09SDavid van Moolenbroek 	/* Locked by lock. */
51*00b67f09SDavid van Moolenbroek 	isc_boolean_t		flush;
52*00b67f09SDavid van Moolenbroek 	isc_uint32_t		references;
53*00b67f09SDavid van Moolenbroek 	unsigned int		loads_pending;
54*00b67f09SDavid van Moolenbroek 	dns_rbt_t		*table;
55*00b67f09SDavid van Moolenbroek };
56*00b67f09SDavid van Moolenbroek 
57*00b67f09SDavid van Moolenbroek #define ZTMAGIC			ISC_MAGIC('Z', 'T', 'b', 'l')
58*00b67f09SDavid van Moolenbroek #define VALID_ZT(zt) 		ISC_MAGIC_VALID(zt, ZTMAGIC)
59*00b67f09SDavid van Moolenbroek 
60*00b67f09SDavid van Moolenbroek static void
61*00b67f09SDavid van Moolenbroek auto_detach(void *, void *);
62*00b67f09SDavid van Moolenbroek 
63*00b67f09SDavid van Moolenbroek static isc_result_t
64*00b67f09SDavid van Moolenbroek load(dns_zone_t *zone, void *uap);
65*00b67f09SDavid van Moolenbroek 
66*00b67f09SDavid van Moolenbroek static isc_result_t
67*00b67f09SDavid van Moolenbroek asyncload(dns_zone_t *zone, void *callback);
68*00b67f09SDavid van Moolenbroek 
69*00b67f09SDavid van Moolenbroek static isc_result_t
70*00b67f09SDavid van Moolenbroek loadnew(dns_zone_t *zone, void *uap);
71*00b67f09SDavid van Moolenbroek 
72*00b67f09SDavid van Moolenbroek static isc_result_t
73*00b67f09SDavid van Moolenbroek freezezones(dns_zone_t *zone, void *uap);
74*00b67f09SDavid van Moolenbroek 
75*00b67f09SDavid van Moolenbroek static isc_result_t
76*00b67f09SDavid van Moolenbroek doneloading(dns_zt_t *zt, dns_zone_t *zone, isc_task_t *task);
77*00b67f09SDavid van Moolenbroek 
78*00b67f09SDavid van Moolenbroek isc_result_t
dns_zt_create(isc_mem_t * mctx,dns_rdataclass_t rdclass,dns_zt_t ** ztp)79*00b67f09SDavid van Moolenbroek dns_zt_create(isc_mem_t *mctx, dns_rdataclass_t rdclass, dns_zt_t **ztp) {
80*00b67f09SDavid van Moolenbroek 	dns_zt_t *zt;
81*00b67f09SDavid van Moolenbroek 	isc_result_t result;
82*00b67f09SDavid van Moolenbroek 
83*00b67f09SDavid van Moolenbroek 	REQUIRE(ztp != NULL && *ztp == NULL);
84*00b67f09SDavid van Moolenbroek 
85*00b67f09SDavid van Moolenbroek 	zt = isc_mem_get(mctx, sizeof(*zt));
86*00b67f09SDavid van Moolenbroek 	if (zt == NULL)
87*00b67f09SDavid van Moolenbroek 		return (ISC_R_NOMEMORY);
88*00b67f09SDavid van Moolenbroek 
89*00b67f09SDavid van Moolenbroek 	zt->table = NULL;
90*00b67f09SDavid van Moolenbroek 	result = dns_rbt_create(mctx, auto_detach, zt, &zt->table);
91*00b67f09SDavid van Moolenbroek 	if (result != ISC_R_SUCCESS)
92*00b67f09SDavid van Moolenbroek 		goto cleanup_zt;
93*00b67f09SDavid van Moolenbroek 
94*00b67f09SDavid van Moolenbroek 	result = isc_rwlock_init(&zt->rwlock, 0, 0);
95*00b67f09SDavid van Moolenbroek 	if (result != ISC_R_SUCCESS)
96*00b67f09SDavid van Moolenbroek 		goto cleanup_rbt;
97*00b67f09SDavid van Moolenbroek 
98*00b67f09SDavid van Moolenbroek 	zt->mctx = NULL;
99*00b67f09SDavid van Moolenbroek 	isc_mem_attach(mctx, &zt->mctx);
100*00b67f09SDavid van Moolenbroek 	zt->references = 1;
101*00b67f09SDavid van Moolenbroek 	zt->flush = ISC_FALSE;
102*00b67f09SDavid van Moolenbroek 	zt->rdclass = rdclass;
103*00b67f09SDavid van Moolenbroek 	zt->magic = ZTMAGIC;
104*00b67f09SDavid van Moolenbroek 	zt->loaddone = NULL;
105*00b67f09SDavid van Moolenbroek 	zt->loaddone_arg = NULL;
106*00b67f09SDavid van Moolenbroek 	zt->loads_pending = 0;
107*00b67f09SDavid van Moolenbroek 	*ztp = zt;
108*00b67f09SDavid van Moolenbroek 
109*00b67f09SDavid van Moolenbroek 	return (ISC_R_SUCCESS);
110*00b67f09SDavid van Moolenbroek 
111*00b67f09SDavid van Moolenbroek    cleanup_rbt:
112*00b67f09SDavid van Moolenbroek 	dns_rbt_destroy(&zt->table);
113*00b67f09SDavid van Moolenbroek 
114*00b67f09SDavid van Moolenbroek    cleanup_zt:
115*00b67f09SDavid van Moolenbroek 	isc_mem_put(mctx, zt, sizeof(*zt));
116*00b67f09SDavid van Moolenbroek 
117*00b67f09SDavid van Moolenbroek 	return (result);
118*00b67f09SDavid van Moolenbroek }
119*00b67f09SDavid van Moolenbroek 
120*00b67f09SDavid van Moolenbroek isc_result_t
dns_zt_mount(dns_zt_t * zt,dns_zone_t * zone)121*00b67f09SDavid van Moolenbroek dns_zt_mount(dns_zt_t *zt, dns_zone_t *zone) {
122*00b67f09SDavid van Moolenbroek 	isc_result_t result;
123*00b67f09SDavid van Moolenbroek 	dns_zone_t *dummy = NULL;
124*00b67f09SDavid van Moolenbroek 	dns_name_t *name;
125*00b67f09SDavid van Moolenbroek 
126*00b67f09SDavid van Moolenbroek 	REQUIRE(VALID_ZT(zt));
127*00b67f09SDavid van Moolenbroek 
128*00b67f09SDavid van Moolenbroek 	name = dns_zone_getorigin(zone);
129*00b67f09SDavid van Moolenbroek 
130*00b67f09SDavid van Moolenbroek 	RWLOCK(&zt->rwlock, isc_rwlocktype_write);
131*00b67f09SDavid van Moolenbroek 
132*00b67f09SDavid van Moolenbroek 	result = dns_rbt_addname(zt->table, name, zone);
133*00b67f09SDavid van Moolenbroek 	if (result == ISC_R_SUCCESS)
134*00b67f09SDavid van Moolenbroek 		dns_zone_attach(zone, &dummy);
135*00b67f09SDavid van Moolenbroek 
136*00b67f09SDavid van Moolenbroek 	RWUNLOCK(&zt->rwlock, isc_rwlocktype_write);
137*00b67f09SDavid van Moolenbroek 
138*00b67f09SDavid van Moolenbroek 	return (result);
139*00b67f09SDavid van Moolenbroek }
140*00b67f09SDavid van Moolenbroek 
141*00b67f09SDavid van Moolenbroek isc_result_t
dns_zt_unmount(dns_zt_t * zt,dns_zone_t * zone)142*00b67f09SDavid van Moolenbroek dns_zt_unmount(dns_zt_t *zt, dns_zone_t *zone) {
143*00b67f09SDavid van Moolenbroek 	isc_result_t result;
144*00b67f09SDavid van Moolenbroek 	dns_name_t *name;
145*00b67f09SDavid van Moolenbroek 
146*00b67f09SDavid van Moolenbroek 	REQUIRE(VALID_ZT(zt));
147*00b67f09SDavid van Moolenbroek 
148*00b67f09SDavid van Moolenbroek 	name = dns_zone_getorigin(zone);
149*00b67f09SDavid van Moolenbroek 
150*00b67f09SDavid van Moolenbroek 	RWLOCK(&zt->rwlock, isc_rwlocktype_write);
151*00b67f09SDavid van Moolenbroek 
152*00b67f09SDavid van Moolenbroek 	result = dns_rbt_deletename(zt->table, name, ISC_FALSE);
153*00b67f09SDavid van Moolenbroek 
154*00b67f09SDavid van Moolenbroek 	RWUNLOCK(&zt->rwlock, isc_rwlocktype_write);
155*00b67f09SDavid van Moolenbroek 
156*00b67f09SDavid van Moolenbroek 	return (result);
157*00b67f09SDavid van Moolenbroek }
158*00b67f09SDavid van Moolenbroek 
159*00b67f09SDavid van Moolenbroek isc_result_t
dns_zt_find(dns_zt_t * zt,dns_name_t * name,unsigned int options,dns_name_t * foundname,dns_zone_t ** zonep)160*00b67f09SDavid van Moolenbroek dns_zt_find(dns_zt_t *zt, dns_name_t *name, unsigned int options,
161*00b67f09SDavid van Moolenbroek 	    dns_name_t *foundname, dns_zone_t **zonep)
162*00b67f09SDavid van Moolenbroek {
163*00b67f09SDavid van Moolenbroek 	isc_result_t result;
164*00b67f09SDavid van Moolenbroek 	dns_zone_t *dummy = NULL;
165*00b67f09SDavid van Moolenbroek 	unsigned int rbtoptions = 0;
166*00b67f09SDavid van Moolenbroek 
167*00b67f09SDavid van Moolenbroek 	REQUIRE(VALID_ZT(zt));
168*00b67f09SDavid van Moolenbroek 
169*00b67f09SDavid van Moolenbroek 	if ((options & DNS_ZTFIND_NOEXACT) != 0)
170*00b67f09SDavid van Moolenbroek 		rbtoptions |= DNS_RBTFIND_NOEXACT;
171*00b67f09SDavid van Moolenbroek 
172*00b67f09SDavid van Moolenbroek 	RWLOCK(&zt->rwlock, isc_rwlocktype_read);
173*00b67f09SDavid van Moolenbroek 
174*00b67f09SDavid van Moolenbroek 	result = dns_rbt_findname(zt->table, name, rbtoptions, foundname,
175*00b67f09SDavid van Moolenbroek 				  (void **) (void*)&dummy);
176*00b67f09SDavid van Moolenbroek 	if (result == ISC_R_SUCCESS || result == DNS_R_PARTIALMATCH)
177*00b67f09SDavid van Moolenbroek 		dns_zone_attach(dummy, zonep);
178*00b67f09SDavid van Moolenbroek 
179*00b67f09SDavid van Moolenbroek 	RWUNLOCK(&zt->rwlock, isc_rwlocktype_read);
180*00b67f09SDavid van Moolenbroek 
181*00b67f09SDavid van Moolenbroek 	return (result);
182*00b67f09SDavid van Moolenbroek }
183*00b67f09SDavid van Moolenbroek 
184*00b67f09SDavid van Moolenbroek void
dns_zt_attach(dns_zt_t * zt,dns_zt_t ** ztp)185*00b67f09SDavid van Moolenbroek dns_zt_attach(dns_zt_t *zt, dns_zt_t **ztp) {
186*00b67f09SDavid van Moolenbroek 
187*00b67f09SDavid van Moolenbroek 	REQUIRE(VALID_ZT(zt));
188*00b67f09SDavid van Moolenbroek 	REQUIRE(ztp != NULL && *ztp == NULL);
189*00b67f09SDavid van Moolenbroek 
190*00b67f09SDavid van Moolenbroek 	RWLOCK(&zt->rwlock, isc_rwlocktype_write);
191*00b67f09SDavid van Moolenbroek 
192*00b67f09SDavid van Moolenbroek 	INSIST(zt->references > 0);
193*00b67f09SDavid van Moolenbroek 	zt->references++;
194*00b67f09SDavid van Moolenbroek 	INSIST(zt->references != 0);
195*00b67f09SDavid van Moolenbroek 
196*00b67f09SDavid van Moolenbroek 	RWUNLOCK(&zt->rwlock, isc_rwlocktype_write);
197*00b67f09SDavid van Moolenbroek 
198*00b67f09SDavid van Moolenbroek 	*ztp = zt;
199*00b67f09SDavid van Moolenbroek }
200*00b67f09SDavid van Moolenbroek 
201*00b67f09SDavid van Moolenbroek static isc_result_t
flush(dns_zone_t * zone,void * uap)202*00b67f09SDavid van Moolenbroek flush(dns_zone_t *zone, void *uap) {
203*00b67f09SDavid van Moolenbroek 	UNUSED(uap);
204*00b67f09SDavid van Moolenbroek 	return (dns_zone_flush(zone));
205*00b67f09SDavid van Moolenbroek }
206*00b67f09SDavid van Moolenbroek 
207*00b67f09SDavid van Moolenbroek static void
zt_destroy(dns_zt_t * zt)208*00b67f09SDavid van Moolenbroek zt_destroy(dns_zt_t *zt) {
209*00b67f09SDavid van Moolenbroek 	if (zt->flush)
210*00b67f09SDavid van Moolenbroek 		(void)dns_zt_apply(zt, ISC_FALSE, flush, NULL);
211*00b67f09SDavid van Moolenbroek 	dns_rbt_destroy(&zt->table);
212*00b67f09SDavid van Moolenbroek 	isc_rwlock_destroy(&zt->rwlock);
213*00b67f09SDavid van Moolenbroek 	zt->magic = 0;
214*00b67f09SDavid van Moolenbroek 	isc_mem_putanddetach(&zt->mctx, zt, sizeof(*zt));
215*00b67f09SDavid van Moolenbroek }
216*00b67f09SDavid van Moolenbroek 
217*00b67f09SDavid van Moolenbroek static void
zt_flushanddetach(dns_zt_t ** ztp,isc_boolean_t need_flush)218*00b67f09SDavid van Moolenbroek zt_flushanddetach(dns_zt_t **ztp, isc_boolean_t need_flush) {
219*00b67f09SDavid van Moolenbroek 	isc_boolean_t destroy = ISC_FALSE;
220*00b67f09SDavid van Moolenbroek 	dns_zt_t *zt;
221*00b67f09SDavid van Moolenbroek 
222*00b67f09SDavid van Moolenbroek 	REQUIRE(ztp != NULL && VALID_ZT(*ztp));
223*00b67f09SDavid van Moolenbroek 
224*00b67f09SDavid van Moolenbroek 	zt = *ztp;
225*00b67f09SDavid van Moolenbroek 
226*00b67f09SDavid van Moolenbroek 	RWLOCK(&zt->rwlock, isc_rwlocktype_write);
227*00b67f09SDavid van Moolenbroek 
228*00b67f09SDavid van Moolenbroek 	INSIST(zt->references > 0);
229*00b67f09SDavid van Moolenbroek 	zt->references--;
230*00b67f09SDavid van Moolenbroek 	if (zt->references == 0)
231*00b67f09SDavid van Moolenbroek 		destroy = ISC_TRUE;
232*00b67f09SDavid van Moolenbroek 	if (need_flush)
233*00b67f09SDavid van Moolenbroek 		zt->flush = ISC_TRUE;
234*00b67f09SDavid van Moolenbroek 
235*00b67f09SDavid van Moolenbroek 	RWUNLOCK(&zt->rwlock, isc_rwlocktype_write);
236*00b67f09SDavid van Moolenbroek 
237*00b67f09SDavid van Moolenbroek 	if (destroy)
238*00b67f09SDavid van Moolenbroek 		zt_destroy(zt);
239*00b67f09SDavid van Moolenbroek 
240*00b67f09SDavid van Moolenbroek 	*ztp = NULL;
241*00b67f09SDavid van Moolenbroek }
242*00b67f09SDavid van Moolenbroek 
243*00b67f09SDavid van Moolenbroek void
dns_zt_flushanddetach(dns_zt_t ** ztp)244*00b67f09SDavid van Moolenbroek dns_zt_flushanddetach(dns_zt_t **ztp) {
245*00b67f09SDavid van Moolenbroek 	zt_flushanddetach(ztp, ISC_TRUE);
246*00b67f09SDavid van Moolenbroek }
247*00b67f09SDavid van Moolenbroek 
248*00b67f09SDavid van Moolenbroek void
dns_zt_detach(dns_zt_t ** ztp)249*00b67f09SDavid van Moolenbroek dns_zt_detach(dns_zt_t **ztp) {
250*00b67f09SDavid van Moolenbroek 	zt_flushanddetach(ztp, ISC_FALSE);
251*00b67f09SDavid van Moolenbroek }
252*00b67f09SDavid van Moolenbroek 
253*00b67f09SDavid van Moolenbroek isc_result_t
dns_zt_load(dns_zt_t * zt,isc_boolean_t stop)254*00b67f09SDavid van Moolenbroek dns_zt_load(dns_zt_t *zt, isc_boolean_t stop) {
255*00b67f09SDavid van Moolenbroek 	isc_result_t result;
256*00b67f09SDavid van Moolenbroek 
257*00b67f09SDavid van Moolenbroek 	REQUIRE(VALID_ZT(zt));
258*00b67f09SDavid van Moolenbroek 
259*00b67f09SDavid van Moolenbroek 	RWLOCK(&zt->rwlock, isc_rwlocktype_read);
260*00b67f09SDavid van Moolenbroek 	result = dns_zt_apply(zt, stop, load, NULL);
261*00b67f09SDavid van Moolenbroek 	RWUNLOCK(&zt->rwlock, isc_rwlocktype_read);
262*00b67f09SDavid van Moolenbroek 	return (result);
263*00b67f09SDavid van Moolenbroek }
264*00b67f09SDavid van Moolenbroek 
265*00b67f09SDavid van Moolenbroek static isc_result_t
load(dns_zone_t * zone,void * uap)266*00b67f09SDavid van Moolenbroek load(dns_zone_t *zone, void *uap) {
267*00b67f09SDavid van Moolenbroek 	isc_result_t result;
268*00b67f09SDavid van Moolenbroek 	UNUSED(uap);
269*00b67f09SDavid van Moolenbroek 
270*00b67f09SDavid van Moolenbroek 	result = dns_zone_load(zone);
271*00b67f09SDavid van Moolenbroek 	if (result == DNS_R_CONTINUE || result == DNS_R_UPTODATE)
272*00b67f09SDavid van Moolenbroek 		result = ISC_R_SUCCESS;
273*00b67f09SDavid van Moolenbroek 
274*00b67f09SDavid van Moolenbroek 	return (result);
275*00b67f09SDavid van Moolenbroek }
276*00b67f09SDavid van Moolenbroek 
277*00b67f09SDavid van Moolenbroek isc_result_t
dns_zt_asyncload(dns_zt_t * zt,dns_zt_allloaded_t alldone,void * arg)278*00b67f09SDavid van Moolenbroek dns_zt_asyncload(dns_zt_t *zt, dns_zt_allloaded_t alldone, void *arg) {
279*00b67f09SDavid van Moolenbroek 	isc_result_t result;
280*00b67f09SDavid van Moolenbroek 	static dns_zt_zoneloaded_t dl = doneloading;
281*00b67f09SDavid van Moolenbroek 	int pending;
282*00b67f09SDavid van Moolenbroek 
283*00b67f09SDavid van Moolenbroek 	REQUIRE(VALID_ZT(zt));
284*00b67f09SDavid van Moolenbroek 
285*00b67f09SDavid van Moolenbroek 	RWLOCK(&zt->rwlock, isc_rwlocktype_write);
286*00b67f09SDavid van Moolenbroek 
287*00b67f09SDavid van Moolenbroek 	INSIST(zt->loads_pending == 0);
288*00b67f09SDavid van Moolenbroek 	result = dns_zt_apply2(zt, ISC_FALSE, NULL, asyncload, &dl);
289*00b67f09SDavid van Moolenbroek 
290*00b67f09SDavid van Moolenbroek 	pending = zt->loads_pending;
291*00b67f09SDavid van Moolenbroek 	if (pending != 0) {
292*00b67f09SDavid van Moolenbroek 		zt->loaddone = alldone;
293*00b67f09SDavid van Moolenbroek 		zt->loaddone_arg = arg;
294*00b67f09SDavid van Moolenbroek 	}
295*00b67f09SDavid van Moolenbroek 
296*00b67f09SDavid van Moolenbroek 	RWUNLOCK(&zt->rwlock, isc_rwlocktype_write);
297*00b67f09SDavid van Moolenbroek 
298*00b67f09SDavid van Moolenbroek 	if (pending == 0)
299*00b67f09SDavid van Moolenbroek 		alldone(arg);
300*00b67f09SDavid van Moolenbroek 
301*00b67f09SDavid van Moolenbroek 	return (result);
302*00b67f09SDavid van Moolenbroek }
303*00b67f09SDavid van Moolenbroek 
304*00b67f09SDavid van Moolenbroek /*
305*00b67f09SDavid van Moolenbroek  * Initiates asynchronous loading of zone 'zone'.  'callback' is a
306*00b67f09SDavid van Moolenbroek  * pointer to a function which will be used to inform the caller when
307*00b67f09SDavid van Moolenbroek  * the zone loading is complete.
308*00b67f09SDavid van Moolenbroek  */
309*00b67f09SDavid van Moolenbroek static isc_result_t
asyncload(dns_zone_t * zone,void * callback)310*00b67f09SDavid van Moolenbroek asyncload(dns_zone_t *zone, void *callback) {
311*00b67f09SDavid van Moolenbroek 	isc_result_t result;
312*00b67f09SDavid van Moolenbroek 	dns_zt_zoneloaded_t *loaded = callback;
313*00b67f09SDavid van Moolenbroek 	dns_zt_t *zt;
314*00b67f09SDavid van Moolenbroek 
315*00b67f09SDavid van Moolenbroek 	REQUIRE(zone != NULL);
316*00b67f09SDavid van Moolenbroek 	zt = dns_zone_getview(zone)->zonetable;
317*00b67f09SDavid van Moolenbroek 	INSIST(VALID_ZT(zt));
318*00b67f09SDavid van Moolenbroek 
319*00b67f09SDavid van Moolenbroek 	INSIST(zt->references > 0);
320*00b67f09SDavid van Moolenbroek 	zt->references++;
321*00b67f09SDavid van Moolenbroek 	zt->loads_pending++;
322*00b67f09SDavid van Moolenbroek 
323*00b67f09SDavid van Moolenbroek 	result = dns_zone_asyncload(zone, *loaded, zt);
324*00b67f09SDavid van Moolenbroek 	if (result != ISC_R_SUCCESS) {
325*00b67f09SDavid van Moolenbroek 		zt->references--;
326*00b67f09SDavid van Moolenbroek 		zt->loads_pending--;
327*00b67f09SDavid van Moolenbroek 		INSIST(zt->references > 0);
328*00b67f09SDavid van Moolenbroek 	}
329*00b67f09SDavid van Moolenbroek 	return (ISC_R_SUCCESS);
330*00b67f09SDavid van Moolenbroek }
331*00b67f09SDavid van Moolenbroek 
332*00b67f09SDavid van Moolenbroek isc_result_t
dns_zt_loadnew(dns_zt_t * zt,isc_boolean_t stop)333*00b67f09SDavid van Moolenbroek dns_zt_loadnew(dns_zt_t *zt, isc_boolean_t stop) {
334*00b67f09SDavid van Moolenbroek 	isc_result_t result;
335*00b67f09SDavid van Moolenbroek 
336*00b67f09SDavid van Moolenbroek 	REQUIRE(VALID_ZT(zt));
337*00b67f09SDavid van Moolenbroek 
338*00b67f09SDavid van Moolenbroek 	RWLOCK(&zt->rwlock, isc_rwlocktype_read);
339*00b67f09SDavid van Moolenbroek 	result = dns_zt_apply(zt, stop, loadnew, NULL);
340*00b67f09SDavid van Moolenbroek 	RWUNLOCK(&zt->rwlock, isc_rwlocktype_read);
341*00b67f09SDavid van Moolenbroek 	return (result);
342*00b67f09SDavid van Moolenbroek }
343*00b67f09SDavid van Moolenbroek 
344*00b67f09SDavid van Moolenbroek static isc_result_t
loadnew(dns_zone_t * zone,void * uap)345*00b67f09SDavid van Moolenbroek loadnew(dns_zone_t *zone, void *uap) {
346*00b67f09SDavid van Moolenbroek 	isc_result_t result;
347*00b67f09SDavid van Moolenbroek 	UNUSED(uap);
348*00b67f09SDavid van Moolenbroek 
349*00b67f09SDavid van Moolenbroek 	result = dns_zone_loadnew(zone);
350*00b67f09SDavid van Moolenbroek 	if (result == DNS_R_CONTINUE || result == DNS_R_UPTODATE ||
351*00b67f09SDavid van Moolenbroek 	    result == DNS_R_DYNAMIC)
352*00b67f09SDavid van Moolenbroek 		result = ISC_R_SUCCESS;
353*00b67f09SDavid van Moolenbroek 	return (result);
354*00b67f09SDavid van Moolenbroek }
355*00b67f09SDavid van Moolenbroek 
356*00b67f09SDavid van Moolenbroek isc_result_t
dns_zt_freezezones(dns_zt_t * zt,isc_boolean_t freeze)357*00b67f09SDavid van Moolenbroek dns_zt_freezezones(dns_zt_t *zt, isc_boolean_t freeze) {
358*00b67f09SDavid van Moolenbroek 	isc_result_t result, tresult;
359*00b67f09SDavid van Moolenbroek 
360*00b67f09SDavid van Moolenbroek 	REQUIRE(VALID_ZT(zt));
361*00b67f09SDavid van Moolenbroek 
362*00b67f09SDavid van Moolenbroek 	RWLOCK(&zt->rwlock, isc_rwlocktype_read);
363*00b67f09SDavid van Moolenbroek 	result = dns_zt_apply2(zt, ISC_FALSE, &tresult, freezezones, &freeze);
364*00b67f09SDavid van Moolenbroek 	RWUNLOCK(&zt->rwlock, isc_rwlocktype_read);
365*00b67f09SDavid van Moolenbroek 	if (tresult == ISC_R_NOTFOUND)
366*00b67f09SDavid van Moolenbroek 		tresult = ISC_R_SUCCESS;
367*00b67f09SDavid van Moolenbroek 	return ((result == ISC_R_SUCCESS) ? tresult : result);
368*00b67f09SDavid van Moolenbroek }
369*00b67f09SDavid van Moolenbroek 
370*00b67f09SDavid van Moolenbroek static isc_result_t
freezezones(dns_zone_t * zone,void * uap)371*00b67f09SDavid van Moolenbroek freezezones(dns_zone_t *zone, void *uap) {
372*00b67f09SDavid van Moolenbroek 	isc_boolean_t freeze = *(isc_boolean_t *)uap;
373*00b67f09SDavid van Moolenbroek 	isc_boolean_t frozen;
374*00b67f09SDavid van Moolenbroek 	isc_result_t result = ISC_R_SUCCESS;
375*00b67f09SDavid van Moolenbroek 	char classstr[DNS_RDATACLASS_FORMATSIZE];
376*00b67f09SDavid van Moolenbroek 	char zonename[DNS_NAME_FORMATSIZE];
377*00b67f09SDavid van Moolenbroek 	dns_zone_t *raw = NULL;
378*00b67f09SDavid van Moolenbroek 	dns_view_t *view;
379*00b67f09SDavid van Moolenbroek 	const char *vname;
380*00b67f09SDavid van Moolenbroek 	const char *sep;
381*00b67f09SDavid van Moolenbroek 	int level;
382*00b67f09SDavid van Moolenbroek 
383*00b67f09SDavid van Moolenbroek 	dns_zone_getraw(zone, &raw);
384*00b67f09SDavid van Moolenbroek 	if (raw != NULL)
385*00b67f09SDavid van Moolenbroek 		zone = raw;
386*00b67f09SDavid van Moolenbroek 	if (dns_zone_gettype(zone) != dns_zone_master) {
387*00b67f09SDavid van Moolenbroek 		if (raw != NULL)
388*00b67f09SDavid van Moolenbroek 			dns_zone_detach(&raw);
389*00b67f09SDavid van Moolenbroek 		return (ISC_R_SUCCESS);
390*00b67f09SDavid van Moolenbroek 	}
391*00b67f09SDavid van Moolenbroek 	if (!dns_zone_isdynamic(zone, ISC_TRUE)) {
392*00b67f09SDavid van Moolenbroek 		if (raw != NULL)
393*00b67f09SDavid van Moolenbroek 			dns_zone_detach(&raw);
394*00b67f09SDavid van Moolenbroek 		return (ISC_R_SUCCESS);
395*00b67f09SDavid van Moolenbroek 	}
396*00b67f09SDavid van Moolenbroek 
397*00b67f09SDavid van Moolenbroek 	frozen = dns_zone_getupdatedisabled(zone);
398*00b67f09SDavid van Moolenbroek 	if (freeze) {
399*00b67f09SDavid van Moolenbroek 		if (frozen)
400*00b67f09SDavid van Moolenbroek 			result = DNS_R_FROZEN;
401*00b67f09SDavid van Moolenbroek 		if (result == ISC_R_SUCCESS)
402*00b67f09SDavid van Moolenbroek 			result = dns_zone_flush(zone);
403*00b67f09SDavid van Moolenbroek 		if (result == ISC_R_SUCCESS)
404*00b67f09SDavid van Moolenbroek 			dns_zone_setupdatedisabled(zone, freeze);
405*00b67f09SDavid van Moolenbroek 	} else {
406*00b67f09SDavid van Moolenbroek 		if (frozen) {
407*00b67f09SDavid van Moolenbroek 			result = dns_zone_loadandthaw(zone);
408*00b67f09SDavid van Moolenbroek 			if (result == DNS_R_CONTINUE ||
409*00b67f09SDavid van Moolenbroek 			    result == DNS_R_UPTODATE)
410*00b67f09SDavid van Moolenbroek 				result = ISC_R_SUCCESS;
411*00b67f09SDavid van Moolenbroek 		}
412*00b67f09SDavid van Moolenbroek 	}
413*00b67f09SDavid van Moolenbroek 	view = dns_zone_getview(zone);
414*00b67f09SDavid van Moolenbroek 	if (strcmp(view->name, "_bind") == 0 ||
415*00b67f09SDavid van Moolenbroek 	    strcmp(view->name, "_default") == 0)
416*00b67f09SDavid van Moolenbroek 	{
417*00b67f09SDavid van Moolenbroek 		vname = "";
418*00b67f09SDavid van Moolenbroek 		sep = "";
419*00b67f09SDavid van Moolenbroek 	} else {
420*00b67f09SDavid van Moolenbroek 		vname = view->name;
421*00b67f09SDavid van Moolenbroek 		sep = " ";
422*00b67f09SDavid van Moolenbroek 	}
423*00b67f09SDavid van Moolenbroek 	dns_rdataclass_format(dns_zone_getclass(zone), classstr,
424*00b67f09SDavid van Moolenbroek 			      sizeof(classstr));
425*00b67f09SDavid van Moolenbroek 	dns_name_format(dns_zone_getorigin(zone), zonename, sizeof(zonename));
426*00b67f09SDavid van Moolenbroek 	level = (result != ISC_R_SUCCESS) ? ISC_LOG_ERROR : ISC_LOG_DEBUG(1);
427*00b67f09SDavid van Moolenbroek 	isc_log_write(dns_lctx, DNS_LOGCATEGORY_GENERAL, DNS_LOGMODULE_ZONE,
428*00b67f09SDavid van Moolenbroek 		      level, "%s zone '%s/%s'%s%s: %s",
429*00b67f09SDavid van Moolenbroek 		      freeze ? "freezing" : "thawing",
430*00b67f09SDavid van Moolenbroek 		      zonename, classstr, sep, vname,
431*00b67f09SDavid van Moolenbroek 		      isc_result_totext(result));
432*00b67f09SDavid van Moolenbroek 	if (raw != NULL)
433*00b67f09SDavid van Moolenbroek 		dns_zone_detach(&raw);
434*00b67f09SDavid van Moolenbroek 	return (result);
435*00b67f09SDavid van Moolenbroek }
436*00b67f09SDavid van Moolenbroek 
437*00b67f09SDavid van Moolenbroek isc_result_t
dns_zt_apply(dns_zt_t * zt,isc_boolean_t stop,isc_result_t (* action)(dns_zone_t *,void *),void * uap)438*00b67f09SDavid van Moolenbroek dns_zt_apply(dns_zt_t *zt, isc_boolean_t stop,
439*00b67f09SDavid van Moolenbroek 	     isc_result_t (*action)(dns_zone_t *, void *), void *uap)
440*00b67f09SDavid van Moolenbroek {
441*00b67f09SDavid van Moolenbroek 	return (dns_zt_apply2(zt, stop, NULL, action, uap));
442*00b67f09SDavid van Moolenbroek }
443*00b67f09SDavid van Moolenbroek 
444*00b67f09SDavid van Moolenbroek isc_result_t
dns_zt_apply2(dns_zt_t * zt,isc_boolean_t stop,isc_result_t * sub,isc_result_t (* action)(dns_zone_t *,void *),void * uap)445*00b67f09SDavid van Moolenbroek dns_zt_apply2(dns_zt_t *zt, isc_boolean_t stop, isc_result_t *sub,
446*00b67f09SDavid van Moolenbroek 	      isc_result_t (*action)(dns_zone_t *, void *), void *uap)
447*00b67f09SDavid van Moolenbroek {
448*00b67f09SDavid van Moolenbroek 	dns_rbtnode_t *node;
449*00b67f09SDavid van Moolenbroek 	dns_rbtnodechain_t chain;
450*00b67f09SDavid van Moolenbroek 	isc_result_t result, tresult = ISC_R_SUCCESS;
451*00b67f09SDavid van Moolenbroek 	dns_zone_t *zone;
452*00b67f09SDavid van Moolenbroek 
453*00b67f09SDavid van Moolenbroek 	REQUIRE(VALID_ZT(zt));
454*00b67f09SDavid van Moolenbroek 	REQUIRE(action != NULL);
455*00b67f09SDavid van Moolenbroek 
456*00b67f09SDavid van Moolenbroek 	dns_rbtnodechain_init(&chain, zt->mctx);
457*00b67f09SDavid van Moolenbroek 	result = dns_rbtnodechain_first(&chain, zt->table, NULL, NULL);
458*00b67f09SDavid van Moolenbroek 	if (result == ISC_R_NOTFOUND) {
459*00b67f09SDavid van Moolenbroek 		/*
460*00b67f09SDavid van Moolenbroek 		 * The tree is empty.
461*00b67f09SDavid van Moolenbroek 		 */
462*00b67f09SDavid van Moolenbroek 		tresult = result;
463*00b67f09SDavid van Moolenbroek 		result = ISC_R_NOMORE;
464*00b67f09SDavid van Moolenbroek 	}
465*00b67f09SDavid van Moolenbroek 	while (result == DNS_R_NEWORIGIN || result == ISC_R_SUCCESS) {
466*00b67f09SDavid van Moolenbroek 		result = dns_rbtnodechain_current(&chain, NULL, NULL,
467*00b67f09SDavid van Moolenbroek 						  &node);
468*00b67f09SDavid van Moolenbroek 		if (result == ISC_R_SUCCESS) {
469*00b67f09SDavid van Moolenbroek 			zone = node->data;
470*00b67f09SDavid van Moolenbroek 			if (zone != NULL)
471*00b67f09SDavid van Moolenbroek 				result = (action)(zone, uap);
472*00b67f09SDavid van Moolenbroek 			if (result != ISC_R_SUCCESS && stop) {
473*00b67f09SDavid van Moolenbroek 				tresult = result;
474*00b67f09SDavid van Moolenbroek 				goto cleanup;	/* don't break */
475*00b67f09SDavid van Moolenbroek 			} else if (result != ISC_R_SUCCESS &&
476*00b67f09SDavid van Moolenbroek 				   tresult == ISC_R_SUCCESS)
477*00b67f09SDavid van Moolenbroek 				tresult = result;
478*00b67f09SDavid van Moolenbroek 		}
479*00b67f09SDavid van Moolenbroek 		result = dns_rbtnodechain_next(&chain, NULL, NULL);
480*00b67f09SDavid van Moolenbroek 	}
481*00b67f09SDavid van Moolenbroek 	if (result == ISC_R_NOMORE)
482*00b67f09SDavid van Moolenbroek 		result = ISC_R_SUCCESS;
483*00b67f09SDavid van Moolenbroek 
484*00b67f09SDavid van Moolenbroek  cleanup:
485*00b67f09SDavid van Moolenbroek 	dns_rbtnodechain_invalidate(&chain);
486*00b67f09SDavid van Moolenbroek 	if (sub != NULL)
487*00b67f09SDavid van Moolenbroek 		*sub = tresult;
488*00b67f09SDavid van Moolenbroek 
489*00b67f09SDavid van Moolenbroek 	return (result);
490*00b67f09SDavid van Moolenbroek }
491*00b67f09SDavid van Moolenbroek 
492*00b67f09SDavid van Moolenbroek /*
493*00b67f09SDavid van Moolenbroek  * Decrement the loads_pending counter; when counter reaches
494*00b67f09SDavid van Moolenbroek  * zero, call the loaddone callback that was initially set by
495*00b67f09SDavid van Moolenbroek  * dns_zt_asyncload().
496*00b67f09SDavid van Moolenbroek  */
497*00b67f09SDavid van Moolenbroek static isc_result_t
doneloading(dns_zt_t * zt,dns_zone_t * zone,isc_task_t * task)498*00b67f09SDavid van Moolenbroek doneloading(dns_zt_t *zt, dns_zone_t *zone, isc_task_t *task) {
499*00b67f09SDavid van Moolenbroek 	isc_boolean_t destroy = ISC_FALSE;
500*00b67f09SDavid van Moolenbroek 	dns_zt_allloaded_t alldone = NULL;
501*00b67f09SDavid van Moolenbroek 	void *arg = NULL;
502*00b67f09SDavid van Moolenbroek 
503*00b67f09SDavid van Moolenbroek 	UNUSED(zone);
504*00b67f09SDavid van Moolenbroek 	UNUSED(task);
505*00b67f09SDavid van Moolenbroek 
506*00b67f09SDavid van Moolenbroek 	REQUIRE(VALID_ZT(zt));
507*00b67f09SDavid van Moolenbroek 
508*00b67f09SDavid van Moolenbroek 	RWLOCK(&zt->rwlock, isc_rwlocktype_write);
509*00b67f09SDavid van Moolenbroek 	INSIST(zt->loads_pending != 0);
510*00b67f09SDavid van Moolenbroek 	INSIST(zt->references != 0);
511*00b67f09SDavid van Moolenbroek 	zt->references--;
512*00b67f09SDavid van Moolenbroek 	if (zt->references == 0)
513*00b67f09SDavid van Moolenbroek 		destroy = ISC_TRUE;
514*00b67f09SDavid van Moolenbroek 	zt->loads_pending--;
515*00b67f09SDavid van Moolenbroek 	if (zt->loads_pending == 0) {
516*00b67f09SDavid van Moolenbroek 		alldone = zt->loaddone;
517*00b67f09SDavid van Moolenbroek 		arg = zt->loaddone_arg;
518*00b67f09SDavid van Moolenbroek 		zt->loaddone = NULL;
519*00b67f09SDavid van Moolenbroek 		zt->loaddone_arg = NULL;
520*00b67f09SDavid van Moolenbroek 	}
521*00b67f09SDavid van Moolenbroek 	RWUNLOCK(&zt->rwlock, isc_rwlocktype_write);
522*00b67f09SDavid van Moolenbroek 
523*00b67f09SDavid van Moolenbroek 	if (alldone != NULL)
524*00b67f09SDavid van Moolenbroek 		alldone(arg);
525*00b67f09SDavid van Moolenbroek 
526*00b67f09SDavid van Moolenbroek 	if (destroy)
527*00b67f09SDavid van Moolenbroek 		zt_destroy(zt);
528*00b67f09SDavid van Moolenbroek 
529*00b67f09SDavid van Moolenbroek 	return (ISC_R_SUCCESS);
530*00b67f09SDavid van Moolenbroek }
531*00b67f09SDavid van Moolenbroek 
532*00b67f09SDavid van Moolenbroek /***
533*00b67f09SDavid van Moolenbroek  *** Private
534*00b67f09SDavid van Moolenbroek  ***/
535*00b67f09SDavid van Moolenbroek 
536*00b67f09SDavid van Moolenbroek static void
auto_detach(void * data,void * arg)537*00b67f09SDavid van Moolenbroek auto_detach(void *data, void *arg) {
538*00b67f09SDavid van Moolenbroek 	dns_zone_t *zone = data;
539*00b67f09SDavid van Moolenbroek 
540*00b67f09SDavid van Moolenbroek 	UNUSED(arg);
541*00b67f09SDavid van Moolenbroek 	dns_zone_detach(&zone);
542*00b67f09SDavid van Moolenbroek }
543