diff options
Diffstat (limited to 'mm/memcontrol.c')
-rw-r--r-- | mm/memcontrol.c | 20 |
1 files changed, 15 insertions, 5 deletions
diff --git a/mm/memcontrol.c b/mm/memcontrol.c index 15af3da5af02..696c6529e900 100644 --- a/mm/memcontrol.c +++ b/mm/memcontrol.c | |||
@@ -1777,6 +1777,10 @@ static void drain_local_stock(struct work_struct *dummy) | |||
1777 | struct memcg_stock_pcp *stock; | 1777 | struct memcg_stock_pcp *stock; |
1778 | unsigned long flags; | 1778 | unsigned long flags; |
1779 | 1779 | ||
1780 | /* | ||
1781 | * The only protection from memory hotplug vs. drain_stock races is | ||
1782 | * that we always operate on local CPU stock here with IRQ disabled | ||
1783 | */ | ||
1780 | local_irq_save(flags); | 1784 | local_irq_save(flags); |
1781 | 1785 | ||
1782 | stock = this_cpu_ptr(&memcg_stock); | 1786 | stock = this_cpu_ptr(&memcg_stock); |
@@ -1821,27 +1825,33 @@ static void drain_all_stock(struct mem_cgroup *root_memcg) | |||
1821 | /* If someone's already draining, avoid adding running more workers. */ | 1825 | /* If someone's already draining, avoid adding running more workers. */ |
1822 | if (!mutex_trylock(&percpu_charge_mutex)) | 1826 | if (!mutex_trylock(&percpu_charge_mutex)) |
1823 | return; | 1827 | return; |
1824 | /* Notify other cpus that system-wide "drain" is running */ | 1828 | /* |
1825 | get_online_cpus(); | 1829 | * Notify other cpus that system-wide "drain" is running |
1830 | * We do not care about races with the cpu hotplug because cpu down | ||
1831 | * as well as workers from this path always operate on the local | ||
1832 | * per-cpu data. CPU up doesn't touch memcg_stock at all. | ||
1833 | */ | ||
1826 | curcpu = get_cpu(); | 1834 | curcpu = get_cpu(); |
1827 | for_each_online_cpu(cpu) { | 1835 | for_each_online_cpu(cpu) { |
1828 | struct memcg_stock_pcp *stock = &per_cpu(memcg_stock, cpu); | 1836 | struct memcg_stock_pcp *stock = &per_cpu(memcg_stock, cpu); |
1829 | struct mem_cgroup *memcg; | 1837 | struct mem_cgroup *memcg; |
1830 | 1838 | ||
1831 | memcg = stock->cached; | 1839 | memcg = stock->cached; |
1832 | if (!memcg || !stock->nr_pages) | 1840 | if (!memcg || !stock->nr_pages || !css_tryget(&memcg->css)) |
1833 | continue; | 1841 | continue; |
1834 | if (!mem_cgroup_is_descendant(memcg, root_memcg)) | 1842 | if (!mem_cgroup_is_descendant(memcg, root_memcg)) { |
1843 | css_put(&memcg->css); | ||
1835 | continue; | 1844 | continue; |
1845 | } | ||
1836 | if (!test_and_set_bit(FLUSHING_CACHED_CHARGE, &stock->flags)) { | 1846 | if (!test_and_set_bit(FLUSHING_CACHED_CHARGE, &stock->flags)) { |
1837 | if (cpu == curcpu) | 1847 | if (cpu == curcpu) |
1838 | drain_local_stock(&stock->work); | 1848 | drain_local_stock(&stock->work); |
1839 | else | 1849 | else |
1840 | schedule_work_on(cpu, &stock->work); | 1850 | schedule_work_on(cpu, &stock->work); |
1841 | } | 1851 | } |
1852 | css_put(&memcg->css); | ||
1842 | } | 1853 | } |
1843 | put_cpu(); | 1854 | put_cpu(); |
1844 | put_online_cpus(); | ||
1845 | mutex_unlock(&percpu_charge_mutex); | 1855 | mutex_unlock(&percpu_charge_mutex); |
1846 | } | 1856 | } |
1847 | 1857 | ||