Merge branch 'kho-scratch' into next

This commit is contained in:
Mike Rapoport (Microsoft)
2026-07-29 09:32:08 +03:00
18 changed files with 632 additions and 273 deletions
+1
View File
@@ -14334,6 +14334,7 @@ S: Maintained
T: git git://git.kernel.org/pub/scm/linux/kernel/git/liveupdate/linux.git
F: Documentation/admin-guide/mm/kho.rst
F: Documentation/core-api/kho/*
F: include/asm-generic/kexec_handover.h
F: include/linux/kexec_handover.h
F: include/linux/kho/
F: include/linux/kho_block.h
+2
View File
@@ -32,6 +32,8 @@
#include <asm/setup.h> /* For COMMAND_LINE_SIZE */
#undef _SETUP
#include <asm/kexec_handover.h>
extern unsigned long get_cmd_line_ptr(void);
/* Simplified build-specific string for starting entropy. */
+1
View File
@@ -15,3 +15,4 @@ generic-y += fprobe.h
generic-y += mcs_spinlock.h
generic-y += mmzone.h
generic-y += ring_buffer.h
generic-y += kexec_handover.h
-2
View File
@@ -69,8 +69,6 @@ extern void x86_ce4100_early_setup(void);
static inline void x86_ce4100_early_setup(void) { }
#endif
#include <linux/kexec_handover.h>
#ifndef _SETUP
#include <asm/espfix.h>
+1
View File
@@ -16,6 +16,7 @@
#include <linux/init_ohci1394_dma.h>
#include <linux/initrd.h>
#include <linux/iscsi_ibft.h>
#include <linux/kexec_handover.h>
#include <linux/memblock.h>
#include <linux/panic_notifier.h>
#include <linux/pci.h>
+12
View File
@@ -0,0 +1,12 @@
/* SPDX-License-Identifier: GPL-2.0 */
#ifndef __ASM_GENERIC_KEXEC_HANDOVER_H
#define __ASM_GENERIC_KEXEC_HANDOVER_H
#include <linux/types.h>
struct kho_scratch {
phys_addr_t addr;
phys_addr_t size;
};
#endif /* __ASM_GENERIC_KEXEC_HANDOVER_H */
+26 -5
View File
@@ -5,11 +5,8 @@
#include <linux/err.h>
#include <linux/errno.h>
#include <linux/types.h>
struct kho_scratch {
phys_addr_t addr;
phys_addr_t size;
};
#include <linux/mmzone.h>
#include <asm-generic/kexec_handover.h>
struct kho_vmalloc;
@@ -37,9 +34,20 @@ void kho_remove_subtree(void *blob);
int kho_retrieve_subtree(const char *name, phys_addr_t *phys, size_t *size);
void kho_memory_init(void);
void kho_memory_init_early(void);
void kho_populate(phys_addr_t fdt_phys, u64 fdt_len, phys_addr_t scratch_phys,
u64 scratch_len);
bool kho_scratch_overlap(phys_addr_t phys, size_t size);
static inline enum migratetype kho_scratch_migratetype(unsigned long pfn,
enum migratetype mt)
{
if (kho_scratch_overlap(PFN_PHYS(pfn), pageblock_nr_pages << PAGE_SHIFT))
return MIGRATE_CMA;
return mt;
}
#else
static inline bool kho_is_enabled(void)
{
@@ -112,10 +120,23 @@ static inline int kho_retrieve_subtree(const char *name, phys_addr_t *phys,
static inline void kho_memory_init(void) { }
static inline void kho_memory_init_early(void) { }
static inline void kho_populate(phys_addr_t fdt_phys, u64 fdt_len,
phys_addr_t scratch_phys, u64 scratch_len)
{
}
static inline bool kho_scratch_overlap(phys_addr_t phys, size_t size)
{
return false;
}
static inline enum migratetype kho_scratch_migratetype(unsigned long pfn,
enum migratetype mt)
{
return mt;
}
#endif /* CONFIG_KEXEC_HANDOVER */
#endif /* LINUX_KEXEC_HANDOVER_H */
+3 -6
View File
@@ -257,11 +257,8 @@ struct kho_vmalloc {
* memory. These constants govern the indexing, sizing, and depth of the tree.
*/
enum kho_radix_consts {
/*
* The bit position of the order bit (and also the length of the
* shifted physical address) for an order-0 page.
*/
KHO_ORDER_0_LOG2 = 64 - PAGE_SHIFT,
/* Need to store the PFN, plus one bit for order. */
KHO_RADIX_KEY_WIDTH = 64 - PAGE_SHIFT + 1,
/* Size of the table in kho_radix_node, in log2 */
KHO_TABLE_SIZE_LOG2 = const_ilog2(PAGE_SIZE / sizeof(phys_addr_t)),
@@ -274,7 +271,7 @@ enum kho_radix_consts {
* and 1 bitmap level.
*/
KHO_TREE_MAX_DEPTH =
DIV_ROUND_UP(KHO_ORDER_0_LOG2 - KHO_BITMAP_SIZE_LOG2 + 1,
DIV_ROUND_UP(KHO_RADIX_KEY_WIDTH - KHO_BITMAP_SIZE_LOG2,
KHO_TABLE_SIZE_LOG2) + 1,
};
+30 -14
View File
@@ -34,37 +34,53 @@ struct kho_radix_tree {
struct mutex lock; /* protects the tree's structure and root pointer */
};
typedef int (*kho_radix_tree_walk_callback_t)(phys_addr_t phys,
unsigned int order);
/**
* struct kho_radix_walk_cb - Callbacks for KHO radix tree walk.
* @leaf: Called on each present key in the radix tree.
* @node: Called on each node of the radix tree itself. Receives the
* physical address of the page containing the node.
*
* For each callback, a return value of 0 continues the walk and a non-zero
* return value is directly returned to the caller.
*/
struct kho_radix_walk_cb {
int (*leaf)(unsigned long key, void *data);
int (*node)(phys_addr_t phys, void *data);
};
#ifdef CONFIG_KEXEC_HANDOVER
int kho_radix_add_page(struct kho_radix_tree *tree, unsigned long pfn,
unsigned int order);
void kho_radix_del_page(struct kho_radix_tree *tree, unsigned long pfn,
unsigned int order);
int kho_radix_add_key(struct kho_radix_tree *tree, unsigned long key);
void kho_radix_del_key(struct kho_radix_tree *tree, unsigned long key);
int kho_radix_walk_tree(struct kho_radix_tree *tree,
kho_radix_tree_walk_callback_t cb);
const struct kho_radix_walk_cb *cb, void *data);
int kho_radix_init_tree(struct kho_radix_tree *tree, struct kho_radix_node *root);
void kho_radix_destroy_tree(struct kho_radix_tree *tree);
#else /* #ifdef CONFIG_KEXEC_HANDOVER */
static inline int kho_radix_add_page(struct kho_radix_tree *tree, long pfn,
unsigned int order)
static inline int kho_radix_add_key(struct kho_radix_tree *tree, unsigned long key)
{
return -EOPNOTSUPP;
}
static inline void kho_radix_del_page(struct kho_radix_tree *tree,
unsigned long pfn, unsigned int order) { }
static inline void kho_radix_del_key(struct kho_radix_tree *tree,
unsigned long key) { }
static inline int kho_radix_walk_tree(struct kho_radix_tree *tree,
kho_radix_tree_walk_callback_t cb)
const struct kho_radix_walk_cb *cb, void *data)
{
return -EOPNOTSUPP;
}
static inline int kho_radix_init_tree(struct kho_radix_tree *tree,
struct kho_radix_node *root)
{
return 0;
}
static inline void kho_radix_destroy_tree(struct kho_radix_tree *tree) { }
#endif /* #ifdef CONFIG_KEXEC_HANDOVER */
#endif /* _LINUX_KHO_RADIX_TREE_H */
+4 -19
View File
@@ -51,6 +51,7 @@ extern unsigned long long max_possible_pfn;
* memory reservations yet, so we get scratch memory from the previous
* kernel that we know is good to use. It is the only memory that
* allocations may happen from in this phase.
* @MEMBLOCK_RSRV_HUGETLB: memory is reserved for hugetlb pages
*/
enum memblock_flags {
MEMBLOCK_NONE = 0x0, /* No special request */
@@ -61,6 +62,7 @@ enum memblock_flags {
MEMBLOCK_RSRV_NOINIT = 0x10, /* don't initialize struct pages */
MEMBLOCK_RSRV_KERN = 0x20, /* memory reserved for kernel use */
MEMBLOCK_KHO_SCRATCH = 0x40, /* scratch memory for kexec handover */
MEMBLOCK_RSRV_HUGETLB = 0x80, /* memory reserved for hugetlb pages */
};
/**
@@ -420,6 +422,7 @@ void *memblock_alloc_try_nid_raw(phys_addr_t size, phys_addr_t align,
void *memblock_alloc_try_nid(phys_addr_t size, phys_addr_t align,
phys_addr_t min_addr, phys_addr_t max_addr,
int nid);
void *memblock_alloc_hugetlb(phys_addr_t size, int nid, bool exact_nid);
static __always_inline void *memblock_alloc(phys_addr_t size, phys_addr_t align)
{
@@ -484,6 +487,7 @@ static inline __init_memblock bool memblock_bottom_up(void)
phys_addr_t memblock_phys_mem_size(void);
phys_addr_t memblock_reserved_size(void);
phys_addr_t memblock_reserved_kern_size(phys_addr_t limit, int nid);
phys_addr_t memblock_reserved_hugetlb_size(phys_addr_t limit, int nid);
unsigned long memblock_estimated_nr_free_pages(void);
phys_addr_t memblock_start_of_DRAM(void);
phys_addr_t memblock_end_of_DRAM(void);
@@ -613,28 +617,9 @@ static inline void memtest_report_meminfo(struct seq_file *m) { }
#ifdef CONFIG_MEMBLOCK_KHO_SCRATCH
void memblock_set_kho_scratch_only(void);
void memblock_clear_kho_scratch_only(void);
bool memblock_is_kho_scratch_memory(phys_addr_t addr);
static inline enum migratetype kho_scratch_migratetype(unsigned long pfn,
enum migratetype mt)
{
if (memblock_is_kho_scratch_memory(PFN_PHYS(pfn)))
return MIGRATE_CMA;
return mt;
}
#else
static inline void memblock_set_kho_scratch_only(void) { }
static inline void memblock_clear_kho_scratch_only(void) { }
static inline bool memblock_is_kho_scratch_memory(phys_addr_t addr)
{
return false;
}
static inline enum migratetype kho_scratch_migratetype(unsigned long pfn,
enum migratetype mt)
{
return mt;
}
#endif
#endif /* _LINUX_MEMBLOCK_H */
-1
View File
@@ -8,7 +8,6 @@ luo-y := \
luo_session.o
obj-$(CONFIG_KEXEC_HANDOVER) += kexec_handover.o
obj-$(CONFIG_KEXEC_HANDOVER_DEBUG) += kexec_handover_debug.o
obj-$(CONFIG_KEXEC_HANDOVER_DEBUGFS) += kexec_handover_debugfs.o
obj-$(CONFIG_LIVEUPDATE) += luo.o
File diff suppressed because it is too large Load Diff
-25
View File
@@ -1,25 +0,0 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* kexec_handover_debug.c - kexec handover optional debug functionality
* Copyright (C) 2025 Google LLC, Pasha Tatashin <pasha.tatashin@soleen.com>
*/
#define pr_fmt(fmt) "KHO: " fmt
#include "kexec_handover_internal.h"
bool kho_scratch_overlap(phys_addr_t phys, size_t size)
{
phys_addr_t scratch_start, scratch_end;
unsigned int i;
for (i = 0; i < kho_scratch_cnt; i++) {
scratch_start = kho_scratch[i].addr;
scratch_end = kho_scratch[i].addr + kho_scratch[i].size;
if (phys < scratch_end && (phys + size) > scratch_start)
return true;
}
return false;
}
@@ -41,13 +41,4 @@ static inline void kho_debugfs_blob_remove(struct kho_debugfs *dbg,
void *blob) { }
#endif /* CONFIG_KEXEC_HANDOVER_DEBUGFS */
#ifdef CONFIG_KEXEC_HANDOVER_DEBUG
bool kho_scratch_overlap(phys_addr_t phys, size_t size);
#else
static inline bool kho_scratch_overlap(phys_addr_t phys, size_t size)
{
return false;
}
#endif /* CONFIG_KEXEC_HANDOVER_DEBUG */
#endif /* LINUX_KEXEC_HANDOVER_INTERNAL_H */
+7 -15
View File
@@ -3033,29 +3033,21 @@ static __init void *alloc_bootmem(struct hstate *h, int nid, bool node_exact)
if (hugetlb_early_cma(h))
m = hugetlb_cma_alloc_bootmem(h, &listnode, node_exact);
else {
if (node_exact)
m = memblock_alloc_exact_nid_raw(huge_page_size(h),
huge_page_size(h), 0,
MEMBLOCK_ALLOC_ACCESSIBLE, nid);
else {
m = memblock_alloc_try_nid_raw(huge_page_size(h),
huge_page_size(h), 0,
MEMBLOCK_ALLOC_ACCESSIBLE, nid);
m = memblock_alloc_hugetlb(huge_page_size(h), nid, node_exact);
if (m) {
m->flags = 0;
m->cma = NULL;
/*
* For pre-HVO to work correctly, pages need to be on
* the list for the node they were actually allocated
* from. That node may be different in the case of
* fallback by memblock_alloc_try_nid_raw. So,
* fallback by memblock_alloc_hugetlb_bootmem. So,
* extract the actual node first.
*/
if (m)
if (!node_exact)
listnode = early_pfn_to_nid(PHYS_PFN(__pa(m)));
}
if (m) {
m->flags = 0;
m->cma = NULL;
}
}
if (m) {
+112 -34
View File
@@ -19,11 +19,9 @@
#include <linux/mutex.h>
#include <linux/string_helpers.h>
#ifdef CONFIG_KEXEC_HANDOVER
#include <linux/libfdt.h>
#include <linux/kexec_handover.h>
#include <linux/kho/abi/memblock.h>
#endif /* CONFIG_KEXEC_HANDOVER */
#include <asm/sections.h>
#include <linux/io.h>
@@ -1506,6 +1504,32 @@ int __init_memblock memblock_set_node(phys_addr_t base, phys_addr_t size,
return 0;
}
static void memblock_prep_allocation(phys_addr_t start, phys_addr_t size,
bool kmemleak_trace)
{
/*
* Skip kmemleak for those places like kasan_init() and
* early_pgtable_alloc() due to high volume.
*/
if (kmemleak_trace)
/*
* Memblock allocated blocks are never reported as
* leaks. This is because many of these blocks are
* only referred via the physical address which is
* not looked up by kmemleak.
*/
kmemleak_alloc_phys(start, size, 0);
/*
* Some Virtual Machine platforms, such as Intel TDX or AMD SEV-SNP,
* require memory to be accepted before it can be used by the
* guest.
*
* Accept the memory of the allocated buffer.
*/
accept_memory(start, size);
}
/**
* memblock_alloc_range_nid - allocate boot memory block
* @size: size of memory block to be allocated in bytes
@@ -1580,28 +1604,7 @@ again:
return 0;
done:
/*
* Skip kmemleak for those places like kasan_init() and
* early_pgtable_alloc() due to high volume.
*/
if (end != MEMBLOCK_ALLOC_NOLEAKTRACE)
/*
* Memblock allocated blocks are never reported as
* leaks. This is because many of these blocks are
* only referred via the physical address which is
* not looked up by kmemleak.
*/
kmemleak_alloc_phys(found, size, 0);
/*
* Some Virtual Machine platforms, such as Intel TDX or AMD SEV-SNP,
* require memory to be accepted before it can be used by the
* guest.
*
* Accept the memory of the allocated buffer.
*/
accept_memory(found, size);
memblock_prep_allocation(found, size, end != MEMBLOCK_ALLOC_NOLEAKTRACE);
return found;
}
@@ -1756,6 +1759,69 @@ void * __init memblock_alloc_try_nid_raw(
false);
}
/**
* memblock_alloc_hugetlb - allocate boot memory for HugeTLB pages
* @size: size of the memory to be allocated in bytes
* @nid: nid of the free memory to find, %NUMA_NO_NODE for any node
* @exact_nid: only allocate from the specified nid. If %false, the specified
* nid is tried first, and then all nodes are tried as fallback.
*
* HugeTLB pages are always aligned by their size, so the alignment matches
* @size. Since the memory is for userspace, mirrored memory is not used. The
* memory is not zeroed. Does not panic if request cannot be satisfied.
*
* Return:
* Virtual address of allocated memory block on success, %NULL on failure.
*/
void * __init memblock_alloc_hugetlb(phys_addr_t size, int nid, bool exact_nid)
{
enum memblock_flags flags = choose_memblock_flags();
phys_addr_t addr, start = 0, end = MEMBLOCK_ALLOC_ACCESSIBLE;
memblock_dbg("%s: %llu bytes, nid=%d, exact_nid=%d %pS\n", __func__,
(u64)size, nid, exact_nid, (void *)_RET_IP_);
/* Don't waste mirrored memory on HugeTLB pages. */
flags &= ~MEMBLOCK_MIRROR;
retry:
/* HugeTLB pages are always aligned by their size. */
addr = memblock_find_in_range_node(size, size, start, end, nid, flags);
if (addr)
goto found;
/* Try all nodes if allowed. */
if (numa_valid_node(nid) && !exact_nid) {
nid = NUMA_NO_NODE;
goto retry;
}
/* Found nothing... :-( */
return NULL;
found:
/*
* HugeTLB pages can be preserved with KHO and no preserved memory can
* be in scratch. So retry if found address overlaps with scratch.
*
* Scratch areas are normally not very large, so this shouldn't take too
* many retries.
*/
if (kho_scratch_overlap(addr, size)) {
if (memblock_bottom_up())
start = addr + size;
else
start = addr - size;
goto retry;
}
if (__memblock_reserve(addr, size, nid, MEMBLOCK_RSRV_KERN | MEMBLOCK_RSRV_HUGETLB))
return NULL;
memblock_prep_allocation(addr, size, true);
return phys_to_virt(addr);
}
/**
* memblock_alloc_try_nid - allocate boot memory block
* @size: size of memory block to be allocated in bytes
@@ -1825,6 +1891,28 @@ phys_addr_t __init_memblock memblock_reserved_size(void)
return memblock.reserved.total_size;
}
phys_addr_t __init_memblock memblock_reserved_hugetlb_size(phys_addr_t limit, int nid)
{
struct memblock_region *r;
phys_addr_t total = 0;
for_each_reserved_mem_region(r) {
phys_addr_t size = r->size;
if (r->base > limit)
break;
if (r->base + r->size > limit)
size = limit - r->base;
if (nid == memblock_get_region_node(r) || !numa_valid_node(nid))
if (r->flags & MEMBLOCK_RSRV_HUGETLB)
total += size;
}
return total;
}
phys_addr_t __init_memblock memblock_reserved_kern_size(phys_addr_t limit, int nid)
{
struct memblock_region *r;
@@ -2511,16 +2599,6 @@ __init void memblock_clear_kho_scratch_only(void)
{
kho_scratch_only = false;
}
bool __init_memblock memblock_is_kho_scratch_memory(phys_addr_t addr)
{
int i = memblock_search(&memblock.memory, addr);
if (i == -1)
return false;
return memblock_is_kho_scratch(&memblock.memory.regions[i]);
}
#endif
#ifdef CONFIG_KEXEC_HANDOVER
+21 -24
View File
@@ -674,15 +674,17 @@ static inline void fixup_hashdist(void)
static inline void fixup_hashdist(void) {}
#endif /* CONFIG_NUMA */
#ifdef CONFIG_ZONE_DEVICE
#if defined(CONFIG_ZONE_DEVICE) || defined(CONFIG_DEFERRED_STRUCT_PAGE_INIT)
static __meminit void pageblock_migratetype_init_range(unsigned long pfn,
unsigned long nr_pages, int migratetype)
unsigned long nr_pages, int migratetype, bool atomic)
{
const unsigned long end = pfn + nr_pages;
for (pfn = pageblock_align(pfn); pfn < end; pfn += pageblock_nr_pages) {
init_pageblock_migratetype(pfn_to_page(pfn), migratetype, false);
if (IS_ALIGNED(pfn, PAGES_PER_SECTION))
enum migratetype mt = kho_scratch_migratetype(pfn, migratetype);
init_pageblock_migratetype(pfn_to_page(pfn), mt, false);
if (!atomic && IS_ALIGNED(pfn, PAGES_PER_SECTION))
cond_resched();
}
}
@@ -932,8 +934,9 @@ void __meminit memmap_init_range(unsigned long size, int nid, unsigned long zone
* over the place during system boot.
*/
if (pageblock_aligned(pfn)) {
init_pageblock_migratetype(page, migratetype,
isolate_pageblock);
enum migratetype mt = kho_scratch_migratetype(pfn, migratetype);
init_pageblock_migratetype(page, mt, isolate_pageblock);
cond_resched();
}
pfn++;
@@ -943,8 +946,7 @@ void __meminit memmap_init_range(unsigned long size, int nid, unsigned long zone
static void __init memmap_init_zone_range(struct zone *zone,
unsigned long start_pfn,
unsigned long end_pfn,
unsigned long *hole_pfn,
enum migratetype mt)
unsigned long *hole_pfn)
{
unsigned long zone_start_pfn = zone->zone_start_pfn;
unsigned long zone_end_pfn = zone_start_pfn + zone->spanned_pages;
@@ -957,7 +959,8 @@ static void __init memmap_init_zone_range(struct zone *zone,
return;
memmap_init_range(end_pfn - start_pfn, nid, zone_id, start_pfn,
zone_end_pfn, MEMINIT_EARLY, NULL, mt, false);
zone_end_pfn, MEMINIT_EARLY, NULL, MIGRATE_MOVABLE,
false);
if (*hole_pfn < start_pfn)
init_unavailable_range(*hole_pfn, start_pfn, zone_id, nid);
@@ -973,8 +976,6 @@ static void __init memmap_init(void)
for_each_mem_pfn_range(i, MAX_NUMNODES, &start_pfn, &end_pfn, &nid) {
struct pglist_data *node = NODE_DATA(nid);
enum migratetype mt =
kho_scratch_migratetype(start_pfn, MIGRATE_MOVABLE);
for (j = 0; j < MAX_NR_ZONES; j++) {
struct zone *zone = node->node_zones + j;
@@ -983,7 +984,7 @@ static void __init memmap_init(void)
continue;
memmap_init_zone_range(zone, start_pfn, end_pfn,
&hole_pfn, mt);
&hole_pfn);
zone_id = j;
}
}
@@ -1142,7 +1143,7 @@ void __ref memmap_init_zone_device(struct zone *zone,
compound_nr_pages(pfn, altmap, pgmap));
}
pageblock_migratetype_init_range(start_pfn, nr_pages, MIGRATE_MOVABLE);
pageblock_migratetype_init_range(start_pfn, nr_pages, MIGRATE_MOVABLE, false);
pr_debug("%s initialised %lu pages in %ums\n", __func__,
nr_pages, jiffies_to_msecs(jiffies - start));
@@ -1973,7 +1974,7 @@ unsigned long __init node_map_pfn_alignment(void)
#ifdef CONFIG_DEFERRED_STRUCT_PAGE_INIT
static void __init deferred_free_pages(unsigned long pfn,
unsigned long nr_pages, enum migratetype mt)
unsigned long nr_pages)
{
struct page *page;
unsigned long i;
@@ -1981,12 +1982,12 @@ static void __init deferred_free_pages(unsigned long pfn,
if (!nr_pages)
return;
pageblock_migratetype_init_range(pfn, nr_pages, MIGRATE_MOVABLE, true);
page = pfn_to_page(pfn);
/* Free a large naturally-aligned chunk if possible */
if (nr_pages == MAX_ORDER_NR_PAGES && IS_MAX_ORDER_ALIGNED(pfn)) {
for (i = 0; i < nr_pages; i += pageblock_nr_pages)
init_pageblock_migratetype(page + i, mt, false);
__free_pages_core(page, MAX_PAGE_ORDER, MEMINIT_EARLY);
return;
}
@@ -1994,11 +1995,8 @@ static void __init deferred_free_pages(unsigned long pfn,
/* Accept chunks smaller than MAX_PAGE_ORDER upfront */
accept_memory(PFN_PHYS(pfn), nr_pages * PAGE_SIZE);
for (i = 0; i < nr_pages; i++, page++, pfn++) {
if (pageblock_aligned(pfn))
init_pageblock_migratetype(page, mt, false);
__free_pages_core(page, 0, MEMINIT_EARLY);
}
for (i = 0; i < nr_pages; i++)
__free_pages_core(page + i, 0, MEMINIT_EARLY);
}
/* Completion tracking for deferred_init_memmap() threads */
@@ -2054,8 +2052,6 @@ deferred_init_memmap_chunk(unsigned long start_pfn, unsigned long end_pfn,
for_each_free_mem_range(i, nid, 0, &start, &end, NULL) {
unsigned long spfn = PFN_UP(start);
unsigned long epfn = PFN_DOWN(end);
enum migratetype mt =
kho_scratch_migratetype(spfn, MIGRATE_MOVABLE);
if (spfn >= end_pfn)
break;
@@ -2068,7 +2064,7 @@ deferred_init_memmap_chunk(unsigned long start_pfn, unsigned long end_pfn,
unsigned long chunk_end = min(mo_pfn, epfn);
nr_pages += deferred_init_pages(zone, spfn, chunk_end);
deferred_free_pages(spfn, chunk_end - spfn, mt);
deferred_free_pages(spfn, chunk_end - spfn);
spfn = chunk_end;
@@ -2687,6 +2683,7 @@ void __init __weak mem_init(void)
void __init mm_core_init_early(void)
{
kho_memory_init_early();
hugetlb_cma_reserve();
hugetlb_bootmem_alloc();
+5
View File
@@ -66,4 +66,9 @@ static inline void init_deferred_page(unsigned long pfn, int nid)
#define __SetPageReserved(p) ((void)(p))
static inline bool kho_scratch_overlap(phys_addr_t phys, size_t size)
{
return false;
}
#endif