From: Christoph Lameter - Add comments explaing how drain_pages() works. - Eliminate useless functions - Rename drain_all_local_pages to drain_all_pages(). It does drain all pages not only those of the local processor. - Eliminate useless interrupt off / on sequences. drain_pages() disables interrupts on its own. The execution thread is pinned to processor by the caller. So there is no need to disable interrupts. - Put drain_all_pages() declaration in gfp.h and remove the declarations from suspend.h and from mm/memory_hotplug.c - Make software suspend call drain_all_pages(). The draining of processor local pages is may not the right approach if software suspend wants to support SMP. If they call drain_all_pages then we can make drain_pages() static. Signed-off-by: Christoph Lameter Acked-by: Mel Gorman Cc: "Rafael J. Wysocki" Signed-off-by: Andrew Morton --- include/linux/gfp.h | 1 include/linux/suspend.h | 1 kernel/power/snapshot.c | 4 - mm/memory_hotplug.c | 6 -- mm/page_alloc.c | 79 ++++++++++++++++++++------------------ 5 files changed, 47 insertions(+), 44 deletions(-) diff -puN include/linux/gfp.h~page-allocator-clean-up-pcp-draining-functions include/linux/gfp.h --- a/include/linux/gfp.h~page-allocator-clean-up-pcp-draining-functions +++ a/include/linux/gfp.h @@ -228,5 +228,6 @@ extern void FASTCALL(free_cold_page(stru void page_alloc_init(void); void drain_zone_pages(struct zone *zone, struct per_cpu_pages *pcp); +void drain_all_pages(void); #endif /* __LINUX_GFP_H */ diff -puN include/linux/suspend.h~page-allocator-clean-up-pcp-draining-functions include/linux/suspend.h --- a/include/linux/suspend.h~page-allocator-clean-up-pcp-draining-functions +++ a/include/linux/suspend.h @@ -123,7 +123,6 @@ struct pbe { }; /* mm/page_alloc.c */ -extern void drain_local_pages(void); extern void mark_free_pages(struct zone *zone); /** diff -puN kernel/power/snapshot.c~page-allocator-clean-up-pcp-draining-functions kernel/power/snapshot.c --- a/kernel/power/snapshot.c~page-allocator-clean-up-pcp-draining-functions +++ a/kernel/power/snapshot.c @@ -1203,7 +1203,7 @@ asmlinkage int swsusp_save(void) printk("swsusp: critical section: \n"); - drain_local_pages(); + drain_all_pages(); nr_pages = count_data_pages(); nr_highmem = count_highmem_pages(); printk("swsusp: Need to copy %u pages\n", nr_pages + nr_highmem); @@ -1221,7 +1221,7 @@ asmlinkage int swsusp_save(void) /* During allocating of suspend pagedir, new cold pages may appear. * Kill them. */ - drain_local_pages(); + drain_all_pages(); copy_data_pages(©_bm, &orig_bm); /* diff -puN mm/memory_hotplug.c~page-allocator-clean-up-pcp-draining-functions mm/memory_hotplug.c --- a/mm/memory_hotplug.c~page-allocator-clean-up-pcp-draining-functions +++ a/mm/memory_hotplug.c @@ -537,8 +537,6 @@ check_pages_isolated(unsigned long start return offlined; } -extern void drain_all_local_pages(void); - int offline_pages(unsigned long start_pfn, unsigned long end_pfn, unsigned long timeout) { @@ -596,7 +594,7 @@ repeat: lru_add_drain_all(); flush_scheduled_work(); cond_resched(); - drain_all_local_pages(); + drain_all_pages(); } pfn = scan_lru_pages(start_pfn, end_pfn); @@ -619,7 +617,7 @@ repeat: flush_scheduled_work(); yield(); /* drain pcp pages , this is synchrouns. */ - drain_all_local_pages(); + drain_all_pages(); /* check again */ offlined_pages = check_pages_isolated(start_pfn, end_pfn); if (offlined_pages < 0) { diff -puN mm/page_alloc.c~page-allocator-clean-up-pcp-draining-functions mm/page_alloc.c --- a/mm/page_alloc.c~page-allocator-clean-up-pcp-draining-functions +++ a/mm/page_alloc.c @@ -880,7 +880,14 @@ void drain_zone_pages(struct zone *zone, } #endif -static void __drain_pages(unsigned int cpu) +/* + * Drain pages of the indicated processor. + * + * The processor must either be the current processor and the + * thread pinned to the current processor or a processor that + * is not online. + */ +static void drain_pages(unsigned int cpu) { unsigned long flags; struct zone *zone; @@ -905,6 +912,22 @@ static void __drain_pages(unsigned int c } } +/* + * Spill all of this CPU's per-cpu pages back into the buddy allocator. + */ +static void drain_local_pages(void *arg) +{ + drain_pages(smp_processor_id()); +} + +/* + * Spill all the per-cpu pages from all CPUs back into the buddy allocator + */ +void drain_all_pages(void) +{ + on_each_cpu(drain_local_pages, NULL, 0, 1); +} + #ifdef CONFIG_HIBERNATION void mark_free_pages(struct zone *zone) @@ -942,37 +965,6 @@ void mark_free_pages(struct zone *zone) #endif /* CONFIG_PM */ /* - * Spill all of this CPU's per-cpu pages back into the buddy allocator. - */ -void drain_local_pages(void) -{ - unsigned long flags; - - local_irq_save(flags); - __drain_pages(smp_processor_id()); - local_irq_restore(flags); -} - -void smp_drain_local_pages(void *arg) -{ - drain_local_pages(); -} - -/* - * Spill all the per-cpu pages from all CPUs back into the buddy allocator - */ -void drain_all_local_pages(void) -{ - unsigned long flags; - - local_irq_save(flags); - __drain_pages(smp_processor_id()); - local_irq_restore(flags); - - smp_call_function(smp_drain_local_pages, NULL, 0, 1); -} - -/* * Free a 0-order page */ static void fastcall free_hot_cold_page(struct page *page, int cold) @@ -1559,7 +1551,7 @@ nofail_alloc: cond_resched(); if (order != 0) - drain_all_local_pages(); + drain_all_pages(); if (likely(did_some_progress)) { page = get_page_from_freelist(gfp_mask, order, @@ -3968,10 +3960,23 @@ static int page_alloc_cpu_notify(struct int cpu = (unsigned long)hcpu; if (action == CPU_DEAD || action == CPU_DEAD_FROZEN) { - local_irq_disable(); - __drain_pages(cpu); + drain_pages(cpu); + + /* + * Spill the event counters of the dead processor + * into the current processors event counters. + * This artificially elevates the count of the current + * processor. + */ vm_events_fold_cpu(cpu); - local_irq_enable(); + + /* + * Zero the differential counters of the dead processor + * so that the vm statistics are consistent. + * + * This is only okay since the processor is dead and cannot + * race with what we are doing. + */ refresh_cpu_vm_stats(cpu); } return NOTIFY_OK; @@ -4470,7 +4475,7 @@ int set_migratetype_isolate(struct page out: spin_unlock_irqrestore(&zone->lock, flags); if (!ret) - drain_all_local_pages(); + drain_all_pages(); return ret; } _