diff options
author | Bob Picco <bob.picco@hp.com> | 2006-05-20 18:00:31 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@g5.osdl.org> | 2006-05-21 15:59:22 -0400 |
commit | e984bb43f7450312ba66fe0e67a99efa6be3b246 (patch) | |
tree | 54c86240172136fc81c773f71cd70eda54fed6f2 | |
parent | ae57a856429dd932c547530df1b234eb7e642297 (diff) |
[PATCH] Align the node_mem_map endpoints to a MAX_ORDER boundary
Andy added code to buddy allocator which does not require the zone's
endpoints to be aligned to MAX_ORDER. An issue is that the buddy allocator
requires the node_mem_map's endpoints to be MAX_ORDER aligned. Otherwise
__page_find_buddy could compute a buddy not in node_mem_map for partial
MAX_ORDER regions at zone's endpoints. page_is_buddy will detect that
these pages at endpoints are not PG_buddy (they were zeroed out by bootmem
allocator and not part of zone). Of course the negative here is we could
waste a little memory but the positive is eliminating all the old checks
for zone boundary conditions.
SPARSEMEM won't encounter this issue because of MAX_ORDER size constraint
when SPARSEMEM is configured. ia64 VIRTUAL_MEM_MAP doesn't need the logic
either because the holes and endpoints are handled differently. This
leaves checking alloc_remap and other arches which privately allocate for
node_mem_map.
Signed-off-by: Bob Picco <bob.picco@hp.com>
Acked-by: Mel Gorman <mel@csn.ul.ie>
Cc: Dave Hansen <haveblue@us.ibm.com>
Cc: Andy Whitcroft <apw@shadowen.org>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
-rw-r--r-- | include/linux/mmzone.h | 1 | ||||
-rw-r--r-- | mm/page_alloc.c | 14 |
2 files changed, 12 insertions, 3 deletions
diff --git a/include/linux/mmzone.h b/include/linux/mmzone.h index b5c21122c299..36740354d4db 100644 --- a/include/linux/mmzone.h +++ b/include/linux/mmzone.h | |||
@@ -22,6 +22,7 @@ | |||
22 | #else | 22 | #else |
23 | #define MAX_ORDER CONFIG_FORCE_MAX_ZONEORDER | 23 | #define MAX_ORDER CONFIG_FORCE_MAX_ZONEORDER |
24 | #endif | 24 | #endif |
25 | #define MAX_ORDER_NR_PAGES (1 << (MAX_ORDER - 1)) | ||
25 | 26 | ||
26 | struct free_area { | 27 | struct free_area { |
27 | struct list_head free_list; | 28 | struct list_head free_list; |
diff --git a/mm/page_alloc.c b/mm/page_alloc.c index bb3416932ab0..253a450c400d 100644 --- a/mm/page_alloc.c +++ b/mm/page_alloc.c | |||
@@ -2125,14 +2125,22 @@ static void __init alloc_node_mem_map(struct pglist_data *pgdat) | |||
2125 | #ifdef CONFIG_FLAT_NODE_MEM_MAP | 2125 | #ifdef CONFIG_FLAT_NODE_MEM_MAP |
2126 | /* ia64 gets its own node_mem_map, before this, without bootmem */ | 2126 | /* ia64 gets its own node_mem_map, before this, without bootmem */ |
2127 | if (!pgdat->node_mem_map) { | 2127 | if (!pgdat->node_mem_map) { |
2128 | unsigned long size; | 2128 | unsigned long size, start, end; |
2129 | struct page *map; | 2129 | struct page *map; |
2130 | 2130 | ||
2131 | size = (pgdat->node_spanned_pages + 1) * sizeof(struct page); | 2131 | /* |
2132 | * The zone's endpoints aren't required to be MAX_ORDER | ||
2133 | * aligned but the node_mem_map endpoints must be in order | ||
2134 | * for the buddy allocator to function correctly. | ||
2135 | */ | ||
2136 | start = pgdat->node_start_pfn & ~(MAX_ORDER_NR_PAGES - 1); | ||
2137 | end = pgdat->node_start_pfn + pgdat->node_spanned_pages; | ||
2138 | end = ALIGN(end, MAX_ORDER_NR_PAGES); | ||
2139 | size = (end - start) * sizeof(struct page); | ||
2132 | map = alloc_remap(pgdat->node_id, size); | 2140 | map = alloc_remap(pgdat->node_id, size); |
2133 | if (!map) | 2141 | if (!map) |
2134 | map = alloc_bootmem_node(pgdat, size); | 2142 | map = alloc_bootmem_node(pgdat, size); |
2135 | pgdat->node_mem_map = map; | 2143 | pgdat->node_mem_map = map + (pgdat->node_start_pfn - start); |
2136 | } | 2144 | } |
2137 | #ifdef CONFIG_FLATMEM | 2145 | #ifdef CONFIG_FLATMEM |
2138 | /* | 2146 | /* |