summaryrefslogtreecommitdiff
path: root/backport-Skip-unusable-entries-in-first-pass-in-prune_cache.patch
diff options
context:
space:
mode:
Diffstat (limited to 'backport-Skip-unusable-entries-in-first-pass-in-prune_cache.patch')
-rw-r--r--backport-Skip-unusable-entries-in-first-pass-in-prune_cache.patch93
1 files changed, 93 insertions, 0 deletions
diff --git a/backport-Skip-unusable-entries-in-first-pass-in-prune_cache.patch b/backport-Skip-unusable-entries-in-first-pass-in-prune_cache.patch
new file mode 100644
index 0000000..dcd3609
--- /dev/null
+++ b/backport-Skip-unusable-entries-in-first-pass-in-prune_cache.patch
@@ -0,0 +1,93 @@
+From c00b984fcd53f679ca2dafcd1aee2c89836e6e73 Mon Sep 17 00:00:00 2001
+From: Florian Weimer <fweimer@redhat.com>
+Date: Tue, 29 Aug 2023 08:28:31 +0200
+Subject: [PATCH] nscd: Skip unusable entries in first pass in prune_cache (bug
+ 30800)
+
+Previously, if an entry was marked unusable for any reason, but had
+not timed out yet, the assert would trigger.
+
+One way to get into such state is if a data change is detected during
+re-validation of an entry. This causes the entry to be marked as not
+usable. If exits nscd soon after that, then the clock jumps
+backwards, and nscd restarted, the cache re-validation run after
+startup triggers the removed assert.
+
+The change is more complicated than just the removal of the assert
+because entries marked as not usable should be garbage-collected in
+the second pass. To make this happen, it is necessary to update some
+book-keeping data.
+
+Reviewed-by: DJ Delorie <dj@redhat.com>
+
+Conflict:NA
+Reference:https://sourceware.org/git/?p=glibc.git;a=commitdiff;h=c00b984fcd53f679ca2dafcd1aee2c89836e6e73
+
+---
+ nscd/cache.c | 25 +++++++++++--------------
+ 1 file changed, 11 insertions(+), 14 deletions(-)
+
+diff --git a/nscd/cache.c b/nscd/cache.c
+index 78b22697..ac5902ae 100644
+--- a/nscd/cache.c
++++ b/nscd/cache.c
+@@ -371,8 +371,11 @@ prune_cache (struct database_dyn *table, time_t now, int fd)
+ serv2str[runp->type], str, dh->timeout);
+ }
+
+- /* Check whether the entry timed out. */
+- if (dh->timeout < now)
++ /* Check whether the entry timed out. Timed out entries
++ will be revalidated. For unusable records, it is still
++ necessary to record that the bucket needs to be scanned
++ again below. */
++ if (dh->timeout < now || !dh->usable)
+ {
+ /* This hash bucket could contain entries which need to
+ be looked at. */
+@@ -384,7 +387,7 @@ prune_cache (struct database_dyn *table, time_t now, int fd)
+ /* We only have to look at the data of the first entries
+ since the count information is kept in the data part
+ which is shared. */
+- if (runp->first)
++ if (runp->first && dh->usable)
+ {
+
+ /* At this point there are two choices: we reload the
+@@ -400,9 +403,6 @@ prune_cache (struct database_dyn *table, time_t now, int fd)
+ {
+ /* Remove the value. */
+ dh->usable = false;
+-
+- /* We definitely have some garbage entries now. */
+- any = true;
+ }
+ else
+ {
+@@ -414,18 +414,15 @@ prune_cache (struct database_dyn *table, time_t now, int fd)
+
+ time_t timeout = readdfcts[runp->type] (table, runp, dh);
+ next_timeout = MIN (next_timeout, timeout);
+-
+- /* If the entry has been replaced, we might need
+- cleanup. */
+- any |= !dh->usable;
+ }
+ }
++
++ /* If the entry has been replaced, we might need cleanup. */
++ any |= !dh->usable;
+ }
+ else
+- {
+- assert (dh->usable);
+- next_timeout = MIN (next_timeout, dh->timeout);
+- }
++ /* Entry has not timed out and is usable. */
++ next_timeout = MIN (next_timeout, dh->timeout);
+
+ run = runp->next;
+ }
+--
+2.33.0
+