[RFC][PATCH 2/3] alloc-order watermarks

Nick Piggin
2004-09-05T05:46:41Z

[-- Attachment #1: Type: text/plain, Size: 4 bytes --]

2/3

[-- Attachment #2: vm-alloc-order-watermarks.patch --]
[-- Type: text/x-patch, Size: 3849 bytes --]

Move the watermark checking code into a single function. Extend it to account
for the order of the allocation and the number of free pages that could satisfy
such a request.

Signed-off-by: Nick Piggin <nickpiggin@yahoo.com.au>

---

linux-2.6-npiggin/include/linux/mmzone.h | 2 +
linux-2.6-npiggin/mm/page_alloc.c | 57 ++++++++++++++++++++-----------
2 files changed, 40 insertions(+), 19 deletions(-)

diff -puN mm/page_alloc.c~vm-alloc-order-watermarks mm/page_alloc.c
--- linux-2.6/mm/page_alloc.c~vm-alloc-order-watermarks 2004-09-05 14:55:46.000000000 +1000
+++ linux-2.6-npiggin/mm/page_alloc.c 2004-09-05 15:10:07.000000000 +1000
@@ -676,6 +676,36 @@ buffered_rmqueue(struct zone *zone, int
}

/*
+ * Return the number of pages available for order 'order' allocations.
+ */
+int zone_watermark_ok(struct zone *z, int order, unsigned long mark,
+ int alloc_type, int can_try_harder, int gfp_high)
+{
+ unsigned long min = mark, free_pages = z->free_pages;
+ int o;
+
+ if (gfp_high)
+ min -= min / 2;
+ if (can_try_harder)
+ min -= min / 4;
+ min += z->protection[alloc_type];
+
+ if (free_pages < min)
+ return 0;
+ for (o = 0; o < order; o++) {
+ /* At the next order, this order's pages become unavailable */
+ free_pages -= z->free_area[order].nr_free << o;
+
+ /* Require fewer higher order pages to be free */
+ min >>= 1;
+
+ if (free_pages < min + (1 << order) - 1)
+ return 0;
+ }
+ return 1;
+}
+
+/*
* This is the 'heart' of the zoned buddy allocator.
*
* Herein lies the mysterious "incremental min". That's the
@@ -696,7 +726,6 @@ __alloc_pages(unsigned int gfp_mask, uns
struct zonelist *zonelist)
{
const int wait = gfp_mask & __GFP_WAIT;
- unsigned long min;
struct zone **zones, *z;
struct page *page;
struct reclaim_state reclaim_state;
@@ -732,9 +761,9 @@ __alloc_pages(unsigned int gfp_mask, uns

/* Go through the zonelist once, looking for a zone with enough free */
for (i = 0; (z = zones[i]) != NULL; i++) {
- min = z->pages_low + (1<<order) + z->protection[alloc_type];

- if (z->free_pages < min)
+ if (!zone_watermark_ok(z, order, z->pages_low,
+ alloc_type, 0, 0))
continue;

if (!cpuset_zone_allowed(z))
@@ -753,14 +782,9 @@ __alloc_pages(unsigned int gfp_mask, uns
* coming from realtime tasks to go deeper into reserves
*/
for (i = 0; (z = zones[i]) != NULL; i++) {
- min = z->pages_min;
- if (gfp_mask & __GFP_HIGH)
- min /= 2;
- if (can_try_harder)
- min -= min / 4;
- min += (1<<order) + z->protection[alloc_type];
-
- if (z->free_pages < min)
+ if (!zone_watermark_ok(z, order, z->pages_min,
+ alloc_type, can_try_harder,
+ gfp_mask & __GFP_HIGH))
continue;

if (!cpuset_zone_allowed(z))
@@ -801,14 +825,9 @@ rebalance:

/* go through the zonelist yet one more time */
for (i = 0; (z = zones[i]) != NULL; i++) {
- min = z->pages_min;
- if (gfp_mask & __GFP_HIGH)
- min /= 2;
- if (can_try_harder)
- min -= min / 4;
- min += (1<<order) + z->protection[alloc_type];
-
- if (z->free_pages < min)
+ if (!zone_watermark_ok(z, order, z->pages_min,
+ alloc_type, can_try_harder,
+ gfp_mask & __GFP_HIGH))
continue;

if (!cpuset_zone_allowed(z))
diff -puN include/linux/mmzone.h~vm-alloc-order-watermarks include/linux/mmzone.h
--- linux-2.6/include/linux/mmzone.h~vm-alloc-order-watermarks 2004-09-05 14:55:46.000000000 +1000
+++ linux-2.6-npiggin/include/linux/mmzone.h 2004-09-05 15:10:07.000000000 +1000
@@ -279,6 +279,8 @@ void get_zone_counts(unsigned long *acti
unsigned long *free);
void build_all_zonelists(void);
void wakeup_kswapd(struct zone *zone);
+int zone_watermark_ok(struct zone *z, int order, unsigned long mark,
+ int alloc_type, int can_try_harder, int gfp_high);

/*
* zone_idx() returns 0 for the ZONE_DMA zone, 1 for the ZONE_NORMAL zone, etc.

_