[9.20] fix: dev: Fix data race in server round-trip time tracking

The SRTT (Smoothed Round-Trip Time) update for remote servers was not
atomic — concurrent callers could each read the same value and one
update would be silently lost. Additionally, the aging decay applied
once per second could run multiple times if several threads entered the
function simultaneously.

Use compare-and-swap loops for the SRTT update and for the aging
timestamp to ensure no updates are lost.

Backport of MR !11718

Merge branch 'backport-ondrej/fix-non-atomic-srtt-aging-9.20' into 'bind-9.20'

See merge request isc-projects/bind9!11723
This commit is contained in:
Ondřej Surý 2026-03-20 02:47:55 +01:00
commit 31cbfc9fb3

View file

@ -3029,22 +3029,35 @@ static void
adjustsrtt(dns_adbaddrinfo_t *addr, unsigned int rtt, unsigned int factor,
isc_stdtime_t now) {
unsigned int new_srtt;
unsigned int old_srtt;
if (factor == DNS_ADB_RTTADJAGE) {
if (atomic_load(&addr->entry->lastage) != now) {
new_srtt = (uint64_t)atomic_load(&addr->entry->srtt) *
98 / 100;
atomic_store(&addr->entry->lastage, now);
atomic_store(&addr->entry->srtt, new_srtt);
addr->srtt = new_srtt;
isc_stdtime_t lastage =
atomic_load_acquire(&addr->entry->lastage);
/* prevent double aging */
if (lastage == now ||
!atomic_compare_exchange_strong_acq_rel(
&addr->entry->lastage, &lastage, now))
{
return;
}
} else {
new_srtt = ((uint64_t)atomic_load(&addr->entry->srtt) / 10 *
factor) +
((uint64_t)rtt / 10 * (10 - factor));
atomic_store(&addr->entry->srtt, new_srtt);
addr->srtt = new_srtt;
}
/*
* Correct CAS aging...
*/
old_srtt = atomic_load_acquire(&addr->entry->srtt);
do {
if (factor == DNS_ADB_RTTADJAGE) {
new_srtt = (uint64_t)old_srtt * 98 / 100;
} else {
new_srtt = ((uint64_t)old_srtt / 10 * factor) +
((uint64_t)rtt / 10 * (10 - factor));
}
} while (!atomic_compare_exchange_weak_acq_rel(&addr->entry->srtt,
&old_srtt, new_srtt));
addr->srtt = new_srtt;
}
void