From: Ondřej Surý Date: Thu, 18 Jun 2026 14:51:28 +0000 (+0200) Subject: Store the bound node and slabheader reference on the rdataset X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=d9701e1fae6bea1643b484de164c29506e8c353a;p=thirdparty%2Fbind9.git Store the bound node and slabheader reference on the rdataset The bound rdataset now keeps its own node reference instead of reaching it through the slabheader, and each slabheader carries its own memory context so it can free itself once its reference count reaches zero. The noqname/closest proof rdatasets are views into a slabheader's proof slabs, so they now hold a reference to that slabheader too, keeping the proof slab (and the cloned owner name): alive for as long as the proof rdataset is. Keeping the node on the rdataset means node access stays valid for the life of the rdataset, independent of the slabheader's own node pointer. --- diff --git a/lib/dns/include/dns/rdataset.h b/lib/dns/include/dns/rdataset.h index 6691216ecdf..4beb2a4ba30 100644 --- a/lib/dns/include/dns/rdataset.h +++ b/lib/dns/include/dns/rdataset.h @@ -192,6 +192,7 @@ struct dns_rdataset { * comments in rdataslab.c for details.) */ struct { + dns_dbnode_t *node; unsigned char *raw; unsigned char *iter_pos; unsigned int iter_count; @@ -207,10 +208,11 @@ struct dns_rdataset { * comments in rdataslab.c for details.) */ struct { - unsigned char *raw; - unsigned char *iter_pos; - unsigned int iter_count; - dns_dbnode_t *node; + dns_dbnode_t *node; + dns_slabheader_t *header; + unsigned char *raw; + unsigned char *iter_pos; + unsigned int iter_count; } proof; /* diff --git a/lib/dns/include/dns/rdataslab.h b/lib/dns/include/dns/rdataslab.h index a1cfeedd49f..f55473c97a4 100644 --- a/lib/dns/include/dns/rdataslab.h +++ b/lib/dns/include/dns/rdataslab.h @@ -94,6 +94,8 @@ struct dns_slabheader { isc_refcount_t references; + isc_mem_t *mctx; + /*% * Locked by the owning node's lock. */ diff --git a/lib/dns/qpcache.c b/lib/dns/qpcache.c index c31572fdc1e..3528a1e39b3 100644 --- a/lib/dns/qpcache.c +++ b/lib/dns/qpcache.c @@ -1052,6 +1052,7 @@ bindrdataset(qpcache_t *qpdb, qpcnode_t *node, dns_slabheader_t *header, rdataset->ttl = 0; } + rdataset->slab.node = (dns_dbnode_t *)node; rdataset->slab.raw = header->raw; rdataset->slab.iter_pos = NULL; rdataset->slab.iter_count = 0; @@ -2702,10 +2703,12 @@ addnoqname(isc_mem_t *mctx, dns_slabheader_t *newheader, uint32_t maxrrperset, cleanup: if (result != ISC_R_SUCCESS) { if (r1.base != NULL) { - isc_mem_put(mctx, r1.base, r1.length); + dns_slabheader_t *header = (dns_slabheader_t *)r1.base; + dns_slabheader_detach(&header); } if (r2.base != NULL) { - isc_mem_put(mctx, r2.base, r2.length); + dns_slabheader_t *header = (dns_slabheader_t *)r2.base; + dns_slabheader_detach(&header); } } dns_rdataset_disassociate(&neg); @@ -2743,10 +2746,12 @@ addclosest(isc_mem_t *mctx, dns_slabheader_t *newheader, uint32_t maxrrperset, cleanup: if (result != ISC_R_SUCCESS) { if (r1.base != NULL) { - isc_mem_put(mctx, r1.base, r1.length); + dns_slabheader_t *header = (dns_slabheader_t *)r1.base; + dns_slabheader_detach(&header); } if (r2.base != NULL) { - isc_mem_put(mctx, r2.base, r2.length); + dns_slabheader_t *header = (dns_slabheader_t *)r2.base; + dns_slabheader_detach(&header); } } dns_rdataset_disassociate(&neg); diff --git a/lib/dns/rdataslab.c b/lib/dns/rdataslab.c index b917fdce335..7753f609d6e 100644 --- a/lib/dns/rdataslab.c +++ b/lib/dns/rdataslab.c @@ -144,6 +144,7 @@ newslab(dns_rdataset_t *rdataset, isc_mem_t *mctx, isc_region_t *region, .dirtylink = ISC_LINK_INITIALIZER, .nitems = nitems, .references = ISC_REFCOUNT_INITIALIZER(1), + .mctx = isc_mem_ref(mctx), }; #if DNS_SLABHEADER_TRACE @@ -551,6 +552,7 @@ dns_slabheader__new(isc_mem_t *mctx, dns_dbnode_t *node, const char *func, .node = node, .dirtylink = ISC_LINK_INITIALIZER, .references = ISC_REFCOUNT_INITIALIZER(1), + .mctx = isc_mem_ref(mctx), }; #if DNS_SLABHEADER_TRACE @@ -570,7 +572,6 @@ static void slabheader_destroy(dns_slabheader_t *header) { unsigned int size; - isc_mem_t *mctx = header->node->mctx; dns_db_deletedata(header->node, header); if (EXISTS(header)) { @@ -579,13 +580,11 @@ slabheader_destroy(dns_slabheader_t *header) { size = sizeof(*header); } - isc_mem_put(mctx, header, size); + isc_mem_putanddetach(&header->mctx, header, size); } void dns_slabheader_freeproof(isc_mem_t *mctx, dns_slabheader_proof_t **proofp) { - unsigned int buflen; - uint8_t *rawbuf; dns_slabheader_proof_t *proof = *proofp; *proofp = NULL; @@ -593,18 +592,16 @@ dns_slabheader_freeproof(isc_mem_t *mctx, dns_slabheader_proof_t **proofp) { dns_name_free(&proof->name, mctx); } if (proof->neg != NULL) { - rawbuf = proof->neg; - rawbuf -= sizeof(dns_slabheader_t); - buflen = dns_rdataslab_size((dns_slabheader_t *)rawbuf); - - isc_mem_put(mctx, rawbuf, buflen); + dns_slabheader_t *header = + (dns_slabheader_t *)((uint8_t *)proof->neg - + sizeof(dns_slabheader_t)); + dns_slabheader_detach(&header); } if (proof->negsig != NULL) { - rawbuf = proof->negsig; - rawbuf -= sizeof(dns_slabheader_t); - buflen = dns_rdataslab_size((dns_slabheader_t *)rawbuf); - - isc_mem_put(mctx, rawbuf, buflen); + dns_slabheader_t *header = + (dns_slabheader_t *)((uint8_t *)proof->negsig - + sizeof(dns_slabheader_t)); + dns_slabheader_detach(&header); } isc_mem_put(mctx, proof, sizeof(*proof)); } @@ -620,11 +617,10 @@ ISC_REFCOUNT_IMPL(dns_slabheader, slabheader_destroy); static void rdataset_disassociate(dns_rdataset_t *rdataset DNS__DB_FLARG) { dns_slabheader_t *header = rdataset_getheader(rdataset); - dns_dbnode_t *node = header->node; dns_slabheader_detach(&header); - dns__db_detachnode(&node DNS__DB_FLARG_PASS); + dns__db_detachnode(&rdataset->slab.node DNS__DB_FLARG_PASS); } static isc_result_t @@ -706,12 +702,13 @@ rdataset_clone(const dns_rdataset_t *source, dns_rdataset_t *target DNS__DB_FLARG) { dns_slabheader_t *header = rdataset_getheader(source); - dns__db_attachnode(header->node, - &(dns_dbnode_t *){ NULL } DNS__DB_FLARG_PASS); - + INSIST(target->slab.node == NULL); INSIST(!ISC_LINK_LINKED(target, link)); *target = *source; ISC_LINK_INIT(target, link); + target->slab.node = NULL; + dns__db_attachnode(source->slab.node, + &target->slab.node DNS__DB_FLARG_PASS); target->slab.iter_pos = NULL; target->slab.iter_count = 0; @@ -730,8 +727,8 @@ static isc_result_t rdataset_getnoqname(dns_rdataset_t *rdataset, dns_name_t *name, dns_rdataset_t *nsec, dns_rdataset_t *nsecsig DNS__DB_FLARG) { + dns_dbnode_t *node = rdataset->slab.node; dns_slabheader_t *header = rdataset_getheader(rdataset); - dns_dbnode_t *node = header->node; const dns_slabheader_proof_t *noqname = rdataset->slab.noqname; /* @@ -744,22 +741,21 @@ rdataset_getnoqname(dns_rdataset_t *rdataset, dns_name_t *name, * getownercase methods from affecting the case of NSEC/NSEC3 * owner names. */ - dns__db_attachnode(node, &(dns_dbnode_t *){ NULL } DNS__DB_FLARG_PASS); *nsec = (dns_rdataset_t){ .methods = &dns_rdataslab_proof_rdatasetmethods, .rdclass = rdataset->rdclass, .type = noqname->type, .ttl = rdataset->ttl, .trust = rdataset->trust, - .proof.node = node, + .proof.header = dns_slabheader_ref(header), .proof.raw = noqname->neg, .link = nsec->link, .attributes = nsec->attributes, .magic = nsec->magic, }; nsec->attributes.keepcase = true; + dns__db_attachnode(node, &nsec->proof.node DNS__DB_FLARG_PASS); - dns__db_attachnode(node, &(dns_dbnode_t *){ NULL } DNS__DB_FLARG_PASS); *nsecsig = (dns_rdataset_t){ .methods = &dns_rdataslab_proof_rdatasetmethods, .rdclass = rdataset->rdclass, @@ -767,13 +763,14 @@ rdataset_getnoqname(dns_rdataset_t *rdataset, dns_name_t *name, .covers = noqname->type, .ttl = rdataset->ttl, .trust = rdataset->trust, - .proof.node = node, + .proof.header = dns_slabheader_ref(header), .proof.raw = noqname->negsig, .link = nsecsig->link, .attributes = nsecsig->attributes, .magic = nsecsig->magic, }; nsecsig->attributes.keepcase = true; + dns__db_attachnode(node, &nsecsig->proof.node DNS__DB_FLARG_PASS); dns_name_clone(&noqname->name, name); @@ -784,8 +781,8 @@ static isc_result_t rdataset_getclosest(dns_rdataset_t *rdataset, dns_name_t *name, dns_rdataset_t *nsec, dns_rdataset_t *nsecsig DNS__DB_FLARG) { + dns_dbnode_t *node = rdataset->slab.node; dns_slabheader_t *header = rdataset_getheader(rdataset); - dns_dbnode_t *node = header->node; const dns_slabheader_proof_t *closest = rdataset->slab.closest; /* @@ -798,22 +795,21 @@ rdataset_getclosest(dns_rdataset_t *rdataset, dns_name_t *name, * getownercase methods from affecting the case of NSEC/NSEC3 * owner names. */ - dns__db_attachnode(node, &(dns_dbnode_t *){ NULL } DNS__DB_FLARG_PASS); *nsec = (dns_rdataset_t){ .methods = &dns_rdataslab_proof_rdatasetmethods, .rdclass = rdataset->rdclass, .type = closest->type, .ttl = rdataset->ttl, .trust = rdataset->trust, - .proof.node = node, + .proof.header = dns_slabheader_ref(header), .proof.raw = closest->neg, .link = nsec->link, .attributes = nsec->attributes, .magic = nsec->magic, }; nsec->attributes.keepcase = true; + dns__db_attachnode(node, &nsec->proof.node DNS__DB_FLARG_PASS); - dns__db_attachnode(node, &(dns_dbnode_t *){ NULL } DNS__DB_FLARG_PASS); *nsecsig = (dns_rdataset_t){ .methods = &dns_rdataslab_proof_rdatasetmethods, .rdclass = rdataset->rdclass, @@ -821,13 +817,14 @@ rdataset_getclosest(dns_rdataset_t *rdataset, dns_name_t *name, .covers = closest->type, .ttl = rdataset->ttl, .trust = rdataset->trust, - .proof.node = node, + .proof.header = dns_slabheader_ref(header), .proof.raw = closest->negsig, .link = nsecsig->link, .attributes = nsecsig->attributes, .magic = nsecsig->magic, }; nsecsig->attributes.keepcase = true; + dns__db_attachnode(node, &nsecsig->proof.node DNS__DB_FLARG_PASS); dns_name_clone(&closest->name, name); @@ -846,7 +843,7 @@ static void rdataset_expire(dns_rdataset_t *rdataset DNS__DB_FLARG) { dns_slabheader_t *header = rdataset_getheader(rdataset); - dns_db_expiredata(header->node, header); + dns_db_expiredata(rdataset->slab.node, header); } static void @@ -894,9 +891,8 @@ rdataset_getheader(const dns_rdataset_t *rdataset) { static void slabheader_proof_disassociate(dns_rdataset_t *rdataset DNS__DB_FLARG) { - dns_dbnode_t *node = rdataset->proof.node; - - dns__db_detachnode(&node DNS__DB_FLARG_PASS); + dns_slabheader_detach(&rdataset->proof.header); + dns__db_detachnode(&rdataset->proof.node DNS__DB_FLARG_PASS); } static isc_result_t @@ -977,6 +973,7 @@ slabheader_proof_clone(const dns_rdataset_t *source, dns_rdataset_t *target DNS__DB_FLARG) { INSIST(!ISC_LINK_LINKED(target, link)); INSIST(target->proof.node == NULL); + INSIST(target->proof.header == NULL); *target = *source; @@ -984,6 +981,7 @@ slabheader_proof_clone(const dns_rdataset_t *source, target->proof.node = NULL; dns__db_attachnode(source->proof.node, &target->proof.node DNS__DB_FLARG_PASS); + dns_slabheader_ref(target->proof.header); target->proof.iter_pos = NULL; target->proof.iter_count = 0;