diff --git a/lib/dns/adb.c b/lib/dns/adb.c index 00471556cb..50d4d83bf3 100644 --- a/lib/dns/adb.c +++ b/lib/dns/adb.c @@ -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