From 6306d4857d08b5aa6f190cdd54fe3231f3a35d9f Mon Sep 17 00:00:00 2001
From: Andrew Morton <akpm@digeo.com>
Date: Sun, 29 Dec 2002 21:40:31 -0800
Subject: [PATCH] [PATCH] add drain_local_pages() for CONFIG_SOFTWARE_SUSPEND

swsusp gets confused when pages which it freed do not appear in the
buddy lists.  So provide a function which will drain the calling CPU's
per-cpu-pages into the buddy.

The patch has been tested by Pavel.  Presence of the new code is
conditional on CONFIG_SOFTWARE_SUSPEND.
---
 include/linux/suspend.h |  3 +++
 mm/page_alloc.c         | 25 +++++++++++++++++++++++++
 2 files changed, 28 insertions(+)

diff --git a/include/linux/suspend.h b/include/linux/suspend.h
index a481f80034fa..80b4a657b49c 100644
--- a/include/linux/suspend.h
+++ b/include/linux/suspend.h
@@ -46,6 +46,9 @@ struct suspend_header {
 /* mm/vmscan.c */
 extern int shrink_mem(void);
 
+/* mm/page_alloc.c */
+extern void drain_local_pages(void);
+
 /* kernel/suspend.c */
 extern void software_suspend(void);
 extern void software_resume(void);
diff --git a/mm/page_alloc.c b/mm/page_alloc.c
index 7de787fd57d9..1c8015736d61 100644
--- a/mm/page_alloc.c
+++ b/mm/page_alloc.c
@@ -350,6 +350,31 @@ int is_head_of_free_region(struct page *page)
 	spin_unlock_irqrestore(&zone->lock, flags);
         return 0;
 }
+
+/*
+ * Spill all of this CPU's per-cpu pages back into the buddy allocator.
+ */
+void drain_local_pages(void)
+{
+	unsigned long flags;
+	struct zone *zone;
+	int i;
+
+	local_irq_save(flags);	
+	for_each_zone(zone) {
+		struct per_cpu_pageset *pset;
+
+		pset = &zone->pageset[smp_processor_id()];
+		for (i = 0; i < ARRAY_SIZE(pset->pcp); i++) {
+			struct per_cpu_pages *pcp;
+
+			pcp = &pset->pcp[i];
+			pcp->count -= free_pages_bulk(zone, pcp->count,
+						&pcp->list, 0);
+		}
+	}
+	local_irq_restore(flags);	
+}
 #endif /* CONFIG_SOFTWARE_SUSPEND */
 
 /*
-- 
2.30.9