summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--drivers/base/dma-removed.c2
-rw-r--r--include/linux/memblock.h2
-rw-r--r--mm/memblock.c44
3 files changed, 47 insertions, 1 deletions
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 <linux/debugfs.h>
#include <linux/seq_file.h>
#include <linux/memblock.h>
+#include <linux/preempt.h>
+#include <linux/seqlock.h>
#include <asm-generic/sections.h>
#include <linux/io.h>
@@ -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"))