cachestat-do-not-flush-stats-in-recency-check.patch removed from -mm tree
The quilt patch titled
Subject: cachestat: do not flush stats in recency check
has been removed from the -mm tree. Its filename was
cachestat-do-not-flush-stats-in-recency-check.patch
This patch was dropped because it was merged into the mm-hotfixes-stable branch of git://git.kernel.org/pub/scm/linux/kernel/git/akpm/mm
------------------------------------------------------
From: Nhat Pham <[email protected]>
Subject: cachestat: do not flush stats in recency check
Date: Thu, 27 Jun 2024 13:17:37 -0700
syzbot detects that cachestat() is flushing stats, which can sleep, in its RCU read section (see [1]). This is done in the workingset_test_recent() step (which checks if the folio's eviction is recent).
Move the stat flushing step to before the RCU read section of cachestat, and skip stat flushing during the recency check.
[1]: https://lore.kernel.org/cgroups/[email protected]/
---
include/linux/swap.h | 3 ++- mm/filemap.c | 5 ++++- mm/workingset.c | 14 +++++++++++--- 3 files changed, 17 insertions(+), 5 deletions(-)
include/linux/swap.h renamed from include/linux/swap.h~cachestat-do-not-flush-stats-in-recency-check +2 -1
@@ -354,7 +354,8 @@ static inline swp_entry_t page_swap_entr }/* linux/mm/workingset.c */ -bool workingset_test_recent (void *shadow,bool file,bool *workingset); +bool workingset_test_recent (void *shadow,bool file,bool *workingset, +bool flush);void workingset_age_nonresident (struct lruvec *lruvec,unsigned long nr_pages);void *workingset_eviction (struct folio *folio,struct mem_cgroup *target_memcg);void workingset_refault (struct folio *folio,void *shadow);
mm/filemap.c renamed from mm/filemap.c~cachestat-do-not-flush-stats-in-recency-check +4 -1
@@ -4248,6 +4248,9 @@ static void filemap_cachestat(struct addXA_STATE (xas, &mapping->i_pages, first_index);struct folio *folio; +/* Flush stats (and potentially sleep) outside the RCU read section. */ +mem_cgroup_flush_stats_ratelimited (NULL ); +rcu_read_lock ();xas_for_each (&xas, folio, last_index) {int order;
@@ -4311,7 +4314,7 @@ static void filemap_cachestat(struct add goto resched; }#endif -if (workingset_test_recent (shadow, true, &workingset)) +if (workingset_test_recent (shadow, true, &workingset, false)) cs->nr_recently_evicted += nr_pages; goto resched;
mm/workingset.c renamed from mm/workingset.c~cachestat-do-not-flush-stats-in-recency-check +11 -3
@@ -412,10 +412,12 @@ void *workingset_eviction(struct folio ** @file: whether the corresponding folio is from the file lru. * @workingset: where the workingset value unpacked from shadow should * be stored. +* @flush: whether to flush cgroup rstat. * * Return: true if the shadow is for a recently evicted folio; false otherwise. */ -bool workingset_test_recent (void *shadow,bool file,bool *workingset) +bool workingset_test_recent (void *shadow,bool file,bool *workingset, +bool flush) {struct mem_cgroup *eviction_memcg;struct lruvec *eviction_lruvec;
@@ -467,10 +469,16 @@ bool workingset_test_recent(void *shadow/* * Flush stats (and potentially sleep) outside the RCU read section. +* +* Note that workingset_test_recent() itself might be called in RCU read +* section (for e.g, in cachestat) - these callers need to skip flushing +* stats (via the flush argument). +* * XXX: With per-memcg flushing and thresholding, is ratelimiting * still needed here? */ -mem_cgroup_flush_stats_ratelimited (eviction_memcg); +if (flush) +mem_cgroup_flush_stats_ratelimited (eviction_memcg); eviction_lruvec =mem_cgroup_lruvec (eviction_memcg, pgdat); refault =atomic_long_read (&eviction_lruvec->nonresident_age);
@@ -558,7 +566,7 @@ void workingset_refault(struct folio *fomod_lruvec_state (lruvec,WORKINGSET_REFAULT_BASE + file, nr); -if (!workingset_test_recent (shadow, file, &workingset)) +if (!workingset_test_recent (shadow, file, &workingset, true))return ;folio_set_active (folio);
_
Patches currently in -mm which might be from [email protected] are