diff options
Diffstat (limited to 'mm/memblock.c')
-rw-r--r-- | mm/memblock.c | 74 |
1 files changed, 71 insertions, 3 deletions
diff --git a/mm/memblock.c b/mm/memblock.c index 99c7f493d45f..e39ef2fe5c17 100644 --- a/mm/memblock.c +++ b/mm/memblock.c @@ -19,6 +19,9 @@ #include <linux/debugfs.h> #include <linux/seq_file.h> #include <linux/memblock.h> +#include <linux/preempt.h> +#include <linux/seqlock.h> +#include <linux/irqflags.h> #include <asm-generic/sections.h> #include <linux/io.h> @@ -31,6 +34,7 @@ static struct memblock_region memblock_reserved_init_regions[INIT_MEMBLOCK_REGIO static struct memblock_region memblock_physmem_init_regions[INIT_PHYSMEM_REGIONS] __initdata_memblock; #endif +static seqcount_t memblock_seq; struct memblock memblock __initdata_memblock = { .memory.regions = memblock_memory_init_regions, .memory.cnt = 1, /* empty dummy entry */ @@ -733,7 +737,8 @@ int __init_memblock memblock_free(phys_addr_t base, phys_addr_t size) (unsigned long long)base + size - 1, (void *)_RET_IP_); - kmemleak_free_part(__va(base), size); + if (base < memblock.current_limit) + kmemleak_free_part(__va(base), size); return memblock_remove_range(&memblock.reserved, base, size); } @@ -834,6 +839,16 @@ int __init_memblock memblock_mark_nomap(phys_addr_t base, phys_addr_t size) } /** + * memblock_clear_nomap - Clear a flag of MEMBLOCK_NOMAP memory region + * @base: the base phys addr of the region + * @size: the size of the region + */ +int __init_memblock memblock_clear_nomap(phys_addr_t base, phys_addr_t size) +{ + return memblock_setclr_flag(base, size, 0, MEMBLOCK_NOMAP); +} + +/** * __next_reserved_mem_region - next function for for_each_reserved_region() * @idx: pointer to u64 loop variable * @out_start: ptr to phys_addr_t for start address of the region, can be %NULL @@ -1169,7 +1184,8 @@ static phys_addr_t __init memblock_alloc_range_nid(phys_addr_t size, * The min_count is set to 0 so that memblock allocations are * never reported as leaks. */ - kmemleak_alloc(__va(found), size, 0, 0); + if (found < memblock.current_limit) + kmemleak_alloc(__va(found), size, 0, 0); return found; } return 0; @@ -1509,7 +1525,7 @@ void __init memblock_enforce_memory_limit(phys_addr_t limit) (phys_addr_t)ULLONG_MAX); } -static int __init_memblock memblock_search(struct memblock_type *type, phys_addr_t addr) +static int __init_memblock __memblock_search(struct memblock_type *type, phys_addr_t addr) { unsigned int left = 0, right = type->cnt; @@ -1527,6 +1543,19 @@ static int __init_memblock memblock_search(struct memblock_type *type, phys_addr return -1; } +static int __init_memblock memblock_search(struct memblock_type *type, phys_addr_t addr) +{ + int ret; + unsigned long seq; + + do { + seq = raw_read_seqcount_begin(&memblock_seq); + ret = __memblock_search(type, addr); + } while (unlikely(read_seqcount_retry(&memblock_seq, seq))); + + return ret; +} + int __init memblock_is_reserved(phys_addr_t addr) { return memblock_search(&memblock.reserved, addr) != -1; @@ -1585,6 +1614,14 @@ int __init_memblock memblock_is_region_memory(phys_addr_t base, phys_addr_t size memblock.memory.regions[idx].size) >= end; } +bool __init_memblock memblock_overlaps_memory(phys_addr_t base, + phys_addr_t size) +{ + memblock_cap_size(base, &size); + + return memblock_overlaps_region(&memblock.memory, base, size); +} + /** * memblock_is_region_reserved - check if a region intersects reserved memory * @base: base of region to check @@ -1701,6 +1738,37 @@ void __init memblock_allow_resize(void) memblock_can_resize = 1; } +static unsigned long __init_memblock +memblock_resize_late(int begin, unsigned long flags) +{ + static int memblock_can_resize_old; + + if (begin) { + preempt_disable(); + local_irq_save(flags); + memblock_can_resize_old = memblock_can_resize; + memblock_can_resize = 0; + raw_write_seqcount_begin(&memblock_seq); + } else { + raw_write_seqcount_end(&memblock_seq); + memblock_can_resize = memblock_can_resize_old; + local_irq_restore(flags); + preempt_enable(); + } + + return flags; +} + +unsigned long __init_memblock memblock_region_resize_late_begin(void) +{ + return memblock_resize_late(1, 0); +} + +void __init_memblock memblock_region_resize_late_end(unsigned long flags) +{ + memblock_resize_late(0, flags); +} + static int __init early_memblock(char *p) { if (p && strstr(p, "debug")) |