From 2f819526585d8143ef12ee103e1ade33f7d6b2e8 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 1/7] Pass 'mctx' instead of 'db' to dns_slabheader_new() The slabheader doesn't directly attach or link to 'db' anymore. Pass only the memory context needed to create the slab header to make the lack of relation ship more prominent. Also don't call dns_slabheader_reset() from dns_slabheader_new(), it has no added value. --- lib/dns/include/dns/rdataslab.h | 6 +++--- lib/dns/qpcache.c | 2 +- lib/dns/qpzone.c | 4 ++-- lib/dns/rdataslab.c | 6 +++--- 4 files changed, 9 insertions(+), 9 deletions(-) diff --git a/lib/dns/include/dns/rdataslab.h b/lib/dns/include/dns/rdataslab.h index c5e61c3b92..b93619f600 100644 --- a/lib/dns/include/dns/rdataslab.h +++ b/lib/dns/include/dns/rdataslab.h @@ -295,14 +295,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 diff --git a/lib/dns/qpcache.c b/lib/dns/qpcache.c index 8a2cd03879..93ae06cd18 100644 --- a/lib/dns/qpcache.c +++ b/lib/dns/qpcache.c @@ -3163,7 +3163,7 @@ 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); diff --git a/lib/dns/qpzone.c b/lib/dns/qpzone.c index 76eb96c9d5..10d1065e12 100644 --- a/lib/dns/qpzone.c +++ b/lib/dns/qpzone.c @@ -5026,7 +5026,7 @@ 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; @@ -5110,7 +5110,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); diff --git a/lib/dns/rdataslab.c b/lib/dns/rdataslab.c index 35645b66e3..c175f449a0 100644 --- a/lib/dns/rdataslab.c +++ b/lib/dns/rdataslab.c @@ -886,14 +886,14 @@ 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; } 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 2/7] 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)); +} From d7801aec7172047936c11138ae4dd304af58a1f2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Sur=C3=BD?= Date: Wed, 13 Aug 2025 09:30:45 +0200 Subject: [PATCH 3/7] Move SIEVE-LRU to dns_slabtop_t structure As the qpcache has only one active header at the time, we can move the SIEVE-LRU members from dns_slabheader_t to dns_slabtop_t structure thus saving a little bit of memory in each slabheader and using it only once per type. --- lib/dns/include/dns/rdataslab.h | 10 +++---- lib/dns/include/dns/types.h | 33 ++++++++++----------- lib/dns/qpcache.c | 52 ++++++++++++++++++++------------- lib/dns/qpzone.c | 29 ++++++++++++++---- lib/dns/rdataslab.c | 5 +--- 5 files changed, 76 insertions(+), 53 deletions(-) diff --git a/lib/dns/include/dns/rdataslab.h b/lib/dns/include/dns/rdataslab.h index d5b6fe53b5..45bff01d1a 100644 --- a/lib/dns/include/dns/rdataslab.h +++ b/lib/dns/include/dns/rdataslab.h @@ -69,6 +69,11 @@ 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 { @@ -132,11 +137,6 @@ 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, 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 3990371541..5d31550258 100644 --- a/lib/dns/qpcache.c +++ b/lib/dns/qpcache.c @@ -201,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; @@ -486,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); @@ -529,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 @@ -537,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); } /* @@ -586,6 +588,12 @@ clean_cache_node(qpcache_t *qpdb, qpcnode_t *node) { } else { node->data = top->next; } + + 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 = top; @@ -2804,13 +2812,16 @@ find_header: return DNS_R_UNCHANGED; } - qpcache_miss(qpdb, newheader, &nlocktype, - &tlocktype DNS__DB_FLARG_PASS); - 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); + mark_ancient(header); if (sigheader != NULL) { mark_ancient(sigheader); @@ -2827,12 +2838,12 @@ find_header: dns_slabtop_t *newtop = dns_slabtop_new( ((dns_db_t *)qpdb)->mctx, newheader->typepair); - qpcache_miss(qpdb, newheader, &nlocktype, - &tlocktype DNS__DB_FLARG_PASS); - newtop->header = newheader; newheader->top = newtop; + qpcache_miss(qpdb, newheader, &nlocktype, + &tlocktype DNS__DB_FLARG_PASS); + if (prio_header(newtop)) { /* This is a priority type, prepend it */ newtop->next = qpnode->data; @@ -3755,7 +3766,6 @@ 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); @@ -3767,10 +3777,6 @@ qpcnode_deletedata(dns_dbnode_t *node ISC_ATTR_UNUSED, void *data) { 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); } @@ -3855,7 +3861,7 @@ static dns_dbmethods_t qpdb_cachemethods = { static void qpcnode_destroy(qpcnode_t *qpnode) { dns_slabtop_t *top = NULL, *top_next = NULL; - dns_db_t *db = (dns_db_t *)qpnode->qpdb; + qpcache_t *qpdb = qpnode->qpdb; for (top = qpnode->data; top != NULL; top = top_next) { top_next = top->next; @@ -3867,7 +3873,11 @@ qpcnode_destroy(qpcnode_t *qpnode) { } top->header = NULL; - dns_slabtop_destroy(db->mctx, &top); + 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(&qpnode->name, qpnode->mctx); diff --git a/lib/dns/qpzone.c b/lib/dns/qpzone.c index 50d5260d11..e2cc089c75 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; @@ -1284,7 +1291,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); @@ -1304,7 +1310,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 @@ -1358,7 +1372,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)); @@ -1532,11 +1546,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); diff --git a/lib/dns/rdataslab.c b/lib/dns/rdataslab.c index be1d3e29bf..e2d054a588 100644 --- a/lib/dns/rdataslab.c +++ b/lib/dns/rdataslab.c @@ -346,7 +346,6 @@ dns_rdataslab_fromrdataset(dns_rdataset_t *rdataset, isc_mem_t *mctx, .typepair = typepair, .trust = rdataset->trust, .ttl = rdataset->ttl, - .link = ISC_LINK_INITIALIZER, }; } @@ -858,11 +857,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); @@ -878,7 +875,6 @@ dns_slabheader_new(isc_mem_t *mctx, dns_dbnode_t *node) { h = isc_mem_get(mctx, sizeof(*h)); *h = (dns_slabheader_t){ - .link = ISC_LINK_INITIALIZER, .node = node, }; return h; @@ -1246,6 +1242,7 @@ 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; From 04d6412558db9b608add54541c26590167042269 Mon Sep 17 00:00:00 2001 From: Evan Hunt Date: Sun, 17 Aug 2025 13:53:04 -0700 Subject: [PATCH 4/7] simplify iterator_active() the if statements calling iterator_active() checked the EXISTS flag on the header and then iterator_active() checked it again. simplify so only the caller checks it. --- lib/dns/qpcache.c | 17 ++++++----------- 1 file changed, 6 insertions(+), 11 deletions(-) diff --git a/lib/dns/qpcache.c b/lib/dns/qpcache.c index 5d31550258..7613105123 100644 --- a/lib/dns/qpcache.c +++ b/lib/dns/qpcache.c @@ -3316,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. */ @@ -3352,8 +3345,9 @@ rdatasetiter_first(dns_rdatasetiter_t *it DNS__DB_FLARG) { NODE_RDLOCK(nlock, &nlocktype); for (top = qpnode->data; top != NULL; top = top->next) { - if ((EXPIREDOK(iterator) && EXISTS(top->header)) || - iterator_active(qpdb, iterator, top->header)) + if (EXISTS(top->header) && + (EXPIREDOK(iterator) || + iterator_active(qpdb, iterator, top->header))) { break; } @@ -3387,8 +3381,9 @@ rdatasetiter_next(dns_rdatasetiter_t *it DNS__DB_FLARG) { NODE_RDLOCK(nlock, &nlocktype); for (top = top->next; top != NULL; top = top->next) { - if ((EXPIREDOK(iterator) && EXISTS(top->header)) || - iterator_active(qpdb, iterator, top->header)) + if (EXISTS(top->header) && + (EXPIREDOK(iterator) || + iterator_active(qpdb, iterator, top->header))) { break; } From 712ef31a0c9598777b1628083774fc4b391c9157 Mon Sep 17 00:00:00 2001 From: Evan Hunt Date: Sun, 17 Aug 2025 13:59:05 -0700 Subject: [PATCH 5/7] use get_uint16() to read count and rdlen use the same macro defned for rdataslab.c to get count and length values from raw slabs in qpzone.c. --- lib/dns/qpzone.c | 13 +++++-------- lib/dns/rdataslab.c | 13 ------------- lib/dns/rdataslab_p.h | 13 +++++++++++++ 3 files changed, 18 insertions(+), 21 deletions(-) diff --git a/lib/dns/qpzone.c b/lib/dns/qpzone.c index e2cc089c75..3f2124546b 100644 --- a/lib/dns/qpzone.c +++ b/lib/dns/qpzone.c @@ -1111,12 +1111,11 @@ setnsec3parameters(dns_db_t *db, qpz_version_t *version) { * Find an NSEC3PARAM with a supported algorithm. */ raw = dns_slabheader_raw(found); - count = raw[0] * 256 + raw[1]; /* count */ - raw += DNS_RDATASET_LENGTH; + count = get_uint16(raw); while (count-- > 0U) { dns_rdata_t rdata = DNS_RDATA_INIT; - length = raw[0] * 256 + raw[1]; - raw += DNS_RDATASET_LENGTH; + + length = get_uint16(raw); region.base = raw; region.length = length; raw += length; @@ -2617,14 +2616,12 @@ matchparams(dns_slabheader_t *header, qpz_search_t *search) { 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) { dns_rdata_t rdata = DNS_RDATA_INIT; - rdlen = raw[0] * 256 + raw[1]; - raw += DNS_RDATASET_LENGTH; + rdlen = get_uint16(raw); region.base = raw; region.length = rdlen; dns_rdata_fromregion(&rdata, search->qpdb->common.rdclass, diff --git a/lib/dns/rdataslab.c b/lib/dns/rdataslab.c index e2d054a588..48fd9962d1 100644 --- a/lib/dns/rdataslab.c +++ b/lib/dns/rdataslab.c @@ -49,19 +49,6 @@ * 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 diff --git a/lib/dns/rdataslab_p.h b/lib/dns/rdataslab_p.h index e3b4fbb573..2fed31a2f0 100644 --- a/lib/dns/rdataslab_p.h +++ b/lib/dns/rdataslab_p.h @@ -57,3 +57,16 @@ #define ZEROTTL(header) \ ((atomic_load_acquire(&(header)->attributes) & \ DNS_SLABHEADERATTR_ZEROTTL) != 0) + +#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); \ + }) From 727fb9a011cac7bdf5b0e97bf8b2f2c8814648a3 Mon Sep 17 00:00:00 2001 From: Evan Hunt Date: Sun, 17 Aug 2025 15:54:03 -0700 Subject: [PATCH 6/7] replace dns_slabheader_raw() with a flexible array member we can use header->raw instead of dns_slabheader_raw(). --- lib/dns/include/dns/rdataslab.h | 12 ++++++------ lib/dns/qpcache.c | 10 +++++----- lib/dns/qpzone.c | 4 ++-- lib/dns/rdataslab.c | 5 ----- 4 files changed, 13 insertions(+), 18 deletions(-) diff --git a/lib/dns/include/dns/rdataslab.h b/lib/dns/include/dns/rdataslab.h index 45bff01d1a..a292b4acd3 100644 --- a/lib/dns/include/dns/rdataslab.h +++ b/lib/dns/include/dns/rdataslab.h @@ -143,6 +143,12 @@ struct dns_slabheader { * 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 { @@ -278,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); /*%< diff --git a/lib/dns/qpcache.c b/lib/dns/qpcache.c index 7613105123..db285441c4 100644 --- a/lib/dns/qpcache.c +++ b/lib/dns/qpcache.c @@ -1072,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; @@ -2913,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, }; @@ -2952,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, }; diff --git a/lib/dns/qpzone.c b/lib/dns/qpzone.c index 3f2124546b..16f67d3ded 100644 --- a/lib/dns/qpzone.c +++ b/lib/dns/qpzone.c @@ -1042,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; @@ -1110,7 +1110,7 @@ setnsec3parameters(dns_db_t *db, qpz_version_t *version) { /* * Find an NSEC3PARAM with a supported algorithm. */ - raw = dns_slabheader_raw(found); + raw = found->raw; count = get_uint16(raw); while (count-- > 0U) { dns_rdata_t rdata = DNS_RDATA_INIT; diff --git a/lib/dns/rdataslab.c b/lib/dns/rdataslab.c index 48fd9962d1..2297418665 100644 --- a/lib/dns/rdataslab.c +++ b/lib/dns/rdataslab.c @@ -800,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)); From 80dac1bbae31fa947d70b6a5387ae6f68e4d8061 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Sur=C3=BD?= Date: Mon, 18 Aug 2025 08:05:33 +0200 Subject: [PATCH 7/7] Use ISC_UxxTOyy_BE macros for {peek,get,put}_uint16 macros Reduce the duplication and use existing macros from isc/endian.h for network to host and vice versa conversion. --- lib/dns/rdataslab_p.h | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/lib/dns/rdataslab_p.h b/lib/dns/rdataslab_p.h index 2fed31a2f0..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) \ @@ -58,15 +60,15 @@ ((atomic_load_acquire(&(header)->attributes) & \ DNS_SLABHEADERATTR_ZEROTTL) != 0) -#define peek_uint16(buffer) ({ ((uint16_t)*(buffer) << 8) | *((buffer) + 1); }) +#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) \ - ({ \ - *buffer++ = (val & 0xff00) >> 8; \ - *buffer++ = (val & 0x00ff); \ - }) +#define put_uint16(buffer, val) \ + { \ + ISC_U16TO8_BE(buffer, val); \ + (buffer) += sizeof(uint16_t); \ + }