aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTejun Heo <[email protected]>2012-01-13 10:14:12 -0800
committerIngo Molnar <[email protected]>2012-01-16 08:38:06 +0100
commit5d53cb27d849c899136c048ec84c940ac449494b (patch)
tree66c78c014a06641245fa3cd219afabdc7afdf427
parentedf7c8148ec40c0fd27c0ef3f688defcc65e3913 (diff)
memblock: Fix alloc failure due to dumb underflow protection in memblock_find_in_range_node()
7bd0b0f0da ("memblock: Reimplement memblock allocation using reverse free area iterator") implemented a simple top-down allocator using a reverse memblock iterator. To avoid underflow in the allocator loop, it simply raised the lower boundary to the requested size under the assumption that requested size would be far smaller than available memblocks. This causes early page table allocation failure under certain configurations in Xen. Fix it by checking for underflow directly instead of bumping up lower bound. Signed-off-by: Tejun Heo <[email protected]> Reported-by: Konrad Rzeszutek Wilk <[email protected]> Cc: [email protected] Cc: [email protected] Cc: Benjamin Herrenschmidt <[email protected]> Cc: Andrew Morton <[email protected]> Cc: Linus Torvalds <[email protected]> Link: http://lkml.kernel.org/r/[email protected] Signed-off-by: Ingo Molnar <[email protected]>
-rw-r--r--mm/memblock.c7
1 files changed, 5 insertions, 2 deletions
diff --git a/mm/memblock.c b/mm/memblock.c
index 2f55f19b7c86..77b5f227e1d8 100644
--- a/mm/memblock.c
+++ b/mm/memblock.c
@@ -106,14 +106,17 @@ phys_addr_t __init_memblock memblock_find_in_range_node(phys_addr_t start,
if (end == MEMBLOCK_ALLOC_ACCESSIBLE)
end = memblock.current_limit;
- /* adjust @start to avoid underflow and allocating the first page */
- start = max3(start, size, (phys_addr_t)PAGE_SIZE);
+ /* avoid allocating the first page */
+ start = max_t(phys_addr_t, start, PAGE_SIZE);
end = max(start, end);
for_each_free_mem_range_reverse(i, nid, &this_start, &this_end, NULL) {
this_start = clamp(this_start, start, end);
this_end = clamp(this_end, start, end);
+ if (this_end < size)
+ continue;
+
cand = round_down(this_end - size, align);
if (cand >= this_start)
return cand;