]> git.ipfire.org Git - thirdparty/bind9.git/commitdiff
Add DNS_SLABTOP_FOREACH macros
authorOndřej Surý <ondrej@isc.org>
Thu, 21 Aug 2025 06:56:29 +0000 (08:56 +0200)
committerOndřej Surý <ondrej@isc.org>
Thu, 28 Aug 2025 17:28:55 +0000 (19:28 +0200)
Add foreach macros to iterate through the dns_slabtop_t
single-linked lists.

.clang-format
lib/dns/include/dns/rdataslab.h
lib/dns/qpcache.c
lib/dns/qpzone.c

index b26764d5d02f079bc6002c8a8a0ea26383f7a756..bab1c2c0a23ef7cd2918b3dd8819a74808134e1a 100644 (file)
@@ -79,7 +79,7 @@ PenaltyBreakString: 80
 PenaltyExcessCharacter: 100
 Standard: Cpp11
 ContinuationIndentWidth: 8
-ForEachMacros: [ 'cds_lfs_for_each', 'cds_lfs_for_each_safe', 'cds_list_for_each_entry_safe', 'ISC_LIST_FOREACH', 'ISC_LIST_FOREACH_SAFE', 'ISC_LIST_FOREACH_REV', 'ISC_LIST_FOREACH_REV_SAFE', 'MSG_SECTION_FOREACH', 'DNS_DBITERATOR_FOREACH', 'DNS_RDATASET_FOREACH', 'DNS_RDATASETITER_FOREACH', 'CFG_LIST_FOREACH' ]
+ForEachMacros: [ 'cds_lfs_for_each', 'cds_lfs_for_each_safe', 'cds_list_for_each_entry_safe', 'ISC_LIST_FOREACH', 'ISC_LIST_FOREACH_SAFE', 'ISC_LIST_FOREACH_REV', 'ISC_LIST_FOREACH_REV_SAFE', 'MSG_SECTION_FOREACH', 'DNS_DBITERATOR_FOREACH', 'DNS_RDATASET_FOREACH', 'DNS_RDATASETITER_FOREACH', 'CFG_LIST_FOREACH', 'DNS_SLABTOP_FOREACH' ]
 RemoveParentheses: ReturnStatement
 RemoveSemicolon: true
 SpaceBeforeParens: ControlStatementsExceptControlMacros
index a292b4acd35b8b2df9941c04d2cc5697d42041bf..8b6bd7ab041bcdc0c0854057a91f4225c0bca189 100644 (file)
@@ -64,6 +64,12 @@ struct dns_slabheader_proof {
        dns_rdatatype_t type;
 };
 
+#define DNS_SLABTOP_FOREACH(elt, first)                                    \
+       for (dns_slabtop_t *elt = first,                                   \
+                          *elt##_next = (elt != NULL) ? elt->next : NULL; \
+            elt != NULL;                                                  \
+            elt = elt##_next, elt##_next = (elt != NULL) ? elt->next : NULL)
+
 typedef struct dns_slabtop dns_slabtop_t;
 struct dns_slabtop {
        dns_slabtop_t    *next;
index fa2cfae7ac1f9b4c0a4bfe5e919a84060707cc9f..70c88a6788300f220eec338e519feea603c86da4 100644 (file)
@@ -559,14 +559,13 @@ clean_stale_headers(dns_slabheader_t *top) {
 
 static void
 clean_cache_node(qpcache_t *qpdb, qpcnode_t *node) {
-       dns_slabtop_t *top = NULL, *top_prev = NULL, *top_next = NULL;
+       dns_slabtop_t *top_prev = NULL;
 
        /*
         * Caller must be holding the node lock.
         */
 
-       for (top = node->data; top != NULL; top = top_next) {
-               top_next = top->next;
+       DNS_SLABTOP_FOREACH(top, node->data) {
                clean_stale_headers(top->header);
 
                /*
@@ -599,6 +598,7 @@ clean_cache_node(qpcache_t *qpdb, qpcnode_t *node) {
                        top_prev = top;
                }
        }
+
        node->dirty = 0;
 }
 
@@ -1275,7 +1275,6 @@ 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_slabtop_t *top = NULL;
        dns_slabheader_t *found = NULL, *foundsig = NULL;
        isc_result_t result;
        isc_rwlock_t *nlock = NULL;
@@ -1289,7 +1288,7 @@ check_zonecut(qpcnode_t *node, void *arg DNS__DB_FLARG) {
        /*
         * Look for a DNAME or RRSIG DNAME rdataset.
         */
-       for (top = node->data; top != NULL; top = top->next) {
+       DNS_SLABTOP_FOREACH(top, node->data) {
                if (check_stale_header(top->header, search)) {
                        continue;
                }
@@ -1339,7 +1338,6 @@ 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_slabtop_t *top = NULL;
                dns_slabheader_t *found = NULL, *foundsig = NULL;
                isc_rwlock_t *nlock = NULL;
                isc_rwlocktype_t nlocktype = isc_rwlocktype_none;
@@ -1352,7 +1350,7 @@ find_deepest_zonecut(qpc_search_t *search, qpcnode_t *node,
                /*
                 * Look for NS and RRSIG NS rdatasets.
                 */
-               for (top = node->data; top != NULL; top = top->next) {
+               DNS_SLABTOP_FOREACH(top, node->data) {
                        if (check_stale_header(top->header, search)) {
                                continue;
                        }
@@ -1415,7 +1413,6 @@ 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_slabtop_t *top = NULL;
 
        /*
         * Look for the node in the auxilary tree.
@@ -1456,7 +1453,7 @@ find_coveringnsec(qpc_search_t *search, const dns_name_t *name,
 
        nlock = &search->qpdb->buckets[node->locknum].lock;
        NODE_RDLOCK(nlock, &nlocktype);
-       for (top = node->data; top != NULL; top = top->next) {
+       DNS_SLABTOP_FOREACH(top, node->data) {
                if (check_stale_header(top->header, search)) {
                        continue;
                }
@@ -1534,7 +1531,6 @@ 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_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;
@@ -1657,7 +1653,7 @@ qpcache_find(dns_db_t *db, const dns_name_t *name, dns_dbversion_t *version,
        nsecsig = NULL;
        cnamesig = NULL;
        empty_node = true;
-       for (top = node->data; top != NULL; top = top->next) {
+       DNS_SLABTOP_FOREACH(top, node->data) {
                if (check_stale_header(top->header, &search)) {
                        continue;
                }
@@ -1917,14 +1913,13 @@ 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_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 (top = node->data; top != NULL; top = top->next) {
+       DNS_SLABTOP_FOREACH(top, node->data) {
                bool ns = top->typepair == DNS_TYPEPAIR(dns_rdatatype_ns) ||
                          top->typepair == DNS_SIGTYPEPAIR(dns_rdatatype_ns);
                if (check_stale_header(top->header, search)) {
@@ -2068,7 +2063,6 @@ 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_slabtop_t *top = NULL;
        dns_slabheader_t *found = NULL, *foundsig = NULL;
        dns_typepair_t typepair, sigpair;
        isc_result_t result = ISC_R_SUCCESS;
@@ -2095,7 +2089,7 @@ qpcache_findrdataset(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version,
        sigpair = (type != dns_rdatatype_rrsig) ? DNS_SIGTYPEPAIR(type)
                                                : dns_typepair_none;
 
-       for (top = qpnode->data; top != NULL; top = top->next) {
+       DNS_SLABTOP_FOREACH(top, qpnode->data) {
                if (check_stale_header(top->header, &search)) {
                        continue;
                }
@@ -2543,7 +2537,6 @@ static isc_result_t
 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_slabtop_t *top = NULL;
        dns_slabtop_t *priotop = NULL, *expiretop = NULL;
        dns_slabheader_t *header = NULL, *sigheader = NULL;
        dns_trust_t trust;
@@ -2586,9 +2579,7 @@ add(qpcache_t *qpdb, qpcnode_t *qpnode, dns_slabheader_t *newheader,
                                 * only rdataset that can be found at this
                                 * node is the negative cache entry.
                                 */
-                               for (top = qpnode->data; top != NULL;
-                                    top = top->next)
-                               {
+                               DNS_SLABTOP_FOREACH(top, qpnode->data) {
                                        mark_ancient(top->header);
                                }
                                goto find_header;
@@ -2602,9 +2593,7 @@ add(qpcache_t *qpdb, qpcnode_t *qpnode, dns_slabheader_t *newheader,
                                 * above, but just for RRSIGs.
                                 */
 
-                               for (top = qpnode->data; top != NULL;
-                                    top = top->next)
-                               {
+                               DNS_SLABTOP_FOREACH(top, qpnode->data) {
                                        if (DNS_TYPEPAIR_TYPE(top->typepair) ==
                                            dns_rdatatype_rrsig)
                                        {
@@ -2618,18 +2607,19 @@ add(qpcache_t *qpdb, qpcnode_t *qpnode, dns_slabheader_t *newheader,
                         * Otherwise look for any RRSIGs of the given
                         * type so they can be marked ancient later.
                         */
-                       for (top = qpnode->data; top != NULL; top = top->next) {
+                       DNS_SLABTOP_FOREACH(top, qpnode->data) {
                                if (top->typepair == sigpair) {
                                        sigheader = top->header;
                                        break;
                                }
                        }
                } else {
+                       dns_slabtop_t *foundtop = NULL;
                        /*
                         * We're adding something that isn't a
                         * negative cache entry.
                         */
-                       for (top = qpnode->data; top != NULL; top = top->next) {
+                       DNS_SLABTOP_FOREACH(top, qpnode->data) {
                                /*
                                 * Look for any existing negative cache
                                 * entries.
@@ -2643,33 +2633,36 @@ add(qpcache_t *qpdb, qpcnode_t *qpnode, dns_slabheader_t *newheader,
                                 * cache anything else.
                                 */
                                if (top->typepair == dns_typepair_any) {
+                                       foundtop = top;
                                        break;
                                }
 
                                /*
-                                * Don't cache an RRSIG if it cover a type
+                                * Don't cache an RRSIG if it covers a type
                                 * for which we have a cached NODATA record.
                                 */
                                if (newheader->typepair == sigpair &&
                                    DNS_TYPEPAIR_TYPE(top->typepair) == covers)
                                {
+                                       foundtop = top;
                                        break;
                                }
                        }
-                       if (top != NULL && EXISTS(top->header) &&
-                           ACTIVE(top->header, now))
+
+                       if (foundtop != NULL && EXISTS(foundtop->header) &&
+                           ACTIVE(foundtop->header, now))
                        {
                                /*
                                 * Found one.
                                 */
-                               if (trust < top->header->trust) {
+                               if (trust < foundtop->header->trust) {
                                        /*
                                         * The NXDOMAIN/NODATA(QTYPE=ANY)
                                         * is more trusted.
                                         */
                                        bindrdataset(
-                                               qpdb, qpnode, top->header, now,
-                                               nlocktype, tlocktype,
+                                               qpdb, qpnode, foundtop->header,
+                                               now, nlocktype, tlocktype,
                                                addedrdataset
                                                        DNS__DB_FLARG_PASS);
                                        return DNS_R_UNCHANGED;
@@ -2678,14 +2671,13 @@ add(qpcache_t *qpdb, qpcnode_t *qpnode, dns_slabheader_t *newheader,
                                 * The new rdataset is better.  Expire the
                                 * ncache entry.
                                 */
-                               mark_ancient(top->header);
-                               top = NULL;
+                               mark_ancient(foundtop->header);
                                goto find_header;
                        }
                }
        }
 
-       for (top = qpnode->data; top != NULL; top = top->next) {
+       DNS_SLABTOP_FOREACH(top, qpnode->data) {
                if (ACTIVE(top->header, now)) {
                        ++ntypes;
                        expiretop = top;
@@ -2695,16 +2687,17 @@ add(qpcache_t *qpdb, qpcnode_t *qpnode, dns_slabheader_t *newheader,
                }
 
                if (top->typepair == newheader->typepair) {
+                       header = top->header;
                        break;
                }
        }
 
 find_header:
-       /*
-        * If top isn't NULL, we've found the right type.
-        */
-       if (top != NULL) {
-               header = top->header;
+       if (header != NULL) {
+               /*
+                * We've found the right type.
+                */
+
                /*
                 * Deleting an already non-existent rdataset has no effect.
                 */
@@ -2737,13 +2730,13 @@ find_header:
                 * further down.
                 */
                if (ACTIVE(header, now) &&
-                   top->typepair == DNS_TYPEPAIR(dns_rdatatype_ns) &&
+                   header->typepair == DNS_TYPEPAIR(dns_rdatatype_ns) &&
                    EXISTS(header) && EXISTS(newheader) &&
                    header->trust >= newheader->trust &&
                    header->expire < newheader->expire &&
                    dns_rdataslab_equalx(header, newheader,
                                         qpdb->common.rdclass,
-                                        DNS_TYPEPAIR_TYPE(top->typepair)))
+                                        DNS_TYPEPAIR_TYPE(header->typepair)))
                {
                        qpcache_hit(qpdb, header);
 
@@ -2771,7 +2764,7 @@ find_header:
                 * ensures the delegations that are withdrawn are honoured.
                 */
                if (ACTIVE(header, now) &&
-                   top->typepair == DNS_TYPEPAIR(dns_rdatatype_ns) &&
+                   header->typepair == DNS_TYPEPAIR(dns_rdatatype_ns) &&
                    EXISTS(header) && EXISTS(newheader) &&
                    header->trust <= newheader->trust)
                {
@@ -2786,10 +2779,10 @@ find_header:
                }
                if (ACTIVE(header, now) &&
                    (options & DNS_DBADD_PREFETCH) == 0 &&
-                   (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)) &&
+                   (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)) &&
                    EXISTS(header) && EXISTS(newheader) &&
                    header->trust >= newheader->trust &&
                    header->expire < newheader->expire &&
@@ -2815,12 +2808,12 @@ find_header:
                        return DNS_R_UNCHANGED;
                }
 
-               top->header = newheader;
-               newheader->top = top;
+               header->top->header = newheader;
+               newheader->top = header->top;
                newheader->down = header;
 
-               ISC_SIEVE_UNLINK(qpdb->buckets[qpnode->locknum].sieve, top,
-                                link);
+               ISC_SIEVE_UNLINK(qpdb->buckets[qpnode->locknum].sieve,
+                                header->top, link);
 
                qpcache_miss(qpdb, newheader, &nlocktype,
                             &tlocktype DNS__DB_FLARG_PASS);
@@ -3334,26 +3327,26 @@ 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_slabtop_t *top = NULL;
        isc_rwlocktype_t nlocktype = isc_rwlocktype_none;
        isc_rwlock_t *nlock = &qpdb->buckets[qpnode->locknum].lock;
 
+       iterator->current = NULL;
+
        NODE_RDLOCK(nlock, &nlocktype);
 
-       for (top = qpnode->data; top != NULL; top = top->next) {
+       DNS_SLABTOP_FOREACH(top, qpnode->data) {
                if (EXISTS(top->header) &&
                    (EXPIREDOK(iterator) ||
                     iterator_active(qpdb, iterator, top->header)))
                {
+                       iterator->current = top;
                        break;
                }
        }
 
        NODE_UNLOCK(nlock, &nlocktype);
 
-       iterator->current = top;
-
-       if (top == NULL) {
+       if (iterator->current == NULL) {
                return ISC_R_NOMORE;
        }
 
@@ -3365,31 +3358,31 @@ 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_slabtop_t *top = NULL;
        isc_rwlocktype_t nlocktype = isc_rwlocktype_none;
        isc_rwlock_t *nlock = &qpdb->buckets[qpnode->locknum].lock;
+       dns_slabtop_t *next = NULL;
 
-       top = iterator->current;
-       if (top == NULL) {
+       if (iterator->current == NULL) {
                return ISC_R_NOMORE;
        }
+       next = iterator->current->next;
+       iterator->current = NULL;
 
        NODE_RDLOCK(nlock, &nlocktype);
 
-       for (top = top->next; top != NULL; top = top->next) {
+       DNS_SLABTOP_FOREACH(top, next) {
                if (EXISTS(top->header) &&
                    (EXPIREDOK(iterator) ||
                     iterator_active(qpdb, iterator, top->header)))
                {
+                       iterator->current = top;
                        break;
                }
        }
 
        NODE_UNLOCK(nlock, &nlocktype);
 
-       iterator->current = top;
-
-       if (top == NULL) {
+       if (iterator->current == NULL) {
                return ISC_R_NOMORE;
        }
 
@@ -3851,12 +3844,9 @@ static dns_dbmethods_t qpdb_cachemethods = {
 
 static void
 qpcnode_destroy(qpcnode_t *qpnode) {
-       dns_slabtop_t *top = NULL, *top_next = NULL;
        qpcache_t *qpdb = qpnode->qpdb;
 
-       for (top = qpnode->data; top != NULL; top = top_next) {
-               top_next = top->next;
-
+       DNS_SLABTOP_FOREACH(top, qpnode->data) {
                dns_slabheader_t *down = NULL, *down_next = NULL;
                for (down = top->header; down != NULL; down = down_next) {
                        down_next = down->down;
index 247434d3ace5564ec4640c5068e77100aea1d8cc..1c28adfb7d4aee13bf60f628fd516eed712851bd 100644 (file)
@@ -814,7 +814,7 @@ qpznode_acquire(qpznode_t *node DNS__DB_FLARG) {
 
 static void
 clean_zone_node(qpznode_t *node, uint32_t least_serial) {
-       dns_slabtop_t *top = NULL, *top_prev = NULL, *top_next = NULL;
+       dns_slabtop_t *top_prev = NULL;
        bool still_dirty = false;
 
        /*
@@ -822,9 +822,7 @@ clean_zone_node(qpznode_t *node, uint32_t least_serial) {
         */
        REQUIRE(least_serial != 0);
 
-       for (top = node->data; top != NULL; top = top_next) {
-               top_next = top->next;
-
+       DNS_SLABTOP_FOREACH(top, node->data) {
                INSIST(top->header != NULL);
 
                /*
@@ -1285,7 +1283,6 @@ make_least_version(qpzonedb_t *qpdb, qpz_version_t *version,
 
 static void
 rollback_node(qpznode_t *node, uint32_t serial) {
-       dns_slabtop_t *top = NULL;
        bool make_dirty = false;
 
        /*
@@ -1293,7 +1290,7 @@ 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 (top = node->data; top != NULL; top = top->next) {
+       DNS_SLABTOP_FOREACH(top, node->data) {
                dns_slabheader_t *header = top->header;
 
                if (header->serial == serial) {
@@ -1554,7 +1551,6 @@ 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_slabtop_t *top = NULL;
        dns_slabheader_t *found = NULL, *foundsig = NULL;
        uint32_t serial;
        qpz_version_t *version = (qpz_version_t *)dbversion;
@@ -1587,7 +1583,7 @@ qpzone_findrdataset(dns_db_t *db, dns_dbnode_t *dbnode,
                sigpair = dns_typepair_none;
        }
 
-       for (top = node->data; top != NULL; top = top->next) {
+       DNS_SLABTOP_FOREACH(top, node->data) {
                dns_slabheader_t *header = top->header;
                do {
                        if (header->serial <= serial && !IGNORE(header)) {
@@ -1708,14 +1704,13 @@ static bool
 cname_and_other(qpznode_t *node, uint32_t serial) {
        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 (top = node->data; top != NULL; top = top->next) {
+       DNS_SLABTOP_FOREACH(top, node->data) {
                dns_slabheader_t *header = top->header;
 
                rdtype = DNS_TYPEPAIR_TYPE(top->typepair);
@@ -1819,7 +1814,7 @@ 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_slabtop_t *top = NULL;
+       dns_slabtop_t *foundtop = NULL;
        dns_slabtop_t *priotop = NULL;
        dns_slabheader_t *merged = NULL;
        isc_result_t result;
@@ -1842,12 +1837,13 @@ add(qpzonedb_t *qpdb, qpznode_t *node, const dns_name_t *nodename,
        }
 
        ntypes = 0;
-       for (top = node->data; top != NULL; top = top->next) {
+       DNS_SLABTOP_FOREACH(top, node->data) {
                ++ntypes;
                if (prio_type(top->typepair)) {
                        priotop = top;
                }
                if (top->typepair == newheader->typepair) {
+                       foundtop = top;
                        break;
                }
        }
@@ -1858,8 +1854,8 @@ add(qpzonedb_t *qpdb, qpznode_t *node, const dns_name_t *nodename,
         * data.  We skip over them.
         */
        dns_slabheader_t *header = NULL, *header_prev = NULL;
-       if (top != NULL) {
-               header = top->header;
+       if (foundtop != NULL) {
+               header = foundtop->header;
                while (header != NULL && IGNORE(header)) {
                        header_prev = header;
                        header = header->down;
@@ -1930,8 +1926,8 @@ add(qpzonedb_t *qpdb, qpznode_t *node, const dns_name_t *nodename,
                        }
                }
 
-               INSIST(version->serial >= top->header->serial);
-               INSIST(top->typepair == newheader->typepair);
+               INSIST(version->serial >= foundtop->header->serial);
+               INSIST(foundtop->typepair == newheader->typepair);
 
                if (loading) {
                        newheader->down = NULL;
@@ -1946,8 +1942,8 @@ 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.
                         */
-                       newheader->top = top;
-                       top->header = newheader;
+                       newheader->top = foundtop;
+                       foundtop->header = newheader;
                        maybe_update_recordsandsize(false, version, header,
                                                    nodename->length);
 
@@ -1962,10 +1958,10 @@ add(qpzonedb_t *qpdb, qpznode_t *node, const dns_name_t *nodename,
                        if (header_prev != NULL) {
                                header_prev->down = newheader;
                        } else {
-                               top->header = newheader;
+                               foundtop->header = newheader;
                        }
 
-                       newheader->top = top;
+                       newheader->top = foundtop;
                        newheader->down = header;
 
                        node->dirty = true;
@@ -1992,7 +1988,7 @@ add(qpzonedb_t *qpdb, qpznode_t *node, const dns_name_t *nodename,
                        resigndelete(qpdb, version, header DNS__DB_FLARG_PASS);
                }
 
-               if (top != NULL) {
+               if (foundtop != NULL) {
                        /*
                         * We have a list of rdatasets of the given type,
                         * but they're all marked IGNORE.  We simply insert
@@ -2002,10 +1998,10 @@ add(qpzonedb_t *qpdb, qpznode_t *node, const dns_name_t *nodename,
                         * we INSIST on it.
                         */
                        INSIST(!loading);
-                       INSIST(version->serial >= top->header->serial);
-                       newheader->top = top;
-                       newheader->down = top->header;
-                       top->header = newheader;
+                       INSIST(version->serial >= foundtop->header->serial);
+                       newheader->top = foundtop;
+                       newheader->down = foundtop->header;
+                       foundtop->header = newheader;
                        if (changed != NULL) {
                                changed->dirty = true;
                        }
@@ -2673,11 +2669,10 @@ step(qpz_search_t *search, dns_qpiter_t *it, direction_t direction,
        while (result == ISC_R_SUCCESS) {
                isc_rwlock_t *nlock = qpzone_get_lock(node);
                isc_rwlocktype_t nlocktype = isc_rwlocktype_none;
-               dns_slabtop_t *top = NULL;
                dns_slabheader_t *found = NULL;
 
                NODE_RDLOCK(nlock, &nlocktype);
-               for (top = node->data; top != NULL; top = top->next) {
+               DNS_SLABTOP_FOREACH(top, node->data) {
                        dns_slabheader_t *header = top->header;
                        while (header != NULL &&
                               (IGNORE(header) ||
@@ -2810,7 +2805,6 @@ 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_slabtop_t *top = NULL;
        dns_slabheader_t *found = NULL;
        isc_result_t result = ISC_R_NOTFOUND;
 
@@ -2839,7 +2833,7 @@ 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 (top = node->data; top != NULL; top = top->next) {
+               DNS_SLABTOP_FOREACH(top, node->data) {
                        dns_slabheader_t *header = top->header;
                        if (header->serial <= search->serial &&
                            !IGNORE(header) && EXISTS(header))
@@ -2879,9 +2873,7 @@ find_wildcard(qpz_search_t *search, qpznode_t **nodep, const dns_name_t *qname,
                                 */
                                nlock = qpzone_get_lock(wnode);
                                NODE_RDLOCK(nlock, &nlocktype);
-                               for (top = wnode->data; top != NULL;
-                                    top = top->next)
-                               {
+                               DNS_SLABTOP_FOREACH(top, wnode->data) {
                                        dns_slabheader_t *header = top->header;
                                        if (header->serial <= search->serial &&
                                            !IGNORE(header) && EXISTS(header))
@@ -3055,13 +3047,12 @@ 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 (top = node->data; top != NULL; top = top->next) {
+               DNS_SLABTOP_FOREACH(top, node->data) {
                        dns_slabheader_t *header = top->header;
                        /*
                         * Look for an active, extant NSEC or RRSIG NSEC.
@@ -3192,7 +3183,6 @@ again:
 static isc_result_t
 qpzone_check_zonecut(qpznode_t *node, void *arg DNS__DB_FLARG) {
        qpz_search_t *search = arg;
-       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;
@@ -3205,7 +3195,7 @@ qpzone_check_zonecut(qpznode_t *node, void *arg DNS__DB_FLARG) {
        /*
         * Look for an NS or DNAME rdataset active in our version.
         */
-       for (top = node->data; top != NULL; top = top->next) {
+       DNS_SLABTOP_FOREACH(top, node->data) {
                dns_slabheader_t *header = top->header;
                if (top->typepair == DNS_TYPEPAIR(dns_rdatatype_ns) ||
                    top->typepair == DNS_TYPEPAIR(dns_rdatatype_dname) ||
@@ -3358,7 +3348,6 @@ 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_slabtop_t *top = NULL;
        dns_slabheader_t *found = NULL, *nsecheader = NULL;
        dns_slabheader_t *foundsig = NULL, *cnamesig = NULL, *nsecsig = NULL;
        dns_typepair_t sigpair;
@@ -3536,7 +3525,7 @@ found:
 
        sigpair = DNS_SIGTYPEPAIR(type);
        empty_node = true;
-       for (top = node->data; top != NULL; top = top->next) {
+       DNS_SLABTOP_FOREACH(top, node->data) {
                dns_slabheader_t *header = top->header;
                /*
                 * Look for an active, extant rdataset.
@@ -4044,12 +4033,13 @@ rdatasetiter_first(dns_rdatasetiter_t *iterator DNS__DB_FLARG) {
        qpz_version_t *version = (qpz_version_t *)qrditer->common.version;
        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;
+
+       qrditer->currenttop = NULL;
+       qrditer->current = NULL;
 
        NODE_RDLOCK(nlock, &nlocktype);
 
-       for (top = node->data; top != NULL; top = top->next) {
+       DNS_SLABTOP_FOREACH(top, node->data) {
                dns_slabheader_t *header = top->header;
                while (header != NULL &&
                       (IGNORE(header) || header->serial > version->serial))
@@ -4058,17 +4048,15 @@ rdatasetiter_first(dns_rdatasetiter_t *iterator DNS__DB_FLARG) {
                }
 
                if (header != NULL && EXISTS(header)) {
-                       found = header;
+                       qrditer->currenttop = top;
+                       qrditer->current = header;
                        break;
                }
        }
 
        NODE_UNLOCK(nlock, &nlocktype);
 
-       qrditer->currenttop = top;
-       qrditer->current = found;
-
-       if (top == NULL) {
+       if (qrditer->currenttop == NULL) {
                return ISC_R_NOMORE;
        }
 
@@ -4082,19 +4070,21 @@ rdatasetiter_next(dns_rdatasetiter_t *iterator DNS__DB_FLARG) {
        qpz_version_t *version = (qpz_version_t *)qrditer->common.version;
        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;
+       dns_slabtop_t *next = NULL;
 
-       if (top == NULL) {
+       if (qrditer->currenttop == NULL) {
                return ISC_R_NOMORE;
        }
+       next = qrditer->currenttop->next;
+       qrditer->currenttop = NULL;
+       qrditer->current = NULL;
 
        NODE_RDLOCK(nlock, &nlocktype);
 
        /*
         * Find the start of the header chain for the next type.
         */
-       for (top = top->next; top != NULL; top = top->next) {
+       DNS_SLABTOP_FOREACH(top, next) {
                dns_slabheader_t *header = top->header;
                while (header != NULL &&
                       (IGNORE(header) || header->serial > version->serial))
@@ -4103,17 +4093,15 @@ rdatasetiter_next(dns_rdatasetiter_t *iterator DNS__DB_FLARG) {
                }
 
                if (header != NULL && EXISTS(header)) {
-                       found = header;
+                       qrditer->currenttop = top;
+                       qrditer->current = header;
                        break;
                }
        }
 
        NODE_UNLOCK(nlock, &nlocktype);
 
-       qrditer->currenttop = top;
-       qrditer->current = found;
-
-       if (top == NULL) {
+       if (qrditer->currenttop == NULL) {
                return ISC_R_NOMORE;
        }
 
@@ -4837,7 +4825,7 @@ 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_slabtop_t *top = NULL;
+       dns_slabtop_t *foundtop = NULL;
        dns_slabheader_t *newheader = NULL;
        dns_slabheader_t *subresult = NULL;
        isc_region_t region;
@@ -4881,8 +4869,9 @@ qpzone_subtractrdataset(dns_db_t *db, dns_dbnode_t *dbnode,
        NODE_WRLOCK(nlock, &nlocktype);
 
        changed = add_changed(qpdb, newheader, version DNS__DB_FLARG_PASS);
-       for (top = node->data; top != NULL; top = top->next) {
+       DNS_SLABTOP_FOREACH(top, node->data) {
                if (top->typepair == newheader->typepair) {
+                       foundtop = top;
                        break;
                }
        }
@@ -4892,8 +4881,8 @@ qpzone_subtractrdataset(dns_db_t *db, dns_dbnode_t *dbnode,
         * data.  We skip over them.
         */
        dns_slabheader_t *header = NULL;
-       if (top != NULL) {
-               header = top->header;
+       if (foundtop != NULL) {
+               header = foundtop->header;
                while (header != NULL && IGNORE(header)) {
                        header = header->down;
                }
@@ -4912,7 +4901,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(top->typepair), flags,
+                               DNS_TYPEPAIR_TYPE(foundtop->typepair), flags,
                                &subresult);
                }
                if (result == ISC_R_SUCCESS) {
@@ -4949,7 +4938,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 = top->typepair;
+                       newheader->typepair = foundtop->typepair;
                        atomic_init(&newheader->attributes,
                                    DNS_SLABHEADERATTR_NONEXISTENT);
                        newheader->serial = version->serial;
@@ -4961,13 +4950,13 @@ qpzone_subtractrdataset(dns_db_t *db, dns_dbnode_t *dbnode,
                /*
                 * If we're here, we want to link newheader at the top.
                 */
-               INSIST(version->serial >= top->header->serial);
+               INSIST(version->serial >= foundtop->header->serial);
                maybe_update_recordsandsize(false, version, header,
                                            nodename->length);
 
-               newheader->top = top;
-               newheader->down = top->header;
-               top->header = newheader;
+               newheader->top = foundtop;
+               newheader->down = foundtop->header;
+               foundtop->header = newheader;
 
                node->dirty = true;
                changed->dirty = true;
@@ -5433,11 +5422,7 @@ static dns_dbnode_methods_t qpznode_methods = (dns_dbnode_methods_t){
 
 static void
 destroy_qpznode(qpznode_t *node) {
-       dns_slabtop_t *top = NULL, *top_next = NULL;
-
-       for (top = node->data; top != NULL; top = top_next) {
-               top_next = top->next;
-
+       DNS_SLABTOP_FOREACH(top, node->data) {
                dns_slabheader_t *down = NULL, *down_next = NULL;
                for (down = top->header; down != NULL; down = down_next) {
                        down_next = down->down;