]> git.ipfire.org Git - thirdparty/bind9.git/commitdiff
lib/dns/adb.c: Use atomics for adb quota values and reference counting
authorWitold Kręcicki <wpk@isc.org>
Tue, 22 Jan 2019 09:47:18 +0000 (10:47 +0100)
committerOndřej Surý <ondrej@isc.org>
Tue, 26 Nov 2019 12:07:12 +0000 (13:07 +0100)
lib/dns/adb.c

index ce879f09d54c794f97513e219e74552d5e3c8160..d07dcd36ad5529104001425d79050da587efae9b 100644 (file)
@@ -252,8 +252,8 @@ struct dns_adbentry {
        unsigned char                   to4096;         /* Our max. */
 
        uint8_t                 mode;
-       uint32_t                        quota;
-       uint32_t                        active;
+       atomic_uint_fast32_t            quota;
+       atomic_uint_fast32_t            active;
        double                          atr;
 
        /*
@@ -1832,9 +1832,9 @@ new_adbentry(dns_adb_t *adb) {
        e->srtt = (isc_random_uniform(0x1f)) + 1;
        e->lastage = 0;
        e->expires = 0;
-       e->active = 0;
+       atomic_init(&e->active, 0);
        e->mode = 0;
-       e->quota = adb->quota;
+       atomic_init(&e->quota, adb->quota);
        e->atr = 0.0;
        ISC_LIST_INIT(e->lameinfo);
        ISC_LINK_INIT(e, plink);
@@ -2161,8 +2161,10 @@ log_quota(dns_adbentry_t *entry, const char *fmt, ...) {
        isc_netaddr_format(&netaddr, addrbuf, sizeof(addrbuf));
 
        isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE, DNS_LOGMODULE_ADB,
-                     ISC_LOG_INFO, "adb: quota %s (%u/%u): %s",
-                     addrbuf, entry->active, entry->quota, msgbuf);
+                     ISC_LOG_INFO,
+                     "adb: quota %s (%" PRIuFAST32 "/%" PRIuFAST32 "): %s",
+                     addrbuf, atomic_load_relaxed(&entry->active),
+                     atomic_load_relaxed(&entry->quota), msgbuf);
 }
 
 static void
@@ -2185,9 +2187,7 @@ copy_namehook_lists(dns_adb_t *adb, dns_adbfind_t *find,
                        INSIST(bucket != DNS_ADB_INVALIDBUCKET);
                        LOCK(&adb->entrylocks[bucket]);
 
-                       if (entry->quota != 0 &&
-                           entry->active >= entry->quota)
-                       {
+                       if (dns_adbentry_overquota(entry)) {
                                find->options |=
                                        (DNS_ADBFIND_LAMEPRUNED|
                                         DNS_ADBFIND_OVERQUOTA);
@@ -2225,9 +2225,7 @@ copy_namehook_lists(dns_adb_t *adb, dns_adbfind_t *find,
                        INSIST(bucket != DNS_ADB_INVALIDBUCKET);
                        LOCK(&adb->entrylocks[bucket]);
 
-                       if (entry->quota != 0 &&
-                           entry->active >= entry->quota)
-                       {
+                       if (dns_adbentry_overquota(entry)) {
                                find->options |=
                                        (DNS_ADBFIND_LAMEPRUNED|
                                         DNS_ADBFIND_OVERQUOTA);
@@ -3534,8 +3532,8 @@ dump_entry(FILE *f, dns_adb_t *adb, dns_adbentry_t *entry,
                fprintf(f, " [ttl %d]", (int)(entry->expires - now));
 
        if (adb != NULL && adb->quota != 0 && adb->atr_freq != 0) {
-               fprintf(f, " [atr %0.2f] [quota %u]",
-                       entry->atr, entry->quota);
+               fprintf(f, " [atr %0.2f] [quota %" PRIuFAST32 "]",
+                       entry->atr, atomic_load_relaxed(&entry->quota));
        }
 
        fprintf(f, "\n");
@@ -4257,21 +4255,25 @@ maybe_adjust_quota(dns_adb_t *adb, dns_adbaddrinfo_t *addr,
        addr->entry->atr = ISC_CLAMP(addr->entry->atr, 0.0, 1.0);
 
        if (addr->entry->atr < adb->atr_low && addr->entry->mode > 0) {
-               addr->entry->quota = adb->quota *
-                       quota_adj[--addr->entry->mode] / 10000;
-               log_quota(addr->entry, "atr %0.2f, quota increased to %u",
-                         addr->entry->atr, addr->entry->quota);
+               uint_fast32_t new_quota =
+                       adb->quota * quota_adj[--addr->entry->mode] / 10000;
+               atomic_store_release(&addr->entry->quota,
+                                    ISC_MIN(1, new_quota));
+               log_quota(addr->entry, "atr %0.2f, quota increased to %"
+                         PRIuFAST32,
+                         addr->entry->atr,
+                         new_quota);
        } else if (addr->entry->atr > adb->atr_high &&
                   addr->entry->mode < (QUOTA_ADJ_SIZE - 1)) {
-               addr->entry->quota = adb->quota *
-                       quota_adj[++addr->entry->mode] / 10000;
-               log_quota(addr->entry, "atr %0.2f, quota decreased to %u",
-                         addr->entry->atr, addr->entry->quota);
+               uint_fast32_t new_quota =
+                       adb->quota * quota_adj[++addr->entry->mode] / 10000;
+               atomic_store_release(&addr->entry->quota,
+                                    ISC_MIN(1, new_quota));
+               log_quota(addr->entry, "atr %0.2f, quota decreased to %"
+                         PRIuFAST32,
+                         addr->entry->atr,
+                         new_quota);
        }
-
-       /* Ensure we don't drop to zero */
-       if (addr->entry->quota == 0)
-               addr->entry->quota = 1;
 }
 
 #define EDNSTOS 3U
@@ -4773,34 +4775,25 @@ dns_adb_setquota(dns_adb_t *adb, uint32_t quota, uint32_t freq,
 bool
 dns_adbentry_overquota(dns_adbentry_t *entry) {
        REQUIRE(DNS_ADBENTRY_VALID(entry));
-       return (entry->quota != 0 && entry->active >= entry->quota);
+
+       uint_fast32_t quota = atomic_load_relaxed(&entry->quota);
+       uint_fast32_t active = atomic_load_acquire(&entry->active);
+
+       return (quota != 0 && active >= quota);
 }
 
 void
 dns_adb_beginudpfetch(dns_adb_t *adb, dns_adbaddrinfo_t *addr) {
-       int bucket;
-
        REQUIRE(DNS_ADB_VALID(adb));
        REQUIRE(DNS_ADBADDRINFO_VALID(addr));
 
-       bucket = addr->entry->lock_bucket;
-
-       LOCK(&adb->entrylocks[bucket]);
-       addr->entry->active++;
-       UNLOCK(&adb->entrylocks[bucket]);
+       INSIST(atomic_fetch_add_relaxed(&addr->entry->active, 1) != UINT32_MAX);
 }
 
 void
 dns_adb_endudpfetch(dns_adb_t *adb, dns_adbaddrinfo_t *addr) {
-       int bucket;
-
        REQUIRE(DNS_ADB_VALID(adb));
        REQUIRE(DNS_ADBADDRINFO_VALID(addr));
 
-       bucket = addr->entry->lock_bucket;
-
-       LOCK(&adb->entrylocks[bucket]);
-       if (addr->entry->active > 0)
-               addr->entry->active--;
-       UNLOCK(&adb->entrylocks[bucket]);
+       INSIST(atomic_fetch_sub_release(&addr->entry->active, 1) != 0);
 }