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)); +}