patch-2.4.0-test5 linux/mm/page_alloc.c

Next file: linux/mm/vmscan.c
Previous file: linux/mm/mmap.c
Back to the patch index
Back to the overall index

diff -u --recursive --new-file v2.4.0-test4/linux/mm/page_alloc.c linux/mm/page_alloc.c
@@ -64,7 +64,8 @@
  * Hint: -mask = 1+~mask
  */
 
-void __free_pages_ok (struct page *page, unsigned long order)
+static void FASTCALL(__free_pages_ok (struct page *page, unsigned long order));
+static void __free_pages_ok (struct page *page, unsigned long order)
 {
 	unsigned long index, page_idx, mask, flags;
 	free_area_t *area;
@@ -217,7 +218,7 @@
  */
 struct page * __alloc_pages(zonelist_t *zonelist, unsigned long order)
 {
-	zone_t **zone = zonelist->zones;
+	zone_t **zone;
 	extern wait_queue_head_t kswapd_wait;
 
 	/*
@@ -228,21 +229,6 @@
 	 * in a higher zone fails.
 	 */
 
-	for (;;) {
-		zone_t *z = *(zone++);
-		if (!z)
-			break;
-		if (!z->size)
-			BUG();
-
-		/* If there are zones with a lot of free memory allocate from them */
-		if (z->free_pages > z->pages_high) {
-			struct page *page = rmqueue(z, order);
-			if (page)
-				return page;
-		}
-	}
-
 	zone = zonelist->zones;
 	for (;;) {
 		zone_t *z = *(zone++);
@@ -264,6 +250,21 @@
 		}
 	}
 
+	/* Three possibilities to get here
+	 * - Previous alloc_pages resulted in last zone set to have
+	 *   zone_wake_kswapd and start it. kswapd has not been able
+	 *   to release enough pages so that one zone does not have
+	 *   zone_wake_kswapd set.
+	 * - Different sets of zones (zonelist)
+	 *   previous did not have all zones with zone_wake_kswapd but
+	 *   this one has... should kswapd be woken up? it will run once.
+	 * - SMP race, kswapd went to sleep slightly after it as running
+	 *   in 'if (waitqueue_active(...))' above.
+	 * + anyway the test is very cheap to do...
+	 */
+	if (waitqueue_active(&kswapd_wait))
+		wake_up_interruptible(&kswapd_wait);
+
 	/*
 	 * Ok, we don't have any zones that don't need some
 	 * balancing.. See if we have any that aren't critical..
@@ -313,6 +314,50 @@
 fail:
 	/* No luck.. */
 	return NULL;
+}
+
+/*
+ * Common helper functions.
+ */
+unsigned long __get_free_pages(int gfp_mask, unsigned long order)
+{
+	struct page * page;
+
+	page = alloc_pages(gfp_mask, order);
+	if (!page)
+		return 0;
+	return page_address(page);
+}
+
+unsigned long get_zeroed_page(int gfp_mask)
+{
+	struct page * page;
+
+	page = alloc_pages(gfp_mask, 0);
+	if (page) {
+		unsigned long address = page_address(page);
+		clear_page((void *)address);
+		return address;
+	}
+	return 0;
+}
+
+void __free_pages(struct page *page, unsigned long order)
+{
+	if (put_page_testzero(page))
+		__free_pages_ok(page, order);
+}
+
+void free_pages(unsigned long addr, unsigned long order)
+{
+	unsigned long map_nr;
+
+#ifdef CONFIG_DISCONTIGMEM
+	if (addr == 0) return;
+#endif
+	map_nr = MAP_NR(addr);
+	if (map_nr < max_mapnr)
+		__free_pages(mem_map + map_nr, order);
 }
 
 /*

FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)