aboutsummaryrefslogtreecommitdiffstats
path: root/mm
diff options
context:
space:
mode:
authorTejun Heo <tj@kernel.org>2015-05-22 18:23:18 -0400
committerJens Axboe <axboe@fb.com>2015-06-02 10:38:12 -0400
commit733a572e66d2a23c852fdce34dba5bbd40667817 (patch)
tree6c248783b36581b36ee3f37a3ebd6a48428f2123 /mm
parent108dad65be9786650c78ed9aea28c9b4a68810d9 (diff)
memcg: make mem_cgroup_read_{stat|event}() iterate possible cpus instead of online
cpu_possible_mask represents the CPUs which are actually possible during that boot instance. For systems which don't support CPU hotplug, this will match cpu_online_mask exactly in most cases. Even for systems which support CPU hotplug, the number of possible CPU slots is highly unlikely to diverge greatly from the number of online CPUs. The only cases where the difference between possible and online caused problems were when the boot code failed to initialize the possible mask and left it fully set at NR_CPUS - 1. As such, most per-cpu constructs allocate for all possible CPUs and often iterate over the possibles, which also has the benefit of avoiding the blocking CPU hotplug synchronization. memcg open codes per-cpu stat counting for mem_cgroup_read_stat() and mem_cgroup_read_events(), which iterates over online CPUs and handles CPU hotplug operations explicitly. This complexity doesn't actually buy anything. Switch to iterating over the possibles and drop the explicit CPU hotplug handling. Eventually, we want to convert memcg to use percpu_counter instead of its own custom implementation which also benefits from quick access w/o summing for cases where larger error margin is acceptable. This will allow mem_cgroup_read_stat() to be called from non-sleepable contexts which will be used by cgroup writeback. Signed-off-by: Tejun Heo <tj@kernel.org> Cc: Michal Hocko <mhocko@suse.cz> Acked-by: Johannes Weiner <hannes@cmpxchg.org> Signed-off-by: Jens Axboe <axboe@fb.com>
Diffstat (limited to 'mm')
-rw-r--r--mm/memcontrol.c51
1 files changed, 2 insertions, 49 deletions
diff --git a/mm/memcontrol.c b/mm/memcontrol.c
index 49e5aa6abca6..701cbee9acba 100644
--- a/mm/memcontrol.c
+++ b/mm/memcontrol.c
@@ -324,11 +324,6 @@ struct mem_cgroup {
324 * percpu counter. 324 * percpu counter.
325 */ 325 */
326 struct mem_cgroup_stat_cpu __percpu *stat; 326 struct mem_cgroup_stat_cpu __percpu *stat;
327 /*
328 * used when a cpu is offlined or other synchronizations
329 * See mem_cgroup_read_stat().
330 */
331 struct mem_cgroup_stat_cpu nocpu_base;
332 spinlock_t pcp_counter_lock; 327 spinlock_t pcp_counter_lock;
333 328
334#if defined(CONFIG_MEMCG_KMEM) && defined(CONFIG_INET) 329#if defined(CONFIG_MEMCG_KMEM) && defined(CONFIG_INET)
@@ -834,15 +829,8 @@ static long mem_cgroup_read_stat(struct mem_cgroup *memcg,
834 long val = 0; 829 long val = 0;
835 int cpu; 830 int cpu;
836 831
837 get_online_cpus(); 832 for_each_possible_cpu(cpu)
838 for_each_online_cpu(cpu)
839 val += per_cpu(memcg->stat->count[idx], cpu); 833 val += per_cpu(memcg->stat->count[idx], cpu);
840#ifdef CONFIG_HOTPLUG_CPU
841 spin_lock(&memcg->pcp_counter_lock);
842 val += memcg->nocpu_base.count[idx];
843 spin_unlock(&memcg->pcp_counter_lock);
844#endif
845 put_online_cpus();
846 return val; 834 return val;
847} 835}
848 836
@@ -852,15 +840,8 @@ static unsigned long mem_cgroup_read_events(struct mem_cgroup *memcg,
852 unsigned long val = 0; 840 unsigned long val = 0;
853 int cpu; 841 int cpu;
854 842
855 get_online_cpus(); 843 for_each_possible_cpu(cpu)
856 for_each_online_cpu(cpu)
857 val += per_cpu(memcg->stat->events[idx], cpu); 844 val += per_cpu(memcg->stat->events[idx], cpu);
858#ifdef CONFIG_HOTPLUG_CPU
859 spin_lock(&memcg->pcp_counter_lock);
860 val += memcg->nocpu_base.events[idx];
861 spin_unlock(&memcg->pcp_counter_lock);
862#endif
863 put_online_cpus();
864 return val; 845 return val;
865} 846}
866 847
@@ -2210,37 +2191,12 @@ static void drain_all_stock(struct mem_cgroup *root_memcg)
2210 mutex_unlock(&percpu_charge_mutex); 2191 mutex_unlock(&percpu_charge_mutex);
2211} 2192}
2212 2193
2213/*
2214 * This function drains percpu counter value from DEAD cpu and
2215 * move it to local cpu. Note that this function can be preempted.
2216 */
2217static void mem_cgroup_drain_pcp_counter(struct mem_cgroup *memcg, int cpu)
2218{
2219 int i;
2220
2221 spin_lock(&memcg->pcp_counter_lock);
2222 for (i = 0; i < MEM_CGROUP_STAT_NSTATS; i++) {
2223 long x = per_cpu(memcg->stat->count[i], cpu);
2224
2225 per_cpu(memcg->stat->count[i], cpu) = 0;
2226 memcg->nocpu_base.count[i] += x;
2227 }
2228 for (i = 0; i < MEM_CGROUP_EVENTS_NSTATS; i++) {
2229 unsigned long x = per_cpu(memcg->stat->events[i], cpu);
2230
2231 per_cpu(memcg->stat->events[i], cpu) = 0;
2232 memcg->nocpu_base.events[i] += x;
2233 }
2234 spin_unlock(&memcg->pcp_counter_lock);
2235}
2236
2237static int memcg_cpu_hotplug_callback(struct notifier_block *nb, 2194static int memcg_cpu_hotplug_callback(struct notifier_block *nb,
2238 unsigned long action, 2195 unsigned long action,
2239 void *hcpu) 2196 void *hcpu)
2240{ 2197{
2241 int cpu = (unsigned long)hcpu; 2198 int cpu = (unsigned long)hcpu;
2242 struct memcg_stock_pcp *stock; 2199 struct memcg_stock_pcp *stock;
2243 struct mem_cgroup *iter;
2244 2200
2245 if (action == CPU_ONLINE) 2201 if (action == CPU_ONLINE)
2246 return NOTIFY_OK; 2202 return NOTIFY_OK;
@@ -2248,9 +2204,6 @@ static int memcg_cpu_hotplug_callback(struct notifier_block *nb,
2248 if (action != CPU_DEAD && action != CPU_DEAD_FROZEN) 2204 if (action != CPU_DEAD && action != CPU_DEAD_FROZEN)
2249 return NOTIFY_OK; 2205 return NOTIFY_OK;
2250 2206
2251 for_each_mem_cgroup(iter)
2252 mem_cgroup_drain_pcp_counter(iter, cpu);
2253
2254 stock = &per_cpu(memcg_stock, cpu); 2207 stock = &per_cpu(memcg_stock, cpu);
2255 drain_stock(stock); 2208 drain_stock(stock);
2256 return NOTIFY_OK; 2209 return NOTIFY_OK;