The bootmem code contained many #ifdefs in it so that it could be
splitted into two files for the readability. The split was quite
mechanical and only function need to be shared was free_bootmem_late.
Tested on x86-64 and um which use nobootmem and bootmem respectively.
Signed-off-by: Namhyung Kim <[email protected]>
---
mm/Makefile | 8 +-
mm/bootmem.c | 164 +--------------------
mm/nobootmem.c | 445 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
3 files changed, 454 insertions(+), 163 deletions(-)
create mode 100644 mm/nobootmem.c
diff --git a/mm/Makefile b/mm/Makefile
index 2b1b575ae712..e9a074dbad15 100644
--- a/mm/Makefile
+++ b/mm/Makefile
@@ -7,7 +7,7 @@ mmu-$(CONFIG_MMU) := fremap.o highmem.o madvise.o memory.o mincore.o \
mlock.o mmap.o mprotect.o mremap.o msync.o rmap.o \
vmalloc.o pagewalk.o pgtable-generic.o
-obj-y := bootmem.o filemap.o mempool.o oom_kill.o fadvise.o \
+obj-y := filemap.o mempool.o oom_kill.o fadvise.o \
maccess.o page_alloc.o page-writeback.o \
readahead.o swap.o truncate.o vmscan.o shmem.o \
prio_tree.o util.o mmzone.o vmstat.o backing-dev.o \
@@ -15,6 +15,12 @@ obj-y := bootmem.o filemap.o mempool.o oom_kill.o fadvise.o \
$(mmu-y)
obj-y += init-mm.o
+ifeq ($(CONFIG_NO_BOOTMEM),y)
+obj-y += nobootmem.o
+else
+obj-y += bootmem.o
+endif
+
obj-$(CONFIG_HAVE_MEMBLOCK) += memblock.o
obj-$(CONFIG_BOUNCE) += bounce.o
diff --git a/mm/bootmem.c b/mm/bootmem.c
index 13b0caa9793c..209be265ad94 100644
--- a/mm/bootmem.c
+++ b/mm/bootmem.c
@@ -35,7 +35,6 @@ unsigned long max_pfn;
unsigned long saved_max_pfn;
#endif
-#ifndef CONFIG_NO_BOOTMEM
bootmem_data_t bootmem_node_data[MAX_NUMNODES] __initdata;
static struct list_head bdata_list __initdata = LIST_HEAD_INIT(bdata_list);
@@ -146,8 +145,8 @@ unsigned long __init init_bootmem(unsigned long start, unsigned long pages)
min_low_pfn = start;
return init_bootmem_core(NODE_DATA(0)->bdata, start, 0, pages);
}
-#endif
-/*
+
+/**
* free_bootmem_late - free bootmem pages directly to page allocator
* @addr: starting address of the range
* @size: size of the range in bytes
@@ -171,53 +170,6 @@ void __init free_bootmem_late(unsigned long addr, unsigned long size)
}
}
-#ifdef CONFIG_NO_BOOTMEM
-static void __init __free_pages_memory(unsigned long start, unsigned long end)
-{
- int i;
- unsigned long start_aligned, end_aligned;
- int order = ilog2(BITS_PER_LONG);
-
- start_aligned = (start + (BITS_PER_LONG - 1)) & ~(BITS_PER_LONG - 1);
- end_aligned = end & ~(BITS_PER_LONG - 1);
-
- if (end_aligned <= start_aligned) {
- for (i = start; i < end; i++)
- __free_pages_bootmem(pfn_to_page(i), 0);
-
- return;
- }
-
- for (i = start; i < start_aligned; i++)
- __free_pages_bootmem(pfn_to_page(i), 0);
-
- for (i = start_aligned; i < end_aligned; i += BITS_PER_LONG)
- __free_pages_bootmem(pfn_to_page(i), order);
-
- for (i = end_aligned; i < end; i++)
- __free_pages_bootmem(pfn_to_page(i), 0);
-}
-
-unsigned long __init free_all_memory_core_early(int nodeid)
-{
- int i;
- u64 start, end;
- unsigned long count = 0;
- struct range *range = NULL;
- int nr_range;
-
- nr_range = get_free_all_memory_range(&range, nodeid);
-
- for (i = 0; i < nr_range; i++) {
- start = range[i].start;
- end = range[i].end;
- count += end - start;
- __free_pages_memory(start, end);
- }
-
- return count;
-}
-#else
static unsigned long __init free_all_bootmem_core(bootmem_data_t *bdata)
{
int aligned;
@@ -278,7 +230,6 @@ static unsigned long __init free_all_bootmem_core(bootmem_data_t *bdata)
return count;
}
-#endif
/**
* free_all_bootmem_node - release a node's free pages to the buddy allocator
@@ -289,12 +240,7 @@ static unsigned long __init free_all_bootmem_core(bootmem_data_t *bdata)
unsigned long __init free_all_bootmem_node(pg_data_t *pgdat)
{
register_page_bootmem_info_node(pgdat);
-#ifdef CONFIG_NO_BOOTMEM
- /* free_all_memory_core_early(MAX_NUMNODES) will be called later */
- return 0;
-#else
return free_all_bootmem_core(pgdat->bdata);
-#endif
}
/**
@@ -304,16 +250,6 @@ unsigned long __init free_all_bootmem_node(pg_data_t *pgdat)
*/
unsigned long __init free_all_bootmem(void)
{
-#ifdef CONFIG_NO_BOOTMEM
- /*
- * We need to use MAX_NUMNODES instead of NODE_DATA(0)->node_id
- * because in some case like Node0 doesnt have RAM installed
- * low ram will be on Node1
- * Use MAX_NUMNODES will make sure all ranges in early_node_map[]
- * will be used instead of only Node0 related
- */
- return free_all_memory_core_early(MAX_NUMNODES);
-#else
unsigned long total_pages = 0;
bootmem_data_t *bdata;
@@ -321,10 +257,8 @@ unsigned long __init free_all_bootmem(void)
total_pages += free_all_bootmem_core(bdata);
return total_pages;
-#endif
}
-#ifndef CONFIG_NO_BOOTMEM
static void __init __free(bootmem_data_t *bdata,
unsigned long sidx, unsigned long eidx)
{
@@ -419,7 +353,6 @@ static int __init mark_bootmem(unsigned long start, unsigned long end,
}
BUG();
}
-#endif
/**
* free_bootmem_node - mark a page range as usable
@@ -434,10 +367,6 @@ static int __init mark_bootmem(unsigned long start, unsigned long end,
void __init free_bootmem_node(pg_data_t *pgdat, unsigned long physaddr,
unsigned long size)
{
-#ifdef CONFIG_NO_BOOTMEM
- kmemleak_free_part(__va(physaddr), size);
- memblock_x86_free_range(physaddr, physaddr + size);
-#else
unsigned long start, end;
kmemleak_free_part(__va(physaddr), size);
@@ -446,7 +375,6 @@ void __init free_bootmem_node(pg_data_t *pgdat, unsigned long physaddr,
end = PFN_DOWN(physaddr + size);
mark_bootmem_node(pgdat->bdata, start, end, 0, 0);
-#endif
}
/**
@@ -460,10 +388,6 @@ void __init free_bootmem_node(pg_data_t *pgdat, unsigned long physaddr,
*/
void __init free_bootmem(unsigned long addr, unsigned long size)
{
-#ifdef CONFIG_NO_BOOTMEM
- kmemleak_free_part(__va(addr), size);
- memblock_x86_free_range(addr, addr + size);
-#else
unsigned long start, end;
kmemleak_free_part(__va(addr), size);
@@ -472,7 +396,6 @@ void __init free_bootmem(unsigned long addr, unsigned long size)
end = PFN_DOWN(addr + size);
mark_bootmem(start, end, 0, 0);
-#endif
}
/**
@@ -489,17 +412,12 @@ void __init free_bootmem(unsigned long addr, unsigned long size)
int __init reserve_bootmem_node(pg_data_t *pgdat, unsigned long physaddr,
unsigned long size, int flags)
{
-#ifdef CONFIG_NO_BOOTMEM
- panic("no bootmem");
- return 0;
-#else
unsigned long start, end;
start = PFN_DOWN(physaddr);
end = PFN_UP(physaddr + size);
return mark_bootmem_node(pgdat->bdata, start, end, 1, flags);
-#endif
}
/**
@@ -515,20 +433,14 @@ int __init reserve_bootmem_node(pg_data_t *pgdat, unsigned long physaddr,
int __init reserve_bootmem(unsigned long addr, unsigned long size,
int flags)
{
-#ifdef CONFIG_NO_BOOTMEM
- panic("no bootmem");
- return 0;
-#else
unsigned long start, end;
start = PFN_DOWN(addr);
end = PFN_UP(addr + size);
return mark_bootmem(start, end, 1, flags);
-#endif
}
-#ifndef CONFIG_NO_BOOTMEM
int __weak __init reserve_bootmem_generic(unsigned long phys, unsigned long len,
int flags)
{
@@ -685,33 +597,12 @@ static void * __init alloc_arch_preferred_bootmem(bootmem_data_t *bdata,
#endif
return NULL;
}
-#endif
static void * __init ___alloc_bootmem_nopanic(unsigned long size,
unsigned long align,
unsigned long goal,
unsigned long limit)
{
-#ifdef CONFIG_NO_BOOTMEM
- void *ptr;
-
- if (WARN_ON_ONCE(slab_is_available()))
- return kzalloc(size, GFP_NOWAIT);
-
-restart:
-
- ptr = __alloc_memory_core_early(MAX_NUMNODES, size, align, goal, limit);
-
- if (ptr)
- return ptr;
-
- if (goal != 0) {
- goal = 0;
- goto restart;
- }
-
- return NULL;
-#else
bootmem_data_t *bdata;
void *region;
@@ -737,7 +628,6 @@ restart:
}
return NULL;
-#endif
}
/**
@@ -758,10 +648,6 @@ void * __init __alloc_bootmem_nopanic(unsigned long size, unsigned long align,
{
unsigned long limit = 0;
-#ifdef CONFIG_NO_BOOTMEM
- limit = -1UL;
-#endif
-
return ___alloc_bootmem_nopanic(size, align, goal, limit);
}
@@ -798,14 +684,9 @@ void * __init __alloc_bootmem(unsigned long size, unsigned long align,
{
unsigned long limit = 0;
-#ifdef CONFIG_NO_BOOTMEM
- limit = -1UL;
-#endif
-
return ___alloc_bootmem(size, align, goal, limit);
}
-#ifndef CONFIG_NO_BOOTMEM
static void * __init ___alloc_bootmem_node(bootmem_data_t *bdata,
unsigned long size, unsigned long align,
unsigned long goal, unsigned long limit)
@@ -822,7 +703,6 @@ static void * __init ___alloc_bootmem_node(bootmem_data_t *bdata,
return ___alloc_bootmem(size, align, goal, limit);
}
-#endif
/**
* __alloc_bootmem_node - allocate boot memory from a specific node
@@ -847,17 +727,7 @@ void * __init __alloc_bootmem_node(pg_data_t *pgdat, unsigned long size,
if (WARN_ON_ONCE(slab_is_available()))
return kzalloc_node(size, GFP_NOWAIT, pgdat->node_id);
-#ifdef CONFIG_NO_BOOTMEM
- ptr = __alloc_memory_core_early(pgdat->node_id, size, align,
- goal, -1ULL);
- if (ptr)
- return ptr;
-
- ptr = __alloc_memory_core_early(MAX_NUMNODES, size, align,
- goal, -1ULL);
-#else
ptr = ___alloc_bootmem_node(pgdat->bdata, size, align, goal, 0);
-#endif
return ptr;
}
@@ -880,13 +750,8 @@ void * __init __alloc_bootmem_node_high(pg_data_t *pgdat, unsigned long size,
unsigned long new_goal;
new_goal = MAX_DMA32_PFN << PAGE_SHIFT;
-#ifdef CONFIG_NO_BOOTMEM
- ptr = __alloc_memory_core_early(pgdat->node_id, size, align,
- new_goal, -1ULL);
-#else
ptr = alloc_bootmem_core(pgdat->bdata, size, align,
new_goal, 0);
-#endif
if (ptr)
return ptr;
}
@@ -907,16 +772,6 @@ void * __init __alloc_bootmem_node_high(pg_data_t *pgdat, unsigned long size,
void * __init alloc_bootmem_section(unsigned long size,
unsigned long section_nr)
{
-#ifdef CONFIG_NO_BOOTMEM
- unsigned long pfn, goal, limit;
-
- pfn = section_nr_to_pfn(section_nr);
- goal = pfn << PAGE_SHIFT;
- limit = section_nr_to_pfn(section_nr + 1) << PAGE_SHIFT;
-
- return __alloc_memory_core_early(early_pfn_to_nid(pfn), size,
- SMP_CACHE_BYTES, goal, limit);
-#else
bootmem_data_t *bdata;
unsigned long pfn, goal, limit;
@@ -926,7 +781,6 @@ void * __init alloc_bootmem_section(unsigned long size,
bdata = &bootmem_node_data[early_pfn_to_nid(pfn)];
return alloc_bootmem_core(bdata, size, SMP_CACHE_BYTES, goal, limit);
-#endif
}
#endif
@@ -938,16 +792,11 @@ void * __init __alloc_bootmem_node_nopanic(pg_data_t *pgdat, unsigned long size,
if (WARN_ON_ONCE(slab_is_available()))
return kzalloc_node(size, GFP_NOWAIT, pgdat->node_id);
-#ifdef CONFIG_NO_BOOTMEM
- ptr = __alloc_memory_core_early(pgdat->node_id, size, align,
- goal, -1ULL);
-#else
ptr = alloc_arch_preferred_bootmem(pgdat->bdata, size, align, goal, 0);
if (ptr)
return ptr;
ptr = alloc_bootmem_core(pgdat->bdata, size, align, goal, 0);
-#endif
if (ptr)
return ptr;
@@ -1000,16 +849,7 @@ void * __init __alloc_bootmem_low_node(pg_data_t *pgdat, unsigned long size,
if (WARN_ON_ONCE(slab_is_available()))
return kzalloc_node(size, GFP_NOWAIT, pgdat->node_id);
-#ifdef CONFIG_NO_BOOTMEM
- ptr = __alloc_memory_core_early(pgdat->node_id, size, align,
- goal, ARCH_LOW_ADDRESS_LIMIT);
- if (ptr)
- return ptr;
- ptr = __alloc_memory_core_early(MAX_NUMNODES, size, align,
- goal, ARCH_LOW_ADDRESS_LIMIT);
-#else
ptr = ___alloc_bootmem_node(pgdat->bdata, size, align,
goal, ARCH_LOW_ADDRESS_LIMIT);
-#endif
return ptr;
}
diff --git a/mm/nobootmem.c b/mm/nobootmem.c
new file mode 100644
index 000000000000..e93c3475011b
--- /dev/null
+++ b/mm/nobootmem.c
@@ -0,0 +1,445 @@
+/*
+ * nobootmem - A boot-time physical memory allocator and configurator
+ *
+ * Copyright (C) 1999 Ingo Molnar
+ * 1999 Kanoj Sarcar, SGI
+ * 2008 Johannes Weiner
+ *
+ * Split out of bootmem.c by Namhyung Kim <[email protected]>
+ *
+ * Access to this subsystem has to be serialized externally (which is true
+ * for the boot process anyway).
+ */
+#include <linux/init.h>
+#include <linux/pfn.h>
+#include <linux/slab.h>
+#include <linux/bootmem.h>
+#include <linux/module.h>
+#include <linux/kmemleak.h>
+#include <linux/range.h>
+#include <linux/memblock.h>
+
+#include <asm/bug.h>
+#include <asm/io.h>
+#include <asm/processor.h>
+
+#include "internal.h"
+
+unsigned long max_low_pfn;
+unsigned long min_low_pfn;
+unsigned long max_pfn;
+
+#ifdef CONFIG_CRASH_DUMP
+/*
+ * If we have booted due to a crash, max_pfn will be a very low value. We need
+ * to know the amount of memory that the previous kernel used.
+ */
+unsigned long saved_max_pfn;
+#endif
+
+/**
+ * free_bootmem_late - free bootmem pages directly to page allocator
+ * @addr: starting address of the range
+ * @size: size of the range in bytes
+ *
+ * This is only useful when the bootmem allocator has already been torn
+ * down, but we are still initializing the system. Pages are given directly
+ * to the page allocator, no bootmem metadata is updated because it is gone.
+ */
+void __init free_bootmem_late(unsigned long addr, unsigned long size)
+{
+ unsigned long cursor, end;
+
+ kmemleak_free_part(__va(addr), size);
+
+ cursor = PFN_UP(addr);
+ end = PFN_DOWN(addr + size);
+
+ for (; cursor < end; cursor++) {
+ __free_pages_bootmem(pfn_to_page(cursor), 0);
+ totalram_pages++;
+ }
+}
+
+static void __init __free_pages_memory(unsigned long start, unsigned long end)
+{
+ int i;
+ unsigned long start_aligned, end_aligned;
+ int order = ilog2(BITS_PER_LONG);
+
+ start_aligned = (start + (BITS_PER_LONG - 1)) & ~(BITS_PER_LONG - 1);
+ end_aligned = end & ~(BITS_PER_LONG - 1);
+
+ if (end_aligned <= start_aligned) {
+ for (i = start; i < end; i++)
+ __free_pages_bootmem(pfn_to_page(i), 0);
+
+ return;
+ }
+
+ for (i = start; i < start_aligned; i++)
+ __free_pages_bootmem(pfn_to_page(i), 0);
+
+ for (i = start_aligned; i < end_aligned; i += BITS_PER_LONG)
+ __free_pages_bootmem(pfn_to_page(i), order);
+
+ for (i = end_aligned; i < end; i++)
+ __free_pages_bootmem(pfn_to_page(i), 0);
+}
+
+unsigned long __init free_all_memory_core_early(int nodeid)
+{
+ int i;
+ u64 start, end;
+ unsigned long count = 0;
+ struct range *range = NULL;
+ int nr_range;
+
+ nr_range = get_free_all_memory_range(&range, nodeid);
+
+ for (i = 0; i < nr_range; i++) {
+ start = range[i].start;
+ end = range[i].end;
+ count += end - start;
+ __free_pages_memory(start, end);
+ }
+
+ return count;
+}
+
+/**
+ * free_all_bootmem_node - release a node's free pages to the buddy allocator
+ * @pgdat: node to be released
+ *
+ * Returns the number of pages actually released.
+ */
+unsigned long __init free_all_bootmem_node(pg_data_t *pgdat)
+{
+ register_page_bootmem_info_node(pgdat);
+
+ /* free_all_memory_core_early(MAX_NUMNODES) will be called later */
+ return 0;
+}
+
+/**
+ * free_all_bootmem - release free pages to the buddy allocator
+ *
+ * Returns the number of pages actually released.
+ */
+unsigned long __init free_all_bootmem(void)
+{
+ /*
+ * We need to use MAX_NUMNODES instead of NODE_DATA(0)->node_id
+ * because in some case like Node0 doesnt have RAM installed
+ * low ram will be on Node1
+ * Use MAX_NUMNODES will make sure all ranges in early_node_map[]
+ * will be used instead of only Node0 related
+ */
+ return free_all_memory_core_early(MAX_NUMNODES);
+}
+
+/**
+ * free_bootmem_node - mark a page range as usable
+ * @pgdat: node the range resides on
+ * @physaddr: starting address of the range
+ * @size: size of the range in bytes
+ *
+ * Partial pages will be considered reserved and left as they are.
+ *
+ * The range must reside completely on the specified node.
+ */
+void __init free_bootmem_node(pg_data_t *pgdat, unsigned long physaddr,
+ unsigned long size)
+{
+ kmemleak_free_part(__va(physaddr), size);
+ memblock_x86_free_range(physaddr, physaddr + size);
+}
+
+/**
+ * free_bootmem - mark a page range as usable
+ * @addr: starting address of the range
+ * @size: size of the range in bytes
+ *
+ * Partial pages will be considered reserved and left as they are.
+ *
+ * The range must be contiguous but may span node boundaries.
+ */
+void __init free_bootmem(unsigned long addr, unsigned long size)
+{
+ kmemleak_free_part(__va(addr), size);
+ memblock_x86_free_range(addr, addr + size);
+}
+
+/**
+ * reserve_bootmem_node - mark a page range as reserved
+ * @pgdat: node the range resides on
+ * @physaddr: starting address of the range
+ * @size: size of the range in bytes
+ * @flags: reservation flags (see linux/bootmem.h)
+ *
+ * Partial pages will be reserved.
+ *
+ * The range must reside completely on the specified node.
+ */
+int __init reserve_bootmem_node(pg_data_t *pgdat, unsigned long physaddr,
+ unsigned long size, int flags)
+{
+ panic("no bootmem");
+ return 0;
+}
+
+/**
+ * reserve_bootmem - mark a page range as usable
+ * @addr: starting address of the range
+ * @size: size of the range in bytes
+ * @flags: reservation flags (see linux/bootmem.h)
+ *
+ * Partial pages will be reserved.
+ *
+ * The range must be contiguous but may span node boundaries.
+ */
+int __init reserve_bootmem(unsigned long addr, unsigned long size,
+ int flags)
+{
+ panic("no bootmem");
+ return 0;
+}
+
+static void * __init ___alloc_bootmem_nopanic(unsigned long size,
+ unsigned long align,
+ unsigned long goal,
+ unsigned long limit)
+{
+ void *ptr;
+
+ if (WARN_ON_ONCE(slab_is_available()))
+ return kzalloc(size, GFP_NOWAIT);
+
+restart:
+
+ ptr = __alloc_memory_core_early(MAX_NUMNODES, size, align, goal, limit);
+
+ if (ptr)
+ return ptr;
+
+ if (goal != 0) {
+ goal = 0;
+ goto restart;
+ }
+
+ return NULL;
+}
+
+/**
+ * __alloc_bootmem_nopanic - allocate boot memory without panicking
+ * @size: size of the request in bytes
+ * @align: alignment of the region
+ * @goal: preferred starting address of the region
+ *
+ * The goal is dropped if it can not be satisfied and the allocation will
+ * fall back to memory below @goal.
+ *
+ * Allocation may happen on any node in the system.
+ *
+ * Returns NULL on failure.
+ */
+void * __init __alloc_bootmem_nopanic(unsigned long size, unsigned long align,
+ unsigned long goal)
+{
+ unsigned long limit = -1UL;
+
+ return ___alloc_bootmem_nopanic(size, align, goal, limit);
+}
+
+static void * __init ___alloc_bootmem(unsigned long size, unsigned long align,
+ unsigned long goal, unsigned long limit)
+{
+ void *mem = ___alloc_bootmem_nopanic(size, align, goal, limit);
+
+ if (mem)
+ return mem;
+ /*
+ * Whoops, we cannot satisfy the allocation request.
+ */
+ printk(KERN_ALERT "bootmem alloc of %lu bytes failed!\n", size);
+ panic("Out of memory");
+ return NULL;
+}
+
+/**
+ * __alloc_bootmem - allocate boot memory
+ * @size: size of the request in bytes
+ * @align: alignment of the region
+ * @goal: preferred starting address of the region
+ *
+ * The goal is dropped if it can not be satisfied and the allocation will
+ * fall back to memory below @goal.
+ *
+ * Allocation may happen on any node in the system.
+ *
+ * The function panics if the request can not be satisfied.
+ */
+void * __init __alloc_bootmem(unsigned long size, unsigned long align,
+ unsigned long goal)
+{
+ unsigned long limit = -1UL;
+
+ return ___alloc_bootmem(size, align, goal, limit);
+}
+
+/**
+ * __alloc_bootmem_node - allocate boot memory from a specific node
+ * @pgdat: node to allocate from
+ * @size: size of the request in bytes
+ * @align: alignment of the region
+ * @goal: preferred starting address of the region
+ *
+ * The goal is dropped if it can not be satisfied and the allocation will
+ * fall back to memory below @goal.
+ *
+ * Allocation may fall back to any node in the system if the specified node
+ * can not hold the requested memory.
+ *
+ * The function panics if the request can not be satisfied.
+ */
+void * __init __alloc_bootmem_node(pg_data_t *pgdat, unsigned long size,
+ unsigned long align, unsigned long goal)
+{
+ void *ptr;
+
+ if (WARN_ON_ONCE(slab_is_available()))
+ return kzalloc_node(size, GFP_NOWAIT, pgdat->node_id);
+
+ ptr = __alloc_memory_core_early(pgdat->node_id, size, align,
+ goal, -1ULL);
+ if (ptr)
+ return ptr;
+
+ ptr = __alloc_memory_core_early(MAX_NUMNODES, size, align,
+ goal, -1ULL);
+
+ return ptr;
+}
+
+void * __init __alloc_bootmem_node_high(pg_data_t *pgdat, unsigned long size,
+ unsigned long align, unsigned long goal)
+{
+#ifdef MAX_DMA32_PFN
+ unsigned long end_pfn;
+
+ if (WARN_ON_ONCE(slab_is_available()))
+ return kzalloc_node(size, GFP_NOWAIT, pgdat->node_id);
+
+ /* update goal according ...MAX_DMA32_PFN */
+ end_pfn = pgdat->node_start_pfn + pgdat->node_spanned_pages;
+
+ if (end_pfn > MAX_DMA32_PFN + (128 >> (20 - PAGE_SHIFT)) &&
+ (goal >> PAGE_SHIFT) < MAX_DMA32_PFN) {
+ void *ptr;
+ unsigned long new_goal;
+
+ new_goal = MAX_DMA32_PFN << PAGE_SHIFT;
+ ptr = __alloc_memory_core_early(pgdat->node_id, size, align,
+ new_goal, -1ULL);
+ if (ptr)
+ return ptr;
+ }
+#endif
+
+ return __alloc_bootmem_node(pgdat, size, align, goal);
+
+}
+
+#ifdef CONFIG_SPARSEMEM
+/**
+ * alloc_bootmem_section - allocate boot memory from a specific section
+ * @size: size of the request in bytes
+ * @section_nr: sparse map section to allocate from
+ *
+ * Return NULL on failure.
+ */
+void * __init alloc_bootmem_section(unsigned long size,
+ unsigned long section_nr)
+{
+ unsigned long pfn, goal, limit;
+
+ pfn = section_nr_to_pfn(section_nr);
+ goal = pfn << PAGE_SHIFT;
+ limit = section_nr_to_pfn(section_nr + 1) << PAGE_SHIFT;
+
+ return __alloc_memory_core_early(early_pfn_to_nid(pfn), size,
+ SMP_CACHE_BYTES, goal, limit);
+}
+#endif
+
+void * __init __alloc_bootmem_node_nopanic(pg_data_t *pgdat, unsigned long size,
+ unsigned long align, unsigned long goal)
+{
+ void *ptr;
+
+ if (WARN_ON_ONCE(slab_is_available()))
+ return kzalloc_node(size, GFP_NOWAIT, pgdat->node_id);
+
+ ptr = __alloc_memory_core_early(pgdat->node_id, size, align,
+ goal, -1ULL);
+ if (ptr)
+ return ptr;
+
+ return __alloc_bootmem_nopanic(size, align, goal);
+}
+
+#ifndef ARCH_LOW_ADDRESS_LIMIT
+#define ARCH_LOW_ADDRESS_LIMIT 0xffffffffUL
+#endif
+
+/**
+ * __alloc_bootmem_low - allocate low boot memory
+ * @size: size of the request in bytes
+ * @align: alignment of the region
+ * @goal: preferred starting address of the region
+ *
+ * The goal is dropped if it can not be satisfied and the allocation will
+ * fall back to memory below @goal.
+ *
+ * Allocation may happen on any node in the system.
+ *
+ * The function panics if the request can not be satisfied.
+ */
+void * __init __alloc_bootmem_low(unsigned long size, unsigned long align,
+ unsigned long goal)
+{
+ return ___alloc_bootmem(size, align, goal, ARCH_LOW_ADDRESS_LIMIT);
+}
+
+/**
+ * __alloc_bootmem_low_node - allocate low boot memory from a specific node
+ * @pgdat: node to allocate from
+ * @size: size of the request in bytes
+ * @align: alignment of the region
+ * @goal: preferred starting address of the region
+ *
+ * The goal is dropped if it can not be satisfied and the allocation will
+ * fall back to memory below @goal.
+ *
+ * Allocation may fall back to any node in the system if the specified node
+ * can not hold the requested memory.
+ *
+ * The function panics if the request can not be satisfied.
+ */
+void * __init __alloc_bootmem_low_node(pg_data_t *pgdat, unsigned long size,
+ unsigned long align, unsigned long goal)
+{
+ void *ptr;
+
+ if (WARN_ON_ONCE(slab_is_available()))
+ return kzalloc_node(size, GFP_NOWAIT, pgdat->node_id);
+
+ ptr = __alloc_memory_core_early(pgdat->node_id, size, align,
+ goal, ARCH_LOW_ADDRESS_LIMIT);
+ if (ptr)
+ return ptr;
+
+ ptr = __alloc_memory_core_early(MAX_NUMNODES, size, align,
+ goal, ARCH_LOW_ADDRESS_LIMIT);
+ return ptr;
+}
--
1.7.3.4.600.g982838b0
On Mon, Feb 7, 2011 at 7:30 AM, Namhyung Kim <[email protected]> wrote:
> The bootmem code contained many #ifdefs in it so that it could be
> splitted into two files for the readability. The split was quite
> mechanical and only function need to be shared was free_bootmem_late.
>
> Tested on x86-64 and um which use nobootmem and bootmem respectively.
>
> Signed-off-by: Namhyung Kim <[email protected]>
https://lkml.org/lkml/2010/6/16/44
...
> ---
> ?mm/Makefile ? ?| ? ?8 +-
> ?mm/bootmem.c ? | ?164 +--------------------
> ?mm/nobootmem.c | ?445 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
> ?3 files changed, 454 insertions(+), 163 deletions(-)
> ?create mode 100644 mm/nobootmem.c
>
> diff --git a/mm/Makefile b/mm/Makefile
> index 2b1b575ae712..e9a074dbad15 100644
> --- a/mm/Makefile
> +++ b/mm/Makefile
> @@ -7,7 +7,7 @@ mmu-$(CONFIG_MMU) ? ? ? := fremap.o highmem.o madvise.o memory.o mincore.o \
> ? ? ? ? ? ? ? ? ? ? ? ? ? mlock.o mmap.o mprotect.o mremap.o msync.o rmap.o \
> ? ? ? ? ? ? ? ? ? ? ? ? ? vmalloc.o pagewalk.o pgtable-generic.o
>
> -obj-y ? ? ? ? ? ? ? ? ?:= bootmem.o filemap.o mempool.o oom_kill.o fadvise.o \
> +obj-y ? ? ? ? ? ? ? ? ?:= filemap.o mempool.o oom_kill.o fadvise.o \
> ? ? ? ? ? ? ? ? ? ? ? ? ? maccess.o page_alloc.o page-writeback.o \
> ? ? ? ? ? ? ? ? ? ? ? ? ? readahead.o swap.o truncate.o vmscan.o shmem.o \
> ? ? ? ? ? ? ? ? ? ? ? ? ? prio_tree.o util.o mmzone.o vmstat.o backing-dev.o \
> @@ -15,6 +15,12 @@ obj-y ? ? ? ? ? ? ? ? ? ? ? ?:= bootmem.o filemap.o mempool.o oom_kill.o fadvise.o \
> ? ? ? ? ? ? ? ? ? ? ? ? ? $(mmu-y)
> ?obj-y += init-mm.o
>
> +ifeq ($(CONFIG_NO_BOOTMEM),y)
> +obj-y += nobootmem.o
> +else
> +obj-y += bootmem.o
> +endif
> +
> ?obj-$(CONFIG_HAVE_MEMBLOCK) += memblock.o
>
> ?obj-$(CONFIG_BOUNCE) ? += bounce.o
> diff --git a/mm/bootmem.c b/mm/bootmem.c
> index 13b0caa9793c..209be265ad94 100644
> --- a/mm/bootmem.c
> +++ b/mm/bootmem.c
> @@ -35,7 +35,6 @@ unsigned long max_pfn;
> ?unsigned long saved_max_pfn;
> ?#endif
>
> -#ifndef CONFIG_NO_BOOTMEM
> ?bootmem_data_t bootmem_node_data[MAX_NUMNODES] __initdata;
>
> ?static struct list_head bdata_list __initdata = LIST_HEAD_INIT(bdata_list);
> @@ -146,8 +145,8 @@ unsigned long __init init_bootmem(unsigned long start, unsigned long pages)
> ? ? ? ?min_low_pfn = start;
> ? ? ? ?return init_bootmem_core(NODE_DATA(0)->bdata, start, 0, pages);
> ?}
> -#endif
> -/*
> +
> +/**
> ?* free_bootmem_late - free bootmem pages directly to page allocator
> ?* @addr: starting address of the range
> ?* @size: size of the range in bytes
> @@ -171,53 +170,6 @@ void __init free_bootmem_late(unsigned long addr, unsigned long size)
> ? ? ? ?}
> ?}
>
> -#ifdef CONFIG_NO_BOOTMEM
> -static void __init __free_pages_memory(unsigned long start, unsigned long end)
> -{
> - ? ? ? int i;
> - ? ? ? unsigned long start_aligned, end_aligned;
> - ? ? ? int order = ilog2(BITS_PER_LONG);
> -
> - ? ? ? start_aligned = (start + (BITS_PER_LONG - 1)) & ~(BITS_PER_LONG - 1);
> - ? ? ? end_aligned = end & ~(BITS_PER_LONG - 1);
> -
> - ? ? ? if (end_aligned <= start_aligned) {
> - ? ? ? ? ? ? ? for (i = start; i < end; i++)
> - ? ? ? ? ? ? ? ? ? ? ? __free_pages_bootmem(pfn_to_page(i), 0);
> -
> - ? ? ? ? ? ? ? return;
> - ? ? ? }
> -
> - ? ? ? for (i = start; i < start_aligned; i++)
> - ? ? ? ? ? ? ? __free_pages_bootmem(pfn_to_page(i), 0);
> -
> - ? ? ? for (i = start_aligned; i < end_aligned; i += BITS_PER_LONG)
> - ? ? ? ? ? ? ? __free_pages_bootmem(pfn_to_page(i), order);
> -
> - ? ? ? for (i = end_aligned; i < end; i++)
> - ? ? ? ? ? ? ? __free_pages_bootmem(pfn_to_page(i), 0);
> -}
> -
> -unsigned long __init free_all_memory_core_early(int nodeid)
> -{
> - ? ? ? int i;
> - ? ? ? u64 start, end;
> - ? ? ? unsigned long count = 0;
> - ? ? ? struct range *range = NULL;
> - ? ? ? int nr_range;
> -
> - ? ? ? nr_range = get_free_all_memory_range(&range, nodeid);
> -
> - ? ? ? for (i = 0; i < nr_range; i++) {
> - ? ? ? ? ? ? ? start = range[i].start;
> - ? ? ? ? ? ? ? end = range[i].end;
> - ? ? ? ? ? ? ? count += end - start;
> - ? ? ? ? ? ? ? __free_pages_memory(start, end);
> - ? ? ? }
> -
> - ? ? ? return count;
> -}
> -#else
> ?static unsigned long __init free_all_bootmem_core(bootmem_data_t *bdata)
> ?{
> ? ? ? ?int aligned;
> @@ -278,7 +230,6 @@ static unsigned long __init free_all_bootmem_core(bootmem_data_t *bdata)
>
> ? ? ? ?return count;
> ?}
> -#endif
>
> ?/**
> ?* free_all_bootmem_node - release a node's free pages to the buddy allocator
> @@ -289,12 +240,7 @@ static unsigned long __init free_all_bootmem_core(bootmem_data_t *bdata)
> ?unsigned long __init free_all_bootmem_node(pg_data_t *pgdat)
> ?{
> ? ? ? ?register_page_bootmem_info_node(pgdat);
> -#ifdef CONFIG_NO_BOOTMEM
> - ? ? ? /* free_all_memory_core_early(MAX_NUMNODES) will be called later */
> - ? ? ? return 0;
> -#else
> ? ? ? ?return free_all_bootmem_core(pgdat->bdata);
> -#endif
> ?}
>
> ?/**
> @@ -304,16 +250,6 @@ unsigned long __init free_all_bootmem_node(pg_data_t *pgdat)
> ?*/
> ?unsigned long __init free_all_bootmem(void)
> ?{
> -#ifdef CONFIG_NO_BOOTMEM
> - ? ? ? /*
> - ? ? ? ?* We need to use MAX_NUMNODES instead of NODE_DATA(0)->node_id
> - ? ? ? ?* ?because in some case like Node0 doesnt have RAM installed
> - ? ? ? ?* ?low ram will be on Node1
> - ? ? ? ?* Use MAX_NUMNODES will make sure all ranges in early_node_map[]
> - ? ? ? ?* ?will be used instead of only Node0 related
> - ? ? ? ?*/
> - ? ? ? return free_all_memory_core_early(MAX_NUMNODES);
> -#else
> ? ? ? ?unsigned long total_pages = 0;
> ? ? ? ?bootmem_data_t *bdata;
>
> @@ -321,10 +257,8 @@ unsigned long __init free_all_bootmem(void)
> ? ? ? ? ? ? ? ?total_pages += free_all_bootmem_core(bdata);
>
> ? ? ? ?return total_pages;
> -#endif
> ?}
>
> -#ifndef CONFIG_NO_BOOTMEM
> ?static void __init __free(bootmem_data_t *bdata,
> ? ? ? ? ? ? ? ? ? ? ? ?unsigned long sidx, unsigned long eidx)
> ?{
> @@ -419,7 +353,6 @@ static int __init mark_bootmem(unsigned long start, unsigned long end,
> ? ? ? ?}
> ? ? ? ?BUG();
> ?}
> -#endif
>
> ?/**
> ?* free_bootmem_node - mark a page range as usable
> @@ -434,10 +367,6 @@ static int __init mark_bootmem(unsigned long start, unsigned long end,
> ?void __init free_bootmem_node(pg_data_t *pgdat, unsigned long physaddr,
> ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?unsigned long size)
> ?{
> -#ifdef CONFIG_NO_BOOTMEM
> - ? ? ? kmemleak_free_part(__va(physaddr), size);
> - ? ? ? memblock_x86_free_range(physaddr, physaddr + size);
> -#else
> ? ? ? ?unsigned long start, end;
>
> ? ? ? ?kmemleak_free_part(__va(physaddr), size);
> @@ -446,7 +375,6 @@ void __init free_bootmem_node(pg_data_t *pgdat, unsigned long physaddr,
> ? ? ? ?end = PFN_DOWN(physaddr + size);
>
> ? ? ? ?mark_bootmem_node(pgdat->bdata, start, end, 0, 0);
> -#endif
> ?}
>
> ?/**
> @@ -460,10 +388,6 @@ void __init free_bootmem_node(pg_data_t *pgdat, unsigned long physaddr,
> ?*/
> ?void __init free_bootmem(unsigned long addr, unsigned long size)
> ?{
> -#ifdef CONFIG_NO_BOOTMEM
> - ? ? ? kmemleak_free_part(__va(addr), size);
> - ? ? ? memblock_x86_free_range(addr, addr + size);
> -#else
> ? ? ? ?unsigned long start, end;
>
> ? ? ? ?kmemleak_free_part(__va(addr), size);
> @@ -472,7 +396,6 @@ void __init free_bootmem(unsigned long addr, unsigned long size)
> ? ? ? ?end = PFN_DOWN(addr + size);
>
> ? ? ? ?mark_bootmem(start, end, 0, 0);
> -#endif
> ?}
>
> ?/**
> @@ -489,17 +412,12 @@ void __init free_bootmem(unsigned long addr, unsigned long size)
> ?int __init reserve_bootmem_node(pg_data_t *pgdat, unsigned long physaddr,
> ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? unsigned long size, int flags)
> ?{
> -#ifdef CONFIG_NO_BOOTMEM
> - ? ? ? panic("no bootmem");
> - ? ? ? return 0;
> -#else
> ? ? ? ?unsigned long start, end;
>
> ? ? ? ?start = PFN_DOWN(physaddr);
> ? ? ? ?end = PFN_UP(physaddr + size);
>
> ? ? ? ?return mark_bootmem_node(pgdat->bdata, start, end, 1, flags);
> -#endif
> ?}
>
> ?/**
> @@ -515,20 +433,14 @@ int __init reserve_bootmem_node(pg_data_t *pgdat, unsigned long physaddr,
> ?int __init reserve_bootmem(unsigned long addr, unsigned long size,
> ? ? ? ? ? ? ? ? ? ? ? ? ? ?int flags)
> ?{
> -#ifdef CONFIG_NO_BOOTMEM
> - ? ? ? panic("no bootmem");
> - ? ? ? return 0;
> -#else
> ? ? ? ?unsigned long start, end;
>
> ? ? ? ?start = PFN_DOWN(addr);
> ? ? ? ?end = PFN_UP(addr + size);
>
> ? ? ? ?return mark_bootmem(start, end, 1, flags);
> -#endif
> ?}
>
> -#ifndef CONFIG_NO_BOOTMEM
> ?int __weak __init reserve_bootmem_generic(unsigned long phys, unsigned long len,
> ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? int flags)
> ?{
> @@ -685,33 +597,12 @@ static void * __init alloc_arch_preferred_bootmem(bootmem_data_t *bdata,
> ?#endif
> ? ? ? ?return NULL;
> ?}
> -#endif
>
> ?static void * __init ___alloc_bootmem_nopanic(unsigned long size,
> ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?unsigned long align,
> ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?unsigned long goal,
> ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?unsigned long limit)
> ?{
> -#ifdef CONFIG_NO_BOOTMEM
> - ? ? ? void *ptr;
> -
> - ? ? ? if (WARN_ON_ONCE(slab_is_available()))
> - ? ? ? ? ? ? ? return kzalloc(size, GFP_NOWAIT);
> -
> -restart:
> -
> - ? ? ? ptr = __alloc_memory_core_early(MAX_NUMNODES, size, align, goal, limit);
> -
> - ? ? ? if (ptr)
> - ? ? ? ? ? ? ? return ptr;
> -
> - ? ? ? if (goal != 0) {
> - ? ? ? ? ? ? ? goal = 0;
> - ? ? ? ? ? ? ? goto restart;
> - ? ? ? }
> -
> - ? ? ? return NULL;
> -#else
> ? ? ? ?bootmem_data_t *bdata;
> ? ? ? ?void *region;
>
> @@ -737,7 +628,6 @@ restart:
> ? ? ? ?}
>
> ? ? ? ?return NULL;
> -#endif
> ?}
>
> ?/**
> @@ -758,10 +648,6 @@ void * __init __alloc_bootmem_nopanic(unsigned long size, unsigned long align,
> ?{
> ? ? ? ?unsigned long limit = 0;
>
> -#ifdef CONFIG_NO_BOOTMEM
> - ? ? ? limit = -1UL;
> -#endif
> -
> ? ? ? ?return ___alloc_bootmem_nopanic(size, align, goal, limit);
> ?}
>
> @@ -798,14 +684,9 @@ void * __init __alloc_bootmem(unsigned long size, unsigned long align,
> ?{
> ? ? ? ?unsigned long limit = 0;
>
> -#ifdef CONFIG_NO_BOOTMEM
> - ? ? ? limit = -1UL;
> -#endif
> -
> ? ? ? ?return ___alloc_bootmem(size, align, goal, limit);
> ?}
>
> -#ifndef CONFIG_NO_BOOTMEM
> ?static void * __init ___alloc_bootmem_node(bootmem_data_t *bdata,
> ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?unsigned long size, unsigned long align,
> ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?unsigned long goal, unsigned long limit)
> @@ -822,7 +703,6 @@ static void * __init ___alloc_bootmem_node(bootmem_data_t *bdata,
>
> ? ? ? ?return ___alloc_bootmem(size, align, goal, limit);
> ?}
> -#endif
>
> ?/**
> ?* __alloc_bootmem_node - allocate boot memory from a specific node
> @@ -847,17 +727,7 @@ void * __init __alloc_bootmem_node(pg_data_t *pgdat, unsigned long size,
> ? ? ? ?if (WARN_ON_ONCE(slab_is_available()))
> ? ? ? ? ? ? ? ?return kzalloc_node(size, GFP_NOWAIT, pgdat->node_id);
>
> -#ifdef CONFIG_NO_BOOTMEM
> - ? ? ? ptr = __alloc_memory_core_early(pgdat->node_id, size, align,
> - ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?goal, -1ULL);
> - ? ? ? if (ptr)
> - ? ? ? ? ? ? ? return ptr;
> -
> - ? ? ? ptr = __alloc_memory_core_early(MAX_NUMNODES, size, align,
> - ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?goal, -1ULL);
> -#else
> ? ? ? ?ptr = ___alloc_bootmem_node(pgdat->bdata, size, align, goal, 0);
> -#endif
>
> ? ? ? ?return ptr;
> ?}
> @@ -880,13 +750,8 @@ void * __init __alloc_bootmem_node_high(pg_data_t *pgdat, unsigned long size,
> ? ? ? ? ? ? ? ?unsigned long new_goal;
>
> ? ? ? ? ? ? ? ?new_goal = MAX_DMA32_PFN << PAGE_SHIFT;
> -#ifdef CONFIG_NO_BOOTMEM
> - ? ? ? ? ? ? ? ptr = ?__alloc_memory_core_early(pgdat->node_id, size, align,
> - ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?new_goal, -1ULL);
> -#else
> ? ? ? ? ? ? ? ?ptr = alloc_bootmem_core(pgdat->bdata, size, align,
> ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? new_goal, 0);
> -#endif
> ? ? ? ? ? ? ? ?if (ptr)
> ? ? ? ? ? ? ? ? ? ? ? ?return ptr;
> ? ? ? ?}
> @@ -907,16 +772,6 @@ void * __init __alloc_bootmem_node_high(pg_data_t *pgdat, unsigned long size,
> ?void * __init alloc_bootmem_section(unsigned long size,
> ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?unsigned long section_nr)
> ?{
> -#ifdef CONFIG_NO_BOOTMEM
> - ? ? ? unsigned long pfn, goal, limit;
> -
> - ? ? ? pfn = section_nr_to_pfn(section_nr);
> - ? ? ? goal = pfn << PAGE_SHIFT;
> - ? ? ? limit = section_nr_to_pfn(section_nr + 1) << PAGE_SHIFT;
> -
> - ? ? ? return __alloc_memory_core_early(early_pfn_to_nid(pfn), size,
> - ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?SMP_CACHE_BYTES, goal, limit);
> -#else
> ? ? ? ?bootmem_data_t *bdata;
> ? ? ? ?unsigned long pfn, goal, limit;
>
> @@ -926,7 +781,6 @@ void * __init alloc_bootmem_section(unsigned long size,
> ? ? ? ?bdata = &bootmem_node_data[early_pfn_to_nid(pfn)];
>
> ? ? ? ?return alloc_bootmem_core(bdata, size, SMP_CACHE_BYTES, goal, limit);
> -#endif
> ?}
> ?#endif
>
> @@ -938,16 +792,11 @@ void * __init __alloc_bootmem_node_nopanic(pg_data_t *pgdat, unsigned long size,
> ? ? ? ?if (WARN_ON_ONCE(slab_is_available()))
> ? ? ? ? ? ? ? ?return kzalloc_node(size, GFP_NOWAIT, pgdat->node_id);
>
> -#ifdef CONFIG_NO_BOOTMEM
> - ? ? ? ptr = ?__alloc_memory_core_early(pgdat->node_id, size, align,
> - ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?goal, -1ULL);
> -#else
> ? ? ? ?ptr = alloc_arch_preferred_bootmem(pgdat->bdata, size, align, goal, 0);
> ? ? ? ?if (ptr)
> ? ? ? ? ? ? ? ?return ptr;
>
> ? ? ? ?ptr = alloc_bootmem_core(pgdat->bdata, size, align, goal, 0);
> -#endif
> ? ? ? ?if (ptr)
> ? ? ? ? ? ? ? ?return ptr;
>
> @@ -1000,16 +849,7 @@ void * __init __alloc_bootmem_low_node(pg_data_t *pgdat, unsigned long size,
> ? ? ? ?if (WARN_ON_ONCE(slab_is_available()))
> ? ? ? ? ? ? ? ?return kzalloc_node(size, GFP_NOWAIT, pgdat->node_id);
>
> -#ifdef CONFIG_NO_BOOTMEM
> - ? ? ? ptr = __alloc_memory_core_early(pgdat->node_id, size, align,
> - ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? goal, ARCH_LOW_ADDRESS_LIMIT);
> - ? ? ? if (ptr)
> - ? ? ? ? ? ? ? return ptr;
> - ? ? ? ptr = __alloc_memory_core_early(MAX_NUMNODES, size, align,
> - ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? goal, ARCH_LOW_ADDRESS_LIMIT);
> -#else
> ? ? ? ?ptr = ___alloc_bootmem_node(pgdat->bdata, size, align,
> ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?goal, ARCH_LOW_ADDRESS_LIMIT);
> -#endif
> ? ? ? ?return ptr;
> ?}
> diff --git a/mm/nobootmem.c b/mm/nobootmem.c
> new file mode 100644
> index 000000000000..e93c3475011b
> --- /dev/null
> +++ b/mm/nobootmem.c
> @@ -0,0 +1,445 @@
> +/*
> + * ?nobootmem - A boot-time physical memory allocator and configurator
> + *
> + * ?Copyright (C) 1999 Ingo Molnar
> + * ? ? ? ? ? ? ? ?1999 Kanoj Sarcar, SGI
> + * ? ? ? ? ? ? ? ?2008 Johannes Weiner
> + *
> + * ?Split out of bootmem.c by Namhyung Kim <[email protected]>
> + *
> + * Access to this subsystem has to be serialized externally (which is true
> + * for the boot process anyway).
> + */
> +#include <linux/init.h>
> +#include <linux/pfn.h>
> +#include <linux/slab.h>
> +#include <linux/bootmem.h>
> +#include <linux/module.h>
> +#include <linux/kmemleak.h>
> +#include <linux/range.h>
> +#include <linux/memblock.h>
> +
> +#include <asm/bug.h>
> +#include <asm/io.h>
> +#include <asm/processor.h>
> +
> +#include "internal.h"
> +
> +unsigned long max_low_pfn;
> +unsigned long min_low_pfn;
> +unsigned long max_pfn;
> +
> +#ifdef CONFIG_CRASH_DUMP
> +/*
> + * If we have booted due to a crash, max_pfn will be a very low value. We need
> + * to know the amount of memory that the previous kernel used.
> + */
> +unsigned long saved_max_pfn;
> +#endif
> +
> +/**
> + * free_bootmem_late - free bootmem pages directly to page allocator
> + * @addr: starting address of the range
> + * @size: size of the range in bytes
> + *
> + * This is only useful when the bootmem allocator has already been torn
> + * down, but we are still initializing the system. ?Pages are given directly
> + * to the page allocator, no bootmem metadata is updated because it is gone.
> + */
> +void __init free_bootmem_late(unsigned long addr, unsigned long size)
> +{
> + ? ? ? unsigned long cursor, end;
> +
> + ? ? ? kmemleak_free_part(__va(addr), size);
> +
> + ? ? ? cursor = PFN_UP(addr);
> + ? ? ? end = PFN_DOWN(addr + size);
> +
> + ? ? ? for (; cursor < end; cursor++) {
> + ? ? ? ? ? ? ? __free_pages_bootmem(pfn_to_page(cursor), 0);
> + ? ? ? ? ? ? ? totalram_pages++;
> + ? ? ? }
> +}
> +
> +static void __init __free_pages_memory(unsigned long start, unsigned long end)
> +{
> + ? ? ? int i;
> + ? ? ? unsigned long start_aligned, end_aligned;
> + ? ? ? int order = ilog2(BITS_PER_LONG);
> +
> + ? ? ? start_aligned = (start + (BITS_PER_LONG - 1)) & ~(BITS_PER_LONG - 1);
> + ? ? ? end_aligned = end & ~(BITS_PER_LONG - 1);
> +
> + ? ? ? if (end_aligned <= start_aligned) {
> + ? ? ? ? ? ? ? for (i = start; i < end; i++)
> + ? ? ? ? ? ? ? ? ? ? ? __free_pages_bootmem(pfn_to_page(i), 0);
> +
> + ? ? ? ? ? ? ? return;
> + ? ? ? }
> +
> + ? ? ? for (i = start; i < start_aligned; i++)
> + ? ? ? ? ? ? ? __free_pages_bootmem(pfn_to_page(i), 0);
> +
> + ? ? ? for (i = start_aligned; i < end_aligned; i += BITS_PER_LONG)
> + ? ? ? ? ? ? ? __free_pages_bootmem(pfn_to_page(i), order);
> +
> + ? ? ? for (i = end_aligned; i < end; i++)
> + ? ? ? ? ? ? ? __free_pages_bootmem(pfn_to_page(i), 0);
> +}
> +
> +unsigned long __init free_all_memory_core_early(int nodeid)
> +{
> + ? ? ? int i;
> + ? ? ? u64 start, end;
> + ? ? ? unsigned long count = 0;
> + ? ? ? struct range *range = NULL;
> + ? ? ? int nr_range;
> +
> + ? ? ? nr_range = get_free_all_memory_range(&range, nodeid);
> +
> + ? ? ? for (i = 0; i < nr_range; i++) {
> + ? ? ? ? ? ? ? start = range[i].start;
> + ? ? ? ? ? ? ? end = range[i].end;
> + ? ? ? ? ? ? ? count += end - start;
> + ? ? ? ? ? ? ? __free_pages_memory(start, end);
> + ? ? ? }
> +
> + ? ? ? return count;
> +}
> +
> +/**
> + * free_all_bootmem_node - release a node's free pages to the buddy allocator
> + * @pgdat: node to be released
> + *
> + * Returns the number of pages actually released.
> + */
> +unsigned long __init free_all_bootmem_node(pg_data_t *pgdat)
> +{
> + ? ? ? register_page_bootmem_info_node(pgdat);
> +
> + ? ? ? /* free_all_memory_core_early(MAX_NUMNODES) will be called later */
> + ? ? ? return 0;
> +}
> +
> +/**
> + * free_all_bootmem - release free pages to the buddy allocator
> + *
> + * Returns the number of pages actually released.
> + */
> +unsigned long __init free_all_bootmem(void)
> +{
> + ? ? ? /*
> + ? ? ? ?* We need to use MAX_NUMNODES instead of NODE_DATA(0)->node_id
> + ? ? ? ?* ?because in some case like Node0 doesnt have RAM installed
> + ? ? ? ?* ?low ram will be on Node1
> + ? ? ? ?* Use MAX_NUMNODES will make sure all ranges in early_node_map[]
> + ? ? ? ?* ?will be used instead of only Node0 related
> + ? ? ? ?*/
> + ? ? ? return free_all_memory_core_early(MAX_NUMNODES);
> +}
> +
> +/**
> + * free_bootmem_node - mark a page range as usable
> + * @pgdat: node the range resides on
> + * @physaddr: starting address of the range
> + * @size: size of the range in bytes
> + *
> + * Partial pages will be considered reserved and left as they are.
> + *
> + * The range must reside completely on the specified node.
> + */
> +void __init free_bootmem_node(pg_data_t *pgdat, unsigned long physaddr,
> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? unsigned long size)
> +{
> + ? ? ? kmemleak_free_part(__va(physaddr), size);
> + ? ? ? memblock_x86_free_range(physaddr, physaddr + size);
> +}
> +
> +/**
> + * free_bootmem - mark a page range as usable
> + * @addr: starting address of the range
> + * @size: size of the range in bytes
> + *
> + * Partial pages will be considered reserved and left as they are.
> + *
> + * The range must be contiguous but may span node boundaries.
> + */
> +void __init free_bootmem(unsigned long addr, unsigned long size)
> +{
> + ? ? ? kmemleak_free_part(__va(addr), size);
> + ? ? ? memblock_x86_free_range(addr, addr + size);
> +}
> +
> +/**
> + * reserve_bootmem_node - mark a page range as reserved
> + * @pgdat: node the range resides on
> + * @physaddr: starting address of the range
> + * @size: size of the range in bytes
> + * @flags: reservation flags (see linux/bootmem.h)
> + *
> + * Partial pages will be reserved.
> + *
> + * The range must reside completely on the specified node.
> + */
> +int __init reserve_bootmem_node(pg_data_t *pgdat, unsigned long physaddr,
> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?unsigned long size, int flags)
> +{
> + ? ? ? panic("no bootmem");
> + ? ? ? return 0;
> +}
> +
> +/**
> + * reserve_bootmem - mark a page range as usable
> + * @addr: starting address of the range
> + * @size: size of the range in bytes
> + * @flags: reservation flags (see linux/bootmem.h)
> + *
> + * Partial pages will be reserved.
> + *
> + * The range must be contiguous but may span node boundaries.
> + */
> +int __init reserve_bootmem(unsigned long addr, unsigned long size,
> + ? ? ? ? ? ? ? ? ? ? ? ? ? int flags)
> +{
> + ? ? ? panic("no bootmem");
> + ? ? ? return 0;
> +}
> +
> +static void * __init ___alloc_bootmem_nopanic(unsigned long size,
> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? unsigned long align,
> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? unsigned long goal,
> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? unsigned long limit)
> +{
> + ? ? ? void *ptr;
> +
> + ? ? ? if (WARN_ON_ONCE(slab_is_available()))
> + ? ? ? ? ? ? ? return kzalloc(size, GFP_NOWAIT);
> +
> +restart:
> +
> + ? ? ? ptr = __alloc_memory_core_early(MAX_NUMNODES, size, align, goal, limit);
> +
> + ? ? ? if (ptr)
> + ? ? ? ? ? ? ? return ptr;
> +
> + ? ? ? if (goal != 0) {
> + ? ? ? ? ? ? ? goal = 0;
> + ? ? ? ? ? ? ? goto restart;
> + ? ? ? }
> +
> + ? ? ? return NULL;
> +}
> +
> +/**
> + * __alloc_bootmem_nopanic - allocate boot memory without panicking
> + * @size: size of the request in bytes
> + * @align: alignment of the region
> + * @goal: preferred starting address of the region
> + *
> + * The goal is dropped if it can not be satisfied and the allocation will
> + * fall back to memory below @goal.
> + *
> + * Allocation may happen on any node in the system.
> + *
> + * Returns NULL on failure.
> + */
> +void * __init __alloc_bootmem_nopanic(unsigned long size, unsigned long align,
> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? unsigned long goal)
> +{
> + ? ? ? unsigned long limit = -1UL;
> +
> + ? ? ? return ___alloc_bootmem_nopanic(size, align, goal, limit);
> +}
> +
> +static void * __init ___alloc_bootmem(unsigned long size, unsigned long align,
> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? unsigned long goal, unsigned long limit)
> +{
> + ? ? ? void *mem = ___alloc_bootmem_nopanic(size, align, goal, limit);
> +
> + ? ? ? if (mem)
> + ? ? ? ? ? ? ? return mem;
> + ? ? ? /*
> + ? ? ? ?* Whoops, we cannot satisfy the allocation request.
> + ? ? ? ?*/
> + ? ? ? printk(KERN_ALERT "bootmem alloc of %lu bytes failed!\n", size);
> + ? ? ? panic("Out of memory");
> + ? ? ? return NULL;
> +}
> +
> +/**
> + * __alloc_bootmem - allocate boot memory
> + * @size: size of the request in bytes
> + * @align: alignment of the region
> + * @goal: preferred starting address of the region
> + *
> + * The goal is dropped if it can not be satisfied and the allocation will
> + * fall back to memory below @goal.
> + *
> + * Allocation may happen on any node in the system.
> + *
> + * The function panics if the request can not be satisfied.
> + */
> +void * __init __alloc_bootmem(unsigned long size, unsigned long align,
> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? unsigned long goal)
> +{
> + ? ? ? unsigned long limit = -1UL;
> +
> + ? ? ? return ___alloc_bootmem(size, align, goal, limit);
> +}
> +
> +/**
> + * __alloc_bootmem_node - allocate boot memory from a specific node
> + * @pgdat: node to allocate from
> + * @size: size of the request in bytes
> + * @align: alignment of the region
> + * @goal: preferred starting address of the region
> + *
> + * The goal is dropped if it can not be satisfied and the allocation will
> + * fall back to memory below @goal.
> + *
> + * Allocation may fall back to any node in the system if the specified node
> + * can not hold the requested memory.
> + *
> + * The function panics if the request can not be satisfied.
> + */
> +void * __init __alloc_bootmem_node(pg_data_t *pgdat, unsigned long size,
> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?unsigned long align, unsigned long goal)
> +{
> + ? ? ? void *ptr;
> +
> + ? ? ? if (WARN_ON_ONCE(slab_is_available()))
> + ? ? ? ? ? ? ? return kzalloc_node(size, GFP_NOWAIT, pgdat->node_id);
> +
> + ? ? ? ptr = __alloc_memory_core_early(pgdat->node_id, size, align,
> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?goal, -1ULL);
> + ? ? ? if (ptr)
> + ? ? ? ? ? ? ? return ptr;
> +
> + ? ? ? ptr = __alloc_memory_core_early(MAX_NUMNODES, size, align,
> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?goal, -1ULL);
> +
> + ? ? ? return ptr;
> +}
> +
> +void * __init __alloc_bootmem_node_high(pg_data_t *pgdat, unsigned long size,
> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?unsigned long align, unsigned long goal)
> +{
> +#ifdef MAX_DMA32_PFN
> + ? ? ? unsigned long end_pfn;
> +
> + ? ? ? if (WARN_ON_ONCE(slab_is_available()))
> + ? ? ? ? ? ? ? return kzalloc_node(size, GFP_NOWAIT, pgdat->node_id);
> +
> + ? ? ? /* update goal according ...MAX_DMA32_PFN */
> + ? ? ? end_pfn = pgdat->node_start_pfn + pgdat->node_spanned_pages;
> +
> + ? ? ? if (end_pfn > MAX_DMA32_PFN + (128 >> (20 - PAGE_SHIFT)) &&
> + ? ? ? ? ? (goal >> PAGE_SHIFT) < MAX_DMA32_PFN) {
> + ? ? ? ? ? ? ? void *ptr;
> + ? ? ? ? ? ? ? unsigned long new_goal;
> +
> + ? ? ? ? ? ? ? new_goal = MAX_DMA32_PFN << PAGE_SHIFT;
> + ? ? ? ? ? ? ? ptr = ?__alloc_memory_core_early(pgdat->node_id, size, align,
> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?new_goal, -1ULL);
> + ? ? ? ? ? ? ? if (ptr)
> + ? ? ? ? ? ? ? ? ? ? ? return ptr;
> + ? ? ? }
> +#endif
> +
> + ? ? ? return __alloc_bootmem_node(pgdat, size, align, goal);
> +
> +}
> +
> +#ifdef CONFIG_SPARSEMEM
> +/**
> + * alloc_bootmem_section - allocate boot memory from a specific section
> + * @size: size of the request in bytes
> + * @section_nr: sparse map section to allocate from
> + *
> + * Return NULL on failure.
> + */
> +void * __init alloc_bootmem_section(unsigned long size,
> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? unsigned long section_nr)
> +{
> + ? ? ? unsigned long pfn, goal, limit;
> +
> + ? ? ? pfn = section_nr_to_pfn(section_nr);
> + ? ? ? goal = pfn << PAGE_SHIFT;
> + ? ? ? limit = section_nr_to_pfn(section_nr + 1) << PAGE_SHIFT;
> +
> + ? ? ? return __alloc_memory_core_early(early_pfn_to_nid(pfn), size,
> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?SMP_CACHE_BYTES, goal, limit);
> +}
> +#endif
> +
> +void * __init __alloc_bootmem_node_nopanic(pg_data_t *pgdat, unsigned long size,
> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?unsigned long align, unsigned long goal)
> +{
> + ? ? ? void *ptr;
> +
> + ? ? ? if (WARN_ON_ONCE(slab_is_available()))
> + ? ? ? ? ? ? ? return kzalloc_node(size, GFP_NOWAIT, pgdat->node_id);
> +
> + ? ? ? ptr = ?__alloc_memory_core_early(pgdat->node_id, size, align,
> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?goal, -1ULL);
> + ? ? ? if (ptr)
> + ? ? ? ? ? ? ? return ptr;
> +
> + ? ? ? return __alloc_bootmem_nopanic(size, align, goal);
> +}
> +
> +#ifndef ARCH_LOW_ADDRESS_LIMIT
> +#define ARCH_LOW_ADDRESS_LIMIT 0xffffffffUL
> +#endif
> +
> +/**
> + * __alloc_bootmem_low - allocate low boot memory
> + * @size: size of the request in bytes
> + * @align: alignment of the region
> + * @goal: preferred starting address of the region
> + *
> + * The goal is dropped if it can not be satisfied and the allocation will
> + * fall back to memory below @goal.
> + *
> + * Allocation may happen on any node in the system.
> + *
> + * The function panics if the request can not be satisfied.
> + */
> +void * __init __alloc_bootmem_low(unsigned long size, unsigned long align,
> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? unsigned long goal)
> +{
> + ? ? ? return ___alloc_bootmem(size, align, goal, ARCH_LOW_ADDRESS_LIMIT);
> +}
> +
> +/**
> + * __alloc_bootmem_low_node - allocate low boot memory from a specific node
> + * @pgdat: node to allocate from
> + * @size: size of the request in bytes
> + * @align: alignment of the region
> + * @goal: preferred starting address of the region
> + *
> + * The goal is dropped if it can not be satisfied and the allocation will
> + * fall back to memory below @goal.
> + *
> + * Allocation may fall back to any node in the system if the specified node
> + * can not hold the requested memory.
> + *
> + * The function panics if the request can not be satisfied.
> + */
> +void * __init __alloc_bootmem_low_node(pg_data_t *pgdat, unsigned long size,
> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?unsigned long align, unsigned long goal)
> +{
> + ? ? ? void *ptr;
> +
> + ? ? ? if (WARN_ON_ONCE(slab_is_available()))
> + ? ? ? ? ? ? ? return kzalloc_node(size, GFP_NOWAIT, pgdat->node_id);
> +
> + ? ? ? ptr = __alloc_memory_core_early(pgdat->node_id, size, align,
> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? goal, ARCH_LOW_ADDRESS_LIMIT);
> + ? ? ? if (ptr)
> + ? ? ? ? ? ? ? return ptr;
> +
> + ? ? ? ptr = __alloc_memory_core_early(MAX_NUMNODES, size, align,
> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? goal, ARCH_LOW_ADDRESS_LIMIT);
> + ? ? ? return ptr;
> +}
> --
> 1.7.3.4.600.g982838b0
>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
> the body of a message to [email protected]
> More majordomo info at ?http://vger.kernel.org/majordomo-info.html
> Please read the FAQ at ?http://www.tux.org/lkml/
>
2011-02-07 (월), 10:45 -0800, Yinghai Lu:
> On Mon, Feb 7, 2011 at 7:30 AM, Namhyung Kim <[email protected]> wrote:
> > The bootmem code contained many #ifdefs in it so that it could be
> > splitted into two files for the readability. The split was quite
> > mechanical and only function need to be shared was free_bootmem_late.
> >
> > Tested on x86-64 and um which use nobootmem and bootmem respectively.
> >
> > Signed-off-by: Namhyung Kim <[email protected]>
>
>
> https://lkml.org/lkml/2010/6/16/44
> ...
>
Ah, you already made same patch before. OK, I'll drop mine then.
Thanks.
--
Regards,
Namhyung Kim