aboutsummaryrefslogtreecommitdiffstats
path: root/mm
diff options
context:
space:
mode:
authorJohannes Weiner <jweiner@fb.com>2016-09-19 17:44:36 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2016-09-19 18:36:17 -0400
commitdb2ba40c277dc545bab531671c3f45ac0afea6f8 (patch)
tree0a8cf97596ce97c77a4cf44e4ab8262cbdb429af /mm
parent3bb8b653c86f6b1d2cc05aa1744fed4b18f99485 (diff)
mm: memcontrol: make per-cpu charge cache IRQ-safe for socket accounting
During cgroup2 rollout into production, we started encountering css refcount underflows and css access crashes in the memory controller. Splitting the heavily shared css reference counter into logical users narrowed the imbalance down to the cgroup2 socket memory accounting. The problem turns out to be the per-cpu charge cache. Cgroup1 had a separate socket counter, but the new cgroup2 socket accounting goes through the common charge path that uses a shared per-cpu cache for all memory that is being tracked. Those caches are safe against scheduling preemption, but not against interrupts - such as the newly added packet receive path. When cache draining is interrupted by network RX taking pages out of the cache, the resuming drain operation will put references of in-use pages, thus causing the imbalance. Disable IRQs during all per-cpu charge cache operations. Fixes: f7e1cb6ec51b ("mm: memcontrol: account socket memory in unified hierarchy memory controller") Link: http://lkml.kernel.org/r/20160914194846.11153-1-hannes@cmpxchg.org Signed-off-by: Johannes Weiner <hannes@cmpxchg.org> Acked-by: Tejun Heo <tj@kernel.org> Cc: "David S. Miller" <davem@davemloft.net> Cc: Michal Hocko <mhocko@suse.cz> Cc: Vladimir Davydov <vdavydov@virtuozzo.com> Cc: <stable@vger.kernel.org> [4.5+] Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'mm')
-rw-r--r--mm/memcontrol.c31
1 files changed, 22 insertions, 9 deletions
diff --git a/mm/memcontrol.c b/mm/memcontrol.c
index 9a6a51a7c416..4be518d4e68a 100644
--- a/mm/memcontrol.c
+++ b/mm/memcontrol.c
@@ -1740,17 +1740,22 @@ static DEFINE_MUTEX(percpu_charge_mutex);
1740static bool consume_stock(struct mem_cgroup *memcg, unsigned int nr_pages) 1740static bool consume_stock(struct mem_cgroup *memcg, unsigned int nr_pages)
1741{ 1741{
1742 struct memcg_stock_pcp *stock; 1742 struct memcg_stock_pcp *stock;
1743 unsigned long flags;
1743 bool ret = false; 1744 bool ret = false;
1744 1745
1745 if (nr_pages > CHARGE_BATCH) 1746 if (nr_pages > CHARGE_BATCH)
1746 return ret; 1747 return ret;
1747 1748
1748 stock = &get_cpu_var(memcg_stock); 1749 local_irq_save(flags);
1750
1751 stock = this_cpu_ptr(&memcg_stock);
1749 if (memcg == stock->cached && stock->nr_pages >= nr_pages) { 1752 if (memcg == stock->cached && stock->nr_pages >= nr_pages) {
1750 stock->nr_pages -= nr_pages; 1753 stock->nr_pages -= nr_pages;
1751 ret = true; 1754 ret = true;
1752 } 1755 }
1753 put_cpu_var(memcg_stock); 1756
1757 local_irq_restore(flags);
1758
1754 return ret; 1759 return ret;
1755} 1760}
1756 1761
@@ -1771,15 +1776,18 @@ static void drain_stock(struct memcg_stock_pcp *stock)
1771 stock->cached = NULL; 1776 stock->cached = NULL;
1772} 1777}
1773 1778
1774/*
1775 * This must be called under preempt disabled or must be called by
1776 * a thread which is pinned to local cpu.
1777 */
1778static void drain_local_stock(struct work_struct *dummy) 1779static void drain_local_stock(struct work_struct *dummy)
1779{ 1780{
1780 struct memcg_stock_pcp *stock = this_cpu_ptr(&memcg_stock); 1781 struct memcg_stock_pcp *stock;
1782 unsigned long flags;
1783
1784 local_irq_save(flags);
1785
1786 stock = this_cpu_ptr(&memcg_stock);
1781 drain_stock(stock); 1787 drain_stock(stock);
1782 clear_bit(FLUSHING_CACHED_CHARGE, &stock->flags); 1788 clear_bit(FLUSHING_CACHED_CHARGE, &stock->flags);
1789
1790 local_irq_restore(flags);
1783} 1791}
1784 1792
1785/* 1793/*
@@ -1788,14 +1796,19 @@ static void drain_local_stock(struct work_struct *dummy)
1788 */ 1796 */
1789static void refill_stock(struct mem_cgroup *memcg, unsigned int nr_pages) 1797static void refill_stock(struct mem_cgroup *memcg, unsigned int nr_pages)
1790{ 1798{
1791 struct memcg_stock_pcp *stock = &get_cpu_var(memcg_stock); 1799 struct memcg_stock_pcp *stock;
1800 unsigned long flags;
1801
1802 local_irq_save(flags);
1792 1803
1804 stock = this_cpu_ptr(&memcg_stock);
1793 if (stock->cached != memcg) { /* reset if necessary */ 1805 if (stock->cached != memcg) { /* reset if necessary */
1794 drain_stock(stock); 1806 drain_stock(stock);
1795 stock->cached = memcg; 1807 stock->cached = memcg;
1796 } 1808 }
1797 stock->nr_pages += nr_pages; 1809 stock->nr_pages += nr_pages;
1798 put_cpu_var(memcg_stock); 1810
1811 local_irq_restore(flags);
1799} 1812}
1800 1813
1801/* 1814/*