4.11-stable review patch.  If anyone has any objections, please let me know.

------------------

From: Sahitya Tummala <[email protected]>

commit 2c80cd57c74339889a8752b20862a16c28929c3a upstream.

list_lru_count_node() iterates over all memcgs to get the total number of
entries on the node but it can race with memcg_drain_all_list_lrus(),
which migrates the entries from a dead cgroup to another.  This can return
incorrect number of entries from list_lru_count_node().

Fix this by keeping track of entries per node and simply return it in
list_lru_count_node().

Link: 
http://lkml.kernel.org/r/[email protected]
Signed-off-by: Sahitya Tummala <[email protected]>
Acked-by: Vladimir Davydov <[email protected]>
Cc: Jan Kara <[email protected]>
Cc: Alexander Polakov <[email protected]>
Cc: Al Viro <[email protected]>
Signed-off-by: Andrew Morton <[email protected]>
Signed-off-by: Linus Torvalds <[email protected]>
Signed-off-by: Greg Kroah-Hartman <[email protected]>

---
 include/linux/list_lru.h |    1 +
 mm/list_lru.c            |   14 ++++++--------
 2 files changed, 7 insertions(+), 8 deletions(-)

--- a/include/linux/list_lru.h
+++ b/include/linux/list_lru.h
@@ -44,6 +44,7 @@ struct list_lru_node {
        /* for cgroup aware lrus points to per cgroup lists, otherwise NULL */
        struct list_lru_memcg   *memcg_lrus;
 #endif
+       long nr_items;
 } ____cacheline_aligned_in_smp;
 
 struct list_lru {
--- a/mm/list_lru.c
+++ b/mm/list_lru.c
@@ -117,6 +117,7 @@ bool list_lru_add(struct list_lru *lru,
                l = list_lru_from_kmem(nlru, item);
                list_add_tail(item, &l->list);
                l->nr_items++;
+               nlru->nr_items++;
                spin_unlock(&nlru->lock);
                return true;
        }
@@ -136,6 +137,7 @@ bool list_lru_del(struct list_lru *lru,
                l = list_lru_from_kmem(nlru, item);
                list_del_init(item);
                l->nr_items--;
+               nlru->nr_items--;
                spin_unlock(&nlru->lock);
                return true;
        }
@@ -183,15 +185,10 @@ EXPORT_SYMBOL_GPL(list_lru_count_one);
 
 unsigned long list_lru_count_node(struct list_lru *lru, int nid)
 {
-       long count = 0;
-       int memcg_idx;
+       struct list_lru_node *nlru;
 
-       count += __list_lru_count_one(lru, nid, -1);
-       if (list_lru_memcg_aware(lru)) {
-               for_each_memcg_cache_index(memcg_idx)
-                       count += __list_lru_count_one(lru, nid, memcg_idx);
-       }
-       return count;
+       nlru = &lru->node[nid];
+       return nlru->nr_items;
 }
 EXPORT_SYMBOL_GPL(list_lru_count_node);
 
@@ -226,6 +223,7 @@ restart:
                        assert_spin_locked(&nlru->lock);
                case LRU_REMOVED:
                        isolated++;
+                       nlru->nr_items--;
                        /*
                         * If the lru lock has been dropped, our list
                         * traversal is now invalid and so we have to


Reply via email to