]> git.ipfire.org Git - thirdparty/bind9.git/commitdiff
2059. [bug] Search into cache rbtdb could trigger an INSIST
authorMark Andrews <marka@isc.org>
Mon, 24 Jul 2006 01:23:11 +0000 (01:23 +0000)
committerMark Andrews <marka@isc.org>
Mon, 24 Jul 2006 01:23:11 +0000 (01:23 +0000)
                        failure while cleaning up a stale rdataset.
                        [RT #16292]

CHANGES
lib/dns/rbtdb.c

diff --git a/CHANGES b/CHANGES
index 48e9e6f329dfe6f5cce51961119989453eafcd3a..70ce6e30ad27f8e89e3c63bba0af761685a0fe9c 100644 (file)
--- a/CHANGES
+++ b/CHANGES
@@ -1,3 +1,7 @@
+2059.  [bug]           Search into cache rbtdb could trigger an INSIST
+                       failure while cleaning up a stale rdataset.
+                       [RT #16292]
+
 2058.  [bug]           Adjust how we calculate rtt estimates in the presence
                        of authoritative servers that drop EDNS and/or CD
                        requests.  Also fallback to EDNS/512 and plain DNS
 2046.  [bug]           rbtdb.c:rdataset_setadditional() could cause duplicate
                        cleanup [RT #16247].
 
-2045.  [func]          use lock buckets for acache entries to limit memory
+2045.  [func]          Use lock buckets for acache entries to limit memory
                        consumption. [RT #16183]
 
-2044.  [port]          add support for atomic operations for Itanium.
+2044.  [port]          Add support for atomic operations for Itanium.
                        [RT #16179]
 
 2043.  [port]          nsupdate/nslookup: Force the flushing of the prompt
index 91ba5208cf3ae9372c1a4a1806971bb58bba9576..03204ee4d703ef69e9aee28faf59652038dfa564 100644 (file)
@@ -15,7 +15,7 @@
  * PERFORMANCE OF THIS SOFTWARE.
  */
 
-/* $Id: rbtdb.c,v 1.196.18.38 2006/07/06 06:43:26 jinmei Exp $ */
+/* $Id: rbtdb.c,v 1.196.18.39 2006/07/24 01:23:11 marka Exp $ */
 
 /*! \file */
 
@@ -944,9 +944,20 @@ rollback_node(dns_rbtnode_t *node, rbtdb_serial_t serial) {
                node->dirty = 1;
 }
 
+static inline void
+clean_stale_headers(isc_mem_t *mctx, rdatasetheader_t *top) {
+       rdatasetheader_t *d, *down_next;
+
+       for (d = top->down; d != NULL; d = down_next) {
+               down_next = d->down;
+               free_rdataset(mctx, d);
+       }
+       top->down = NULL;
+}
+
 static inline void
 clean_cache_node(dns_rbtdb_t *rbtdb, dns_rbtnode_t *node) {
-       rdatasetheader_t *current, *dcurrent, *top_prev, *top_next, *down_next;
+       rdatasetheader_t *current, *top_prev, *top_next;
        isc_mem_t *mctx = rbtdb->common.mctx;
 
        /*
@@ -956,15 +967,7 @@ clean_cache_node(dns_rbtdb_t *rbtdb, dns_rbtnode_t *node) {
        top_prev = NULL;
        for (current = node->data; current != NULL; current = top_next) {
                top_next = current->next;
-               dcurrent = current->down;
-               if (dcurrent != NULL) {
-                       do {
-                               down_next = dcurrent->down;
-                               free_rdataset(mctx, dcurrent);
-                               dcurrent = down_next;
-                       } while (dcurrent != NULL);
-                       current->down = NULL;
-               }
+               clean_stale_headers(mctx, current);
                /*
                 * If current is nonexistent or stale, we can clean it up.
                 */
@@ -3000,14 +3003,24 @@ cache_zonecut_callback(dns_rbtnode_t *node, dns_name_t *name, void *arg) {
                                locktype = isc_rwlocktype_write;
 
                                if (dns_rbtnode_refcurrent(node) == 0) {
-                                       INSIST(header->down == NULL);
+                                       isc_mem_t *mctx;
+
+                                       /*
+                                        * header->down can be NULL if the
+                                        * refcount has just decremented to 0
+                                        * but no_references() has not
+                                        * performed clean_cache_node(), in
+                                        * which case we need to purge the
+                                        * stale headers first.
+                                        */
+                                       mctx = search->rbtdb->common.mctx;
+                                       clean_stale_headers(mctx, header);
                                        if (header_prev != NULL)
                                                header_prev->next =
                                                        header->next;
                                        else
                                                node->data = header->next;
-                                       free_rdataset(search->rbtdb->common.mctx,
-                                                     header);
+                                       free_rdataset(mctx, header);
                                } else {
                                        header->attributes |=
                                                RDATASET_ATTR_STALE;
@@ -3107,15 +3120,17 @@ find_deepest_zonecut(rbtdb_search_t *search, dns_rbtnode_t *node,
 
                                        if (dns_rbtnode_refcurrent(node)
                                            == 0) {
-                                               INSIST(header->down == NULL);
+                                               isc_mem_t *m;
+
+                                               m = search->rbtdb->common.mctx;
+                                               clean_stale_headers(m, header);
                                                if (header_prev != NULL)
                                                        header_prev->next =
                                                                header->next;
                                                else
                                                        node->data =
                                                                header->next;
-                                               free_rdataset(search->rbtdb->common.mctx,
-                                                             header);
+                                               free_rdataset(m, header);
                                        } else {
                                                header->attributes |=
                                                        RDATASET_ATTR_STALE;
@@ -3260,14 +3275,16 @@ find_coveringnsec(rbtdb_search_t *search, dns_dbnode_t **nodep,
 
                                        if (dns_rbtnode_refcurrent(node)
                                            == 0) {
-                                               INSIST(header->down == NULL);
+                                               isc_mem_t *m;
+
+                                               m = search->rbtdb->common.mctx;
+                                               clean_stale_headers(m, header);
                                                if (header_prev != NULL)
                                                        header_prev->next =
                                                                header->next;
                                                else
                                                        node->data = header->next;
-                                               free_rdataset(search->rbtdb->common.mctx,
-                                                             header);
+                                               free_rdataset(m, header);
                                        } else {
                                                header->attributes |=
                                                        RDATASET_ATTR_STALE;
@@ -3431,14 +3448,16 @@ cache_find(dns_db_t *db, dns_name_t *name, dns_dbversion_t *version,
                                locktype = isc_rwlocktype_write;
 
                                if (dns_rbtnode_refcurrent(node) == 0) {
-                                       INSIST(header->down == NULL);
+                                       isc_mem_t *mctx;
+
+                                       mctx = search.rbtdb->common.mctx;
+                                       clean_stale_headers(mctx, header);
                                        if (header_prev != NULL)
                                                header_prev->next =
                                                        header->next;
                                        else
                                                node->data = header->next;
-                                       free_rdataset(search.rbtdb->common.mctx,
-                                                     header);
+                                       free_rdataset(mctx, header);
                                } else {
                                        header->attributes |=
                                                RDATASET_ATTR_STALE;
@@ -3720,14 +3739,16 @@ cache_findzonecut(dns_db_t *db, dns_name_t *name, unsigned int options,
                                locktype = isc_rwlocktype_write;
 
                                if (dns_rbtnode_refcurrent(node) == 0) {
-                                       INSIST(header->down == NULL);
+                                       isc_mem_t *mctx;
+
+                                       mctx = search.rbtdb->common.mctx;
+                                       clean_stale_headers(mctx, header);
                                        if (header_prev != NULL)
                                                header_prev->next =
                                                        header->next;
                                        else
                                                node->data = header->next;
-                                       free_rdataset(search.rbtdb->common.mctx,
-                                                     header);
+                                       free_rdataset(mctx, header);
                                } else {
                                        header->attributes |=
                                                RDATASET_ATTR_STALE;