]> git.ipfire.org Git - thirdparty/bind9.git/commitdiff
Rewrite the GLUE cache in QP zone database
authorOndřej Surý <ondrej@isc.org>
Thu, 5 Dec 2024 12:45:24 +0000 (13:45 +0100)
committerOndřej Surý <ondrej@isc.org>
Mon, 6 Jan 2025 13:00:47 +0000 (14:00 +0100)
This is a second attempt to rewrite the GLUE cache to not use per
database version hash table.  Instead of keeping a hash table indexed by
the node, use a directly linked list of GLUE records for each
slabheader.  This was attempted before, but there was a data race caused
by the fact that the thread cleaning the GLUE records could be slower
than accessing the slab headers again and reinitializing the wait-free
stack.

The improved design builds on the previous design, but adds a new
dns_gluelist structure that has a pointer to the database version.

If a dns_gluelist belonging to a different (old) version is detected, it
is just detached from the slabheader and left for the closeversion() to
clean it up later.

(cherry picked from commit 29bde687b5736261f6498a78851c628af93a4277)

lib/dns/db.c
lib/dns/db_p.h
lib/dns/include/dns/rdataslab.h
lib/dns/include/dns/types.h
lib/dns/qpzone.c
lib/dns/rbt-zonedb.c
lib/dns/rbtdb.c
lib/dns/rdataslab.c

index 43edbb76a47357d0a931204ee9915607d7621cb1..1567111d206bff50c9807755fc0b6d9c734d7ef6 100644 (file)
@@ -41,6 +41,8 @@
 #include <dns/rdataclass.h>
 #include <dns/rdataset.h>
 #include <dns/rdatasetiter.h>
+#include <dns/rdataslab.h>
+#include <dns/stats.h>
 
 /***
  *** Private Types
@@ -1214,3 +1216,260 @@ dns__db_logtoomanyrecords(dns_db_t *db, const dns_name_t *name,
                (db->attributes & DNS_DBATTR_CACHE) != 0 ? "cache" : "zone",
                isc_result_totext(DNS_R_TOOMANYRECORDS), limit);
 }
+
+void
+dns__db_free_glue(isc_mem_t *mctx, dns_glue_t *glue) {
+       while (glue != NULL) {
+               dns_glue_t *next = glue->next;
+
+               if (dns_rdataset_isassociated(&glue->rdataset_a)) {
+                       dns_rdataset_disassociate(&glue->rdataset_a);
+               }
+               if (dns_rdataset_isassociated(&glue->sigrdataset_a)) {
+                       dns_rdataset_disassociate(&glue->sigrdataset_a);
+               }
+
+               if (dns_rdataset_isassociated(&glue->rdataset_aaaa)) {
+                       dns_rdataset_disassociate(&glue->rdataset_aaaa);
+               }
+               if (dns_rdataset_isassociated(&glue->sigrdataset_aaaa)) {
+                       dns_rdataset_disassociate(&glue->sigrdataset_aaaa);
+               }
+
+               dns_rdataset_invalidate(&glue->rdataset_a);
+               dns_rdataset_invalidate(&glue->sigrdataset_a);
+               dns_rdataset_invalidate(&glue->rdataset_aaaa);
+               dns_rdataset_invalidate(&glue->sigrdataset_aaaa);
+
+               dns_name_free(&glue->name, mctx);
+
+               isc_mem_put(mctx, glue, sizeof(*glue));
+
+               glue = next;
+       }
+}
+
+void
+dns__db_destroy_gluelist(dns_gluelist_t **gluelistp) {
+       REQUIRE(gluelistp != NULL);
+       if (*gluelistp == NULL) {
+               return;
+       }
+
+       dns_gluelist_t *gluelist = *gluelistp;
+
+       dns__db_free_glue(gluelist->mctx, gluelist->glue);
+
+       isc_mem_putanddetach(&gluelist->mctx, gluelist, sizeof(*gluelist));
+}
+
+void
+dns__db_free_gluelist_rcu(struct rcu_head *rcu_head) {
+       dns_gluelist_t *gluelist = caa_container_of(rcu_head, dns_gluelist_t,
+                                                   rcu_head);
+       dns__db_destroy_gluelist(&gluelist);
+}
+
+void
+dns__db_cleanup_gluelists(struct cds_wfs_stack *glue_stack) {
+       struct cds_wfs_head *head = __cds_wfs_pop_all(glue_stack);
+       struct cds_wfs_node *node = NULL, *next = NULL;
+
+       rcu_read_lock();
+       cds_wfs_for_each_blocking_safe(head, node, next) {
+               dns_gluelist_t *gluelist =
+                       caa_container_of(node, dns_gluelist_t, wfs_node);
+               dns_slabheader_t *header = rcu_xchg_pointer(&gluelist->header,
+                                                           NULL);
+               (void)rcu_cmpxchg_pointer(&header->gluelist, gluelist, NULL);
+
+               call_rcu(&gluelist->rcu_head, dns__db_free_gluelist_rcu);
+       }
+       rcu_read_unlock();
+}
+
+#define IS_REQUIRED_GLUE(r) (((r)->attributes & DNS_RDATASETATTR_REQUIRED) != 0)
+
+static void
+addglue_to_message(dns_glue_t *ge, dns_message_t *msg) {
+       for (; ge != NULL; ge = ge->next) {
+               dns_name_t *name = NULL;
+               dns_rdataset_t *rdataset_a = NULL;
+               dns_rdataset_t *sigrdataset_a = NULL;
+               dns_rdataset_t *rdataset_aaaa = NULL;
+               dns_rdataset_t *sigrdataset_aaaa = NULL;
+               bool prepend_name = false;
+
+               dns_message_gettempname(msg, &name);
+
+               dns_name_copy(&ge->name, name);
+
+               if (dns_rdataset_isassociated(&ge->rdataset_a)) {
+                       dns_message_gettemprdataset(msg, &rdataset_a);
+               }
+
+               if (dns_rdataset_isassociated(&ge->sigrdataset_a)) {
+                       dns_message_gettemprdataset(msg, &sigrdataset_a);
+               }
+
+               if (dns_rdataset_isassociated(&ge->rdataset_aaaa)) {
+                       dns_message_gettemprdataset(msg, &rdataset_aaaa);
+               }
+
+               if (dns_rdataset_isassociated(&ge->sigrdataset_aaaa)) {
+                       dns_message_gettemprdataset(msg, &sigrdataset_aaaa);
+               }
+
+               if (rdataset_a != NULL) {
+                       dns_rdataset_clone(&ge->rdataset_a, rdataset_a);
+                       ISC_LIST_APPEND(name->list, rdataset_a, link);
+                       if (IS_REQUIRED_GLUE(rdataset_a)) {
+                               prepend_name = true;
+                       }
+               }
+
+               if (sigrdataset_a != NULL) {
+                       dns_rdataset_clone(&ge->sigrdataset_a, sigrdataset_a);
+                       ISC_LIST_APPEND(name->list, sigrdataset_a, link);
+               }
+
+               if (rdataset_aaaa != NULL) {
+                       dns_rdataset_clone(&ge->rdataset_aaaa, rdataset_aaaa);
+                       ISC_LIST_APPEND(name->list, rdataset_aaaa, link);
+                       if (IS_REQUIRED_GLUE(rdataset_aaaa)) {
+                               prepend_name = true;
+                       }
+               }
+               if (sigrdataset_aaaa != NULL) {
+                       dns_rdataset_clone(&ge->sigrdataset_aaaa,
+                                          sigrdataset_aaaa);
+                       ISC_LIST_APPEND(name->list, sigrdataset_aaaa, link);
+               }
+
+               dns_message_addname(msg, name, DNS_SECTION_ADDITIONAL);
+
+               /*
+                * When looking for required glue, dns_message_rendersection()
+                * only processes the first rdataset associated with the first
+                * name added to the ADDITIONAL section.  dns_message_addname()
+                * performs an append on the list of names in a given section,
+                * so if any glue record was marked as required, we need to
+                * move the name it is associated with to the beginning of the
+                * list for the ADDITIONAL section or else required glue might
+                * not be rendered.
+                */
+               if (prepend_name) {
+                       ISC_LIST_UNLINK(msg->sections[DNS_SECTION_ADDITIONAL],
+                                       name, link);
+                       ISC_LIST_PREPEND(msg->sections[DNS_SECTION_ADDITIONAL],
+                                        name, link);
+               }
+       }
+}
+
+static dns_gluelist_t *
+new_gluelist(dns_db_t *db, dns_slabheader_t *header,
+            const dns_dbversion_t *dbversion) {
+       dns_gluelist_t *gluelist = isc_mem_get(db->mctx, sizeof(*gluelist));
+       *gluelist = (dns_gluelist_t){
+               .version = dbversion,
+               .header = header,
+       };
+
+       isc_mem_attach(db->mctx, &gluelist->mctx);
+
+       cds_wfs_node_init(&gluelist->wfs_node);
+
+       return gluelist;
+}
+
+static dns_gluelist_t *
+create_gluelist(dns_db_t *db, dns_dbversion_t *dbversion, dns_dbnode_t *dbnode,
+               dns_rdataset_t *rdataset, dns_additionaldatafunc_t add) {
+       dns_slabheader_t *header = dns_slabheader_fromrdataset(rdataset);
+       dns_glue_additionaldata_ctx_t ctx = {
+               .db = db,
+               .version = dbversion,
+               .node = dbnode,
+       };
+       dns_gluelist_t *gluelist = new_gluelist(ctx.db, header, ctx.version);
+
+       /*
+        * Get the owner name of the NS RRset - it will be necessary for
+        * identifying required glue in glue_nsdname_cb() (by
+        * determining which NS records in the delegation are
+        * in-bailiwick).
+        */
+
+       (void)dns_rdataset_additionaldata(rdataset, dns_rootname, add, &ctx);
+
+       gluelist->glue = ctx.glue;
+
+       return gluelist;
+}
+
+isc_result_t
+dns__db_addglue(dns_db_t *db, dns_dbversion_t *dbversion,
+               dns_rdataset_t *rdataset, dns_message_t *msg,
+               dns_additionaldatafunc_t add,
+               struct cds_wfs_stack *glue_stack) {
+       dns_dbnode_t *dbnode = (dns_dbnode_t *)rdataset->slab.node;
+       dns_slabheader_t *header = dns_slabheader_fromrdataset(rdataset);
+       dns_glue_t *glue = NULL;
+       isc_result_t result = ISC_R_SUCCESS;
+
+       REQUIRE(rdataset->type == dns_rdatatype_ns);
+
+       rcu_read_lock();
+
+       dns_gluelist_t *gluelist = rcu_dereference(header->gluelist);
+       if (gluelist == NULL || gluelist->version != dbversion) {
+               /* No or old glue list was found in the table. */
+
+               dns_gluelist_t *xchg_gluelist = gluelist;
+               dns_gluelist_t *old_gluelist = (void *)-1;
+               dns_gluelist_t *new_gluelist =
+                       create_gluelist(db, dbversion, dbnode, rdataset, add);
+
+               while (old_gluelist != xchg_gluelist &&
+                      (xchg_gluelist == NULL ||
+                       xchg_gluelist->version != dbversion))
+               {
+                       old_gluelist = xchg_gluelist;
+                       xchg_gluelist = rcu_cmpxchg_pointer(
+                               &header->gluelist, old_gluelist, new_gluelist);
+               }
+
+               if (old_gluelist == xchg_gluelist) {
+                       /* CAS was successful */
+                       cds_wfs_push(glue_stack, &new_gluelist->wfs_node);
+                       gluelist = new_gluelist;
+               } else {
+                       dns__db_destroy_gluelist(&new_gluelist);
+                       gluelist = xchg_gluelist;
+               }
+       }
+
+       glue = gluelist->glue;
+
+       if (glue != NULL) {
+               addglue_to_message(glue, msg);
+               result = ISC_R_NOTFOUND;
+       }
+
+       rcu_read_unlock();
+
+       return result;
+}
+
+dns_glue_t *
+dns__db_new_glue(isc_mem_t *mctx, const dns_name_t *name) {
+       dns_glue_t *glue = isc_mem_get(mctx, sizeof(*glue));
+       *glue = (dns_glue_t){
+               .name = DNS_NAME_INITEMPTY,
+       };
+
+       dns_name_dup(name, mctx, &glue->name);
+
+       return glue;
+}
index 2d920a823e5f8182e02dca38d260287bffcc77c2..19788bbe4cb897bef919dad76147061896295582 100644 (file)
@@ -120,21 +120,31 @@ ISC_LANG_BEGINDECLS
 
 struct dns_glue {
        struct dns_glue *next;
-       dns_fixedname_t fixedname;
+       dns_name_t name;
        dns_rdataset_t rdataset_a;
        dns_rdataset_t sigrdataset_a;
        dns_rdataset_t rdataset_aaaa;
        dns_rdataset_t sigrdataset_aaaa;
+};
 
+struct dns_gluelist {
        isc_mem_t *mctx;
+
+       const dns_dbversion_t *version;
+       dns_slabheader_t *header;
+
+       struct dns_glue *glue;
+
        struct rcu_head rcu_head;
+       struct cds_wfs_node wfs_node;
 };
 
-typedef struct {
-       dns_glue_t *glue_list;
+typedef struct dns_glue_additionaldata_ctx {
        dns_db_t *db;
        dns_dbversion_t *version;
-       dns_name_t *nodename;
+       dns_dbnode_t *node;
+
+       dns_glue_t *glue;
 } dns_glue_additionaldata_ctx_t;
 
 typedef struct {
@@ -196,4 +206,20 @@ dns__db_logtoomanyrecords(dns_db_t *db, const dns_name_t *name,
  * the addition is to create a new rdataset or to merge to an existing one.
  */
 
+void
+dns__db_free_glue(isc_mem_t *mctx, dns_glue_t *glue);
+void
+dns__db_destroy_gluelist(dns_gluelist_t **gluelistp);
+void
+dns__db_free_gluelist_rcu(struct rcu_head *rcu_head);
+void
+dns__db_cleanup_gluelists(struct cds_wfs_stack *glue_stack);
+isc_result_t
+dns__db_addglue(dns_db_t *db, dns_dbversion_t *dbversion,
+               dns_rdataset_t *rdataset, dns_message_t *msg,
+               dns_additionaldatafunc_t add, struct cds_wfs_stack *glue_stack);
+
+dns_glue_t *
+dns__db_new_glue(isc_mem_t *mctx, const dns_name_t *name);
+
 ISC_LANG_ENDDECLS
index 1a46d12d0f6e09250f5ad1422b9022e0f66fc34a..3061f0ece45a33441cdf74dc048725d7ba962c41 100644 (file)
@@ -132,9 +132,9 @@ struct dns_slabheader {
         */
        unsigned char upper[32];
 
-       isc_heap_t         *heap;
-       dns_glue_t         *glue_list;
-       struct cds_wfs_node wfs_node;
+       isc_heap_t *heap;
+
+       dns_gluelist_t *gluelist;
 };
 
 enum {
index c4353aef4c2bd6567760d91195dd2ff79d44ca33..6b124bf734a911b9e96380df620f58da784ad837 100644 (file)
@@ -94,6 +94,7 @@ typedef struct dns_forwarder     dns_forwarder_t;
 typedef struct dns_fwdtable       dns_fwdtable_t;
 typedef struct dns_geoip_databases dns_geoip_databases_t;
 typedef struct dns_glue                   dns_glue_t;
+typedef struct dns_gluelist       dns_gluelist_t;
 typedef struct dns_iptable        dns_iptable_t;
 typedef uint32_t                  dns_iterations_t;
 typedef struct dns_kasp                   dns_kasp_t;
index 3acb6b7ea8f121cb06de57285a6147ff597b6ac1..e15be4504f06062134869298fbc0f9c59a89c304 100644 (file)
@@ -369,64 +369,6 @@ set_index(void *what, unsigned int idx) {
        h->heap_index = idx;
 }
 
-static void
-freeglue(dns_glue_t *glue_list) {
-       if (glue_list == (void *)-1) {
-               return;
-       }
-
-       dns_glue_t *glue = glue_list;
-       while (glue != NULL) {
-               dns_glue_t *next = glue->next;
-
-               if (dns_rdataset_isassociated(&glue->rdataset_a)) {
-                       dns_rdataset_disassociate(&glue->rdataset_a);
-               }
-               if (dns_rdataset_isassociated(&glue->sigrdataset_a)) {
-                       dns_rdataset_disassociate(&glue->sigrdataset_a);
-               }
-
-               if (dns_rdataset_isassociated(&glue->rdataset_aaaa)) {
-                       dns_rdataset_disassociate(&glue->rdataset_aaaa);
-               }
-               if (dns_rdataset_isassociated(&glue->sigrdataset_aaaa)) {
-                       dns_rdataset_disassociate(&glue->sigrdataset_aaaa);
-               }
-
-               dns_rdataset_invalidate(&glue->rdataset_a);
-               dns_rdataset_invalidate(&glue->sigrdataset_a);
-               dns_rdataset_invalidate(&glue->rdataset_aaaa);
-               dns_rdataset_invalidate(&glue->sigrdataset_aaaa);
-
-               isc_mem_putanddetach(&glue->mctx, glue, sizeof(*glue));
-
-               glue = next;
-       }
-}
-
-static void
-free_gluelist_rcu(struct rcu_head *rcu_head) {
-       dns_glue_t *glue = caa_container_of(rcu_head, dns_glue_t, rcu_head);
-
-       freeglue(glue);
-}
-
-static void
-free_gluetable(struct cds_wfs_stack *glue_stack) {
-       struct cds_wfs_head *head = __cds_wfs_pop_all(glue_stack);
-       struct cds_wfs_node *node = NULL, *next = NULL;
-
-       rcu_read_lock();
-       cds_wfs_for_each_blocking_safe(head, node, next) {
-               dns_slabheader_t *header =
-                       caa_container_of(node, dns_slabheader_t, wfs_node);
-               dns_glue_t *glue = rcu_xchg_pointer(&header->glue_list, NULL);
-
-               call_rcu(&glue->rcu_head, free_gluelist_rcu);
-       }
-       rcu_read_unlock();
-}
-
 static void
 free_db_rcu(struct rcu_head *rcu_head) {
        qpzonedb_t *qpdb = caa_container_of(rcu_head, qpzonedb_t, rcu_head);
@@ -513,7 +455,7 @@ qpdb_destroy(dns_db_t *arg) {
         * node count below.
         */
        if (qpdb->current_version != NULL) {
-               free_gluetable(&qpdb->current_version->glue_stack);
+               dns__db_cleanup_gluelists(&qpdb->current_version->glue_stack);
        }
 
        /*
@@ -1475,7 +1417,7 @@ closeversion(dns_db_t *db, dns_dbversion_t **versionp,
        if (cleanup_version != NULL) {
                isc_refcount_destroy(&cleanup_version->references);
                INSIST(EMPTY(cleanup_version->changed_list));
-               free_gluetable(&cleanup_version->glue_stack);
+               dns__db_cleanup_gluelists(&cleanup_version->glue_stack);
                cds_wfs_destroy(&cleanup_version->glue_stack);
                isc_rwlock_destroy(&cleanup_version->rwlock);
                isc_mem_put(qpdb->common.mctx, cleanup_version,
@@ -4020,10 +3962,6 @@ deletedata(dns_db_t *db ISC_ATTR_UNUSED, dns_dbnode_t *node ISC_ATTR_UNUSED,
                RWUNLOCK(&qpdb->lock, isc_rwlocktype_write);
        }
        header->heap_index = 0;
-
-       if (header->glue_list) {
-               freeglue(header->glue_list);
-       }
 }
 
 /*
@@ -4987,26 +4925,15 @@ nodefullname(dns_db_t *db, dns_dbnode_t *node, dns_name_t *name) {
        return ISC_R_SUCCESS;
 }
 
-static dns_glue_t *
-new_gluelist(isc_mem_t *mctx, dns_name_t *name) {
-       dns_glue_t *glue = isc_mem_get(mctx, sizeof(*glue));
-       *glue = (dns_glue_t){ 0 };
-       dns_name_t *gluename = dns_fixedname_initname(&glue->fixedname);
-
-       isc_mem_attach(mctx, &glue->mctx);
-       dns_name_copy(name, gluename);
-
-       return glue;
-}
-
 static isc_result_t
 glue_nsdname_cb(void *arg, const dns_name_t *name, dns_rdatatype_t qtype,
-               dns_rdataset_t *unused DNS__DB_FLARG) {
+               dns_rdataset_t *rdataset ISC_ATTR_UNUSED DNS__DB_FLARG) {
        dns_glue_additionaldata_ctx_t *ctx = NULL;
        isc_result_t result;
        dns_fixedname_t fixedname_a;
        dns_name_t *name_a = NULL;
        dns_rdataset_t rdataset_a, sigrdataset_a;
+       const qpznode_t *node = NULL;
        qpznode_t *node_a = NULL;
        dns_fixedname_t fixedname_aaaa;
        dns_name_t *name_aaaa = NULL;
@@ -5014,8 +4941,6 @@ glue_nsdname_cb(void *arg, const dns_name_t *name, dns_rdatatype_t qtype,
        qpznode_t *node_aaaa = NULL;
        dns_glue_t *glue = NULL;
 
-       UNUSED(unused);
-
        /*
         * NS records want addresses in additional records.
         */
@@ -5023,6 +4948,8 @@ glue_nsdname_cb(void *arg, const dns_name_t *name, dns_rdatatype_t qtype,
 
        ctx = (dns_glue_additionaldata_ctx_t *)arg;
 
+       node = (qpznode_t *)ctx->node;
+
        name_a = dns_fixedname_initname(&fixedname_a);
        dns_rdataset_init(&rdataset_a);
        dns_rdataset_init(&sigrdataset_a);
@@ -5035,7 +4962,7 @@ glue_nsdname_cb(void *arg, const dns_name_t *name, dns_rdatatype_t qtype,
                      DNS_DBFIND_GLUEOK, 0, (dns_dbnode_t **)&node_a, name_a,
                      &rdataset_a, &sigrdataset_a DNS__DB_FLARG_PASS);
        if (result == DNS_R_GLUE) {
-               glue = new_gluelist(ctx->db->mctx, name_a);
+               glue = dns__db_new_glue(ctx->db->mctx, name_a);
 
                dns_rdataset_init(&glue->rdataset_a);
                dns_rdataset_init(&glue->sigrdataset_a);
@@ -5055,7 +4982,7 @@ glue_nsdname_cb(void *arg, const dns_name_t *name, dns_rdatatype_t qtype,
                      &sigrdataset_aaaa DNS__DB_FLARG_PASS);
        if (result == DNS_R_GLUE) {
                if (glue == NULL) {
-                       glue = new_gluelist(ctx->db->mctx, name_aaaa);
+                       glue = dns__db_new_glue(ctx->db->mctx, name_aaaa);
 
                        dns_rdataset_init(&glue->rdataset_a);
                        dns_rdataset_init(&glue->sigrdataset_a);
@@ -5081,7 +5008,7 @@ glue_nsdname_cb(void *arg, const dns_name_t *name, dns_rdatatype_t qtype,
         * attributes for the first rdataset associated with the first name
         * added to the ADDITIONAL section.
         */
-       if (glue != NULL && dns_name_issubdomain(name, ctx->nodename)) {
+       if (glue != NULL && dns_name_issubdomain(name, &node->name)) {
                if (dns_rdataset_isassociated(&glue->rdataset_a)) {
                        glue->rdataset_a.attributes |=
                                DNS_RDATASETATTR_REQUIRED;
@@ -5093,8 +5020,8 @@ glue_nsdname_cb(void *arg, const dns_name_t *name, dns_rdatatype_t qtype,
        }
 
        if (glue != NULL) {
-               glue->next = ctx->glue_list;
-               ctx->glue_list = glue;
+               glue->next = ctx->glue;
+               ctx->glue = glue;
        }
 
        result = ISC_R_SUCCESS;
@@ -5125,162 +5052,30 @@ glue_nsdname_cb(void *arg, const dns_name_t *name, dns_rdatatype_t qtype,
        return result;
 }
 
-#define IS_REQUIRED_GLUE(r) (((r)->attributes & DNS_RDATASETATTR_REQUIRED) != 0)
-
-static void
-addglue_to_message(dns_glue_t *ge, dns_message_t *msg) {
-       for (; ge != NULL; ge = ge->next) {
-               dns_name_t *name = NULL;
-               dns_rdataset_t *rdataset_a = NULL;
-               dns_rdataset_t *sigrdataset_a = NULL;
-               dns_rdataset_t *rdataset_aaaa = NULL;
-               dns_rdataset_t *sigrdataset_aaaa = NULL;
-               dns_name_t *gluename = dns_fixedname_name(&ge->fixedname);
-               bool prepend_name = false;
-
-               dns_message_gettempname(msg, &name);
-
-               dns_name_copy(gluename, name);
-
-               if (dns_rdataset_isassociated(&ge->rdataset_a)) {
-                       dns_message_gettemprdataset(msg, &rdataset_a);
-               }
-
-               if (dns_rdataset_isassociated(&ge->sigrdataset_a)) {
-                       dns_message_gettemprdataset(msg, &sigrdataset_a);
-               }
-
-               if (dns_rdataset_isassociated(&ge->rdataset_aaaa)) {
-                       dns_message_gettemprdataset(msg, &rdataset_aaaa);
-               }
-
-               if (dns_rdataset_isassociated(&ge->sigrdataset_aaaa)) {
-                       dns_message_gettemprdataset(msg, &sigrdataset_aaaa);
-               }
-
-               if (rdataset_a != NULL) {
-                       dns_rdataset_clone(&ge->rdataset_a, rdataset_a);
-                       ISC_LIST_APPEND(name->list, rdataset_a, link);
-                       if (IS_REQUIRED_GLUE(rdataset_a)) {
-                               prepend_name = true;
-                       }
-               }
-
-               if (sigrdataset_a != NULL) {
-                       dns_rdataset_clone(&ge->sigrdataset_a, sigrdataset_a);
-                       ISC_LIST_APPEND(name->list, sigrdataset_a, link);
-               }
-
-               if (rdataset_aaaa != NULL) {
-                       dns_rdataset_clone(&ge->rdataset_aaaa, rdataset_aaaa);
-                       ISC_LIST_APPEND(name->list, rdataset_aaaa, link);
-                       if (IS_REQUIRED_GLUE(rdataset_aaaa)) {
-                               prepend_name = true;
-                       }
-               }
-               if (sigrdataset_aaaa != NULL) {
-                       dns_rdataset_clone(&ge->sigrdataset_aaaa,
-                                          sigrdataset_aaaa);
-                       ISC_LIST_APPEND(name->list, sigrdataset_aaaa, link);
-               }
-
-               dns_message_addname(msg, name, DNS_SECTION_ADDITIONAL);
-
-               /*
-                * When looking for required glue, dns_message_rendersection()
-                * only processes the first rdataset associated with the first
-                * name added to the ADDITIONAL section.  dns_message_addname()
-                * performs an append on the list of names in a given section,
-                * so if any glue record was marked as required, we need to
-                * move the name it is associated with to the beginning of the
-                * list for the ADDITIONAL section or else required glue might
-                * not be rendered.
-                */
-               if (prepend_name) {
-                       ISC_LIST_UNLINK(msg->sections[DNS_SECTION_ADDITIONAL],
-                                       name, link);
-                       ISC_LIST_PREPEND(msg->sections[DNS_SECTION_ADDITIONAL],
-                                        name, link);
-               }
-       }
-}
-
-static dns_glue_t *
-newglue(qpzonedb_t *qpdb, qpz_version_t *version, qpznode_t *node,
-       dns_rdataset_t *rdataset) {
-       dns_fixedname_t nodename;
-       dns_glue_additionaldata_ctx_t ctx = {
-               .db = (dns_db_t *)qpdb,
-               .version = (dns_dbversion_t *)version,
-               .nodename = dns_fixedname_initname(&nodename),
-       };
-
-       /*
-        * Get the owner name of the NS RRset - it will be necessary for
-        * identifying required glue in glue_nsdname_cb() (by
-        * determining which NS records in the delegation are
-        * in-bailiwick).
-        */
-       dns_name_copy(&node->name, ctx.nodename);
-
-       (void)dns_rdataset_additionaldata(rdataset, dns_rootname,
-                                         glue_nsdname_cb, &ctx);
-
-       return ctx.glue_list;
-}
-
 static isc_result_t
 addglue(dns_db_t *db, dns_dbversion_t *dbversion, dns_rdataset_t *rdataset,
        dns_message_t *msg) {
        qpzonedb_t *qpdb = (qpzonedb_t *)db;
        qpz_version_t *version = dbversion;
-       qpznode_t *node = (qpznode_t *)rdataset->slab.node;
-       dns_slabheader_t *header = dns_slabheader_fromrdataset(rdataset);
+       isc_result_t result;
 
        REQUIRE(rdataset->type == dns_rdatatype_ns);
        REQUIRE(qpdb == (qpzonedb_t *)rdataset->slab.db);
        REQUIRE(qpdb == version->qpdb);
        REQUIRE(!IS_STUB(qpdb));
 
-       rcu_read_lock();
-
-       dns_glue_t *glue = rcu_dereference(header->glue_list);
-       if (glue == NULL) {
-               /* No cached glue was found in the table. Get new glue. */
-               glue = newglue(qpdb, version, node, rdataset);
-
-               /* Cache the glue or (void *)-1 if no glue was found. */
-               dns_glue_t *old_glue = rcu_cmpxchg_pointer(
-                       &header->glue_list, NULL, (glue) ? glue : (void *)-1);
-               if (old_glue != NULL) {
-                       /* Somebody else was faster */
-                       freeglue(glue);
-                       glue = old_glue;
-               } else if (glue != NULL) {
-                       cds_wfs_push(&version->glue_stack, &header->wfs_node);
-               }
-       }
-
-       /* We have a cached result. Add it to the message and return. */
+       result = dns__db_addglue(db, dbversion, rdataset, msg, glue_nsdname_cb,
+                                &version->glue_stack);
 
        if (qpdb->gluecachestats != NULL) {
-               isc_stats_increment(
-                       qpdb->gluecachestats,
-                       (glue == (void *)-1)
-                               ? dns_gluecachestatscounter_hits_absent
-                               : dns_gluecachestatscounter_hits_present);
-       }
+               isc_statscounter_t counter =
+                       (result == ISC_R_SUCCESS)
+                               ? dns_gluecachestatscounter_hits_present
+                               : dns_gluecachestatscounter_hits_absent;
 
-       /*
-        * (void *)-1 is a special value that means no glue is present in the
-        * zone.
-        */
-       if (glue != (void *)-1) {
-               addglue_to_message(glue, msg);
+               isc_stats_increment(qpdb->gluecachestats, counter);
        }
 
-       rcu_read_unlock();
-
        return ISC_R_SUCCESS;
 }
 
index ba7d46d2412fb558ad2d343ded681d4d7d783591..226603dea5150d2799b7f14d60e9fa598f3d382f 100644 (file)
@@ -2091,18 +2091,6 @@ setgluecachestats(dns_db_t *db, isc_stats_t *stats) {
        return ISC_R_SUCCESS;
 }
 
-static dns_glue_t *
-new_gluelist(isc_mem_t *mctx, dns_name_t *name) {
-       dns_glue_t *glue = isc_mem_get(mctx, sizeof(*glue));
-       *glue = (dns_glue_t){ 0 };
-       dns_name_t *gluename = dns_fixedname_initname(&glue->fixedname);
-
-       isc_mem_attach(mctx, &glue->mctx);
-       dns_name_copy(name, gluename);
-
-       return glue;
-}
-
 static isc_result_t
 glue_nsdname_cb(void *arg, const dns_name_t *name, dns_rdatatype_t qtype,
                dns_rdataset_t *unused DNS__DB_FLARG) {
@@ -2117,6 +2105,8 @@ glue_nsdname_cb(void *arg, const dns_name_t *name, dns_rdatatype_t qtype,
        dns_rdataset_t rdataset_aaaa, sigrdataset_aaaa;
        dns_rbtnode_t *node_aaaa = NULL;
        dns_glue_t *glue = NULL;
+       dns_fixedname_t f_nodename;
+       dns_name_t *nodename = dns_fixedname_initname(&f_nodename);
 
        UNUSED(unused);
 
@@ -2127,6 +2117,8 @@ glue_nsdname_cb(void *arg, const dns_name_t *name, dns_rdatatype_t qtype,
 
        ctx = (dns_glue_additionaldata_ctx_t *)arg;
 
+       dns__rbtdb_nodefullname(ctx->db, ctx->node, nodename);
+
        name_a = dns_fixedname_initname(&fixedname_a);
        dns_rdataset_init(&rdataset_a);
        dns_rdataset_init(&sigrdataset_a);
@@ -2140,7 +2132,7 @@ glue_nsdname_cb(void *arg, const dns_name_t *name, dns_rdatatype_t qtype,
                           name_a, &rdataset_a,
                           &sigrdataset_a DNS__DB_FLARG_PASS);
        if (result == DNS_R_GLUE) {
-               glue = new_gluelist(ctx->db->mctx, name_a);
+               glue = dns__db_new_glue(ctx->db->mctx, name_a);
 
                dns_rdataset_init(&glue->rdataset_a);
                dns_rdataset_init(&glue->sigrdataset_a);
@@ -2160,7 +2152,7 @@ glue_nsdname_cb(void *arg, const dns_name_t *name, dns_rdatatype_t qtype,
                           &sigrdataset_aaaa DNS__DB_FLARG_PASS);
        if (result == DNS_R_GLUE) {
                if (glue == NULL) {
-                       glue = new_gluelist(ctx->db->mctx, name_aaaa);
+                       glue = dns__db_new_glue(ctx->db->mctx, name_aaaa);
 
                        dns_rdataset_init(&glue->rdataset_a);
                        dns_rdataset_init(&glue->sigrdataset_a);
@@ -2186,7 +2178,10 @@ glue_nsdname_cb(void *arg, const dns_name_t *name, dns_rdatatype_t qtype,
         * attributes for the first rdataset associated with the first name
         * added to the ADDITIONAL section.
         */
-       if (glue != NULL && dns_name_issubdomain(name, ctx->nodename)) {
+       isc_result_t dns_rbt_fullnamefromnode(dns_rbtnode_t * node,
+                                             dns_name_t * name);
+
+       if (glue != NULL && dns_name_issubdomain(name, nodename)) {
                if (dns_rdataset_isassociated(&glue->rdataset_a)) {
                        glue->rdataset_a.attributes |=
                                DNS_RDATASETATTR_REQUIRED;
@@ -2198,8 +2193,8 @@ glue_nsdname_cb(void *arg, const dns_name_t *name, dns_rdatatype_t qtype,
        }
 
        if (glue != NULL) {
-               glue->next = ctx->glue_list;
-               ctx->glue_list = glue;
+               glue->next = ctx->glue;
+               ctx->glue = glue;
        }
 
        result = ISC_R_SUCCESS;
@@ -2230,163 +2225,30 @@ glue_nsdname_cb(void *arg, const dns_name_t *name, dns_rdatatype_t qtype,
        return result;
 }
 
-#define IS_REQUIRED_GLUE(r) (((r)->attributes & DNS_RDATASETATTR_REQUIRED) != 0)
-
-static void
-addglue_to_message(dns_glue_t *ge, dns_message_t *msg) {
-       for (; ge != NULL; ge = ge->next) {
-               dns_name_t *name = NULL;
-               dns_rdataset_t *rdataset_a = NULL;
-               dns_rdataset_t *sigrdataset_a = NULL;
-               dns_rdataset_t *rdataset_aaaa = NULL;
-               dns_rdataset_t *sigrdataset_aaaa = NULL;
-               dns_name_t *gluename = dns_fixedname_name(&ge->fixedname);
-               bool prepend_name = false;
-
-               dns_message_gettempname(msg, &name);
-
-               dns_name_copy(gluename, name);
-
-               if (dns_rdataset_isassociated(&ge->rdataset_a)) {
-                       dns_message_gettemprdataset(msg, &rdataset_a);
-               }
-
-               if (dns_rdataset_isassociated(&ge->sigrdataset_a)) {
-                       dns_message_gettemprdataset(msg, &sigrdataset_a);
-               }
-
-               if (dns_rdataset_isassociated(&ge->rdataset_aaaa)) {
-                       dns_message_gettemprdataset(msg, &rdataset_aaaa);
-               }
-
-               if (dns_rdataset_isassociated(&ge->sigrdataset_aaaa)) {
-                       dns_message_gettemprdataset(msg, &sigrdataset_aaaa);
-               }
-
-               if (rdataset_a != NULL) {
-                       dns_rdataset_clone(&ge->rdataset_a, rdataset_a);
-                       ISC_LIST_APPEND(name->list, rdataset_a, link);
-                       if (IS_REQUIRED_GLUE(rdataset_a)) {
-                               prepend_name = true;
-                       }
-               }
-
-               if (sigrdataset_a != NULL) {
-                       dns_rdataset_clone(&ge->sigrdataset_a, sigrdataset_a);
-                       ISC_LIST_APPEND(name->list, sigrdataset_a, link);
-               }
-
-               if (rdataset_aaaa != NULL) {
-                       dns_rdataset_clone(&ge->rdataset_aaaa, rdataset_aaaa);
-                       ISC_LIST_APPEND(name->list, rdataset_aaaa, link);
-                       if (IS_REQUIRED_GLUE(rdataset_aaaa)) {
-                               prepend_name = true;
-                       }
-               }
-               if (sigrdataset_aaaa != NULL) {
-                       dns_rdataset_clone(&ge->sigrdataset_aaaa,
-                                          sigrdataset_aaaa);
-                       ISC_LIST_APPEND(name->list, sigrdataset_aaaa, link);
-               }
-
-               dns_message_addname(msg, name, DNS_SECTION_ADDITIONAL);
-
-               /*
-                * When looking for required glue, dns_message_rendersection()
-                * only processes the first rdataset associated with the first
-                * name added to the ADDITIONAL section.  dns_message_addname()
-                * performs an append on the list of names in a given section,
-                * so if any glue record was marked as required, we need to
-                * move the name it is associated with to the beginning of the
-                * list for the ADDITIONAL section or else required glue might
-                * not be rendered.
-                */
-               if (prepend_name) {
-                       ISC_LIST_UNLINK(msg->sections[DNS_SECTION_ADDITIONAL],
-                                       name, link);
-                       ISC_LIST_PREPEND(msg->sections[DNS_SECTION_ADDITIONAL],
-                                        name, link);
-               }
-       }
-}
-
-static dns_glue_t *
-newglue(dns_rbtdb_t *rbtdb, dns_rbtdb_version_t *rbtversion,
-       dns_rbtnode_t *node, dns_rdataset_t *rdataset) {
-       dns_fixedname_t nodename;
-       dns_glue_additionaldata_ctx_t ctx = {
-               .db = (dns_db_t *)rbtdb,
-               .version = (dns_dbversion_t *)rbtversion,
-               .nodename = dns_fixedname_initname(&nodename),
-       };
-
-       /*
-        * Get the owner name of the NS RRset - it will be necessary for
-        * identifying required glue in glue_nsdname_cb() (by
-        * determining which NS records in the delegation are
-        * in-bailiwick).
-        */
-       dns__rbtdb_nodefullname((dns_db_t *)rbtdb, node, ctx.nodename);
-
-       (void)dns_rdataset_additionaldata(rdataset, dns_rootname,
-                                         glue_nsdname_cb, &ctx);
-
-       return ctx.glue_list;
-}
-
 static isc_result_t
-addglue(dns_db_t *db, dns_dbversion_t *version, dns_rdataset_t *rdataset,
+addglue(dns_db_t *db, dns_dbversion_t *dbversion, dns_rdataset_t *rdataset,
        dns_message_t *msg) {
        dns_rbtdb_t *rbtdb = (dns_rbtdb_t *)db;
-       dns_rbtdb_version_t *rbtversion = version;
-       dns_rbtnode_t *node = (dns_rbtnode_t *)rdataset->slab.node;
-       dns_slabheader_t *header = dns_slabheader_fromrdataset(rdataset);
+       dns_rbtdb_version_t *rbtversion = dbversion;
+       isc_result_t result;
 
        REQUIRE(rdataset->type == dns_rdatatype_ns);
        REQUIRE(rbtdb == (dns_rbtdb_t *)rdataset->slab.db);
        REQUIRE(rbtdb == rbtversion->rbtdb);
        REQUIRE(!IS_CACHE(rbtdb) && !IS_STUB(rbtdb));
 
-       rcu_read_lock();
-
-       dns_glue_t *glue = rcu_dereference(header->glue_list);
-       if (glue == NULL) {
-               /* No cached glue was found in the table. Get new glue. */
-               glue = newglue(rbtdb, rbtversion, node, rdataset);
-
-               /* Cache the glue or (void *)-1 if no glue was found. */
-               dns_glue_t *old_glue = rcu_cmpxchg_pointer(
-                       &header->glue_list, NULL, (glue) ? glue : (void *)-1);
-               if (old_glue != NULL) {
-                       /* Somebody else was faster */
-                       dns__rbtdb_freeglue(glue);
-                       glue = old_glue;
-               } else if (glue != NULL) {
-                       cds_wfs_push(&rbtversion->glue_stack,
-                                    &header->wfs_node);
-               }
-       }
-
-       /* We have a cached result. Add it to the message and return. */
+       result = dns__db_addglue(db, dbversion, rdataset, msg, glue_nsdname_cb,
+                                &rbtversion->glue_stack);
 
        if (rbtdb->gluecachestats != NULL) {
-               isc_stats_increment(
-                       rbtdb->gluecachestats,
-                       (glue == (void *)-1)
-                               ? dns_gluecachestatscounter_hits_absent
-                               : dns_gluecachestatscounter_hits_present);
-       }
+               isc_statscounter_t counter =
+                       (result == ISC_R_SUCCESS)
+                               ? dns_gluecachestatscounter_hits_present
+                               : dns_gluecachestatscounter_hits_absent;
 
-       /*
-        * (void *)-1 is a special value that means no glue is present in the
-        * zone.
-        */
-       if (glue != (void *)-1) {
-               addglue_to_message(glue, msg);
+               isc_stats_increment(rbtdb->gluecachestats, counter);
        }
 
-       rcu_read_unlock();
-
        return ISC_R_SUCCESS;
 }
 
index fc4ac5068eefb2274f650bc3e0b112cb34ad36a9..8e8db1e4dfa3cd1ff52d0e1d01139c5717061c96 100644 (file)
@@ -166,8 +166,6 @@ static void
 delete_callback(void *data, void *arg);
 static void
 prune_tree(void *arg);
-static void
-free_gluetable(dns_rbtdb_version_t *version);
 
 static void
 rdatasetiter_destroy(dns_rdatasetiter_t **iteratorp DNS__DB_FLARG);
@@ -623,7 +621,7 @@ dns__rbtdb_destroy(dns_db_t *arg) {
         * node count below.
         */
        if (rbtdb->current_version != NULL) {
-               free_gluetable(rbtdb->current_version);
+               dns__db_cleanup_gluelists(&rbtdb->current_version->glue_stack);
        }
 
        /*
@@ -1947,7 +1945,7 @@ dns__rbtdb_closeversion(dns_db_t *db, dns_dbversion_t **versionp,
        if (cleanup_version != NULL) {
                isc_refcount_destroy(&cleanup_version->references);
                INSIST(EMPTY(cleanup_version->changed_list));
-               free_gluetable(cleanup_version);
+               dns__db_cleanup_gluelists(&cleanup_version->glue_stack);
                cds_wfs_destroy(&cleanup_version->glue_stack);
                isc_rwlock_destroy(&cleanup_version->rwlock);
                isc_mem_put(rbtdb->common.mctx, cleanup_version,
@@ -4873,64 +4871,6 @@ dbiterator_origin(dns_dbiterator_t *iterator, dns_name_t *name) {
        return ISC_R_SUCCESS;
 }
 
-void
-dns__rbtdb_freeglue(dns_glue_t *glue_list) {
-       if (glue_list == (void *)-1) {
-               return;
-       }
-
-       dns_glue_t *glue = glue_list;
-       while (glue != NULL) {
-               dns_glue_t *next = glue->next;
-
-               if (dns_rdataset_isassociated(&glue->rdataset_a)) {
-                       dns_rdataset_disassociate(&glue->rdataset_a);
-               }
-               if (dns_rdataset_isassociated(&glue->sigrdataset_a)) {
-                       dns_rdataset_disassociate(&glue->sigrdataset_a);
-               }
-
-               if (dns_rdataset_isassociated(&glue->rdataset_aaaa)) {
-                       dns_rdataset_disassociate(&glue->rdataset_aaaa);
-               }
-               if (dns_rdataset_isassociated(&glue->sigrdataset_aaaa)) {
-                       dns_rdataset_disassociate(&glue->sigrdataset_aaaa);
-               }
-
-               dns_rdataset_invalidate(&glue->rdataset_a);
-               dns_rdataset_invalidate(&glue->sigrdataset_a);
-               dns_rdataset_invalidate(&glue->rdataset_aaaa);
-               dns_rdataset_invalidate(&glue->sigrdataset_aaaa);
-
-               isc_mem_putanddetach(&glue->mctx, glue, sizeof(*glue));
-
-               glue = next;
-       }
-}
-
-static void
-free_gluelist_rcu(struct rcu_head *rcu_head) {
-       dns_glue_t *glue = caa_container_of(rcu_head, dns_glue_t, rcu_head);
-
-       dns__rbtdb_freeglue(glue);
-}
-
-static void
-free_gluetable(dns_rbtdb_version_t *rbtversion) {
-       struct cds_wfs_head *head = __cds_wfs_pop_all(&rbtversion->glue_stack);
-       struct cds_wfs_node *node = NULL, *next = NULL;
-
-       rcu_read_lock();
-       cds_wfs_for_each_blocking_safe(head, node, next) {
-               dns_slabheader_t *header =
-                       caa_container_of(node, dns_slabheader_t, wfs_node);
-               dns_glue_t *glue = rcu_xchg_pointer(&header->glue_list, NULL);
-
-               call_rcu(&glue->rcu_head, free_gluelist_rcu);
-       }
-       rcu_read_unlock();
-}
-
 void
 dns__rbtdb_deletedata(dns_db_t *db ISC_ATTR_UNUSED,
                      dns_dbnode_t *node ISC_ATTR_UNUSED, void *data) {
@@ -4958,10 +4898,6 @@ dns__rbtdb_deletedata(dns_db_t *db ISC_ATTR_UNUSED,
                if (header->closest != NULL) {
                        dns_slabheader_freeproof(db->mctx, &header->closest);
                }
-       } else {
-               if (header->glue_list) {
-                       dns__rbtdb_freeglue(header->glue_list);
-               }
        }
 }
 
index 29fc2debbaeeb7c3b1c0182e7114f8b287a9c85c..3da416e2efc7967a490318d2e69608e571331909 100644 (file)
@@ -1081,15 +1081,12 @@ dns_slabheader_reset(dns_slabheader_t *h, dns_db_t *db, dns_dbnode_t *node) {
        ISC_LINK_INIT(h, link);
        h->heap_index = 0;
        h->heap = NULL;
-       h->glue_list = NULL;
        h->db = db;
        h->node = node;
 
        atomic_init(&h->attributes, 0);
        atomic_init(&h->last_refresh_fail_ts, 0);
 
-       cds_wfs_node_init(&h->wfs_node);
-
        STATIC_ASSERT((sizeof(h->attributes) == 2),
                      "The .attributes field of dns_slabheader_t needs to be "
                      "16-bit int type exactly.");