diff --git a/drivers/base/dma-removed.c b/drivers/base/dma-removed.c index a757e86bbf62..d20a29744665 100644 --- a/drivers/base/dma-removed.c +++ b/drivers/base/dma-removed.c @@ -184,8 +184,10 @@ static void removed_region_fixup(struct removed_region *dma_mem, int index) return; /* carve-out */ + memblock_region_resize_late_begin(); memblock_free(dma_mem->base, dma_mem->nr_pages * PAGE_SIZE); memblock_remove(dma_mem->base, index * PAGE_SIZE); + memblock_region_resize_late_end(); /* clear page-mappings */ base_pfn = dma_mem->base >> PAGE_SHIFT; diff --git a/include/linux/memblock.h b/include/linux/memblock.h index ea96ba46ef9d..42b40345119f 100644 --- a/include/linux/memblock.h +++ b/include/linux/memblock.h @@ -83,6 +83,8 @@ int memblock_mark_hotplug(phys_addr_t base, phys_addr_t size); int memblock_clear_hotplug(phys_addr_t base, phys_addr_t size); int memblock_mark_mirror(phys_addr_t base, phys_addr_t size); ulong choose_memblock_flags(void); +void memblock_region_resize_late_begin(void); +void memblock_region_resize_late_end(void); /* Low level functions */ int memblock_add_range(struct memblock_type *type, diff --git a/mm/memblock.c b/mm/memblock.c index 04480ee049aa..bdeb22faafff 100644 --- a/mm/memblock.c +++ b/mm/memblock.c @@ -19,6 +19,8 @@ #include #include #include +#include +#include #include #include @@ -31,6 +33,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 */ @@ -1493,7 +1496,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; @@ -1511,6 +1514,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; @@ -1659,6 +1675,32 @@ void __init memblock_allow_resize(void) memblock_can_resize = 1; } +static void __init_memblock memblock_resize_late(int begin) +{ + static int memblock_can_resize_old; + + if (begin) { + preempt_disable(); + 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; + preempt_enable(); + } +} + +void __init_memblock memblock_region_resize_late_begin(void) +{ + memblock_resize_late(1); +} + +void __init_memblock memblock_region_resize_late_end(void) +{ + memblock_resize_late(0); +} + static int __init early_memblock(char *p) { if (p && strstr(p, "debug"))