diff --git a/lib/dns/include/dns/rdataslab.h b/lib/dns/include/dns/rdataslab.h index c5e61c3b92..a292b4acd3 100644 --- a/lib/dns/include/dns/rdataslab.h +++ b/lib/dns/include/dns/rdataslab.h @@ -64,6 +64,18 @@ struct dns_slabheader_proof { dns_rdatatype_t type; }; +typedef struct dns_slabtop dns_slabtop_t; +struct dns_slabtop { + dns_slabtop_t *next; + dns_slabheader_t *header; + dns_typepair_t typepair; + + /*% Used for SIEVE-LRU (cache) and changed_list (zone) */ + ISC_LINK(struct dns_slabtop) link; + /*% Used for SIEVE-LRU */ + bool visited; +}; + struct dns_slabheader { _Atomic(uint16_t) attributes; @@ -101,10 +113,8 @@ struct dns_slabheader { * both head and tail pointers, and is doubly linked. */ - union { - struct dns_slabheader *next; - struct dns_slabheader *up; - }; + dns_slabtop_t *top; + /*%< * If this is the top header for an rdataset, 'next' points * to the top header for the next rdataset (i.e., the next type). @@ -127,17 +137,18 @@ struct dns_slabheader { dns_gluelist_t *gluelist; - /*% Used for SIEVE-LRU (cache) and changed_list (zone) */ - ISC_LINK(struct dns_slabheader) link; - /*% Used for SIEVE-LRU */ - bool visited; - /*% * Case vector. If the bit is set then the corresponding * character in the owner name needs to be AND'd with 0x20, * rendering that character upper case. */ unsigned char upper[32]; + + /*% + * Flexible member indicates the address of the raw data + * following this header. + */ + unsigned char raw[]; }; enum { @@ -273,12 +284,6 @@ dns_rdataslab_equalx(dns_slabheader_t *header1, dns_slabheader_t *header2, *\li true if the slabs are equal, #false otherwise. */ -void * -dns_slabheader_raw(dns_slabheader_t *header); -/*% - * Returns the address of the raw memory following a dns_slabheader. - */ - void dns_slabheader_setownercase(dns_slabheader_t *header, const dns_name_t *name); /*%< @@ -295,14 +300,14 @@ void dns_slabheader_reset(dns_slabheader_t *h, dns_dbnode_t *node); /*%< * Reset an rdataslab header 'h' so it can be used to store data in - * database 'db' and node 'node'. + * database node 'node'. */ dns_slabheader_t * -dns_slabheader_new(dns_db_t *db, dns_dbnode_t *node); +dns_slabheader_new(isc_mem_t *mctx, dns_dbnode_t *node); /*%< * Allocate memory for an rdataslab header and initialize it for use - * in database 'db'/node 'node'. + * in database node 'node'. */ void @@ -317,8 +322,15 @@ dns_slabheader_freeproof(isc_mem_t *mctx, dns_slabheader_proof_t **proof); * Free all memory associated with a nonexistence proof. */ -dns_slabheader_t * -dns_slabheader_top(dns_slabheader_t *header); +dns_slabtop_t * +dns_slabtop_new(isc_mem_t *mctx, dns_typepair_t typepair); /*%< - * Return the top header for the type or the negtype + * Allocate memory for an rdataslab top and initialize it for use + * with 'typepair' type and covers pair. + */ + +void +dns_slabtop_destroy(isc_mem_t *mctx, dns_slabtop_t **topp); +/*%< + * Free all memory associated with '*slabtopp'. */ diff --git a/lib/dns/include/dns/types.h b/lib/dns/include/dns/types.h index 619f3a779a..11eab4baf7 100644 --- a/lib/dns/include/dns/types.h +++ b/lib/dns/include/dns/types.h @@ -154,23 +154,22 @@ typedef uint8_t dns_secproto_t; typedef struct dns_signature dns_signature_t; typedef struct dns_skr dns_skr_t; typedef struct dns_slabheader dns_slabheader_t; -typedef ISC_LIST(dns_slabheader_t) dns_slabheaderlist_t; -typedef struct dns_ssurule dns_ssurule_t; -typedef struct dns_ssutable dns_ssutable_t; -typedef struct dns_stats dns_stats_t; -typedef uint32_t dns_rdatastatstype_t; -typedef struct dns_tkeyctx dns_tkeyctx_t; -typedef struct dns_transport dns_transport_t; -typedef struct dns_transport_list dns_transport_list_t; -typedef uint16_t dns_trust_t; -typedef struct dns_tsigkeyring dns_tsigkeyring_t; -typedef struct dns_tsigkey dns_tsigkey_t; -typedef uint32_t dns_ttl_t; -typedef uint32_t dns_typepair_t; -typedef struct dns_unreachcache dns_unreachcache_t; -typedef struct dns_update_state dns_update_state_t; -typedef struct dns_validator dns_validator_t; -typedef struct dns_view dns_view_t; +typedef struct dns_ssurule dns_ssurule_t; +typedef struct dns_ssutable dns_ssutable_t; +typedef struct dns_stats dns_stats_t; +typedef uint32_t dns_rdatastatstype_t; +typedef struct dns_tkeyctx dns_tkeyctx_t; +typedef struct dns_transport dns_transport_t; +typedef struct dns_transport_list dns_transport_list_t; +typedef uint16_t dns_trust_t; +typedef struct dns_tsigkeyring dns_tsigkeyring_t; +typedef struct dns_tsigkey dns_tsigkey_t; +typedef uint32_t dns_ttl_t; +typedef uint32_t dns_typepair_t; +typedef struct dns_unreachcache dns_unreachcache_t; +typedef struct dns_update_state dns_update_state_t; +typedef struct dns_validator dns_validator_t; +typedef struct dns_view dns_view_t; typedef ISC_LIST(dns_view_t) dns_viewlist_t; typedef struct dns_zone dns_zone_t; typedef ISC_LIST(dns_zone_t) dns_zonelist_t; diff --git a/lib/dns/qpcache.c b/lib/dns/qpcache.c index 8a2cd03879..db285441c4 100644 --- a/lib/dns/qpcache.c +++ b/lib/dns/qpcache.c @@ -156,7 +156,8 @@ struct qpcnode { */ isc_refcount_t references; isc_refcount_t erefs; - void *data; + + dns_slabtop_t *data; /*% * NOTE: The 'dirty' flag is protected by the node lock, so @@ -200,13 +201,13 @@ typedef struct qpcache_bucket { isc_heap_t *heap; /* SIEVE-LRU cache cleaning state. */ - ISC_SIEVE(dns_slabheader_t) sieve; + ISC_SIEVE(dns_slabtop_t) sieve; /* Padding to prevent false sharing between locks. */ uint8_t __padding[ISC_OS_CACHELINE_SIZE - (sizeof(isc_queue_t) + sizeof(isc_rwlock_t) + sizeof(isc_heap_t *) + - sizeof(ISC_SIEVE(dns_slabheader_t))) % + sizeof(ISC_SIEVE(dns_slabtop_t))) % ISC_OS_CACHELINE_SIZE]; } qpcache_bucket_t; @@ -381,7 +382,7 @@ static dns_rdatasetitermethods_t rdatasetiter_methods = { typedef struct qpc_rditer { dns_rdatasetiter_t common; - dns_slabheader_t *current; + dns_slabtop_t *current; } qpc_rditer_t; static void @@ -485,13 +486,15 @@ expire_lru_headers(qpcache_t *qpdb, uint32_t idx, size_t requested, size_t expired = 0; do { - dns_slabheader_t *header = - ISC_SIEVE_NEXT(qpdb->buckets[idx].sieve, visited, link); - if (header == NULL) { + dns_slabtop_t *top = ISC_SIEVE_NEXT(qpdb->buckets[idx].sieve, + visited, link); + if (top == NULL) { return; } - ISC_SIEVE_UNLINK(qpdb->buckets[idx].sieve, header, link); + ISC_SIEVE_UNLINK(qpdb->buckets[idx].sieve, top, link); + + dns_slabheader_t *header = top->header; expired += rdataset_size(header); @@ -528,7 +531,7 @@ qpcache_miss(qpcache_t *qpdb, dns_slabheader_t *newheader, tlocktypep DNS__DB_FLARG_PASS); } - ISC_SIEVE_INSERT(qpdb->buckets[idx].sieve, newheader, link); + ISC_SIEVE_INSERT(qpdb->buckets[idx].sieve, newheader->top, link); } static void @@ -536,7 +539,7 @@ qpcache_hit(qpcache_t *qpdb ISC_ATTR_UNUSED, dns_slabheader_t *header) { /* * On cache hit, we only mark the header as seen. */ - ISC_SIEVE_MARK(header, visited); + ISC_SIEVE_MARK(header->top, visited); } /* @@ -556,30 +559,44 @@ clean_stale_headers(dns_slabheader_t *top) { static void clean_cache_node(qpcache_t *qpdb, qpcnode_t *node) { - dns_slabheader_t *current = NULL, *top_prev = NULL, *top_next = NULL; + dns_slabtop_t *top = NULL, *top_prev = NULL, *top_next = NULL; /* * Caller must be holding the node lock. */ - for (current = node->data; current != NULL; current = top_next) { - top_next = current->next; - clean_stale_headers(current); + for (top = node->data; top != NULL; top = top_next) { + top_next = top->next; + clean_stale_headers(top->header); + /* - * If current is nonexistent, ancient, or stale and + * If current header is nonexistent, ancient, or stale and * we are not keeping stale, we can clean it up. */ - if (!EXISTS(current) || ANCIENT(current) || - (STALE(current) && !KEEPSTALE(qpdb))) + if (!EXISTS(top->header) || ANCIENT(top->header) || + (STALE(top->header) && !KEEPSTALE(qpdb))) { + dns_slabheader_destroy(&top->header); + } + + /* + * If current slabtype is empty, we can also clean it up. + */ + if (top->header == NULL) { if (top_prev != NULL) { - top_prev->next = current->next; + top_prev->next = top->next; } else { - node->data = current->next; + node->data = top->next; } - dns_slabheader_destroy(¤t); + + if (ISC_LINK_LINKED(top, link)) { + ISC_SIEVE_UNLINK( + qpdb->buckets[node->locknum].sieve, top, + link); + } + dns_slabtop_destroy(((dns_db_t *)qpdb)->mctx, &top); } else { - top_prev = current; + top_prev = top; } } node->dirty = 0; @@ -1055,7 +1072,7 @@ bindrdataset(qpcache_t *qpdb, qpcnode_t *node, dns_slabheader_t *header, rdataset->slab.db = (dns_db_t *)qpdb; rdataset->slab.node = (dns_dbnode_t *)node; - rdataset->slab.raw = dns_slabheader_raw(header); + rdataset->slab.raw = header->raw; rdataset->slab.iter_pos = NULL; rdataset->slab.iter_count = 0; @@ -1134,10 +1151,8 @@ setup_delegation(qpc_search_t *search, dns_dbnode_t **nodep, } static bool -check_stale_header(dns_slabheader_t *header, qpc_search_t *search, - dns_slabheader_t **header_prev) { +check_stale_header(dns_slabheader_t *header, qpc_search_t *search) { if (ACTIVE(header, search->now)) { - *header_prev = header; return false; } @@ -1153,7 +1168,6 @@ check_stale_header(dns_slabheader_t *header, qpc_search_t *search, if (!ZEROTTL(header) && KEEPSTALE(search->qpdb) && stale > search->now) { mark(header, DNS_SLABHEADERATTR_STALE); - *header_prev = header; /* * If DNS_DBFIND_STALESTART is set then it means we * failed to resolve the name during recursion, in @@ -1188,7 +1202,6 @@ check_stale_header(dns_slabheader_t *header, qpc_search_t *search, return (search->options & DNS_DBFIND_STALEOK) == 0; } - *header_prev = header; return true; } @@ -1262,8 +1275,7 @@ both_headers(dns_slabheader_t *header, dns_rdatatype_t type, static isc_result_t check_zonecut(qpcnode_t *node, void *arg DNS__DB_FLARG) { qpc_search_t *search = arg; - dns_slabheader_t *header = NULL; - dns_slabheader_t *header_prev = NULL, *header_next = NULL; + dns_slabtop_t *top = NULL; dns_slabheader_t *found = NULL, *foundsig = NULL; isc_result_t result; isc_rwlock_t *nlock = NULL; @@ -1277,13 +1289,12 @@ check_zonecut(qpcnode_t *node, void *arg DNS__DB_FLARG) { /* * Look for a DNAME or RRSIG DNAME rdataset. */ - for (header = node->data; header != NULL; header = header_next) { - header_next = header->next; - if (check_stale_header(header, search, &header_prev)) { + for (top = node->data; top != NULL; top = top->next) { + if (check_stale_header(top->header, search)) { continue; } - if (both_headers(header, dns_rdatatype_dname, &found, + if (both_headers(top->header, dns_rdatatype_dname, &found, &foundsig)) { break; @@ -1328,8 +1339,7 @@ find_deepest_zonecut(qpc_search_t *search, qpcnode_t *node, qpdb = search->qpdb; for (int i = dns_qpchain_length(&search->chain) - 1; i >= 0; i--) { - dns_slabheader_t *header = NULL; - dns_slabheader_t *header_prev = NULL, *header_next = NULL; + dns_slabtop_t *top = NULL; dns_slabheader_t *found = NULL, *foundsig = NULL; isc_rwlock_t *nlock = NULL; isc_rwlocktype_t nlocktype = isc_rwlocktype_none; @@ -1342,14 +1352,12 @@ find_deepest_zonecut(qpc_search_t *search, qpcnode_t *node, /* * Look for NS and RRSIG NS rdatasets. */ - for (header = node->data; header != NULL; header = header_next) - { - header_next = header->next; - if (check_stale_header(header, search, &header_prev)) { + for (top = node->data; top != NULL; top = top->next) { + if (check_stale_header(top->header, search)) { continue; } - if (both_headers(header, dns_rdatatype_ns, &found, + if (both_headers(top->header, dns_rdatatype_ns, &found, &foundsig)) { break; @@ -1407,8 +1415,7 @@ find_coveringnsec(qpc_search_t *search, const dns_name_t *name, isc_rwlocktype_t nlocktype = isc_rwlocktype_none; isc_rwlock_t *nlock = NULL; dns_slabheader_t *found = NULL, *foundsig = NULL; - dns_slabheader_t *header = NULL; - dns_slabheader_t *header_next = NULL, *header_prev = NULL; + dns_slabtop_t *top = NULL; /* * Look for the node in the auxilary tree. @@ -1449,13 +1456,13 @@ find_coveringnsec(qpc_search_t *search, const dns_name_t *name, nlock = &search->qpdb->buckets[node->locknum].lock; NODE_RDLOCK(nlock, &nlocktype); - for (header = node->data; header != NULL; header = header_next) { - header_next = header->next; - if (check_stale_header(header, search, &header_prev)) { + for (top = node->data; top != NULL; top = top->next) { + if (check_stale_header(top->header, search)) { continue; } - if (both_headers(header, dns_rdatatype_nsec, &found, &foundsig)) + if (both_headers(top->header, dns_rdatatype_nsec, &found, + &foundsig)) { break; } @@ -1527,8 +1534,7 @@ qpcache_find(dns_db_t *db, const dns_name_t *name, dns_dbversion_t *version, isc_rwlock_t *nlock = NULL; isc_rwlocktype_t tlocktype = isc_rwlocktype_none; isc_rwlocktype_t nlocktype = isc_rwlocktype_none; - dns_slabheader_t *header = NULL; - dns_slabheader_t *header_prev = NULL, *header_next = NULL; + dns_slabtop_t *top = NULL; dns_slabheader_t *found = NULL, *nsheader = NULL; dns_slabheader_t *foundsig = NULL, *nssig = NULL, *cnamesig = NULL; dns_slabheader_t *nsecheader = NULL, *nsecsig = NULL; @@ -1647,14 +1653,12 @@ qpcache_find(dns_db_t *db, const dns_name_t *name, dns_dbversion_t *version, nsecsig = NULL; cnamesig = NULL; empty_node = true; - header_prev = NULL; - for (header = node->data; header != NULL; header = header_next) { - header_next = header->next; - if (check_stale_header(header, &search, &header_prev)) { + for (top = node->data; top != NULL; top = top->next) { + if (check_stale_header(top->header, &search)) { continue; } - if (!EXISTS(header) || ANCIENT(header)) { + if (!EXISTS(top->header) || ANCIENT(top->header)) { continue; } @@ -1664,18 +1668,18 @@ qpcache_find(dns_db_t *db, const dns_name_t *name, dns_dbversion_t *version, */ empty_node = false; - if (header->noqname != NULL && - header->trust == dns_trust_secure) + if (top->header->noqname != NULL && + top->header->trust == dns_trust_secure) { found_noqname = true; } - if (!NEGATIVE(header)) { + if (!NEGATIVE(top->header)) { all_negative = false; } bool match = false; - if (related_headers(header, typepair, sigpair, &found, + if (related_headers(top->header, typepair, sigpair, &found, &foundsig, &match) && !MISSING_ANSWER(found, options)) { @@ -1694,7 +1698,7 @@ qpcache_find(dns_db_t *db, const dns_name_t *name, dns_dbversion_t *version, continue; } - if (NEGATIVE(header)) { + if (NEGATIVE(top->header)) { /* * FIXME: As of now, we are not interested in * the negative headers. This could be @@ -1706,13 +1710,13 @@ qpcache_find(dns_db_t *db, const dns_name_t *name, dns_dbversion_t *version, continue; } - switch (header->typepair) { + switch (top->typepair) { case dns_rdatatype_cname: if (!cname_ok) { break; } - found = header; + found = top->header; if (cnamesig != NULL) { /* We already have CNAME signature */ foundsig = cnamesig; @@ -1727,28 +1731,28 @@ qpcache_find(dns_db_t *db, const dns_name_t *name, dns_dbversion_t *version, break; } - cnamesig = header; + cnamesig = top->header; break; case dns_rdatatype_ns: /* Remember the NS rdataset */ - nsheader = header; + nsheader = top->header; break; case DNS_SIGTYPEPAIR(dns_rdatatype_ns): /* ...and its signature */ - nssig = header; + nssig = top->header; break; case dns_rdatatype_nsec: - nsecheader = header; + nsecheader = top->header; break; case DNS_SIGTYPEPAIR(dns_rdatatype_nsec): - nsecsig = header; + nsecsig = top->header; break; default: if (typepair == dns_typepair_any) { /* QTYPE==ANY, so any anwers will do */ - found = header; + found = top->header; break; } } @@ -1909,19 +1913,17 @@ seek_ns_headers(qpc_search_t *search, qpcnode_t *node, dns_dbnode_t **nodep, dns_rdataset_t *rdataset, dns_rdataset_t *sigrdataset, dns_name_t *foundname, dns_name_t *dcname, isc_rwlocktype_t *tlocktype) { - dns_slabheader_t *header = NULL; - dns_slabheader_t *header_prev = NULL, *header_next = NULL; + dns_slabtop_t *top = NULL; isc_rwlocktype_t nlocktype = isc_rwlocktype_none; isc_rwlock_t *nlock = &search->qpdb->buckets[node->locknum].lock; dns_slabheader_t *found = NULL, *foundsig = NULL; NODE_RDLOCK(nlock, &nlocktype); - for (header = node->data; header != NULL; header = header_next) { - header_next = header->next; - bool ns = header->typepair == DNS_TYPEPAIR(dns_rdatatype_ns) || - header->typepair == DNS_SIGTYPEPAIR(dns_rdatatype_ns); - if (check_stale_header(header, search, &header_prev)) { + for (top = node->data; top != NULL; top = top->next) { + bool ns = top->typepair == DNS_TYPEPAIR(dns_rdatatype_ns) || + top->typepair == DNS_SIGTYPEPAIR(dns_rdatatype_ns); + if (check_stale_header(top->header, search)) { if (ns) { /* * We found a cached NS, but was either @@ -1936,7 +1938,9 @@ seek_ns_headers(qpc_search_t *search, qpcnode_t *node, dns_dbnode_t **nodep, continue; } - if (both_headers(header, dns_rdatatype_ns, &found, &foundsig)) { + if (both_headers(top->header, dns_rdatatype_ns, &found, + &foundsig)) + { break; } } @@ -2060,8 +2064,7 @@ qpcache_findrdataset(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version, dns_rdataset_t *sigrdataset DNS__DB_FLARG) { qpcache_t *qpdb = (qpcache_t *)db; qpcnode_t *qpnode = (qpcnode_t *)node; - dns_slabheader_t *header = NULL; - dns_slabheader_t *header_prev = NULL, *header_next = NULL; + dns_slabtop_t *top = NULL; dns_slabheader_t *found = NULL, *foundsig = NULL; dns_typepair_t typepair, sigpair; isc_result_t result = ISC_R_SUCCESS; @@ -2091,14 +2094,12 @@ qpcache_findrdataset(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version, sigpair = !dns_rdatatype_issig(type) ? DNS_SIGTYPEPAIR(type) : dns_typepair_none; - for (header = qpnode->data; header != NULL; header = header_next) { - header_next = header->next; - - if (check_stale_header(header, &search, &header_prev)) { + for (top = qpnode->data; top != NULL; top = top->next) { + if (check_stale_header(top->header, &search)) { continue; } - if (related_headers(header, typepair, sigpair, &found, + if (related_headers(top->header, typepair, sigpair, &found, &foundsig, NULL)) { break; @@ -2487,8 +2488,8 @@ overmaxtype(qpcache_t *qpdb, uint32_t ntypes) { } static bool -prio_header(dns_slabheader_t *header) { - return prio_type(header->typepair); +prio_header(dns_slabtop_t *top) { + return prio_type(top->typepair); } static void @@ -2538,13 +2539,12 @@ qpcnode_detachnode(dns_dbnode_t **nodep DNS__DB_FLARG) { } static isc_result_t -add(qpcache_t *qpdb, qpcnode_t *qpnode, - const dns_name_t *nodename ISC_ATTR_UNUSED, dns_slabheader_t *newheader, +add(qpcache_t *qpdb, qpcnode_t *qpnode, dns_slabheader_t *newheader, unsigned int options, dns_rdataset_t *addedrdataset, isc_stdtime_t now, isc_rwlocktype_t nlocktype, isc_rwlocktype_t tlocktype DNS__DB_FLARG) { - dns_slabheader_t *topheader = NULL, *topheader_prev = NULL; + dns_slabtop_t *top = NULL; + dns_slabtop_t *priotop = NULL, *expiretop = NULL; dns_slabheader_t *header = NULL, *sigheader = NULL; - dns_slabheader_t *prioheader = NULL, *expireheader = NULL; dns_trust_t trust; uint32_t ntypes = 0; dns_rdatatype_t rdtype = DNS_TYPEPAIR_TYPE(newheader->typepair); @@ -2586,11 +2586,10 @@ add(qpcache_t *qpdb, qpcnode_t *qpnode, * only rdataset that can be found at this * node is the negative cache entry. */ - for (topheader = qpnode->data; - topheader != NULL; - topheader = topheader->next) + for (top = qpnode->data; top != NULL; + top = top->next) { - mark_ancient(topheader); + mark_ancient(top->header); } goto find_header; } @@ -2598,11 +2597,9 @@ add(qpcache_t *qpdb, qpcnode_t *qpnode, * Otherwise look for any RRSIGs of the given * type so they can be marked ancient later. */ - for (topheader = qpnode->data; topheader != NULL; - topheader = topheader->next) - { - if (topheader->typepair == sigpair) { - sigheader = topheader; + for (top = qpnode->data; top != NULL; top = top->next) { + if (top->typepair == sigpair) { + sigheader = top->header; break; } } @@ -2611,14 +2608,12 @@ add(qpcache_t *qpdb, qpcnode_t *qpnode, * We're adding something that isn't a * negative cache entry. */ - for (topheader = qpnode->data; topheader != NULL; - topheader = topheader->next) - { + for (top = qpnode->data; top != NULL; top = top->next) { /* * Look for any existing negative cache * entries. */ - if (!NEGATIVE(topheader)) { + if (!NEGATIVE(top->header)) { continue; } @@ -2626,7 +2621,7 @@ add(qpcache_t *qpdb, qpcnode_t *qpnode, * If we find a cached NXDOMAIN, don't * cache anything else. */ - if (topheader->typepair == dns_typepair_any) { + if (top->typepair == dns_typepair_any) { break; } @@ -2635,28 +2630,27 @@ add(qpcache_t *qpdb, qpcnode_t *qpnode, * for which we have a cached NODATA record. */ if (newheader->typepair == sigpair && - DNS_TYPEPAIR_TYPE(topheader->typepair) == - covers) + DNS_TYPEPAIR_TYPE(top->typepair) == covers) { break; } } - if (topheader != NULL && EXISTS(topheader) && - ACTIVE(topheader, now)) + if (top != NULL && EXISTS(top->header) && + ACTIVE(top->header, now)) { /* * Found one. */ - if (trust < topheader->trust) { + if (trust < top->header->trust) { /* * The NXDOMAIN/NODATA(QTYPE=ANY) * is more trusted. */ if (addedrdataset != NULL) { bindrdataset( - qpdb, qpnode, topheader, - now, nlocktype, - tlocktype, + qpdb, qpnode, + top->header, now, + nlocktype, tlocktype, addedrdataset DNS__DB_FLARG_PASS); } @@ -2666,36 +2660,33 @@ add(qpcache_t *qpdb, qpcnode_t *qpnode, * The new rdataset is better. Expire the * ncache entry. */ - mark_ancient(topheader); - topheader = NULL; + mark_ancient(top->header); + top = NULL; goto find_header; } } } - for (topheader = qpnode->data; topheader != NULL; - topheader = topheader->next) - { - if (ACTIVE(topheader, now)) { + for (top = qpnode->data; top != NULL; top = top->next) { + if (ACTIVE(top->header, now)) { ++ntypes; - expireheader = topheader; + expiretop = top; } - if (prio_header(topheader)) { - prioheader = topheader; + if (prio_header(top)) { + priotop = top; } - if (topheader->typepair == newheader->typepair) { + if (top->typepair == newheader->typepair) { break; } - topheader_prev = topheader; } find_header: /* - * If header isn't NULL, we've found the right type. + * If top isn't NULL, we've found the right type. */ - header = topheader; - if (header != NULL) { + if (top != NULL) { + header = top->header; /* * Deleting an already non-existent rdataset has no effect. */ @@ -2730,12 +2721,12 @@ find_header: * normally further down. */ if (ACTIVE(header, now) && - header->typepair == DNS_TYPEPAIR(dns_rdatatype_ns) && + top->typepair == DNS_TYPEPAIR(dns_rdatatype_ns) && EXISTS(header) && EXISTS(newheader) && header->trust >= newheader->trust && dns_rdataslab_equalx(header, newheader, qpdb->common.rdclass, - DNS_TYPEPAIR_TYPE(header->typepair))) + DNS_TYPEPAIR_TYPE(top->typepair))) { /* * Honour the new ttl if it is less than the @@ -2773,7 +2764,7 @@ find_header: * ensures the delegations that are withdrawn are honoured. */ if (ACTIVE(header, now) && - header->typepair == DNS_TYPEPAIR(dns_rdatatype_ns) && + top->typepair == DNS_TYPEPAIR(dns_rdatatype_ns) && EXISTS(header) && EXISTS(newheader) && header->trust <= newheader->trust) { @@ -2783,10 +2774,10 @@ find_header: } if (ACTIVE(header, now) && (options & DNS_DBADD_PREFETCH) == 0 && - (header->typepair == DNS_TYPEPAIR(dns_rdatatype_a) || - header->typepair == DNS_TYPEPAIR(dns_rdatatype_aaaa) || - header->typepair == DNS_TYPEPAIR(dns_rdatatype_ds) || - header->typepair == DNS_SIGTYPEPAIR(dns_rdatatype_ds)) && + (top->typepair == DNS_TYPEPAIR(dns_rdatatype_a) || + top->typepair == DNS_TYPEPAIR(dns_rdatatype_aaaa) || + top->typepair == DNS_TYPEPAIR(dns_rdatatype_ds) || + top->typepair == DNS_SIGTYPEPAIR(dns_rdatatype_ds)) && EXISTS(header) && EXISTS(newheader) && header->trust >= newheader->trust && dns_rdataslab_equal(header, newheader)) @@ -2821,17 +2812,16 @@ find_header: return DNS_R_UNCHANGED; } + top->header = newheader; + newheader->top = top; + newheader->down = header; + + ISC_SIEVE_UNLINK(qpdb->buckets[qpnode->locknum].sieve, top, + link); + qpcache_miss(qpdb, newheader, &nlocktype, &tlocktype DNS__DB_FLARG_PASS); - if (topheader_prev != NULL) { - topheader_prev->next = newheader; - } else { - qpnode->data = newheader; - } - newheader->next = topheader->next; - newheader->down = topheader; - topheader->next = newheader; mark_ancient(header); if (sigheader != NULL) { mark_ancient(sigheader); @@ -2846,36 +2836,42 @@ find_header: /* No rdatasets of the given type exist at the node. */ INSIST(newheader->down == NULL); + dns_slabtop_t *newtop = dns_slabtop_new( + ((dns_db_t *)qpdb)->mctx, newheader->typepair); + newtop->header = newheader; + newheader->top = newtop; + qpcache_miss(qpdb, newheader, &nlocktype, &tlocktype DNS__DB_FLARG_PASS); - if (prio_header(newheader)) { + + if (prio_header(newtop)) { /* This is a priority type, prepend it */ - newheader->next = qpnode->data; - qpnode->data = newheader; - } else if (prioheader != NULL) { + newtop->next = qpnode->data; + qpnode->data = newtop; + } else if (priotop != NULL) { /* Append after the priority headers */ - newheader->next = prioheader->next; - prioheader->next = newheader; + newtop->next = priotop->next; + priotop->next = newtop; } else { /* There were no priority headers */ - newheader->next = qpnode->data; - qpnode->data = newheader; + newtop->next = qpnode->data; + qpnode->data = newtop; } if (overmaxtype(qpdb, ntypes)) { - if (expireheader == NULL) { - expireheader = newheader; + if (expiretop == NULL) { + expiretop = newtop; } - if (NEGATIVE(newheader) && !prio_header(newheader)) { + if (NEGATIVE(newheader) && !prio_header(newtop)) { /* * Add the new non-priority negative * header to the database only * temporarily. */ - expireheader = newheader; + expiretop = newtop; } - mark_ancient(expireheader); + mark_ancient(expiretop->header); /* * FIXME: In theory, we should mark the RRSIG * and the header at the same time, but there is @@ -2917,8 +2913,8 @@ addnoqname(isc_mem_t *mctx, dns_slabheader_t *newheader, uint32_t maxrrperset, noqname = isc_mem_get(mctx, sizeof(*noqname)); *noqname = (dns_slabheader_proof_t){ - .neg = dns_slabheader_raw((dns_slabheader_t *)r1.base), - .negsig = dns_slabheader_raw((dns_slabheader_t *)r2.base), + .neg = ((dns_slabheader_t *)r1.base)->raw, + .negsig = ((dns_slabheader_t *)r2.base)->raw, .type = neg.type, .name = DNS_NAME_INITEMPTY, }; @@ -2956,8 +2952,8 @@ addclosest(isc_mem_t *mctx, dns_slabheader_t *newheader, uint32_t maxrrperset, closest = isc_mem_get(mctx, sizeof(*closest)); *closest = (dns_slabheader_proof_t){ - .neg = dns_slabheader_raw((dns_slabheader_t *)r1.base), - .negsig = dns_slabheader_raw((dns_slabheader_t *)r2.base), + .neg = ((dns_slabheader_t *)r1.base)->raw, + .negsig = ((dns_slabheader_t *)r2.base)->raw, .name = DNS_NAME_INITEMPTY, .type = neg.type, }; @@ -3105,7 +3101,7 @@ qpcache_addrdataset(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version, qpnode->havensec = true; } - result = add(qpdb, qpnode, name, newheader, options, addedrdataset, now, + result = add(qpdb, qpnode, newheader, options, addedrdataset, now, nlocktype, tlocktype DNS__DB_FLARG_PASS); if (result == ISC_R_SUCCESS) { @@ -3163,14 +3159,14 @@ qpcache_deleterdataset(dns_db_t *db, dns_dbnode_t *node, return ISC_R_NOTIMPLEMENTED; } - newheader = dns_slabheader_new(db, node); + newheader = dns_slabheader_new(db->mctx, node); newheader->typepair = DNS_TYPEPAIR_VALUE(type, covers); setttl(newheader, 0); atomic_init(&newheader->attributes, attributes); nlock = &qpdb->buckets[qpnode->locknum].lock; NODE_WRLOCK(nlock, &nlocktype); - result = add(qpdb, qpnode, NULL, newheader, DNS_DBADD_FORCE, NULL, 0, + result = add(qpdb, qpnode, newheader, DNS_DBADD_FORCE, NULL, 0, nlocktype, isc_rwlocktype_none DNS__DB_FLARG_PASS); if (result != ISC_R_SUCCESS) { dns_slabheader_destroy(&newheader); @@ -3320,13 +3316,6 @@ iterator_active(qpcache_t *qpdb, qpc_rditer_t *iterator, dns_slabheader_t *header) { dns_ttl_t stale_ttl = header->expire + STALE_TTL(header, qpdb); - /* - * Is this a "this rdataset doesn't exist" record? - */ - if (!EXISTS(header)) { - return false; - } - /* * If this header is still active then return it. */ @@ -3349,15 +3338,16 @@ rdatasetiter_first(dns_rdatasetiter_t *it DNS__DB_FLARG) { qpc_rditer_t *iterator = (qpc_rditer_t *)it; qpcache_t *qpdb = (qpcache_t *)(iterator->common.db); qpcnode_t *qpnode = (qpcnode_t *)iterator->common.node; - dns_slabheader_t *header = NULL; + dns_slabtop_t *top = NULL; isc_rwlocktype_t nlocktype = isc_rwlocktype_none; isc_rwlock_t *nlock = &qpdb->buckets[qpnode->locknum].lock; NODE_RDLOCK(nlock, &nlocktype); - for (header = qpnode->data; header != NULL; header = header->next) { - if ((EXPIREDOK(iterator) && EXISTS(header)) || - iterator_active(qpdb, iterator, header)) + for (top = qpnode->data; top != NULL; top = top->next) { + if (EXISTS(top->header) && + (EXPIREDOK(iterator) || + iterator_active(qpdb, iterator, top->header))) { break; } @@ -3365,9 +3355,9 @@ rdatasetiter_first(dns_rdatasetiter_t *it DNS__DB_FLARG) { NODE_UNLOCK(nlock, &nlocktype); - iterator->current = header; + iterator->current = top; - if (header == NULL) { + if (top == NULL) { return ISC_R_NOMORE; } @@ -3379,20 +3369,21 @@ rdatasetiter_next(dns_rdatasetiter_t *it DNS__DB_FLARG) { qpc_rditer_t *iterator = (qpc_rditer_t *)it; qpcache_t *qpdb = (qpcache_t *)(iterator->common.db); qpcnode_t *qpnode = (qpcnode_t *)iterator->common.node; - dns_slabheader_t *header = NULL; + dns_slabtop_t *top = NULL; isc_rwlocktype_t nlocktype = isc_rwlocktype_none; isc_rwlock_t *nlock = &qpdb->buckets[qpnode->locknum].lock; - header = iterator->current; - if (header == NULL) { + top = iterator->current; + if (top == NULL) { return ISC_R_NOMORE; } NODE_RDLOCK(nlock, &nlocktype); - for (header = header->next; header != NULL; header = header->next) { - if ((EXPIREDOK(iterator) && EXISTS(header)) || - iterator_active(qpdb, iterator, header)) + for (top = top->next; top != NULL; top = top->next) { + if (EXISTS(top->header) && + (EXPIREDOK(iterator) || + iterator_active(qpdb, iterator, top->header))) { break; } @@ -3400,9 +3391,9 @@ rdatasetiter_next(dns_rdatasetiter_t *it DNS__DB_FLARG) { NODE_UNLOCK(nlock, &nlocktype); - iterator->current = header; + iterator->current = top; - if (header == NULL) { + if (top == NULL) { return ISC_R_NOMORE; } @@ -3415,16 +3406,16 @@ rdatasetiter_current(dns_rdatasetiter_t *it, qpc_rditer_t *iterator = (qpc_rditer_t *)it; qpcache_t *qpdb = (qpcache_t *)(iterator->common.db); qpcnode_t *qpnode = (qpcnode_t *)iterator->common.node; - dns_slabheader_t *header = NULL; + dns_slabtop_t *top = NULL; isc_rwlocktype_t nlocktype = isc_rwlocktype_none; isc_rwlock_t *nlock = &qpdb->buckets[qpnode->locknum].lock; - header = iterator->current; - REQUIRE(header != NULL); + top = iterator->current; + REQUIRE(top != NULL); NODE_RDLOCK(nlock, &nlocktype); - bindrdataset(qpdb, qpnode, header, iterator->common.now, nlocktype, + bindrdataset(qpdb, qpnode, top->header, iterator->common.now, nlocktype, isc_rwlocktype_none, rdataset DNS__DB_FLARG_PASS); NODE_UNLOCK(nlock, &nlocktype); @@ -3771,19 +3762,16 @@ qpcnode_deletedata(dns_dbnode_t *node ISC_ATTR_UNUSED, void *data) { dns_slabheader_t *header = data; qpcache_t *qpdb = HEADERNODE(header)->qpdb; - int idx = HEADERNODE(header)->locknum; - if (header->heap != NULL && header->heap_index != 0) { isc_heap_delete(header->heap, header->heap_index); } + /* + * This place is the only place where we actually need header->typepair. + */ update_rrsetstats(qpdb->rrsetstats, header->typepair, atomic_load_acquire(&header->attributes), false); - if (ISC_LINK_LINKED(header, link)) { - ISC_SIEVE_UNLINK(qpdb->buckets[idx].sieve, header, link); - } - if (header->noqname != NULL) { dns_slabheader_freeproof(qpdb->common.mctx, &header->noqname); } @@ -3866,24 +3854,29 @@ static dns_dbmethods_t qpdb_cachemethods = { }; static void -qpcnode_destroy(qpcnode_t *data) { - dns_slabheader_t *current = NULL, *next = NULL; +qpcnode_destroy(qpcnode_t *qpnode) { + dns_slabtop_t *top = NULL, *top_next = NULL; + qpcache_t *qpdb = qpnode->qpdb; - for (current = data->data; current != NULL; current = next) { - dns_slabheader_t *down = current->down, *down_next = NULL; + for (top = qpnode->data; top != NULL; top = top_next) { + top_next = top->next; - next = current->next; - - for (down = current->down; down != NULL; down = down_next) { + dns_slabheader_t *down = NULL, *down_next = NULL; + for (down = top->header; down != NULL; down = down_next) { down_next = down->down; dns_slabheader_destroy(&down); } + top->header = NULL; - dns_slabheader_destroy(¤t); + if (ISC_LINK_LINKED(top, link)) { + ISC_SIEVE_UNLINK(qpdb->buckets[qpnode->locknum].sieve, + top, link); + } + dns_slabtop_destroy(((dns_db_t *)qpdb)->mctx, &top); } - dns_name_free(&data->name, data->mctx); - isc_mem_putanddetach(&data->mctx, data, sizeof(qpcnode_t)); + dns_name_free(&qpnode->name, qpnode->mctx); + isc_mem_putanddetach(&qpnode->mctx, qpnode, sizeof(qpcnode_t)); } #ifdef DNS_DB_NODETRACE diff --git a/lib/dns/qpzone.c b/lib/dns/qpzone.c index 76eb96c9d5..16f67d3ded 100644 --- a/lib/dns/qpzone.c +++ b/lib/dns/qpzone.c @@ -113,6 +113,13 @@ typedef struct qpz_changed { typedef ISC_LIST(qpz_changed_t) qpz_changedlist_t; +typedef struct qpz_resigned { + dns_slabheader_t *header; + ISC_LINK(struct qpz_resigned) link; +} qpz_resigned_t; + +typedef ISC_LIST(qpz_resigned_t) qpz_resignedlist_t; + typedef struct qpz_version qpz_version_t; struct qpz_version { /* Not locked */ @@ -122,7 +129,7 @@ struct qpz_version { /* Locked by database lock. */ bool writer; qpz_changedlist_t changed_list; - dns_slabheaderlist_t resigned_list; + qpz_resignedlist_t resigned_list; ISC_LINK(qpz_version_t) link; bool secure; bool havensec3; @@ -191,7 +198,7 @@ struct qpznode { atomic_bool wild; atomic_bool delegating; atomic_bool dirty; - void *data; + dns_slabtop_t *data; }; struct qpzonedb { @@ -327,6 +334,7 @@ static dns_rdatasetitermethods_t rdatasetiter_methods = { typedef struct qpdb_rdatasetiter { dns_rdatasetiter_t common; + dns_slabtop_t *currenttop; dns_slabheader_t *current; } qpdb_rdatasetiter_t; @@ -825,26 +833,30 @@ qpznode_acquire(qpzonedb_t *qpdb, qpznode_t *node DNS__DB_FLARG) { static void clean_zone_node(qpznode_t *node, uint32_t least_serial) { - dns_slabheader_t *current = NULL, *dcurrent = NULL; - dns_slabheader_t *dcurrent_down = NULL, *dparent = NULL; - dns_slabheader_t *top_prev = NULL, *top_next = NULL; + dns_slabtop_t *top = NULL, *top_prev = NULL, *top_next = NULL; bool still_dirty = false; + dns_db_t *db = (dns_db_t *)node->qpdb; /* * Caller must be holding the node lock. */ REQUIRE(least_serial != 0); - for (current = node->data; current != NULL; current = top_next) { - top_next = current->next; + for (top = node->data; top != NULL; top = top_next) { + top_next = top->next; + + INSIST(top->header != NULL); /* * First, we clean up any instances of multiple rdatasets * with the same serial number, or that have the IGNORE * attribute. */ - dparent = current; - for (dcurrent = current->down; dcurrent != NULL; + dns_slabheader_t *dcurrent = NULL; + dns_slabheader_t *dcurrent_down = NULL, *dparent = NULL; + + dparent = top->header; + for (dcurrent = dparent->down; dcurrent != NULL; dcurrent = dcurrent_down) { dcurrent_down = dcurrent->down; @@ -852,9 +864,6 @@ clean_zone_node(qpznode_t *node, uint32_t least_serial) { if (dcurrent->serial == dparent->serial || IGNORE(dcurrent)) { - if (dcurrent_down != NULL) { - dcurrent_down->up = dparent; - } dparent->down = dcurrent_down; dns_slabheader_destroy(&dcurrent); } else { @@ -866,75 +875,51 @@ clean_zone_node(qpznode_t *node, uint32_t least_serial) { * We've now eliminated all IGNORE datasets with the possible * exception of current, which we now check. */ - dcurrent = current; + dcurrent = top->header; if (IGNORE(dcurrent)) { - dcurrent_down = current->down; - if (dcurrent_down == NULL) { - if (top_prev != NULL) { - top_prev->next = current->next; - } else { - node->data = current->next; - } - dns_slabheader_destroy(¤t); - /* - * current no longer exists, so we can - * just continue with the loop. - */ - continue; - } else { - /* - * Pull up current->down, making it the new - * current. - */ - if (top_prev != NULL) { - top_prev->next = dcurrent_down; - } else { - node->data = dcurrent_down; - } - dcurrent_down->next = top_next; - dns_slabheader_destroy(¤t); - current = dcurrent_down; - } + top->header = dcurrent->down; + dns_slabheader_destroy(&dcurrent); + } + + if (top->header == NULL) { + goto empty; } /* - * We now try to find the first down node less than the - * least serial. + * We now try to find the first down node less than the least + * serial, and if there are such rdatasets, delete it and any + * older versions. */ - dparent = current; - for (dcurrent = current->down; dcurrent != NULL; + dparent = top->header; + for (dcurrent = dparent->down; dcurrent != NULL; dcurrent = dcurrent_down) { dcurrent_down = dcurrent->down; if (dcurrent->serial < least_serial) { - break; - } - dparent = dcurrent; - } - - /* - * If there is a such an rdataset, delete it and any older - * versions. - */ - if (dcurrent != NULL) { - do { - dcurrent_down = dcurrent->down; - INSIST(dcurrent->serial <= least_serial); + dparent->down = dcurrent_down; dns_slabheader_destroy(&dcurrent); - dcurrent = dcurrent_down; - } while (dcurrent != NULL); - dparent->down = NULL; + } else { + dparent = dcurrent; + } } - /* - * Note. The serial number of 'current' might be less than - * least_serial too, but we cannot delete it because it is - * the most recent version. - */ - if (current->down != NULL) { + if (top->header == NULL) { + empty: + if (top_prev != NULL) { + top_prev->next = top->next; + } else { + node->data = top->next; + } + dns_slabtop_destroy(db->mctx, &top); + } else { + /* + * Note. The serial number of 'current' might be less + * than least_serial too, but we cannot delete it + * because it is the most recent version. + */ still_dirty = true; + top_prev = top; } - top_prev = current; } if (!still_dirty) { node->dirty = false; @@ -1057,7 +1042,7 @@ bindrdataset(qpzonedb_t *qpdb, qpznode_t *node, dns_slabheader_t *header, rdataset->slab.db = (dns_db_t *)qpdb; rdataset->slab.node = (dns_dbnode_t *)node; - rdataset->slab.raw = dns_slabheader_raw(header); + rdataset->slab.raw = header->raw; rdataset->slab.iter_pos = NULL; rdataset->slab.iter_count = 0; @@ -1088,82 +1073,80 @@ static void setnsec3parameters(dns_db_t *db, qpz_version_t *version) { qpznode_t *node = NULL; dns_rdata_nsec3param_t nsec3param; - dns_rdata_t rdata = DNS_RDATA_INIT; isc_region_t region; isc_result_t result; - dns_slabheader_t *header = NULL, *header_next = NULL; + dns_slabtop_t *top = NULL; unsigned char *raw; /* RDATASLAB */ unsigned int count, length; qpzonedb_t *qpdb = (qpzonedb_t *)db; isc_rwlocktype_t nlocktype = isc_rwlocktype_none; isc_rwlock_t *nlock = NULL; + dns_slabheader_t *found = NULL; version->havensec3 = false; node = qpdb->origin; nlock = qpzone_get_lock(node); + NODE_RDLOCK(nlock, &nlocktype); - for (header = node->data; header != NULL; header = header_next) { - header_next = header->next; - do { - if (header->serial <= version->serial && - !IGNORE(header)) - { - if (!EXISTS(header)) { - header = NULL; - } - break; - } else { - header = header->down; - } - } while (header != NULL); - if (header != NULL && - (header->typepair == dns_rdatatype_nsec3param)) + top = node->data; + while (top != NULL && top->typepair != dns_rdatatype_nsec3param) { + top = top->next; + } + if (top != NULL) { + dns_slabheader_t *header = top->header; + while (header != NULL && + (IGNORE(header) || header->serial > version->serial)) { + header = header->down; + } + + if (header != NULL && EXISTS(header)) { + found = header; + } + } + + if (found != NULL) { + /* + * Find an NSEC3PARAM with a supported algorithm. + */ + raw = found->raw; + count = get_uint16(raw); + while (count-- > 0U) { + dns_rdata_t rdata = DNS_RDATA_INIT; + + length = get_uint16(raw); + region.base = raw; + region.length = length; + raw += length; + dns_rdata_fromregion(&rdata, qpdb->common.rdclass, + dns_rdatatype_nsec3param, ®ion); + result = dns_rdata_tostruct(&rdata, &nsec3param, NULL); + INSIST(result == ISC_R_SUCCESS); + + if (nsec3param.hash != DNS_NSEC3_UNKNOWNALG && + !dns_nsec3_supportedhash(nsec3param.hash)) + { + continue; + } + + if (nsec3param.flags != 0) { + continue; + } + + memmove(version->salt, nsec3param.salt, + nsec3param.salt_length); + version->hash = nsec3param.hash; + version->salt_length = nsec3param.salt_length; + version->iterations = nsec3param.iterations; + version->flags = nsec3param.flags; + version->havensec3 = true; /* - * Find an NSEC3PARAM with a supported algorithm. + * Look for a better algorithm than the + * unknown test algorithm. */ - raw = dns_slabheader_raw(header); - count = raw[0] * 256 + raw[1]; /* count */ - raw += DNS_RDATASET_LENGTH; - while (count-- > 0U) { - length = raw[0] * 256 + raw[1]; - raw += DNS_RDATASET_LENGTH; - region.base = raw; - region.length = length; - raw += length; - dns_rdata_fromregion( - &rdata, qpdb->common.rdclass, - dns_rdatatype_nsec3param, ®ion); - result = dns_rdata_tostruct(&rdata, &nsec3param, - NULL); - INSIST(result == ISC_R_SUCCESS); - dns_rdata_reset(&rdata); - - if (nsec3param.hash != DNS_NSEC3_UNKNOWNALG && - !dns_nsec3_supportedhash(nsec3param.hash)) - { - continue; - } - - if (nsec3param.flags != 0) { - continue; - } - - memmove(version->salt, nsec3param.salt, - nsec3param.salt_length); - version->hash = nsec3param.hash; - version->salt_length = nsec3param.salt_length; - version->iterations = nsec3param.iterations; - version->flags = nsec3param.flags; - version->havensec3 = true; - /* - * Look for a better algorithm than the - * unknown test algorithm. - */ - if (nsec3param.hash != DNS_NSEC3_UNKNOWNALG) { - goto unlock; - } + if (nsec3param.hash != DNS_NSEC3_UNKNOWNALG) { + goto unlock; } } } @@ -1307,7 +1290,6 @@ newversion(dns_db_t *db, dns_dbversion_t **versionp) { static void resigninsert(dns_slabheader_t *newheader) { REQUIRE(newheader->heap_index == 0); - REQUIRE(!ISC_LINK_LINKED(newheader, link)); LOCK(get_heap_lock(newheader)); isc_heap_insert(HEADERNODE(newheader)->heap->heap, newheader); @@ -1327,7 +1309,15 @@ resigndelete(qpzonedb_t *qpdb ISC_ATTR_UNUSED, qpz_version_t *version, header->heap_index = 0; qpznode_acquire(qpdb, HEADERNODE(header) DNS__DB_FLARG_PASS); - ISC_LIST_APPEND(version->resigned_list, header, link); + + qpz_resigned_t *resigned = isc_mem_get(((dns_db_t *)qpdb)->mctx, + sizeof(*resigned)); + *resigned = (qpz_resigned_t){ + .header = header, + .link = ISC_LINK_INITIALIZER, + }; + + ISC_LIST_APPEND(version->resigned_list, resigned, link); } static void @@ -1340,7 +1330,7 @@ make_least_version(qpzonedb_t *qpdb, qpz_version_t *version, static void rollback_node(qpznode_t *node, uint32_t serial) { - dns_slabheader_t *header = NULL, *dcurrent = NULL; + dns_slabtop_t *top = NULL; bool make_dirty = false; /* @@ -1348,18 +1338,21 @@ rollback_node(qpznode_t *node, uint32_t serial) { * 'serial'. When the reference count goes to zero, these rdatasets * will be cleaned up; until that time, they will be ignored. */ - for (header = node->data; header != NULL; header = header->next) { + for (top = node->data; top != NULL; top = top->next) { + dns_slabheader_t *header = top->header; + if (header->serial == serial) { DNS_SLABHEADER_SETATTR(header, DNS_SLABHEADERATTR_IGNORE); make_dirty = true; } - for (dcurrent = header->down; dcurrent != NULL; - dcurrent = dcurrent->down) + + for (header = header->down; header != NULL; + header = header->down) { - if (dcurrent->serial == serial) { + if (header->serial == serial) { DNS_SLABHEADER_SETATTR( - dcurrent, DNS_SLABHEADERATTR_IGNORE); + header, DNS_SLABHEADERATTR_IGNORE); make_dirty = true; } } @@ -1378,7 +1371,7 @@ closeversion(dns_db_t *db, dns_dbversion_t **versionp, qpznode_t *node = NULL; bool rollback = false; qpz_changedlist_t cleanup_list; - dns_slabheaderlist_t resigned_list; + qpz_resignedlist_t resigned_list; uint32_t serial, least_serial; REQUIRE(VALID_QPZONE(qpdb)); @@ -1552,11 +1545,14 @@ closeversion(dns_db_t *db, dns_dbversion_t **versionp, /* * Commit/rollback re-signed headers. */ - ISC_LIST_FOREACH (resigned_list, header, link) { + ISC_LIST_FOREACH (resigned_list, resigned, link) { isc_rwlock_t *nlock = NULL; isc_rwlocktype_t nlocktype = isc_rwlocktype_none; + dns_slabheader_t *header = resigned->header; - ISC_LIST_UNLINK(resigned_list, header, link); + ISC_LIST_UNLINK(resigned_list, resigned, link); + + isc_mem_put(db->mctx, resigned, sizeof(*resigned)); nlock = qpzone_get_lock(HEADERNODE(header)); NODE_WRLOCK(nlock, &nlocktype); @@ -1603,7 +1599,7 @@ qpzone_findrdataset(dns_db_t *db, dns_dbnode_t *dbnode, dns_rdataset_t *sigrdataset DNS__DB_FLARG) { qpzonedb_t *qpdb = (qpzonedb_t *)db; qpznode_t *node = (qpznode_t *)dbnode; - dns_slabheader_t *header = NULL, *header_next = NULL; + dns_slabtop_t *top = NULL; dns_slabheader_t *found = NULL, *foundsig = NULL; uint32_t serial; qpz_version_t *version = (qpz_version_t *)dbversion; @@ -1636,8 +1632,8 @@ qpzone_findrdataset(dns_db_t *db, dns_dbnode_t *dbnode, sigpair = dns_typepair_none; } - for (header = node->data; header != NULL; header = header_next) { - header_next = header->next; + for (top = node->data; top != NULL; top = top->next) { + dns_slabheader_t *header = top->header; do { if (header->serial <= serial && !IGNORE(header)) { if (!EXISTS(header)) { @@ -1653,12 +1649,12 @@ qpzone_findrdataset(dns_db_t *db, dns_dbnode_t *dbnode, * We have an active, extant rdataset. If it's a * type we're looking for, remember it. */ - if (header->typepair == typepair) { + if (top->typepair == typepair) { found = header; if (foundsig != NULL) { break; } - } else if (header->typepair == sigpair) { + } else if (top->typepair == sigpair) { foundsig = header; if (found != NULL) { break; @@ -1690,8 +1686,8 @@ qpzone_findrdataset(dns_db_t *db, dns_dbnode_t *dbnode, static bool delegating_type(qpzonedb_t *qpdb, qpznode_t *node, dns_typepair_t typepair) { - return typepair == dns_rdatatype_dname || - (typepair == dns_rdatatype_ns && + return typepair == DNS_TYPEPAIR(dns_rdatatype_dname) || + (typepair == DNS_TYPEPAIR(dns_rdatatype_ns) && (node != qpdb->origin || IS_STUB(qpdb))); } @@ -1755,19 +1751,19 @@ done: static bool cname_and_other(qpznode_t *node, uint32_t serial) { - dns_slabheader_t *header = NULL, *header_next = NULL; bool cname = false, other = false; dns_rdatatype_t rdtype; + dns_slabtop_t *top = NULL; /* * Look for CNAME and "other data" rdatasets active in our version. * ("Other data" is any rdataset whose type is not KEY, NSEC, SIG * or RRSIG. */ - for (header = node->data; header != NULL; header = header_next) { - header_next = header->next; + for (top = node->data; top != NULL; top = top->next) { + dns_slabheader_t *header = top->header; - rdtype = DNS_TYPEPAIR_TYPE(header->typepair); + rdtype = DNS_TYPEPAIR_TYPE(top->typepair); if (rdtype == dns_rdatatype_cname) { do { if (header->serial <= serial && !IGNORE(header)) @@ -1798,7 +1794,7 @@ cname_and_other(qpznode_t *node, uint32_t serial) { header = header->down; } while (header != NULL); if (header != NULL) { - if (!prio_type(header->typepair)) { + if (!prio_type(rdtype)) { /* * CNAME is in the priority list, so if * we are done with priority types, we @@ -1868,9 +1864,8 @@ add(qpzonedb_t *qpdb, qpznode_t *node, const dns_name_t *nodename, bool loading, dns_rdataset_t *addedrdataset, isc_stdtime_t now ISC_ATTR_UNUSED DNS__DB_FLARG) { qpz_changed_t *changed = NULL; - dns_slabheader_t *topheader = NULL, *topheader_prev = NULL; - dns_slabheader_t *prioheader = NULL; - dns_slabheader_t *header = NULL; + dns_slabtop_t *top = NULL; + dns_slabtop_t *priotop = NULL; dns_slabheader_t *merged = NULL; isc_result_t result; bool merge = false; @@ -1891,17 +1886,14 @@ add(qpzonedb_t *qpdb, qpznode_t *node, const dns_name_t *nodename, } ntypes = 0; - for (topheader = node->data; topheader != NULL; - topheader = topheader->next) - { + for (top = node->data; top != NULL; top = top->next) { ++ntypes; - if (prio_type(topheader->typepair)) { - prioheader = topheader; + if (prio_type(top->typepair)) { + priotop = top; } - if (topheader->typepair == newheader->typepair) { + if (top->typepair == newheader->typepair) { break; } - topheader_prev = topheader; } /* @@ -1909,10 +1901,15 @@ add(qpzonedb_t *qpdb, qpznode_t *node, const dns_name_t *nodename, * IGNORE rdatasets between the top of the chain and the first real * data. We skip over them. */ - header = topheader; - while (header != NULL && IGNORE(header)) { - header = header->down; + dns_slabheader_t *header = NULL, *header_prev = NULL; + if (top != NULL) { + header = top->header; + while (header != NULL && IGNORE(header)) { + header_prev = header; + header = header->down; + } } + if (header != NULL) { /* * If 'merge' is true and header isn't empty/nonexistent, @@ -1977,7 +1974,9 @@ add(qpzonedb_t *qpdb, qpznode_t *node, const dns_name_t *nodename, } } - INSIST(version->serial >= topheader->serial); + INSIST(version->serial >= top->header->serial); + INSIST(top->typepair == newheader->typepair); + if (loading) { newheader->down = NULL; if (RESIGN(newheader)) { @@ -1991,14 +1990,11 @@ add(qpzonedb_t *qpdb, qpznode_t *node, const dns_name_t *nodename, * Since we don't generate changed records when * loading, we MUST clean up 'header' now. */ - if (topheader_prev != NULL) { - topheader_prev->next = newheader; - } else { - node->data = newheader; - } - newheader->next = topheader->next; + newheader->top = top; + top->header = newheader; maybe_update_recordsandsize(false, version, header, nodename->length); + dns_slabheader_destroy(&header); } else { if (RESIGN(newheader)) { @@ -2006,14 +2002,16 @@ add(qpzonedb_t *qpdb, qpznode_t *node, const dns_name_t *nodename, resigndelete(qpdb, version, header DNS__DB_FLARG_PASS); } - if (topheader_prev != NULL) { - topheader_prev->next = newheader; + + if (header_prev != NULL) { + header_prev->down = newheader; } else { - node->data = newheader; + top->header = newheader; } - newheader->next = topheader->next; - newheader->down = topheader; - topheader->up = newheader; + + newheader->top = top; + newheader->down = header; + node->dirty = true; if (changed != NULL) { changed->dirty = true; @@ -2038,7 +2036,7 @@ add(qpzonedb_t *qpdb, qpznode_t *node, const dns_name_t *nodename, resigndelete(qpdb, version, header DNS__DB_FLARG_PASS); } - if (topheader != NULL) { + if (top != NULL) { /* * We have a list of rdatasets of the given type, * but they're all marked IGNORE. We simply insert @@ -2048,15 +2046,10 @@ add(qpzonedb_t *qpdb, qpznode_t *node, const dns_name_t *nodename, * we INSIST on it. */ INSIST(!loading); - INSIST(version->serial >= topheader->serial); - if (topheader_prev != NULL) { - topheader_prev->next = newheader; - } else { - node->data = newheader; - } - newheader->next = topheader->next; - newheader->down = topheader; - topheader->up = newheader; + INSIST(version->serial >= top->header->serial); + newheader->top = top; + newheader->down = top->header; + top->header = newheader; if (changed != NULL) { changed->dirty = true; } @@ -2073,20 +2066,24 @@ add(qpzonedb_t *qpdb, qpznode_t *node, const dns_name_t *nodename, return DNS_R_TOOMANYRECORDS; } - INSIST(newheader->down == NULL); + dns_slabtop_t *newtop = dns_slabtop_new( + ((dns_db_t *)qpdb)->mctx, newheader->typepair); + + newheader->top = newtop; + newtop->header = newheader; if (prio_type(newheader->typepair)) { /* This is a priority type, prepend it */ - newheader->next = node->data; - node->data = newheader; - } else if (prioheader != NULL) { + newtop->next = node->data; + node->data = newtop; + } else if (priotop != NULL) { /* Append after the priority headers */ - newheader->next = prioheader->next; - prioheader->next = newheader; + newtop->next = priotop->next; + priotop->next = newtop; } else { /* There were no priority headers */ - newheader->next = node->data; - node->data = newheader; + newtop->next = node->data; + node->data = newtop; } } } @@ -2610,22 +2607,21 @@ qpzone_findnsec3node(dns_db_t *db, const dns_name_t *name, bool create, static bool matchparams(dns_slabheader_t *header, qpz_search_t *search) { - dns_rdata_t rdata = DNS_RDATA_INIT; dns_rdata_nsec3_t nsec3; unsigned char *raw = NULL; unsigned int rdlen, count; isc_region_t region; isc_result_t result; - REQUIRE(header->typepair == dns_rdatatype_nsec3); + REQUIRE(header->typepair == DNS_TYPEPAIR(dns_rdatatype_nsec3)); raw = (unsigned char *)header + sizeof(*header); - count = raw[0] * 256 + raw[1]; /* count */ - raw += DNS_RDATASET_LENGTH; + count = get_uint16(raw); while (count-- > 0) { - rdlen = raw[0] * 256 + raw[1]; - raw += DNS_RDATASET_LENGTH; + dns_rdata_t rdata = DNS_RDATA_INIT; + + rdlen = get_uint16(raw); region.base = raw; region.length = rdlen; dns_rdata_fromregion(&rdata, search->qpdb->common.rdclass, @@ -2641,7 +2637,6 @@ matchparams(dns_slabheader_t *header, qpz_search_t *search) { { return true; } - dns_rdata_reset(&rdata); } return false; } @@ -2699,7 +2694,7 @@ qpzone_setup_delegation(qpz_search_t *search, dns_dbnode_t **nodep, NODE_UNLOCK(nlock, &nlocktype); } - if (typepair == dns_rdatatype_dname) { + if (typepair == DNS_TYPEPAIR(dns_rdatatype_dname)) { return DNS_R_DNAME; } return DNS_R_DELEGATION; @@ -2720,36 +2715,30 @@ step(qpz_search_t *search, dns_qpiter_t *it, direction_t direction, dns_name_t *nodename = dns_fixedname_initname(&fnodename); qpznode_t *node = NULL; isc_result_t result = ISC_R_SUCCESS; - dns_slabheader_t *header = NULL; result = dns_qpiter_current(it, nodename, (void **)&node, NULL); while (result == ISC_R_SUCCESS) { isc_rwlock_t *nlock = qpzone_get_lock(node); isc_rwlocktype_t nlocktype = isc_rwlocktype_none; - dns_slabheader_t *header_next = NULL; + dns_slabtop_t *top = NULL; + dns_slabheader_t *found = NULL; NODE_RDLOCK(nlock, &nlocktype); - for (header = node->data; header != NULL; header = header_next) - { - header_next = header->next; - while (header != NULL) { - if (header->serial <= search->serial && - !IGNORE(header)) - { - if (!EXISTS(header)) { - header = NULL; - } - break; - } else { - header = header->down; - } + for (top = node->data; top != NULL; top = top->next) { + dns_slabheader_t *header = top->header; + while (header != NULL && + (IGNORE(header) || + header->serial > search->serial)) + { + header = header->down; } - if (header != NULL) { + if (header != NULL && EXISTS(header)) { + found = header; break; } } NODE_UNLOCK(nlock, &nlocktype); - if (header != NULL) { + if (found != NULL) { break; } @@ -2868,7 +2857,8 @@ wildcard_blocked(qpz_search_t *search, const dns_name_t *qname, static isc_result_t find_wildcard(qpz_search_t *search, qpznode_t **nodep, const dns_name_t *qname, dns_namespace_t nspace) { - dns_slabheader_t *header = NULL; + dns_slabtop_t *top = NULL; + dns_slabheader_t *found = NULL; isc_result_t result = ISC_R_NOTFOUND; /* @@ -2896,16 +2886,17 @@ find_wildcard(qpz_search_t *search, qpznode_t **nodep, const dns_name_t *qname, * may not need the information, because it simplifies the * locking and code flow. */ - for (header = node->data; header != NULL; header = header->next) - { + for (top = node->data; top != NULL; top = top->next) { + dns_slabheader_t *header = top->header; if (header->serial <= search->serial && !IGNORE(header) && EXISTS(header)) { + found = header; break; } } - active = (header != NULL); + active = (found != NULL); wild = node->wild; NODE_UNLOCK(nlock, &nlocktype); @@ -2935,17 +2926,19 @@ find_wildcard(qpz_search_t *search, qpznode_t **nodep, const dns_name_t *qname, */ nlock = qpzone_get_lock(wnode); NODE_RDLOCK(nlock, &nlocktype); - for (header = wnode->data; header != NULL; - header = header->next) + for (top = wnode->data; top != NULL; + top = top->next) { + dns_slabheader_t *header = top->header; if (header->serial <= search->serial && !IGNORE(header) && EXISTS(header)) { + found = header; break; } } NODE_UNLOCK(nlock, &nlocktype); - if (header != NULL || + if (found != NULL || activeempty(search, &wit, wname)) { if (wildcard_blocked(search, qname, @@ -3086,7 +3079,6 @@ find_closest_nsec(qpz_search_t *search, dns_dbnode_t **nodep, dns_rdataset_t *sigrdataset, bool nsec3, bool secure DNS__DB_FLARG) { qpznode_t *node = NULL, *prevnode = NULL; - dns_slabheader_t *header = NULL, *header_next = NULL; dns_qpiter_t nseciter; bool empty_node; isc_result_t result; @@ -3110,14 +3102,14 @@ find_closest_nsec(qpz_search_t *search, dns_dbnode_t **nodep, } again: do { + dns_slabtop_t *top = NULL; dns_slabheader_t *found = NULL, *foundsig = NULL; isc_rwlocktype_t nlocktype = isc_rwlocktype_none; isc_rwlock_t *nlock = qpzone_get_lock(node); NODE_RDLOCK(nlock, &nlocktype); empty_node = true; - for (header = node->data; header != NULL; header = header_next) - { - header_next = header->next; + for (top = node->data; top != NULL; top = top->next) { + dns_slabheader_t *header = top->header; /* * Look for an active, extant NSEC or RRSIG NSEC. */ @@ -3139,12 +3131,12 @@ again: * active rdataset at this node. */ empty_node = false; - if (header->typepair == typepair) { + if (top->typepair == typepair) { found = header; if (foundsig != NULL) { break; } - } else if (header->typepair == sigpair) { + } else if (top->typepair == sigpair) { foundsig = header; if (found != NULL) { break; @@ -3154,7 +3146,8 @@ again: } if (!empty_node) { if (found != NULL && search->version->havensec3 && - found->typepair == dns_rdatatype_nsec3 && + found->typepair == + DNS_TYPEPAIR(dns_rdatatype_nsec3) && !matchparams(found, search)) { empty_node = true; @@ -3247,7 +3240,7 @@ again: static isc_result_t qpzone_check_zonecut(qpznode_t *node, void *arg DNS__DB_FLARG) { qpz_search_t *search = arg; - dns_slabheader_t *header = NULL, *header_next = NULL; + dns_slabtop_t *top = NULL; dns_slabheader_t *dname_header = NULL, *sigdname_header = NULL; dns_slabheader_t *ns_header = NULL; dns_slabheader_t *found = NULL; @@ -3260,11 +3253,11 @@ qpzone_check_zonecut(qpznode_t *node, void *arg DNS__DB_FLARG) { /* * Look for an NS or DNAME rdataset active in our version. */ - for (header = node->data; header != NULL; header = header_next) { - header_next = header->next; - if (header->typepair == dns_rdatatype_ns || - header->typepair == dns_rdatatype_dname || - header->typepair == DNS_SIGTYPEPAIR(dns_rdatatype_dname)) + for (top = node->data; top != NULL; top = top->next) { + dns_slabheader_t *header = top->header; + if (top->typepair == DNS_TYPEPAIR(dns_rdatatype_ns) || + top->typepair == DNS_TYPEPAIR(dns_rdatatype_dname) || + top->typepair == DNS_SIGTYPEPAIR(dns_rdatatype_dname)) { do { if (header->serial <= search->serial && @@ -3279,9 +3272,11 @@ qpzone_check_zonecut(qpznode_t *node, void *arg DNS__DB_FLARG) { } } while (header != NULL); if (header != NULL) { - if (header->typepair == dns_rdatatype_dname) { + if (top->typepair == + DNS_TYPEPAIR(dns_rdatatype_dname)) + { dname_header = header; - } else if (header->typepair == + } else if (top->typepair == DNS_SIGTYPEPAIR(dns_rdatatype_dname)) { sigdname_header = header; @@ -3411,7 +3406,7 @@ qpzone_find(dns_db_t *db, const dns_name_t *name, dns_dbversion_t *version, bool maybe_zonecut = false, at_zonecut = false; bool wild = false, empty_node = false; bool nsec3 = false; - dns_slabheader_t *header = NULL, *header_next = NULL; + dns_slabtop_t *top = NULL; dns_slabheader_t *found = NULL, *nsecheader = NULL; dns_slabheader_t *foundsig = NULL, *cnamesig = NULL, *nsecsig = NULL; dns_typepair_t sigpair; @@ -3589,8 +3584,8 @@ found: sigpair = DNS_SIGTYPEPAIR(type); empty_node = true; - for (header = node->data; header != NULL; header = header_next) { - header_next = header->next; + for (top = node->data; top != NULL; top = top->next) { + dns_slabheader_t *header = top->header; /* * Look for an active, extant rdataset. */ @@ -3616,7 +3611,7 @@ found: * Do special zone cut handling, if requested. */ if (maybe_zonecut && - header->typepair == dns_rdatatype_ns) + top->typepair == DNS_TYPEPAIR(dns_rdatatype_ns)) { /* * We increment the reference count on node to @@ -3658,7 +3653,8 @@ found: * If the NSEC3 record doesn't match the chain * we are using behave as if it isn't here. */ - if (header->typepair == dns_rdatatype_nsec3 && + if (top->typepair == + DNS_TYPEPAIR(dns_rdatatype_nsec3) && !matchparams(header, &search)) { NODE_UNLOCK(nlock, &nlocktype); @@ -3668,16 +3664,18 @@ found: * If we found a type we were looking for, * remember it. */ - if (header->typepair == type || + if (top->typepair == type || type == dns_rdatatype_any || - (header->typepair == dns_rdatatype_cname && + (top->typepair == + DNS_TYPEPAIR(dns_rdatatype_cname) && cname_ok)) { /* * We've found the answer! */ found = header; - if (header->typepair == dns_rdatatype_cname && + if (top->typepair == + DNS_TYPEPAIR(dns_rdatatype_cname) && cname_ok) { /* @@ -3701,7 +3699,7 @@ found: if (!maybe_zonecut && foundsig != NULL) { break; } - } else if (header->typepair == sigpair) { + } else if (top->typepair == sigpair) { /* * We've found the RRSIG rdataset for our * target type. Remember it. @@ -3713,7 +3711,8 @@ found: if (!maybe_zonecut && found != NULL) { break; } - } else if (header->typepair == dns_rdatatype_nsec && + } else if (top->typepair == + DNS_TYPEPAIR(dns_rdatatype_nsec) && !search.version->havensec3) { /* @@ -3722,7 +3721,7 @@ found: * we might need it later. */ nsecheader = header; - } else if (header->typepair == + } else if (top->typepair == DNS_SIGTYPEPAIR( dns_rdatatype_nsec) && !search.version->havensec3) @@ -3733,7 +3732,7 @@ found: */ nsecsig = header; } else if (cname_ok && - header->typepair == + top->typepair == DNS_SIGTYPEPAIR(dns_rdatatype_cname)) { /* @@ -3831,7 +3830,7 @@ found: * We found what we were looking for, or we found a CNAME. */ if (type != found->typepair && type != dns_rdatatype_any && - found->typepair == dns_rdatatype_cname) + found->typepair == DNS_TYPEPAIR(dns_rdatatype_cname)) { /* * We weren't doing an ANY query and we found a CNAME instead @@ -4102,36 +4101,33 @@ rdatasetiter_first(dns_rdatasetiter_t *iterator DNS__DB_FLARG) { qpdb_rdatasetiter_t *qrditer = (qpdb_rdatasetiter_t *)iterator; qpznode_t *node = (qpznode_t *)qrditer->common.node; qpz_version_t *version = (qpz_version_t *)qrditer->common.version; - dns_slabheader_t *header = NULL, *top_next = NULL; isc_rwlocktype_t nlocktype = isc_rwlocktype_none; isc_rwlock_t *nlock = qpzone_get_lock(node); + dns_slabheader_t *found = NULL; + dns_slabtop_t *top = NULL; NODE_RDLOCK(nlock, &nlocktype); - for (header = node->data; header != NULL; header = top_next) { - top_next = header->next; - do { - if (header->serial <= version->serial && - !IGNORE(header)) - { - if (!EXISTS(header)) { - header = NULL; - } - break; - } else { - header = header->down; - } - } while (header != NULL); - if (header != NULL) { + for (top = node->data; top != NULL; top = top->next) { + dns_slabheader_t *header = top->header; + while (header != NULL && + (IGNORE(header) || header->serial > version->serial)) + { + header = header->down; + } + + if (header != NULL && EXISTS(header)) { + found = header; break; } } NODE_UNLOCK(nlock, &nlocktype); - qrditer->current = header; + qrditer->currenttop = top; + qrditer->current = found; - if (header == NULL) { + if (top == NULL) { return ISC_R_NOMORE; } @@ -4143,13 +4139,12 @@ rdatasetiter_next(dns_rdatasetiter_t *iterator DNS__DB_FLARG) { qpdb_rdatasetiter_t *qrditer = (qpdb_rdatasetiter_t *)iterator; qpznode_t *node = (qpznode_t *)qrditer->common.node; qpz_version_t *version = (qpz_version_t *)qrditer->common.version; - dns_slabheader_t *header = NULL; - dns_slabheader_t *topheader, *topheader_next = NULL; isc_rwlocktype_t nlocktype = isc_rwlocktype_none; isc_rwlock_t *nlock = qpzone_get_lock(node); + dns_slabtop_t *top = qrditer->currenttop; + dns_slabheader_t *found = NULL; - header = qrditer->current; - if (header == NULL) { + if (top == NULL) { return ISC_R_NOMORE; } @@ -4158,38 +4153,26 @@ rdatasetiter_next(dns_rdatasetiter_t *iterator DNS__DB_FLARG) { /* * Find the start of the header chain for the next type. */ - topheader = dns_slabheader_top(header); - - for (header = topheader->next; header != NULL; header = topheader_next) - { - topheader_next = header->next; - do { - if (header->serial <= version->serial && - !IGNORE(header)) - { - if (!EXISTS(header)) { - header = NULL; - } - break; - } else { - header = header->down; - } - } while (header != NULL); - if (header != NULL) { - break; + for (top = top->next; top != NULL; top = top->next) { + dns_slabheader_t *header = top->header; + while (header != NULL && + (IGNORE(header) || header->serial > version->serial)) + { + header = header->down; } - /* - * Find the start of the header chain for the next type. - */ - topheader = topheader->next; + if (header != NULL && EXISTS(header)) { + found = header; + break; + } } NODE_UNLOCK(nlock, &nlocktype); - qrditer->current = header; + qrditer->currenttop = top; + qrditer->current = found; - if (header == NULL) { + if (top == NULL) { return ISC_R_NOMORE; } @@ -4201,17 +4184,16 @@ rdatasetiter_current(dns_rdatasetiter_t *iterator, dns_rdataset_t *rdataset DNS__DB_FLARG) { qpdb_rdatasetiter_t *qrditer = (qpdb_rdatasetiter_t *)iterator; qpzonedb_t *qpdb = (qpzonedb_t *)(qrditer->common.db); - qpznode_t *node = (qpznode_t *)qrditer->common.node; - dns_slabheader_t *header = NULL; + qpznode_t *qpnode = (qpznode_t *)qrditer->common.node; isc_rwlocktype_t nlocktype = isc_rwlocktype_none; - isc_rwlock_t *nlock = qpzone_get_lock(node); + isc_rwlock_t *nlock = qpzone_get_lock(qpnode); + dns_slabheader_t *header = qrditer->current; - header = qrditer->current; REQUIRE(header != NULL); NODE_RDLOCK(nlock, &nlocktype); - bindrdataset(qpdb, node, header, rdataset DNS__DB_FLARG_PASS); + bindrdataset(qpdb, qpnode, header, rdataset DNS__DB_FLARG_PASS); NODE_UNLOCK(nlock, &nlocktype); } @@ -4917,8 +4899,8 @@ qpzone_subtractrdataset(dns_db_t *db, dns_dbnode_t *dbnode, qpz_version_t *version = (qpz_version_t *)dbversion; dns_fixedname_t fname; dns_name_t *nodename = dns_fixedname_initname(&fname); - dns_slabheader_t *topheader = NULL, *topheader_prev = NULL; - dns_slabheader_t *header = NULL, *newheader = NULL; + dns_slabtop_t *top = NULL; + dns_slabheader_t *newheader = NULL; dns_slabheader_t *subresult = NULL; isc_region_t region; isc_result_t result; @@ -4961,22 +4943,22 @@ qpzone_subtractrdataset(dns_db_t *db, dns_dbnode_t *dbnode, NODE_WRLOCK(nlock, &nlocktype); changed = add_changed(newheader, version DNS__DB_FLARG_PASS); - for (topheader = node->data; topheader != NULL; - topheader = topheader->next) - { - if (topheader->typepair == newheader->typepair) { + for (top = node->data; top != NULL; top = top->next) { + if (top->typepair == newheader->typepair) { break; } - topheader_prev = topheader; } /* * If header isn't NULL, we've found the right type. There may be * IGNORE rdatasets between the top of the chain and the first real * data. We skip over them. */ - header = topheader; - while (header != NULL && IGNORE(header)) { - header = header->down; + dns_slabheader_t *header = NULL; + if (top != NULL) { + header = top->header; + while (header != NULL && IGNORE(header)) { + header = header->down; + } } if (header != NULL && EXISTS(header)) { unsigned int flags = 0; @@ -4992,7 +4974,7 @@ qpzone_subtractrdataset(dns_db_t *db, dns_dbnode_t *dbnode, result = dns_rdataslab_subtract( header, newheader, qpdb->common.mctx, qpdb->common.rdclass, - DNS_TYPEPAIR_TYPE(header->typepair), flags, + DNS_TYPEPAIR_TYPE(top->typepair), flags, &subresult); } if (result == ISC_R_SUCCESS) { @@ -5026,10 +5008,10 @@ qpzone_subtractrdataset(dns_db_t *db, dns_dbnode_t *dbnode, * add a nonexistent header instead. */ dns_slabheader_destroy(&newheader); - newheader = dns_slabheader_new((dns_db_t *)qpdb, + newheader = dns_slabheader_new(db->mctx, (dns_dbnode_t *)node); newheader->ttl = 0; - newheader->typepair = topheader->typepair; + newheader->typepair = top->typepair; atomic_init(&newheader->attributes, DNS_SLABHEADERATTR_NONEXISTENT); newheader->serial = version->serial; @@ -5039,20 +5021,16 @@ qpzone_subtractrdataset(dns_db_t *db, dns_dbnode_t *dbnode, } /* - * If we're here, we want to link newheader in front of - * topheader. + * If we're here, we want to link newheader at the top. */ - INSIST(version->serial >= topheader->serial); + INSIST(version->serial >= top->header->serial); maybe_update_recordsandsize(false, version, header, nodename->length); - if (topheader_prev != NULL) { - topheader_prev->next = newheader; - } else { - node->data = newheader; - } - newheader->next = topheader->next; - newheader->down = topheader; - topheader->next = newheader; + + newheader->top = top; + newheader->down = top->header; + top->header = newheader; + node->dirty = true; changed->dirty = true; resigndelete(qpdb, version, header DNS__DB_FLARG_PASS); @@ -5110,7 +5088,7 @@ qpzone_deleterdataset(dns_db_t *db, dns_dbnode_t *dbnode, return ISC_R_NOTIMPLEMENTED; } - newheader = dns_slabheader_new(db, (dns_dbnode_t *)node); + newheader = dns_slabheader_new(db->mctx, (dns_dbnode_t *)node); newheader->typepair = DNS_TYPEPAIR_VALUE(type, covers); newheader->ttl = 0; atomic_init(&newheader->attributes, DNS_SLABHEADERATTR_NONEXISTENT); @@ -5517,19 +5495,20 @@ static dns_dbnode_methods_t qpznode_methods = (dns_dbnode_methods_t){ static void destroy_qpznode(qpznode_t *node) { - dns_slabheader_t *current = NULL, *next = NULL; + dns_slabtop_t *top = NULL, *top_next = NULL; + dns_db_t *db = (dns_db_t *)node->qpdb; - for (current = node->data; current != NULL; current = next) { - dns_slabheader_t *down = current->down, *down_next = NULL; + for (top = node->data; top != NULL; top = top_next) { + top_next = top->next; - next = current->next; - - for (down = current->down; down != NULL; down = down_next) { + dns_slabheader_t *down = NULL, *down_next = NULL; + for (down = top->header; down != NULL; down = down_next) { down_next = down->down; dns_slabheader_destroy(&down); } + top->header = NULL; - dns_slabheader_destroy(¤t); + dns_slabtop_destroy(db->mctx, &top); } qpz_heap_unref(node->heap); diff --git a/lib/dns/rdataslab.c b/lib/dns/rdataslab.c index 35645b66e3..2297418665 100644 --- a/lib/dns/rdataslab.c +++ b/lib/dns/rdataslab.c @@ -34,47 +34,21 @@ #include "rdataslab_p.h" /* - * The rdataslab structure allows iteration to occur in both load order - * and DNSSEC order. The structure is as follows: + * The memory structure of an rdataslab is as follows: * * header (dns_slabheader_t) * record count (2 bytes) - * offset table (4 x record count bytes in load order) * data records * data length (2 bytes) * order (2 bytes) - * meta data (1 byte for RRSIG's) + * meta data (1 byte for RRSIG, 0 for all other types) * data (data length bytes) * - * A "raw" rdataslab is the same but without the header. + * A "bare" rdataslab is everything after "header". * - * DNSSEC order traversal is performed by walking the data records. - * - * The order is stored with record to allow for efficient reconstruction - * of the offset table following a merge or subtraction. - * - * The iterator methods in rbtdb support both load order and DNSSEC order - * iteration. - * - * WARNING: - * rbtdb.c directly interacts with the slab's raw structures. If the - * structure changes then rbtdb.c also needs to be updated to reflect - * the changes. See the areas tagged with "RDATASLAB". + * When a slab is created, data records are sorted into DNSSEC order. */ -#define peek_uint16(buffer) ({ ((uint16_t)*(buffer) << 8) | *((buffer) + 1); }) -#define get_uint16(buffer) \ - ({ \ - uint16_t __ret = peek_uint16(buffer); \ - buffer += sizeof(uint16_t); \ - __ret; \ - }) -#define put_uint16(buffer, val) \ - ({ \ - *buffer++ = (val & 0xff00) >> 8; \ - *buffer++ = (val & 0x00ff); \ - }) - static void rdataset_disassociate(dns_rdataset_t *rdataset DNS__DB_FLARG); static isc_result_t @@ -240,8 +214,8 @@ makeslab(dns_rdataset_t *rdataset, isc_mem_t *mctx, isc_region_t *region, * If an rdata is not a duplicate, accumulate the storage size * required for the rdata. We do not store the class, type, etc, * just the rdata, so our overhead is 2 bytes for the number of - * records, and 8 for each rdata, (length(2), offset(4) and order(2)) - * and then the rdata itself. + * records, and 2 bytes for the length of each rdata, plus the + * rdata itself. */ for (i = 1; i < nalloc; i++) { if (compare_rdata(&rdata[i - 1], &rdata[i]) == 0) { @@ -359,7 +333,6 @@ dns_rdataslab_fromrdataset(dns_rdataset_t *rdataset, isc_mem_t *mctx, .typepair = typepair, .trust = rdataset->trust, .ttl = rdataset->ttl, - .link = ISC_LINK_INITIALIZER, }; } @@ -397,8 +370,8 @@ dns_rdataslab_count(dns_slabheader_t *header) { /* * Make the dns_rdata_t 'rdata' refer to the slab item - * beginning at '*current', which is part of a slab of type - * 'type' and class 'rdclass', and advance '*current' to + * beginning at '*current' (which is part of a slab of type + * 'type' and class 'rdclass') and advance '*current' to * point to the next item in the slab. */ static void @@ -827,11 +800,6 @@ dns_rdataslab_equalx(dns_slabheader_t *slab1, dns_slabheader_t *slab2, return true; } -void * -dns_slabheader_raw(dns_slabheader_t *header) { - return header + 1; -} - void dns_slabheader_setownercase(dns_slabheader_t *header, const dns_name_t *name) { REQUIRE(!CASESET(header)); @@ -871,11 +839,9 @@ dns_slabheader_copycase(dns_slabheader_t *dest, dns_slabheader_t *src) { void dns_slabheader_reset(dns_slabheader_t *h, dns_dbnode_t *node) { - ISC_LINK_INIT(h, link); h->heap_index = 0; h->heap = NULL; h->node = node; - h->visited = false; atomic_init(&h->attributes, 0); atomic_init(&h->last_refresh_fail_ts, 0); @@ -886,14 +852,13 @@ dns_slabheader_reset(dns_slabheader_t *h, dns_dbnode_t *node) { } dns_slabheader_t * -dns_slabheader_new(dns_db_t *db, dns_dbnode_t *node) { +dns_slabheader_new(isc_mem_t *mctx, dns_dbnode_t *node) { dns_slabheader_t *h = NULL; - h = isc_mem_get(db->mctx, sizeof(*h)); + h = isc_mem_get(mctx, sizeof(*h)); *h = (dns_slabheader_t){ - .link = ISC_LINK_INITIALIZER, + .node = node, }; - dns_slabheader_reset(h, node); return h; } @@ -943,23 +908,8 @@ dns_slabheader_freeproof(isc_mem_t *mctx, dns_slabheader_proof_t **proofp) { isc_mem_put(mctx, proof, sizeof(*proof)); } -dns_slabheader_t * -dns_slabheader_top(dns_slabheader_t *header) { - /* - * Find the start of the header chain for the next type - * by walking back up the list. - */ - while (header->up != NULL && header->up->typepair == header->typepair) { - header = header->up; - } - - return header; -} - /* Fixed RRSet helper macros */ -#define DNS_RDATASET_LENGTH 2; - static void rdataset_disassociate(dns_rdataset_t *rdataset DNS__DB_FLARG) { dns_dbnode_t *node = rdataset->slab.node; @@ -984,7 +934,7 @@ rdataset_first(dns_rdataset_t *rdataset) { * * 'raw' points to the first record. */ - rdataset->slab.iter_pos = raw + DNS_RDATASET_LENGTH; + rdataset->slab.iter_pos = raw + sizeof(uint16_t); rdataset->slab.iter_count = count - 1; return ISC_R_SUCCESS; @@ -1005,7 +955,7 @@ rdataset_next(dns_rdataset_t *rdataset) { unsigned char *raw = rdataset->slab.iter_pos; uint16_t length = peek_uint16(raw); raw += length; - rdataset->slab.iter_pos = raw + DNS_RDATASET_LENGTH; + rdataset->slab.iter_pos = raw + sizeof(uint16_t); return ISC_R_SUCCESS; } @@ -1024,9 +974,7 @@ rdataset_current(dns_rdataset_t *rdataset, dns_rdata_t *rdata) { * Find the start of the record if not already in iter_pos * then skip the length and order fields. */ - length = peek_uint16(raw); - - raw += DNS_RDATASET_LENGTH; + length = get_uint16(raw); if (rdataset->type == dns_rdatatype_rrsig) { if (*raw & DNS_RDATASLAB_OFFLINE) { @@ -1075,7 +1023,12 @@ rdataset_getnoqname(dns_rdataset_t *rdataset, dns_name_t *name, const dns_slabheader_proof_t *noqname = rdataset->slab.noqname; /* - * The _KEEPCASE attribute is set to prevent setownercase and + * Normally, rdataset->slab.raw points to the data immediately + * following a dns_slabheader in memory. Here, though, it will + * point to a bare rdataslab, a pointer to which is stored in + * the dns_slabheader's `noqname` field. + * + * The 'keepcase' attribute is set to prevent setownercase and * getownercase methods from affecting the case of NSEC/NSEC3 * owner names. */ @@ -1128,9 +1081,14 @@ rdataset_getclosest(dns_rdataset_t *rdataset, dns_name_t *name, const dns_slabheader_proof_t *closest = rdataset->slab.closest; /* - * As mentioned above, rdataset->slab.raw usually refers the data - * following an dns_slabheader, but in this case it points to a bare - * rdataslab belonging to the dns_slabheader's `closest` field. + * Normally, rdataset->slab.raw points to the data immediately + * following a dns_slabheader in memory. Here, though, it will + * point to a bare rdataslab, a pointer to which is stored in + * the dns_slabheader's `closest` field. + * + * The 'keepcase' attribute is set to prevent setownercase and + * getownercase methods from affecting the case of NSEC/NSEC3 + * owner names. */ dns__db_attachnode(node, &(dns_dbnode_t *){ NULL } DNS__DB_FLARG_PASS); *nsec = (dns_rdataset_t){ @@ -1260,3 +1218,22 @@ rdataset_equals(const dns_rdataset_t *rdataset1, return dns_rdataslab_equalx(header1, header2, rdataset1->rdclass, rdataset2->type); } + +dns_slabtop_t * +dns_slabtop_new(isc_mem_t *mctx, dns_typepair_t typepair) { + dns_slabtop_t *top = isc_mem_get(mctx, sizeof(*top)); + *top = (dns_slabtop_t){ + .typepair = typepair, + .link = ISC_LINK_INITIALIZER, + }; + + return top; +} + +void +dns_slabtop_destroy(isc_mem_t *mctx, dns_slabtop_t **topp) { + REQUIRE(topp != NULL && *topp != NULL); + dns_slabtop_t *top = *topp; + *topp = NULL; + isc_mem_put(mctx, top, sizeof(*top)); +} diff --git a/lib/dns/rdataslab_p.h b/lib/dns/rdataslab_p.h index e3b4fbb573..5ce39fbbc6 100644 --- a/lib/dns/rdataslab_p.h +++ b/lib/dns/rdataslab_p.h @@ -13,6 +13,8 @@ #pragma once +#include + #include #define ANCIENT(header) \ @@ -57,3 +59,16 @@ #define ZEROTTL(header) \ ((atomic_load_acquire(&(header)->attributes) & \ DNS_SLABHEADERATTR_ZEROTTL) != 0) + +#define peek_uint16(buffer) ISC_U8TO16_BE(buffer) +#define get_uint16(buffer) \ + ({ \ + uint16_t __ret = peek_uint16(buffer); \ + buffer += sizeof(uint16_t); \ + __ret; \ + }) +#define put_uint16(buffer, val) \ + { \ + ISC_U16TO8_BE(buffer, val); \ + (buffer) += sizeof(uint16_t); \ + }