mm: fix boundary checking in free_bootmem_core
PATCH 1/12 mm: fix boundary checking in free_bootmem_core
In reply to a message not in the archive[PATCH] mm: fix boundary checking in free_bootmem_core
With numa enabled, some callers could have a range of memory on one node but try to free that on other node. This can cause some pages to be freed wrongly.
For example: when we try to allocate 128g boot ram early for gart/swiotlb, and free that range later so gart/swiotlb can get some range afterwards.
With this patch, we don't need to care which node holds the range, just loop to call free_bootmem_node for all online nodes.
This patch make free_bootmem_core() more robust by trimming the sidx and eidx according the ram range that the node has.
Signed-off-by Yinghai Lu <[email protected]>
mm/bootmem.c +16 -5
@@ -125,6 +125,7 @@ static int __init reserve_bootmem_core(bBUG_ON (!size);BUG_ON (PFN_DOWN (addr) >= bdata->node_low_pfn);BUG_ON (PFN_UP (addr + size) > bdata->node_low_pfn); +BUG_ON (addr < bdata->node_boot_start); sidx =PFN_DOWN (addr - bdata->node_boot_start); eidx =PFN_UP (addr + size - bdata->node_boot_start);
@@ -156,21 +157,31 @@ static void __init free_bootmem_core(boounsigned long sidx, eidx;unsigned long i; +BUG_ON (!size); + +/* out range */ +if (addr + size < bdata->node_boot_start || +PFN_DOWN (addr) > bdata->node_low_pfn) +return ;/* * round down end of usable mem, partially free pages are * considered reserved. */ -BUG_ON (!size); -BUG_ON (PFN_DOWN (addr + size) > bdata->node_low_pfn); -if (addr < bdata->last_success) +if (addr >= bdata->node_boot_start && addr < bdata->last_success) bdata->last_success = addr;/* -* Round up the beginning of the address. +* Round up to index to the range. */ - sidx =PFN_UP (addr) -PFN_DOWN (bdata->node_boot_start); +if (PFN_UP (addr) >PFN_DOWN (bdata->node_boot_start)) + sidx =PFN_UP (addr) -PFN_DOWN (bdata->node_boot_start); +else + sidx =0 ; + eidx =PFN_DOWN (addr + size - bdata->node_boot_start); +if (eidx > bdata->node_low_pfn -PFN_DOWN (bdata->node_boot_start)) + eidx = bdata->node_low_pfn -PFN_DOWN (bdata->node_boot_start);for (i = sidx; i < eidx; i++) {if (unlikely (!test_and_clear_bit (i, bdata->node_bootmem_map)))