From f4d8841f0d8b936763a5f40aea2a2eed3f25ffbd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Sur=C3=BD?= Date: Tue, 5 Aug 2025 18:05:52 +0200 Subject: [PATCH] Split the top level slab header hierarchy and the headers The code that combines the top-level hierarchy (per-typepair) and individual slab headers (per-version) saves a little bit of memory, but makes the code convoluted, hard to read and hard to modify. Change the top level hierarchy to be of different type with individual slabheaders "hanging" from the per-typepair dns_slabtop_t structure. This change makes the future enhancements (changing the top level data structure for faster lookups; coupling type + sig(type) into single slabtop) much easier. --- lib/dns/include/dns/rdataslab.h | 26 +- lib/dns/qpcache.c | 334 +++++++++-------- lib/dns/qpzone.c | 615 +++++++++++++++----------------- lib/dns/rdataslab.c | 88 +++-- 4 files changed, 513 insertions(+), 550 deletions(-) diff --git a/lib/dns/include/dns/rdataslab.h b/lib/dns/include/dns/rdataslab.h index b93619f600..d5b6fe53b5 100644 --- a/lib/dns/include/dns/rdataslab.h +++ b/lib/dns/include/dns/rdataslab.h @@ -64,6 +64,13 @@ 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; +}; + struct dns_slabheader { _Atomic(uint16_t) attributes; @@ -101,10 +108,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). @@ -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/qpcache.c b/lib/dns/qpcache.c index 93ae06cd18..3990371541 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 @@ -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 @@ -556,30 +557,38 @@ 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); + dns_slabtop_destroy(((dns_db_t *)qpdb)->mctx, &top); } else { - top_prev = current; + top_prev = top; } } node->dirty = 0; @@ -1134,10 +1143,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 +1160,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 +1194,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 +1267,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 +1281,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 +1331,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 +1344,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 +1407,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 +1448,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 +1526,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 +1645,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 +1660,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 +1690,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 +1702,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 +1723,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 +1905,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 +1930,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 +2056,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 +2086,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 +2480,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 +2531,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 +2578,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 +2589,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 +2600,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 +2613,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 +2622,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 +2652,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 +2713,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 +2756,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 +2766,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)) @@ -2824,14 +2807,10 @@ find_header: 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; + top->header = newheader; + newheader->top = top; + newheader->down = header; + mark_ancient(header); if (sigheader != NULL) { mark_ancient(sigheader); @@ -2846,36 +2825,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); qpcache_miss(qpdb, newheader, &nlocktype, &tlocktype DNS__DB_FLARG_PASS); - if (prio_header(newheader)) { + + newtop->header = newheader; + newheader->top = newtop; + + 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 @@ -3105,7 +3090,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) { @@ -3170,7 +3155,7 @@ qpcache_deleterdataset(dns_db_t *db, dns_dbnode_t *node, 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); @@ -3349,15 +3334,15 @@ 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 ((EXPIREDOK(iterator) && EXISTS(top->header)) || + iterator_active(qpdb, iterator, top->header)) { break; } @@ -3365,9 +3350,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 +3364,20 @@ 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 ((EXPIREDOK(iterator) && EXISTS(top->header)) || + iterator_active(qpdb, iterator, top->header)) { break; } @@ -3400,9 +3385,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 +3400,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); @@ -3770,13 +3755,15 @@ static void 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); @@ -3866,24 +3853,25 @@ 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; + dns_db_t *db = (dns_db_t *)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); + dns_slabtop_destroy(db->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 10d1065e12..50d5260d11 100644 --- a/lib/dns/qpzone.c +++ b/lib/dns/qpzone.c @@ -191,7 +191,7 @@ struct qpznode { atomic_bool wild; atomic_bool delegating; atomic_bool dirty; - void *data; + dns_slabtop_t *data; }; struct qpzonedb { @@ -327,6 +327,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 +826,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 +857,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 +868,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; @@ -1088,82 +1066,81 @@ 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)) { - /* - * Find an NSEC3PARAM with a supported algorithm. - */ - raw = dns_slabheader_raw(header); - count = raw[0] * 256 + raw[1]; /* count */ + header = header->down; + } + + if (header != NULL && EXISTS(header)) { + found = header; + } + } + + if (found != NULL) { + /* + * Find an NSEC3PARAM with a supported algorithm. + */ + raw = dns_slabheader_raw(found); + count = raw[0] * 256 + raw[1]; /* count */ + raw += DNS_RDATASET_LENGTH; + while (count-- > 0U) { + dns_rdata_t rdata = DNS_RDATA_INIT; + length = raw[0] * 256 + raw[1]; 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); + 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.hash != DNS_NSEC3_UNKNOWNALG && + !dns_nsec3_supportedhash(nsec3param.hash)) + { + continue; + } - if (nsec3param.flags != 0) { - 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; - } + 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; } } } @@ -1340,7 +1317,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 +1325,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; } } @@ -1603,7 +1583,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 +1616,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 +1633,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 +1670,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 +1735,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 +1778,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 +1848,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 +1870,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 +1885,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 +1958,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 +1974,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 +1986,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 +2020,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 +2030,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 +2050,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,20 +2591,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; while (count-- > 0) { + dns_rdata_t rdata = DNS_RDATA_INIT; + rdlen = raw[0] * 256 + raw[1]; raw += DNS_RDATASET_LENGTH; region.base = raw; @@ -2641,7 +2623,6 @@ matchparams(dns_slabheader_t *header, qpz_search_t *search) { { return true; } - dns_rdata_reset(&rdata); } return false; } @@ -2699,7 +2680,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 +2701,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 +2843,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 +2872,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 +2912,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 +3065,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 +3088,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 +3117,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 +3132,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 +3226,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 +3239,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 +3258,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 +3392,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 +3570,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 +3597,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 +3639,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 +3650,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 +3685,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 +3697,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 +3707,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 +3718,7 @@ found: */ nsecsig = header; } else if (cname_ok && - header->typepair == + top->typepair == DNS_SIGTYPEPAIR(dns_rdatatype_cname)) { /* @@ -3831,7 +3816,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 +4087,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 +4125,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 +4139,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 +4170,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 +4885,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 +4929,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 +4960,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) { @@ -5029,7 +4997,7 @@ qpzone_subtractrdataset(dns_db_t *db, dns_dbnode_t *dbnode, 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 +5007,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); @@ -5517,19 +5481,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 c175f449a0..be1d3e29bf 100644 --- a/lib/dns/rdataslab.c +++ b/lib/dns/rdataslab.c @@ -34,32 +34,19 @@ #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); }) @@ -240,8 +227,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) { @@ -397,8 +384,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 @@ -943,23 +930,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 +956,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 +977,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 +996,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 +1045,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 +1103,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 +1240,21 @@ 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, + }; + + 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)); +}