[RFC PATCH 1/6] f2fs: generalize metadata cache shrinking to explicit lists
From: Wenjie Qi
Date: Tue Sep 29 2026 - 03:31:42 EST
The metadata-cache shrinker currently operates on cache->lru_list.
Node-cache compression needs separate raw and compressed queues, while
keeping the existing isolation, truncation and refcount rules.
Move the common shrink loop to f2fs_shrink_cache_list(), and pass it an
explicit list, population and scan budget. Existing caches continue to
use their current LRU lists.
Also return the number of examined entries for queue-specific reclaim
accounting.
Signed-off-by: Wenjie Qi <qiwenjie@xxxxxxxxxx>
---
fs/f2fs/cache.c | 30 +++++++++++++++++++++---------
fs/f2fs/cache.h | 6 +++++-
2 files changed, 26 insertions(+), 10 deletions(-)
diff --git a/fs/f2fs/cache.c b/fs/f2fs/cache.c
index 38fc5eb17f92..8f81aed132ed 100644
--- a/fs/f2fs/cache.c
+++ b/fs/f2fs/cache.c
@@ -547,8 +547,10 @@ void f2fs_destroy_cache(struct f2fs_cached_block_list *cache)
goto next;
}
-static unsigned long f2fs_do_shrink_cache(struct f2fs_cached_block_list *cache,
- unsigned long nr_to_scan)
+unsigned long
+f2fs_shrink_cache_list(struct f2fs_cached_block_list *cache,
+ struct list_head *head, unsigned long nr_entries,
+ unsigned long nr_to_scan, unsigned long *nr_scanned)
{
struct f2fs_cached_block *entry, *next;
LIST_HEAD(dispose_list);
@@ -558,15 +560,15 @@ static unsigned long f2fs_do_shrink_cache(struct f2fs_cached_block_list *cache,
/* Phase 1: Isolate candidate entries from LRU list into dispose_list */
spin_lock(&cache->list_lock);
- list_for_each_entry_safe(entry, next, &cache->lru_list, list) {
- if (scanned >= cache->num_entries)
- break;
- if (scanned++ >= nr_to_scan)
+ nr_entries = min(nr_entries, cache->num_entries);
+ list_for_each_entry_safe(entry, next, head, list) {
+ if (scanned >= nr_entries || scanned >= nr_to_scan)
break;
+ scanned++;
/* If accessed, give it a second chance to rotate to tail */
if (f2fs_cache_test_and_clear_referenced(entry)) {
- list_move_tail(&entry->list, &cache->lru_list);
+ list_move_tail(&entry->list, head);
continue;
}
@@ -620,16 +622,26 @@ static unsigned long f2fs_do_shrink_cache(struct f2fs_cached_block_list *cache,
freed++;
}
- /* Phase 3: Splice un-reclaimed entries back onto cache->lru_list */
+ /* Phase 3: Splice un-reclaimed entries back onto the scanned list */
if (!list_empty(&keep_list)) {
spin_lock(&cache->list_lock);
- list_splice_tail(&keep_list, &cache->lru_list);
+ list_splice_tail(&keep_list, head);
spin_unlock(&cache->list_lock);
}
+ if (nr_scanned)
+ *nr_scanned = scanned;
return freed;
}
+static unsigned long
+f2fs_do_shrink_cache(struct f2fs_cached_block_list *cache,
+ unsigned long nr_to_scan)
+{
+ return f2fs_shrink_cache_list(cache, &cache->lru_list, ULONG_MAX,
+ nr_to_scan, NULL);
+}
+
unsigned long f2fs_shrink_cache(struct f2fs_sb_info *sbi,
unsigned long nr_to_scan)
{
diff --git a/fs/f2fs/cache.h b/fs/f2fs/cache.h
index 6c4db910d767..c4c3d09a0008 100644
--- a/fs/f2fs/cache.h
+++ b/fs/f2fs/cache.h
@@ -222,7 +222,11 @@ void f2fs_drop_cache_range(struct f2fs_cached_block_list *cache,
f2fs_drop_cache_range(NODE_CACHE(sbi), start, len, true)
unsigned long f2fs_shrink_cache(struct f2fs_sb_info *sbi,
- unsigned long nr_to_scan);
+ unsigned long nr_to_scan);
+unsigned long
+f2fs_shrink_cache_list(struct f2fs_cached_block_list *cache,
+ struct list_head *head, unsigned long nr_entries,
+ unsigned long nr_to_scan, unsigned long *nr_scanned);
#define DEF_DIRTY_CACHE_TIMEOUT 5000
#define MIN_DIRTY_CACHE_TIMEOUT 100
--
2.43.0