}
 
 /* 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);
 
        XA_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;
                                        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;
 
  * @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;
 
        /*
         * 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);
 
        mod_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);