diff options
author | Tejun Heo <tj@kernel.org> | 2011-12-08 13:22:07 -0500 |
---|---|---|
committer | Tejun Heo <tj@kernel.org> | 2011-12-08 13:22:07 -0500 |
commit | eb18f1b5bfb99b1d7d2f5d792e6ee5c9b7d89330 (patch) | |
tree | 6f2a6865b929358c1c46a61f7f3ac5563cc03f02 /mm | |
parent | 719361809fde9dbe9ccc4cf71f9fa9add5fa8bf9 (diff) |
memblock: Make memblock functions handle overflowing range @size
Allow memblock users to specify range where @base + @size overflows
and automatically cap it at maximum. This makes the interface more
robust and specifying till-the-end-of-memory easier.
Signed-off-by: Tejun Heo <tj@kernel.org>
Cc: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Cc: Yinghai Lu <yinghai@kernel.org>
Diffstat (limited to 'mm')
-rw-r--r-- | mm/memblock.c | 15 |
1 files changed, 12 insertions, 3 deletions
diff --git a/mm/memblock.c b/mm/memblock.c index fffe68b4bf14..945dc31258eb 100644 --- a/mm/memblock.c +++ b/mm/memblock.c | |||
@@ -49,6 +49,12 @@ static inline const char *memblock_type_name(struct memblock_type *type) | |||
49 | return "unknown"; | 49 | return "unknown"; |
50 | } | 50 | } |
51 | 51 | ||
52 | /* adjust *@size so that (@base + *@size) doesn't overflow, return new size */ | ||
53 | static inline phys_addr_t memblock_cap_size(phys_addr_t base, phys_addr_t *size) | ||
54 | { | ||
55 | return *size = min(*size, (phys_addr_t)ULLONG_MAX - base); | ||
56 | } | ||
57 | |||
52 | /* | 58 | /* |
53 | * Address comparison utilities | 59 | * Address comparison utilities |
54 | */ | 60 | */ |
@@ -328,7 +334,8 @@ static int __init_memblock memblock_add_region(struct memblock_type *type, | |||
328 | phys_addr_t base, phys_addr_t size) | 334 | phys_addr_t base, phys_addr_t size) |
329 | { | 335 | { |
330 | bool insert = false; | 336 | bool insert = false; |
331 | phys_addr_t obase = base, end = base + size; | 337 | phys_addr_t obase = base; |
338 | phys_addr_t end = base + memblock_cap_size(base, &size); | ||
332 | int i, nr_new; | 339 | int i, nr_new; |
333 | 340 | ||
334 | /* special case for empty array */ | 341 | /* special case for empty array */ |
@@ -420,7 +427,7 @@ static int __init_memblock memblock_isolate_range(struct memblock_type *type, | |||
420 | phys_addr_t base, phys_addr_t size, | 427 | phys_addr_t base, phys_addr_t size, |
421 | int *start_rgn, int *end_rgn) | 428 | int *start_rgn, int *end_rgn) |
422 | { | 429 | { |
423 | phys_addr_t end = base + size; | 430 | phys_addr_t end = base + memblock_cap_size(base, &size); |
424 | int i; | 431 | int i; |
425 | 432 | ||
426 | *start_rgn = *end_rgn = 0; | 433 | *start_rgn = *end_rgn = 0; |
@@ -868,16 +875,18 @@ int __init_memblock memblock_is_memory(phys_addr_t addr) | |||
868 | int __init_memblock memblock_is_region_memory(phys_addr_t base, phys_addr_t size) | 875 | int __init_memblock memblock_is_region_memory(phys_addr_t base, phys_addr_t size) |
869 | { | 876 | { |
870 | int idx = memblock_search(&memblock.memory, base); | 877 | int idx = memblock_search(&memblock.memory, base); |
878 | phys_addr_t end = base + memblock_cap_size(base, &size); | ||
871 | 879 | ||
872 | if (idx == -1) | 880 | if (idx == -1) |
873 | return 0; | 881 | return 0; |
874 | return memblock.memory.regions[idx].base <= base && | 882 | return memblock.memory.regions[idx].base <= base && |
875 | (memblock.memory.regions[idx].base + | 883 | (memblock.memory.regions[idx].base + |
876 | memblock.memory.regions[idx].size) >= (base + size); | 884 | memblock.memory.regions[idx].size) >= end; |
877 | } | 885 | } |
878 | 886 | ||
879 | int __init_memblock memblock_is_region_reserved(phys_addr_t base, phys_addr_t size) | 887 | int __init_memblock memblock_is_region_reserved(phys_addr_t base, phys_addr_t size) |
880 | { | 888 | { |
889 | memblock_cap_size(base, &size); | ||
881 | return memblock_overlaps_region(&memblock.reserved, base, size) >= 0; | 890 | return memblock_overlaps_region(&memblock.reserved, base, size) >= 0; |
882 | } | 891 | } |
883 | 892 | ||