}
 #endif
 
+/*
+ * flush_reclaim_state(): add pages reclaimed outside of LRU-based reclaim to
+ * scan_control->nr_reclaimed.
+ */
+static void flush_reclaim_state(struct scan_control *sc)
+{
+       /*
+        * Currently, reclaim_state->reclaimed includes three types of pages
+        * freed outside of vmscan:
+        * (1) Slab pages.
+        * (2) Clean file pages from pruned inodes (on highmem systems).
+        * (3) XFS freed buffer pages.
+        *
+        * For all of these cases, we cannot universally link the pages to a
+        * single memcg. For example, a memcg-aware shrinker can free one object
+        * charged to the target memcg, causing an entire page to be freed.
+        * If we count the entire page as reclaimed from the memcg, we end up
+        * overestimating the reclaimed amount (potentially under-reclaiming).
+        *
+        * Only count such pages for global reclaim to prevent under-reclaiming
+        * from the target memcg; preventing unnecessary retries during memcg
+        * charging and false positives from proactive reclaim.
+        *
+        * For uncommon cases where the freed pages were actually mostly
+        * charged to the target memcg, we end up underestimating the reclaimed
+        * amount. This should be fine. The freed pages will be uncharged
+        * anyway, even if they are not counted here properly, and we will be
+        * able to make forward progress in charging (which is usually in a
+        * retry loop).
+        *
+        * We can go one step further, and report the uncharged objcg pages in
+        * memcg reclaim, to make reporting more accurate and reduce
+        * underestimation, but it's probably not worth the complexity for now.
+        */
+       if (current->reclaim_state && global_reclaim(sc)) {
+               sc->nr_reclaimed += current->reclaim_state->reclaimed;
+               current->reclaim_state->reclaimed = 0;
+       }
+}
+
 static long xchg_nr_deferred(struct shrinker *shrinker,
                             struct shrink_control *sc)
 {
                vmpressure(sc->gfp_mask, memcg, false, sc->nr_scanned - scanned,
                           sc->nr_reclaimed - reclaimed);
 
-       sc->nr_reclaimed += current->reclaim_state->reclaimed_slab;
-       current->reclaim_state->reclaimed_slab = 0;
+       flush_reclaim_state(sc);
 
        return success ? MEMCG_LRU_YOUNG : 0;
 }
 
 static void shrink_node(pg_data_t *pgdat, struct scan_control *sc)
 {
-       struct reclaim_state *reclaim_state = current->reclaim_state;
        unsigned long nr_reclaimed, nr_scanned, nr_node_reclaimed;
        struct lruvec *target_lruvec;
        bool reclaimable = false;
 
        shrink_node_memcgs(pgdat, sc);
 
-       if (reclaim_state) {
-               sc->nr_reclaimed += reclaim_state->reclaimed_slab;
-               reclaim_state->reclaimed_slab = 0;
-       }
+       flush_reclaim_state(sc);
 
        nr_node_reclaimed = sc->nr_reclaimed - nr_reclaimed;