aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLinus Torvalds2013-02-18 11:58:02 -0600
committerGreg Kroah-Hartman2013-02-28 08:32:23 -0600
commit744dac7d299be82e4d13b217e81eb4bfee9826a8 (patch)
treee2c00d906bce1c616ceec7c1f6ba888e7b7627b8
parentdbb694e810c87e7e1760527a783437f26ac5a547 (diff)
downloadkernel-common-744dac7d299be82e4d13b217e81eb4bfee9826a8.tar.gz
kernel-common-744dac7d299be82e4d13b217e81eb4bfee9826a8.tar.xz
kernel-common-744dac7d299be82e4d13b217e81eb4bfee9826a8.zip
mm: fix pageblock bitmap allocation
commit 7c45512df987c5619db041b5c9b80d281e26d3db upstream. Commit c060f943d092 ("mm: use aligned zone start for pfn_to_bitidx calculation") fixed out calculation of the index into the pageblock bitmap when a !SPARSEMEM zome was not aligned to pageblock_nr_pages. However, the _allocation_ of that bitmap had never taken this alignment requirement into accout, so depending on the exact size and alignment of the zone, the use of that index could then access past the allocation, resulting in some very subtle memory corruption. This was reported (and bisected) by Ingo Molnar: one of his random config builds would hang with certain very specific kernel command line options. In the meantime, commit c060f943d092 has been marked for stable, so this fix needs to be back-ported to the stable kernels that backported the commit to use the right alignment. Bisected-and-tested-by: Ingo Molnar <mingo@kernel.org> Acked-by: Mel Gorman <mgorman@suse.de> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
-rw-r--r--mm/page_alloc.c15
1 files changed, 9 insertions, 6 deletions
diff --git a/mm/page_alloc.c b/mm/page_alloc.c
index 0ec869e6436..1b94f0868c2 100644
--- a/mm/page_alloc.c
+++ b/mm/page_alloc.c
@@ -4264,10 +4264,11 @@ static void __meminit calculate_node_totalpages(struct pglist_data *pgdat,
4264 * round what is now in bits to nearest long in bits, then return it in 4264 * round what is now in bits to nearest long in bits, then return it in
4265 * bytes. 4265 * bytes.
4266 */ 4266 */
4267static unsigned long __init usemap_size(unsigned long zonesize) 4267static unsigned long __init usemap_size(unsigned long zone_start_pfn, unsigned long zonesize)
4268{ 4268{
4269 unsigned long usemapsize; 4269 unsigned long usemapsize;
4270 4270
4271 zonesize += zone_start_pfn & (pageblock_nr_pages-1);
4271 usemapsize = roundup(zonesize, pageblock_nr_pages); 4272 usemapsize = roundup(zonesize, pageblock_nr_pages);
4272 usemapsize = usemapsize >> pageblock_order; 4273 usemapsize = usemapsize >> pageblock_order;
4273 usemapsize *= NR_PAGEBLOCK_BITS; 4274 usemapsize *= NR_PAGEBLOCK_BITS;
@@ -4277,17 +4278,19 @@ static unsigned long __init usemap_size(unsigned long zonesize)
4277} 4278}
4278 4279
4279static void __init setup_usemap(struct pglist_data *pgdat, 4280static void __init setup_usemap(struct pglist_data *pgdat,
4280 struct zone *zone, unsigned long zonesize) 4281 struct zone *zone,
4282 unsigned long zone_start_pfn,
4283 unsigned long zonesize)
4281{ 4284{
4282 unsigned long usemapsize = usemap_size(zonesize); 4285 unsigned long usemapsize = usemap_size(zone_start_pfn, zonesize);
4283 zone->pageblock_flags = NULL; 4286 zone->pageblock_flags = NULL;
4284 if (usemapsize) 4287 if (usemapsize)
4285 zone->pageblock_flags = alloc_bootmem_node_nopanic(pgdat, 4288 zone->pageblock_flags = alloc_bootmem_node_nopanic(pgdat,
4286 usemapsize); 4289 usemapsize);
4287} 4290}
4288#else 4291#else
4289static inline void setup_usemap(struct pglist_data *pgdat, 4292static inline void setup_usemap(struct pglist_data *pgdat, struct zone *zone,
4290 struct zone *zone, unsigned long zonesize) {} 4293 unsigned long zone_start_pfn, unsigned long zonesize) {}
4291#endif /* CONFIG_SPARSEMEM */ 4294#endif /* CONFIG_SPARSEMEM */
4292 4295
4293#ifdef CONFIG_HUGETLB_PAGE_SIZE_VARIABLE 4296#ifdef CONFIG_HUGETLB_PAGE_SIZE_VARIABLE
@@ -4415,7 +4418,7 @@ static void __paginginit free_area_init_core(struct pglist_data *pgdat,
4415 continue; 4418 continue;
4416 4419
4417 set_pageblock_order(pageblock_default_order()); 4420 set_pageblock_order(pageblock_default_order());
4418 setup_usemap(pgdat, zone, size); 4421 setup_usemap(pgdat, zone, zone_start_pfn, size);
4419 ret = init_currently_empty_zone(zone, zone_start_pfn, 4422 ret = init_currently_empty_zone(zone, zone_start_pfn,
4420 size, MEMMAP_EARLY); 4423 size, MEMMAP_EARLY);
4421 BUG_ON(ret); 4424 BUG_ON(ret);