]> git.ipfire.org Git - thirdparty/bind9.git/commitdiff
Account transient delegsets against the caller's memory context
authorOndřej Surý <ondrej@isc.org>
Thu, 9 Apr 2026 10:45:30 +0000 (12:45 +0200)
committerColin Vidal <colin@isc.org>
Thu, 16 Apr 2026 09:28:13 +0000 (11:28 +0200)
dns_delegset_fromnsrdataset() used isc_g_mctx for the transient
delegset it builds from a DNS NS rdataset.  That hides delegation
data in the global default context instead of accounting it against
the subsystem that owns it: a resolver fctx, a view, or a query
context.

Take an explicit mctx parameter so callers can direct the allocation
to the right place, and update the three call sites:
- lib/dns/view.c:1189 (dns_view_bestzonecut fallback) uses view->mctx
- lib/dns/resolver.c:7071 (resume_dslookup) uses fctx->mctx
- lib/ns/query.c:8672 (query_delegation_recurse) uses the client
  manager's mctx

Also tighten delegdb cleanup to run inside the same write transaction
as the insert: delegdb_node_prepare() now returns the size of the new
node, and delegdb_cleanup() takes the caller's open qp so that the
overmem reclamation and the insert share one commit instead of doing
two nested write transactions.

lib/dns/deleg.c
lib/dns/include/dns/deleg.h
lib/dns/resolver.c
lib/dns/view.c
lib/ns/query.c
tests/dns/deleg_test.c

index 28fb777ef889392745fcdf9f10ef37577dd24084..df989c3b742cf0ca5c5147cfcacd14e5b4bb87e8 100644 (file)
@@ -458,19 +458,15 @@ dns_delegset_addns(dns_delegset_t *delegset, dns_deleg_t *deleg,
 }
 
 static void
-delegdb_cleanup(dns_delegdb_t *delegdb, dns_qpmulti_t *nodes) {
-       dns_qp_t *qp = NULL;
+delegdb_cleanup(dns_qp_t *qp, dns_delegdb_t *delegdb, size_t requested) {
        delegdb_node_t *node = NULL;
        size_t reclaimed = 0;
-       size_t requested = 0;
 
        if (!isc_mem_isovermem(delegdb->mctx)) {
                return;
        }
        requested = delegdb->hiwater - delegdb->lowater;
 
-       dns_qpmulti_write(nodes, &qp);
-
        while (reclaimed < requested) {
                node = ISC_SIEVE_NEXT(delegdb->lru[isc_tid()], visited, link);
 
@@ -483,9 +479,6 @@ delegdb_cleanup(dns_delegdb_t *delegdb, dns_qpmulti_t *nodes) {
                (void)dns_qp_deletename(qp, &node->zonecut,
                                        DNS_DBNAMESPACE_NORMAL, NULL, NULL);
        }
-
-       dns_qp_compact(qp, DNS_QPGC_ALL);
-       dns_qpmulti_commit(nodes, &qp);
 }
 
 static size_t
@@ -517,13 +510,10 @@ delegdb_node_size(const dns_name_t *zonecut, dns_delegset_t *delegset) {
        return sz;
 }
 
-static void
-delegdb_node_prepare(dns_delegdb_t *delegdb, dns_qpmulti_t *nodes,
-                    isc_stdtime_t now, dns_ttl_t ttl,
+static size_t
+delegdb_node_prepare(dns_delegdb_t *delegdb, isc_stdtime_t now, dns_ttl_t ttl,
                     const dns_name_t *zonecut, dns_delegset_t *delegset,
                     delegdb_node_t **nodep) {
-       delegdb_cleanup(delegdb, nodes);
-
        if (ttl == 0) {
                ttl = 1;
        }
@@ -542,6 +532,8 @@ delegdb_node_prepare(dns_delegdb_t *delegdb, dns_qpmulti_t *nodes,
        dns_delegdb_attach(delegdb, &(*nodep)->delegdb);
        dns_delegset_attach(delegset, &(*nodep)->delegset);
        dns_name_dup(zonecut, delegdb->mctx, &(*nodep)->zonecut);
+
+       return sizeof(**nodep) + (*nodep)->size;
 }
 
 isc_result_t
@@ -593,13 +585,16 @@ dns_delegset_insert(dns_delegdb_t *delegdb, const dns_name_t *zonecut,
         * clean up expired/least recently used delegation, then allocate and
         * initialize a new node.
         */
-       delegdb_node_prepare(delegdb, nodes, now, ttl, zonecut, delegset,
-                            &node);
+       size_t requested = delegdb_node_prepare(delegdb, now, ttl, zonecut,
+                                               delegset, &node);
 
        /*
         * Add the node in the DB
         */
        dns_qpmulti_write(nodes, &qp);
+
+       delegdb_cleanup(qp, delegdb, requested);
+
        if (result == ISC_R_SUCCESS) {
                /*
                 * A node at the same zonecut exists, and it is expired. Ignore
@@ -821,7 +816,7 @@ dns_delegdb_dump(dns_delegdb_t *delegdb, bool expired, FILE *fp) {
 }
 
 void
-dns_delegset_fromnsrdataset(dns_rdataset_t *rdataset,
+dns_delegset_fromnsrdataset(isc_mem_t *mctx, dns_rdataset_t *rdataset,
                            dns_delegset_t **delegsetp) {
        dns_delegset_t *delegset = NULL;
        dns_deleg_t *deleg = NULL;
@@ -834,17 +829,17 @@ dns_delegset_fromnsrdataset(dns_rdataset_t *rdataset,
 
        REQUIRE(rdataset->type == dns_rdatatype_ns);
 
-       delegset = isc_mem_get(isc_g_mctx, sizeof(*delegset));
+       delegset = isc_mem_get(mctx, sizeof(*delegset));
        *delegset = (dns_delegset_t){
                .magic = DNS_DELEGSET_MAGIC,
+               .mctx = isc_mem_ref(mctx),
                .references = ISC_REFCOUNT_INITIALIZER(1),
                .delegs = ISC_LIST_INITIALIZER,
                .expires = rdataset->ttl + isc_stdtime_now(),
                .staticstub = rdataset->attributes.staticstub
        };
-       isc_mem_attach(isc_g_mctx, &delegset->mctx);
 
-       deleg = isc_mem_get(isc_g_mctx, sizeof(*deleg));
+       deleg = isc_mem_get(delegset->mctx, sizeof(*deleg));
        *deleg = (dns_deleg_t){ .addresses = ISC_LIST_INITIALIZER,
                                .names = ISC_LIST_INITIALIZER,
                                .type = DNS_DELEGTYPE_NS_NAMES,
index 4a7bccb0041ff04c1e7afd30af587fdec6158df5..907d4ffc6889ee44ae55f308e71bbac229fb2e63 100644 (file)
@@ -206,7 +206,7 @@ dns_delegdb_dump(dns_delegdb_t *db, bool expired, FILE *fp);
  * (which accepts only delegset allocated using `dns_deleg_alloc*()` APIs.
  */
 void
-dns_delegset_fromnsrdataset(dns_rdataset_t  *rdataset,
+dns_delegset_fromnsrdataset(isc_mem_t *mctx, dns_rdataset_t *rdataset,
                            dns_delegset_t **delegsetp);
 
 /*
index b2e925f55b03c13459615bcfac0355fc02c9b96b..65da6ae1554a0fea9a4d16f9ebdd7a6f4a8dcece 100644 (file)
@@ -7068,7 +7068,7 @@ resume_dslookup(void *arg) {
        case ISC_R_SUCCESS:
                FCTXTRACE("resuming DS lookup");
 
-               dns_delegset_fromnsrdataset(frdataset, &delegset);
+               dns_delegset_fromnsrdataset(fctx->mctx, frdataset, &delegset);
                dns_rdataset_cleanup(frdataset);
 
                if (delegset == NULL) {
index 6208a1bfc439d58177a3523d3542837d222ce248..1637131a6cafced67ceab1cf3ade0a1de6926138 100644 (file)
@@ -1186,7 +1186,7 @@ dns_view_bestzonecut(dns_view_t *view, const dns_name_t *name,
                 * the same, and this avoid adding extra code here to extract
                 * A/AAAA rdataset if any.
                 */
-               dns_delegset_fromnsrdataset(&rdataset, delegsetp);
+               dns_delegset_fromnsrdataset(view->mctx, &rdataset, delegsetp);
        }
 
        dns_rdataset_cleanup(&rdataset);
index b801b781e5f0726e3fe4f6b9d9d2423238b895cd..b41e8c980d8b39cc5f6c732844433f67934e9cd2 100644 (file)
@@ -8669,7 +8669,8 @@ query_delegation_recurse(query_ctx_t *qctx) {
                                               qctx->client->inner.now, 0, true,
                                               true, &delegset);
                if (tresult != ISC_R_SUCCESS) {
-                       dns_delegset_fromnsrdataset(qctx->rdataset, &delegset);
+                       dns_delegset_fromnsrdataset(qctx->client->manager->mctx,
+                                                   qctx->rdataset, &delegset);
                        fname = qctx->fname;
                }
 
index e27b7b1eb74f819c1461a0491e1f0c2fd563009e..8082b670914621c3fe643e4e58d2fe2e2b89f8c2 100644 (file)
@@ -587,7 +587,7 @@ cleanuptests_phase3(void *arg) {
        dns_delegset_t *delegset = NULL;
        isc_result_t result;
 
-       assert_int_in_range(isc_mem_inuse(db->mctx), 4000000, 4100000);
+       assert_int_in_range(isc_mem_inuse(db->mctx), 8000000, 8100000);
 
        /*
         * baz. is there, but bar. is gone, as it has been