]> git.ipfire.org Git - thirdparty/bind9.git/commitdiff
Don't expire fresh ADB names and entries
authorOndřej Surý <ondrej@isc.org>
Tue, 13 Dec 2022 13:32:19 +0000 (14:32 +0100)
committerOndřej Surý <ondrej@isc.org>
Mon, 19 Dec 2022 08:26:58 +0000 (09:26 +0100)
The overmem cleaning in ADB could become overzealous and clean fresh ADB
names and entries.  Add a safety check to not clean any ADB names and
entries that are below ADB_CACHE_MINIMUM threshold.

(cherry picked from commit 0b661b6f951907dcff23b48a10e8984a1f28eb74)

lib/dns/adb.c

index dca715bea617ed478e22f0ffc09f8254581bb7a9..208c659187aaf685d7d2b3428a66cde78c4aef1a 100644 (file)
@@ -324,7 +324,7 @@ inc_adb_erefcnt(dns_adb_t *);
 static void
 inc_entry_refcnt(dns_adb_t *, dns_adbentry_t *, bool);
 static bool
-dec_entry_refcnt(dns_adb_t *, bool, dns_adbentry_t *, bool);
+dec_entry_refcnt(dns_adb_t *, bool, dns_adbentry_t *, bool, isc_stdtime_t);
 static void
 violate_locking_hierarchy(isc_mutex_t *, isc_mutex_t *);
 static bool
@@ -1372,7 +1372,8 @@ clean_namehooks(dns_adb_t *adb, dns_adbnamehooklist_t *namehooks) {
                        }
 
                        entry->nh--;
-                       result = dec_entry_refcnt(adb, overmem, entry, false);
+                       result = dec_entry_refcnt(adb, overmem, entry, false,
+                                                 INT_MAX);
                }
 
                /*
@@ -1648,10 +1649,10 @@ inc_entry_refcnt(dns_adb_t *adb, dns_adbentry_t *entry, bool lock) {
 }
 
 static bool
-dec_entry_refcnt(dns_adb_t *adb, bool overmem, dns_adbentry_t *entry,
-                bool lock) {
+dec_entry_refcnt(dns_adb_t *adb, bool overmem, dns_adbentry_t *entry, bool lock,
+                isc_stdtime_t now) {
        int bucket;
-       bool destroy_entry;
+       bool destroy_entry = false;
        bool result = false;
 
        bucket = entry->lock_bucket;
@@ -1663,9 +1664,9 @@ dec_entry_refcnt(dns_adb_t *adb, bool overmem, dns_adbentry_t *entry,
        INSIST(entry->refcnt > 0);
        entry->refcnt--;
 
-       destroy_entry = false;
        if (entry->refcnt == 0 &&
-           (adb->entry_sd[bucket] || entry->expires == 0 || overmem ||
+           (adb->entry_sd[bucket] || entry->expires == 0 ||
+            (overmem && entry->expires + ADB_CACHE_MINIMUM < now) ||
             (entry->flags & ENTRY_IS_DEAD) != 0))
        {
                destroy_entry = true;
@@ -2370,6 +2371,14 @@ check_stale_name(dns_adb_t *adb, int bucket, isc_stdtime_t now) {
                        goto next;
                }
 
+               /*
+                * Make sure that we are not purging ADB names that has been
+                * just created.
+                */
+               if (victim->last_used + ADB_CACHE_MINIMUM >= now) {
+                       break;
+               }
+
                if (!NAME_FETCH(victim) &&
                    (overmem || victim->last_used + ADB_STALE_MARGIN <= now))
                {
@@ -3240,6 +3249,7 @@ dns_adb_destroyfind(dns_adbfind_t **findp) {
        int bucket;
        dns_adb_t *adb;
        bool overmem;
+       isc_stdtime_t now;
 
        REQUIRE(findp != NULL && DNS_ADBFIND_VALID(*findp));
        find = *findp;
@@ -3264,6 +3274,7 @@ dns_adb_destroyfind(dns_adbfind_t **findp) {
         * Return the find to the memory pool, and decrement the adb's
         * reference count.
         */
+       isc_stdtime_get(&now);
        overmem = isc_mem_isovermem(adb->mctx);
        ai = ISC_LIST_HEAD(find->list);
        while (ai != NULL) {
@@ -3271,7 +3282,8 @@ dns_adb_destroyfind(dns_adbfind_t **findp) {
                entry = ai->entry;
                ai->entry = NULL;
                INSIST(DNS_ADBENTRY_VALID(entry));
-               RUNTIME_CHECK(!dec_entry_refcnt(adb, overmem, entry, true));
+               RUNTIME_CHECK(
+                       !dec_entry_refcnt(adb, overmem, entry, true, now));
                free_adbaddrinfo(adb, &ai);
                ai = ISC_LIST_HEAD(find->list);
        }
@@ -4533,12 +4545,12 @@ dns_adb_freeaddrinfo(dns_adb_t *adb, dns_adbaddrinfo_t **addrp) {
        bucket = addr->entry->lock_bucket;
        LOCK(&adb->entrylocks[bucket]);
 
+       isc_stdtime_get(&now);
        if (entry->expires == 0) {
-               isc_stdtime_get(&now);
                entry->expires = now + ADB_ENTRY_WINDOW;
        }
 
-       want_check_exit = dec_entry_refcnt(adb, overmem, entry, false);
+       want_check_exit = dec_entry_refcnt(adb, overmem, entry, false, now);
 
        UNLOCK(&adb->entrylocks[bucket]);