|
@@ -1161,11 +1161,47 @@ void drain_local_pages(void *arg)
|
|
|
}
|
|
|
|
|
|
/*
|
|
|
- * Spill all the per-cpu pages from all CPUs back into the buddy allocator
|
|
|
+ * Spill all the per-cpu pages from all CPUs back into the buddy allocator.
|
|
|
+ *
|
|
|
+ * Note that this code is protected against sending an IPI to an offline
|
|
|
+ * CPU but does not guarantee sending an IPI to newly hotplugged CPUs:
|
|
|
+ * on_each_cpu_mask() blocks hotplug and won't talk to offlined CPUs but
|
|
|
+ * nothing keeps CPUs from showing up after we populated the cpumask and
|
|
|
+ * before the call to on_each_cpu_mask().
|
|
|
*/
|
|
|
void drain_all_pages(void)
|
|
|
{
|
|
|
- on_each_cpu(drain_local_pages, NULL, 1);
|
|
|
+ int cpu;
|
|
|
+ struct per_cpu_pageset *pcp;
|
|
|
+ struct zone *zone;
|
|
|
+
|
|
|
+ /*
|
|
|
+ * Allocate in the BSS so we wont require allocation in
|
|
|
+ * direct reclaim path for CONFIG_CPUMASK_OFFSTACK=y
|
|
|
+ */
|
|
|
+ static cpumask_t cpus_with_pcps;
|
|
|
+
|
|
|
+ /*
|
|
|
+ * We don't care about racing with CPU hotplug event
|
|
|
+ * as offline notification will cause the notified
|
|
|
+ * cpu to drain that CPU pcps and on_each_cpu_mask
|
|
|
+ * disables preemption as part of its processing
|
|
|
+ */
|
|
|
+ for_each_online_cpu(cpu) {
|
|
|
+ bool has_pcps = false;
|
|
|
+ for_each_populated_zone(zone) {
|
|
|
+ pcp = per_cpu_ptr(zone->pageset, cpu);
|
|
|
+ if (pcp->pcp.count) {
|
|
|
+ has_pcps = true;
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ if (has_pcps)
|
|
|
+ cpumask_set_cpu(cpu, &cpus_with_pcps);
|
|
|
+ else
|
|
|
+ cpumask_clear_cpu(cpu, &cpus_with_pcps);
|
|
|
+ }
|
|
|
+ on_each_cpu_mask(&cpus_with_pcps, drain_local_pages, NULL, 1);
|
|
|
}
|
|
|
|
|
|
#ifdef CONFIG_HIBERNATION
|