summaryrefslogtreecommitdiff
path: root/mm/memblock.c
diff options
context:
space:
mode:
Diffstat (limited to 'mm/memblock.c')
-rw-r--r--mm/memblock.c74
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"))