Fixes for node alignment and flatmem assumptions
Subsystems (4)
cover Fixes for node alignment and flatmem assumptions
After almost 3 days of banging the head on the keyboard, it was discovered why arch-independent zone-sizing failed on IA64 for the configuration posted on http://www.zip.com.au/~akpm/linux/patches/stuff/config-ia64 .
The two patches in this set address the following;
1. The buddy allocator requires that the node_mem_map be aligned on a MAX_ORDER boundary. Patch 1 from Bob Picco's patch aligns the node_map_map correctly.
2. This is the one that was giving me keyboard face. The FLATMEM memory model assumes that
mem_map[0] == NODE_DATA(0)->node_mem_map == PFN 0
This is not the case on IA64 with arch-independent zone sizing because NODE_DATA(0)->node_mem_map starts where the first valid page frame is. On my test machine, that is PFN 1025 but it probably varies. Patch 2 from Andy Whitcroft relaxes the assumption that NODE_DATA(0)->node_mem_map == PFN 0 .
These patches apply to 2.6.17-rc4-mm1 and are independent of architecture-independent zone sizing. Patch 1 in particular fixes a real problem that is just difficult to trigger. However, once applied, have-ia64-use-add_active_range-and-free_area_init_nodes.patch will work again.
2.6.17-rc4-mm1 with this patchset have been boot-tested by me and verified that /proc/zoneinfo is ok on x86, ppc64, x86_64 and ia64 in a variety of configurations. Bob Picco also says that both patches passed a test with mem=750M and 4Gb on a rx2600 (ia64) with large memory holes. They have also been successfully tested with have-ia64-use-add_active_range-and-free_area_init_nodes.patch added back in.
Signature · 10 lines
-- Mel Gorman Part-time Phd Student Linux Technology Center University of Limerick IBM Dublin Software Lab -- To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM, see: http://www.linux-mm.org/ . Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
PATCH 1/2 Align the node_mem_map endpoints to a MAX_ORDER boundary
From: Bob Picco <[email protected]>
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.
include/linux/mmzone.h | 1 + mm/page_alloc.c | 14 +++++++++++--- 2 files changed, 12 insertions(+), 3 deletions(-)
include/linux/mmzone.h +1 -0
@@ -21,6 +21,7 @@#else #define MAX_ORDER CONFIG_FORCE_MAX_ZONEORDER#endif +#define MAX_ORDER_NR_PAGES (1 << (MAX_ORDER - 1))struct free_area {struct list_head free_list;
mm/page_alloc.c +11 -3
@@ -2484,14 +2484,22 @@ static void __init alloc_node_mem_map(st#ifdef CONFIG_FLAT_NODE_MEM_MAP /* ia64 gets its own node_mem_map, before this, without bootmem */ if (!pgdat->node_mem_map) { -unsigned long size; +unsigned long size, start, end;struct page *map; - size = (pgdat->node_spanned_pages +1 ) *sizeof (struct page ); +/* +* The zone's endpoints aren't required to be MAX_ORDER +* aligned but the node_mem_map endpoints must be in order +* for the buddy allocator to function correctly. +*/ + start = pgdat->node_start_pfn & ~(MAX_ORDER_NR_PAGES -1 ); + end = pgdat->node_start_pfn + pgdat->node_spanned_pages; + end =ALIGN (end,MAX_ORDER_NR_PAGES ); + size = (end - start) *sizeof (struct page ); map =alloc_remap (pgdat->node_id, size);if (!map) map =alloc_bootmem_node (pgdat, size); - pgdat->node_mem_map = map; + pgdat->node_mem_map = map + (pgdat->node_start_pfn - start); }#ifdef CONFIG_FLATMEM /*
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
Re: [PATCH 1/2] Align the node_mem_map endpoints to a MAX_ORDER boundary
Quoted 11 lines · Mel Gorman
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 beMAX_ORDERaligned. Otherwise__page_find_buddycould compute a buddy not innode_mem_mapfor partialMAX_ORDERregions at zone's endpoints.page_is_buddywill detect that these pages at endpoints are notPG_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.
Quoted 5 lines
SPARSEMEM won't encounter this issue because of
MAX_ORDERsize constraint when SPARSEMEM is configured. ia64VIRTUAL_MEM_MAPdoesn't need the logic either because the holes and endpoints are handled differently. This leaves checkingalloc_remapand other arches which privately allocate fornode_mem_map.
Do we think we need this in 2.6.17?
Re: [PATCH 1/2] Align the node_mem_map endpoints to a MAX_ORDER boundary
Quoted 12 lines · Andrew Morton
Quoted 11 lines · Mel Gorman
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 beMAX_ORDERaligned. Otherwise__page_find_buddycould compute a buddy not innode_mem_mapfor partialMAX_ORDERregions at zone's endpoints.page_is_buddywill detect that these pages at endpoints are notPG_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.
Quoted 8 lines
Quoted 5 lines
SPARSEMEM won't encounter this issue because of
MAX_ORDERsize constraint when SPARSEMEM is configured. ia64VIRTUAL_MEM_MAPdoesn't need the logic either because the holes and endpoints are handled differently. This leaves checkingalloc_remapand other arches which privately allocate fornode_mem_map.Do we think we need this in 2.6.17?
I think so. Not all architectures are making sure their node_start_pfn is aligned to a boundary. For example, x86_64 does, ia64 may align depending on the value of MAX_ORDER and i386 does not appear to make any effort. No one seems to be making any special effort to align the end of the zone at all. This potentially means that the buddy allocator is checking portions of memory as if they were struct page * when they are something totally different. I suspect it's just luck that the memory outside of the mem_map never looked like buddies.
Anyone else care to comment?
Signature · 9 lines
Mel Gorman Part-time Phd Student Linux Technology Center University of Limerick IBM Dublin Software Lab -- To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM, see: http://www.linux-mm.org/ . Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
Re: [PATCH 1/2] Align the node_mem_map endpoints to a MAX_ORDER boundary
In reply to Andrew MortonQuoted 12 lines · Andrew Morton
Quoted 10 lines · Mel Gorman
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 beMAX_ORDERaligned. Otherwise__page_find_buddycould compute a buddy not innode_mem_mapfor partialMAX_ORDERregions at zone's endpoints.page_is_buddywill detect that these pages at endpoints are notPG_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.
Quoted 8 lines
Quoted 5 lines
SPARSEMEM won't encounter this issue because of
MAX_ORDERsize constraint when SPARSEMEM is configured. ia64VIRTUAL_MEM_MAPdoesn't need the logic either because the holes and endpoints are handled differently. This leaves checkingalloc_remapand other arches which privately allocate fornode_mem_map.Do we think we need this in 2.6.17?
I would say yes, it is a very low risk patch in my view and provides a very large part of the protections we require. i386 as our largest userbase should be safe from zone/node alignment issues with just this change. Others need slightly more (the page_zone_idx check) which is being discussed in another thread.
-apw
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
Re: [PATCH 1/2] Align the node_mem_map endpoints to a MAX_ORDER boundary
Quoted 21 lines · Andy Whitcroft
Quoted 19 lines · Andrew Morton
Quoted 15 lines · Mel Gorman
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 beMAX_ORDERaligned. Otherwise__page_find_buddycould compute a buddy not innode_mem_mapfor partialMAX_ORDERregions at zone's endpoints.page_is_buddywill detect that these pages at endpoints are notPG_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_ORDERsize constraint when SPARSEMEM is configured. ia64VIRTUAL_MEM_MAPdoesn't need the logic either because the holes and endpoints are handled differently. This leaves checkingalloc_remapand other arches which privately allocate fornode_mem_map.
Quoted 8 lines
Quoted 1 line
Do we think we need this in 2.6.17?
I would say yes, it is a very low risk patch in my view and provides a very large part of the protections we require. i386 as our largest userbase should be safe from zone/node alignment issues with just this change. Others need slightly more (the
page_zone_idxcheck) which is being discussed in another thread.
Well I've largely lost the plot here (which happens often), and it appears that Nick has concerns with this approach (which also is not uncommon).
So could you guys please come to some sort of (rapid) consensus and tell me which patches from -mm3 (hopefully but an hour away) need to go into 2.6.17?
Thanks.
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
PATCH 2/2 FLATMEM relax requirement for memory to start at pfn 0
In reply to Mel GormanFrom: Andy Whitcroft <[email protected]>
The FLATMEM memory model assumes that memory is in one contigious area based at pfn 0. If we initialise node 0 to start at any other offset we will incorrectly map pfn's to the wrong struct page *. The key to the memory model is the contigious nature of the memory not the location of it. Relax the requirement for the area to start at 0.
page_alloc.c | 17 +++++++++++++---- 1 files changed, 13 insertions(+), 4 deletions(-)
mm/page_alloc.c +13 -4
@@ -2477,15 +2477,16 @@ static void __meminit free_area_init_corstatic void __init alloc_node_mem_map (struct pglist_data *pgdat) { +#ifdef CONFIG_FLAT_NODE_MEM_MAP +struct page *map = pgdat->node_mem_map; +/* Skip empty nodes */ if (!pgdat->node_spanned_pages)return ; -#ifdef CONFIG_FLAT_NODE_MEM_MAP /* ia64 gets its own node_mem_map, before this, without bootmem */ -if (!pgdat->node_mem_map) { +if (!map) {unsigned long size, start, end; -struct page *map;/* * The zone's endpoints aren't required to be MAX_ORDER
@@ -2500,13 +2501,21 @@ static void __init alloc_node_mem_map(stif (!map) map =alloc_bootmem_node (pgdat, size); pgdat->node_mem_map = map + (pgdat->node_start_pfn - start); + +/* +* With FLATMEM the global mem_map is used. This is assumed +* to be based at pfn 0 such that 'pfn = page* - mem_map' +* is true. Adjust map relative to node_mem_map to +* maintain this relationship. +*/ + map -= pgdat->node_start_pfn; }#ifdef CONFIG_FLATMEM /* * With no DISCONTIG, the global mem_map is just set as node 0's */ if (pgdat ==NODE_DATA (0 )) - mem_map =NODE_DATA (0 )->node_mem_map; + mem_map = map;#endif #endif /* CONFIG_FLAT_NODE_MEM_MAP */ }
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>