From: Ondřej Surý Date: Fri, 12 Sep 2025 09:25:40 +0000 (+0200) Subject: Convert slabtop to use the cds_list X-Git-Tag: v9.21.14~32^2~1 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=63389b8ce6da705da10606829b0eb9031f22df26;p=thirdparty%2Fbind9.git Convert slabtop to use the cds_list This is the first commit in series that aims to reduce the node locking by replacing the single-linked list of slabtop(s) with CDS linked list. This commit doesn't do anything else beyond replacing .next link with the cds_list_head. RCU semantics is going to be added in the subsequent commits. --- diff --git a/lib/dns/include/dns/rdataslab.h b/lib/dns/include/dns/rdataslab.h index 59387029277..bacec3bcf70 100644 --- a/lib/dns/include/dns/rdataslab.h +++ b/lib/dns/include/dns/rdataslab.h @@ -64,15 +64,18 @@ struct dns_slabheader_proof { dns_rdatatype_t type; }; -#define DNS_SLABTOP_FOREACH(elt, first) \ - for (dns_slabtop_t *elt = first, \ - *elt##_next = (elt != NULL) ? elt->next : NULL; \ - elt != NULL; \ - elt = elt##_next, elt##_next = (elt != NULL) ? elt->next : NULL) +#define DNS_SLABTOP_FOREACH(pos, head) \ + dns_slabtop_t *pos = NULL, *pos##_next = NULL; \ + cds_list_for_each_entry_safe(pos, pos##_next, head, types_link) + +#define DNS_SLABTOP_FOREACH_FROM(pos, head, first) \ + dns_slabtop_t *pos = first, *pos##_next = NULL; \ + cds_list_for_each_entry_safe_from(pos, pos##_next, head, types_link) typedef struct dns_slabtop dns_slabtop_t; struct dns_slabtop { - dns_slabtop_t *next; + struct cds_list_head types_link; + dns_slabheader_t *header; dns_typepair_t typepair; diff --git a/lib/dns/qpcache.c b/lib/dns/qpcache.c index efc987c12cc..e90277cb33c 100644 --- a/lib/dns/qpcache.c +++ b/lib/dns/qpcache.c @@ -157,7 +157,8 @@ struct qpcnode { isc_refcount_t references; isc_refcount_t erefs; - dns_slabtop_t *data; + struct cds_list_head types_list; + struct cds_list_head *data; /*% * NOTE: The 'dirty' flag is protected by the node lock, so @@ -561,8 +562,6 @@ clean_cache_headers(dns_slabtop_t *top) { static void clean_cache_node(qpcache_t *qpdb, qpcnode_t *node) { - dns_slabtop_t *top_prev = NULL; - /* * Caller must be holding the node lock. */ @@ -584,11 +583,7 @@ clean_cache_node(qpcache_t *qpdb, qpcnode_t *node) { * If current slabtop is empty, we can clean it up. */ if (top->header == NULL) { - if (top_prev != NULL) { - top_prev->next = top->next; - } else { - node->data = top->next; - } + cds_list_del(&top->types_link); if (ISC_LINK_LINKED(top, link)) { ISC_SIEVE_UNLINK( @@ -596,8 +591,6 @@ clean_cache_node(qpcache_t *qpdb, qpcnode_t *node) { link); } dns_slabtop_destroy(((dns_db_t *)qpdb)->mctx, &top); - } else { - top_prev = top; } } @@ -750,7 +743,7 @@ qpcnode_release(qpcache_t *qpdb, qpcnode_t *node, isc_rwlocktype_t *nlocktypep, } /* Handle easy and typical case first. */ - if (!node->dirty && node->data != NULL) { + if (!node->dirty && !cds_list_empty(node->data)) { goto unref; } @@ -781,7 +774,7 @@ qpcnode_release(qpcache_t *qpdb, qpcnode_t *node, isc_rwlocktype_t *nlocktypep, clean_cache_node(qpdb, node); } - if (node->data != NULL) { + if (!cds_list_empty(node->data)) { goto unref; } @@ -2383,6 +2376,8 @@ static qpcnode_t * new_qpcnode(qpcache_t *qpdb, const dns_name_t *name, dns_namespace_t nspace) { qpcnode_t *newdata = isc_mem_get(qpdb->common.mctx, sizeof(*newdata)); *newdata = (qpcnode_t){ + .types_list = CDS_LIST_HEAD_INIT(newdata->types_list), + .data = &newdata->types_list, .methods = &qpcnode_methods, .qpdb = qpdb, .name = DNS_NAME_INITEMPTY, @@ -2888,16 +2883,13 @@ add(qpcache_t *qpdb, qpcnode_t *qpnode, dns_slabheader_t *newheader, if (prio_header(newtop)) { /* This is a priority type, prepend it */ - newtop->next = qpnode->data; - qpnode->data = newtop; + cds_list_add(&newtop->types_link, qpnode->data); } else if (priotop != NULL) { /* Append after the priority headers */ - newtop->next = priotop->next; - priotop->next = newtop; + cds_list_add(&newtop->types_link, &priotop->types_link); } else { /* There were no priority headers */ - newtop->next = qpnode->data; - qpnode->data = newtop; + cds_list_add(&newtop->types_link, qpnode->data); } if (overmaxtype(qpdb, ntypes)) { @@ -3387,24 +3379,29 @@ rdatasetiter_next(dns_rdatasetiter_t *it DNS__DB_FLARG) { qpcnode_t *qpnode = (qpcnode_t *)iterator->common.node; isc_rwlocktype_t nlocktype = isc_rwlocktype_none; isc_rwlock_t *nlock = &qpdb->buckets[qpnode->locknum].lock; - dns_slabtop_t *next = NULL; + dns_slabtop_t *from = NULL; if (iterator->current == NULL) { return ISC_R_NOMORE; } - next = iterator->current->next; - iterator->current = NULL; NODE_RDLOCK(nlock, &nlocktype); - DNS_SLABTOP_FOREACH(top, next) { - dns_slabheader_t *header = first_existing_header(top); + from = cds_list_entry(iterator->current->types_link.next, dns_slabtop_t, + types_link); + iterator->current = NULL; - if (EXPIREDOK(iterator) || - (header != NULL && iterator_active(qpdb, iterator, header))) - { - iterator->current = top; - break; + if (from != NULL) { + DNS_SLABTOP_FOREACH_FROM(top, qpnode->data, from) { + dns_slabheader_t *header = first_existing_header(top); + + if (EXPIREDOK(iterator) || + (header != NULL && + iterator_active(qpdb, iterator, header))) + { + iterator->current = top; + break; + } } } diff --git a/lib/dns/qpzone.c b/lib/dns/qpzone.c index 9eaf4f28e79..567603eba79 100644 --- a/lib/dns/qpzone.c +++ b/lib/dns/qpzone.c @@ -198,7 +198,9 @@ struct qpznode { atomic_bool wild; atomic_bool delegating; atomic_bool dirty; - dns_slabtop_t *data; + + struct cds_list_head types_list; + struct cds_list_head *data; }; struct qpzonedb { @@ -631,6 +633,8 @@ static qpznode_t * new_qpznode(qpzonedb_t *qpdb, const dns_name_t *name, dns_namespace_t nspace) { qpznode_t *newdata = isc_mem_get(qpdb->common.mctx, sizeof(*newdata)); *newdata = (qpznode_t){ + .types_list = CDS_LIST_HEAD_INIT(newdata->types_list), + .data = &newdata->types_list, .methods = &qpznode_methods, .name = DNS_NAME_INITEMPTY, .nspace = nspace, @@ -848,7 +852,6 @@ clean_multiple_versions(dns_slabtop_t *top, uint32_t least_serial) { static void clean_zone_node(qpznode_t *node, uint32_t least_serial) { - dns_slabtop_t *top_prev = NULL; bool still_dirty = false; /* @@ -873,11 +876,7 @@ clean_zone_node(qpznode_t *node, uint32_t least_serial) { check_top_header(top); if (top->header == NULL) { - if (top_prev != NULL) { - top_prev->next = top->next; - } else { - node->data = top->next; - } + cds_list_del(&top->types_link); dns_slabtop_destroy(node->mctx, &top); } else { /* @@ -891,8 +890,6 @@ clean_zone_node(qpznode_t *node, uint32_t least_serial) { */ still_dirty = clean_multiple_versions(top, least_serial); - - top_prev = top; } } if (!still_dirty) { @@ -942,7 +939,7 @@ qpznode_release(qpznode_t *node, uint32_t least_serial, } /* Handle easy and typical case first. */ - if (!node->dirty && node->data != NULL) { + if (!node->dirty && !cds_list_empty(node->data)) { goto unref; } @@ -1998,16 +1995,14 @@ add(qpzonedb_t *qpdb, qpznode_t *node, const dns_name_t *nodename, if (prio_type(newheader->typepair)) { /* This is a priority type, prepend it */ - newtop->next = node->data; - node->data = newtop; + cds_list_add(&newtop->types_link, node->data); } else if (priotop != NULL) { /* Append after the priority headers */ - newtop->next = priotop->next; - priotop->next = newtop; + cds_list_add(&newtop->types_link, + &priotop->types_link); } else { /* There were no priority headers */ - newtop->next = node->data; - node->data = newtop; + cds_list_add(&newtop->types_link, node->data); } } } @@ -3964,25 +3959,30 @@ rdatasetiter_next(dns_rdatasetiter_t *iterator DNS__DB_FLARG) { qpz_version_t *version = (qpz_version_t *)qrditer->common.version; isc_rwlocktype_t nlocktype = isc_rwlocktype_none; isc_rwlock_t *nlock = qpzone_get_lock(node); - dns_slabtop_t *next = NULL; + dns_slabtop_t *from = NULL; if (qrditer->currenttop == NULL) { return ISC_R_NOMORE; } - next = qrditer->currenttop->next; - qrditer->currenttop = NULL; - qrditer->current = NULL; NODE_RDLOCK(nlock, &nlocktype); + from = cds_list_entry(qrditer->currenttop->types_link.next, + dns_slabtop_t, types_link); + qrditer->currenttop = NULL; + qrditer->current = NULL; + /* * Find the start of the header chain for the next type. */ - DNS_SLABTOP_FOREACH(top, next) { - qrditer->current = first_existing_header(top, version->serial); - if (qrditer->current != NULL) { - qrditer->currenttop = top; - break; + if (from != NULL) { + DNS_SLABTOP_FOREACH_FROM(top, node->data, from) { + qrditer->current = + first_existing_header(top, version->serial); + if (qrditer->current != NULL) { + qrditer->currenttop = top; + break; + } } } diff --git a/lib/dns/rdataslab.c b/lib/dns/rdataslab.c index 3616b3aeadc..beb5f38d019 100644 --- a/lib/dns/rdataslab.c +++ b/lib/dns/rdataslab.c @@ -1179,6 +1179,7 @@ dns_slabtop_t * dns_slabtop_new(isc_mem_t *mctx, dns_typepair_t typepair) { dns_slabtop_t *top = isc_mem_get(mctx, sizeof(*top)); *top = (dns_slabtop_t){ + .types_link = CDS_LIST_HEAD_INIT(top->types_link), .typepair = typepair, .link = ISC_LINK_INITIALIZER, }; diff --git a/lib/isc/include/isc/urcu.h b/lib/isc/include/isc/urcu.h index cf62934632b..88e68bf80ce 100644 --- a/lib/isc/include/isc/urcu.h +++ b/lib/isc/include/isc/urcu.h @@ -30,6 +30,7 @@ #include #include +#include #include #include #include