diff options
author | Chris Metcalf <cmetcalf@ezchip.com> | 2015-09-08 18:02:12 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2015-09-08 18:35:28 -0400 |
commit | 1b4ace4141db1ddc46f6c9915086dd5e18d7154d (patch) | |
tree | b76bfc0fddf6ab377647b0094c70eee83d2365b8 | |
parent | c5b4e1b02f2a0c2309ecd58a235a2f5ee4eb0074 (diff) |
bootmem: avoid freeing to bootmem after bootmem is done
Bootmem isn't popular any more, but some architectures still use it, and
freeing to bootmem after calling free_all_bootmem_core() can end up
scribbling over random memory. Instead, make sure the kernel generates
a warning in this case by ensuring the node_bootmem_map field is
non-NULL when are freeing or marking bootmem.
An instance of this bug was just fixed in the tile architecture ("tile:
use free_bootmem_late() for initrd") and catching this case more widely
seems like a good thing.
Signed-off-by: Chris Metcalf <cmetcalf@ezchip.com>
Acked-by: Mel Gorman <mgorman@suse.de>
Cc: Yasuaki Ishimatsu <isimatu.yasuaki@jp.fujitsu.com>
Cc: Pekka Enberg <penberg@kernel.org>
Cc: Paul McQuade <paulmcquad@gmail.com>
Cc: Tang Chen <tangchen@cn.fujitsu.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
-rw-r--r-- | mm/bootmem.c | 7 |
1 files changed, 7 insertions, 0 deletions
diff --git a/mm/bootmem.c b/mm/bootmem.c index a23dd1934654..3b6380784c28 100644 --- a/mm/bootmem.c +++ b/mm/bootmem.c | |||
@@ -236,6 +236,7 @@ static unsigned long __init free_all_bootmem_core(bootmem_data_t *bdata) | |||
236 | count += pages; | 236 | count += pages; |
237 | while (pages--) | 237 | while (pages--) |
238 | __free_pages_bootmem(page++, cur++, 0); | 238 | __free_pages_bootmem(page++, cur++, 0); |
239 | bdata->node_bootmem_map = NULL; | ||
239 | 240 | ||
240 | bdebug("nid=%td released=%lx\n", bdata - bootmem_node_data, count); | 241 | bdebug("nid=%td released=%lx\n", bdata - bootmem_node_data, count); |
241 | 242 | ||
@@ -294,6 +295,9 @@ static void __init __free(bootmem_data_t *bdata, | |||
294 | sidx + bdata->node_min_pfn, | 295 | sidx + bdata->node_min_pfn, |
295 | eidx + bdata->node_min_pfn); | 296 | eidx + bdata->node_min_pfn); |
296 | 297 | ||
298 | if (WARN_ON(bdata->node_bootmem_map == NULL)) | ||
299 | return; | ||
300 | |||
297 | if (bdata->hint_idx > sidx) | 301 | if (bdata->hint_idx > sidx) |
298 | bdata->hint_idx = sidx; | 302 | bdata->hint_idx = sidx; |
299 | 303 | ||
@@ -314,6 +318,9 @@ static int __init __reserve(bootmem_data_t *bdata, unsigned long sidx, | |||
314 | eidx + bdata->node_min_pfn, | 318 | eidx + bdata->node_min_pfn, |
315 | flags); | 319 | flags); |
316 | 320 | ||
321 | if (WARN_ON(bdata->node_bootmem_map == NULL)) | ||
322 | return 0; | ||
323 | |||
317 | for (idx = sidx; idx < eidx; idx++) | 324 | for (idx = sidx; idx < eidx; idx++) |
318 | if (test_and_set_bit(idx, bdata->node_bootmem_map)) { | 325 | if (test_and_set_bit(idx, bdata->node_bootmem_map)) { |
319 | if (exclusive) { | 326 | if (exclusive) { |