1 1.21 christos /* $NetBSD: rbtdb.c,v 1.23 2026/01/29 18:37:49 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.15 christos * SPDX-License-Identifier: MPL-2.0 7 1.15 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.9 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.3 christos #include <inttypes.h> 19 1.3 christos #include <stdbool.h> 20 1.19 christos #include <sys/mman.h> 21 1.1 christos 22 1.21 christos #include <isc/ascii.h> 23 1.21 christos #include <isc/async.h> 24 1.7 christos #include <isc/atomic.h> 25 1.1 christos #include <isc/crc64.h> 26 1.7 christos #include <isc/file.h> 27 1.7 christos #include <isc/hash.h> 28 1.21 christos #include <isc/hashmap.h> 29 1.1 christos #include <isc/heap.h> 30 1.1 christos #include <isc/hex.h> 31 1.21 christos #include <isc/loop.h> 32 1.1 christos #include <isc/mem.h> 33 1.1 christos #include <isc/mutex.h> 34 1.1 christos #include <isc/once.h> 35 1.1 christos #include <isc/random.h> 36 1.1 christos #include <isc/refcount.h> 37 1.19 christos #include <isc/result.h> 38 1.1 christos #include <isc/rwlock.h> 39 1.1 christos #include <isc/serial.h> 40 1.1 christos #include <isc/stdio.h> 41 1.1 christos #include <isc/string.h> 42 1.1 christos #include <isc/time.h> 43 1.21 christos #include <isc/urcu.h> 44 1.1 christos #include <isc/util.h> 45 1.1 christos 46 1.1 christos #include <dns/callbacks.h> 47 1.1 christos #include <dns/db.h> 48 1.1 christos #include <dns/dbiterator.h> 49 1.1 christos #include <dns/fixedname.h> 50 1.1 christos #include <dns/log.h> 51 1.1 christos #include <dns/masterdump.h> 52 1.1 christos #include <dns/nsec.h> 53 1.1 christos #include <dns/nsec3.h> 54 1.1 christos #include <dns/rbt.h> 55 1.1 christos #include <dns/rdata.h> 56 1.1 christos #include <dns/rdataset.h> 57 1.1 christos #include <dns/rdatasetiter.h> 58 1.1 christos #include <dns/rdataslab.h> 59 1.1 christos #include <dns/rdatastruct.h> 60 1.1 christos #include <dns/stats.h> 61 1.1 christos #include <dns/time.h> 62 1.1 christos #include <dns/view.h> 63 1.1 christos #include <dns/zone.h> 64 1.1 christos #include <dns/zonekey.h> 65 1.1 christos 66 1.21 christos #include "db_p.h" 67 1.21 christos #include "rbtdb_p.h" 68 1.1 christos 69 1.9 christos #define EXISTS(header) \ 70 1.9 christos ((atomic_load_acquire(&(header)->attributes) & \ 71 1.21 christos DNS_SLABHEADERATTR_NONEXISTENT) == 0) 72 1.9 christos #define NONEXISTENT(header) \ 73 1.9 christos ((atomic_load_acquire(&(header)->attributes) & \ 74 1.21 christos DNS_SLABHEADERATTR_NONEXISTENT) != 0) 75 1.9 christos #define IGNORE(header) \ 76 1.9 christos ((atomic_load_acquire(&(header)->attributes) & \ 77 1.21 christos DNS_SLABHEADERATTR_IGNORE) != 0) 78 1.21 christos #define NXDOMAIN(header) \ 79 1.9 christos ((atomic_load_acquire(&(header)->attributes) & \ 80 1.21 christos DNS_SLABHEADERATTR_NXDOMAIN) != 0) 81 1.21 christos #define STALE(header) \ 82 1.9 christos ((atomic_load_acquire(&(header)->attributes) & \ 83 1.21 christos DNS_SLABHEADERATTR_STALE) != 0) 84 1.9 christos #define STALE_WINDOW(header) \ 85 1.9 christos ((atomic_load_acquire(&(header)->attributes) & \ 86 1.21 christos DNS_SLABHEADERATTR_STALE_WINDOW) != 0) 87 1.9 christos #define RESIGN(header) \ 88 1.9 christos ((atomic_load_acquire(&(header)->attributes) & \ 89 1.21 christos DNS_SLABHEADERATTR_RESIGN) != 0) 90 1.9 christos #define OPTOUT(header) \ 91 1.9 christos ((atomic_load_acquire(&(header)->attributes) & \ 92 1.21 christos DNS_SLABHEADERATTR_OPTOUT) != 0) 93 1.9 christos #define NEGATIVE(header) \ 94 1.9 christos ((atomic_load_acquire(&(header)->attributes) & \ 95 1.21 christos DNS_SLABHEADERATTR_NEGATIVE) != 0) 96 1.9 christos #define PREFETCH(header) \ 97 1.9 christos ((atomic_load_acquire(&(header)->attributes) & \ 98 1.21 christos DNS_SLABHEADERATTR_PREFETCH) != 0) 99 1.9 christos #define CASESET(header) \ 100 1.9 christos ((atomic_load_acquire(&(header)->attributes) & \ 101 1.21 christos DNS_SLABHEADERATTR_CASESET) != 0) 102 1.9 christos #define ZEROTTL(header) \ 103 1.9 christos ((atomic_load_acquire(&(header)->attributes) & \ 104 1.21 christos DNS_SLABHEADERATTR_ZEROTTL) != 0) 105 1.9 christos #define ANCIENT(header) \ 106 1.9 christos ((atomic_load_acquire(&(header)->attributes) & \ 107 1.21 christos DNS_SLABHEADERATTR_ANCIENT) != 0) 108 1.9 christos #define STATCOUNT(header) \ 109 1.9 christos ((atomic_load_acquire(&(header)->attributes) & \ 110 1.21 christos DNS_SLABHEADERATTR_STATCOUNT) != 0) 111 1.21 christos 112 1.21 christos #define STALE_TTL(header, rbtdb) \ 113 1.21 christos (NXDOMAIN(header) ? 0 : rbtdb->common.serve_stale_ttl) 114 1.9 christos 115 1.21 christos #define ACTIVE(header, now) \ 116 1.21 christos (((header)->ttl > (now)) || ((header)->ttl == (now) && ZEROTTL(header))) 117 1.21 christos 118 1.21 christos #define DEFAULT_NODE_LOCK_COUNT 7 /*%< Should be prime. */ 119 1.1 christos 120 1.16 christos #define EXPIREDOK(rbtiterator) \ 121 1.16 christos (((rbtiterator)->common.options & DNS_DB_EXPIREDOK) != 0) 122 1.16 christos 123 1.16 christos #define STALEOK(rbtiterator) \ 124 1.16 christos (((rbtiterator)->common.options & DNS_DB_STALEOK) != 0) 125 1.16 christos 126 1.21 christos #define KEEPSTALE(rbtdb) ((rbtdb)->common.serve_stale_ttl > 0) 127 1.21 christos 128 1.20 christos #define RBTDBITER_NSEC3_ORIGIN_NODE(rbtdb, iterator) \ 129 1.20 christos ((iterator)->current == &(iterator)->nsec3chain && \ 130 1.20 christos (iterator)->node == (rbtdb)->nsec3_origin_node) 131 1.20 christos 132 1.1 christos /*% 133 1.1 christos * Number of buckets for cache DB entries (locks, LRU lists, TTL heaps). 134 1.1 christos * There is a tradeoff issue about configuring this value: if this is too 135 1.1 christos * small, it may cause heavier contention between threads; if this is too large, 136 1.1 christos * LRU purge algorithm won't work well (entries tend to be purged prematurely). 137 1.1 christos * The default value should work well for most environments, but this can 138 1.1 christos * also be configurable at compilation time via the 139 1.1 christos * DNS_RBTDB_CACHE_NODE_LOCK_COUNT variable. This value must be larger than 140 1.21 christos * 1 due to the assumption of dns__cacherbt_overmem(). 141 1.1 christos */ 142 1.1 christos #ifdef DNS_RBTDB_CACHE_NODE_LOCK_COUNT 143 1.1 christos #if DNS_RBTDB_CACHE_NODE_LOCK_COUNT <= 1 144 1.1 christos #error "DNS_RBTDB_CACHE_NODE_LOCK_COUNT must be larger than 1" 145 1.7 christos #else /* if DNS_RBTDB_CACHE_NODE_LOCK_COUNT <= 1 */ 146 1.1 christos #define DEFAULT_CACHE_NODE_LOCK_COUNT DNS_RBTDB_CACHE_NODE_LOCK_COUNT 147 1.7 christos #endif /* if DNS_RBTDB_CACHE_NODE_LOCK_COUNT <= 1 */ 148 1.7 christos #else /* ifdef DNS_RBTDB_CACHE_NODE_LOCK_COUNT */ 149 1.14 christos #define DEFAULT_CACHE_NODE_LOCK_COUNT 17 150 1.7 christos #endif /* DNS_RBTDB_CACHE_NODE_LOCK_COUNT */ 151 1.1 christos 152 1.20 christos /* 153 1.20 christos * This defines the number of headers that we try to expire each time the 154 1.20 christos * expire_ttl_headers() is run. The number should be small enough, so the 155 1.20 christos * TTL-based header expiration doesn't take too long, but it should be large 156 1.20 christos * enough, so we expire enough headers if their TTL is clustered. 157 1.20 christos */ 158 1.20 christos #define DNS_RBTDB_EXPIRE_TTL_COUNT 10 159 1.20 christos 160 1.7 christos static void 161 1.7 christos delete_callback(void *data, void *arg); 162 1.7 christos static void 163 1.21 christos prune_tree(void *arg); 164 1.1 christos 165 1.7 christos static void 166 1.21 christos rdatasetiter_destroy(dns_rdatasetiter_t **iteratorp DNS__DB_FLARG); 167 1.7 christos static isc_result_t 168 1.21 christos rdatasetiter_first(dns_rdatasetiter_t *iterator DNS__DB_FLARG); 169 1.7 christos static isc_result_t 170 1.21 christos rdatasetiter_next(dns_rdatasetiter_t *iterator DNS__DB_FLARG); 171 1.7 christos static void 172 1.21 christos rdatasetiter_current(dns_rdatasetiter_t *iterator, 173 1.21 christos dns_rdataset_t *rdataset DNS__DB_FLARG); 174 1.1 christos 175 1.1 christos static dns_rdatasetitermethods_t rdatasetiter_methods = { 176 1.7 christos rdatasetiter_destroy, rdatasetiter_first, rdatasetiter_next, 177 1.1 christos rdatasetiter_current 178 1.1 christos }; 179 1.1 christos 180 1.1 christos typedef struct rbtdb_rdatasetiter { 181 1.7 christos dns_rdatasetiter_t common; 182 1.21 christos dns_slabheader_t *current; 183 1.1 christos } rbtdb_rdatasetiter_t; 184 1.1 christos 185 1.1 christos /* 186 1.1 christos * Note that these iterators, unless created with either DNS_DB_NSEC3ONLY or 187 1.1 christos * DNS_DB_NONSEC3, will transparently move between the last node of the 188 1.1 christos * "regular" RBT ("chain" field) and the root node of the NSEC3 RBT 189 1.1 christos * ("nsec3chain" field) of the database in question, as if the latter was a 190 1.1 christos * successor to the former in lexical order. The "current" field always holds 191 1.1 christos * the address of either "chain" or "nsec3chain", depending on which RBT is 192 1.1 christos * being traversed at given time. 193 1.1 christos */ 194 1.7 christos static void 195 1.21 christos dbiterator_destroy(dns_dbiterator_t **iteratorp DNS__DB_FLARG); 196 1.7 christos static isc_result_t 197 1.21 christos dbiterator_first(dns_dbiterator_t *iterator DNS__DB_FLARG); 198 1.7 christos static isc_result_t 199 1.21 christos dbiterator_last(dns_dbiterator_t *iterator DNS__DB_FLARG); 200 1.7 christos static isc_result_t 201 1.21 christos dbiterator_seek(dns_dbiterator_t *iterator, 202 1.21 christos const dns_name_t *name DNS__DB_FLARG); 203 1.7 christos static isc_result_t 204 1.23 christos dbiterator_seek3(dns_dbiterator_t *iterator, 205 1.23 christos const dns_name_t *name DNS__DB_FLARG); 206 1.23 christos static isc_result_t 207 1.21 christos dbiterator_prev(dns_dbiterator_t *iterator DNS__DB_FLARG); 208 1.7 christos static isc_result_t 209 1.21 christos dbiterator_next(dns_dbiterator_t *iterator DNS__DB_FLARG); 210 1.7 christos static isc_result_t 211 1.7 christos dbiterator_current(dns_dbiterator_t *iterator, dns_dbnode_t **nodep, 212 1.21 christos dns_name_t *name DNS__DB_FLARG); 213 1.7 christos static isc_result_t 214 1.7 christos dbiterator_pause(dns_dbiterator_t *iterator); 215 1.7 christos static isc_result_t 216 1.7 christos dbiterator_origin(dns_dbiterator_t *iterator, dns_name_t *name); 217 1.1 christos 218 1.1 christos static dns_dbiteratormethods_t dbiterator_methods = { 219 1.23 christos dbiterator_destroy, dbiterator_first, dbiterator_last, 220 1.23 christos dbiterator_seek, dbiterator_seek3, dbiterator_prev, 221 1.23 christos dbiterator_next, dbiterator_current, dbiterator_pause, 222 1.23 christos dbiterator_origin 223 1.1 christos }; 224 1.1 christos 225 1.1 christos /* 226 1.3 christos * If 'paused' is true, then the tree lock is not being held. 227 1.1 christos */ 228 1.1 christos typedef struct rbtdb_dbiterator { 229 1.7 christos dns_dbiterator_t common; 230 1.7 christos bool paused; 231 1.7 christos bool new_origin; 232 1.7 christos isc_rwlocktype_t tree_locked; 233 1.7 christos isc_result_t result; 234 1.7 christos dns_fixedname_t name; 235 1.7 christos dns_fixedname_t origin; 236 1.7 christos dns_rbtnodechain_t chain; 237 1.7 christos dns_rbtnodechain_t nsec3chain; 238 1.7 christos dns_rbtnodechain_t *current; 239 1.7 christos dns_rbtnode_t *node; 240 1.20 christos enum { full, nonsec3, nsec3only } nsec3mode; 241 1.1 christos } rbtdb_dbiterator_t; 242 1.1 christos 243 1.7 christos static void 244 1.21 christos free_rbtdb(dns_rbtdb_t *rbtdb, bool log); 245 1.7 christos static void 246 1.21 christos setnsec3parameters(dns_db_t *db, dns_rbtdb_version_t *version); 247 1.1 christos 248 1.1 christos /*% 249 1.1 christos * 'init_count' is used to initialize 'newheader->count' which inturn 250 1.1 christos * is used to determine where in the cycle rrset-order cyclic starts. 251 1.1 christos * We don't lock this as we don't care about simultaneous updates. 252 1.1 christos */ 253 1.21 christos static atomic_uint_fast16_t init_count = 0; 254 1.1 christos 255 1.1 christos /* 256 1.1 christos * Locking 257 1.1 christos * 258 1.1 christos * If a routine is going to lock more than one lock in this module, then 259 1.1 christos * the locking must be done in the following order: 260 1.1 christos * 261 1.1 christos * Tree Lock 262 1.1 christos * 263 1.1 christos * Node Lock (Only one from the set may be locked at one time by 264 1.1 christos * any caller) 265 1.1 christos * 266 1.1 christos * Database Lock 267 1.1 christos * 268 1.1 christos * Failure to follow this hierarchy can result in deadlock. 269 1.1 christos */ 270 1.1 christos 271 1.1 christos /* 272 1.1 christos * Deleting Nodes 273 1.1 christos * 274 1.1 christos * For zone databases the node for the origin of the zone MUST NOT be deleted. 275 1.1 christos */ 276 1.1 christos 277 1.1 christos /* 278 1.1 christos * DB Routines 279 1.1 christos */ 280 1.1 christos 281 1.1 christos static void 282 1.21 christos update_rrsetstats(dns_stats_t *stats, const dns_typepair_t htype, 283 1.9 christos const uint_least16_t hattributes, const bool increment) { 284 1.1 christos dns_rdatastatstype_t statattributes = 0; 285 1.1 christos dns_rdatastatstype_t base = 0; 286 1.1 christos dns_rdatastatstype_t type; 287 1.21 christos dns_slabheader_t *header = &(dns_slabheader_t){ 288 1.15 christos .type = htype, 289 1.15 christos .attributes = hattributes, 290 1.10 rillig }; 291 1.1 christos 292 1.21 christos if (!EXISTS(header) || !STATCOUNT(header)) { 293 1.5 christos return; 294 1.5 christos } 295 1.5 christos 296 1.1 christos if (NEGATIVE(header)) { 297 1.7 christos if (NXDOMAIN(header)) { 298 1.1 christos statattributes = DNS_RDATASTATSTYPE_ATTR_NXDOMAIN; 299 1.7 christos } else { 300 1.1 christos statattributes = DNS_RDATASTATSTYPE_ATTR_NXRRSET; 301 1.21 christos base = DNS_TYPEPAIR_COVERS(header->type); 302 1.1 christos } 303 1.5 christos } else { 304 1.21 christos base = DNS_TYPEPAIR_TYPE(header->type); 305 1.5 christos } 306 1.1 christos 307 1.5 christos if (STALE(header)) { 308 1.1 christos statattributes |= DNS_RDATASTATSTYPE_ATTR_STALE; 309 1.5 christos } 310 1.5 christos if (ANCIENT(header)) { 311 1.5 christos statattributes |= DNS_RDATASTATSTYPE_ATTR_ANCIENT; 312 1.5 christos } 313 1.1 christos 314 1.1 christos type = DNS_RDATASTATSTYPE_VALUE(base, statattributes); 315 1.5 christos if (increment) { 316 1.21 christos dns_rdatasetstats_increment(stats, type); 317 1.5 christos } else { 318 1.21 christos dns_rdatasetstats_decrement(stats, type); 319 1.5 christos } 320 1.1 christos } 321 1.1 christos 322 1.21 christos void 323 1.21 christos dns__rbtdb_setttl(dns_slabheader_t *header, dns_ttl_t newttl) { 324 1.21 christos dns_ttl_t oldttl = header->ttl; 325 1.21 christos 326 1.21 christos header->ttl = newttl; 327 1.1 christos 328 1.21 christos if (header->db == NULL || !dns_db_iscache(header->db)) { 329 1.1 christos return; 330 1.1 christos } 331 1.1 christos 332 1.1 christos /* 333 1.21 christos * This is a cache. Adjust the heaps if necessary. 334 1.1 christos */ 335 1.21 christos if (header->heap == NULL || header->heap_index == 0 || newttl == oldttl) 336 1.21 christos { 337 1.7 christos return; 338 1.7 christos } 339 1.1 christos 340 1.7 christos if (newttl < oldttl) { 341 1.21 christos isc_heap_increased(header->heap, header->heap_index); 342 1.7 christos } else { 343 1.21 christos isc_heap_decreased(header->heap, header->heap_index); 344 1.7 christos } 345 1.20 christos 346 1.20 christos if (newttl == 0) { 347 1.21 christos isc_heap_delete(header->heap, header->heap_index); 348 1.20 christos } 349 1.1 christos } 350 1.1 christos 351 1.1 christos /*% 352 1.1 christos * These functions allow the heap code to rank the priority of each 353 1.3 christos * element. It returns true if v1 happens "sooner" than v2. 354 1.1 christos */ 355 1.3 christos static bool 356 1.1 christos ttl_sooner(void *v1, void *v2) { 357 1.21 christos dns_slabheader_t *h1 = v1; 358 1.21 christos dns_slabheader_t *h2 = v2; 359 1.1 christos 360 1.21 christos return h1->ttl < h2->ttl; 361 1.1 christos } 362 1.1 christos 363 1.7 christos /*% 364 1.7 christos * Return which RRset should be resigned sooner. If the RRsets have the 365 1.7 christos * same signing time, prefer the other RRset over the SOA RRset. 366 1.7 christos */ 367 1.3 christos static bool 368 1.1 christos resign_sooner(void *v1, void *v2) { 369 1.21 christos dns_slabheader_t *h1 = v1; 370 1.21 christos dns_slabheader_t *h2 = v2; 371 1.1 christos 372 1.21 christos return h1->resign < h2->resign || 373 1.21 christos (h1->resign == h2->resign && h1->resign_lsb < h2->resign_lsb) || 374 1.21 christos (h1->resign == h2->resign && h1->resign_lsb == h2->resign_lsb && 375 1.21 christos h2->type == DNS_SIGTYPE(dns_rdatatype_soa)); 376 1.1 christos } 377 1.1 christos 378 1.1 christos /*% 379 1.1 christos * This function sets the heap index into the header. 380 1.1 christos */ 381 1.1 christos static void 382 1.1 christos set_index(void *what, unsigned int idx) { 383 1.21 christos dns_slabheader_t *h = what; 384 1.1 christos 385 1.1 christos h->heap_index = idx; 386 1.1 christos } 387 1.1 christos 388 1.1 christos /*% 389 1.1 christos * Work out how many nodes can be deleted in the time between two 390 1.1 christos * requests to the nameserver. Smooth the resulting number and use it 391 1.1 christos * as a estimate for the number of nodes to be deleted in the next 392 1.1 christos * iteration. 393 1.1 christos */ 394 1.1 christos static unsigned int 395 1.1 christos adjust_quantum(unsigned int old, isc_time_t *start) { 396 1.7 christos unsigned int pps = dns_pps; /* packets per second */ 397 1.1 christos unsigned int interval; 398 1.3 christos uint64_t usecs; 399 1.1 christos isc_time_t end; 400 1.1 christos unsigned int nodes; 401 1.1 christos 402 1.7 christos if (pps < 100) { 403 1.1 christos pps = 100; 404 1.7 christos } 405 1.21 christos end = isc_time_now(); 406 1.1 christos 407 1.7 christos interval = 1000000 / pps; /* interval in usec */ 408 1.7 christos if (interval == 0) { 409 1.1 christos interval = 1; 410 1.7 christos } 411 1.1 christos usecs = isc_time_microdiff(&end, start); 412 1.1 christos if (usecs == 0) { 413 1.1 christos /* 414 1.1 christos * We were unable to measure the amount of time taken. 415 1.1 christos * Double the nodes deleted next time. 416 1.1 christos */ 417 1.1 christos old *= 2; 418 1.7 christos if (old > 1000) { 419 1.1 christos old = 1000; 420 1.7 christos } 421 1.21 christos return old; 422 1.1 christos } 423 1.1 christos nodes = old * interval; 424 1.1 christos nodes /= (unsigned int)usecs; 425 1.7 christos if (nodes == 0) { 426 1.1 christos nodes = 1; 427 1.7 christos } else if (nodes > 1000) { 428 1.1 christos nodes = 1000; 429 1.7 christos } 430 1.1 christos 431 1.1 christos /* Smooth */ 432 1.1 christos nodes = (nodes + old * 3) / 4; 433 1.1 christos 434 1.7 christos if (nodes != old) { 435 1.1 christos isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE, 436 1.1 christos DNS_LOGMODULE_CACHE, ISC_LOG_DEBUG(1), 437 1.1 christos "adjust_quantum: old=%d, new=%d", old, nodes); 438 1.7 christos } 439 1.1 christos 440 1.21 christos return nodes; 441 1.21 christos } 442 1.21 christos 443 1.21 christos static void 444 1.21 christos free_rbtdb_callback(void *arg) { 445 1.21 christos dns_rbtdb_t *rbtdb = (dns_rbtdb_t *)arg; 446 1.21 christos 447 1.21 christos free_rbtdb(rbtdb, true); 448 1.1 christos } 449 1.1 christos 450 1.1 christos static void 451 1.21 christos free_rbtdb(dns_rbtdb_t *rbtdb, bool log) { 452 1.1 christos unsigned int i; 453 1.1 christos isc_result_t result; 454 1.1 christos char buf[DNS_NAME_FORMATSIZE]; 455 1.21 christos dns_rbt_t **treep = NULL; 456 1.1 christos isc_time_t start; 457 1.1 christos 458 1.1 christos REQUIRE(rbtdb->current_version != NULL || EMPTY(rbtdb->open_versions)); 459 1.1 christos REQUIRE(rbtdb->future_version == NULL); 460 1.1 christos 461 1.1 christos if (rbtdb->current_version != NULL) { 462 1.9 christos isc_refcount_decrementz(&rbtdb->current_version->references); 463 1.21 christos 464 1.21 christos isc_refcount_destroy(&rbtdb->current_version->references); 465 1.1 christos UNLINK(rbtdb->open_versions, rbtdb->current_version, link); 466 1.22 christos cds_wfs_destroy(&rbtdb->current_version->glue_stack); 467 1.1 christos isc_rwlock_destroy(&rbtdb->current_version->rwlock); 468 1.1 christos isc_mem_put(rbtdb->common.mctx, rbtdb->current_version, 469 1.21 christos sizeof(*rbtdb->current_version)); 470 1.1 christos } 471 1.1 christos 472 1.1 christos /* 473 1.1 christos * We assume the number of remaining dead nodes is reasonably small; 474 1.1 christos * the overhead of unlinking all nodes here should be negligible. 475 1.1 christos */ 476 1.1 christos for (i = 0; i < rbtdb->node_lock_count; i++) { 477 1.21 christos dns_rbtnode_t *node = NULL; 478 1.20 christos 479 1.1 christos node = ISC_LIST_HEAD(rbtdb->deadnodes[i]); 480 1.1 christos while (node != NULL) { 481 1.1 christos ISC_LIST_UNLINK(rbtdb->deadnodes[i], node, deadlink); 482 1.1 christos node = ISC_LIST_HEAD(rbtdb->deadnodes[i]); 483 1.1 christos } 484 1.1 christos } 485 1.1 christos 486 1.21 christos rbtdb->quantum = (rbtdb->loop != NULL) ? 100 : 0; 487 1.1 christos 488 1.1 christos for (;;) { 489 1.1 christos /* 490 1.1 christos * pick the next tree to (start to) destroy 491 1.1 christos */ 492 1.1 christos treep = &rbtdb->tree; 493 1.1 christos if (*treep == NULL) { 494 1.1 christos treep = &rbtdb->nsec; 495 1.1 christos if (*treep == NULL) { 496 1.1 christos treep = &rbtdb->nsec3; 497 1.1 christos /* 498 1.1 christos * we're finished after clear cutting 499 1.1 christos */ 500 1.7 christos if (*treep == NULL) { 501 1.1 christos break; 502 1.7 christos } 503 1.1 christos } 504 1.1 christos } 505 1.1 christos 506 1.21 christos start = isc_time_now(); 507 1.21 christos result = dns_rbt_destroy(treep, rbtdb->quantum); 508 1.1 christos if (result == ISC_R_QUOTA) { 509 1.21 christos INSIST(rbtdb->loop != NULL); 510 1.7 christos if (rbtdb->quantum != 0) { 511 1.1 christos rbtdb->quantum = adjust_quantum(rbtdb->quantum, 512 1.1 christos &start); 513 1.7 christos } 514 1.21 christos isc_async_run(rbtdb->loop, free_rbtdb_callback, rbtdb); 515 1.1 christos return; 516 1.1 christos } 517 1.1 christos INSIST(result == ISC_R_SUCCESS && *treep == NULL); 518 1.1 christos } 519 1.1 christos 520 1.1 christos if (log) { 521 1.7 christos if (dns_name_dynamic(&rbtdb->common.origin)) { 522 1.1 christos dns_name_format(&rbtdb->common.origin, buf, 523 1.1 christos sizeof(buf)); 524 1.7 christos } else { 525 1.1 christos strlcpy(buf, "<UNKNOWN>", sizeof(buf)); 526 1.7 christos } 527 1.1 christos isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE, 528 1.1 christos DNS_LOGMODULE_CACHE, ISC_LOG_DEBUG(1), 529 1.1 christos "done free_rbtdb(%s)", buf); 530 1.1 christos } 531 1.7 christos if (dns_name_dynamic(&rbtdb->common.origin)) { 532 1.1 christos dns_name_free(&rbtdb->common.origin, rbtdb->common.mctx); 533 1.7 christos } 534 1.1 christos for (i = 0; i < rbtdb->node_lock_count; i++) { 535 1.1 christos isc_refcount_destroy(&rbtdb->node_locks[i].references); 536 1.1 christos NODE_DESTROYLOCK(&rbtdb->node_locks[i].lock); 537 1.1 christos } 538 1.1 christos 539 1.1 christos /* 540 1.1 christos * Clean up LRU / re-signing order lists. 541 1.1 christos */ 542 1.21 christos if (rbtdb->lru != NULL) { 543 1.7 christos for (i = 0; i < rbtdb->node_lock_count; i++) { 544 1.21 christos INSIST(ISC_LIST_EMPTY(rbtdb->lru[i])); 545 1.7 christos } 546 1.21 christos isc_mem_cput(rbtdb->common.mctx, rbtdb->lru, 547 1.21 christos rbtdb->node_lock_count, 548 1.21 christos sizeof(dns_slabheaderlist_t)); 549 1.1 christos } 550 1.1 christos /* 551 1.1 christos * Clean up dead node buckets. 552 1.1 christos */ 553 1.1 christos if (rbtdb->deadnodes != NULL) { 554 1.7 christos for (i = 0; i < rbtdb->node_lock_count; i++) { 555 1.1 christos INSIST(ISC_LIST_EMPTY(rbtdb->deadnodes[i])); 556 1.7 christos } 557 1.21 christos isc_mem_cput(rbtdb->common.mctx, rbtdb->deadnodes, 558 1.21 christos rbtdb->node_lock_count, sizeof(dns_rbtnodelist_t)); 559 1.1 christos } 560 1.1 christos /* 561 1.1 christos * Clean up heap objects. 562 1.1 christos */ 563 1.1 christos if (rbtdb->heaps != NULL) { 564 1.7 christos for (i = 0; i < rbtdb->node_lock_count; i++) { 565 1.1 christos isc_heap_destroy(&rbtdb->heaps[i]); 566 1.7 christos } 567 1.21 christos isc_mem_cput(rbtdb->hmctx, rbtdb->heaps, rbtdb->node_lock_count, 568 1.21 christos sizeof(isc_heap_t *)); 569 1.1 christos } 570 1.1 christos 571 1.7 christos if (rbtdb->rrsetstats != NULL) { 572 1.1 christos dns_stats_detach(&rbtdb->rrsetstats); 573 1.7 christos } 574 1.7 christos if (rbtdb->cachestats != NULL) { 575 1.1 christos isc_stats_detach(&rbtdb->cachestats); 576 1.7 christos } 577 1.7 christos if (rbtdb->gluecachestats != NULL) { 578 1.1 christos isc_stats_detach(&rbtdb->gluecachestats); 579 1.7 christos } 580 1.1 christos 581 1.21 christos isc_mem_cput(rbtdb->common.mctx, rbtdb->node_locks, 582 1.21 christos rbtdb->node_lock_count, sizeof(db_nodelock_t)); 583 1.21 christos TREE_DESTROYLOCK(&rbtdb->tree_lock); 584 1.21 christos isc_refcount_destroy(&rbtdb->common.references); 585 1.21 christos if (rbtdb->loop != NULL) { 586 1.21 christos isc_loop_detach(&rbtdb->loop); 587 1.20 christos } 588 1.1 christos 589 1.21 christos isc_rwlock_destroy(&rbtdb->lock); 590 1.1 christos rbtdb->common.magic = 0; 591 1.1 christos rbtdb->common.impmagic = 0; 592 1.1 christos isc_mem_detach(&rbtdb->hmctx); 593 1.1 christos 594 1.21 christos if (rbtdb->common.update_listeners != NULL) { 595 1.21 christos INSIST(!cds_lfht_destroy(rbtdb->common.update_listeners, NULL)); 596 1.21 christos } 597 1.1 christos 598 1.1 christos isc_mem_putanddetach(&rbtdb->common.mctx, rbtdb, sizeof(*rbtdb)); 599 1.1 christos } 600 1.1 christos 601 1.21 christos void 602 1.21 christos dns__rbtdb_destroy(dns_db_t *arg) { 603 1.21 christos dns_rbtdb_t *rbtdb = (dns_rbtdb_t *)arg; 604 1.3 christos bool want_free = false; 605 1.1 christos unsigned int i; 606 1.1 christos unsigned int inactive = 0; 607 1.1 christos 608 1.1 christos /* XXX check for open versions here */ 609 1.1 christos 610 1.7 christos if (rbtdb->soanode != NULL) { 611 1.1 christos dns_db_detachnode((dns_db_t *)rbtdb, &rbtdb->soanode); 612 1.7 christos } 613 1.7 christos if (rbtdb->nsnode != NULL) { 614 1.1 christos dns_db_detachnode((dns_db_t *)rbtdb, &rbtdb->nsnode); 615 1.7 christos } 616 1.1 christos 617 1.1 christos /* 618 1.1 christos * The current version's glue table needs to be freed early 619 1.1 christos * so the nodes are dereferenced before we check the active 620 1.1 christos * node count below. 621 1.1 christos */ 622 1.1 christos if (rbtdb->current_version != NULL) { 623 1.22 christos dns__db_cleanup_gluelists(&rbtdb->current_version->glue_stack); 624 1.1 christos } 625 1.1 christos 626 1.1 christos /* 627 1.1 christos * Even though there are no external direct references, there still 628 1.1 christos * may be nodes in use. 629 1.1 christos */ 630 1.1 christos for (i = 0; i < rbtdb->node_lock_count; i++) { 631 1.21 christos isc_rwlocktype_t nodelock = isc_rwlocktype_none; 632 1.21 christos NODE_WRLOCK(&rbtdb->node_locks[i].lock, &nodelock); 633 1.3 christos rbtdb->node_locks[i].exiting = true; 634 1.1 christos if (isc_refcount_current(&rbtdb->node_locks[i].references) == 0) 635 1.1 christos { 636 1.1 christos inactive++; 637 1.1 christos } 638 1.21 christos NODE_UNLOCK(&rbtdb->node_locks[i].lock, &nodelock); 639 1.1 christos } 640 1.1 christos 641 1.1 christos if (inactive != 0) { 642 1.21 christos RWLOCK(&rbtdb->lock, isc_rwlocktype_write); 643 1.1 christos rbtdb->active -= inactive; 644 1.1 christos if (rbtdb->active == 0) { 645 1.3 christos want_free = true; 646 1.1 christos } 647 1.21 christos RWUNLOCK(&rbtdb->lock, isc_rwlocktype_write); 648 1.1 christos if (want_free) { 649 1.1 christos char buf[DNS_NAME_FORMATSIZE]; 650 1.1 christos if (dns_name_dynamic(&rbtdb->common.origin)) { 651 1.1 christos dns_name_format(&rbtdb->common.origin, buf, 652 1.1 christos sizeof(buf)); 653 1.1 christos } else { 654 1.1 christos strlcpy(buf, "<UNKNOWN>", sizeof(buf)); 655 1.1 christos } 656 1.1 christos isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE, 657 1.1 christos DNS_LOGMODULE_CACHE, ISC_LOG_DEBUG(1), 658 1.1 christos "calling free_rbtdb(%s)", buf); 659 1.21 christos free_rbtdb(rbtdb, true); 660 1.1 christos } 661 1.1 christos } 662 1.1 christos } 663 1.1 christos 664 1.21 christos void 665 1.21 christos dns__rbtdb_currentversion(dns_db_t *db, dns_dbversion_t **versionp) { 666 1.1 christos dns_rbtdb_t *rbtdb = (dns_rbtdb_t *)db; 667 1.21 christos dns_rbtdb_version_t *version = NULL; 668 1.1 christos 669 1.1 christos REQUIRE(VALID_RBTDB(rbtdb)); 670 1.1 christos 671 1.21 christos RWLOCK(&rbtdb->lock, isc_rwlocktype_read); 672 1.1 christos version = rbtdb->current_version; 673 1.3 christos isc_refcount_increment(&version->references); 674 1.21 christos RWUNLOCK(&rbtdb->lock, isc_rwlocktype_read); 675 1.1 christos 676 1.1 christos *versionp = (dns_dbversion_t *)version; 677 1.1 christos } 678 1.1 christos 679 1.21 christos static dns_rbtdb_version_t * 680 1.21 christos allocate_version(isc_mem_t *mctx, uint32_t serial, unsigned int references, 681 1.21 christos bool writer) { 682 1.21 christos dns_rbtdb_version_t *version = isc_mem_get(mctx, sizeof(*version)); 683 1.21 christos *version = (dns_rbtdb_version_t){ 684 1.21 christos .serial = serial, 685 1.21 christos .writer = writer, 686 1.21 christos .changed_list = ISC_LIST_INITIALIZER, 687 1.21 christos .resigned_list = ISC_LIST_INITIALIZER, 688 1.21 christos .link = ISC_LINK_INITIALIZER, 689 1.21 christos }; 690 1.3 christos 691 1.22 christos cds_wfs_init(&version->glue_stack); 692 1.22 christos 693 1.3 christos isc_refcount_init(&version->references, references); 694 1.1 christos 695 1.21 christos return version; 696 1.1 christos } 697 1.1 christos 698 1.21 christos isc_result_t 699 1.21 christos dns__rbtdb_newversion(dns_db_t *db, dns_dbversion_t **versionp) { 700 1.1 christos dns_rbtdb_t *rbtdb = (dns_rbtdb_t *)db; 701 1.21 christos dns_rbtdb_version_t *version = NULL; 702 1.1 christos 703 1.1 christos REQUIRE(VALID_RBTDB(rbtdb)); 704 1.1 christos REQUIRE(versionp != NULL && *versionp == NULL); 705 1.1 christos REQUIRE(rbtdb->future_version == NULL); 706 1.1 christos 707 1.21 christos RWLOCK(&rbtdb->lock, isc_rwlocktype_write); 708 1.7 christos RUNTIME_CHECK(rbtdb->next_serial != 0); /* XXX Error? */ 709 1.1 christos version = allocate_version(rbtdb->common.mctx, rbtdb->next_serial, 1, 710 1.3 christos true); 711 1.13 christos version->rbtdb = rbtdb; 712 1.13 christos version->commit_ok = true; 713 1.13 christos version->secure = rbtdb->current_version->secure; 714 1.13 christos version->havensec3 = rbtdb->current_version->havensec3; 715 1.13 christos if (version->havensec3) { 716 1.13 christos version->flags = rbtdb->current_version->flags; 717 1.13 christos version->iterations = rbtdb->current_version->iterations; 718 1.13 christos version->hash = rbtdb->current_version->hash; 719 1.13 christos version->salt_length = rbtdb->current_version->salt_length; 720 1.13 christos memmove(version->salt, rbtdb->current_version->salt, 721 1.13 christos version->salt_length); 722 1.13 christos } else { 723 1.13 christos version->flags = 0; 724 1.13 christos version->iterations = 0; 725 1.13 christos version->hash = 0; 726 1.13 christos version->salt_length = 0; 727 1.13 christos memset(version->salt, 0, sizeof(version->salt)); 728 1.13 christos } 729 1.22 christos isc_rwlock_init(&version->rwlock); 730 1.13 christos RWLOCK(&rbtdb->current_version->rwlock, isc_rwlocktype_read); 731 1.13 christos version->records = rbtdb->current_version->records; 732 1.13 christos version->xfrsize = rbtdb->current_version->xfrsize; 733 1.13 christos RWUNLOCK(&rbtdb->current_version->rwlock, isc_rwlocktype_read); 734 1.13 christos rbtdb->next_serial++; 735 1.13 christos rbtdb->future_version = version; 736 1.21 christos RWUNLOCK(&rbtdb->lock, isc_rwlocktype_write); 737 1.1 christos 738 1.1 christos *versionp = version; 739 1.1 christos 740 1.21 christos return ISC_R_SUCCESS; 741 1.1 christos } 742 1.1 christos 743 1.21 christos void 744 1.21 christos dns__rbtdb_attachversion(dns_db_t *db, dns_dbversion_t *source, 745 1.21 christos dns_dbversion_t **targetp) { 746 1.1 christos dns_rbtdb_t *rbtdb = (dns_rbtdb_t *)db; 747 1.21 christos dns_rbtdb_version_t *rbtversion = source; 748 1.1 christos 749 1.1 christos REQUIRE(VALID_RBTDB(rbtdb)); 750 1.1 christos INSIST(rbtversion != NULL && rbtversion->rbtdb == rbtdb); 751 1.1 christos 752 1.3 christos isc_refcount_increment(&rbtversion->references); 753 1.1 christos 754 1.1 christos *targetp = rbtversion; 755 1.1 christos } 756 1.1 christos 757 1.1 christos static rbtdb_changed_t * 758 1.21 christos add_changed(dns_slabheader_t *header, 759 1.21 christos dns_rbtdb_version_t *version DNS__DB_FLARG) { 760 1.21 christos rbtdb_changed_t *changed = NULL; 761 1.21 christos dns_rbtdb_t *rbtdb = (dns_rbtdb_t *)header->db; 762 1.1 christos 763 1.1 christos /* 764 1.1 christos * Caller must be holding the node lock if its reference must be 765 1.1 christos * protected by the lock. 766 1.1 christos */ 767 1.1 christos 768 1.1 christos changed = isc_mem_get(rbtdb->common.mctx, sizeof(*changed)); 769 1.1 christos 770 1.21 christos RWLOCK(&rbtdb->lock, isc_rwlocktype_write); 771 1.1 christos 772 1.1 christos REQUIRE(version->writer); 773 1.1 christos 774 1.1 christos if (changed != NULL) { 775 1.21 christos dns_rbtnode_t *node = (dns_rbtnode_t *)header->node; 776 1.21 christos uint_fast32_t refs = isc_refcount_increment(&node->references); 777 1.21 christos #if DNS_DB_NODETRACE 778 1.21 christos fprintf(stderr, 779 1.21 christos "incr:node:%s:%s:%u:%p->references = %" PRIuFAST32 "\n", 780 1.21 christos func, file, line, node, refs + 1); 781 1.21 christos #else 782 1.21 christos UNUSED(refs); 783 1.21 christos #endif 784 1.1 christos changed->node = node; 785 1.3 christos changed->dirty = false; 786 1.1 christos ISC_LIST_INITANDAPPEND(version->changed_list, changed, link); 787 1.7 christos } else { 788 1.3 christos version->commit_ok = false; 789 1.7 christos } 790 1.1 christos 791 1.21 christos RWUNLOCK(&rbtdb->lock, isc_rwlocktype_write); 792 1.1 christos 793 1.21 christos return changed; 794 1.1 christos } 795 1.1 christos 796 1.15 christos static void 797 1.21 christos rollback_node(dns_rbtnode_t *node, uint32_t serial) { 798 1.21 christos dns_slabheader_t *header = NULL, *dcurrent = NULL; 799 1.3 christos bool make_dirty = false; 800 1.1 christos 801 1.1 christos /* 802 1.1 christos * Caller must hold the node lock. 803 1.1 christos */ 804 1.1 christos 805 1.1 christos /* 806 1.1 christos * We set the IGNORE attribute on rdatasets with serial number 807 1.1 christos * 'serial'. When the reference count goes to zero, these rdatasets 808 1.1 christos * will be cleaned up; until that time, they will be ignored. 809 1.1 christos */ 810 1.1 christos for (header = node->data; header != NULL; header = header->next) { 811 1.1 christos if (header->serial == serial) { 812 1.21 christos DNS_SLABHEADER_SETATTR(header, 813 1.21 christos DNS_SLABHEADERATTR_IGNORE); 814 1.3 christos make_dirty = true; 815 1.1 christos } 816 1.7 christos for (dcurrent = header->down; dcurrent != NULL; 817 1.16 christos dcurrent = dcurrent->down) 818 1.16 christos { 819 1.1 christos if (dcurrent->serial == serial) { 820 1.21 christos DNS_SLABHEADER_SETATTR( 821 1.21 christos dcurrent, DNS_SLABHEADERATTR_IGNORE); 822 1.3 christos make_dirty = true; 823 1.1 christos } 824 1.1 christos } 825 1.1 christos } 826 1.7 christos if (make_dirty) { 827 1.1 christos node->dirty = 1; 828 1.7 christos } 829 1.1 christos } 830 1.1 christos 831 1.21 christos void 832 1.21 christos dns__rbtdb_mark(dns_slabheader_t *header, uint_least16_t flag) { 833 1.9 christos uint_least16_t attributes = atomic_load_acquire(&header->attributes); 834 1.9 christos uint_least16_t newattributes = 0; 835 1.21 christos dns_stats_t *stats = NULL; 836 1.9 christos 837 1.1 christos /* 838 1.1 christos * If we are already ancient there is nothing to do. 839 1.1 christos */ 840 1.9 christos do { 841 1.21 christos if ((attributes & flag) != 0) { 842 1.9 christos return; 843 1.9 christos } 844 1.21 christos newattributes = attributes | flag; 845 1.9 christos } while (!atomic_compare_exchange_weak_acq_rel( 846 1.9 christos &header->attributes, &attributes, newattributes)); 847 1.5 christos 848 1.5 christos /* 849 1.21 christos * Decrement and increment the stats counter for the appropriate 850 1.21 christos * RRtype. 851 1.5 christos */ 852 1.21 christos stats = dns_db_getrrsetstats(header->db); 853 1.21 christos if (stats != NULL) { 854 1.21 christos update_rrsetstats(stats, header->type, attributes, false); 855 1.21 christos update_rrsetstats(stats, header->type, newattributes, true); 856 1.21 christos } 857 1.5 christos } 858 1.5 christos 859 1.22 christos void 860 1.22 christos dns__rbtdb_mark_ancient(dns_slabheader_t *header) { 861 1.21 christos dns__rbtdb_setttl(header, 0); 862 1.21 christos dns__rbtdb_mark(header, DNS_SLABHEADERATTR_ANCIENT); 863 1.21 christos RBTDB_HEADERNODE(header)->dirty = 1; 864 1.1 christos } 865 1.1 christos 866 1.15 christos static void 867 1.21 christos clean_stale_headers(dns_slabheader_t *top) { 868 1.21 christos dns_slabheader_t *d = NULL, *down_next = NULL; 869 1.1 christos 870 1.1 christos for (d = top->down; d != NULL; d = down_next) { 871 1.1 christos down_next = d->down; 872 1.21 christos dns_slabheader_destroy(&d); 873 1.1 christos } 874 1.1 christos top->down = NULL; 875 1.1 christos } 876 1.1 christos 877 1.15 christos static void 878 1.1 christos clean_cache_node(dns_rbtdb_t *rbtdb, dns_rbtnode_t *node) { 879 1.21 christos dns_slabheader_t *current = NULL, *top_prev = NULL, *top_next = NULL; 880 1.1 christos 881 1.1 christos /* 882 1.1 christos * Caller must be holding the node lock. 883 1.1 christos */ 884 1.1 christos 885 1.1 christos for (current = node->data; current != NULL; current = top_next) { 886 1.1 christos top_next = current->next; 887 1.21 christos clean_stale_headers(current); 888 1.1 christos /* 889 1.7 christos * If current is nonexistent, ancient, or stale and 890 1.7 christos * we are not keeping stale, we can clean it up. 891 1.1 christos */ 892 1.1 christos if (NONEXISTENT(current) || ANCIENT(current) || 893 1.7 christos (STALE(current) && !KEEPSTALE(rbtdb))) 894 1.7 christos { 895 1.7 christos if (top_prev != NULL) { 896 1.1 christos top_prev->next = current->next; 897 1.7 christos } else { 898 1.1 christos node->data = current->next; 899 1.7 christos } 900 1.21 christos dns_slabheader_destroy(¤t); 901 1.7 christos } else { 902 1.1 christos top_prev = current; 903 1.7 christos } 904 1.1 christos } 905 1.1 christos node->dirty = 0; 906 1.1 christos } 907 1.1 christos 908 1.15 christos static void 909 1.21 christos clean_zone_node(dns_rbtnode_t *node, uint32_t least_serial) { 910 1.21 christos dns_slabheader_t *current = NULL, *dcurrent = NULL; 911 1.21 christos dns_slabheader_t *down_next = NULL, *dparent = NULL; 912 1.21 christos dns_slabheader_t *top_prev = NULL, *top_next = NULL; 913 1.3 christos bool still_dirty = false; 914 1.1 christos 915 1.1 christos /* 916 1.1 christos * Caller must be holding the node lock. 917 1.1 christos */ 918 1.1 christos REQUIRE(least_serial != 0); 919 1.1 christos 920 1.1 christos for (current = node->data; current != NULL; current = top_next) { 921 1.1 christos top_next = current->next; 922 1.1 christos 923 1.1 christos /* 924 1.1 christos * First, we clean up any instances of multiple rdatasets 925 1.1 christos * with the same serial number, or that have the IGNORE 926 1.1 christos * attribute. 927 1.1 christos */ 928 1.1 christos dparent = current; 929 1.7 christos for (dcurrent = current->down; dcurrent != NULL; 930 1.16 christos dcurrent = down_next) 931 1.16 christos { 932 1.1 christos down_next = dcurrent->down; 933 1.1 christos INSIST(dcurrent->serial <= dparent->serial); 934 1.1 christos if (dcurrent->serial == dparent->serial || 935 1.16 christos IGNORE(dcurrent)) 936 1.16 christos { 937 1.7 christos if (down_next != NULL) { 938 1.1 christos down_next->next = dparent; 939 1.7 christos } 940 1.1 christos dparent->down = down_next; 941 1.21 christos dns_slabheader_destroy(&dcurrent); 942 1.7 christos } else { 943 1.1 christos dparent = dcurrent; 944 1.7 christos } 945 1.1 christos } 946 1.1 christos 947 1.1 christos /* 948 1.1 christos * We've now eliminated all IGNORE datasets with the possible 949 1.1 christos * exception of current, which we now check. 950 1.1 christos */ 951 1.1 christos if (IGNORE(current)) { 952 1.1 christos down_next = current->down; 953 1.1 christos if (down_next == NULL) { 954 1.7 christos if (top_prev != NULL) { 955 1.1 christos top_prev->next = current->next; 956 1.7 christos } else { 957 1.1 christos node->data = current->next; 958 1.7 christos } 959 1.21 christos dns_slabheader_destroy(¤t); 960 1.1 christos /* 961 1.1 christos * current no longer exists, so we can 962 1.1 christos * just continue with the loop. 963 1.1 christos */ 964 1.1 christos continue; 965 1.1 christos } else { 966 1.1 christos /* 967 1.1 christos * Pull up current->down, making it the new 968 1.1 christos * current. 969 1.1 christos */ 970 1.7 christos if (top_prev != NULL) { 971 1.1 christos top_prev->next = down_next; 972 1.7 christos } else { 973 1.1 christos node->data = down_next; 974 1.7 christos } 975 1.1 christos down_next->next = top_next; 976 1.21 christos dns_slabheader_destroy(¤t); 977 1.1 christos current = down_next; 978 1.1 christos } 979 1.1 christos } 980 1.1 christos 981 1.1 christos /* 982 1.1 christos * We now try to find the first down node less than the 983 1.1 christos * least serial. 984 1.1 christos */ 985 1.1 christos dparent = current; 986 1.7 christos for (dcurrent = current->down; dcurrent != NULL; 987 1.16 christos dcurrent = down_next) 988 1.16 christos { 989 1.1 christos down_next = dcurrent->down; 990 1.7 christos if (dcurrent->serial < least_serial) { 991 1.1 christos break; 992 1.7 christos } 993 1.1 christos dparent = dcurrent; 994 1.1 christos } 995 1.1 christos 996 1.1 christos /* 997 1.1 christos * If there is a such an rdataset, delete it and any older 998 1.1 christos * versions. 999 1.1 christos */ 1000 1.1 christos if (dcurrent != NULL) { 1001 1.1 christos do { 1002 1.1 christos down_next = dcurrent->down; 1003 1.1 christos INSIST(dcurrent->serial <= least_serial); 1004 1.21 christos dns_slabheader_destroy(&dcurrent); 1005 1.1 christos dcurrent = down_next; 1006 1.1 christos } while (dcurrent != NULL); 1007 1.1 christos dparent->down = NULL; 1008 1.1 christos } 1009 1.1 christos 1010 1.1 christos /* 1011 1.1 christos * Note. The serial number of 'current' might be less than 1012 1.1 christos * least_serial too, but we cannot delete it because it is 1013 1.1 christos * the most recent version, unless it is a NONEXISTENT 1014 1.1 christos * rdataset. 1015 1.1 christos */ 1016 1.1 christos if (current->down != NULL) { 1017 1.3 christos still_dirty = true; 1018 1.1 christos top_prev = current; 1019 1.1 christos } else { 1020 1.1 christos /* 1021 1.1 christos * If this is a NONEXISTENT rdataset, we can delete it. 1022 1.1 christos */ 1023 1.1 christos if (NONEXISTENT(current)) { 1024 1.7 christos if (top_prev != NULL) { 1025 1.1 christos top_prev->next = current->next; 1026 1.7 christos } else { 1027 1.1 christos node->data = current->next; 1028 1.7 christos } 1029 1.21 christos dns_slabheader_destroy(¤t); 1030 1.7 christos } else { 1031 1.1 christos top_prev = current; 1032 1.7 christos } 1033 1.1 christos } 1034 1.1 christos } 1035 1.7 christos if (!still_dirty) { 1036 1.1 christos node->dirty = 0; 1037 1.7 christos } 1038 1.1 christos } 1039 1.1 christos 1040 1.7 christos /* 1041 1.7 christos * tree_lock(write) must be held. 1042 1.7 christos */ 1043 1.1 christos static void 1044 1.1 christos delete_node(dns_rbtdb_t *rbtdb, dns_rbtnode_t *node) { 1045 1.21 christos dns_rbtnode_t *nsecnode = NULL; 1046 1.1 christos dns_fixedname_t fname; 1047 1.21 christos dns_name_t *name = NULL; 1048 1.1 christos isc_result_t result = ISC_R_UNEXPECTED; 1049 1.1 christos 1050 1.1 christos INSIST(!ISC_LINK_LINKED(node, deadlink)); 1051 1.1 christos 1052 1.1 christos if (isc_log_wouldlog(dns_lctx, ISC_LOG_DEBUG(1))) { 1053 1.1 christos char printname[DNS_NAME_FORMATSIZE]; 1054 1.7 christos isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE, 1055 1.7 christos DNS_LOGMODULE_CACHE, ISC_LOG_DEBUG(1), 1056 1.7 christos "delete_node(): %p %s (bucket %d)", node, 1057 1.7 christos dns_rbt_formatnodename(node, printname, 1058 1.7 christos sizeof(printname)), 1059 1.1 christos node->locknum); 1060 1.1 christos } 1061 1.1 christos 1062 1.1 christos switch (node->nsec) { 1063 1.21 christos case DNS_DB_NSEC_NORMAL: 1064 1.19 christos result = dns_rbt_deletenode(rbtdb->tree, node, false); 1065 1.19 christos break; 1066 1.21 christos case DNS_DB_NSEC_HAS_NSEC: 1067 1.1 christos /* 1068 1.1 christos * Though this may be wasteful, it has to be done before 1069 1.1 christos * node is deleted. 1070 1.1 christos */ 1071 1.1 christos name = dns_fixedname_initname(&fname); 1072 1.1 christos dns_rbt_fullnamefromnode(node, name); 1073 1.1 christos /* 1074 1.1 christos * Delete the corresponding node from the auxiliary NSEC 1075 1.1 christos * tree before deleting from the main tree. 1076 1.1 christos */ 1077 1.1 christos nsecnode = NULL; 1078 1.1 christos result = dns_rbt_findnode(rbtdb->nsec, name, NULL, &nsecnode, 1079 1.7 christos NULL, DNS_RBTFIND_EMPTYDATA, NULL, 1080 1.7 christos NULL); 1081 1.1 christos if (result != ISC_R_SUCCESS) { 1082 1.1 christos isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE, 1083 1.1 christos DNS_LOGMODULE_CACHE, ISC_LOG_WARNING, 1084 1.1 christos "delete_node: " 1085 1.1 christos "dns_rbt_findnode(nsec): %s", 1086 1.1 christos isc_result_totext(result)); 1087 1.1 christos } else { 1088 1.1 christos result = dns_rbt_deletenode(rbtdb->nsec, nsecnode, 1089 1.3 christos false); 1090 1.1 christos if (result != ISC_R_SUCCESS) { 1091 1.7 christos isc_log_write( 1092 1.7 christos dns_lctx, DNS_LOGCATEGORY_DATABASE, 1093 1.7 christos DNS_LOGMODULE_CACHE, ISC_LOG_WARNING, 1094 1.7 christos "delete_node(): " 1095 1.7 christos "dns_rbt_deletenode(nsecnode): %s", 1096 1.7 christos isc_result_totext(result)); 1097 1.1 christos } 1098 1.1 christos } 1099 1.3 christos result = dns_rbt_deletenode(rbtdb->tree, node, false); 1100 1.1 christos break; 1101 1.21 christos case DNS_DB_NSEC_NSEC: 1102 1.3 christos result = dns_rbt_deletenode(rbtdb->nsec, node, false); 1103 1.1 christos break; 1104 1.21 christos case DNS_DB_NSEC_NSEC3: 1105 1.3 christos result = dns_rbt_deletenode(rbtdb->nsec3, node, false); 1106 1.1 christos break; 1107 1.1 christos } 1108 1.1 christos if (result != ISC_R_SUCCESS) { 1109 1.7 christos isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE, 1110 1.7 christos DNS_LOGMODULE_CACHE, ISC_LOG_WARNING, 1111 1.1 christos "delete_node(): " 1112 1.1 christos "dns_rbt_deletenode: %s", 1113 1.1 christos isc_result_totext(result)); 1114 1.1 christos } 1115 1.1 christos } 1116 1.1 christos 1117 1.22 christos static void 1118 1.22 christos rbtnode_erefs_increment(dns_rbtdb_t *rbtdb, dns_rbtnode_t *node DNS__DB_FLARG) { 1119 1.22 christos uint_fast32_t refs = isc_refcount_increment0(&node->references); 1120 1.22 christos 1121 1.22 christos #if DNS_DB_NODETRACE 1122 1.22 christos fprintf(stderr, "incr:node:%s:%s:%u:%p->references = %" PRIuFAST32 "\n", 1123 1.22 christos func, file, line, node, refs + 1); 1124 1.22 christos #endif 1125 1.22 christos 1126 1.22 christos if (refs > 0) { 1127 1.22 christos return; 1128 1.22 christos } 1129 1.22 christos 1130 1.22 christos /* this is the first reference to the node */ 1131 1.22 christos refs = isc_refcount_increment0( 1132 1.22 christos &rbtdb->node_locks[node->locknum].references); 1133 1.22 christos #if DNS_DB_NODETRACE 1134 1.22 christos fprintf(stderr, 1135 1.22 christos "incr:nodelock:%s:%s:%u:%p:%p->references = " 1136 1.22 christos "%" PRIuFAST32 "\n", 1137 1.22 christos func, file, line, node, &rbtdb->node_locks[node->locknum], 1138 1.22 christos refs + 1); 1139 1.22 christos #else 1140 1.22 christos UNUSED(refs); 1141 1.22 christos #endif 1142 1.22 christos } 1143 1.22 christos 1144 1.1 christos /* 1145 1.1 christos * Caller must be holding the node lock. 1146 1.1 christos */ 1147 1.21 christos void 1148 1.22 christos dns__rbtnode_acquire(dns_rbtdb_t *rbtdb, dns_rbtnode_t *node, 1149 1.22 christos isc_rwlocktype_t nlocktype DNS__DB_FLARG) { 1150 1.20 christos if (nlocktype == isc_rwlocktype_write && 1151 1.20 christos ISC_LINK_LINKED(node, deadlink)) 1152 1.8 christos { 1153 1.8 christos ISC_LIST_UNLINK(rbtdb->deadnodes[node->locknum], node, 1154 1.8 christos deadlink); 1155 1.8 christos } 1156 1.21 christos 1157 1.22 christos rbtnode_erefs_increment(rbtdb, node); 1158 1.1 christos } 1159 1.1 christos 1160 1.1 christos /*% 1161 1.7 christos * The tree lock must be held for the result to be valid. 1162 1.7 christos */ 1163 1.15 christos static bool 1164 1.20 christos is_last_node_on_its_level(dns_rbtnode_t *node) { 1165 1.21 christos return node->parent != NULL && node->parent->down == node && 1166 1.21 christos node->left == NULL && node->right == NULL; 1167 1.7 christos } 1168 1.7 christos 1169 1.15 christos static void 1170 1.8 christos send_to_prune_tree(dns_rbtdb_t *rbtdb, dns_rbtnode_t *node, 1171 1.21 christos isc_rwlocktype_t nlocktype DNS__DB_FLARG) { 1172 1.21 christos rbtdb_prune_t *prune = isc_mem_get(rbtdb->common.mctx, sizeof(*prune)); 1173 1.21 christos *prune = (rbtdb_prune_t){ .node = node }; 1174 1.21 christos 1175 1.21 christos dns_db_attach((dns_db_t *)rbtdb, &prune->db); 1176 1.22 christos dns__rbtnode_acquire(rbtdb, node, nlocktype DNS__DB_FLARG_PASS); 1177 1.21 christos 1178 1.21 christos isc_async_run(rbtdb->loop, prune_tree, prune); 1179 1.7 christos } 1180 1.7 christos 1181 1.7 christos /*% 1182 1.1 christos * Clean up dead nodes. These are nodes which have no references, and 1183 1.1 christos * have no data. They are dead but we could not or chose not to delete 1184 1.1 christos * them when we deleted all the data at that node because we did not want 1185 1.1 christos * to wait for the tree write lock. 1186 1.1 christos * 1187 1.1 christos * The caller must hold a tree write lock and bucketnum'th node (write) lock. 1188 1.1 christos */ 1189 1.1 christos static void 1190 1.21 christos cleanup_dead_nodes(dns_rbtdb_t *rbtdb, int bucketnum DNS__DB_FLARG) { 1191 1.21 christos dns_rbtnode_t *node = NULL; 1192 1.7 christos int count = 10; /* XXXJT: should be adjustable */ 1193 1.1 christos 1194 1.1 christos node = ISC_LIST_HEAD(rbtdb->deadnodes[bucketnum]); 1195 1.1 christos while (node != NULL && count > 0) { 1196 1.1 christos ISC_LIST_UNLINK(rbtdb->deadnodes[bucketnum], node, deadlink); 1197 1.1 christos 1198 1.1 christos /* 1199 1.8 christos * We might have reactivated this node without a tree write 1200 1.8 christos * lock, so we couldn't remove this node from deadnodes then 1201 1.8 christos * and we have to do it now. 1202 1.8 christos */ 1203 1.8 christos if (isc_refcount_current(&node->references) != 0 || 1204 1.16 christos node->data != NULL) 1205 1.16 christos { 1206 1.8 christos node = ISC_LIST_HEAD(rbtdb->deadnodes[bucketnum]); 1207 1.8 christos count--; 1208 1.8 christos continue; 1209 1.8 christos } 1210 1.1 christos 1211 1.21 christos if (is_last_node_on_its_level(node) && rbtdb->loop != NULL) { 1212 1.21 christos send_to_prune_tree( 1213 1.21 christos rbtdb, node, 1214 1.21 christos isc_rwlocktype_write DNS__DB_FLARG_PASS); 1215 1.7 christos } else if (node->down == NULL && node->data == NULL) { 1216 1.7 christos /* 1217 1.7 christos * Not a interior node and not needing to be 1218 1.7 christos * reactivated. 1219 1.7 christos */ 1220 1.1 christos delete_node(rbtdb, node); 1221 1.7 christos } else if (node->data == NULL) { 1222 1.7 christos /* 1223 1.7 christos * A interior node without data. Leave linked to 1224 1.7 christos * to be cleaned up when node->down becomes NULL. 1225 1.7 christos */ 1226 1.7 christos ISC_LIST_APPEND(rbtdb->deadnodes[bucketnum], node, 1227 1.7 christos deadlink); 1228 1.1 christos } 1229 1.1 christos node = ISC_LIST_HEAD(rbtdb->deadnodes[bucketnum]); 1230 1.1 christos count--; 1231 1.1 christos } 1232 1.1 christos } 1233 1.1 christos 1234 1.1 christos /* 1235 1.1 christos * This function is assumed to be called when a node is newly referenced 1236 1.1 christos * and can be in the deadnode list. In that case the node must be retrieved 1237 1.1 christos * from the list because it is going to be used. In addition, if the caller 1238 1.1 christos * happens to hold a write lock on the tree, it's a good chance to purge dead 1239 1.1 christos * nodes. 1240 1.1 christos * Note: while a new reference is gained in multiple places, there are only very 1241 1.1 christos * few cases where the node can be in the deadnode list (only empty nodes can 1242 1.1 christos * have been added to the list). 1243 1.1 christos */ 1244 1.15 christos static void 1245 1.1 christos reactivate_node(dns_rbtdb_t *rbtdb, dns_rbtnode_t *node, 1246 1.21 christos isc_rwlocktype_t tlocktype DNS__DB_FLARG) { 1247 1.21 christos isc_rwlocktype_t nlocktype = isc_rwlocktype_none; 1248 1.21 christos isc_rwlock_t *nodelock = &rbtdb->node_locks[node->locknum].lock; 1249 1.3 christos bool maybe_cleanup = false; 1250 1.1 christos 1251 1.21 christos POST(nlocktype); 1252 1.1 christos 1253 1.21 christos NODE_RDLOCK(nodelock, &nlocktype); 1254 1.1 christos 1255 1.1 christos /* 1256 1.1 christos * Check if we can possibly cleanup the dead node. If so, upgrade 1257 1.1 christos * the node lock below to perform the cleanup. 1258 1.1 christos */ 1259 1.1 christos if (!ISC_LIST_EMPTY(rbtdb->deadnodes[node->locknum]) && 1260 1.21 christos tlocktype == isc_rwlocktype_write) 1261 1.7 christos { 1262 1.3 christos maybe_cleanup = true; 1263 1.1 christos } 1264 1.1 christos 1265 1.1 christos if (ISC_LINK_LINKED(node, deadlink) || maybe_cleanup) { 1266 1.1 christos /* 1267 1.1 christos * Upgrade the lock and test if we still need to unlink. 1268 1.1 christos */ 1269 1.21 christos NODE_FORCEUPGRADE(nodelock, &nlocktype); 1270 1.21 christos POST(nlocktype); 1271 1.7 christos if (ISC_LINK_LINKED(node, deadlink)) { 1272 1.7 christos ISC_LIST_UNLINK(rbtdb->deadnodes[node->locknum], node, 1273 1.7 christos deadlink); 1274 1.7 christos } 1275 1.7 christos if (maybe_cleanup) { 1276 1.21 christos cleanup_dead_nodes(rbtdb, 1277 1.21 christos node->locknum DNS__DB_FILELINE); 1278 1.7 christos } 1279 1.1 christos } 1280 1.1 christos 1281 1.22 christos dns__rbtnode_acquire(rbtdb, node, nlocktype DNS__DB_FLARG_PASS); 1282 1.1 christos 1283 1.21 christos NODE_UNLOCK(nodelock, &nlocktype); 1284 1.1 christos } 1285 1.1 christos 1286 1.22 christos static bool 1287 1.22 christos rbtnode_erefs_decrement(dns_rbtdb_t *rbtdb, dns_rbtnode_t *node DNS__DB_FLARG) { 1288 1.22 christos db_nodelock_t *nodelock = &rbtdb->node_locks[node->locknum]; 1289 1.22 christos uint_fast32_t refs = isc_refcount_decrement(&node->references); 1290 1.22 christos #if DNS_DB_NODETRACE 1291 1.22 christos fprintf(stderr, "decr:node:%s:%s:%u:%p->references = %" PRIuFAST32 "\n", 1292 1.22 christos func, file, line, node, refs - 1); 1293 1.22 christos #endif 1294 1.22 christos if (refs > 1) { 1295 1.22 christos return false; 1296 1.22 christos } 1297 1.22 christos refs = isc_refcount_decrement(&nodelock->references); 1298 1.22 christos #if DNS_DB_NODETRACE 1299 1.22 christos fprintf(stderr, 1300 1.22 christos "decr:nodelock:%s:%s:%u:%p:%p->references = " 1301 1.22 christos "%" PRIuFAST32 "\n", 1302 1.22 christos func, file, line, node, nodelock, refs - 1); 1303 1.22 christos #else 1304 1.22 christos UNUSED(refs); 1305 1.22 christos #endif 1306 1.22 christos return true; 1307 1.22 christos } 1308 1.22 christos 1309 1.1 christos /* 1310 1.21 christos * Caller must be holding the node lock; either the read or write lock. 1311 1.21 christos * Note that the lock must be held even when node references are 1312 1.1 christos * atomically modified; in that case the decrement operation itself does not 1313 1.1 christos * have to be protected, but we must avoid a race condition where multiple 1314 1.1 christos * threads are decreasing the reference to zero simultaneously and at least 1315 1.1 christos * one of them is going to free the node. 1316 1.1 christos * 1317 1.3 christos * This function returns true if and only if the node reference decreases 1318 1.1 christos * to zero. 1319 1.1 christos * 1320 1.1 christos * NOTE: Decrementing the reference count of a node to zero does not mean it 1321 1.1 christos * will be immediately freed. 1322 1.1 christos */ 1323 1.21 christos bool 1324 1.22 christos dns__rbtnode_release(dns_rbtdb_t *rbtdb, dns_rbtnode_t *node, 1325 1.22 christos uint32_t least_serial, isc_rwlocktype_t *nlocktypep, 1326 1.22 christos isc_rwlocktype_t *tlocktypep, bool tryupgrade, 1327 1.22 christos bool pruning DNS__DB_FLARG) { 1328 1.1 christos isc_result_t result; 1329 1.21 christos bool locked = *tlocktypep != isc_rwlocktype_none; 1330 1.21 christos bool write_locked = false; 1331 1.22 christos db_nodelock_t *nodelock = &rbtdb->node_locks[node->locknum]; 1332 1.3 christos bool no_reference = true; 1333 1.1 christos 1334 1.21 christos REQUIRE(*nlocktypep != isc_rwlocktype_none); 1335 1.21 christos 1336 1.7 christos #define KEEP_NODE(n, r, l) \ 1337 1.7 christos ((n)->data != NULL || ((l) && (n)->down != NULL) || \ 1338 1.1 christos (n) == (r)->origin_node || (n) == (r)->nsec3_origin_node) 1339 1.1 christos 1340 1.22 christos if (!rbtnode_erefs_decrement(rbtdb, node DNS__DB_FLARG_PASS)) { 1341 1.22 christos return false; 1342 1.22 christos } 1343 1.22 christos 1344 1.7 christos if (!node->dirty && KEEP_NODE(node, rbtdb, locked)) { 1345 1.22 christos return true; 1346 1.1 christos } 1347 1.1 christos 1348 1.1 christos /* Upgrade the lock? */ 1349 1.21 christos if (*nlocktypep == isc_rwlocktype_read) { 1350 1.22 christos /* 1351 1.22 christos * Node lock ref has decremented to 0 and we may need to clean 1352 1.22 christos * up the node. To clean it up, the node ref needs to decrement 1353 1.22 christos * to 0 under the node write lock, so we regain the ref and try 1354 1.22 christos * again. 1355 1.22 christos */ 1356 1.22 christos rbtnode_erefs_increment(rbtdb, node DNS__DB_FLARG_PASS); 1357 1.21 christos NODE_FORCEUPGRADE(&nodelock->lock, nlocktypep); 1358 1.22 christos if (!rbtnode_erefs_decrement(rbtdb, node DNS__DB_FLARG_PASS)) { 1359 1.22 christos return false; 1360 1.22 christos } 1361 1.1 christos } 1362 1.1 christos 1363 1.1 christos if (node->dirty) { 1364 1.7 christos if (IS_CACHE(rbtdb)) { 1365 1.1 christos clean_cache_node(rbtdb, node); 1366 1.7 christos } else { 1367 1.1 christos if (least_serial == 0) { 1368 1.1 christos /* 1369 1.1 christos * Caller doesn't know the least serial. 1370 1.1 christos * Get it. 1371 1.1 christos */ 1372 1.21 christos RWLOCK(&rbtdb->lock, isc_rwlocktype_read); 1373 1.1 christos least_serial = rbtdb->least_serial; 1374 1.21 christos RWUNLOCK(&rbtdb->lock, isc_rwlocktype_read); 1375 1.1 christos } 1376 1.21 christos clean_zone_node(node, least_serial); 1377 1.1 christos } 1378 1.1 christos } 1379 1.1 christos 1380 1.1 christos /* 1381 1.1 christos * Attempt to switch to a write lock on the tree. If this fails, 1382 1.1 christos * we will add this node to a linked list of nodes in this locking 1383 1.1 christos * bucket which we will free later. 1384 1.21 christos * 1385 1.21 christos * Locking hierarchy notwithstanding, we don't need to free 1386 1.21 christos * the node lock before acquiring the tree write lock because 1387 1.21 christos * we only do a trylock. 1388 1.21 christos */ 1389 1.21 christos /* We are allowed to upgrade the tree lock */ 1390 1.21 christos switch (*tlocktypep) { 1391 1.21 christos case isc_rwlocktype_write: 1392 1.21 christos result = ISC_R_SUCCESS; 1393 1.21 christos break; 1394 1.21 christos case isc_rwlocktype_read: 1395 1.21 christos if (tryupgrade) { 1396 1.21 christos result = TREE_TRYUPGRADE(&rbtdb->tree_lock, tlocktypep); 1397 1.7 christos } else { 1398 1.21 christos result = ISC_R_LOCKBUSY; 1399 1.7 christos } 1400 1.21 christos break; 1401 1.21 christos case isc_rwlocktype_none: 1402 1.21 christos result = TREE_TRYWRLOCK(&rbtdb->tree_lock, tlocktypep); 1403 1.21 christos break; 1404 1.21 christos default: 1405 1.21 christos UNREACHABLE(); 1406 1.21 christos } 1407 1.21 christos RUNTIME_CHECK(result == ISC_R_SUCCESS || result == ISC_R_LOCKBUSY); 1408 1.21 christos if (result == ISC_R_SUCCESS) { 1409 1.3 christos write_locked = true; 1410 1.7 christos } 1411 1.1 christos 1412 1.7 christos if (KEEP_NODE(node, rbtdb, locked || write_locked)) { 1413 1.1 christos goto restore_locks; 1414 1.7 christos } 1415 1.1 christos 1416 1.1 christos #undef KEEP_NODE 1417 1.1 christos 1418 1.1 christos if (write_locked) { 1419 1.1 christos /* 1420 1.20 christos * If this node is the only one left on its RBTDB level, 1421 1.20 christos * attempt pruning the RBTDB (i.e. deleting empty nodes that 1422 1.20 christos * are ancestors of 'node' and are not interior nodes) starting 1423 1.20 christos * from this node (see prune_tree()). The main reason this is 1424 1.20 christos * not done immediately, but asynchronously, is that the 1425 1.20 christos * ancestors of 'node' are almost guaranteed to belong to 1426 1.20 christos * different node buckets and we don't want to do juggle locks 1427 1.20 christos * right now. 1428 1.20 christos * 1429 1.22 christos * Since prune_tree() also calls dns__rbtnode_release(), check 1430 1.22 christos * the value of the 'pruning' parameter (which is only set to 1431 1.22 christos * 'true' in the dns__rbtnode_release() call present in 1432 1.20 christos * prune_tree()) to prevent an infinite loop and to allow a 1433 1.20 christos * node sent to prune_tree() to be deleted by the delete_node() 1434 1.20 christos * call in the code branch below. 1435 1.1 christos */ 1436 1.20 christos if (!pruning && is_last_node_on_its_level(node) && 1437 1.21 christos rbtdb->loop != NULL) 1438 1.20 christos { 1439 1.21 christos send_to_prune_tree(rbtdb, node, 1440 1.21 christos *nlocktypep DNS__DB_FLARG_PASS); 1441 1.7 christos no_reference = false; 1442 1.1 christos } else { 1443 1.20 christos /* 1444 1.20 christos * The node can now be deleted. 1445 1.20 christos */ 1446 1.1 christos delete_node(rbtdb, node); 1447 1.1 christos } 1448 1.1 christos } else { 1449 1.1 christos INSIST(node->data == NULL); 1450 1.8 christos if (!ISC_LINK_LINKED(node, deadlink)) { 1451 1.22 christos ISC_LIST_APPEND(rbtdb->deadnodes[node->locknum], node, 1452 1.8 christos deadlink); 1453 1.8 christos } 1454 1.1 christos } 1455 1.1 christos 1456 1.7 christos restore_locks: 1457 1.1 christos /* 1458 1.1 christos * Relock a read lock, or unlock the write lock if no lock was held. 1459 1.1 christos */ 1460 1.21 christos if (!locked && write_locked) { 1461 1.21 christos TREE_UNLOCK(&rbtdb->tree_lock, tlocktypep); 1462 1.7 christos } 1463 1.1 christos 1464 1.21 christos return no_reference; 1465 1.1 christos } 1466 1.1 christos 1467 1.1 christos /* 1468 1.20 christos * Prune the RBTDB tree of trees. Start by attempting to delete a node that is 1469 1.20 christos * the only one left on its RBTDB level (see the send_to_prune_tree() call in 1470 1.22 christos * dns__rbtnode_release()). Then, if the node has a parent (which can either 1471 1.20 christos * exist on the same RBTDB level or on an upper RBTDB level), check whether the 1472 1.20 christos * latter is an interior node (i.e. a node with a non-NULL 'down' pointer). If 1473 1.20 christos * the parent node is not an interior node, attempt deleting the parent node as 1474 1.20 christos * well and then move on to examining the parent node's parent, etc. Continue 1475 1.20 christos * traversing the RBTDB tree until a node is encountered that is still an 1476 1.20 christos * interior node after the previously-processed node gets deleted. 1477 1.20 christos * 1478 1.20 christos * It is acceptable for a node sent to this function to NOT be deleted in the 1479 1.20 christos * process (e.g. if it gets reactivated in the meantime). Furthermore, node 1480 1.20 christos * deletion is not a prerequisite for continuing RBTDB traversal. 1481 1.20 christos * 1482 1.20 christos * This function gets called once for every "starting node" and it continues 1483 1.20 christos * traversing the RBTDB until the stop condition is met. In the worst case, 1484 1.20 christos * the number of nodes processed by a single execution of this function is the 1485 1.20 christos * number of tree levels, which is at most the maximum number of domain name 1486 1.20 christos * labels (127); however, it should be much smaller in practice and deleting 1487 1.20 christos * empty RBTDB nodes is critical to keeping the amount of memory used by the 1488 1.20 christos * cache memory context within the configured limit anyway. 1489 1.1 christos */ 1490 1.1 christos static void 1491 1.21 christos prune_tree(void *arg) { 1492 1.21 christos rbtdb_prune_t *prune = (rbtdb_prune_t *)arg; 1493 1.21 christos dns_rbtdb_t *rbtdb = (dns_rbtdb_t *)prune->db; 1494 1.21 christos dns_rbtnode_t *node = prune->node; 1495 1.18 christos dns_rbtnode_t *parent = NULL; 1496 1.20 christos unsigned int locknum = node->locknum; 1497 1.21 christos isc_rwlocktype_t tlocktype = isc_rwlocktype_none; 1498 1.21 christos isc_rwlocktype_t nlocktype = isc_rwlocktype_none; 1499 1.1 christos 1500 1.21 christos isc_mem_put(rbtdb->common.mctx, prune, sizeof(*prune)); 1501 1.1 christos 1502 1.21 christos TREE_WRLOCK(&rbtdb->tree_lock, &tlocktype); 1503 1.21 christos NODE_WRLOCK(&rbtdb->node_locks[locknum].lock, &nlocktype); 1504 1.20 christos do { 1505 1.20 christos parent = node->parent; 1506 1.22 christos dns__rbtnode_release(rbtdb, node, 0, &nlocktype, &tlocktype, 1507 1.22 christos true, true DNS__DB_FILELINE); 1508 1.1 christos 1509 1.20 christos /* 1510 1.20 christos * Check whether the parent is an interior node. Note that it 1511 1.22 christos * might have been one before the dns__rbtnode_release() call on 1512 1.20 christos * the previous line, but decrementing the reference count for 1513 1.20 christos * 'node' could have caused 'node->parent->down' to become 1514 1.20 christos * NULL. 1515 1.20 christos */ 1516 1.20 christos if (parent != NULL && parent->down == NULL) { 1517 1.20 christos /* 1518 1.20 christos * Keep the node lock if possible; otherwise, release 1519 1.20 christos * the old lock and acquire one for the parent. 1520 1.20 christos */ 1521 1.20 christos if (parent->locknum != locknum) { 1522 1.20 christos NODE_UNLOCK(&rbtdb->node_locks[locknum].lock, 1523 1.21 christos &nlocktype); 1524 1.20 christos locknum = parent->locknum; 1525 1.21 christos NODE_WRLOCK(&rbtdb->node_locks[locknum].lock, 1526 1.21 christos &nlocktype); 1527 1.1 christos } 1528 1.1 christos 1529 1.20 christos /* 1530 1.20 christos * We need to gain a reference to the parent node 1531 1.20 christos * before decrementing it in the next iteration. 1532 1.20 christos */ 1533 1.22 christos dns__rbtnode_acquire(rbtdb, parent, 1534 1.22 christos nlocktype DNS__DB_FLARG_PASS); 1535 1.20 christos } else { 1536 1.20 christos parent = NULL; 1537 1.20 christos } 1538 1.18 christos 1539 1.20 christos node = parent; 1540 1.20 christos } while (node != NULL); 1541 1.21 christos NODE_UNLOCK(&rbtdb->node_locks[locknum].lock, &nlocktype); 1542 1.21 christos TREE_UNLOCK(&rbtdb->tree_lock, &tlocktype); 1543 1.1 christos 1544 1.21 christos dns_db_detach((dns_db_t **)&rbtdb); 1545 1.1 christos } 1546 1.1 christos 1547 1.15 christos static void 1548 1.21 christos make_least_version(dns_rbtdb_t *rbtdb, dns_rbtdb_version_t *version, 1549 1.7 christos rbtdb_changedlist_t *cleanup_list) { 1550 1.1 christos /* 1551 1.1 christos * Caller must be holding the database lock. 1552 1.1 christos */ 1553 1.1 christos 1554 1.1 christos rbtdb->least_serial = version->serial; 1555 1.1 christos *cleanup_list = version->changed_list; 1556 1.1 christos ISC_LIST_INIT(version->changed_list); 1557 1.1 christos } 1558 1.1 christos 1559 1.15 christos static void 1560 1.21 christos cleanup_nondirty(dns_rbtdb_version_t *version, 1561 1.21 christos rbtdb_changedlist_t *cleanup_list) { 1562 1.21 christos rbtdb_changed_t *changed = NULL, *next_changed = NULL; 1563 1.1 christos 1564 1.1 christos /* 1565 1.1 christos * If the changed record is dirty, then 1566 1.1 christos * an update created multiple versions of 1567 1.1 christos * a given rdataset. We keep this list 1568 1.1 christos * until we're the least open version, at 1569 1.1 christos * which point it's safe to get rid of any 1570 1.1 christos * older versions. 1571 1.1 christos * 1572 1.1 christos * If the changed record isn't dirty, then 1573 1.1 christos * we don't need it anymore since we're 1574 1.1 christos * committing and not rolling back. 1575 1.1 christos * 1576 1.1 christos * The caller must be holding the database lock. 1577 1.1 christos */ 1578 1.7 christos for (changed = HEAD(version->changed_list); changed != NULL; 1579 1.7 christos changed = next_changed) 1580 1.7 christos { 1581 1.1 christos next_changed = NEXT(changed, link); 1582 1.1 christos if (!changed->dirty) { 1583 1.7 christos UNLINK(version->changed_list, changed, link); 1584 1.7 christos APPEND(*cleanup_list, changed, link); 1585 1.1 christos } 1586 1.1 christos } 1587 1.1 christos } 1588 1.1 christos 1589 1.21 christos void 1590 1.21 christos dns__rbtdb_setsecure(dns_db_t *db, dns_rbtdb_version_t *version, 1591 1.21 christos dns_dbnode_t *origin) { 1592 1.1 christos dns_rdataset_t keyset; 1593 1.1 christos dns_rdataset_t nsecset, signsecset; 1594 1.3 christos bool haszonekey = false; 1595 1.3 christos bool hasnsec = false; 1596 1.1 christos isc_result_t result; 1597 1.1 christos 1598 1.20 christos REQUIRE(version != NULL); 1599 1.20 christos 1600 1.1 christos dns_rdataset_init(&keyset); 1601 1.1 christos result = dns_db_findrdataset(db, origin, version, dns_rdatatype_dnskey, 1602 1.1 christos 0, 0, &keyset, NULL); 1603 1.1 christos if (result == ISC_R_SUCCESS) { 1604 1.1 christos result = dns_rdataset_first(&keyset); 1605 1.1 christos while (result == ISC_R_SUCCESS) { 1606 1.1 christos dns_rdata_t keyrdata = DNS_RDATA_INIT; 1607 1.1 christos dns_rdataset_current(&keyset, &keyrdata); 1608 1.1 christos if (dns_zonekey_iszonekey(&keyrdata)) { 1609 1.3 christos haszonekey = true; 1610 1.1 christos break; 1611 1.1 christos } 1612 1.1 christos result = dns_rdataset_next(&keyset); 1613 1.1 christos } 1614 1.1 christos dns_rdataset_disassociate(&keyset); 1615 1.1 christos } 1616 1.1 christos if (!haszonekey) { 1617 1.21 christos version->secure = false; 1618 1.3 christos version->havensec3 = false; 1619 1.1 christos return; 1620 1.1 christos } 1621 1.1 christos 1622 1.1 christos dns_rdataset_init(&nsecset); 1623 1.1 christos dns_rdataset_init(&signsecset); 1624 1.7 christos result = dns_db_findrdataset(db, origin, version, dns_rdatatype_nsec, 0, 1625 1.7 christos 0, &nsecset, &signsecset); 1626 1.1 christos if (result == ISC_R_SUCCESS) { 1627 1.1 christos if (dns_rdataset_isassociated(&signsecset)) { 1628 1.3 christos hasnsec = true; 1629 1.1 christos dns_rdataset_disassociate(&signsecset); 1630 1.1 christos } 1631 1.1 christos dns_rdataset_disassociate(&nsecset); 1632 1.1 christos } 1633 1.1 christos 1634 1.1 christos setnsec3parameters(db, version); 1635 1.1 christos 1636 1.1 christos /* 1637 1.1 christos * Do we have a valid NSEC/NSEC3 chain? 1638 1.1 christos */ 1639 1.7 christos if (version->havensec3 || hasnsec) { 1640 1.21 christos version->secure = true; 1641 1.7 christos } else { 1642 1.21 christos version->secure = false; 1643 1.7 christos } 1644 1.1 christos } 1645 1.1 christos 1646 1.1 christos /*%< 1647 1.1 christos * Walk the origin node looking for NSEC3PARAM records. 1648 1.1 christos * Cache the nsec3 parameters. 1649 1.1 christos */ 1650 1.1 christos static void 1651 1.21 christos setnsec3parameters(dns_db_t *db, dns_rbtdb_version_t *version) { 1652 1.21 christos dns_rbtnode_t *node = NULL; 1653 1.1 christos dns_rdata_nsec3param_t nsec3param; 1654 1.1 christos dns_rdata_t rdata = DNS_RDATA_INIT; 1655 1.1 christos isc_region_t region; 1656 1.1 christos isc_result_t result; 1657 1.21 christos dns_slabheader_t *header = NULL, *header_next = NULL; 1658 1.7 christos unsigned char *raw; /* RDATASLAB */ 1659 1.1 christos unsigned int count, length; 1660 1.1 christos dns_rbtdb_t *rbtdb = (dns_rbtdb_t *)db; 1661 1.21 christos isc_rwlocktype_t tlocktype = isc_rwlocktype_none; 1662 1.21 christos isc_rwlocktype_t nlocktype = isc_rwlocktype_none; 1663 1.1 christos 1664 1.21 christos TREE_RDLOCK(&rbtdb->tree_lock, &tlocktype); 1665 1.3 christos version->havensec3 = false; 1666 1.1 christos node = rbtdb->origin_node; 1667 1.21 christos NODE_RDLOCK(&(rbtdb->node_locks[node->locknum].lock), &nlocktype); 1668 1.7 christos for (header = node->data; header != NULL; header = header_next) { 1669 1.1 christos header_next = header->next; 1670 1.1 christos do { 1671 1.1 christos if (header->serial <= version->serial && 1672 1.16 christos !IGNORE(header)) 1673 1.16 christos { 1674 1.7 christos if (NONEXISTENT(header)) { 1675 1.1 christos header = NULL; 1676 1.7 christos } 1677 1.1 christos break; 1678 1.7 christos } else { 1679 1.1 christos header = header->down; 1680 1.7 christos } 1681 1.1 christos } while (header != NULL); 1682 1.1 christos 1683 1.1 christos if (header != NULL && 1684 1.16 christos (header->type == dns_rdatatype_nsec3param)) 1685 1.16 christos { 1686 1.1 christos /* 1687 1.1 christos * Find A NSEC3PARAM with a supported algorithm. 1688 1.1 christos */ 1689 1.21 christos raw = dns_slabheader_raw(header); 1690 1.1 christos count = raw[0] * 256 + raw[1]; /* count */ 1691 1.5 christos raw += DNS_RDATASET_COUNT + DNS_RDATASET_LENGTH; 1692 1.1 christos while (count-- > 0U) { 1693 1.1 christos length = raw[0] * 256 + raw[1]; 1694 1.5 christos raw += DNS_RDATASET_ORDER + DNS_RDATASET_LENGTH; 1695 1.1 christos region.base = raw; 1696 1.1 christos region.length = length; 1697 1.1 christos raw += length; 1698 1.7 christos dns_rdata_fromregion( 1699 1.7 christos &rdata, rbtdb->common.rdclass, 1700 1.7 christos dns_rdatatype_nsec3param, ®ion); 1701 1.7 christos result = dns_rdata_tostruct(&rdata, &nsec3param, 1702 1.1 christos NULL); 1703 1.1 christos INSIST(result == ISC_R_SUCCESS); 1704 1.1 christos dns_rdata_reset(&rdata); 1705 1.1 christos 1706 1.1 christos if (nsec3param.hash != DNS_NSEC3_UNKNOWNALG && 1707 1.1 christos !dns_nsec3_supportedhash(nsec3param.hash)) 1708 1.7 christos { 1709 1.1 christos continue; 1710 1.7 christos } 1711 1.1 christos 1712 1.7 christos if (nsec3param.flags != 0) { 1713 1.1 christos continue; 1714 1.7 christos } 1715 1.1 christos 1716 1.1 christos memmove(version->salt, nsec3param.salt, 1717 1.1 christos nsec3param.salt_length); 1718 1.1 christos version->hash = nsec3param.hash; 1719 1.1 christos version->salt_length = nsec3param.salt_length; 1720 1.1 christos version->iterations = nsec3param.iterations; 1721 1.1 christos version->flags = nsec3param.flags; 1722 1.3 christos version->havensec3 = true; 1723 1.1 christos /* 1724 1.1 christos * Look for a better algorithm than the 1725 1.1 christos * unknown test algorithm. 1726 1.1 christos */ 1727 1.7 christos if (nsec3param.hash != DNS_NSEC3_UNKNOWNALG) { 1728 1.1 christos goto unlock; 1729 1.7 christos } 1730 1.1 christos } 1731 1.1 christos } 1732 1.1 christos } 1733 1.7 christos unlock: 1734 1.21 christos NODE_UNLOCK(&(rbtdb->node_locks[node->locknum].lock), &nlocktype); 1735 1.21 christos TREE_UNLOCK(&rbtdb->tree_lock, &tlocktype); 1736 1.1 christos } 1737 1.1 christos 1738 1.1 christos static void 1739 1.21 christos cleanup_dead_nodes_callback(void *arg) { 1740 1.21 christos dns_rbtdb_t *rbtdb = (dns_rbtdb_t *)arg; 1741 1.3 christos bool again = false; 1742 1.1 christos unsigned int locknum; 1743 1.21 christos isc_rwlocktype_t tlocktype = isc_rwlocktype_none; 1744 1.21 christos isc_rwlocktype_t nlocktype = isc_rwlocktype_none; 1745 1.1 christos 1746 1.21 christos TREE_WRLOCK(&rbtdb->tree_lock, &tlocktype); 1747 1.1 christos for (locknum = 0; locknum < rbtdb->node_lock_count; locknum++) { 1748 1.21 christos NODE_WRLOCK(&rbtdb->node_locks[locknum].lock, &nlocktype); 1749 1.21 christos cleanup_dead_nodes(rbtdb, locknum DNS__DB_FILELINE); 1750 1.7 christos if (ISC_LIST_HEAD(rbtdb->deadnodes[locknum]) != NULL) { 1751 1.3 christos again = true; 1752 1.7 christos } 1753 1.21 christos NODE_UNLOCK(&rbtdb->node_locks[locknum].lock, &nlocktype); 1754 1.1 christos } 1755 1.21 christos TREE_UNLOCK(&rbtdb->tree_lock, &tlocktype); 1756 1.7 christos if (again) { 1757 1.21 christos isc_async_run(rbtdb->loop, cleanup_dead_nodes_callback, rbtdb); 1758 1.7 christos } else { 1759 1.21 christos dns_db_detach((dns_db_t **)&rbtdb); 1760 1.1 christos } 1761 1.1 christos } 1762 1.1 christos 1763 1.21 christos void 1764 1.21 christos dns__rbtdb_closeversion(dns_db_t *db, dns_dbversion_t **versionp, 1765 1.21 christos bool commit DNS__DB_FLARG) { 1766 1.1 christos dns_rbtdb_t *rbtdb = (dns_rbtdb_t *)db; 1767 1.21 christos dns_rbtdb_version_t *version = NULL, *cleanup_version = NULL; 1768 1.21 christos dns_rbtdb_version_t *least_greater = NULL; 1769 1.3 christos bool rollback = false; 1770 1.1 christos rbtdb_changedlist_t cleanup_list; 1771 1.21 christos dns_slabheaderlist_t resigned_list; 1772 1.21 christos rbtdb_changed_t *changed = NULL, *next_changed = NULL; 1773 1.21 christos uint32_t serial, least_serial; 1774 1.21 christos dns_rbtnode_t *rbtnode = NULL; 1775 1.21 christos dns_slabheader_t *header = NULL; 1776 1.1 christos 1777 1.1 christos REQUIRE(VALID_RBTDB(rbtdb)); 1778 1.21 christos version = (dns_rbtdb_version_t *)*versionp; 1779 1.1 christos INSIST(version->rbtdb == rbtdb); 1780 1.1 christos 1781 1.1 christos ISC_LIST_INIT(cleanup_list); 1782 1.1 christos ISC_LIST_INIT(resigned_list); 1783 1.1 christos 1784 1.3 christos if (isc_refcount_decrement(&version->references) > 1) { 1785 1.3 christos /* typical and easy case first */ 1786 1.1 christos if (commit) { 1787 1.21 christos RWLOCK(&rbtdb->lock, isc_rwlocktype_read); 1788 1.1 christos INSIST(!version->writer); 1789 1.21 christos RWUNLOCK(&rbtdb->lock, isc_rwlocktype_read); 1790 1.1 christos } 1791 1.1 christos goto end; 1792 1.1 christos } 1793 1.1 christos 1794 1.1 christos /* 1795 1.1 christos * Update the zone's secure status in version before making 1796 1.1 christos * it the current version. 1797 1.1 christos */ 1798 1.7 christos if (version->writer && commit && !IS_CACHE(rbtdb)) { 1799 1.21 christos dns__rbtdb_setsecure(db, version, rbtdb->origin_node); 1800 1.7 christos } 1801 1.1 christos 1802 1.21 christos RWLOCK(&rbtdb->lock, isc_rwlocktype_write); 1803 1.1 christos serial = version->serial; 1804 1.1 christos if (version->writer) { 1805 1.1 christos if (commit) { 1806 1.21 christos unsigned int cur_ref; 1807 1.21 christos dns_rbtdb_version_t *cur_version = NULL; 1808 1.1 christos 1809 1.1 christos INSIST(version->commit_ok); 1810 1.1 christos INSIST(version == rbtdb->future_version); 1811 1.1 christos /* 1812 1.1 christos * The current version is going to be replaced. 1813 1.1 christos * Release the (likely last) reference to it from the 1814 1.1 christos * DB itself and unlink it from the open list. 1815 1.1 christos */ 1816 1.1 christos cur_version = rbtdb->current_version; 1817 1.7 christos cur_ref = isc_refcount_decrement( 1818 1.7 christos &cur_version->references); 1819 1.3 christos if (cur_ref == 1) { 1820 1.7 christos (void)isc_refcount_current( 1821 1.7 christos &cur_version->references); 1822 1.1 christos if (cur_version->serial == rbtdb->least_serial) 1823 1.7 christos { 1824 1.7 christos INSIST(EMPTY( 1825 1.7 christos cur_version->changed_list)); 1826 1.7 christos } 1827 1.7 christos UNLINK(rbtdb->open_versions, cur_version, link); 1828 1.1 christos } 1829 1.1 christos if (EMPTY(rbtdb->open_versions)) { 1830 1.1 christos /* 1831 1.1 christos * We're going to become the least open 1832 1.1 christos * version. 1833 1.1 christos */ 1834 1.1 christos make_least_version(rbtdb, version, 1835 1.1 christos &cleanup_list); 1836 1.1 christos } else { 1837 1.1 christos /* 1838 1.1 christos * Some other open version is the 1839 1.1 christos * least version. We can't cleanup 1840 1.1 christos * records that were changed in this 1841 1.1 christos * version because the older versions 1842 1.1 christos * may still be in use by an open 1843 1.1 christos * version. 1844 1.1 christos * 1845 1.1 christos * We can, however, discard the 1846 1.1 christos * changed records for things that 1847 1.1 christos * we've added that didn't exist in 1848 1.1 christos * prior versions. 1849 1.1 christos */ 1850 1.1 christos cleanup_nondirty(version, &cleanup_list); 1851 1.1 christos } 1852 1.1 christos /* 1853 1.1 christos * If the (soon to be former) current version 1854 1.1 christos * isn't being used by anyone, we can clean 1855 1.1 christos * it up. 1856 1.1 christos */ 1857 1.3 christos if (cur_ref == 1) { 1858 1.1 christos cleanup_version = cur_version; 1859 1.1 christos APPENDLIST(version->changed_list, 1860 1.7 christos cleanup_version->changed_list, link); 1861 1.1 christos } 1862 1.1 christos /* 1863 1.1 christos * Become the current version. 1864 1.1 christos */ 1865 1.3 christos version->writer = false; 1866 1.1 christos rbtdb->current_version = version; 1867 1.1 christos rbtdb->current_serial = version->serial; 1868 1.1 christos rbtdb->future_version = NULL; 1869 1.1 christos 1870 1.1 christos /* 1871 1.1 christos * Keep the current version in the open list, and 1872 1.1 christos * gain a reference for the DB itself (see the DB 1873 1.1 christos * creation function below). This must be the only 1874 1.1 christos * case where we need to increment the counter from 1875 1.1 christos * zero and need to use isc_refcount_increment0(). 1876 1.1 christos */ 1877 1.7 christos INSIST(isc_refcount_increment0(&version->references) == 1878 1.7 christos 0); 1879 1.7 christos PREPEND(rbtdb->open_versions, rbtdb->current_version, 1880 1.7 christos link); 1881 1.1 christos resigned_list = version->resigned_list; 1882 1.1 christos ISC_LIST_INIT(version->resigned_list); 1883 1.1 christos } else { 1884 1.1 christos /* 1885 1.1 christos * We're rolling back this transaction. 1886 1.1 christos */ 1887 1.1 christos cleanup_list = version->changed_list; 1888 1.1 christos ISC_LIST_INIT(version->changed_list); 1889 1.1 christos resigned_list = version->resigned_list; 1890 1.1 christos ISC_LIST_INIT(version->resigned_list); 1891 1.3 christos rollback = true; 1892 1.1 christos cleanup_version = version; 1893 1.1 christos rbtdb->future_version = NULL; 1894 1.1 christos } 1895 1.1 christos } else { 1896 1.1 christos if (version != rbtdb->current_version) { 1897 1.1 christos /* 1898 1.1 christos * There are no external or internal references 1899 1.1 christos * to this version and it can be cleaned up. 1900 1.1 christos */ 1901 1.1 christos cleanup_version = version; 1902 1.1 christos 1903 1.1 christos /* 1904 1.1 christos * Find the version with the least serial 1905 1.1 christos * number greater than ours. 1906 1.1 christos */ 1907 1.1 christos least_greater = PREV(version, link); 1908 1.7 christos if (least_greater == NULL) { 1909 1.1 christos least_greater = rbtdb->current_version; 1910 1.7 christos } 1911 1.1 christos 1912 1.1 christos INSIST(version->serial < least_greater->serial); 1913 1.1 christos /* 1914 1.1 christos * Is this the least open version? 1915 1.1 christos */ 1916 1.1 christos if (version->serial == rbtdb->least_serial) { 1917 1.1 christos /* 1918 1.1 christos * Yes. Install the new least open 1919 1.1 christos * version. 1920 1.1 christos */ 1921 1.7 christos make_least_version(rbtdb, least_greater, 1922 1.1 christos &cleanup_list); 1923 1.1 christos } else { 1924 1.1 christos /* 1925 1.1 christos * Add any unexecuted cleanups to 1926 1.1 christos * those of the least greater version. 1927 1.1 christos */ 1928 1.1 christos APPENDLIST(least_greater->changed_list, 1929 1.7 christos version->changed_list, link); 1930 1.1 christos } 1931 1.7 christos } else if (version->serial == rbtdb->least_serial) { 1932 1.1 christos INSIST(EMPTY(version->changed_list)); 1933 1.7 christos } 1934 1.1 christos UNLINK(rbtdb->open_versions, version, link); 1935 1.1 christos } 1936 1.1 christos least_serial = rbtdb->least_serial; 1937 1.21 christos RWUNLOCK(&rbtdb->lock, isc_rwlocktype_write); 1938 1.1 christos 1939 1.1 christos if (cleanup_version != NULL) { 1940 1.21 christos isc_refcount_destroy(&cleanup_version->references); 1941 1.1 christos INSIST(EMPTY(cleanup_version->changed_list)); 1942 1.22 christos dns__db_cleanup_gluelists(&cleanup_version->glue_stack); 1943 1.22 christos cds_wfs_destroy(&cleanup_version->glue_stack); 1944 1.1 christos isc_rwlock_destroy(&cleanup_version->rwlock); 1945 1.1 christos isc_mem_put(rbtdb->common.mctx, cleanup_version, 1946 1.1 christos sizeof(*cleanup_version)); 1947 1.1 christos } 1948 1.1 christos 1949 1.1 christos /* 1950 1.1 christos * Commit/rollback re-signed headers. 1951 1.1 christos */ 1952 1.7 christos for (header = HEAD(resigned_list); header != NULL; 1953 1.16 christos header = HEAD(resigned_list)) 1954 1.16 christos { 1955 1.21 christos isc_rwlock_t *lock = NULL; 1956 1.21 christos isc_rwlocktype_t tlocktype = isc_rwlocktype_none; 1957 1.21 christos isc_rwlocktype_t nlocktype = isc_rwlocktype_none; 1958 1.1 christos 1959 1.1 christos ISC_LIST_UNLINK(resigned_list, header, link); 1960 1.1 christos 1961 1.21 christos lock = &rbtdb->node_locks[RBTDB_HEADERNODE(header)->locknum] 1962 1.21 christos .lock; 1963 1.21 christos NODE_WRLOCK(lock, &nlocktype); 1964 1.1 christos if (rollback && !IGNORE(header)) { 1965 1.21 christos dns__zonerbt_resigninsert( 1966 1.21 christos rbtdb, RBTDB_HEADERNODE(header)->locknum, 1967 1.21 christos header); 1968 1.21 christos } 1969 1.22 christos dns__rbtnode_release(rbtdb, RBTDB_HEADERNODE(header), 1970 1.22 christos least_serial, &nlocktype, &tlocktype, true, 1971 1.22 christos false DNS__DB_FLARG_PASS); 1972 1.21 christos NODE_UNLOCK(lock, &nlocktype); 1973 1.21 christos INSIST(tlocktype == isc_rwlocktype_none); 1974 1.1 christos } 1975 1.1 christos 1976 1.1 christos if (!EMPTY(cleanup_list)) { 1977 1.21 christos isc_rwlocktype_t tlocktype = isc_rwlocktype_none; 1978 1.1 christos 1979 1.21 christos if (rbtdb->loop == NULL) { 1980 1.1 christos /* 1981 1.1 christos * We acquire a tree write lock here in order to make 1982 1.1 christos * sure that stale nodes will be removed in 1983 1.22 christos * dns__rbtnode_release(). If we didn't have the lock, 1984 1.1 christos * those nodes could miss the chance to be removed 1985 1.1 christos * until the server stops. The write lock is 1986 1.21 christos * expensive, but this should be rare enough 1987 1.1 christos * to justify the cost. 1988 1.1 christos */ 1989 1.21 christos TREE_WRLOCK(&rbtdb->tree_lock, &tlocktype); 1990 1.1 christos } 1991 1.1 christos 1992 1.7 christos for (changed = HEAD(cleanup_list); changed != NULL; 1993 1.16 christos changed = next_changed) 1994 1.16 christos { 1995 1.21 christos isc_rwlock_t *lock = NULL; 1996 1.21 christos isc_rwlocktype_t nlocktype = isc_rwlocktype_none; 1997 1.1 christos 1998 1.1 christos next_changed = NEXT(changed, link); 1999 1.1 christos rbtnode = changed->node; 2000 1.1 christos lock = &rbtdb->node_locks[rbtnode->locknum].lock; 2001 1.1 christos 2002 1.21 christos NODE_WRLOCK(lock, &nlocktype); 2003 1.1 christos /* 2004 1.1 christos * This is a good opportunity to purge any dead nodes, 2005 1.1 christos * so use it. 2006 1.1 christos */ 2007 1.21 christos if (rbtdb->loop == NULL) { 2008 1.21 christos cleanup_dead_nodes( 2009 1.21 christos rbtdb, 2010 1.21 christos rbtnode->locknum DNS__DB_FLARG_PASS); 2011 1.7 christos } 2012 1.1 christos 2013 1.7 christos if (rollback) { 2014 1.1 christos rollback_node(rbtnode, serial); 2015 1.7 christos } 2016 1.22 christos dns__rbtnode_release(rbtdb, rbtnode, least_serial, 2017 1.22 christos &nlocktype, &tlocktype, true, 2018 1.22 christos false DNS__DB_FILELINE); 2019 1.1 christos 2020 1.21 christos NODE_UNLOCK(lock, &nlocktype); 2021 1.1 christos 2022 1.1 christos isc_mem_put(rbtdb->common.mctx, changed, 2023 1.1 christos sizeof(*changed)); 2024 1.1 christos } 2025 1.21 christos if (rbtdb->loop != NULL) { 2026 1.21 christos dns_db_attach((dns_db_t *)rbtdb, &(dns_db_t *){ NULL }); 2027 1.21 christos isc_async_run(rbtdb->loop, cleanup_dead_nodes_callback, 2028 1.21 christos rbtdb); 2029 1.7 christos } else { 2030 1.21 christos TREE_UNLOCK(&rbtdb->tree_lock, &tlocktype); 2031 1.7 christos } 2032 1.21 christos 2033 1.21 christos INSIST(tlocktype == isc_rwlocktype_none); 2034 1.1 christos } 2035 1.1 christos 2036 1.7 christos end: 2037 1.1 christos *versionp = NULL; 2038 1.1 christos } 2039 1.1 christos 2040 1.21 christos isc_result_t 2041 1.21 christos dns__rbtdb_findnodeintree(dns_rbtdb_t *rbtdb, dns_rbt_t *tree, 2042 1.21 christos const dns_name_t *name, bool create, 2043 1.21 christos dns_dbnode_t **nodep DNS__DB_FLARG) { 2044 1.1 christos dns_rbtnode_t *node = NULL; 2045 1.1 christos dns_name_t nodename; 2046 1.1 christos isc_result_t result; 2047 1.21 christos isc_rwlocktype_t tlocktype = isc_rwlocktype_none; 2048 1.1 christos 2049 1.1 christos INSIST(tree == rbtdb->tree || tree == rbtdb->nsec3); 2050 1.1 christos 2051 1.1 christos dns_name_init(&nodename, NULL); 2052 1.21 christos TREE_RDLOCK(&rbtdb->tree_lock, &tlocktype); 2053 1.1 christos result = dns_rbt_findnode(tree, name, NULL, &node, NULL, 2054 1.1 christos DNS_RBTFIND_EMPTYDATA, NULL, NULL); 2055 1.1 christos if (result != ISC_R_SUCCESS) { 2056 1.1 christos if (!create) { 2057 1.7 christos if (result == DNS_R_PARTIALMATCH) { 2058 1.1 christos result = ISC_R_NOTFOUND; 2059 1.7 christos } 2060 1.21 christos goto unlock; 2061 1.1 christos } 2062 1.1 christos /* 2063 1.21 christos * Try to upgrade the lock and if that fails unlock then relock. 2064 1.1 christos */ 2065 1.21 christos TREE_FORCEUPGRADE(&rbtdb->tree_lock, &tlocktype); 2066 1.1 christos node = NULL; 2067 1.1 christos result = dns_rbt_addnode(tree, name, &node); 2068 1.1 christos if (result == ISC_R_SUCCESS) { 2069 1.1 christos dns_rbt_namefromnode(node, &nodename); 2070 1.1 christos node->locknum = node->hashval % rbtdb->node_lock_count; 2071 1.1 christos if (tree == rbtdb->tree) { 2072 1.21 christos dns__zonerbt_addwildcards(rbtdb, name, true); 2073 1.1 christos 2074 1.1 christos if (dns_name_iswildcard(name)) { 2075 1.21 christos result = dns__zonerbt_wildcardmagic( 2076 1.21 christos rbtdb, name, true); 2077 1.1 christos if (result != ISC_R_SUCCESS) { 2078 1.21 christos goto unlock; 2079 1.1 christos } 2080 1.1 christos } 2081 1.1 christos } 2082 1.7 christos if (tree == rbtdb->nsec3) { 2083 1.21 christos node->nsec = DNS_DB_NSEC_NSEC3; 2084 1.7 christos } 2085 1.21 christos } else if (result == ISC_R_EXISTS) { 2086 1.21 christos result = ISC_R_SUCCESS; 2087 1.21 christos } else { 2088 1.21 christos goto unlock; 2089 1.1 christos } 2090 1.1 christos } 2091 1.1 christos 2092 1.7 christos if (tree == rbtdb->nsec3) { 2093 1.21 christos INSIST(node->nsec == DNS_DB_NSEC_NSEC3); 2094 1.7 christos } 2095 1.1 christos 2096 1.21 christos reactivate_node(rbtdb, node, tlocktype DNS__DB_FLARG_PASS); 2097 1.1 christos 2098 1.1 christos *nodep = (dns_dbnode_t *)node; 2099 1.21 christos unlock: 2100 1.21 christos TREE_UNLOCK(&rbtdb->tree_lock, &tlocktype); 2101 1.1 christos 2102 1.21 christos return result; 2103 1.1 christos } 2104 1.1 christos 2105 1.21 christos isc_result_t 2106 1.21 christos dns__rbtdb_findnode(dns_db_t *db, const dns_name_t *name, bool create, 2107 1.21 christos dns_dbnode_t **nodep DNS__DB_FLARG) { 2108 1.1 christos dns_rbtdb_t *rbtdb = (dns_rbtdb_t *)db; 2109 1.1 christos 2110 1.1 christos REQUIRE(VALID_RBTDB(rbtdb)); 2111 1.1 christos 2112 1.21 christos return dns__rbtdb_findnodeintree(rbtdb, rbtdb->tree, name, create, 2113 1.21 christos nodep DNS__DB_FLARG_PASS); 2114 1.1 christos } 2115 1.1 christos 2116 1.21 christos void 2117 1.21 christos dns__rbtdb_bindrdataset(dns_rbtdb_t *rbtdb, dns_rbtnode_t *node, 2118 1.21 christos dns_slabheader_t *header, isc_stdtime_t now, 2119 1.21 christos isc_rwlocktype_t locktype, 2120 1.21 christos dns_rdataset_t *rdataset DNS__DB_FLARG) { 2121 1.14 christos bool stale = STALE(header); 2122 1.14 christos bool ancient = ANCIENT(header); 2123 1.1 christos 2124 1.1 christos /* 2125 1.1 christos * Caller must be holding the node reader lock. 2126 1.1 christos * XXXJT: technically, we need a writer lock, since we'll increment 2127 1.1 christos * the header count below. However, since the actual counter value 2128 1.1 christos * doesn't matter, we prioritize performance here. (We may want to 2129 1.1 christos * use atomic increment when available). 2130 1.1 christos */ 2131 1.1 christos 2132 1.7 christos if (rdataset == NULL) { 2133 1.1 christos return; 2134 1.7 christos } 2135 1.1 christos 2136 1.22 christos dns__rbtnode_acquire(rbtdb, node, locktype DNS__DB_FLARG_PASS); 2137 1.1 christos 2138 1.7 christos INSIST(rdataset->methods == NULL); /* We must be disassociated. */ 2139 1.1 christos 2140 1.14 christos /* 2141 1.14 christos * Mark header stale or ancient if the RRset is no longer active. 2142 1.14 christos */ 2143 1.14 christos if (!ACTIVE(header, now)) { 2144 1.21 christos dns_ttl_t stale_ttl = header->ttl + STALE_TTL(header, rbtdb); 2145 1.14 christos /* 2146 1.14 christos * If this data is in the stale window keep it and if 2147 1.14 christos * DNS_DBFIND_STALEOK is not set we tell the caller to 2148 1.14 christos * skip this record. We skip the records with ZEROTTL 2149 1.14 christos * (these records should not be cached anyway). 2150 1.14 christos */ 2151 1.14 christos 2152 1.22 christos if (!ZEROTTL(header) && KEEPSTALE(rbtdb) && stale_ttl > now) { 2153 1.14 christos stale = true; 2154 1.14 christos } else { 2155 1.14 christos /* 2156 1.14 christos * We are not keeping stale, or it is outside the 2157 1.14 christos * stale window. Mark ancient, i.e. ready for cleanup. 2158 1.14 christos */ 2159 1.14 christos ancient = true; 2160 1.14 christos } 2161 1.14 christos } 2162 1.14 christos 2163 1.21 christos rdataset->methods = &dns_rdataslab_rdatasetmethods; 2164 1.1 christos rdataset->rdclass = rbtdb->common.rdclass; 2165 1.21 christos rdataset->type = DNS_TYPEPAIR_TYPE(header->type); 2166 1.21 christos rdataset->covers = DNS_TYPEPAIR_COVERS(header->type); 2167 1.22 christos rdataset->ttl = !ZEROTTL(header) ? header->ttl - now : 0; 2168 1.1 christos rdataset->trust = header->trust; 2169 1.14 christos 2170 1.7 christos if (NEGATIVE(header)) { 2171 1.1 christos rdataset->attributes |= DNS_RDATASETATTR_NEGATIVE; 2172 1.7 christos } 2173 1.7 christos if (NXDOMAIN(header)) { 2174 1.1 christos rdataset->attributes |= DNS_RDATASETATTR_NXDOMAIN; 2175 1.7 christos } 2176 1.7 christos if (OPTOUT(header)) { 2177 1.1 christos rdataset->attributes |= DNS_RDATASETATTR_OPTOUT; 2178 1.7 christos } 2179 1.7 christos if (PREFETCH(header)) { 2180 1.1 christos rdataset->attributes |= DNS_RDATASETATTR_PREFETCH; 2181 1.7 christos } 2182 1.14 christos 2183 1.14 christos if (stale && !ancient) { 2184 1.21 christos dns_ttl_t stale_ttl = header->ttl + STALE_TTL(header, rbtdb); 2185 1.14 christos if (stale_ttl > now) { 2186 1.14 christos rdataset->ttl = stale_ttl - now; 2187 1.14 christos } else { 2188 1.14 christos rdataset->ttl = 0; 2189 1.14 christos } 2190 1.9 christos if (STALE_WINDOW(header)) { 2191 1.9 christos rdataset->attributes |= DNS_RDATASETATTR_STALE_WINDOW; 2192 1.9 christos } 2193 1.1 christos rdataset->attributes |= DNS_RDATASETATTR_STALE; 2194 1.22 christos rdataset->expire = header->ttl; 2195 1.9 christos } else if (IS_CACHE(rbtdb) && !ACTIVE(header, now)) { 2196 1.9 christos rdataset->attributes |= DNS_RDATASETATTR_ANCIENT; 2197 1.22 christos rdataset->ttl = 0; 2198 1.1 christos } 2199 1.9 christos 2200 1.7 christos rdataset->count = atomic_fetch_add_relaxed(&header->count, 1); 2201 1.1 christos 2202 1.21 christos rdataset->slab.db = (dns_db_t *)rbtdb; 2203 1.21 christos rdataset->slab.node = (dns_dbnode_t *)node; 2204 1.21 christos rdataset->slab.raw = dns_slabheader_raw(header); 2205 1.21 christos rdataset->slab.iter_pos = NULL; 2206 1.21 christos rdataset->slab.iter_count = 0; 2207 1.1 christos 2208 1.1 christos /* 2209 1.1 christos * Add noqname proof. 2210 1.1 christos */ 2211 1.21 christos rdataset->slab.noqname = header->noqname; 2212 1.21 christos if (header->noqname != NULL) { 2213 1.7 christos rdataset->attributes |= DNS_RDATASETATTR_NOQNAME; 2214 1.7 christos } 2215 1.21 christos rdataset->slab.closest = header->closest; 2216 1.21 christos if (header->closest != NULL) { 2217 1.7 christos rdataset->attributes |= DNS_RDATASETATTR_CLOSEST; 2218 1.7 christos } 2219 1.1 christos 2220 1.1 christos /* 2221 1.1 christos * Copy out re-signing information. 2222 1.1 christos */ 2223 1.1 christos if (RESIGN(header)) { 2224 1.7 christos rdataset->attributes |= DNS_RDATASETATTR_RESIGN; 2225 1.1 christos rdataset->resign = (header->resign << 1) | header->resign_lsb; 2226 1.7 christos } else { 2227 1.1 christos rdataset->resign = 0; 2228 1.7 christos } 2229 1.1 christos } 2230 1.1 christos 2231 1.21 christos void 2232 1.21 christos dns__rbtdb_attachnode(dns_db_t *db, dns_dbnode_t *source, 2233 1.21 christos dns_dbnode_t **targetp DNS__DB_FLARG) { 2234 1.21 christos REQUIRE(VALID_RBTDB((dns_rbtdb_t *)db)); 2235 1.21 christos REQUIRE(targetp != NULL && *targetp == NULL); 2236 1.1 christos 2237 1.21 christos dns_rbtnode_t *node = (dns_rbtnode_t *)source; 2238 1.21 christos uint_fast32_t refs = isc_refcount_increment(&node->references); 2239 1.19 christos 2240 1.21 christos #if DNS_DB_NODETRACE 2241 1.21 christos fprintf(stderr, "incr:node:%s:%s:%u:%p->references = %" PRIuFAST32 "\n", 2242 1.21 christos func, file, line, node, refs + 1); 2243 1.21 christos #else 2244 1.21 christos UNUSED(refs); 2245 1.21 christos #endif 2246 1.1 christos 2247 1.21 christos *targetp = source; 2248 1.21 christos } 2249 1.1 christos 2250 1.21 christos void 2251 1.21 christos dns__rbtdb_detachnode(dns_db_t *db, dns_dbnode_t **targetp DNS__DB_FLARG) { 2252 1.21 christos dns_rbtdb_t *rbtdb = (dns_rbtdb_t *)db; 2253 1.21 christos dns_rbtnode_t *node = NULL; 2254 1.21 christos bool want_free = false; 2255 1.21 christos bool inactive = false; 2256 1.21 christos db_nodelock_t *nodelock = NULL; 2257 1.21 christos isc_rwlocktype_t nlocktype = isc_rwlocktype_none; 2258 1.21 christos isc_rwlocktype_t tlocktype = isc_rwlocktype_none; 2259 1.1 christos 2260 1.21 christos REQUIRE(VALID_RBTDB(rbtdb)); 2261 1.21 christos REQUIRE(targetp != NULL && *targetp != NULL); 2262 1.1 christos 2263 1.21 christos node = (dns_rbtnode_t *)(*targetp); 2264 1.21 christos nodelock = &rbtdb->node_locks[node->locknum]; 2265 1.1 christos 2266 1.21 christos NODE_RDLOCK(&nodelock->lock, &nlocktype); 2267 1.1 christos 2268 1.22 christos if (dns__rbtnode_release(rbtdb, node, 0, &nlocktype, &tlocktype, true, 2269 1.22 christos false DNS__DB_FLARG_PASS)) 2270 1.21 christos { 2271 1.21 christos if (isc_refcount_current(&nodelock->references) == 0 && 2272 1.21 christos nodelock->exiting) 2273 1.21 christos { 2274 1.21 christos inactive = true; 2275 1.1 christos } 2276 1.1 christos } 2277 1.1 christos 2278 1.21 christos NODE_UNLOCK(&nodelock->lock, &nlocktype); 2279 1.21 christos INSIST(tlocktype == isc_rwlocktype_none); 2280 1.21 christos 2281 1.21 christos *targetp = NULL; 2282 1.1 christos 2283 1.21 christos if (inactive) { 2284 1.21 christos RWLOCK(&rbtdb->lock, isc_rwlocktype_write); 2285 1.21 christos rbtdb->active--; 2286 1.21 christos if (rbtdb->active == 0) { 2287 1.21 christos want_free = true; 2288 1.21 christos } 2289 1.21 christos RWUNLOCK(&rbtdb->lock, isc_rwlocktype_write); 2290 1.21 christos if (want_free) { 2291 1.21 christos char buf[DNS_NAME_FORMATSIZE]; 2292 1.21 christos if (dns_name_dynamic(&rbtdb->common.origin)) { 2293 1.21 christos dns_name_format(&rbtdb->common.origin, buf, 2294 1.21 christos sizeof(buf)); 2295 1.21 christos } else { 2296 1.21 christos strlcpy(buf, "<UNKNOWN>", sizeof(buf)); 2297 1.21 christos } 2298 1.21 christos isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE, 2299 1.21 christos DNS_LOGMODULE_CACHE, ISC_LOG_DEBUG(1), 2300 1.21 christos "calling free_rbtdb(%s)", buf); 2301 1.21 christos free_rbtdb(rbtdb, true); 2302 1.1 christos } 2303 1.1 christos } 2304 1.1 christos } 2305 1.1 christos 2306 1.21 christos isc_result_t 2307 1.21 christos dns__rbtdb_createiterator(dns_db_t *db, unsigned int options, 2308 1.21 christos dns_dbiterator_t **iteratorp) { 2309 1.21 christos dns_rbtdb_t *rbtdb = (dns_rbtdb_t *)db; 2310 1.21 christos rbtdb_dbiterator_t *rbtdbiter = NULL; 2311 1.1 christos 2312 1.21 christos REQUIRE(VALID_RBTDB(rbtdb)); 2313 1.21 christos REQUIRE((options & (DNS_DB_NSEC3ONLY | DNS_DB_NONSEC3)) != 2314 1.21 christos (DNS_DB_NSEC3ONLY | DNS_DB_NONSEC3)); 2315 1.1 christos 2316 1.21 christos rbtdbiter = isc_mem_get(rbtdb->common.mctx, sizeof(*rbtdbiter)); 2317 1.1 christos 2318 1.21 christos rbtdbiter->common.methods = &dbiterator_methods; 2319 1.21 christos rbtdbiter->common.db = NULL; 2320 1.21 christos dns_db_attach(db, &rbtdbiter->common.db); 2321 1.21 christos rbtdbiter->common.relative_names = ((options & DNS_DB_RELATIVENAMES) != 2322 1.21 christos 0); 2323 1.21 christos rbtdbiter->common.magic = DNS_DBITERATOR_MAGIC; 2324 1.21 christos rbtdbiter->paused = true; 2325 1.21 christos rbtdbiter->tree_locked = isc_rwlocktype_none; 2326 1.21 christos rbtdbiter->result = ISC_R_SUCCESS; 2327 1.21 christos dns_fixedname_init(&rbtdbiter->name); 2328 1.21 christos dns_fixedname_init(&rbtdbiter->origin); 2329 1.21 christos rbtdbiter->node = NULL; 2330 1.21 christos if ((options & DNS_DB_NSEC3ONLY) != 0) { 2331 1.21 christos rbtdbiter->nsec3mode = nsec3only; 2332 1.21 christos } else if ((options & DNS_DB_NONSEC3) != 0) { 2333 1.21 christos rbtdbiter->nsec3mode = nonsec3; 2334 1.21 christos } else { 2335 1.21 christos rbtdbiter->nsec3mode = full; 2336 1.1 christos } 2337 1.21 christos dns_rbtnodechain_init(&rbtdbiter->chain); 2338 1.21 christos dns_rbtnodechain_init(&rbtdbiter->nsec3chain); 2339 1.21 christos if (rbtdbiter->nsec3mode == nsec3only) { 2340 1.21 christos rbtdbiter->current = &rbtdbiter->nsec3chain; 2341 1.21 christos } else { 2342 1.21 christos rbtdbiter->current = &rbtdbiter->chain; 2343 1.7 christos } 2344 1.21 christos 2345 1.21 christos *iteratorp = (dns_dbiterator_t *)rbtdbiter; 2346 1.21 christos 2347 1.21 christos return ISC_R_SUCCESS; 2348 1.1 christos } 2349 1.1 christos 2350 1.21 christos isc_result_t 2351 1.21 christos dns__rbtdb_allrdatasets(dns_db_t *db, dns_dbnode_t *node, 2352 1.21 christos dns_dbversion_t *version, unsigned int options, 2353 1.21 christos isc_stdtime_t now, 2354 1.21 christos dns_rdatasetiter_t **iteratorp DNS__DB_FLARG) { 2355 1.21 christos dns_rbtdb_t *rbtdb = (dns_rbtdb_t *)db; 2356 1.21 christos dns_rbtnode_t *rbtnode = (dns_rbtnode_t *)node; 2357 1.21 christos dns_rbtdb_version_t *rbtversion = version; 2358 1.21 christos rbtdb_rdatasetiter_t *iterator = NULL; 2359 1.21 christos uint_fast32_t refs; 2360 1.1 christos 2361 1.21 christos REQUIRE(VALID_RBTDB(rbtdb)); 2362 1.1 christos 2363 1.21 christos iterator = isc_mem_get(rbtdb->common.mctx, sizeof(*iterator)); 2364 1.1 christos 2365 1.21 christos if ((db->attributes & DNS_DBATTR_CACHE) == 0) { 2366 1.21 christos now = 0; 2367 1.21 christos if (rbtversion == NULL) { 2368 1.21 christos dns__rbtdb_currentversion( 2369 1.21 christos db, (dns_dbversion_t **)(void *)(&rbtversion)); 2370 1.21 christos } else { 2371 1.21 christos INSIST(rbtversion->rbtdb == rbtdb); 2372 1.1 christos 2373 1.21 christos (void)isc_refcount_increment(&rbtversion->references); 2374 1.7 christos } 2375 1.21 christos } else { 2376 1.21 christos if (now == 0) { 2377 1.21 christos now = isc_stdtime_now(); 2378 1.1 christos } 2379 1.21 christos rbtversion = NULL; 2380 1.7 christos } 2381 1.1 christos 2382 1.21 christos iterator->common.magic = DNS_RDATASETITER_MAGIC; 2383 1.21 christos iterator->common.methods = &rdatasetiter_methods; 2384 1.21 christos iterator->common.db = db; 2385 1.21 christos iterator->common.node = node; 2386 1.21 christos iterator->common.version = (dns_dbversion_t *)rbtversion; 2387 1.21 christos iterator->common.options = options; 2388 1.21 christos iterator->common.now = now; 2389 1.21 christos 2390 1.21 christos refs = isc_refcount_increment(&rbtnode->references); 2391 1.21 christos #if DNS_DB_NODETRACE 2392 1.21 christos fprintf(stderr, "incr:node:%s:%s:%u:%p->references = %" PRIuFAST32 "\n", 2393 1.21 christos func, file, line, node, refs + 1); 2394 1.21 christos #else 2395 1.21 christos UNUSED(refs); 2396 1.21 christos #endif 2397 1.1 christos 2398 1.21 christos iterator->current = NULL; 2399 1.1 christos 2400 1.21 christos *iteratorp = (dns_rdatasetiter_t *)iterator; 2401 1.1 christos 2402 1.21 christos return ISC_R_SUCCESS; 2403 1.1 christos } 2404 1.1 christos 2405 1.21 christos static bool 2406 1.21 christos cname_and_other_data(dns_rbtnode_t *node, uint32_t serial) { 2407 1.21 christos dns_slabheader_t *header = NULL, *header_next = NULL; 2408 1.21 christos bool cname = false, other_data = false; 2409 1.21 christos dns_rdatatype_t rdtype; 2410 1.1 christos 2411 1.1 christos /* 2412 1.21 christos * The caller must hold the node lock. 2413 1.1 christos */ 2414 1.1 christos 2415 1.1 christos /* 2416 1.21 christos * Look for CNAME and "other data" rdatasets active in our version. 2417 1.1 christos */ 2418 1.21 christos for (header = node->data; header != NULL; header = header_next) { 2419 1.21 christos header_next = header->next; 2420 1.21 christos if (header->type == dns_rdatatype_cname) { 2421 1.1 christos /* 2422 1.21 christos * Look for an active extant CNAME. 2423 1.1 christos */ 2424 1.21 christos do { 2425 1.21 christos if (header->serial <= serial && !IGNORE(header)) 2426 1.16 christos { 2427 1.1 christos /* 2428 1.21 christos * Is this a "this rdataset doesn't 2429 1.21 christos * exist" record? 2430 1.1 christos */ 2431 1.21 christos if (NONEXISTENT(header)) { 2432 1.21 christos header = NULL; 2433 1.21 christos } 2434 1.1 christos break; 2435 1.21 christos } else { 2436 1.21 christos header = header->down; 2437 1.1 christos } 2438 1.21 christos } while (header != NULL); 2439 1.21 christos if (header != NULL) { 2440 1.21 christos cname = true; 2441 1.21 christos } 2442 1.21 christos } else { 2443 1.21 christos /* 2444 1.21 christos * Look for active extant "other data". 2445 1.21 christos * 2446 1.21 christos * "Other data" is any rdataset whose type is not 2447 1.21 christos * KEY, NSEC, SIG or RRSIG. 2448 1.21 christos */ 2449 1.21 christos rdtype = DNS_TYPEPAIR_TYPE(header->type); 2450 1.21 christos if (rdtype != dns_rdatatype_key && 2451 1.21 christos rdtype != dns_rdatatype_sig && 2452 1.21 christos rdtype != dns_rdatatype_nsec && 2453 1.21 christos rdtype != dns_rdatatype_rrsig) 2454 1.16 christos { 2455 1.1 christos /* 2456 1.21 christos * Is it active and extant? 2457 1.1 christos */ 2458 1.21 christos do { 2459 1.21 christos if (header->serial <= serial && 2460 1.21 christos !IGNORE(header)) 2461 1.21 christos { 2462 1.21 christos /* 2463 1.21 christos * Is this a "this rdataset 2464 1.21 christos * doesn't exist" record? 2465 1.21 christos */ 2466 1.21 christos if (NONEXISTENT(header)) { 2467 1.21 christos header = NULL; 2468 1.21 christos } 2469 1.21 christos break; 2470 1.21 christos } else { 2471 1.21 christos header = header->down; 2472 1.21 christos } 2473 1.21 christos } while (header != NULL); 2474 1.21 christos if (header != NULL) { 2475 1.22 christos if (!prio_type(header->type)) { 2476 1.22 christos /* 2477 1.22 christos * CNAME is in the priority 2478 1.22 christos * list, so if we are done with 2479 1.22 christos * priority types, we know there 2480 1.22 christos * will not be a CNAME, and are 2481 1.22 christos * safe to skip the rest. 2482 1.22 christos */ 2483 1.22 christos return cname; 2484 1.22 christos } 2485 1.21 christos other_data = true; 2486 1.21 christos } 2487 1.1 christos } 2488 1.1 christos } 2489 1.21 christos if (cname && other_data) { 2490 1.21 christos return true; 2491 1.21 christos } 2492 1.21 christos } 2493 1.1 christos 2494 1.21 christos return false; 2495 1.21 christos } 2496 1.21 christos 2497 1.21 christos static uint64_t 2498 1.21 christos recordsize(dns_slabheader_t *header, unsigned int namelen) { 2499 1.21 christos return dns_rdataslab_rdatasize((unsigned char *)header, 2500 1.21 christos sizeof(*header)) + 2501 1.21 christos sizeof(dns_ttl_t) + sizeof(dns_rdatatype_t) + 2502 1.21 christos sizeof(dns_rdataclass_t) + namelen; 2503 1.21 christos } 2504 1.1 christos 2505 1.21 christos static void 2506 1.21 christos update_recordsandxfrsize(bool add, dns_rbtdb_version_t *rbtversion, 2507 1.21 christos dns_slabheader_t *header, unsigned int namelen) { 2508 1.21 christos unsigned char *hdr = (unsigned char *)header; 2509 1.21 christos size_t hdrsize = sizeof(*header); 2510 1.1 christos 2511 1.21 christos RWLOCK(&rbtversion->rwlock, isc_rwlocktype_write); 2512 1.21 christos if (add) { 2513 1.21 christos rbtversion->records += dns_rdataslab_count(hdr, hdrsize); 2514 1.21 christos rbtversion->xfrsize += recordsize(header, namelen); 2515 1.21 christos } else { 2516 1.21 christos rbtversion->records -= dns_rdataslab_count(hdr, hdrsize); 2517 1.21 christos rbtversion->xfrsize -= recordsize(header, namelen); 2518 1.21 christos } 2519 1.21 christos RWUNLOCK(&rbtversion->rwlock, isc_rwlocktype_write); 2520 1.1 christos } 2521 1.1 christos 2522 1.3 christos static bool 2523 1.21 christos overmaxtype(dns_rbtdb_t *rbtdb, uint32_t ntypes) { 2524 1.21 christos if (rbtdb->maxtypepername == 0) { 2525 1.21 christos return false; 2526 1.21 christos } 2527 1.1 christos 2528 1.21 christos return ntypes >= rbtdb->maxtypepername; 2529 1.21 christos } 2530 1.1 christos 2531 1.21 christos static bool 2532 1.21 christos prio_header(dns_slabheader_t *header) { 2533 1.21 christos if (NEGATIVE(header) && prio_type(DNS_TYPEPAIR_COVERS(header->type))) { 2534 1.21 christos return true; 2535 1.1 christos } 2536 1.21 christos 2537 1.21 christos return prio_type(header->type); 2538 1.1 christos } 2539 1.1 christos 2540 1.21 christos isc_result_t 2541 1.21 christos dns__rbtdb_add(dns_rbtdb_t *rbtdb, dns_rbtnode_t *rbtnode, 2542 1.21 christos const dns_name_t *nodename, dns_rbtdb_version_t *rbtversion, 2543 1.21 christos dns_slabheader_t *newheader, unsigned int options, bool loading, 2544 1.21 christos dns_rdataset_t *addedrdataset, isc_stdtime_t now DNS__DB_FLARG) { 2545 1.21 christos rbtdb_changed_t *changed = NULL; 2546 1.21 christos dns_slabheader_t *topheader = NULL, *topheader_prev = NULL; 2547 1.21 christos dns_slabheader_t *header = NULL, *sigheader = NULL; 2548 1.21 christos dns_slabheader_t *prioheader = NULL, *expireheader = NULL; 2549 1.21 christos unsigned char *merged = NULL; 2550 1.1 christos isc_result_t result; 2551 1.21 christos bool header_nx; 2552 1.21 christos bool newheader_nx; 2553 1.21 christos bool merge; 2554 1.21 christos dns_rdatatype_t rdtype, covers; 2555 1.21 christos dns_typepair_t negtype = 0, sigtype; 2556 1.21 christos dns_trust_t trust; 2557 1.21 christos int idx; 2558 1.21 christos uint32_t ntypes = 0; 2559 1.21 christos 2560 1.21 christos if ((options & DNS_DBADD_MERGE) != 0) { 2561 1.21 christos REQUIRE(rbtversion != NULL); 2562 1.21 christos merge = true; 2563 1.21 christos } else { 2564 1.21 christos merge = false; 2565 1.21 christos } 2566 1.1 christos 2567 1.21 christos if ((options & DNS_DBADD_FORCE) != 0) { 2568 1.21 christos trust = dns_trust_ultimate; 2569 1.21 christos } else { 2570 1.21 christos trust = newheader->trust; 2571 1.21 christos } 2572 1.1 christos 2573 1.21 christos if (rbtversion != NULL && !loading) { 2574 1.21 christos /* 2575 1.21 christos * We always add a changed record, even if no changes end up 2576 1.21 christos * being made to this node, because it's harmless and 2577 1.21 christos * simplifies the code. 2578 1.21 christos */ 2579 1.21 christos changed = add_changed(newheader, rbtversion DNS__DB_FLARG_PASS); 2580 1.21 christos if (changed == NULL) { 2581 1.21 christos dns_slabheader_destroy(&newheader); 2582 1.21 christos return ISC_R_NOMEMORY; 2583 1.7 christos } 2584 1.1 christos } 2585 1.1 christos 2586 1.21 christos newheader_nx = NONEXISTENT(newheader) ? true : false; 2587 1.21 christos if (rbtversion == NULL && !newheader_nx) { 2588 1.21 christos rdtype = DNS_TYPEPAIR_TYPE(newheader->type); 2589 1.21 christos covers = DNS_TYPEPAIR_COVERS(newheader->type); 2590 1.21 christos sigtype = DNS_SIGTYPE(covers); 2591 1.21 christos if (NEGATIVE(newheader)) { 2592 1.1 christos /* 2593 1.21 christos * We're adding a negative cache entry. 2594 1.1 christos */ 2595 1.21 christos if (covers == dns_rdatatype_any) { 2596 1.1 christos /* 2597 1.21 christos * If we're adding an negative cache entry 2598 1.21 christos * which covers all types (NXDOMAIN, 2599 1.21 christos * NODATA(QTYPE=ANY)), 2600 1.21 christos * 2601 1.21 christos * We make all other data ancient so that the 2602 1.21 christos * only rdataset that can be found at this 2603 1.21 christos * node is the negative cache entry. 2604 1.1 christos */ 2605 1.21 christos for (topheader = rbtnode->data; 2606 1.21 christos topheader != NULL; 2607 1.21 christos topheader = topheader->next) 2608 1.21 christos { 2609 1.22 christos dns__rbtdb_mark_ancient(topheader); 2610 1.7 christos } 2611 1.21 christos goto find_header; 2612 1.21 christos } 2613 1.21 christos /* 2614 1.21 christos * Otherwise look for any RRSIGs of the given 2615 1.21 christos * type so they can be marked ancient later. 2616 1.21 christos */ 2617 1.21 christos for (topheader = rbtnode->data; topheader != NULL; 2618 1.21 christos topheader = topheader->next) 2619 1.16 christos { 2620 1.21 christos if (topheader->type == sigtype) { 2621 1.21 christos sigheader = topheader; 2622 1.21 christos break; 2623 1.7 christos } 2624 1.1 christos } 2625 1.21 christos negtype = DNS_TYPEPAIR_VALUE(covers, 0); 2626 1.1 christos } else { 2627 1.1 christos /* 2628 1.21 christos * We're adding something that isn't a 2629 1.21 christos * negative cache entry. Look for an extant 2630 1.21 christos * non-ancient NXDOMAIN/NODATA(QTYPE=ANY) negative 2631 1.21 christos * cache entry. If we're adding an RRSIG, also 2632 1.21 christos * check for an extant non-ancient NODATA ncache 2633 1.21 christos * entry which covers the same type as the RRSIG. 2634 1.1 christos */ 2635 1.21 christos for (topheader = rbtnode->data; topheader != NULL; 2636 1.21 christos topheader = topheader->next) 2637 1.21 christos { 2638 1.21 christos if ((topheader->type == RDATATYPE_NCACHEANY) || 2639 1.21 christos (newheader->type == sigtype && 2640 1.21 christos topheader->type == 2641 1.21 christos DNS_TYPEPAIR_VALUE(0, covers))) 2642 1.16 christos { 2643 1.1 christos break; 2644 1.1 christos } 2645 1.1 christos } 2646 1.21 christos if (topheader != NULL && EXISTS(topheader) && 2647 1.21 christos ACTIVE(topheader, now)) 2648 1.16 christos { 2649 1.1 christos /* 2650 1.21 christos * Found one. 2651 1.1 christos */ 2652 1.21 christos if (trust < topheader->trust) { 2653 1.21 christos /* 2654 1.21 christos * The NXDOMAIN/NODATA(QTYPE=ANY) 2655 1.21 christos * is more trusted. 2656 1.21 christos */ 2657 1.21 christos dns_slabheader_destroy(&newheader); 2658 1.21 christos if (addedrdataset != NULL) { 2659 1.21 christos dns__rbtdb_bindrdataset( 2660 1.21 christos rbtdb, rbtnode, 2661 1.21 christos topheader, now, 2662 1.21 christos isc_rwlocktype_write, 2663 1.21 christos addedrdataset 2664 1.21 christos DNS__DB_FLARG_PASS); 2665 1.7 christos } 2666 1.21 christos return DNS_R_UNCHANGED; 2667 1.1 christos } 2668 1.1 christos /* 2669 1.21 christos * The new rdataset is better. Expire the 2670 1.21 christos * ncache entry. 2671 1.1 christos */ 2672 1.22 christos dns__rbtdb_mark_ancient(topheader); 2673 1.21 christos topheader = NULL; 2674 1.21 christos goto find_header; 2675 1.1 christos } 2676 1.21 christos negtype = DNS_TYPEPAIR_VALUE(0, rdtype); 2677 1.1 christos } 2678 1.7 christos } 2679 1.1 christos 2680 1.21 christos for (topheader = rbtnode->data; topheader != NULL; 2681 1.21 christos topheader = topheader->next) 2682 1.21 christos { 2683 1.21 christos if (IS_CACHE(rbtdb) && ACTIVE(topheader, now)) { 2684 1.21 christos ++ntypes; 2685 1.21 christos expireheader = topheader; 2686 1.21 christos } else if (!IS_CACHE(rbtdb)) { 2687 1.21 christos ++ntypes; 2688 1.21 christos } 2689 1.21 christos if (prio_header(topheader)) { 2690 1.21 christos prioheader = topheader; 2691 1.21 christos } 2692 1.21 christos if (topheader->type == newheader->type || 2693 1.21 christos topheader->type == negtype) 2694 1.21 christos { 2695 1.21 christos break; 2696 1.1 christos } 2697 1.21 christos topheader_prev = topheader; 2698 1.1 christos } 2699 1.1 christos 2700 1.21 christos find_header: 2701 1.1 christos /* 2702 1.21 christos * If header isn't NULL, we've found the right type. There may be 2703 1.21 christos * IGNORE rdatasets between the top of the chain and the first real 2704 1.21 christos * data. We skip over them. 2705 1.1 christos */ 2706 1.21 christos header = topheader; 2707 1.21 christos while (header != NULL && IGNORE(header)) { 2708 1.21 christos header = header->down; 2709 1.7 christos } 2710 1.21 christos if (header != NULL) { 2711 1.21 christos header_nx = NONEXISTENT(header) ? true : false; 2712 1.1 christos 2713 1.21 christos /* 2714 1.21 christos * Deleting an already non-existent rdataset has no effect. 2715 1.21 christos */ 2716 1.21 christos if (header_nx && newheader_nx) { 2717 1.21 christos dns_slabheader_destroy(&newheader); 2718 1.21 christos return DNS_R_UNCHANGED; 2719 1.8 christos } 2720 1.1 christos 2721 1.1 christos /* 2722 1.21 christos * Trying to add an rdataset with lower trust to a cache 2723 1.21 christos * DB has no effect, provided that the cache data isn't 2724 1.21 christos * stale. If the cache data is stale, new lower trust 2725 1.21 christos * data will supersede it below. Unclear what the best 2726 1.21 christos * policy is here. 2727 1.1 christos */ 2728 1.21 christos if (rbtversion == NULL && trust < header->trust && 2729 1.21 christos (ACTIVE(header, now) || header_nx)) 2730 1.1 christos { 2731 1.23 christos result = DNS_R_UNCHANGED; 2732 1.23 christos dns__rbtdb_bindrdataset( 2733 1.23 christos rbtdb, rbtnode, header, now, 2734 1.23 christos isc_rwlocktype_write, 2735 1.23 christos addedrdataset DNS__DB_FLARG_PASS); 2736 1.23 christos if (ACTIVE(header, now) && 2737 1.23 christos (options & DNS_DBADD_EQUALOK) != 0 && 2738 1.23 christos dns_rdataslab_equalx( 2739 1.23 christos (unsigned char *)header, 2740 1.23 christos (unsigned char *)newheader, 2741 1.23 christos (unsigned int)(sizeof(*newheader)), 2742 1.23 christos rbtdb->common.rdclass, 2743 1.23 christos (dns_rdatatype_t)header->type)) 2744 1.23 christos { 2745 1.23 christos result = ISC_R_SUCCESS; 2746 1.23 christos } 2747 1.21 christos dns_slabheader_destroy(&newheader); 2748 1.23 christos return result; 2749 1.7 christos } 2750 1.1 christos 2751 1.1 christos /* 2752 1.21 christos * Don't merge if a nonexistent rdataset is involved. 2753 1.1 christos */ 2754 1.21 christos if (merge && (header_nx || newheader_nx)) { 2755 1.21 christos merge = false; 2756 1.7 christos } 2757 1.1 christos 2758 1.1 christos /* 2759 1.21 christos * If 'merge' is true, we'll try to create a new rdataset 2760 1.21 christos * that is the union of 'newheader' and 'header'. 2761 1.1 christos */ 2762 1.21 christos if (merge) { 2763 1.21 christos unsigned int flags = 0; 2764 1.21 christos INSIST(rbtversion->serial >= header->serial); 2765 1.21 christos merged = NULL; 2766 1.21 christos result = ISC_R_SUCCESS; 2767 1.21 christos 2768 1.21 christos if ((options & DNS_DBADD_EXACT) != 0) { 2769 1.21 christos flags |= DNS_RDATASLAB_EXACT; 2770 1.7 christos } 2771 1.1 christos /* 2772 1.21 christos * TTL use here is irrelevant to the cache; 2773 1.21 christos * merge is only done with zonedbs. 2774 1.1 christos */ 2775 1.21 christos if ((options & DNS_DBADD_EXACTTTL) != 0 && 2776 1.21 christos newheader->ttl != header->ttl) 2777 1.21 christos { 2778 1.21 christos result = DNS_R_NOTEXACT; 2779 1.21 christos } else if (newheader->ttl != header->ttl) { 2780 1.21 christos flags |= DNS_RDATASLAB_FORCE; 2781 1.21 christos } 2782 1.21 christos if (result == ISC_R_SUCCESS) { 2783 1.21 christos result = dns_rdataslab_merge( 2784 1.21 christos (unsigned char *)header, 2785 1.21 christos (unsigned char *)newheader, 2786 1.21 christos (unsigned int)(sizeof(*newheader)), 2787 1.21 christos rbtdb->common.mctx, 2788 1.21 christos rbtdb->common.rdclass, 2789 1.21 christos (dns_rdatatype_t)header->type, flags, 2790 1.21 christos rbtdb->maxrrperset, &merged); 2791 1.21 christos } 2792 1.21 christos if (result == ISC_R_SUCCESS) { 2793 1.1 christos /* 2794 1.21 christos * If 'header' has the same serial number as 2795 1.21 christos * we do, we could clean it up now if we knew 2796 1.21 christos * that our caller had no references to it. 2797 1.21 christos * We don't know this, however, so we leave it 2798 1.21 christos * alone. It will get cleaned up when 2799 1.21 christos * clean_zone_node() runs. 2800 1.1 christos */ 2801 1.21 christos dns_slabheader_destroy(&newheader); 2802 1.21 christos newheader = (dns_slabheader_t *)merged; 2803 1.21 christos dns_slabheader_reset(newheader, 2804 1.21 christos (dns_db_t *)rbtdb, 2805 1.21 christos (dns_dbnode_t *)rbtnode); 2806 1.21 christos dns_slabheader_copycase(newheader, header); 2807 1.21 christos if (loading && RESIGN(newheader) && 2808 1.21 christos RESIGN(header) && 2809 1.21 christos resign_sooner(header, newheader)) 2810 1.7 christos { 2811 1.21 christos newheader->resign = header->resign; 2812 1.21 christos newheader->resign_lsb = 2813 1.21 christos header->resign_lsb; 2814 1.1 christos } 2815 1.21 christos } else { 2816 1.21 christos if (result == DNS_R_TOOMANYRECORDS) { 2817 1.21 christos dns__db_logtoomanyrecords( 2818 1.21 christos (dns_db_t *)rbtdb, nodename, 2819 1.21 christos (dns_rdatatype_t)(header->type), 2820 1.21 christos "updating", rbtdb->maxrrperset); 2821 1.7 christos } 2822 1.21 christos dns_slabheader_destroy(&newheader); 2823 1.21 christos return result; 2824 1.1 christos } 2825 1.21 christos } 2826 1.21 christos /* 2827 1.23 christos * Don't replace existing NS in the cache if they already exist 2828 1.23 christos * and replacing the existing one would increase the TTL. This 2829 1.23 christos * prevents named being locked to old servers. Don't lower trust 2830 1.23 christos * of existing record if the update is forced. Nothing special 2831 1.23 christos * to be done w.r.t stale data; it gets replaced normally 2832 1.23 christos * further down. 2833 1.21 christos */ 2834 1.21 christos if (IS_CACHE(rbtdb) && ACTIVE(header, now) && 2835 1.21 christos header->type == dns_rdatatype_ns && !header_nx && 2836 1.21 christos !newheader_nx && header->trust >= newheader->trust && 2837 1.23 christos header->ttl < newheader->ttl && 2838 1.21 christos dns_rdataslab_equalx((unsigned char *)header, 2839 1.21 christos (unsigned char *)newheader, 2840 1.21 christos (unsigned int)(sizeof(*newheader)), 2841 1.21 christos rbtdb->common.rdclass, 2842 1.21 christos (dns_rdatatype_t)header->type)) 2843 1.21 christos { 2844 1.21 christos if (header->last_used != now) { 2845 1.21 christos ISC_LIST_UNLINK( 2846 1.21 christos rbtdb->lru[RBTDB_HEADERNODE(header) 2847 1.21 christos ->locknum], 2848 1.21 christos header, link); 2849 1.21 christos header->last_used = now; 2850 1.21 christos ISC_LIST_PREPEND( 2851 1.21 christos rbtdb->lru[RBTDB_HEADERNODE(header) 2852 1.21 christos ->locknum], 2853 1.21 christos header, link); 2854 1.21 christos } 2855 1.21 christos if (header->noqname == NULL && 2856 1.21 christos newheader->noqname != NULL) 2857 1.16 christos { 2858 1.21 christos header->noqname = newheader->noqname; 2859 1.21 christos newheader->noqname = NULL; 2860 1.1 christos } 2861 1.21 christos if (header->closest == NULL && 2862 1.21 christos newheader->closest != NULL) 2863 1.7 christos { 2864 1.21 christos header->closest = newheader->closest; 2865 1.21 christos newheader->closest = NULL; 2866 1.21 christos } 2867 1.21 christos dns_slabheader_destroy(&newheader); 2868 1.21 christos if (addedrdataset != NULL) { 2869 1.21 christos dns__rbtdb_bindrdataset( 2870 1.21 christos rbtdb, rbtnode, header, now, 2871 1.21 christos isc_rwlocktype_write, 2872 1.21 christos addedrdataset DNS__DB_FLARG_PASS); 2873 1.1 christos } 2874 1.21 christos return ISC_R_SUCCESS; 2875 1.1 christos } 2876 1.1 christos 2877 1.1 christos /* 2878 1.23 christos * If we will be replacing a NS RRset force its TTL 2879 1.21 christos * to be no more than the current NS RRset's TTL. This 2880 1.21 christos * ensures the delegations that are withdrawn are honoured. 2881 1.1 christos */ 2882 1.21 christos if (IS_CACHE(rbtdb) && ACTIVE(header, now) && 2883 1.21 christos header->type == dns_rdatatype_ns && !header_nx && 2884 1.21 christos !newheader_nx && header->trust <= newheader->trust) 2885 1.21 christos { 2886 1.21 christos if (newheader->ttl > header->ttl) { 2887 1.23 christos if (ZEROTTL(header)) { 2888 1.23 christos DNS_SLABHEADER_SETATTR( 2889 1.23 christos newheader, 2890 1.23 christos DNS_SLABHEADERATTR_ZEROTTL); 2891 1.23 christos } 2892 1.21 christos newheader->ttl = header->ttl; 2893 1.21 christos } 2894 1.1 christos } 2895 1.21 christos if (IS_CACHE(rbtdb) && ACTIVE(header, now) && 2896 1.21 christos (options & DNS_DBADD_PREFETCH) == 0 && 2897 1.21 christos (header->type == dns_rdatatype_a || 2898 1.21 christos header->type == dns_rdatatype_aaaa || 2899 1.21 christos header->type == dns_rdatatype_ds || 2900 1.21 christos header->type == DNS_SIGTYPE(dns_rdatatype_ds)) && 2901 1.21 christos !header_nx && !newheader_nx && 2902 1.21 christos header->trust >= newheader->trust && 2903 1.23 christos header->ttl < newheader->ttl && 2904 1.21 christos dns_rdataslab_equal((unsigned char *)header, 2905 1.21 christos (unsigned char *)newheader, 2906 1.21 christos (unsigned int)(sizeof(*newheader)))) 2907 1.7 christos { 2908 1.21 christos if (header->last_used != now) { 2909 1.21 christos ISC_LIST_UNLINK( 2910 1.21 christos rbtdb->lru[RBTDB_HEADERNODE(header) 2911 1.21 christos ->locknum], 2912 1.21 christos header, link); 2913 1.21 christos header->last_used = now; 2914 1.21 christos ISC_LIST_PREPEND( 2915 1.21 christos rbtdb->lru[RBTDB_HEADERNODE(header) 2916 1.21 christos ->locknum], 2917 1.21 christos header, link); 2918 1.21 christos } 2919 1.21 christos if (header->noqname == NULL && 2920 1.21 christos newheader->noqname != NULL) 2921 1.21 christos { 2922 1.21 christos header->noqname = newheader->noqname; 2923 1.21 christos newheader->noqname = NULL; 2924 1.21 christos } 2925 1.21 christos if (header->closest == NULL && 2926 1.21 christos newheader->closest != NULL) 2927 1.21 christos { 2928 1.21 christos header->closest = newheader->closest; 2929 1.21 christos newheader->closest = NULL; 2930 1.1 christos } 2931 1.21 christos dns_slabheader_destroy(&newheader); 2932 1.21 christos if (addedrdataset != NULL) { 2933 1.21 christos dns__rbtdb_bindrdataset( 2934 1.21 christos rbtdb, rbtnode, header, now, 2935 1.21 christos isc_rwlocktype_write, 2936 1.21 christos addedrdataset DNS__DB_FLARG_PASS); 2937 1.7 christos } 2938 1.21 christos return ISC_R_SUCCESS; 2939 1.1 christos } 2940 1.21 christos INSIST(rbtversion == NULL || 2941 1.21 christos rbtversion->serial >= topheader->serial); 2942 1.21 christos if (loading) { 2943 1.21 christos newheader->down = NULL; 2944 1.21 christos idx = RBTDB_HEADERNODE(newheader)->locknum; 2945 1.21 christos if (IS_CACHE(rbtdb)) { 2946 1.21 christos if (ZEROTTL(newheader)) { 2947 1.21 christos newheader->last_used = 2948 1.21 christos rbtdb->last_used + 1; 2949 1.21 christos ISC_LIST_APPEND(rbtdb->lru[idx], 2950 1.21 christos newheader, link); 2951 1.21 christos } else { 2952 1.21 christos ISC_LIST_PREPEND(rbtdb->lru[idx], 2953 1.21 christos newheader, link); 2954 1.21 christos } 2955 1.21 christos INSIST(rbtdb->heaps != NULL); 2956 1.21 christos isc_heap_insert(rbtdb->heaps[idx], newheader); 2957 1.21 christos newheader->heap = rbtdb->heaps[idx]; 2958 1.21 christos } else if (RESIGN(newheader)) { 2959 1.21 christos dns__zonerbt_resigninsert(rbtdb, idx, 2960 1.21 christos newheader); 2961 1.21 christos /* 2962 1.21 christos * Don't call resigndelete, we don't need 2963 1.21 christos * to reverse the delete. The free_slabheader 2964 1.21 christos * call below will clean up the heap entry. 2965 1.21 christos */ 2966 1.7 christos } 2967 1.1 christos 2968 1.1 christos /* 2969 1.21 christos * There are no other references to 'header' when 2970 1.21 christos * loading, so we MAY clean up 'header' now. 2971 1.21 christos * Since we don't generate changed records when 2972 1.21 christos * loading, we MUST clean up 'header' now. 2973 1.1 christos */ 2974 1.21 christos if (topheader_prev != NULL) { 2975 1.21 christos topheader_prev->next = newheader; 2976 1.7 christos } else { 2977 1.21 christos rbtnode->data = newheader; 2978 1.21 christos } 2979 1.21 christos newheader->next = topheader->next; 2980 1.21 christos if (rbtversion != NULL && !header_nx) { 2981 1.21 christos update_recordsandxfrsize(false, rbtversion, 2982 1.21 christos header, 2983 1.21 christos nodename->length); 2984 1.7 christos } 2985 1.21 christos dns_slabheader_destroy(&header); 2986 1.7 christos } else { 2987 1.21 christos idx = RBTDB_HEADERNODE(newheader)->locknum; 2988 1.21 christos if (IS_CACHE(rbtdb)) { 2989 1.21 christos INSIST(rbtdb->heaps != NULL); 2990 1.21 christos isc_heap_insert(rbtdb->heaps[idx], newheader); 2991 1.21 christos newheader->heap = rbtdb->heaps[idx]; 2992 1.21 christos if (ZEROTTL(newheader)) { 2993 1.21 christos newheader->last_used = 2994 1.21 christos rbtdb->last_used + 1; 2995 1.21 christos ISC_LIST_APPEND(rbtdb->lru[idx], 2996 1.21 christos newheader, link); 2997 1.21 christos } else { 2998 1.21 christos ISC_LIST_PREPEND(rbtdb->lru[idx], 2999 1.21 christos newheader, link); 3000 1.21 christos } 3001 1.21 christos } else if (RESIGN(newheader)) { 3002 1.21 christos dns__zonerbt_resigninsert(rbtdb, idx, 3003 1.21 christos newheader); 3004 1.21 christos dns__zonerbt_resigndelete( 3005 1.21 christos rbtdb, rbtversion, 3006 1.21 christos header DNS__DB_FLARG_PASS); 3007 1.21 christos } 3008 1.21 christos if (topheader_prev != NULL) { 3009 1.21 christos topheader_prev->next = newheader; 3010 1.21 christos } else { 3011 1.21 christos rbtnode->data = newheader; 3012 1.21 christos } 3013 1.21 christos newheader->next = topheader->next; 3014 1.21 christos newheader->down = topheader; 3015 1.21 christos topheader->next = newheader; 3016 1.21 christos rbtnode->dirty = 1; 3017 1.21 christos if (changed != NULL) { 3018 1.21 christos changed->dirty = true; 3019 1.21 christos } 3020 1.21 christos if (rbtversion == NULL) { 3021 1.22 christos dns__rbtdb_mark_ancient(header); 3022 1.21 christos if (sigheader != NULL) { 3023 1.22 christos dns__rbtdb_mark_ancient(sigheader); 3024 1.21 christos } 3025 1.21 christos } 3026 1.21 christos if (rbtversion != NULL && !header_nx) { 3027 1.21 christos update_recordsandxfrsize(false, rbtversion, 3028 1.21 christos header, 3029 1.21 christos nodename->length); 3030 1.21 christos } 3031 1.1 christos } 3032 1.1 christos } else { 3033 1.1 christos /* 3034 1.21 christos * No non-IGNORED rdatasets of the given type exist at 3035 1.21 christos * this node. 3036 1.1 christos */ 3037 1.1 christos 3038 1.1 christos /* 3039 1.21 christos * If we're trying to delete the type, don't bother. 3040 1.1 christos */ 3041 1.21 christos if (newheader_nx) { 3042 1.21 christos dns_slabheader_destroy(&newheader); 3043 1.21 christos return DNS_R_UNCHANGED; 3044 1.21 christos } 3045 1.9 christos 3046 1.21 christos idx = RBTDB_HEADERNODE(newheader)->locknum; 3047 1.21 christos if (IS_CACHE(rbtdb)) { 3048 1.21 christos isc_heap_insert(rbtdb->heaps[idx], newheader); 3049 1.21 christos newheader->heap = rbtdb->heaps[idx]; 3050 1.21 christos if (ZEROTTL(newheader)) { 3051 1.21 christos ISC_LIST_APPEND(rbtdb->lru[idx], newheader, 3052 1.21 christos link); 3053 1.21 christos } else { 3054 1.21 christos ISC_LIST_PREPEND(rbtdb->lru[idx], newheader, 3055 1.21 christos link); 3056 1.9 christos } 3057 1.21 christos } else if (RESIGN(newheader)) { 3058 1.21 christos dns__zonerbt_resigninsert(rbtdb, idx, newheader); 3059 1.21 christos dns__zonerbt_resigndelete(rbtdb, rbtversion, 3060 1.21 christos header DNS__DB_FLARG_PASS); 3061 1.1 christos } 3062 1.1 christos 3063 1.21 christos if (topheader != NULL) { 3064 1.1 christos /* 3065 1.21 christos * We have an list of rdatasets of the given type, 3066 1.21 christos * but they're all marked IGNORE. We simply insert 3067 1.21 christos * the new rdataset at the head of the list. 3068 1.21 christos * 3069 1.21 christos * Ignored rdatasets cannot occur during loading, so 3070 1.21 christos * we INSIST on it. 3071 1.1 christos */ 3072 1.21 christos INSIST(!loading); 3073 1.21 christos INSIST(rbtversion == NULL || 3074 1.21 christos rbtversion->serial >= topheader->serial); 3075 1.21 christos if (topheader_prev != NULL) { 3076 1.21 christos topheader_prev->next = newheader; 3077 1.1 christos } else { 3078 1.21 christos rbtnode->data = newheader; 3079 1.21 christos } 3080 1.21 christos newheader->next = topheader->next; 3081 1.21 christos newheader->down = topheader; 3082 1.21 christos topheader->next = newheader; 3083 1.21 christos rbtnode->dirty = 1; 3084 1.21 christos if (changed != NULL) { 3085 1.21 christos changed->dirty = true; 3086 1.1 christos } 3087 1.7 christos } else { 3088 1.1 christos /* 3089 1.21 christos * No rdatasets of the given type exist at the node. 3090 1.1 christos */ 3091 1.21 christos INSIST(newheader->down == NULL); 3092 1.1 christos 3093 1.21 christos if (!IS_CACHE(rbtdb) && overmaxtype(rbtdb, ntypes)) { 3094 1.21 christos dns_slabheader_destroy(&newheader); 3095 1.21 christos return DNS_R_TOOMANYRECORDS; 3096 1.7 christos } 3097 1.19 christos 3098 1.21 christos if (prio_header(newheader)) { 3099 1.21 christos /* This is a priority type, prepend it */ 3100 1.21 christos newheader->next = rbtnode->data; 3101 1.21 christos rbtnode->data = newheader; 3102 1.21 christos } else if (prioheader != NULL) { 3103 1.21 christos /* Append after the priority headers */ 3104 1.21 christos newheader->next = prioheader->next; 3105 1.21 christos prioheader->next = newheader; 3106 1.21 christos } else { 3107 1.21 christos /* There were no priority headers */ 3108 1.21 christos newheader->next = rbtnode->data; 3109 1.21 christos rbtnode->data = newheader; 3110 1.7 christos } 3111 1.1 christos 3112 1.21 christos if (IS_CACHE(rbtdb) && overmaxtype(rbtdb, ntypes)) { 3113 1.21 christos if (expireheader == NULL) { 3114 1.21 christos expireheader = newheader; 3115 1.21 christos } 3116 1.21 christos if (NEGATIVE(newheader) && 3117 1.21 christos !prio_header(newheader)) 3118 1.16 christos { 3119 1.1 christos /* 3120 1.21 christos * Add the new non-priority negative 3121 1.21 christos * header to the database only 3122 1.21 christos * temporarily. 3123 1.1 christos */ 3124 1.21 christos expireheader = newheader; 3125 1.1 christos } 3126 1.21 christos 3127 1.22 christos dns__rbtdb_mark_ancient(expireheader); 3128 1.1 christos /* 3129 1.21 christos * FIXME: In theory, we should mark the RRSIG 3130 1.21 christos * and the header at the same time, but there is 3131 1.21 christos * no direct link between those two header, so 3132 1.21 christos * we would have to check the whole list again. 3133 1.1 christos */ 3134 1.1 christos } 3135 1.1 christos } 3136 1.21 christos } 3137 1.1 christos 3138 1.21 christos if (rbtversion != NULL && !newheader_nx) { 3139 1.21 christos update_recordsandxfrsize(true, rbtversion, newheader, 3140 1.9 christos nodename->length); 3141 1.1 christos } 3142 1.1 christos 3143 1.21 christos /* 3144 1.21 christos * Check if the node now contains CNAME and other data. 3145 1.21 christos */ 3146 1.21 christos if (rbtversion != NULL && 3147 1.21 christos cname_and_other_data(rbtnode, rbtversion->serial)) 3148 1.21 christos { 3149 1.21 christos return DNS_R_CNAMEANDOTHER; 3150 1.7 christos } 3151 1.1 christos 3152 1.21 christos if (addedrdataset != NULL) { 3153 1.21 christos dns__rbtdb_bindrdataset(rbtdb, rbtnode, newheader, now, 3154 1.21 christos isc_rwlocktype_write, 3155 1.21 christos addedrdataset DNS__DB_FLARG_PASS); 3156 1.7 christos } 3157 1.1 christos 3158 1.21 christos return ISC_R_SUCCESS; 3159 1.21 christos } 3160 1.1 christos 3161 1.21 christos static bool 3162 1.21 christos delegating_type(dns_rbtdb_t *rbtdb, dns_rbtnode_t *node, dns_typepair_t type) { 3163 1.21 christos if (IS_CACHE(rbtdb)) { 3164 1.21 christos if (type == dns_rdatatype_dname) { 3165 1.21 christos return true; 3166 1.21 christos } else { 3167 1.21 christos return false; 3168 1.21 christos } 3169 1.21 christos } else if (type == dns_rdatatype_dname || 3170 1.21 christos (type == dns_rdatatype_ns && 3171 1.21 christos (node != rbtdb->origin_node || IS_STUB(rbtdb)))) 3172 1.21 christos { 3173 1.21 christos return true; 3174 1.21 christos } 3175 1.21 christos return false; 3176 1.1 christos } 3177 1.1 christos 3178 1.1 christos static isc_result_t 3179 1.21 christos addnoqname(isc_mem_t *mctx, dns_slabheader_t *newheader, uint32_t maxrrperset, 3180 1.21 christos dns_rdataset_t *rdataset) { 3181 1.1 christos isc_result_t result; 3182 1.21 christos dns_slabheader_proof_t *noqname = NULL; 3183 1.21 christos dns_name_t name = DNS_NAME_INITEMPTY; 3184 1.21 christos dns_rdataset_t neg = DNS_RDATASET_INIT, negsig = DNS_RDATASET_INIT; 3185 1.21 christos isc_region_t r1, r2; 3186 1.1 christos 3187 1.21 christos result = dns_rdataset_getnoqname(rdataset, &name, &neg, &negsig); 3188 1.21 christos RUNTIME_CHECK(result == ISC_R_SUCCESS); 3189 1.1 christos 3190 1.21 christos result = dns_rdataslab_fromrdataset(&neg, mctx, &r1, 0, maxrrperset); 3191 1.21 christos if (result != ISC_R_SUCCESS) { 3192 1.21 christos goto cleanup; 3193 1.7 christos } 3194 1.1 christos 3195 1.21 christos result = dns_rdataslab_fromrdataset(&negsig, mctx, &r2, 0, maxrrperset); 3196 1.21 christos if (result != ISC_R_SUCCESS) { 3197 1.21 christos goto cleanup; 3198 1.7 christos } 3199 1.1 christos 3200 1.21 christos noqname = isc_mem_get(mctx, sizeof(*noqname)); 3201 1.21 christos *noqname = (dns_slabheader_proof_t){ 3202 1.21 christos .neg = r1.base, 3203 1.21 christos .negsig = r2.base, 3204 1.21 christos .type = neg.type, 3205 1.21 christos .name = DNS_NAME_INITEMPTY, 3206 1.21 christos }; 3207 1.21 christos dns_name_dup(&name, mctx, &noqname->name); 3208 1.21 christos newheader->noqname = noqname; 3209 1.8 christos 3210 1.21 christos cleanup: 3211 1.21 christos dns_rdataset_disassociate(&neg); 3212 1.21 christos dns_rdataset_disassociate(&negsig); 3213 1.1 christos 3214 1.21 christos return result; 3215 1.1 christos } 3216 1.1 christos 3217 1.1 christos static isc_result_t 3218 1.21 christos addclosest(isc_mem_t *mctx, dns_slabheader_t *newheader, uint32_t maxrrperset, 3219 1.21 christos dns_rdataset_t *rdataset) { 3220 1.21 christos isc_result_t result; 3221 1.21 christos dns_slabheader_proof_t *closest = NULL; 3222 1.21 christos dns_name_t name = DNS_NAME_INITEMPTY; 3223 1.21 christos dns_rdataset_t neg = DNS_RDATASET_INIT, negsig = DNS_RDATASET_INIT; 3224 1.21 christos isc_region_t r1, r2; 3225 1.1 christos 3226 1.21 christos result = dns_rdataset_getclosest(rdataset, &name, &neg, &negsig); 3227 1.21 christos RUNTIME_CHECK(result == ISC_R_SUCCESS); 3228 1.1 christos 3229 1.21 christos result = dns_rdataslab_fromrdataset(&neg, mctx, &r1, 0, maxrrperset); 3230 1.21 christos if (result != ISC_R_SUCCESS) { 3231 1.21 christos goto cleanup; 3232 1.1 christos } 3233 1.1 christos 3234 1.21 christos result = dns_rdataslab_fromrdataset(&negsig, mctx, &r2, 0, maxrrperset); 3235 1.21 christos if (result != ISC_R_SUCCESS) { 3236 1.21 christos goto cleanup; 3237 1.1 christos } 3238 1.1 christos 3239 1.21 christos closest = isc_mem_get(mctx, sizeof(*closest)); 3240 1.21 christos *closest = (dns_slabheader_proof_t){ 3241 1.21 christos .neg = r1.base, 3242 1.21 christos .negsig = r2.base, 3243 1.21 christos .name = DNS_NAME_INITEMPTY, 3244 1.21 christos .type = neg.type, 3245 1.21 christos }; 3246 1.21 christos dns_name_dup(&name, mctx, &closest->name); 3247 1.21 christos newheader->closest = closest; 3248 1.1 christos 3249 1.21 christos cleanup: 3250 1.21 christos dns_rdataset_disassociate(&neg); 3251 1.21 christos dns_rdataset_disassociate(&negsig); 3252 1.21 christos return result; 3253 1.21 christos } 3254 1.1 christos 3255 1.21 christos static void 3256 1.21 christos expire_ttl_headers(dns_rbtdb_t *rbtdb, unsigned int locknum, 3257 1.21 christos isc_rwlocktype_t *tlocktypep, isc_stdtime_t now, 3258 1.21 christos bool cache_is_overmem DNS__DB_FLARG); 3259 1.1 christos 3260 1.21 christos isc_result_t 3261 1.21 christos dns__rbtdb_addrdataset(dns_db_t *db, dns_dbnode_t *node, 3262 1.21 christos dns_dbversion_t *version, isc_stdtime_t now, 3263 1.21 christos dns_rdataset_t *rdataset, unsigned int options, 3264 1.21 christos dns_rdataset_t *addedrdataset DNS__DB_FLARG) { 3265 1.21 christos dns_rbtdb_t *rbtdb = (dns_rbtdb_t *)db; 3266 1.21 christos dns_rbtnode_t *rbtnode = (dns_rbtnode_t *)node; 3267 1.21 christos dns_rbtdb_version_t *rbtversion = version; 3268 1.21 christos isc_region_t region; 3269 1.21 christos dns_slabheader_t *newheader = NULL; 3270 1.1 christos isc_result_t result; 3271 1.21 christos bool delegating; 3272 1.21 christos bool newnsec; 3273 1.21 christos isc_rwlocktype_t tlocktype = isc_rwlocktype_none; 3274 1.21 christos isc_rwlocktype_t nlocktype = isc_rwlocktype_none; 3275 1.21 christos bool cache_is_overmem = false; 3276 1.21 christos dns_fixedname_t fixed; 3277 1.21 christos dns_name_t *name = NULL; 3278 1.1 christos 3279 1.21 christos REQUIRE(VALID_RBTDB(rbtdb)); 3280 1.21 christos INSIST(rbtversion == NULL || rbtversion->rbtdb == rbtdb); 3281 1.1 christos 3282 1.21 christos if (!IS_CACHE(rbtdb)) { 3283 1.1 christos /* 3284 1.21 christos * SOA records are only allowed at top of zone. 3285 1.1 christos */ 3286 1.21 christos if (rdataset->type == dns_rdatatype_soa && 3287 1.21 christos node != rbtdb->origin_node) 3288 1.21 christos { 3289 1.21 christos return DNS_R_NOTZONETOP; 3290 1.7 christos } 3291 1.21 christos TREE_RDLOCK(&rbtdb->tree_lock, &tlocktype); 3292 1.21 christos REQUIRE((rbtnode->nsec == DNS_DB_NSEC_NSEC3 && 3293 1.21 christos (rdataset->type == dns_rdatatype_nsec3 || 3294 1.21 christos rdataset->covers == dns_rdatatype_nsec3)) || 3295 1.21 christos (rbtnode->nsec != DNS_DB_NSEC_NSEC3 && 3296 1.21 christos rdataset->type != dns_rdatatype_nsec3 && 3297 1.21 christos rdataset->covers != dns_rdatatype_nsec3)); 3298 1.21 christos TREE_UNLOCK(&rbtdb->tree_lock, &tlocktype); 3299 1.1 christos } 3300 1.1 christos 3301 1.21 christos if (rbtversion == NULL) { 3302 1.21 christos if (now == 0) { 3303 1.21 christos now = isc_stdtime_now(); 3304 1.7 christos } 3305 1.1 christos } else { 3306 1.21 christos now = 0; 3307 1.1 christos } 3308 1.1 christos 3309 1.1 christos result = dns_rdataslab_fromrdataset(rdataset, rbtdb->common.mctx, 3310 1.21 christos ®ion, sizeof(dns_slabheader_t), 3311 1.20 christos rbtdb->maxrrperset); 3312 1.7 christos if (result != ISC_R_SUCCESS) { 3313 1.21 christos if (result == DNS_R_TOOMANYRECORDS) { 3314 1.21 christos name = dns_fixedname_initname(&fixed); 3315 1.21 christos dns__rbtdb_nodefullname(db, node, name); 3316 1.21 christos dns__db_logtoomanyrecords((dns_db_t *)rbtdb, name, 3317 1.21 christos rdataset->type, "adding", 3318 1.21 christos rbtdb->maxrrperset); 3319 1.21 christos } 3320 1.21 christos return result; 3321 1.21 christos } 3322 1.21 christos 3323 1.21 christos name = dns_fixedname_initname(&fixed); 3324 1.21 christos dns__rbtdb_nodefullname(db, node, name); 3325 1.21 christos dns_rdataset_getownercase(rdataset, name); 3326 1.21 christos 3327 1.21 christos newheader = (dns_slabheader_t *)region.base; 3328 1.21 christos *newheader = (dns_slabheader_t){ 3329 1.21 christos .type = DNS_TYPEPAIR_VALUE(rdataset->type, rdataset->covers), 3330 1.21 christos .trust = rdataset->trust, 3331 1.21 christos .last_used = now, 3332 1.21 christos .node = rbtnode, 3333 1.21 christos }; 3334 1.21 christos 3335 1.21 christos dns_slabheader_reset(newheader, db, node); 3336 1.21 christos dns__rbtdb_setttl(newheader, rdataset->ttl + now); 3337 1.21 christos if (rdataset->ttl == 0U) { 3338 1.21 christos DNS_SLABHEADER_SETATTR(newheader, DNS_SLABHEADERATTR_ZEROTTL); 3339 1.7 christos } 3340 1.7 christos atomic_init(&newheader->count, 3341 1.7 christos atomic_fetch_add_relaxed(&init_count, 1)); 3342 1.21 christos if (rbtversion != NULL) { 3343 1.21 christos newheader->serial = rbtversion->serial; 3344 1.21 christos now = 0; 3345 1.1 christos 3346 1.21 christos if ((rdataset->attributes & DNS_RDATASETATTR_RESIGN) != 0) { 3347 1.21 christos DNS_SLABHEADER_SETATTR(newheader, 3348 1.21 christos DNS_SLABHEADERATTR_RESIGN); 3349 1.21 christos newheader->resign = 3350 1.21 christos (isc_stdtime_t)(dns_time64_from32( 3351 1.21 christos rdataset->resign) >> 3352 1.21 christos 1); 3353 1.21 christos newheader->resign_lsb = rdataset->resign & 0x1; 3354 1.21 christos } 3355 1.1 christos } else { 3356 1.21 christos newheader->serial = 1; 3357 1.21 christos if ((rdataset->attributes & DNS_RDATASETATTR_PREFETCH) != 0) { 3358 1.21 christos DNS_SLABHEADER_SETATTR(newheader, 3359 1.21 christos DNS_SLABHEADERATTR_PREFETCH); 3360 1.21 christos } 3361 1.21 christos if ((rdataset->attributes & DNS_RDATASETATTR_NEGATIVE) != 0) { 3362 1.21 christos DNS_SLABHEADER_SETATTR(newheader, 3363 1.21 christos DNS_SLABHEADERATTR_NEGATIVE); 3364 1.21 christos } 3365 1.21 christos if ((rdataset->attributes & DNS_RDATASETATTR_NXDOMAIN) != 0) { 3366 1.21 christos DNS_SLABHEADER_SETATTR(newheader, 3367 1.21 christos DNS_SLABHEADERATTR_NXDOMAIN); 3368 1.21 christos } 3369 1.21 christos if ((rdataset->attributes & DNS_RDATASETATTR_OPTOUT) != 0) { 3370 1.21 christos DNS_SLABHEADER_SETATTR(newheader, 3371 1.21 christos DNS_SLABHEADERATTR_OPTOUT); 3372 1.21 christos } 3373 1.21 christos if ((rdataset->attributes & DNS_RDATASETATTR_NOQNAME) != 0) { 3374 1.21 christos result = addnoqname(rbtdb->common.mctx, newheader, 3375 1.21 christos rbtdb->maxrrperset, rdataset); 3376 1.21 christos if (result != ISC_R_SUCCESS) { 3377 1.21 christos dns_slabheader_destroy(&newheader); 3378 1.21 christos return result; 3379 1.21 christos } 3380 1.21 christos } 3381 1.21 christos if ((rdataset->attributes & DNS_RDATASETATTR_CLOSEST) != 0) { 3382 1.21 christos result = addclosest(rbtdb->common.mctx, newheader, 3383 1.21 christos rbtdb->maxrrperset, rdataset); 3384 1.21 christos if (result != ISC_R_SUCCESS) { 3385 1.21 christos dns_slabheader_destroy(&newheader); 3386 1.21 christos return result; 3387 1.21 christos } 3388 1.21 christos } 3389 1.1 christos } 3390 1.1 christos 3391 1.21 christos /* 3392 1.21 christos * If we're adding a delegation type (e.g. NS or DNAME for a zone, 3393 1.21 christos * just DNAME for the cache), then we need to set the callback bit 3394 1.21 christos * on the node. 3395 1.21 christos */ 3396 1.21 christos if (delegating_type(rbtdb, rbtnode, rdataset->type)) { 3397 1.21 christos delegating = true; 3398 1.21 christos } else { 3399 1.21 christos delegating = false; 3400 1.21 christos } 3401 1.7 christos 3402 1.21 christos /* 3403 1.21 christos * Add to the auxiliary NSEC tree if we're adding an NSEC record. 3404 1.21 christos */ 3405 1.21 christos TREE_RDLOCK(&rbtdb->tree_lock, &tlocktype); 3406 1.21 christos if (rbtnode->nsec != DNS_DB_NSEC_HAS_NSEC && 3407 1.21 christos rdataset->type == dns_rdatatype_nsec) 3408 1.16 christos { 3409 1.21 christos newnsec = true; 3410 1.7 christos } else { 3411 1.21 christos newnsec = false; 3412 1.7 christos } 3413 1.21 christos TREE_UNLOCK(&rbtdb->tree_lock, &tlocktype); 3414 1.1 christos 3415 1.1 christos /* 3416 1.21 christos * If we're adding a delegation type, adding to the auxiliary NSEC 3417 1.21 christos * tree, or the DB is a cache in an overmem state, hold an 3418 1.21 christos * exclusive lock on the tree. In the latter case the lock does 3419 1.21 christos * not necessarily have to be acquired but it will help purge 3420 1.21 christos * ancient entries more effectively. 3421 1.1 christos */ 3422 1.21 christos if (IS_CACHE(rbtdb) && isc_mem_isovermem(rbtdb->common.mctx)) { 3423 1.21 christos cache_is_overmem = true; 3424 1.21 christos } 3425 1.21 christos if (delegating || newnsec || cache_is_overmem) { 3426 1.21 christos TREE_WRLOCK(&rbtdb->tree_lock, &tlocktype); 3427 1.7 christos } 3428 1.1 christos 3429 1.21 christos if (cache_is_overmem) { 3430 1.21 christos dns__cacherbt_overmem(rbtdb, newheader, 3431 1.21 christos &tlocktype DNS__DB_FLARG_PASS); 3432 1.21 christos } 3433 1.1 christos 3434 1.21 christos NODE_WRLOCK(&rbtdb->node_locks[rbtnode->locknum].lock, &nlocktype); 3435 1.1 christos 3436 1.21 christos if (rbtdb->rrsetstats != NULL) { 3437 1.21 christos DNS_SLABHEADER_SETATTR(newheader, DNS_SLABHEADERATTR_STATCOUNT); 3438 1.21 christos update_rrsetstats(rbtdb->rrsetstats, newheader->type, 3439 1.21 christos atomic_load_acquire(&newheader->attributes), 3440 1.21 christos true); 3441 1.21 christos } 3442 1.1 christos 3443 1.21 christos if (IS_CACHE(rbtdb)) { 3444 1.21 christos if (tlocktype == isc_rwlocktype_write) { 3445 1.21 christos cleanup_dead_nodes(rbtdb, 3446 1.21 christos rbtnode->locknum DNS__DB_FLARG_PASS); 3447 1.21 christos } 3448 1.1 christos 3449 1.21 christos expire_ttl_headers(rbtdb, rbtnode->locknum, &tlocktype, now, 3450 1.21 christos cache_is_overmem DNS__DB_FLARG_PASS); 3451 1.1 christos 3452 1.21 christos /* 3453 1.21 christos * If we've been holding a write lock on the tree just for 3454 1.21 christos * cleaning, we can release it now. However, we still need the 3455 1.21 christos * node lock. 3456 1.21 christos */ 3457 1.21 christos if (tlocktype == isc_rwlocktype_write && !delegating && 3458 1.21 christos !newnsec) 3459 1.21 christos { 3460 1.21 christos TREE_UNLOCK(&rbtdb->tree_lock, &tlocktype); 3461 1.21 christos } 3462 1.21 christos } 3463 1.1 christos 3464 1.21 christos result = ISC_R_SUCCESS; 3465 1.21 christos if (newnsec) { 3466 1.21 christos dns_rbtnode_t *nsecnode = NULL; 3467 1.1 christos 3468 1.21 christos result = dns_rbt_addnode(rbtdb->nsec, name, &nsecnode); 3469 1.21 christos if (result == ISC_R_SUCCESS) { 3470 1.21 christos nsecnode->nsec = DNS_DB_NSEC_NSEC; 3471 1.21 christos rbtnode->nsec = DNS_DB_NSEC_HAS_NSEC; 3472 1.21 christos } else if (result == ISC_R_EXISTS) { 3473 1.21 christos rbtnode->nsec = DNS_DB_NSEC_HAS_NSEC; 3474 1.21 christos result = ISC_R_SUCCESS; 3475 1.21 christos } 3476 1.21 christos } 3477 1.1 christos 3478 1.21 christos if (result == ISC_R_SUCCESS) { 3479 1.21 christos result = dns__rbtdb_add(rbtdb, rbtnode, name, rbtversion, 3480 1.21 christos newheader, options, false, 3481 1.21 christos addedrdataset, now DNS__DB_FLARG_PASS); 3482 1.21 christos } 3483 1.21 christos if (result == ISC_R_SUCCESS && delegating) { 3484 1.21 christos rbtnode->find_callback = 1; 3485 1.1 christos } 3486 1.1 christos 3487 1.21 christos NODE_UNLOCK(&rbtdb->node_locks[rbtnode->locknum].lock, &nlocktype); 3488 1.1 christos 3489 1.21 christos if (tlocktype != isc_rwlocktype_none) { 3490 1.21 christos TREE_UNLOCK(&rbtdb->tree_lock, &tlocktype); 3491 1.21 christos } 3492 1.21 christos INSIST(tlocktype == isc_rwlocktype_none); 3493 1.1 christos 3494 1.21 christos return result; 3495 1.1 christos } 3496 1.1 christos 3497 1.21 christos isc_result_t 3498 1.21 christos dns__rbtdb_subtractrdataset(dns_db_t *db, dns_dbnode_t *node, 3499 1.21 christos dns_dbversion_t *version, dns_rdataset_t *rdataset, 3500 1.21 christos unsigned int options, 3501 1.21 christos dns_rdataset_t *newrdataset DNS__DB_FLARG) { 3502 1.21 christos dns_rbtdb_t *rbtdb = (dns_rbtdb_t *)db; 3503 1.21 christos dns_rbtnode_t *rbtnode = (dns_rbtnode_t *)node; 3504 1.21 christos dns_rbtdb_version_t *rbtversion = version; 3505 1.21 christos dns_fixedname_t fname; 3506 1.21 christos dns_name_t *nodename = dns_fixedname_initname(&fname); 3507 1.21 christos dns_slabheader_t *topheader = NULL, *topheader_prev = NULL; 3508 1.21 christos dns_slabheader_t *header = NULL, *newheader = NULL; 3509 1.21 christos unsigned char *subresult = NULL; 3510 1.21 christos isc_region_t region; 3511 1.21 christos isc_result_t result; 3512 1.21 christos rbtdb_changed_t *changed = NULL; 3513 1.21 christos isc_rwlocktype_t tlocktype = isc_rwlocktype_none; 3514 1.21 christos isc_rwlocktype_t nlocktype = isc_rwlocktype_none; 3515 1.1 christos 3516 1.1 christos REQUIRE(VALID_RBTDB(rbtdb)); 3517 1.21 christos REQUIRE(rbtversion != NULL && rbtversion->rbtdb == rbtdb); 3518 1.1 christos 3519 1.21 christos if (!IS_CACHE(rbtdb)) { 3520 1.21 christos TREE_RDLOCK(&rbtdb->tree_lock, &tlocktype); 3521 1.21 christos REQUIRE((rbtnode->nsec == DNS_DB_NSEC_NSEC3 && 3522 1.21 christos (rdataset->type == dns_rdatatype_nsec3 || 3523 1.21 christos rdataset->covers == dns_rdatatype_nsec3)) || 3524 1.21 christos (rbtnode->nsec != DNS_DB_NSEC_NSEC3 && 3525 1.21 christos rdataset->type != dns_rdatatype_nsec3 && 3526 1.21 christos rdataset->covers != dns_rdatatype_nsec3)); 3527 1.21 christos TREE_UNLOCK(&rbtdb->tree_lock, &tlocktype); 3528 1.19 christos } 3529 1.1 christos 3530 1.21 christos dns__rbtdb_nodefullname(db, node, nodename); 3531 1.1 christos 3532 1.21 christos result = dns_rdataslab_fromrdataset(rdataset, rbtdb->common.mctx, 3533 1.21 christos ®ion, sizeof(dns_slabheader_t), 3534 1.21 christos 0); 3535 1.21 christos if (result != ISC_R_SUCCESS) { 3536 1.21 christos return result; 3537 1.20 christos } 3538 1.1 christos 3539 1.21 christos newheader = (dns_slabheader_t *)region.base; 3540 1.21 christos dns_slabheader_reset(newheader, db, node); 3541 1.21 christos dns__rbtdb_setttl(newheader, rdataset->ttl); 3542 1.21 christos newheader->type = DNS_TYPEPAIR_VALUE(rdataset->type, rdataset->covers); 3543 1.21 christos atomic_init(&newheader->attributes, 0); 3544 1.21 christos newheader->serial = rbtversion->serial; 3545 1.21 christos newheader->trust = 0; 3546 1.21 christos newheader->noqname = NULL; 3547 1.21 christos newheader->closest = NULL; 3548 1.21 christos atomic_init(&newheader->count, 3549 1.21 christos atomic_fetch_add_relaxed(&init_count, 1)); 3550 1.21 christos newheader->last_used = 0; 3551 1.21 christos newheader->node = rbtnode; 3552 1.21 christos newheader->db = (dns_db_t *)rbtdb; 3553 1.21 christos if ((rdataset->attributes & DNS_RDATASETATTR_RESIGN) != 0) { 3554 1.21 christos DNS_SLABHEADER_SETATTR(newheader, DNS_SLABHEADERATTR_RESIGN); 3555 1.21 christos newheader->resign = 3556 1.21 christos (isc_stdtime_t)(dns_time64_from32(rdataset->resign) >> 3557 1.21 christos 1); 3558 1.21 christos newheader->resign_lsb = rdataset->resign & 0x1; 3559 1.1 christos } else { 3560 1.21 christos newheader->resign = 0; 3561 1.21 christos newheader->resign_lsb = 0; 3562 1.1 christos } 3563 1.1 christos 3564 1.21 christos NODE_WRLOCK(&rbtdb->node_locks[rbtnode->locknum].lock, &nlocktype); 3565 1.1 christos 3566 1.21 christos changed = add_changed(newheader, rbtversion DNS__DB_FLARG_PASS); 3567 1.21 christos if (changed == NULL) { 3568 1.21 christos dns_slabheader_destroy(&newheader); 3569 1.21 christos NODE_UNLOCK(&rbtdb->node_locks[rbtnode->locknum].lock, 3570 1.21 christos &nlocktype); 3571 1.21 christos return ISC_R_NOMEMORY; 3572 1.21 christos } 3573 1.1 christos 3574 1.21 christos for (topheader = rbtnode->data; topheader != NULL; 3575 1.21 christos topheader = topheader->next) 3576 1.21 christos { 3577 1.21 christos if (topheader->type == newheader->type) { 3578 1.21 christos break; 3579 1.21 christos } 3580 1.21 christos topheader_prev = topheader; 3581 1.21 christos } 3582 1.21 christos /* 3583 1.21 christos * If header isn't NULL, we've found the right type. There may be 3584 1.21 christos * IGNORE rdatasets between the top of the chain and the first real 3585 1.21 christos * data. We skip over them. 3586 1.21 christos */ 3587 1.21 christos header = topheader; 3588 1.21 christos while (header != NULL && IGNORE(header)) { 3589 1.21 christos header = header->down; 3590 1.7 christos } 3591 1.21 christos if (header != NULL && EXISTS(header)) { 3592 1.21 christos unsigned int flags = 0; 3593 1.21 christos subresult = NULL; 3594 1.21 christos result = ISC_R_SUCCESS; 3595 1.21 christos if ((options & DNS_DBSUB_EXACT) != 0) { 3596 1.21 christos flags |= DNS_RDATASLAB_EXACT; 3597 1.21 christos if (newheader->ttl != header->ttl) { 3598 1.21 christos result = DNS_R_NOTEXACT; 3599 1.21 christos } 3600 1.7 christos } 3601 1.21 christos if (result == ISC_R_SUCCESS) { 3602 1.21 christos result = dns_rdataslab_subtract( 3603 1.21 christos (unsigned char *)header, 3604 1.21 christos (unsigned char *)newheader, 3605 1.21 christos (unsigned int)(sizeof(*newheader)), 3606 1.21 christos rbtdb->common.mctx, rbtdb->common.rdclass, 3607 1.21 christos (dns_rdatatype_t)header->type, flags, 3608 1.21 christos &subresult); 3609 1.1 christos } 3610 1.21 christos if (result == ISC_R_SUCCESS) { 3611 1.21 christos dns_slabheader_destroy(&newheader); 3612 1.21 christos newheader = (dns_slabheader_t *)subresult; 3613 1.21 christos dns_slabheader_reset(newheader, db, node); 3614 1.21 christos dns_slabheader_copycase(newheader, header); 3615 1.21 christos if (RESIGN(header)) { 3616 1.21 christos DNS_SLABHEADER_SETATTR( 3617 1.21 christos newheader, DNS_SLABHEADERATTR_RESIGN); 3618 1.21 christos newheader->resign = header->resign; 3619 1.21 christos newheader->resign_lsb = header->resign_lsb; 3620 1.21 christos dns__zonerbt_resigninsert( 3621 1.21 christos rbtdb, rbtnode->locknum, newheader); 3622 1.21 christos } 3623 1.21 christos /* 3624 1.21 christos * We have to set the serial since the rdataslab 3625 1.21 christos * subtraction routine copies the reserved portion of 3626 1.21 christos * header, not newheader. 3627 1.21 christos */ 3628 1.21 christos newheader->serial = rbtversion->serial; 3629 1.21 christos /* 3630 1.21 christos * XXXJT: dns_rdataslab_subtract() copied the pointers 3631 1.21 christos * to additional info. We need to clear these fields 3632 1.21 christos * to avoid having duplicated references. 3633 1.21 christos */ 3634 1.21 christos update_recordsandxfrsize(true, rbtversion, newheader, 3635 1.21 christos nodename->length); 3636 1.21 christos } else if (result == DNS_R_NXRRSET) { 3637 1.21 christos /* 3638 1.21 christos * This subtraction would remove all of the rdata; 3639 1.21 christos * add a nonexistent header instead. 3640 1.21 christos */ 3641 1.21 christos dns_slabheader_destroy(&newheader); 3642 1.21 christos newheader = dns_slabheader_new((dns_db_t *)rbtdb, 3643 1.21 christos (dns_dbnode_t *)rbtnode); 3644 1.21 christos dns__rbtdb_setttl(newheader, 0); 3645 1.21 christos newheader->type = topheader->type; 3646 1.21 christos atomic_init(&newheader->attributes, 3647 1.21 christos DNS_SLABHEADERATTR_NONEXISTENT); 3648 1.21 christos newheader->serial = rbtversion->serial; 3649 1.21 christos } else { 3650 1.21 christos dns_slabheader_destroy(&newheader); 3651 1.21 christos goto unlock; 3652 1.7 christos } 3653 1.21 christos 3654 1.21 christos /* 3655 1.21 christos * If we're here, we want to link newheader in front of 3656 1.21 christos * topheader. 3657 1.21 christos */ 3658 1.21 christos INSIST(rbtversion->serial >= topheader->serial); 3659 1.21 christos update_recordsandxfrsize(false, rbtversion, header, 3660 1.21 christos nodename->length); 3661 1.21 christos if (topheader_prev != NULL) { 3662 1.21 christos topheader_prev->next = newheader; 3663 1.21 christos } else { 3664 1.21 christos rbtnode->data = newheader; 3665 1.7 christos } 3666 1.21 christos newheader->next = topheader->next; 3667 1.21 christos newheader->down = topheader; 3668 1.21 christos topheader->next = newheader; 3669 1.21 christos rbtnode->dirty = 1; 3670 1.21 christos changed->dirty = true; 3671 1.21 christos dns__zonerbt_resigndelete(rbtdb, rbtversion, 3672 1.21 christos header DNS__DB_FLARG_PASS); 3673 1.21 christos } else { 3674 1.21 christos /* 3675 1.21 christos * The rdataset doesn't exist, so we don't need to do anything 3676 1.21 christos * to satisfy the deletion request. 3677 1.21 christos */ 3678 1.21 christos dns_slabheader_destroy(&newheader); 3679 1.21 christos if ((options & DNS_DBSUB_EXACT) != 0) { 3680 1.21 christos result = DNS_R_NOTEXACT; 3681 1.21 christos } else { 3682 1.21 christos result = DNS_R_UNCHANGED; 3683 1.7 christos } 3684 1.1 christos } 3685 1.1 christos 3686 1.21 christos if (result == ISC_R_SUCCESS && newrdataset != NULL) { 3687 1.21 christos dns__rbtdb_bindrdataset(rbtdb, rbtnode, newheader, 0, 3688 1.21 christos isc_rwlocktype_write, 3689 1.21 christos newrdataset DNS__DB_FLARG_PASS); 3690 1.7 christos } 3691 1.1 christos 3692 1.21 christos if (result == DNS_R_NXRRSET && newrdataset != NULL && 3693 1.21 christos (options & DNS_DBSUB_WANTOLD) != 0) 3694 1.21 christos { 3695 1.21 christos dns__rbtdb_bindrdataset(rbtdb, rbtnode, header, 0, 3696 1.21 christos isc_rwlocktype_write, 3697 1.21 christos newrdataset DNS__DB_FLARG_PASS); 3698 1.7 christos } 3699 1.1 christos 3700 1.21 christos unlock: 3701 1.21 christos NODE_UNLOCK(&rbtdb->node_locks[rbtnode->locknum].lock, &nlocktype); 3702 1.1 christos 3703 1.21 christos /* 3704 1.21 christos * Update the zone's secure status. If version is non-NULL 3705 1.21 christos * this is deferred until dns__rbtdb_closeversion() is called. 3706 1.21 christos */ 3707 1.21 christos if (result == ISC_R_SUCCESS && version == NULL && !IS_CACHE(rbtdb)) { 3708 1.21 christos RWLOCK(&rbtdb->lock, isc_rwlocktype_read); 3709 1.21 christos version = rbtdb->current_version; 3710 1.21 christos RWUNLOCK(&rbtdb->lock, isc_rwlocktype_read); 3711 1.21 christos dns__rbtdb_setsecure(db, version, rbtdb->origin_node); 3712 1.21 christos } 3713 1.1 christos 3714 1.21 christos return result; 3715 1.1 christos } 3716 1.1 christos 3717 1.21 christos isc_result_t 3718 1.21 christos dns__rbtdb_deleterdataset(dns_db_t *db, dns_dbnode_t *node, 3719 1.21 christos dns_dbversion_t *version, dns_rdatatype_t type, 3720 1.21 christos dns_rdatatype_t covers DNS__DB_FLARG) { 3721 1.1 christos dns_rbtdb_t *rbtdb = (dns_rbtdb_t *)db; 3722 1.21 christos dns_rbtnode_t *rbtnode = (dns_rbtnode_t *)node; 3723 1.21 christos dns_rbtdb_version_t *rbtversion = version; 3724 1.21 christos dns_fixedname_t fname; 3725 1.21 christos dns_name_t *nodename = dns_fixedname_initname(&fname); 3726 1.21 christos isc_result_t result; 3727 1.21 christos dns_slabheader_t *newheader = NULL; 3728 1.21 christos isc_rwlocktype_t nlocktype = isc_rwlocktype_none; 3729 1.1 christos 3730 1.1 christos REQUIRE(VALID_RBTDB(rbtdb)); 3731 1.21 christos INSIST(rbtversion == NULL || rbtversion->rbtdb == rbtdb); 3732 1.1 christos 3733 1.21 christos if (type == dns_rdatatype_any) { 3734 1.21 christos return ISC_R_NOTIMPLEMENTED; 3735 1.21 christos } 3736 1.21 christos if (type == dns_rdatatype_rrsig && covers == 0) { 3737 1.21 christos return ISC_R_NOTIMPLEMENTED; 3738 1.21 christos } 3739 1.1 christos 3740 1.21 christos newheader = dns_slabheader_new(db, node); 3741 1.21 christos newheader->type = DNS_TYPEPAIR_VALUE(type, covers); 3742 1.21 christos dns__rbtdb_setttl(newheader, 0); 3743 1.21 christos atomic_init(&newheader->attributes, DNS_SLABHEADERATTR_NONEXISTENT); 3744 1.21 christos if (rbtversion != NULL) { 3745 1.21 christos newheader->serial = rbtversion->serial; 3746 1.1 christos } 3747 1.1 christos 3748 1.21 christos dns__rbtdb_nodefullname(db, node, nodename); 3749 1.1 christos 3750 1.21 christos NODE_WRLOCK(&rbtdb->node_locks[rbtnode->locknum].lock, &nlocktype); 3751 1.21 christos result = dns__rbtdb_add(rbtdb, rbtnode, nodename, rbtversion, newheader, 3752 1.21 christos DNS_DBADD_FORCE, false, NULL, 3753 1.21 christos 0 DNS__DB_FLARG_PASS); 3754 1.21 christos NODE_UNLOCK(&rbtdb->node_locks[rbtnode->locknum].lock, &nlocktype); 3755 1.1 christos 3756 1.21 christos /* 3757 1.21 christos * Update the zone's secure status. If version is non-NULL 3758 1.21 christos * this is deferred until dns__rbtdb_closeversion() is called. 3759 1.21 christos */ 3760 1.21 christos if (result == ISC_R_SUCCESS && version == NULL && !IS_CACHE(rbtdb)) { 3761 1.21 christos RWLOCK(&rbtdb->lock, isc_rwlocktype_read); 3762 1.21 christos version = rbtdb->current_version; 3763 1.21 christos RWUNLOCK(&rbtdb->lock, isc_rwlocktype_read); 3764 1.21 christos dns__rbtdb_setsecure(db, version, rbtdb->origin_node); 3765 1.7 christos } 3766 1.1 christos 3767 1.21 christos return result; 3768 1.1 christos } 3769 1.1 christos 3770 1.1 christos static void 3771 1.21 christos delete_callback(void *data, void *arg) { 3772 1.21 christos dns_rbtdb_t *rbtdb = arg; 3773 1.21 christos dns_slabheader_t *current = NULL, *next = NULL; 3774 1.21 christos unsigned int locknum; 3775 1.21 christos isc_rwlocktype_t nlocktype = isc_rwlocktype_none; 3776 1.1 christos 3777 1.21 christos current = data; 3778 1.21 christos locknum = RBTDB_HEADERNODE(current)->locknum; 3779 1.21 christos NODE_WRLOCK(&rbtdb->node_locks[locknum].lock, &nlocktype); 3780 1.21 christos while (current != NULL) { 3781 1.21 christos next = current->next; 3782 1.21 christos dns_slabheader_destroy(¤t); 3783 1.21 christos current = next; 3784 1.7 christos } 3785 1.21 christos NODE_UNLOCK(&rbtdb->node_locks[locknum].lock, &nlocktype); 3786 1.1 christos } 3787 1.1 christos 3788 1.21 christos unsigned int 3789 1.21 christos dns__rbtdb_nodecount(dns_db_t *db, dns_dbtree_t tree) { 3790 1.1 christos dns_rbtdb_t *rbtdb = (dns_rbtdb_t *)db; 3791 1.21 christos unsigned int count; 3792 1.21 christos isc_rwlocktype_t tlocktype = isc_rwlocktype_none; 3793 1.1 christos 3794 1.1 christos REQUIRE(VALID_RBTDB(rbtdb)); 3795 1.1 christos 3796 1.21 christos TREE_RDLOCK(&rbtdb->tree_lock, &tlocktype); 3797 1.21 christos switch (tree) { 3798 1.21 christos case dns_dbtree_main: 3799 1.21 christos count = dns_rbt_nodecount(rbtdb->tree); 3800 1.21 christos break; 3801 1.21 christos case dns_dbtree_nsec: 3802 1.21 christos count = dns_rbt_nodecount(rbtdb->nsec); 3803 1.21 christos break; 3804 1.21 christos case dns_dbtree_nsec3: 3805 1.21 christos count = dns_rbt_nodecount(rbtdb->nsec3); 3806 1.21 christos break; 3807 1.21 christos default: 3808 1.21 christos UNREACHABLE(); 3809 1.21 christos } 3810 1.21 christos TREE_UNLOCK(&rbtdb->tree_lock, &tlocktype); 3811 1.21 christos 3812 1.21 christos return count; 3813 1.1 christos } 3814 1.1 christos 3815 1.21 christos void 3816 1.21 christos dns__rbtdb_setloop(dns_db_t *db, isc_loop_t *loop) { 3817 1.1 christos dns_rbtdb_t *rbtdb = (dns_rbtdb_t *)db; 3818 1.1 christos 3819 1.1 christos REQUIRE(VALID_RBTDB(rbtdb)); 3820 1.1 christos 3821 1.21 christos RWLOCK(&rbtdb->lock, isc_rwlocktype_write); 3822 1.21 christos if (rbtdb->loop != NULL) { 3823 1.21 christos isc_loop_detach(&rbtdb->loop); 3824 1.21 christos } 3825 1.21 christos if (loop != NULL) { 3826 1.21 christos isc_loop_attach(loop, &rbtdb->loop); 3827 1.21 christos } 3828 1.21 christos RWUNLOCK(&rbtdb->lock, isc_rwlocktype_write); 3829 1.1 christos } 3830 1.1 christos 3831 1.21 christos isc_result_t 3832 1.21 christos dns__rbtdb_getoriginnode(dns_db_t *db, dns_dbnode_t **nodep DNS__DB_FLARG) { 3833 1.20 christos dns_rbtdb_t *rbtdb = (dns_rbtdb_t *)db; 3834 1.21 christos dns_rbtnode_t *onode = NULL; 3835 1.21 christos isc_result_t result = ISC_R_SUCCESS; 3836 1.20 christos 3837 1.20 christos REQUIRE(VALID_RBTDB(rbtdb)); 3838 1.21 christos REQUIRE(nodep != NULL && *nodep == NULL); 3839 1.21 christos 3840 1.21 christos /* Note that the access to origin_node doesn't require a DB lock */ 3841 1.21 christos onode = (dns_rbtnode_t *)rbtdb->origin_node; 3842 1.21 christos if (onode != NULL) { 3843 1.22 christos dns__rbtnode_acquire(rbtdb, onode, 3844 1.22 christos isc_rwlocktype_none DNS__DB_FLARG_PASS); 3845 1.21 christos *nodep = rbtdb->origin_node; 3846 1.21 christos } else { 3847 1.21 christos INSIST(IS_CACHE(rbtdb)); 3848 1.21 christos result = ISC_R_NOTFOUND; 3849 1.21 christos } 3850 1.20 christos 3851 1.21 christos return result; 3852 1.20 christos } 3853 1.20 christos 3854 1.21 christos void 3855 1.21 christos dns__rbtdb_locknode(dns_db_t *db, dns_dbnode_t *node, isc_rwlocktype_t type) { 3856 1.20 christos dns_rbtdb_t *rbtdb = (dns_rbtdb_t *)db; 3857 1.21 christos dns_rbtnode_t *rbtnode = (dns_rbtnode_t *)node; 3858 1.20 christos 3859 1.21 christos RWLOCK(&rbtdb->node_locks[rbtnode->locknum].lock, type); 3860 1.20 christos } 3861 1.20 christos 3862 1.21 christos void 3863 1.21 christos dns__rbtdb_unlocknode(dns_db_t *db, dns_dbnode_t *node, isc_rwlocktype_t type) { 3864 1.1 christos dns_rbtdb_t *rbtdb = (dns_rbtdb_t *)db; 3865 1.21 christos dns_rbtnode_t *rbtnode = (dns_rbtnode_t *)node; 3866 1.1 christos 3867 1.21 christos RWUNLOCK(&rbtdb->node_locks[rbtnode->locknum].lock, type); 3868 1.1 christos } 3869 1.1 christos 3870 1.21 christos isc_result_t 3871 1.21 christos dns__rbtdb_nodefullname(dns_db_t *db, dns_dbnode_t *node, dns_name_t *name) { 3872 1.1 christos dns_rbtdb_t *rbtdb = (dns_rbtdb_t *)db; 3873 1.1 christos dns_rbtnode_t *rbtnode = (dns_rbtnode_t *)node; 3874 1.1 christos isc_result_t result; 3875 1.21 christos isc_rwlocktype_t tlocktype = isc_rwlocktype_none; 3876 1.1 christos 3877 1.1 christos REQUIRE(VALID_RBTDB(rbtdb)); 3878 1.1 christos REQUIRE(node != NULL); 3879 1.1 christos REQUIRE(name != NULL); 3880 1.1 christos 3881 1.21 christos TREE_RDLOCK(&rbtdb->tree_lock, &tlocktype); 3882 1.1 christos result = dns_rbt_fullnamefromnode(rbtnode, name); 3883 1.21 christos TREE_UNLOCK(&rbtdb->tree_lock, &tlocktype); 3884 1.9 christos 3885 1.21 christos return result; 3886 1.9 christos } 3887 1.9 christos 3888 1.1 christos isc_result_t 3889 1.21 christos dns__rbtdb_create(isc_mem_t *mctx, const dns_name_t *origin, dns_dbtype_t type, 3890 1.21 christos dns_rdataclass_t rdclass, unsigned int argc, char *argv[], 3891 1.21 christos void *driverarg ISC_ATTR_UNUSED, dns_db_t **dbp) { 3892 1.21 christos dns_rbtdb_t *rbtdb = NULL; 3893 1.1 christos isc_result_t result; 3894 1.1 christos int i; 3895 1.1 christos dns_name_t name; 3896 1.1 christos isc_mem_t *hmctx = mctx; 3897 1.1 christos 3898 1.21 christos rbtdb = isc_mem_get(mctx, sizeof(*rbtdb)); 3899 1.21 christos *rbtdb = (dns_rbtdb_t){ 3900 1.21 christos .common.origin = DNS_NAME_INITEMPTY, 3901 1.21 christos .common.rdclass = rdclass, 3902 1.21 christos .current_serial = 1, 3903 1.21 christos .least_serial = 1, 3904 1.21 christos .next_serial = 2, 3905 1.21 christos .open_versions = ISC_LIST_INITIALIZER, 3906 1.21 christos }; 3907 1.1 christos 3908 1.21 christos isc_refcount_init(&rbtdb->common.references, 1); 3909 1.1 christos 3910 1.1 christos /* 3911 1.1 christos * If argv[0] exists, it points to a memory context to use for heap 3912 1.1 christos */ 3913 1.7 christos if (argc != 0) { 3914 1.7 christos hmctx = (isc_mem_t *)argv[0]; 3915 1.7 christos } 3916 1.1 christos 3917 1.1 christos if (type == dns_dbtype_cache) { 3918 1.21 christos rbtdb->common.methods = &dns__rbtdb_cachemethods; 3919 1.1 christos rbtdb->common.attributes |= DNS_DBATTR_CACHE; 3920 1.1 christos } else if (type == dns_dbtype_stub) { 3921 1.21 christos rbtdb->common.methods = &dns__rbtdb_zonemethods; 3922 1.1 christos rbtdb->common.attributes |= DNS_DBATTR_STUB; 3923 1.7 christos } else { 3924 1.21 christos rbtdb->common.methods = &dns__rbtdb_zonemethods; 3925 1.7 christos } 3926 1.1 christos 3927 1.21 christos isc_rwlock_init(&rbtdb->lock); 3928 1.21 christos TREE_INITLOCK(&rbtdb->tree_lock); 3929 1.1 christos 3930 1.1 christos /* 3931 1.1 christos * Initialize node_lock_count in a generic way to support future 3932 1.1 christos * extension which allows the user to specify this value on creation. 3933 1.1 christos * Note that when specified for a cache DB it must be larger than 1 3934 1.1 christos * as commented with the definition of DEFAULT_CACHE_NODE_LOCK_COUNT. 3935 1.1 christos */ 3936 1.1 christos if (rbtdb->node_lock_count == 0) { 3937 1.7 christos if (IS_CACHE(rbtdb)) { 3938 1.1 christos rbtdb->node_lock_count = DEFAULT_CACHE_NODE_LOCK_COUNT; 3939 1.7 christos } else { 3940 1.1 christos rbtdb->node_lock_count = DEFAULT_NODE_LOCK_COUNT; 3941 1.7 christos } 3942 1.1 christos } else if (rbtdb->node_lock_count < 2 && IS_CACHE(rbtdb)) { 3943 1.1 christos result = ISC_R_RANGE; 3944 1.1 christos goto cleanup_tree_lock; 3945 1.1 christos } 3946 1.1 christos INSIST(rbtdb->node_lock_count < (1 << DNS_RBT_LOCKLENGTH)); 3947 1.1 christos rbtdb->node_locks = isc_mem_get(mctx, rbtdb->node_lock_count * 3948 1.21 christos sizeof(db_nodelock_t)); 3949 1.1 christos 3950 1.21 christos rbtdb->common.update_listeners = cds_lfht_new(16, 16, 0, 0, NULL); 3951 1.1 christos 3952 1.1 christos if (IS_CACHE(rbtdb)) { 3953 1.21 christos dns_rdatasetstats_create(mctx, &rbtdb->rrsetstats); 3954 1.21 christos rbtdb->lru = isc_mem_get(mctx, 3955 1.21 christos rbtdb->node_lock_count * 3956 1.21 christos sizeof(dns_slabheaderlist_t)); 3957 1.7 christos for (i = 0; i < (int)rbtdb->node_lock_count; i++) { 3958 1.21 christos ISC_LIST_INIT(rbtdb->lru[i]); 3959 1.7 christos } 3960 1.7 christos } 3961 1.1 christos 3962 1.1 christos /* 3963 1.1 christos * Create the heaps. 3964 1.1 christos */ 3965 1.1 christos rbtdb->heaps = isc_mem_get(hmctx, rbtdb->node_lock_count * 3966 1.7 christos sizeof(isc_heap_t *)); 3967 1.7 christos for (i = 0; i < (int)rbtdb->node_lock_count; i++) { 3968 1.7 christos rbtdb->heaps[i] = NULL; 3969 1.1 christos } 3970 1.21 christos 3971 1.21 christos rbtdb->sooner = IS_CACHE(rbtdb) ? ttl_sooner : resign_sooner; 3972 1.1 christos for (i = 0; i < (int)rbtdb->node_lock_count; i++) { 3973 1.21 christos isc_heap_create(hmctx, rbtdb->sooner, set_index, 0, 3974 1.21 christos &rbtdb->heaps[i]); 3975 1.1 christos } 3976 1.1 christos 3977 1.1 christos /* 3978 1.1 christos * Create deadnode lists. 3979 1.1 christos */ 3980 1.1 christos rbtdb->deadnodes = isc_mem_get(mctx, rbtdb->node_lock_count * 3981 1.21 christos sizeof(dns_rbtnodelist_t)); 3982 1.7 christos for (i = 0; i < (int)rbtdb->node_lock_count; i++) { 3983 1.7 christos ISC_LIST_INIT(rbtdb->deadnodes[i]); 3984 1.1 christos } 3985 1.1 christos 3986 1.1 christos rbtdb->active = rbtdb->node_lock_count; 3987 1.1 christos 3988 1.1 christos for (i = 0; i < (int)(rbtdb->node_lock_count); i++) { 3989 1.13 christos NODE_INITLOCK(&rbtdb->node_locks[i].lock); 3990 1.13 christos isc_refcount_init(&rbtdb->node_locks[i].references, 0); 3991 1.3 christos rbtdb->node_locks[i].exiting = false; 3992 1.1 christos } 3993 1.1 christos 3994 1.1 christos /* 3995 1.1 christos * Attach to the mctx. The database will persist so long as there 3996 1.1 christos * are references to it, and attaching to the mctx ensures that our 3997 1.1 christos * mctx won't disappear out from under us. 3998 1.1 christos */ 3999 1.1 christos isc_mem_attach(mctx, &rbtdb->common.mctx); 4000 1.1 christos isc_mem_attach(hmctx, &rbtdb->hmctx); 4001 1.1 christos 4002 1.1 christos /* 4003 1.1 christos * Make a copy of the origin name. 4004 1.1 christos */ 4005 1.21 christos dns_name_dupwithoffsets(origin, mctx, &rbtdb->common.origin); 4006 1.1 christos 4007 1.1 christos /* 4008 1.1 christos * Make the Red-Black Trees. 4009 1.1 christos */ 4010 1.1 christos result = dns_rbt_create(mctx, delete_callback, rbtdb, &rbtdb->tree); 4011 1.1 christos if (result != ISC_R_SUCCESS) { 4012 1.21 christos free_rbtdb(rbtdb, false); 4013 1.21 christos return result; 4014 1.1 christos } 4015 1.1 christos 4016 1.1 christos result = dns_rbt_create(mctx, delete_callback, rbtdb, &rbtdb->nsec); 4017 1.1 christos if (result != ISC_R_SUCCESS) { 4018 1.21 christos free_rbtdb(rbtdb, false); 4019 1.21 christos return result; 4020 1.1 christos } 4021 1.1 christos 4022 1.1 christos result = dns_rbt_create(mctx, delete_callback, rbtdb, &rbtdb->nsec3); 4023 1.1 christos if (result != ISC_R_SUCCESS) { 4024 1.21 christos free_rbtdb(rbtdb, false); 4025 1.21 christos return result; 4026 1.1 christos } 4027 1.1 christos 4028 1.1 christos /* 4029 1.1 christos * In order to set the node callback bit correctly in zone databases, 4030 1.1 christos * we need to know if the node has the origin name of the zone. 4031 1.1 christos * In loading_addrdataset() we could simply compare the new name 4032 1.1 christos * to the origin name, but this is expensive. Also, we don't know the 4033 1.21 christos * node name in dns__rbtdb_addrdataset(), so we need another way of 4034 1.21 christos * knowing the zone's top. 4035 1.1 christos * 4036 1.1 christos * We now explicitly create a node for the zone's origin, and then 4037 1.1 christos * we simply remember the node's address. This is safe, because 4038 1.1 christos * the top-of-zone node can never be deleted, nor can its address 4039 1.1 christos * change. 4040 1.1 christos */ 4041 1.1 christos if (!IS_CACHE(rbtdb)) { 4042 1.1 christos result = dns_rbt_addnode(rbtdb->tree, &rbtdb->common.origin, 4043 1.1 christos &rbtdb->origin_node); 4044 1.1 christos if (result != ISC_R_SUCCESS) { 4045 1.1 christos INSIST(result != ISC_R_EXISTS); 4046 1.21 christos free_rbtdb(rbtdb, false); 4047 1.21 christos return result; 4048 1.1 christos } 4049 1.1 christos INSIST(rbtdb->origin_node != NULL); 4050 1.21 christos rbtdb->origin_node->nsec = DNS_DB_NSEC_NORMAL; 4051 1.1 christos /* 4052 1.1 christos * We need to give the origin node the right locknum. 4053 1.1 christos */ 4054 1.1 christos dns_name_init(&name, NULL); 4055 1.1 christos dns_rbt_namefromnode(rbtdb->origin_node, &name); 4056 1.7 christos rbtdb->origin_node->locknum = rbtdb->origin_node->hashval % 4057 1.7 christos rbtdb->node_lock_count; 4058 1.1 christos /* 4059 1.1 christos * Add an apex node to the NSEC3 tree so that NSEC3 searches 4060 1.1 christos * return partial matches when there is only a single NSEC3 4061 1.1 christos * record in the tree. 4062 1.1 christos */ 4063 1.1 christos result = dns_rbt_addnode(rbtdb->nsec3, &rbtdb->common.origin, 4064 1.1 christos &rbtdb->nsec3_origin_node); 4065 1.1 christos if (result != ISC_R_SUCCESS) { 4066 1.1 christos INSIST(result != ISC_R_EXISTS); 4067 1.21 christos free_rbtdb(rbtdb, false); 4068 1.21 christos return result; 4069 1.1 christos } 4070 1.21 christos rbtdb->nsec3_origin_node->nsec = DNS_DB_NSEC_NSEC3; 4071 1.1 christos /* 4072 1.1 christos * We need to give the nsec3 origin node the right locknum. 4073 1.1 christos */ 4074 1.1 christos dns_name_init(&name, NULL); 4075 1.1 christos dns_rbt_namefromnode(rbtdb->nsec3_origin_node, &name); 4076 1.1 christos rbtdb->nsec3_origin_node->locknum = 4077 1.1 christos rbtdb->nsec3_origin_node->hashval % 4078 1.1 christos rbtdb->node_lock_count; 4079 1.1 christos } 4080 1.1 christos 4081 1.1 christos /* 4082 1.1 christos * Version Initialization. 4083 1.1 christos */ 4084 1.3 christos rbtdb->current_version = allocate_version(mctx, 1, 1, false); 4085 1.1 christos rbtdb->current_version->rbtdb = rbtdb; 4086 1.22 christos isc_rwlock_init(&rbtdb->current_version->rwlock); 4087 1.21 christos 4088 1.1 christos /* 4089 1.1 christos * Keep the current version in the open list so that list operation 4090 1.1 christos * won't happen in normal lookup operations. 4091 1.1 christos */ 4092 1.1 christos PREPEND(rbtdb->open_versions, rbtdb->current_version, link); 4093 1.1 christos 4094 1.1 christos rbtdb->common.magic = DNS_DB_MAGIC; 4095 1.1 christos rbtdb->common.impmagic = RBTDB_MAGIC; 4096 1.1 christos 4097 1.1 christos *dbp = (dns_db_t *)rbtdb; 4098 1.1 christos 4099 1.21 christos return ISC_R_SUCCESS; 4100 1.1 christos 4101 1.7 christos cleanup_tree_lock: 4102 1.21 christos TREE_DESTROYLOCK(&rbtdb->tree_lock); 4103 1.21 christos isc_rwlock_destroy(&rbtdb->lock); 4104 1.7 christos isc_mem_put(mctx, rbtdb, sizeof(*rbtdb)); 4105 1.21 christos return result; 4106 1.1 christos } 4107 1.1 christos 4108 1.1 christos /* 4109 1.1 christos * Rdataset Iterator Methods 4110 1.1 christos */ 4111 1.1 christos 4112 1.1 christos static void 4113 1.21 christos rdatasetiter_destroy(dns_rdatasetiter_t **iteratorp DNS__DB_FLARG) { 4114 1.21 christos rbtdb_rdatasetiter_t *rbtiterator = NULL; 4115 1.1 christos 4116 1.1 christos rbtiterator = (rbtdb_rdatasetiter_t *)(*iteratorp); 4117 1.1 christos 4118 1.7 christos if (rbtiterator->common.version != NULL) { 4119 1.21 christos dns__rbtdb_closeversion(rbtiterator->common.db, 4120 1.21 christos &rbtiterator->common.version, 4121 1.21 christos false DNS__DB_FLARG_PASS); 4122 1.7 christos } 4123 1.21 christos dns__db_detachnode(rbtiterator->common.db, 4124 1.21 christos &rbtiterator->common.node DNS__DB_FLARG_PASS); 4125 1.1 christos isc_mem_put(rbtiterator->common.db->mctx, rbtiterator, 4126 1.1 christos sizeof(*rbtiterator)); 4127 1.1 christos 4128 1.1 christos *iteratorp = NULL; 4129 1.1 christos } 4130 1.1 christos 4131 1.16 christos static bool 4132 1.16 christos iterator_active(dns_rbtdb_t *rbtdb, rbtdb_rdatasetiter_t *rbtiterator, 4133 1.21 christos dns_slabheader_t *header) { 4134 1.21 christos dns_ttl_t stale_ttl = header->ttl + STALE_TTL(header, rbtdb); 4135 1.16 christos 4136 1.16 christos /* 4137 1.16 christos * Is this a "this rdataset doesn't exist" record? 4138 1.16 christos */ 4139 1.16 christos if (NONEXISTENT(header)) { 4140 1.21 christos return false; 4141 1.16 christos } 4142 1.16 christos 4143 1.16 christos /* 4144 1.16 christos * If this is a zone or this header still active then return it. 4145 1.16 christos */ 4146 1.16 christos if (!IS_CACHE(rbtdb) || ACTIVE(header, rbtiterator->common.now)) { 4147 1.21 christos return true; 4148 1.16 christos } 4149 1.16 christos 4150 1.16 christos /* 4151 1.16 christos * If we are not returning stale records or the rdataset is 4152 1.16 christos * too old don't return it. 4153 1.16 christos */ 4154 1.16 christos if (!STALEOK(rbtiterator) || (rbtiterator->common.now > stale_ttl)) { 4155 1.21 christos return false; 4156 1.16 christos } 4157 1.21 christos return true; 4158 1.16 christos } 4159 1.16 christos 4160 1.1 christos static isc_result_t 4161 1.21 christos rdatasetiter_first(dns_rdatasetiter_t *iterator DNS__DB_FLARG) { 4162 1.1 christos rbtdb_rdatasetiter_t *rbtiterator = (rbtdb_rdatasetiter_t *)iterator; 4163 1.1 christos dns_rbtdb_t *rbtdb = (dns_rbtdb_t *)(rbtiterator->common.db); 4164 1.1 christos dns_rbtnode_t *rbtnode = rbtiterator->common.node; 4165 1.21 christos dns_rbtdb_version_t *rbtversion = rbtiterator->common.version; 4166 1.21 christos dns_slabheader_t *header = NULL, *top_next = NULL; 4167 1.21 christos uint32_t serial = IS_CACHE(rbtdb) ? 1 : rbtversion->serial; 4168 1.21 christos isc_rwlocktype_t nlocktype = isc_rwlocktype_none; 4169 1.1 christos 4170 1.21 christos NODE_RDLOCK(&rbtdb->node_locks[rbtnode->locknum].lock, &nlocktype); 4171 1.1 christos 4172 1.1 christos for (header = rbtnode->data; header != NULL; header = top_next) { 4173 1.1 christos top_next = header->next; 4174 1.1 christos do { 4175 1.16 christos if (EXPIREDOK(rbtiterator)) { 4176 1.16 christos if (!NONEXISTENT(header)) { 4177 1.16 christos break; 4178 1.16 christos } 4179 1.16 christos header = header->down; 4180 1.16 christos } else if (header->serial <= serial && !IGNORE(header)) 4181 1.16 christos { 4182 1.16 christos if (!iterator_active(rbtdb, rbtiterator, 4183 1.16 christos header)) 4184 1.16 christos { 4185 1.1 christos header = NULL; 4186 1.7 christos } 4187 1.1 christos break; 4188 1.7 christos } else { 4189 1.1 christos header = header->down; 4190 1.7 christos } 4191 1.1 christos } while (header != NULL); 4192 1.7 christos if (header != NULL) { 4193 1.1 christos break; 4194 1.7 christos } 4195 1.1 christos } 4196 1.1 christos 4197 1.21 christos NODE_UNLOCK(&rbtdb->node_locks[rbtnode->locknum].lock, &nlocktype); 4198 1.1 christos 4199 1.1 christos rbtiterator->current = header; 4200 1.1 christos 4201 1.7 christos if (header == NULL) { 4202 1.21 christos return ISC_R_NOMORE; 4203 1.7 christos } 4204 1.1 christos 4205 1.21 christos return ISC_R_SUCCESS; 4206 1.1 christos } 4207 1.1 christos 4208 1.1 christos static isc_result_t 4209 1.21 christos rdatasetiter_next(dns_rdatasetiter_t *iterator DNS__DB_FLARG) { 4210 1.1 christos rbtdb_rdatasetiter_t *rbtiterator = (rbtdb_rdatasetiter_t *)iterator; 4211 1.1 christos dns_rbtdb_t *rbtdb = (dns_rbtdb_t *)(rbtiterator->common.db); 4212 1.1 christos dns_rbtnode_t *rbtnode = rbtiterator->common.node; 4213 1.21 christos dns_rbtdb_version_t *rbtversion = rbtiterator->common.version; 4214 1.21 christos dns_slabheader_t *header = NULL, *top_next = NULL; 4215 1.21 christos uint32_t serial = IS_CACHE(rbtdb) ? 1 : rbtversion->serial; 4216 1.21 christos dns_typepair_t type, negtype; 4217 1.1 christos dns_rdatatype_t rdtype, covers; 4218 1.21 christos isc_rwlocktype_t nlocktype = isc_rwlocktype_none; 4219 1.16 christos bool expiredok = EXPIREDOK(rbtiterator); 4220 1.1 christos 4221 1.1 christos header = rbtiterator->current; 4222 1.7 christos if (header == NULL) { 4223 1.21 christos return ISC_R_NOMORE; 4224 1.7 christos } 4225 1.1 christos 4226 1.21 christos NODE_RDLOCK(&rbtdb->node_locks[rbtnode->locknum].lock, &nlocktype); 4227 1.1 christos 4228 1.1 christos type = header->type; 4229 1.21 christos rdtype = DNS_TYPEPAIR_TYPE(header->type); 4230 1.1 christos if (NEGATIVE(header)) { 4231 1.21 christos covers = DNS_TYPEPAIR_COVERS(header->type); 4232 1.21 christos negtype = DNS_TYPEPAIR_VALUE(covers, 0); 4233 1.7 christos } else { 4234 1.21 christos negtype = DNS_TYPEPAIR_VALUE(0, rdtype); 4235 1.7 christos } 4236 1.16 christos 4237 1.16 christos /* 4238 1.16 christos * Find the start of the header chain for the next type 4239 1.16 christos * by walking back up the list. 4240 1.16 christos */ 4241 1.16 christos top_next = header->next; 4242 1.16 christos while (top_next != NULL && 4243 1.16 christos (top_next->type == type || top_next->type == negtype)) 4244 1.16 christos { 4245 1.16 christos top_next = top_next->next; 4246 1.16 christos } 4247 1.16 christos if (expiredok) { 4248 1.1 christos /* 4249 1.16 christos * Keep walking down the list if possible or 4250 1.16 christos * start the next type. 4251 1.1 christos */ 4252 1.16 christos header = header->down != NULL ? header->down : top_next; 4253 1.16 christos } else { 4254 1.16 christos header = top_next; 4255 1.16 christos } 4256 1.16 christos for (; header != NULL; header = top_next) { 4257 1.16 christos top_next = header->next; 4258 1.16 christos do { 4259 1.16 christos if (expiredok) { 4260 1.16 christos if (!NONEXISTENT(header)) { 4261 1.16 christos break; 4262 1.16 christos } 4263 1.16 christos header = header->down; 4264 1.16 christos } else if (header->serial <= serial && !IGNORE(header)) 4265 1.16 christos { 4266 1.16 christos if (!iterator_active(rbtdb, rbtiterator, 4267 1.16 christos header)) 4268 1.7 christos { 4269 1.16 christos header = NULL; 4270 1.7 christos } 4271 1.1 christos break; 4272 1.16 christos } else { 4273 1.16 christos header = header->down; 4274 1.7 christos } 4275 1.16 christos } while (header != NULL); 4276 1.16 christos if (header != NULL) { 4277 1.16 christos break; 4278 1.16 christos } 4279 1.16 christos /* 4280 1.16 christos * Find the start of the header chain for the next type 4281 1.16 christos * by walking back up the list. 4282 1.16 christos */ 4283 1.16 christos while (top_next != NULL && 4284 1.16 christos (top_next->type == type || top_next->type == negtype)) 4285 1.16 christos { 4286 1.16 christos top_next = top_next->next; 4287 1.1 christos } 4288 1.1 christos } 4289 1.1 christos 4290 1.21 christos NODE_UNLOCK(&rbtdb->node_locks[rbtnode->locknum].lock, &nlocktype); 4291 1.1 christos 4292 1.1 christos rbtiterator->current = header; 4293 1.1 christos 4294 1.7 christos if (header == NULL) { 4295 1.21 christos return ISC_R_NOMORE; 4296 1.7 christos } 4297 1.1 christos 4298 1.21 christos return ISC_R_SUCCESS; 4299 1.1 christos } 4300 1.1 christos 4301 1.1 christos static void 4302 1.21 christos rdatasetiter_current(dns_rdatasetiter_t *iterator, 4303 1.21 christos dns_rdataset_t *rdataset DNS__DB_FLARG) { 4304 1.1 christos rbtdb_rdatasetiter_t *rbtiterator = (rbtdb_rdatasetiter_t *)iterator; 4305 1.1 christos dns_rbtdb_t *rbtdb = (dns_rbtdb_t *)(rbtiterator->common.db); 4306 1.1 christos dns_rbtnode_t *rbtnode = rbtiterator->common.node; 4307 1.21 christos dns_slabheader_t *header = NULL; 4308 1.21 christos isc_rwlocktype_t nlocktype = isc_rwlocktype_none; 4309 1.1 christos 4310 1.1 christos header = rbtiterator->current; 4311 1.1 christos REQUIRE(header != NULL); 4312 1.1 christos 4313 1.21 christos NODE_RDLOCK(&rbtdb->node_locks[rbtnode->locknum].lock, &nlocktype); 4314 1.1 christos 4315 1.21 christos dns__rbtdb_bindrdataset(rbtdb, rbtnode, header, rbtiterator->common.now, 4316 1.21 christos isc_rwlocktype_read, 4317 1.21 christos rdataset DNS__DB_FLARG_PASS); 4318 1.1 christos 4319 1.21 christos NODE_UNLOCK(&rbtdb->node_locks[rbtnode->locknum].lock, &nlocktype); 4320 1.1 christos } 4321 1.1 christos 4322 1.1 christos /* 4323 1.1 christos * Database Iterator Methods 4324 1.1 christos */ 4325 1.1 christos 4326 1.15 christos static void 4327 1.21 christos reference_iter_node(rbtdb_dbiterator_t *rbtdbiter DNS__DB_FLARG) { 4328 1.1 christos dns_rbtdb_t *rbtdb = (dns_rbtdb_t *)rbtdbiter->common.db; 4329 1.1 christos dns_rbtnode_t *node = rbtdbiter->node; 4330 1.1 christos 4331 1.7 christos if (node == NULL) { 4332 1.1 christos return; 4333 1.7 christos } 4334 1.1 christos 4335 1.1 christos INSIST(rbtdbiter->tree_locked != isc_rwlocktype_none); 4336 1.21 christos reactivate_node(rbtdb, node, rbtdbiter->tree_locked DNS__DB_FLARG_PASS); 4337 1.1 christos } 4338 1.1 christos 4339 1.15 christos static void 4340 1.21 christos dereference_iter_node(rbtdb_dbiterator_t *rbtdbiter DNS__DB_FLARG) { 4341 1.1 christos dns_rbtdb_t *rbtdb = (dns_rbtdb_t *)rbtdbiter->common.db; 4342 1.1 christos dns_rbtnode_t *node = rbtdbiter->node; 4343 1.21 christos isc_rwlock_t *lock = NULL; 4344 1.21 christos isc_rwlocktype_t nlocktype = isc_rwlocktype_none; 4345 1.21 christos isc_rwlocktype_t tlocktype = rbtdbiter->tree_locked; 4346 1.1 christos 4347 1.7 christos if (node == NULL) { 4348 1.1 christos return; 4349 1.7 christos } 4350 1.1 christos 4351 1.21 christos REQUIRE(tlocktype != isc_rwlocktype_write); 4352 1.21 christos 4353 1.1 christos lock = &rbtdb->node_locks[node->locknum].lock; 4354 1.21 christos NODE_RDLOCK(lock, &nlocktype); 4355 1.22 christos dns__rbtnode_release(rbtdb, node, 0, &nlocktype, 4356 1.22 christos &rbtdbiter->tree_locked, false, 4357 1.22 christos false DNS__DB_FLARG_PASS); 4358 1.21 christos NODE_UNLOCK(lock, &nlocktype); 4359 1.21 christos 4360 1.21 christos INSIST(rbtdbiter->tree_locked == tlocktype); 4361 1.1 christos 4362 1.1 christos rbtdbiter->node = NULL; 4363 1.1 christos } 4364 1.1 christos 4365 1.1 christos static void 4366 1.1 christos resume_iteration(rbtdb_dbiterator_t *rbtdbiter) { 4367 1.1 christos dns_rbtdb_t *rbtdb = (dns_rbtdb_t *)rbtdbiter->common.db; 4368 1.1 christos 4369 1.1 christos REQUIRE(rbtdbiter->paused); 4370 1.1 christos REQUIRE(rbtdbiter->tree_locked == isc_rwlocktype_none); 4371 1.1 christos 4372 1.21 christos TREE_RDLOCK(&rbtdb->tree_lock, &rbtdbiter->tree_locked); 4373 1.1 christos 4374 1.3 christos rbtdbiter->paused = false; 4375 1.1 christos } 4376 1.1 christos 4377 1.1 christos static void 4378 1.21 christos dbiterator_destroy(dns_dbiterator_t **iteratorp DNS__DB_FLARG) { 4379 1.1 christos rbtdb_dbiterator_t *rbtdbiter = (rbtdb_dbiterator_t *)(*iteratorp); 4380 1.1 christos dns_rbtdb_t *rbtdb = (dns_rbtdb_t *)rbtdbiter->common.db; 4381 1.1 christos dns_db_t *db = NULL; 4382 1.1 christos 4383 1.1 christos if (rbtdbiter->tree_locked == isc_rwlocktype_read) { 4384 1.21 christos TREE_UNLOCK(&rbtdb->tree_lock, &rbtdbiter->tree_locked); 4385 1.7 christos } 4386 1.21 christos INSIST(rbtdbiter->tree_locked == isc_rwlocktype_none); 4387 1.1 christos 4388 1.21 christos dereference_iter_node(rbtdbiter DNS__DB_FLARG_PASS); 4389 1.1 christos 4390 1.1 christos dns_db_attach(rbtdbiter->common.db, &db); 4391 1.1 christos dns_db_detach(&rbtdbiter->common.db); 4392 1.1 christos 4393 1.1 christos dns_rbtnodechain_reset(&rbtdbiter->chain); 4394 1.1 christos dns_rbtnodechain_reset(&rbtdbiter->nsec3chain); 4395 1.1 christos isc_mem_put(db->mctx, rbtdbiter, sizeof(*rbtdbiter)); 4396 1.1 christos dns_db_detach(&db); 4397 1.1 christos 4398 1.1 christos *iteratorp = NULL; 4399 1.1 christos } 4400 1.1 christos 4401 1.1 christos static isc_result_t 4402 1.21 christos dbiterator_first(dns_dbiterator_t *iterator DNS__DB_FLARG) { 4403 1.1 christos isc_result_t result; 4404 1.1 christos rbtdb_dbiterator_t *rbtdbiter = (rbtdb_dbiterator_t *)iterator; 4405 1.1 christos dns_rbtdb_t *rbtdb = (dns_rbtdb_t *)iterator->db; 4406 1.21 christos dns_name_t *name = NULL, *origin = NULL; 4407 1.1 christos 4408 1.1 christos if (rbtdbiter->result != ISC_R_SUCCESS && 4409 1.1 christos rbtdbiter->result != ISC_R_NOTFOUND && 4410 1.1 christos rbtdbiter->result != DNS_R_PARTIALMATCH && 4411 1.1 christos rbtdbiter->result != ISC_R_NOMORE) 4412 1.7 christos { 4413 1.21 christos return rbtdbiter->result; 4414 1.7 christos } 4415 1.1 christos 4416 1.7 christos if (rbtdbiter->paused) { 4417 1.1 christos resume_iteration(rbtdbiter); 4418 1.7 christos } 4419 1.1 christos 4420 1.21 christos dereference_iter_node(rbtdbiter DNS__DB_FLARG_PASS); 4421 1.1 christos 4422 1.1 christos name = dns_fixedname_name(&rbtdbiter->name); 4423 1.1 christos origin = dns_fixedname_name(&rbtdbiter->origin); 4424 1.1 christos dns_rbtnodechain_reset(&rbtdbiter->chain); 4425 1.1 christos dns_rbtnodechain_reset(&rbtdbiter->nsec3chain); 4426 1.1 christos 4427 1.20 christos switch (rbtdbiter->nsec3mode) { 4428 1.20 christos case nsec3only: 4429 1.1 christos rbtdbiter->current = &rbtdbiter->nsec3chain; 4430 1.1 christos result = dns_rbtnodechain_first(rbtdbiter->current, 4431 1.1 christos rbtdb->nsec3, name, origin); 4432 1.20 christos break; 4433 1.20 christos case nonsec3: 4434 1.20 christos rbtdbiter->current = &rbtdbiter->chain; 4435 1.20 christos result = dns_rbtnodechain_first(rbtdbiter->current, rbtdb->tree, 4436 1.20 christos name, origin); 4437 1.20 christos break; 4438 1.20 christos case full: 4439 1.1 christos rbtdbiter->current = &rbtdbiter->chain; 4440 1.7 christos result = dns_rbtnodechain_first(rbtdbiter->current, rbtdb->tree, 4441 1.7 christos name, origin); 4442 1.20 christos if (result == ISC_R_NOTFOUND) { 4443 1.1 christos rbtdbiter->current = &rbtdbiter->nsec3chain; 4444 1.7 christos result = dns_rbtnodechain_first( 4445 1.7 christos rbtdbiter->current, rbtdb->nsec3, name, origin); 4446 1.1 christos } 4447 1.20 christos break; 4448 1.20 christos default: 4449 1.20 christos UNREACHABLE(); 4450 1.1 christos } 4451 1.20 christos 4452 1.1 christos if (result == ISC_R_SUCCESS || result == DNS_R_NEWORIGIN) { 4453 1.1 christos result = dns_rbtnodechain_current(rbtdbiter->current, NULL, 4454 1.1 christos NULL, &rbtdbiter->node); 4455 1.20 christos 4456 1.20 christos /* If we're in the NSEC3 tree, skip the origin */ 4457 1.20 christos if (RBTDBITER_NSEC3_ORIGIN_NODE(rbtdb, rbtdbiter)) { 4458 1.20 christos rbtdbiter->node = NULL; 4459 1.20 christos result = dns_rbtnodechain_next(rbtdbiter->current, name, 4460 1.20 christos origin); 4461 1.20 christos if (result == ISC_R_SUCCESS || 4462 1.20 christos result == DNS_R_NEWORIGIN) 4463 1.20 christos { 4464 1.20 christos result = dns_rbtnodechain_current( 4465 1.20 christos rbtdbiter->current, NULL, NULL, 4466 1.20 christos &rbtdbiter->node); 4467 1.20 christos } 4468 1.20 christos } 4469 1.1 christos if (result == ISC_R_SUCCESS) { 4470 1.3 christos rbtdbiter->new_origin = true; 4471 1.21 christos reference_iter_node(rbtdbiter DNS__DB_FLARG_PASS); 4472 1.1 christos } 4473 1.1 christos } else { 4474 1.1 christos INSIST(result == ISC_R_NOTFOUND); 4475 1.1 christos result = ISC_R_NOMORE; /* The tree is empty. */ 4476 1.1 christos } 4477 1.1 christos 4478 1.1 christos rbtdbiter->result = result; 4479 1.1 christos 4480 1.7 christos if (result != ISC_R_SUCCESS) { 4481 1.1 christos ENSURE(!rbtdbiter->paused); 4482 1.7 christos } 4483 1.1 christos 4484 1.21 christos return result; 4485 1.1 christos } 4486 1.1 christos 4487 1.1 christos static isc_result_t 4488 1.21 christos dbiterator_last(dns_dbiterator_t *iterator DNS__DB_FLARG) { 4489 1.1 christos isc_result_t result; 4490 1.1 christos rbtdb_dbiterator_t *rbtdbiter = (rbtdb_dbiterator_t *)iterator; 4491 1.1 christos dns_rbtdb_t *rbtdb = (dns_rbtdb_t *)iterator->db; 4492 1.21 christos dns_name_t *name = NULL, *origin = NULL; 4493 1.1 christos 4494 1.1 christos if (rbtdbiter->result != ISC_R_SUCCESS && 4495 1.1 christos rbtdbiter->result != ISC_R_NOTFOUND && 4496 1.1 christos rbtdbiter->result != DNS_R_PARTIALMATCH && 4497 1.1 christos rbtdbiter->result != ISC_R_NOMORE) 4498 1.7 christos { 4499 1.21 christos return rbtdbiter->result; 4500 1.7 christos } 4501 1.1 christos 4502 1.7 christos if (rbtdbiter->paused) { 4503 1.1 christos resume_iteration(rbtdbiter); 4504 1.7 christos } 4505 1.1 christos 4506 1.21 christos dereference_iter_node(rbtdbiter DNS__DB_FLARG_PASS); 4507 1.1 christos 4508 1.1 christos name = dns_fixedname_name(&rbtdbiter->name); 4509 1.1 christos origin = dns_fixedname_name(&rbtdbiter->origin); 4510 1.1 christos dns_rbtnodechain_reset(&rbtdbiter->chain); 4511 1.1 christos dns_rbtnodechain_reset(&rbtdbiter->nsec3chain); 4512 1.1 christos 4513 1.20 christos switch (rbtdbiter->nsec3mode) { 4514 1.20 christos case nsec3only: 4515 1.1 christos rbtdbiter->current = &rbtdbiter->nsec3chain; 4516 1.7 christos result = dns_rbtnodechain_last(rbtdbiter->current, rbtdb->nsec3, 4517 1.7 christos name, origin); 4518 1.20 christos break; 4519 1.20 christos case nonsec3: 4520 1.1 christos rbtdbiter->current = &rbtdbiter->chain; 4521 1.1 christos result = dns_rbtnodechain_last(rbtdbiter->current, rbtdb->tree, 4522 1.1 christos name, origin); 4523 1.20 christos break; 4524 1.20 christos case full: 4525 1.20 christos rbtdbiter->current = &rbtdbiter->nsec3chain; 4526 1.20 christos result = dns_rbtnodechain_last(rbtdbiter->current, rbtdb->nsec3, 4527 1.20 christos name, origin); 4528 1.20 christos if (result == ISC_R_NOTFOUND) { 4529 1.20 christos rbtdbiter->current = &rbtdbiter->chain; 4530 1.20 christos result = dns_rbtnodechain_last( 4531 1.20 christos rbtdbiter->current, rbtdb->tree, name, origin); 4532 1.20 christos } 4533 1.20 christos break; 4534 1.20 christos default: 4535 1.20 christos UNREACHABLE(); 4536 1.1 christos } 4537 1.20 christos 4538 1.1 christos if (result == ISC_R_SUCCESS || result == DNS_R_NEWORIGIN) { 4539 1.1 christos result = dns_rbtnodechain_current(rbtdbiter->current, NULL, 4540 1.1 christos NULL, &rbtdbiter->node); 4541 1.20 christos if (RBTDBITER_NSEC3_ORIGIN_NODE(rbtdb, rbtdbiter)) { 4542 1.20 christos /* 4543 1.20 christos * NSEC3 tree only has an origin node. 4544 1.20 christos */ 4545 1.20 christos rbtdbiter->node = NULL; 4546 1.20 christos switch (rbtdbiter->nsec3mode) { 4547 1.20 christos case nsec3only: 4548 1.20 christos result = ISC_R_NOMORE; 4549 1.20 christos break; 4550 1.20 christos case nonsec3: 4551 1.20 christos case full: 4552 1.20 christos rbtdbiter->current = &rbtdbiter->chain; 4553 1.20 christos result = dns_rbtnodechain_last( 4554 1.20 christos rbtdbiter->current, rbtdb->tree, name, 4555 1.20 christos origin); 4556 1.20 christos if (result == ISC_R_SUCCESS || 4557 1.20 christos result == DNS_R_NEWORIGIN) 4558 1.20 christos { 4559 1.20 christos result = dns_rbtnodechain_current( 4560 1.20 christos rbtdbiter->current, NULL, NULL, 4561 1.20 christos &rbtdbiter->node); 4562 1.20 christos } 4563 1.20 christos break; 4564 1.20 christos default: 4565 1.20 christos UNREACHABLE(); 4566 1.20 christos } 4567 1.20 christos } 4568 1.1 christos if (result == ISC_R_SUCCESS) { 4569 1.3 christos rbtdbiter->new_origin = true; 4570 1.21 christos reference_iter_node(rbtdbiter DNS__DB_FLARG_PASS); 4571 1.1 christos } 4572 1.1 christos } else { 4573 1.1 christos INSIST(result == ISC_R_NOTFOUND); 4574 1.1 christos result = ISC_R_NOMORE; /* The tree is empty. */ 4575 1.1 christos } 4576 1.1 christos 4577 1.1 christos rbtdbiter->result = result; 4578 1.1 christos 4579 1.21 christos return result; 4580 1.1 christos } 4581 1.1 christos 4582 1.1 christos static isc_result_t 4583 1.21 christos dbiterator_seek(dns_dbiterator_t *iterator, 4584 1.21 christos const dns_name_t *name DNS__DB_FLARG) { 4585 1.1 christos isc_result_t result, tresult; 4586 1.1 christos rbtdb_dbiterator_t *rbtdbiter = (rbtdb_dbiterator_t *)iterator; 4587 1.1 christos dns_rbtdb_t *rbtdb = (dns_rbtdb_t *)iterator->db; 4588 1.21 christos dns_name_t *iname = NULL, *origin = NULL; 4589 1.1 christos 4590 1.1 christos if (rbtdbiter->result != ISC_R_SUCCESS && 4591 1.1 christos rbtdbiter->result != ISC_R_NOTFOUND && 4592 1.1 christos rbtdbiter->result != DNS_R_PARTIALMATCH && 4593 1.1 christos rbtdbiter->result != ISC_R_NOMORE) 4594 1.7 christos { 4595 1.21 christos return rbtdbiter->result; 4596 1.7 christos } 4597 1.1 christos 4598 1.7 christos if (rbtdbiter->paused) { 4599 1.1 christos resume_iteration(rbtdbiter); 4600 1.7 christos } 4601 1.1 christos 4602 1.21 christos dereference_iter_node(rbtdbiter DNS__DB_FLARG_PASS); 4603 1.1 christos 4604 1.1 christos iname = dns_fixedname_name(&rbtdbiter->name); 4605 1.1 christos origin = dns_fixedname_name(&rbtdbiter->origin); 4606 1.1 christos dns_rbtnodechain_reset(&rbtdbiter->chain); 4607 1.1 christos dns_rbtnodechain_reset(&rbtdbiter->nsec3chain); 4608 1.1 christos 4609 1.20 christos switch (rbtdbiter->nsec3mode) { 4610 1.20 christos case nsec3only: 4611 1.1 christos rbtdbiter->current = &rbtdbiter->nsec3chain; 4612 1.1 christos result = dns_rbt_findnode(rbtdb->nsec3, name, NULL, 4613 1.7 christos &rbtdbiter->node, rbtdbiter->current, 4614 1.1 christos DNS_RBTFIND_EMPTYDATA, NULL, NULL); 4615 1.20 christos break; 4616 1.20 christos case nonsec3: 4617 1.1 christos rbtdbiter->current = &rbtdbiter->chain; 4618 1.1 christos result = dns_rbt_findnode(rbtdb->tree, name, NULL, 4619 1.7 christos &rbtdbiter->node, rbtdbiter->current, 4620 1.1 christos DNS_RBTFIND_EMPTYDATA, NULL, NULL); 4621 1.20 christos break; 4622 1.20 christos case full: 4623 1.1 christos /* 4624 1.1 christos * Stay on main chain if not found on either chain. 4625 1.1 christos */ 4626 1.1 christos rbtdbiter->current = &rbtdbiter->chain; 4627 1.1 christos result = dns_rbt_findnode(rbtdb->tree, name, NULL, 4628 1.7 christos &rbtdbiter->node, rbtdbiter->current, 4629 1.1 christos DNS_RBTFIND_EMPTYDATA, NULL, NULL); 4630 1.1 christos if (result == DNS_R_PARTIALMATCH) { 4631 1.1 christos dns_rbtnode_t *node = NULL; 4632 1.7 christos tresult = dns_rbt_findnode( 4633 1.7 christos rbtdb->nsec3, name, NULL, &node, 4634 1.7 christos &rbtdbiter->nsec3chain, DNS_RBTFIND_EMPTYDATA, 4635 1.7 christos NULL, NULL); 4636 1.1 christos if (tresult == ISC_R_SUCCESS) { 4637 1.1 christos rbtdbiter->node = node; 4638 1.1 christos rbtdbiter->current = &rbtdbiter->nsec3chain; 4639 1.1 christos result = tresult; 4640 1.1 christos } 4641 1.1 christos } 4642 1.20 christos break; 4643 1.20 christos default: 4644 1.20 christos UNREACHABLE(); 4645 1.1 christos } 4646 1.1 christos 4647 1.1 christos if (result == ISC_R_SUCCESS || result == DNS_R_PARTIALMATCH) { 4648 1.1 christos tresult = dns_rbtnodechain_current(rbtdbiter->current, iname, 4649 1.1 christos origin, NULL); 4650 1.1 christos if (tresult == ISC_R_SUCCESS) { 4651 1.3 christos rbtdbiter->new_origin = true; 4652 1.21 christos reference_iter_node(rbtdbiter DNS__DB_FLARG_PASS); 4653 1.1 christos } else { 4654 1.1 christos result = tresult; 4655 1.1 christos rbtdbiter->node = NULL; 4656 1.1 christos } 4657 1.7 christos } else { 4658 1.1 christos rbtdbiter->node = NULL; 4659 1.7 christos } 4660 1.1 christos 4661 1.7 christos rbtdbiter->result = (result == DNS_R_PARTIALMATCH) ? ISC_R_SUCCESS 4662 1.7 christos : result; 4663 1.1 christos 4664 1.21 christos return result; 4665 1.1 christos } 4666 1.1 christos 4667 1.1 christos static isc_result_t 4668 1.23 christos dbiterator_seek3(dns_dbiterator_t *iterator, 4669 1.23 christos const dns_name_t *name DNS__DB_FLARG) { 4670 1.23 christos isc_result_t result, tresult; 4671 1.23 christos rbtdb_dbiterator_t *rbtdbiter = (rbtdb_dbiterator_t *)iterator; 4672 1.23 christos dns_rbtdb_t *rbtdb = (dns_rbtdb_t *)iterator->db; 4673 1.23 christos dns_name_t *iname = NULL, *origin = NULL; 4674 1.23 christos 4675 1.23 christos if (rbtdbiter->result != ISC_R_SUCCESS && 4676 1.23 christos rbtdbiter->result != ISC_R_NOTFOUND && 4677 1.23 christos rbtdbiter->result != DNS_R_PARTIALMATCH && 4678 1.23 christos rbtdbiter->result != ISC_R_NOMORE) 4679 1.23 christos { 4680 1.23 christos return rbtdbiter->result; 4681 1.23 christos } 4682 1.23 christos 4683 1.23 christos if (rbtdbiter->nsec3mode != nsec3only) { 4684 1.23 christos return ISC_R_NOTIMPLEMENTED; 4685 1.23 christos } 4686 1.23 christos 4687 1.23 christos if (rbtdbiter->paused) { 4688 1.23 christos resume_iteration(rbtdbiter); 4689 1.23 christos } 4690 1.23 christos 4691 1.23 christos dereference_iter_node(rbtdbiter DNS__DB_FLARG_PASS); 4692 1.23 christos 4693 1.23 christos iname = dns_fixedname_name(&rbtdbiter->name); 4694 1.23 christos origin = dns_fixedname_name(&rbtdbiter->origin); 4695 1.23 christos dns_rbtnodechain_reset(&rbtdbiter->chain); 4696 1.23 christos dns_rbtnodechain_reset(&rbtdbiter->nsec3chain); 4697 1.23 christos 4698 1.23 christos rbtdbiter->current = &rbtdbiter->nsec3chain; 4699 1.23 christos result = dns_rbt_findnode(rbtdb->nsec3, name, NULL, &rbtdbiter->node, 4700 1.23 christos rbtdbiter->current, DNS_RBTFIND_EMPTYDATA, 4701 1.23 christos NULL, NULL); 4702 1.23 christos 4703 1.23 christos if (result == ISC_R_SUCCESS) { 4704 1.23 christos tresult = dns_rbtnodechain_current(rbtdbiter->current, iname, 4705 1.23 christos origin, NULL); 4706 1.23 christos 4707 1.23 christos reference_iter_node(rbtdbiter DNS__DB_FLARG_PASS); 4708 1.23 christos 4709 1.23 christos if (tresult == ISC_R_SUCCESS) { 4710 1.23 christos rbtdbiter->new_origin = true; 4711 1.23 christos } else { 4712 1.23 christos result = tresult; 4713 1.23 christos rbtdbiter->node = NULL; 4714 1.23 christos } 4715 1.23 christos } else if (result == DNS_R_PARTIALMATCH) { 4716 1.23 christos tresult = dns_rbtnodechain_current(rbtdbiter->current, iname, 4717 1.23 christos origin, NULL); 4718 1.23 christos 4719 1.23 christos /* dbiterator_next() will dereference the node */ 4720 1.23 christos reference_iter_node(rbtdbiter DNS__DB_FLARG_PASS); 4721 1.23 christos 4722 1.23 christos if (tresult == ISC_R_SUCCESS) { 4723 1.23 christos rbtdbiter->new_origin = true; 4724 1.23 christos 4725 1.23 christos result = dbiterator_next(iterator); 4726 1.23 christos if (result == ISC_R_NOMORE) { 4727 1.23 christos result = dbiterator_first(iterator); 4728 1.23 christos } 4729 1.23 christos 4730 1.23 christos tresult = dns_rbtnodechain_current(rbtdbiter->current, 4731 1.23 christos iname, origin, NULL); 4732 1.23 christos if (tresult == ISC_R_SUCCESS) { 4733 1.23 christos rbtdbiter->new_origin = true; 4734 1.23 christos } else { 4735 1.23 christos result = tresult; 4736 1.23 christos rbtdbiter->node = NULL; 4737 1.23 christos } 4738 1.23 christos } else { 4739 1.23 christos result = tresult; 4740 1.23 christos rbtdbiter->node = NULL; 4741 1.23 christos } 4742 1.23 christos } else { 4743 1.23 christos rbtdbiter->node = NULL; 4744 1.23 christos } 4745 1.23 christos 4746 1.23 christos rbtdbiter->result = result; 4747 1.23 christos 4748 1.23 christos return result; 4749 1.23 christos } 4750 1.23 christos 4751 1.23 christos static isc_result_t 4752 1.21 christos dbiterator_prev(dns_dbiterator_t *iterator DNS__DB_FLARG) { 4753 1.1 christos isc_result_t result; 4754 1.1 christos rbtdb_dbiterator_t *rbtdbiter = (rbtdb_dbiterator_t *)iterator; 4755 1.21 christos dns_name_t *name = NULL, *origin = NULL; 4756 1.1 christos dns_rbtdb_t *rbtdb = (dns_rbtdb_t *)iterator->db; 4757 1.1 christos 4758 1.1 christos REQUIRE(rbtdbiter->node != NULL); 4759 1.1 christos 4760 1.7 christos if (rbtdbiter->result != ISC_R_SUCCESS) { 4761 1.21 christos return rbtdbiter->result; 4762 1.7 christos } 4763 1.1 christos 4764 1.7 christos if (rbtdbiter->paused) { 4765 1.1 christos resume_iteration(rbtdbiter); 4766 1.7 christos } 4767 1.1 christos 4768 1.1 christos name = dns_fixedname_name(&rbtdbiter->name); 4769 1.1 christos origin = dns_fixedname_name(&rbtdbiter->origin); 4770 1.1 christos result = dns_rbtnodechain_prev(rbtdbiter->current, name, origin); 4771 1.23 christos 4772 1.23 christos dereference_iter_node(rbtdbiter DNS__DB_FLARG_PASS); 4773 1.23 christos 4774 1.20 christos if (rbtdbiter->current == &rbtdbiter->nsec3chain && 4775 1.20 christos (result == ISC_R_SUCCESS || result == DNS_R_NEWORIGIN)) 4776 1.20 christos { 4777 1.20 christos /* 4778 1.20 christos * If we're in the NSEC3 tree, it's empty or we've 4779 1.20 christos * reached the origin, then we're done with it. 4780 1.20 christos */ 4781 1.20 christos result = dns_rbtnodechain_current(rbtdbiter->current, NULL, 4782 1.20 christos NULL, &rbtdbiter->node); 4783 1.20 christos if (result == ISC_R_NOTFOUND || 4784 1.20 christos RBTDBITER_NSEC3_ORIGIN_NODE(rbtdb, rbtdbiter)) 4785 1.20 christos { 4786 1.20 christos rbtdbiter->node = NULL; 4787 1.20 christos result = ISC_R_NOMORE; 4788 1.20 christos } 4789 1.20 christos } 4790 1.20 christos if (result == ISC_R_NOMORE && rbtdbiter->nsec3mode != nsec3only && 4791 1.20 christos &rbtdbiter->nsec3chain == rbtdbiter->current) 4792 1.7 christos { 4793 1.1 christos rbtdbiter->current = &rbtdbiter->chain; 4794 1.1 christos dns_rbtnodechain_reset(rbtdbiter->current); 4795 1.1 christos result = dns_rbtnodechain_last(rbtdbiter->current, rbtdb->tree, 4796 1.1 christos name, origin); 4797 1.7 christos if (result == ISC_R_NOTFOUND) { 4798 1.1 christos result = ISC_R_NOMORE; 4799 1.7 christos } 4800 1.1 christos } 4801 1.1 christos 4802 1.1 christos if (result == DNS_R_NEWORIGIN || result == ISC_R_SUCCESS) { 4803 1.3 christos rbtdbiter->new_origin = (result == DNS_R_NEWORIGIN); 4804 1.1 christos result = dns_rbtnodechain_current(rbtdbiter->current, NULL, 4805 1.1 christos NULL, &rbtdbiter->node); 4806 1.1 christos } 4807 1.1 christos 4808 1.7 christos if (result == ISC_R_SUCCESS) { 4809 1.21 christos reference_iter_node(rbtdbiter DNS__DB_FLARG_PASS); 4810 1.7 christos } 4811 1.1 christos 4812 1.1 christos rbtdbiter->result = result; 4813 1.1 christos 4814 1.21 christos return result; 4815 1.1 christos } 4816 1.1 christos 4817 1.1 christos static isc_result_t 4818 1.21 christos dbiterator_next(dns_dbiterator_t *iterator DNS__DB_FLARG) { 4819 1.1 christos isc_result_t result; 4820 1.1 christos rbtdb_dbiterator_t *rbtdbiter = (rbtdb_dbiterator_t *)iterator; 4821 1.21 christos dns_name_t *name = NULL, *origin = NULL; 4822 1.1 christos dns_rbtdb_t *rbtdb = (dns_rbtdb_t *)iterator->db; 4823 1.1 christos 4824 1.1 christos REQUIRE(rbtdbiter->node != NULL); 4825 1.1 christos 4826 1.7 christos if (rbtdbiter->result != ISC_R_SUCCESS) { 4827 1.21 christos return rbtdbiter->result; 4828 1.7 christos } 4829 1.1 christos 4830 1.7 christos if (rbtdbiter->paused) { 4831 1.1 christos resume_iteration(rbtdbiter); 4832 1.7 christos } 4833 1.1 christos 4834 1.1 christos name = dns_fixedname_name(&rbtdbiter->name); 4835 1.1 christos origin = dns_fixedname_name(&rbtdbiter->origin); 4836 1.1 christos result = dns_rbtnodechain_next(rbtdbiter->current, name, origin); 4837 1.20 christos if (result == ISC_R_NOMORE && rbtdbiter->nsec3mode != nonsec3 && 4838 1.20 christos &rbtdbiter->chain == rbtdbiter->current) 4839 1.7 christos { 4840 1.1 christos rbtdbiter->current = &rbtdbiter->nsec3chain; 4841 1.1 christos dns_rbtnodechain_reset(rbtdbiter->current); 4842 1.1 christos result = dns_rbtnodechain_first(rbtdbiter->current, 4843 1.1 christos rbtdb->nsec3, name, origin); 4844 1.7 christos if (result == ISC_R_NOTFOUND) { 4845 1.1 christos result = ISC_R_NOMORE; 4846 1.7 christos } 4847 1.1 christos } 4848 1.1 christos 4849 1.21 christos dereference_iter_node(rbtdbiter DNS__DB_FLARG_PASS); 4850 1.1 christos 4851 1.1 christos if (result == DNS_R_NEWORIGIN || result == ISC_R_SUCCESS) { 4852 1.20 christos /* 4853 1.20 christos * If we've just started the NSEC3 tree, 4854 1.20 christos * skip over the origin. 4855 1.20 christos */ 4856 1.3 christos rbtdbiter->new_origin = (result == DNS_R_NEWORIGIN); 4857 1.1 christos result = dns_rbtnodechain_current(rbtdbiter->current, NULL, 4858 1.1 christos NULL, &rbtdbiter->node); 4859 1.20 christos if (RBTDBITER_NSEC3_ORIGIN_NODE(rbtdb, rbtdbiter)) { 4860 1.20 christos rbtdbiter->node = NULL; 4861 1.20 christos result = dns_rbtnodechain_next(rbtdbiter->current, name, 4862 1.20 christos origin); 4863 1.20 christos if (result == ISC_R_SUCCESS || 4864 1.20 christos result == DNS_R_NEWORIGIN) 4865 1.20 christos { 4866 1.20 christos result = dns_rbtnodechain_current( 4867 1.20 christos rbtdbiter->current, NULL, NULL, 4868 1.20 christos &rbtdbiter->node); 4869 1.20 christos } 4870 1.20 christos } 4871 1.1 christos } 4872 1.7 christos if (result == ISC_R_SUCCESS) { 4873 1.21 christos reference_iter_node(rbtdbiter DNS__DB_FLARG_PASS); 4874 1.7 christos } 4875 1.1 christos 4876 1.1 christos rbtdbiter->result = result; 4877 1.1 christos 4878 1.21 christos return result; 4879 1.1 christos } 4880 1.1 christos 4881 1.1 christos static isc_result_t 4882 1.1 christos dbiterator_current(dns_dbiterator_t *iterator, dns_dbnode_t **nodep, 4883 1.21 christos dns_name_t *name DNS__DB_FLARG) { 4884 1.1 christos dns_rbtdb_t *rbtdb = (dns_rbtdb_t *)iterator->db; 4885 1.1 christos rbtdb_dbiterator_t *rbtdbiter = (rbtdb_dbiterator_t *)iterator; 4886 1.1 christos dns_rbtnode_t *node = rbtdbiter->node; 4887 1.1 christos isc_result_t result; 4888 1.1 christos dns_name_t *nodename = dns_fixedname_name(&rbtdbiter->name); 4889 1.1 christos dns_name_t *origin = dns_fixedname_name(&rbtdbiter->origin); 4890 1.1 christos 4891 1.1 christos REQUIRE(rbtdbiter->result == ISC_R_SUCCESS); 4892 1.1 christos REQUIRE(rbtdbiter->node != NULL); 4893 1.1 christos 4894 1.7 christos if (rbtdbiter->paused) { 4895 1.1 christos resume_iteration(rbtdbiter); 4896 1.7 christos } 4897 1.1 christos 4898 1.1 christos if (name != NULL) { 4899 1.7 christos if (rbtdbiter->common.relative_names) { 4900 1.1 christos origin = NULL; 4901 1.7 christos } 4902 1.1 christos result = dns_name_concatenate(nodename, origin, name, NULL); 4903 1.7 christos if (result != ISC_R_SUCCESS) { 4904 1.21 christos return result; 4905 1.7 christos } 4906 1.7 christos if (rbtdbiter->common.relative_names && rbtdbiter->new_origin) { 4907 1.1 christos result = DNS_R_NEWORIGIN; 4908 1.7 christos } 4909 1.7 christos } else { 4910 1.1 christos result = ISC_R_SUCCESS; 4911 1.7 christos } 4912 1.1 christos 4913 1.22 christos dns__rbtnode_acquire(rbtdb, node, 4914 1.22 christos isc_rwlocktype_none DNS__DB_FLARG_PASS); 4915 1.1 christos 4916 1.1 christos *nodep = rbtdbiter->node; 4917 1.1 christos 4918 1.21 christos return result; 4919 1.1 christos } 4920 1.1 christos 4921 1.1 christos static isc_result_t 4922 1.1 christos dbiterator_pause(dns_dbiterator_t *iterator) { 4923 1.1 christos dns_rbtdb_t *rbtdb = (dns_rbtdb_t *)iterator->db; 4924 1.1 christos rbtdb_dbiterator_t *rbtdbiter = (rbtdb_dbiterator_t *)iterator; 4925 1.1 christos 4926 1.1 christos if (rbtdbiter->result != ISC_R_SUCCESS && 4927 1.1 christos rbtdbiter->result != ISC_R_NOTFOUND && 4928 1.1 christos rbtdbiter->result != DNS_R_PARTIALMATCH && 4929 1.1 christos rbtdbiter->result != ISC_R_NOMORE) 4930 1.7 christos { 4931 1.21 christos return rbtdbiter->result; 4932 1.7 christos } 4933 1.1 christos 4934 1.7 christos if (rbtdbiter->paused) { 4935 1.21 christos return ISC_R_SUCCESS; 4936 1.7 christos } 4937 1.1 christos 4938 1.3 christos rbtdbiter->paused = true; 4939 1.1 christos 4940 1.21 christos if (rbtdbiter->tree_locked == isc_rwlocktype_read) { 4941 1.21 christos TREE_UNLOCK(&rbtdb->tree_lock, &rbtdbiter->tree_locked); 4942 1.1 christos } 4943 1.21 christos INSIST(rbtdbiter->tree_locked == isc_rwlocktype_none); 4944 1.1 christos 4945 1.21 christos return ISC_R_SUCCESS; 4946 1.1 christos } 4947 1.1 christos 4948 1.1 christos static isc_result_t 4949 1.1 christos dbiterator_origin(dns_dbiterator_t *iterator, dns_name_t *name) { 4950 1.1 christos rbtdb_dbiterator_t *rbtdbiter = (rbtdb_dbiterator_t *)iterator; 4951 1.1 christos dns_name_t *origin = dns_fixedname_name(&rbtdbiter->origin); 4952 1.1 christos 4953 1.7 christos if (rbtdbiter->result != ISC_R_SUCCESS) { 4954 1.21 christos return rbtdbiter->result; 4955 1.7 christos } 4956 1.1 christos 4957 1.19 christos dns_name_copy(origin, name); 4958 1.21 christos return ISC_R_SUCCESS; 4959 1.1 christos } 4960 1.1 christos 4961 1.21 christos void 4962 1.21 christos dns__rbtdb_deletedata(dns_db_t *db ISC_ATTR_UNUSED, 4963 1.21 christos dns_dbnode_t *node ISC_ATTR_UNUSED, void *data) { 4964 1.21 christos dns_slabheader_t *header = data; 4965 1.21 christos dns_rbtdb_t *rbtdb = (dns_rbtdb_t *)header->db; 4966 1.9 christos 4967 1.21 christos if (header->heap != NULL && header->heap_index != 0) { 4968 1.21 christos isc_heap_delete(header->heap, header->heap_index); 4969 1.7 christos } 4970 1.1 christos 4971 1.21 christos if (IS_CACHE(rbtdb)) { 4972 1.21 christos update_rrsetstats(rbtdb->rrsetstats, header->type, 4973 1.21 christos atomic_load_acquire(&header->attributes), 4974 1.21 christos false); 4975 1.1 christos 4976 1.21 christos if (ISC_LINK_LINKED(header, link)) { 4977 1.21 christos int idx = RBTDB_HEADERNODE(header)->locknum; 4978 1.21 christos INSIST(IS_CACHE(rbtdb)); 4979 1.21 christos ISC_LIST_UNLINK(rbtdb->lru[idx], header, link); 4980 1.19 christos } 4981 1.1 christos 4982 1.21 christos if (header->noqname != NULL) { 4983 1.21 christos dns_slabheader_freeproof(db->mctx, &header->noqname); 4984 1.7 christos } 4985 1.21 christos if (header->closest != NULL) { 4986 1.21 christos dns_slabheader_freeproof(db->mctx, &header->closest); 4987 1.1 christos } 4988 1.1 christos } 4989 1.1 christos } 4990 1.20 christos 4991 1.20 christos /* 4992 1.20 christos * Caller must be holding the node write lock. 4993 1.20 christos */ 4994 1.20 christos static void 4995 1.21 christos expire_ttl_headers(dns_rbtdb_t *rbtdb, unsigned int locknum, 4996 1.21 christos isc_rwlocktype_t *tlocktypep, isc_stdtime_t now, 4997 1.21 christos bool cache_is_overmem DNS__DB_FLARG) { 4998 1.20 christos isc_heap_t *heap = rbtdb->heaps[locknum]; 4999 1.20 christos 5000 1.20 christos for (size_t i = 0; i < DNS_RBTDB_EXPIRE_TTL_COUNT; i++) { 5001 1.21 christos dns_slabheader_t *header = isc_heap_element(heap, 1); 5002 1.20 christos 5003 1.20 christos if (header == NULL) { 5004 1.20 christos /* No headers left on this TTL heap; exit cleaning */ 5005 1.20 christos return; 5006 1.20 christos } 5007 1.20 christos 5008 1.21 christos dns_ttl_t ttl = header->ttl; 5009 1.20 christos 5010 1.21 christos if (!cache_is_overmem) { 5011 1.20 christos /* Only account for stale TTL if cache is not overmem */ 5012 1.20 christos ttl += STALE_TTL(header, rbtdb); 5013 1.20 christos } 5014 1.20 christos 5015 1.20 christos if (ttl >= now - RBTDB_VIRTUAL) { 5016 1.20 christos /* 5017 1.20 christos * The header at the top of this TTL heap is not yet 5018 1.20 christos * eligible for expiry, so none of the other headers on 5019 1.20 christos * the same heap can be eligible for expiry, either; 5020 1.20 christos * exit cleaning. 5021 1.20 christos */ 5022 1.20 christos return; 5023 1.20 christos } 5024 1.20 christos 5025 1.21 christos dns__cacherbt_expireheader(header, tlocktypep, 5026 1.21 christos dns_expire_ttl DNS__DB_FLARG_PASS); 5027 1.20 christos } 5028 1.20 christos } 5029 1.21 christos 5030 1.21 christos void 5031 1.21 christos dns__rbtdb_setmaxrrperset(dns_db_t *db, uint32_t value) { 5032 1.21 christos dns_rbtdb_t *rbtdb = (dns_rbtdb_t *)db; 5033 1.21 christos 5034 1.21 christos REQUIRE(VALID_RBTDB(rbtdb)); 5035 1.21 christos 5036 1.21 christos rbtdb->maxrrperset = value; 5037 1.21 christos } 5038 1.21 christos 5039 1.21 christos void 5040 1.21 christos dns__rbtdb_setmaxtypepername(dns_db_t *db, uint32_t maxtypepername) { 5041 1.21 christos dns_rbtdb_t *rbtdb = (dns_rbtdb_t *)db; 5042 1.21 christos 5043 1.21 christos REQUIRE(VALID_RBTDB(rbtdb)); 5044 1.21 christos 5045 1.21 christos rbtdb->maxtypepername = maxtypepername; 5046 1.21 christos } 5047