diff options
author | Tejun Heo <tj@kernel.org> | 2011-12-08 19:22:07 +0100 |
---|---|---|
committer | Tejun Heo <tj@kernel.org> | 2011-12-08 19:22:07 +0100 |
commit | eb18f1b5bfb99b1d7d2f5d792e6ee5c9b7d89330 (patch) | |
tree | 6f2a6865b929358c1c46a61f7f3ac5563cc03f02 /mm/memblock.c | |
parent | memblock: Reimplement __memblock_remove() using memblock_isolate_range() (diff) | |
download | linux-eb18f1b5bfb99b1d7d2f5d792e6ee5c9b7d89330.tar.xz linux-eb18f1b5bfb99b1d7d2f5d792e6ee5c9b7d89330.zip |
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/memblock.c')
-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) return "unknown"; } +/* adjust *@size so that (@base + *@size) doesn't overflow, return new size */ +static inline phys_addr_t memblock_cap_size(phys_addr_t base, phys_addr_t *size) +{ + return *size = min(*size, (phys_addr_t)ULLONG_MAX - base); +} + /* * Address comparison utilities */ @@ -328,7 +334,8 @@ static int __init_memblock memblock_add_region(struct memblock_type *type, phys_addr_t base, phys_addr_t size) { bool insert = false; - phys_addr_t obase = base, end = base + size; + phys_addr_t obase = base; + phys_addr_t end = base + memblock_cap_size(base, &size); int i, nr_new; /* special case for empty array */ @@ -420,7 +427,7 @@ static int __init_memblock memblock_isolate_range(struct memblock_type *type, phys_addr_t base, phys_addr_t size, int *start_rgn, int *end_rgn) { - phys_addr_t end = base + size; + phys_addr_t end = base + memblock_cap_size(base, &size); int i; *start_rgn = *end_rgn = 0; @@ -868,16 +875,18 @@ int __init_memblock memblock_is_memory(phys_addr_t addr) int __init_memblock memblock_is_region_memory(phys_addr_t base, phys_addr_t size) { int idx = memblock_search(&memblock.memory, base); + phys_addr_t end = base + memblock_cap_size(base, &size); if (idx == -1) return 0; return memblock.memory.regions[idx].base <= base && (memblock.memory.regions[idx].base + - memblock.memory.regions[idx].size) >= (base + size); + memblock.memory.regions[idx].size) >= end; } int __init_memblock memblock_is_region_reserved(phys_addr_t base, phys_addr_t size) { + memblock_cap_size(base, &size); return memblock_overlaps_region(&memblock.reserved, base, size) >= 0; } |