diff --git a/drivers/of/fdt.c b/drivers/of/fdt.c index bfd262371fff..2eca464249be 100644 --- a/drivers/of/fdt.c +++ b/drivers/of/fdt.c @@ -504,6 +504,7 @@ void __init early_init_fdt_scan_reserved_mem(void) return; memblock_memsize_detect_hole(); + memblock_memsize_disable_tracking(); fdt_scan_reserved_mem(); fdt_reserve_elfcorehdr(); @@ -516,6 +517,7 @@ void __init early_init_fdt_scan_reserved_mem(void) memblock_reserve(base, size); memblock_memsize_record("memreserve", base, size, false, false); } + memblock_memsize_enable_tracking(); } /** diff --git a/include/linux/memblock.h b/include/linux/memblock.h index e2b3a75f8ac7..6d5dbb2fdb36 100644 --- a/include/linux/memblock.h +++ b/include/linux/memblock.h @@ -597,10 +597,16 @@ static inline void memtest_report_meminfo(struct seq_file *m) { } extern void __init_memblock memblock_memsize_record(const char *name, phys_addr_t base, phys_addr_t size, bool nomap, bool reusable); extern void __init memblock_memsize_detect_hole(void); +extern void __init memblock_memsize_enable_tracking(void); +extern void __init memblock_memsize_disable_tracking(void); +extern void memblock_memsize_mod_kernel_size(long size); #else static inline void __init_memblock memblock_memsize_record(const char *name, phys_addr_t base, phys_addr_t size, bool nomap, bool reusable) { } static inline void __init memblock_memsize_detect_hole(void) { } +static inline void __init memblock_memsize_enable_tracking(void) { } +static inline void __init memblock_memsize_disable_tracking(void) { } +static inline void memblock_memsize_mod_kernel_size(long size) { } #endif #endif /* _LINUX_MEMBLOCK_H */ diff --git a/kernel/dma/contiguous.c b/kernel/dma/contiguous.c index 83ab8b629eff..0de38657260e 100644 --- a/kernel/dma/contiguous.c +++ b/kernel/dma/contiguous.c @@ -278,10 +278,11 @@ int __init dma_contiguous_reserve_area(phys_addr_t size, phys_addr_t base, { int ret; + memblock_memsize_disable_tracking(); ret = cma_declare_contiguous(base, size, limit, 0, 0, fixed, "reserved", res_cma); if (ret) - return ret; + goto out; /* Architecture specific contiguous memory fixup. */ dma_contiguous_early_fixup(cma_get_base(*res_cma), @@ -289,7 +290,9 @@ int __init dma_contiguous_reserve_area(phys_addr_t size, phys_addr_t base, memblock_memsize_record("dma_cma", cma_get_base(*res_cma), cma_get_size(*res_cma), false, true); - return 0; +out: + memblock_memsize_enable_tracking(); + return ret; } /** diff --git a/mm/memblock.c b/mm/memblock.c index 10407f3228dc..d484a22ea4a3 100644 --- a/mm/memblock.c +++ b/mm/memblock.c @@ -134,6 +134,11 @@ struct memblock_type physmem = { }; #endif +#ifdef CONFIG_MEMBLOCK_MEMSIZE +static long memsize_kinit; +static bool memblock_memsize_tracking __initdata_memblock = true; +#endif + /* * keep a pointer to &memblock.memory in the text section to use it in * __next_mem_range() and its helpers. @@ -690,6 +695,15 @@ repeat: memblock_merge_regions(type, start_rgn, end_rgn); } done: +#ifdef CONFIG_MEMBLOCK_MEMSIZE + if (memblock_memsize_tracking) { + if (new_size && type == &memblock.reserved) { + memblock_dbg("%s: kernel %lu %+ld\n", __func__, + memsize_kinit, (unsigned long)new_size); + memsize_kinit += size; + } + } +#endif return 0; } @@ -861,6 +875,15 @@ static int __init_memblock memblock_remove_range(struct memblock_type *type, for (i = end_rgn - 1; i >= start_rgn; i--) memblock_remove_region(type, i); +#ifdef CONFIG_MEMBLOCK_MEMSIZE + if (memblock_memsize_tracking) { + if (type == &memblock.reserved) { + memblock_dbg("%s: kernel %lu %+ld\n", __func__, + memsize_kinit, (unsigned long)size); + memsize_kinit -= size; + } + } +#endif return 0; } @@ -2057,6 +2080,21 @@ struct memsize_rgn_struct { static struct memsize_rgn_struct memsize_rgn[CONFIG_MAX_MEMBLOCK_MEMSIZE] __initdata_memblock; static int memsize_rgn_count __initdata_memblock; +void __init memblock_memsize_enable_tracking(void) +{ + memblock_memsize_tracking = true; +} + +void __init memblock_memsize_disable_tracking(void) +{ + memblock_memsize_tracking = false; +} + +void memblock_memsize_mod_kernel_size(long size) +{ + memsize_kinit += size; +} + static void __init_memblock memsize_get_valid_name(char *valid_name, const char *name) { char *head, *tail, *found; @@ -2367,6 +2405,19 @@ static unsigned long __init __free_memory_core(phys_addr_t start, unsigned long end_pfn = min_t(unsigned long, PFN_DOWN(end), max_low_pfn); +#ifdef CONFIG_MEMBLOCK_MEMSIZE + unsigned long start_align_up = PFN_ALIGN(start); + unsigned long end_align_down = PFN_PHYS(end_pfn); + + if (start_pfn >= end_pfn) { + memblock_memsize_mod_kernel_size(end - start); + } else { + if (start_align_up > start) + memblock_memsize_mod_kernel_size(start_align_up - start); + if (end_pfn != max_low_pfn && end_align_down < end) + memblock_memsize_mod_kernel_size(end - end_align_down); + } +#endif if (start_pfn >= end_pfn) return 0; @@ -2471,6 +2522,8 @@ void __init memblock_free_all(void) pages = free_low_memory_core_early(); totalram_pages_add(pages); + + memblock_memsize_disable_tracking(); } /* Keep a table to reserve named memory */ @@ -2694,7 +2747,6 @@ static inline void memblock_memsize_check_size(struct memsize_rgn_struct *rgn) if (rgn->reusable || rgn->nomap) return; - /* check the first page of each 1 MB */ phy = rgn->base; end = rgn->base + rgn->size; while (phy < end) { @@ -2713,6 +2765,8 @@ static inline void memblock_memsize_check_size(struct memsize_rgn_struct *rgn) if (has_freed && (phy + SZ_64K >= end)) memblock_memsize_free(freed, end - freed); + + /* check the first page only */ phy += SZ_64K; } } @@ -2748,6 +2802,8 @@ static int memblock_memsize_show(struct seq_file *m, void *private) } seq_puts(m, "\n"); + seq_printf(m, " .kernel : %7lu KB\n", + DIV_ROUND_UP(memsize_kinit, SZ_1K)); seq_printf(m, " .unusable : %7lu KB\n", DIV_ROUND_UP(reserved, SZ_1K)); seq_printf(m, " .reusable : %7lu KB\n", diff --git a/mm/page_alloc.c b/mm/page_alloc.c index 55265a902e29..6f85a1b2801e 100644 --- a/mm/page_alloc.c +++ b/mm/page_alloc.c @@ -20,6 +20,7 @@ #include #include #include +#include #include #include #include @@ -6147,8 +6148,15 @@ unsigned long free_reserved_area(void *start, void *end, int poison, const char free_reserved_page(page); } - if (pages && s) + if (pages && s) { pr_info("Freeing %s memory: %ldK\n", s, K(pages)); + if (!strcmp(s, "initrd") || !strcmp(s, "unused kernel")) { + long size; + + size = -1 * (long)(pages << PAGE_SHIFT); + memblock_memsize_mod_kernel_size(size); + } + } return pages; }