Home | History | Annotate | Line # | Download | only in dns
      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(&current);
    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(&current);
    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(&current);
    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(&current);
   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, &region);
   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 					    &region, 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 					    &region, 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(&current);
   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