1246847Sjkim/* $NetBSD: zt.c,v 1.10 2024/02/21 22:52:09 christos Exp $ */ 2246847Sjkim 3246847Sjkim/* 4246847Sjkim * Copyright (C) Internet Systems Consortium, Inc. ("ISC") 5246847Sjkim * 6246847Sjkim * SPDX-License-Identifier: MPL-2.0 7246847Sjkim * 8281075Sdim * This Source Code Form is subject to the terms of the Mozilla Public 9246847Sjkim * License, v. 2.0. If a copy of the MPL was not distributed with this 10246847Sjkim * file, you can obtain one at https://mozilla.org/MPL/2.0/. 11246847Sjkim * 12246847Sjkim * See the COPYRIGHT file distributed with this work for additional 13246847Sjkim * information regarding copyright ownership. 14246847Sjkim */ 15246847Sjkim 16246847Sjkim/*! \file */ 17246847Sjkim 18246847Sjkim#include <inttypes.h> 19246847Sjkim#include <stdbool.h> 20246847Sjkim 21246847Sjkim#include <isc/atomic.h> 22246847Sjkim#include <isc/file.h> 23246847Sjkim#include <isc/magic.h> 24246847Sjkim#include <isc/mem.h> 25246847Sjkim#include <isc/result.h> 26246847Sjkim#include <isc/string.h> 27246847Sjkim#include <isc/task.h> 28246847Sjkim#include <isc/util.h> 29246847Sjkim 30246847Sjkim#include <dns/log.h> 31246847Sjkim#include <dns/name.h> 32246847Sjkim#include <dns/rbt.h> 33246847Sjkim#include <dns/rdataclass.h> 34246847Sjkim#include <dns/view.h> 35246847Sjkim#include <dns/zone.h> 36246847Sjkim#include <dns/zt.h> 37246847Sjkim 38246847Sjkimstruct zt_load_params { 39246847Sjkim dns_zt_zoneloaded_t dl; 40246847Sjkim bool newonly; 41246847Sjkim}; 42246847Sjkim 43246847Sjkimstruct dns_zt { 44246849Sjkim /* Unlocked. */ 45246847Sjkim unsigned int magic; 46246849Sjkim isc_mem_t *mctx; 47246847Sjkim dns_rdataclass_t rdclass; 48246847Sjkim isc_rwlock_t rwlock; 49246847Sjkim dns_zt_allloaded_t loaddone; 50246847Sjkim void *loaddone_arg; 51246847Sjkim struct zt_load_params *loadparams; 52246847Sjkim 53246847Sjkim /* Atomic */ 54246847Sjkim atomic_bool flush; 55246847Sjkim isc_refcount_t references; 56246847Sjkim isc_refcount_t loads_pending; 57249663Sjkim 58249663Sjkim /* Locked by lock. */ 59249663Sjkim dns_rbt_t *table; 60249663Sjkim}; 61249663Sjkim 62249663Sjkimstruct zt_freeze_params { 63246847Sjkim dns_view_t *view; 64246847Sjkim bool freeze; 65246847Sjkim}; 66246847Sjkim 67246847Sjkim#define ZTMAGIC ISC_MAGIC('Z', 'T', 'b', 'l') 68246847Sjkim#define VALID_ZT(zt) ISC_MAGIC_VALID(zt, ZTMAGIC) 69246847Sjkim 70246847Sjkimstatic void 71246847Sjkimauto_detach(void *, void *); 72246847Sjkim 73246847Sjkimstatic isc_result_t 74246847Sjkimload(dns_zone_t *zone, void *uap); 75246847Sjkim 76246847Sjkimstatic isc_result_t 77246847Sjkimasyncload(dns_zone_t *zone, void *callback); 78246847Sjkim 79246847Sjkimstatic isc_result_t 80246847Sjkimfreezezones(dns_zone_t *zone, void *uap); 81246847Sjkim 82246847Sjkimstatic isc_result_t 83246847Sjkimdoneloading(dns_zt_t *zt, dns_zone_t *zone, isc_task_t *task); 84246847Sjkim 85246847Sjkimisc_result_t 86246847Sjkimdns_zt_create(isc_mem_t *mctx, dns_rdataclass_t rdclass, dns_zt_t **ztp) { 87246847Sjkim dns_zt_t *zt; 88246847Sjkim isc_result_t result; 89246847Sjkim 90246847Sjkim REQUIRE(ztp != NULL && *ztp == NULL); 91246847Sjkim 92246847Sjkim zt = isc_mem_get(mctx, sizeof(*zt)); 93246847Sjkim 94246847Sjkim zt->table = NULL; 95246847Sjkim result = dns_rbt_create(mctx, auto_detach, zt, &zt->table); 96249663Sjkim if (result != ISC_R_SUCCESS) { 97249663Sjkim goto cleanup_zt; 98249663Sjkim } 99246847Sjkim 100246847Sjkim isc_rwlock_init(&zt->rwlock, 0, 0); 101246847Sjkim zt->mctx = NULL; 102246847Sjkim isc_mem_attach(mctx, &zt->mctx); 103246847Sjkim isc_refcount_init(&zt->references, 1); 104246847Sjkim atomic_init(&zt->flush, false); 105246847Sjkim zt->rdclass = rdclass; 106246847Sjkim zt->magic = ZTMAGIC; 107246847Sjkim zt->loaddone = NULL; 108246847Sjkim zt->loaddone_arg = NULL; 109246847Sjkim zt->loadparams = NULL; 110246847Sjkim isc_refcount_init(&zt->loads_pending, 0); 111246847Sjkim *ztp = zt; 112246847Sjkim 113246847Sjkim return (ISC_R_SUCCESS); 114246847Sjkim 115246847Sjkimcleanup_zt: 116246847Sjkim isc_mem_put(mctx, zt, sizeof(*zt)); 117246847Sjkim 118246847Sjkim return (result); 119246847Sjkim} 120246847Sjkim 121246847Sjkimisc_result_t 122246847Sjkimdns_zt_mount(dns_zt_t *zt, dns_zone_t *zone) { 123246847Sjkim isc_result_t result; 124246847Sjkim dns_zone_t *dummy = NULL; 125246847Sjkim dns_name_t *name; 126246847Sjkim 127246847Sjkim REQUIRE(VALID_ZT(zt)); 128246847Sjkim 129246847Sjkim name = dns_zone_getorigin(zone); 130249112Sjkim 131249112Sjkim RWLOCK(&zt->rwlock, isc_rwlocktype_write); 132249112Sjkim 133249112Sjkim result = dns_rbt_addname(zt->table, name, zone); 134249112Sjkim if (result == ISC_R_SUCCESS) { 135246847Sjkim dns_zone_attach(zone, &dummy); 136246847Sjkim } 137246847Sjkim 138249112Sjkim RWUNLOCK(&zt->rwlock, isc_rwlocktype_write); 139246847Sjkim 140249112Sjkim return (result); 141249112Sjkim} 142249112Sjkim 143249112Sjkimisc_result_t 144249112Sjkimdns_zt_unmount(dns_zt_t *zt, dns_zone_t *zone) { 145246847Sjkim isc_result_t result; 146249112Sjkim dns_name_t *name; 147249112Sjkim 148249112Sjkim REQUIRE(VALID_ZT(zt)); 149249112Sjkim 150249112Sjkim name = dns_zone_getorigin(zone); 151249112Sjkim 152249112Sjkim RWLOCK(&zt->rwlock, isc_rwlocktype_write); 153249112Sjkim 154284460Sjkim result = dns_rbt_deletename(zt->table, name, false); 155249112Sjkim 156249112Sjkim RWUNLOCK(&zt->rwlock, isc_rwlocktype_write); 157249112Sjkim 158246847Sjkim return (result); 159249112Sjkim} 160246847Sjkim 161246847Sjkimisc_result_t 162246847Sjkimdns_zt_find(dns_zt_t *zt, const dns_name_t *name, unsigned int options, 163246847Sjkim dns_name_t *foundname, dns_zone_t **zonep) { 164246847Sjkim isc_result_t result; 165246847Sjkim dns_zone_t *dummy = NULL; 166246847Sjkim unsigned int rbtoptions = 0; 167246847Sjkim 168246847Sjkim REQUIRE(VALID_ZT(zt)); 169246847Sjkim 170246847Sjkim if ((options & DNS_ZTFIND_NOEXACT) != 0) { 171246847Sjkim rbtoptions |= DNS_RBTFIND_NOEXACT; 172246847Sjkim } 173281075Sdim 174246847Sjkim RWLOCK(&zt->rwlock, isc_rwlocktype_read); 175246847Sjkim 176246847Sjkim result = dns_rbt_findname(zt->table, name, rbtoptions, foundname, 177246847Sjkim (void **)(void *)&dummy); 178246847Sjkim if (result == ISC_R_SUCCESS || result == DNS_R_PARTIALMATCH) { 179246847Sjkim /* 180246847Sjkim * If DNS_ZTFIND_MIRROR is set and the zone which was 181246847Sjkim * determined to be the deepest match for the supplied name is 182246847Sjkim * a mirror zone which is expired or not yet loaded, treat it 183246847Sjkim * as non-existent. This will trigger a fallback to recursion 184246847Sjkim * instead of returning a SERVFAIL. 185246847Sjkim * 186246847Sjkim * Note that currently only the deepest match in the zone table 187246847Sjkim * is checked. Consider a server configured with two mirror 188246847Sjkim * zones: "bar" and its child, "foo.bar". If zone data is 189246847Sjkim * available for "bar" but not for "foo.bar", a query with 190246847Sjkim * QNAME equal to or below "foo.bar" will cause ISC_R_NOTFOUND 191246847Sjkim * to be returned, not DNS_R_PARTIALMATCH, despite zone data 192246847Sjkim * being available for "bar". This is considered to be an edge 193246847Sjkim * case, handling which more appropriately is possible, but 194246847Sjkim * arguably not worth the added complexity. 195246847Sjkim */ 196246847Sjkim if ((options & DNS_ZTFIND_MIRROR) != 0 && 197246847Sjkim dns_zone_gettype(dummy) == dns_zone_mirror && 198281075Sdim !dns_zone_isloaded(dummy)) 199249663Sjkim { 200246847Sjkim result = ISC_R_NOTFOUND; 201246847Sjkim } else { 202246847Sjkim dns_zone_attach(dummy, zonep); 203246847Sjkim } 204246847Sjkim } 205246847Sjkim 206246847Sjkim RWUNLOCK(&zt->rwlock, isc_rwlocktype_read); 207246847Sjkim 208246847Sjkim return (result); 209246847Sjkim} 210246847Sjkim 211281075Sdimvoid 212249663Sjkimdns_zt_attach(dns_zt_t *zt, dns_zt_t **ztp) { 213249663Sjkim REQUIRE(VALID_ZT(zt)); 214246847Sjkim REQUIRE(ztp != NULL && *ztp == NULL); 215246847Sjkim 216246847Sjkim isc_refcount_increment(&zt->references); 217246847Sjkim 218246847Sjkim *ztp = zt; 219246847Sjkim} 220246847Sjkim 221246847Sjkimstatic isc_result_t 222246847Sjkimflush(dns_zone_t *zone, void *uap) { 223246847Sjkim UNUSED(uap); 224246847Sjkim return (dns_zone_flush(zone)); 225246847Sjkim} 226246847Sjkim 227246847Sjkimstatic void 228246847Sjkimzt_destroy(dns_zt_t *zt) { 229246847Sjkim isc_refcount_destroy(&zt->references); 230246847Sjkim isc_refcount_destroy(&zt->loads_pending); 231246847Sjkim 232246847Sjkim if (atomic_load_acquire(&zt->flush)) { 233246847Sjkim (void)dns_zt_apply(zt, isc_rwlocktype_none, false, NULL, flush, 234246847Sjkim NULL); 235246847Sjkim } 236246847Sjkim 237246847Sjkim dns_rbt_destroy(&zt->table); 238246847Sjkim isc_rwlock_destroy(&zt->rwlock); 239246847Sjkim zt->magic = 0; 240246847Sjkim isc_mem_putanddetach(&zt->mctx, zt, sizeof(*zt)); 241246847Sjkim} 242246847Sjkim 243246847Sjkimvoid 244246847Sjkimdns_zt_detach(dns_zt_t **ztp) { 245246847Sjkim dns_zt_t *zt; 246246847Sjkim 247246847Sjkim REQUIRE(ztp != NULL && VALID_ZT(*ztp)); 248246847Sjkim 249246847Sjkim zt = *ztp; 250246847Sjkim *ztp = NULL; 251246847Sjkim 252246847Sjkim if (isc_refcount_decrement(&zt->references) == 1) { 253246847Sjkim zt_destroy(zt); 254246847Sjkim } 255281075Sdim} 256246847Sjkim 257246847Sjkimvoid 258246847Sjkimdns_zt_flush(dns_zt_t *zt) { 259246847Sjkim REQUIRE(VALID_ZT(zt)); 260246847Sjkim atomic_store_release(&zt->flush, true); 261246847Sjkim} 262246847Sjkim 263281075Sdimisc_result_t 264246847Sjkimdns_zt_load(dns_zt_t *zt, bool stop, bool newonly) { 265246847Sjkim isc_result_t result; 266246847Sjkim struct zt_load_params params; 267246847Sjkim REQUIRE(VALID_ZT(zt)); 268246847Sjkim params.newonly = newonly; 269246847Sjkim result = dns_zt_apply(zt, isc_rwlocktype_read, stop, NULL, load, 270246847Sjkim ¶ms); 271246847Sjkim return (result); 272246847Sjkim} 273249663Sjkim 274249663Sjkimstatic isc_result_t 275246847Sjkimload(dns_zone_t *zone, void *paramsv) { 276246847Sjkim isc_result_t result; 277246847Sjkim struct zt_load_params *params = (struct zt_load_params *)paramsv; 278246847Sjkim result = dns_zone_load(zone, params->newonly); 279246847Sjkim if (result == DNS_R_CONTINUE || result == DNS_R_UPTODATE || 280246847Sjkim result == DNS_R_DYNAMIC) 281246847Sjkim { 282246847Sjkim result = ISC_R_SUCCESS; 283246847Sjkim } 284246847Sjkim return (result); 285246847Sjkim} 286246847Sjkim 287281075Sdimstatic void 288246847Sjkimcall_loaddone(dns_zt_t *zt) { 289246847Sjkim dns_zt_allloaded_t loaddone = zt->loaddone; 290246847Sjkim void *loaddone_arg = zt->loaddone_arg; 291246847Sjkim 292246847Sjkim /* 293281075Sdim * Set zt->loaddone, zt->loaddone_arg and zt->loadparams to NULL 294281075Sdim * before calling loaddone. 295281075Sdim */ 296281075Sdim zt->loaddone = NULL; 297281075Sdim zt->loaddone_arg = NULL; 298281075Sdim 299281075Sdim isc_mem_put(zt->mctx, zt->loadparams, sizeof(struct zt_load_params)); 300281075Sdim zt->loadparams = NULL; 301281075Sdim 302281075Sdim /* 303281075Sdim * Call the callback last. 304281075Sdim */ 305281075Sdim if (loaddone != NULL) { 306281075Sdim loaddone(loaddone_arg); 307281075Sdim } 308281075Sdim} 309281075Sdim 310281075Sdimisc_result_t 311281075Sdimdns_zt_asyncload(dns_zt_t *zt, bool newonly, dns_zt_allloaded_t alldone, 312281075Sdim void *arg) { 313281075Sdim isc_result_t result; 314281075Sdim uint_fast32_t loads_pending; 315281075Sdim 316281075Sdim REQUIRE(VALID_ZT(zt)); 317281075Sdim 318281075Sdim /* 319281075Sdim * Obtain a reference to zt->loads_pending so that asyncload can 320281075Sdim * safely decrement both zt->references and zt->loads_pending 321281075Sdim * without going to zero. 322281075Sdim */ 323281075Sdim loads_pending = isc_refcount_increment0(&zt->loads_pending); 324281075Sdim INSIST(loads_pending == 0); 325281075Sdim 326281075Sdim /* 327281075Sdim * Only one dns_zt_asyncload call at a time should be active so 328284460Sjkim * these pointers should be NULL. They are set back to NULL 329284460Sjkim * before the zt->loaddone (alldone) is called in call_loaddone. 330284460Sjkim */ 331284460Sjkim INSIST(zt->loadparams == NULL); 332284460Sjkim INSIST(zt->loaddone == NULL); 333284460Sjkim INSIST(zt->loaddone_arg == NULL); 334284460Sjkim 335284460Sjkim zt->loadparams = isc_mem_get(zt->mctx, sizeof(struct zt_load_params)); 336284460Sjkim zt->loadparams->dl = doneloading; 337284460Sjkim zt->loadparams->newonly = newonly; 338284460Sjkim zt->loaddone = alldone; 339284460Sjkim zt->loaddone_arg = arg; 340284460Sjkim 341284460Sjkim result = dns_zt_apply(zt, isc_rwlocktype_read, false, NULL, asyncload, 342284460Sjkim zt); 343284460Sjkim 344284460Sjkim /* 345284460Sjkim * Have all the loads completed? 346284460Sjkim */ 347284460Sjkim if (isc_refcount_decrement(&zt->loads_pending) == 1) { 348284460Sjkim call_loaddone(zt); 349284460Sjkim } 350284460Sjkim 351284460Sjkim return (result); 352284460Sjkim} 353284460Sjkim 354246847Sjkim/* 355246847Sjkim * Initiates asynchronous loading of zone 'zone'. 'callback' is a 356246847Sjkim * pointer to a function which will be used to inform the caller when 357246847Sjkim * the zone loading is complete. 358246847Sjkim */ 359246847Sjkimstatic isc_result_t 360246847Sjkimasyncload(dns_zone_t *zone, void *zt_) { 361281075Sdim isc_result_t result; 362246847Sjkim struct dns_zt *zt = (dns_zt_t *)zt_; 363246847Sjkim REQUIRE(zone != NULL); 364281075Sdim 365246847Sjkim isc_refcount_increment(&zt->references); 366246847Sjkim isc_refcount_increment(&zt->loads_pending); 367246847Sjkim 368246847Sjkim result = dns_zone_asyncload(zone, zt->loadparams->newonly, 369246847Sjkim *zt->loadparams->dl, zt); 370246847Sjkim if (result != ISC_R_SUCCESS) { 371246847Sjkim /* 372246847Sjkim * Caller is holding a reference to zt->loads_pending 373246847Sjkim * and zt->references so these can't decrement to zero. 374246847Sjkim */ 375246847Sjkim isc_refcount_decrement1(&zt->references); 376246847Sjkim isc_refcount_decrement1(&zt->loads_pending); 377246847Sjkim } 378246847Sjkim return (ISC_R_SUCCESS); 379246847Sjkim} 380246847Sjkim 381246847Sjkimisc_result_t 382246847Sjkimdns_zt_freezezones(dns_zt_t *zt, dns_view_t *view, bool freeze) { 383246847Sjkim isc_result_t result, tresult; 384246847Sjkim struct zt_freeze_params params = { view, freeze }; 385246847Sjkim 386249663Sjkim REQUIRE(VALID_ZT(zt)); 387249663Sjkim 388249663Sjkim result = dns_zt_apply(zt, isc_rwlocktype_read, false, &tresult, 389249663Sjkim freezezones, ¶ms); 390249663Sjkim if (tresult == ISC_R_NOTFOUND) { 391249663Sjkim tresult = ISC_R_SUCCESS; 392246847Sjkim } 393246847Sjkim return ((result == ISC_R_SUCCESS) ? tresult : result); 394246847Sjkim} 395246847Sjkim 396246847Sjkimstatic isc_result_t 397246847Sjkimfreezezones(dns_zone_t *zone, void *uap) { 398246847Sjkim struct zt_freeze_params *params = uap; 399246847Sjkim bool frozen; 400246847Sjkim isc_result_t result = ISC_R_SUCCESS; 401246847Sjkim char classstr[DNS_RDATACLASS_FORMATSIZE]; 402246847Sjkim char zonename[DNS_NAME_FORMATSIZE]; 403246847Sjkim dns_zone_t *raw = NULL; 404246847Sjkim dns_view_t *view; 405246847Sjkim const char *vname; 406246847Sjkim const char *sep; 407246847Sjkim int level; 408246847Sjkim 409246847Sjkim dns_zone_getraw(zone, &raw); 410246847Sjkim if (raw != NULL) { 411246847Sjkim zone = raw; 412246847Sjkim } 413246847Sjkim if (params->view != dns_zone_getview(zone)) { 414246847Sjkim if (raw != NULL) { 415246847Sjkim dns_zone_detach(&raw); 416246847Sjkim } 417246847Sjkim return (ISC_R_SUCCESS); 418246847Sjkim } 419246847Sjkim if (dns_zone_gettype(zone) != dns_zone_primary) { 420246847Sjkim if (raw != NULL) { 421246847Sjkim dns_zone_detach(&raw); 422246847Sjkim } 423246847Sjkim return (ISC_R_SUCCESS); 424246847Sjkim } 425246847Sjkim if (!dns_zone_isdynamic(zone, true)) { 426246847Sjkim if (raw != NULL) { 427246847Sjkim dns_zone_detach(&raw); 428246847Sjkim } 429246847Sjkim return (ISC_R_SUCCESS); 430246847Sjkim } 431246847Sjkim 432246847Sjkim frozen = dns_zone_getupdatedisabled(zone); 433246847Sjkim if (params->freeze) { 434246847Sjkim if (frozen) { 435246847Sjkim result = DNS_R_FROZEN; 436246847Sjkim } 437246847Sjkim if (result == ISC_R_SUCCESS) { 438246847Sjkim result = dns_zone_flush(zone); 439246847Sjkim } 440246847Sjkim if (result == ISC_R_SUCCESS) { 441246847Sjkim dns_zone_setupdatedisabled(zone, params->freeze); 442246847Sjkim } 443246847Sjkim } else { 444246847Sjkim if (frozen) { 445246847Sjkim result = dns_zone_loadandthaw(zone); 446246847Sjkim if (result == DNS_R_CONTINUE || 447246847Sjkim result == DNS_R_UPTODATE) 448246847Sjkim { 449246847Sjkim result = ISC_R_SUCCESS; 450246847Sjkim } 451246847Sjkim } 452246847Sjkim } 453246847Sjkim view = dns_zone_getview(zone); 454246847Sjkim if (strcmp(view->name, "_bind") == 0 || strcmp(view->name, "_defaul" 455246847Sjkim "t") == 0) 456246847Sjkim { 457284460Sjkim vname = ""; 458246847Sjkim sep = ""; 459246847Sjkim } else { 460246847Sjkim vname = view->name; 461246847Sjkim sep = " "; 462246847Sjkim } 463246847Sjkim dns_rdataclass_format(dns_zone_getclass(zone), classstr, 464246847Sjkim sizeof(classstr)); 465246847Sjkim dns_name_format(dns_zone_getorigin(zone), zonename, sizeof(zonename)); 466246847Sjkim level = (result != ISC_R_SUCCESS) ? ISC_LOG_ERROR : ISC_LOG_DEBUG(1); 467246847Sjkim isc_log_write(dns_lctx, DNS_LOGCATEGORY_GENERAL, DNS_LOGMODULE_ZONE, 468246847Sjkim level, "%s zone '%s/%s'%s%s: %s", 469246847Sjkim params->freeze ? "freezing" : "thawing", zonename, 470246847Sjkim classstr, sep, vname, isc_result_totext(result)); 471246847Sjkim if (raw != NULL) { 472246847Sjkim dns_zone_detach(&raw); 473246847Sjkim } 474246847Sjkim return (result); 475246847Sjkim} 476246847Sjkim 477246847Sjkimvoid 478246847Sjkimdns_zt_setviewcommit(dns_zt_t *zt) { 479246847Sjkim dns_rbtnode_t *node; 480246847Sjkim dns_rbtnodechain_t chain; 481246847Sjkim isc_result_t result; 482246847Sjkim 483246847Sjkim REQUIRE(VALID_ZT(zt)); 484246847Sjkim 485246847Sjkim RWLOCK(&zt->rwlock, isc_rwlocktype_read); 486246847Sjkim dns_rbtnodechain_init(&chain); 487246847Sjkim 488246847Sjkim result = dns_rbtnodechain_first(&chain, zt->table, NULL, NULL); 489246847Sjkim while (result == DNS_R_NEWORIGIN || result == ISC_R_SUCCESS) { 490246847Sjkim result = dns_rbtnodechain_current(&chain, NULL, NULL, &node); 491246847Sjkim if (result == ISC_R_SUCCESS && node->data != NULL) { 492246847Sjkim dns_zone_setviewcommit(node->data); 493246847Sjkim } 494246847Sjkim 495246847Sjkim result = dns_rbtnodechain_next(&chain, NULL, NULL); 496246847Sjkim } 497246847Sjkim 498246847Sjkim dns_rbtnodechain_invalidate(&chain); 499246847Sjkim RWUNLOCK(&zt->rwlock, isc_rwlocktype_read); 500246847Sjkim} 501246847Sjkim 502246847Sjkimvoid 503246847Sjkimdns_zt_setviewrevert(dns_zt_t *zt) { 504284460Sjkim dns_rbtnode_t *node; 505284460Sjkim dns_rbtnodechain_t chain; 506284460Sjkim isc_result_t result; 507284460Sjkim 508284460Sjkim REQUIRE(VALID_ZT(zt)); 509284460Sjkim 510246847Sjkim dns_rbtnodechain_init(&chain); 511246847Sjkim 512246847Sjkim result = dns_rbtnodechain_first(&chain, zt->table, NULL, NULL); 513246847Sjkim while (result == DNS_R_NEWORIGIN || result == ISC_R_SUCCESS) { 514246847Sjkim result = dns_rbtnodechain_current(&chain, NULL, NULL, &node); 515246847Sjkim if (result == ISC_R_SUCCESS && node->data != NULL) { 516246847Sjkim dns_zone_setviewrevert(node->data); 517246847Sjkim } 518246847Sjkim 519246847Sjkim result = dns_rbtnodechain_next(&chain, NULL, NULL); 520246847Sjkim } 521246847Sjkim 522246847Sjkim dns_rbtnodechain_invalidate(&chain); 523246847Sjkim} 524246847Sjkim 525246847Sjkimisc_result_t 526246847Sjkimdns_zt_apply(dns_zt_t *zt, isc_rwlocktype_t lock, bool stop, isc_result_t *sub, 527246847Sjkim isc_result_t (*action)(dns_zone_t *, void *), void *uap) { 528246847Sjkim dns_rbtnode_t *node; 529246847Sjkim dns_rbtnodechain_t chain; 530246847Sjkim isc_result_t result, tresult = ISC_R_SUCCESS; 531246847Sjkim dns_zone_t *zone; 532246847Sjkim 533246847Sjkim REQUIRE(VALID_ZT(zt)); 534246847Sjkim REQUIRE(action != NULL); 535246847Sjkim 536281075Sdim if (lock != isc_rwlocktype_none) { 537281075Sdim RWLOCK(&zt->rwlock, lock); 538281075Sdim } 539281075Sdim 540281075Sdim dns_rbtnodechain_init(&chain); 541281075Sdim result = dns_rbtnodechain_first(&chain, zt->table, NULL, NULL); 542246847Sjkim if (result == ISC_R_NOTFOUND) { 543246847Sjkim /* 544246847Sjkim * The tree is empty. 545246847Sjkim */ 546246847Sjkim tresult = result; 547246847Sjkim result = ISC_R_NOMORE; 548246847Sjkim } 549246847Sjkim while (result == DNS_R_NEWORIGIN || result == ISC_R_SUCCESS) { 550246847Sjkim result = dns_rbtnodechain_current(&chain, NULL, NULL, &node); 551246847Sjkim if (result == ISC_R_SUCCESS) { 552246847Sjkim zone = node->data; 553246847Sjkim if (zone != NULL) { 554246847Sjkim result = (action)(zone, uap); 555246847Sjkim } 556246847Sjkim if (result != ISC_R_SUCCESS && stop) { 557246847Sjkim tresult = result; 558246847Sjkim goto cleanup; /* don't break */ 559246847Sjkim } else if (result != ISC_R_SUCCESS && 560246847Sjkim tresult == ISC_R_SUCCESS) 561246847Sjkim { 562246847Sjkim tresult = result; 563246847Sjkim } 564246847Sjkim } 565246847Sjkim result = dns_rbtnodechain_next(&chain, NULL, NULL); 566246847Sjkim } 567284460Sjkim if (result == ISC_R_NOMORE) { 568284460Sjkim result = ISC_R_SUCCESS; 569284460Sjkim } 570284460Sjkim 571284460Sjkimcleanup: 572284460Sjkim dns_rbtnodechain_invalidate(&chain); 573284460Sjkim if (sub != NULL) { 574284460Sjkim *sub = tresult; 575284460Sjkim } 576284460Sjkim 577284460Sjkim if (lock != isc_rwlocktype_none) { 578284460Sjkim RWUNLOCK(&zt->rwlock, lock); 579284460Sjkim } 580284460Sjkim 581284460Sjkim return (result); 582284460Sjkim} 583284460Sjkim 584284460Sjkim/* 585284460Sjkim * Decrement the loads_pending counter; when counter reaches 586246847Sjkim * zero, call the loaddone callback that was initially set by 587246847Sjkim * dns_zt_asyncload(). 588281075Sdim */ 589246847Sjkimstatic isc_result_t 590246847Sjkimdoneloading(dns_zt_t *zt, dns_zone_t *zone, isc_task_t *task) { 591246847Sjkim UNUSED(zone); 592246847Sjkim UNUSED(task); 593246847Sjkim 594246847Sjkim REQUIRE(VALID_ZT(zt)); 595246847Sjkim 596246847Sjkim if (isc_refcount_decrement(&zt->loads_pending) == 1) { 597281075Sdim call_loaddone(zt); 598281075Sdim } 599281075Sdim 600281075Sdim if (isc_refcount_decrement(&zt->references) == 1) { 601281075Sdim zt_destroy(zt); 602281075Sdim } 603246847Sjkim 604246847Sjkim return (ISC_R_SUCCESS); 605246847Sjkim} 606246847Sjkim 607246847Sjkim/*** 608246847Sjkim *** Private 609246847Sjkim ***/ 610246847Sjkim 611246847Sjkimstatic void 612246847Sjkimauto_detach(void *data, void *arg) { 613246847Sjkim dns_zone_t *zone = data; 614246847Sjkim 615246847Sjkim UNUSED(arg); 616246847Sjkim dns_zone_detach(&zone); 617281075Sdim} 618246847Sjkim