summaryrefslogtreecommitdiff
path: root/mm/list_lru.c
diff options
context:
space:
mode:
authorSahitya Tummala <stummala@codeaurora.org>2017-07-10 15:49:57 -0700
committerSasha Levin <alexander.levin@verizon.com>2017-07-31 13:37:54 -0400
commiteb8e478e472c57ed02dc5705779298e421b7d96f (patch)
treed052f2fb3957c051c3b37af43a299fb486a4f0a7 /mm/list_lru.c
parent9052d52e8bce71fd5cfd78f79b26f90831dbd7ba (diff)
mm/list_lru.c: fix list_lru_count_node() to be race free
[ Upstream commit 2c80cd57c74339889a8752b20862a16c28929c3a ] 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/1498707555-30525-1-git-send-email-stummala@codeaurora.org Signed-off-by: Sahitya Tummala <stummala@codeaurora.org> Acked-by: Vladimir Davydov <vdavydov.dev@gmail.com> Cc: Jan Kara <jack@suse.cz> Cc: Alexander Polakov <apolyakov@beget.ru> Cc: Al Viro <viro@zeniv.linux.org.uk> Cc: <stable@vger.kernel.org> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org> Signed-off-by: Sasha Levin <alexander.levin@verizon.com>
Diffstat (limited to 'mm/list_lru.c')
-rw-r--r--mm/list_lru.c14
1 files changed, 6 insertions, 8 deletions
diff --git a/mm/list_lru.c b/mm/list_lru.c
index 84b4c21d78d7..2a6a2e4b64ba 100644
--- a/mm/list_lru.c
+++ b/mm/list_lru.c
@@ -103,6 +103,7 @@ bool list_lru_add(struct list_lru *lru, struct list_head *item)
if (list_empty(item)) {
list_add_tail(item, &l->list);
l->nr_items++;
+ nlru->nr_items++;
spin_unlock(&nlru->lock);
return true;
}
@@ -122,6 +123,7 @@ bool list_lru_del(struct list_lru *lru, struct list_head *item)
if (!list_empty(item)) {
list_del_init(item);
l->nr_items--;
+ nlru->nr_items--;
spin_unlock(&nlru->lock);
return true;
}
@@ -169,15 +171,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);
@@ -212,6 +209,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