diff --git a/lib/dns/include/dns/rdataslab.h b/lib/dns/include/dns/rdataslab.h index b160f3494d..421c7df8aa 100644 --- a/lib/dns/include/dns/rdataslab.h +++ b/lib/dns/include/dns/rdataslab.h @@ -113,6 +113,11 @@ struct dns_slabheader { dns_slabheader_proof_t *noqname; dns_slabheader_proof_t *closest; + /*% + * Used for cleaning. + */ + ISC_LINK(dns_slabheader_t) dirtylink; + /*% * Points to the top slabtop structure for the type. */ diff --git a/lib/dns/qpcache.c b/lib/dns/qpcache.c index 725d51fe9c..52ea84506c 100644 --- a/lib/dns/qpcache.c +++ b/lib/dns/qpcache.c @@ -23,6 +23,7 @@ #include #include #include +#include #include #include #include @@ -152,15 +153,7 @@ struct qpcnode { struct cds_list_head types_list; struct cds_list_head *data; - /*% - * NOTE: The 'dirty' flag is protected by the node lock, so - * this bitfield has to be separated from the one above. - * We don't want it to share the same qword with bits - * that can be accessed without the node lock. - */ - uint8_t : 0; - uint8_t dirty : 1; - uint8_t : 0; + ISC_LIST(dns_slabheader_t) dirty; /*% * Used for dead nodes cleaning. This linked list is used to mark nodes @@ -579,7 +572,17 @@ clean_cache_node(qpcache_t *qpdb, qpcnode_t *node) { * Caller must be holding the node lock. */ - DNS_SLABTOP_FOREACH(top, node->data) { + /* + * We can't use ordinary loop because multiple headers to be cleaned can + * be stashed under a single slabtop. + */ + for (dns_slabheader_t *dirty = ISC_LIST_HEAD(node->dirty); + dirty != NULL; dirty = ISC_LIST_HEAD(node->dirty)) + { + dns_slabtop_t *top = dirty->top; + + ISC_LIST_UNLINK(node->dirty, dirty, dirtylink); + clean_cache_headers(top); /* @@ -617,8 +620,6 @@ clean_cache_node(qpcache_t *qpdb, qpcnode_t *node) { dns_slabtop_destroy(((dns_db_t *)qpdb)->mctx, &top); } } - - node->dirty = false; } /* @@ -767,7 +768,7 @@ qpcnode_release(qpcache_t *qpdb, qpcnode_t *node, isc_rwlocktype_t *nlocktypep, } /* Handle easy and typical case first. */ - if (!node->dirty && !cds_list_empty(node->data)) { + if (ISC_LIST_EMPTY(node->dirty) && !cds_list_empty(node->data)) { goto unref; } @@ -794,7 +795,7 @@ qpcnode_release(qpcache_t *qpdb, qpcnode_t *node, isc_rwlocktype_t *nlocktypep, } } - if (node->dirty) { + if (!ISC_LIST_EMPTY(node->dirty)) { clean_cache_node(qpdb, node); } @@ -926,7 +927,9 @@ static void mark_ancient(dns_slabheader_t *header) { setttl(header, 0); mark(header, DNS_SLABHEADERATTR_ANCIENT); - HEADERNODE(header)->dirty = 1; + if (!ISC_LINK_LINKED(header, dirtylink)) { + ISC_LIST_APPEND(HEADERNODE(header)->dirty, header, dirtylink); + } } /* @@ -2425,6 +2428,7 @@ new_qpcnode(qpcache_t *qpdb, const dns_name_t *name, dns_namespace_t nspace) { .nspace = nspace, .references = ISC_REFCOUNT_INITIALIZER(1), .locknum = isc_random_uniform(qpdb->buckets_count), + .dirty = ISC_LIST_INITIALIZER, }; isc_mem_attach(qpdb->common.mctx, &newdata->mctx); @@ -3741,6 +3745,10 @@ qpcnode_deletedata(dns_dbnode_t *node ISC_ATTR_UNUSED, void *data) { dns_slabheader_t *header = data; qpcache_t *qpdb = HEADERNODE(header)->qpdb; + if (ISC_LINK_LINKED(header, dirtylink)) { + ISC_LIST_UNLINK(HEADERNODE(header)->dirty, header, dirtylink); + } + if (header->heap != NULL && header->heap_index != 0) { isc_heap_delete(header->heap, header->heap_index); } diff --git a/lib/dns/rdataslab.c b/lib/dns/rdataslab.c index 2fa0f30c1b..2754b9ec70 100644 --- a/lib/dns/rdataslab.c +++ b/lib/dns/rdataslab.c @@ -19,6 +19,7 @@ #include #include +#include #include #include #include @@ -327,6 +328,7 @@ dns_rdataslab_fromrdataset(dns_rdataset_t *rdataset, isc_mem_t *mctx, .typepair = typepair, .trust = rdataset->trust, .ttl = rdataset->ttl, + .dirtylink = ISC_LINK_INITIALIZER, }; } @@ -833,6 +835,8 @@ dns_slabheader_reset(dns_slabheader_t *h, dns_dbnode_t *node) { atomic_init(&h->attributes, 0); atomic_init(&h->last_refresh_fail_ts, 0); + ISC_LINK_INIT(h, dirtylink); + STATIC_ASSERT(sizeof(h->attributes) == 2, "The .attributes field of dns_slabheader_t needs to be " "16-bit int type exactly."); @@ -845,6 +849,7 @@ dns_slabheader_new(isc_mem_t *mctx, dns_dbnode_t *node) { h = isc_mem_get(mctx, sizeof(*h)); *h = (dns_slabheader_t){ .node = node, + .dirtylink = ISC_LINK_INITIALIZER, }; return h; }