History

Revert "memcg: cleanup racy sum avoidance code"

This reverts commit 96e51ccf1af33e82f429a0d6baebba29c6448d0f. Recently we started running the kernel with rstat infrastructure on production traffic and begin to see negative memcg stats values. Particularly the 'sock' stat is the one which we observed having negative value. $ grep "sock " /mnt/memory/job/memory.stat sock 253952 total_sock 18446744073708724224 Re-run after couple of seconds $ grep "sock " /mnt/memory/job/memory.stat sock 253952 total_sock 53248 For now we are only seeing this issue on large machines (256 CPUs) and only with 'sock' stat. I think the networking stack increase the stat on one cpu and decrease it on another cpu much more often. So, this negative sock is due to rstat flusher flushing the stats on the CPU that has seen the decrement of sock but missed the CPU that has increments. A typical race condition. For easy stable backport, revert is the most simple solution. For long term solution, I am thinking of two directions. First is just reduce the race window by optimizing the rstat flusher. Second is if the reader sees a negative stat value, force flush and restart the stat collection. Basically retry but limited.

Shakeel Butt committed 4 years ago

Commit dbb16df1 parent a5d21721 file · +13 −2Browse files

Showing the changes to include/linux (1 of 1 file). Show all

Unified · Split

include/linux/memcontrol.h+13−2
@@ -987,19 +987,30 @@ static inline void mod_memcg_page_state(struct page *page, · 986 unmodified lines
987 987
988static inline unsigned long memcg_page_state(struct mem_cgroup *memcg, int idx)988static inline unsigned long memcg_page_state(struct mem_cgroup *memcg, int idx)
989{989{
990 return READ_ONCE(memcg->vmstats.state[idx]);990 long x = READ_ONCE(memcg->vmstats.state[idx]);
991#ifdef CONFIG_SMP
992 if (x < 0)
993 x = 0;
994#endif
995 return x;
991}996}
992 997
993static inline unsigned long lruvec_page_state(struct lruvec *lruvec,998static inline unsigned long lruvec_page_state(struct lruvec *lruvec,
994 enum node_stat_item idx)999 enum node_stat_item idx)
995{1000{
996 struct mem_cgroup_per_node *pn;1001 struct mem_cgroup_per_node *pn;
1002 long x;
997 1003
998 if (mem_cgroup_disabled())1004 if (mem_cgroup_disabled())
999 return node_page_state(lruvec_pgdat(lruvec), idx);1005 return node_page_state(lruvec_pgdat(lruvec), idx);
1000 1006
1001 pn = container_of(lruvec, struct mem_cgroup_per_node, lruvec);1007 pn = container_of(lruvec, struct mem_cgroup_per_node, lruvec);
1002 return READ_ONCE(pn->lruvec_stats.state[idx]);1008 x = READ_ONCE(pn->lruvec_stats.state[idx]);
1009#ifdef CONFIG_SMP
1010 if (x < 0)
1011 x = 0;
1012#endif
1013 return x;
1003}1014}
1004 1015
1005static inline unsigned long lruvec_page_state_local(struct lruvec *lruvec,1016static inline unsigned long lruvec_page_state_local(struct lruvec *lruvec,