Account transient delegsets against the caller's memory context

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.
This commit is contained in:
Ondřej Surý 2026-04-09 12:45:30 +02:00 committed by Colin Vidal
parent 9191dc7acb
commit 876a896f0f
6 changed files with 20 additions and 24 deletions

View 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,

View 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);
/*

View 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) {

View 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);

View 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;
}

View 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