Skip to content

Commit

Permalink
Merge tag 'fixes-2025-04-29' of git://git.kernel.org/pub/scm/linux/ke…
Browse files Browse the repository at this point in the history
…rnel/git/rppt/memblock

Pull memblock fixes from Mike Rapoport:
 "Fixes for nid setting in memmap_init_reserved_pages():

   - pass 'size' rather than 'end' to memblock_set_node() as that
     function expects

   - fix a corner case when memblock.reserved is doubled at
     memmap_init_reserved_pages() and the newly reserved block
     won't have nid assigned"

* tag 'fixes-2025-04-29' of git://git.kernel.org/pub/scm/linux/kernel/git/rppt/memblock:
  memblock tests: add test for memblock_set_node
  mm/memblock: repeat setting reserved region nid if array is doubled
  mm/memblock: pass size instead of end to memblock_set_node()
  • Loading branch information
Linus Torvalds committed Apr 29, 2025
2 parents ca91b95 + 3b394df commit 4b5256f
Show file tree
Hide file tree
Showing 2 changed files with 113 additions and 1 deletion.
12 changes: 11 additions & 1 deletion mm/memblock.c
Original file line number Diff line number Diff line change
Expand Up @@ -2183,11 +2183,14 @@ static void __init memmap_init_reserved_pages(void)
struct memblock_region *region;
phys_addr_t start, end;
int nid;
unsigned long max_reserved;

/*
* set nid on all reserved pages and also treat struct
* pages for the NOMAP regions as PageReserved
*/
repeat:
max_reserved = memblock.reserved.max;
for_each_mem_region(region) {
nid = memblock_get_region_node(region);
start = region->base;
Expand All @@ -2196,8 +2199,15 @@ static void __init memmap_init_reserved_pages(void)
if (memblock_is_nomap(region))
reserve_bootmem_region(start, end, nid);

memblock_set_node(start, end, &memblock.reserved, nid);
memblock_set_node(start, region->size, &memblock.reserved, nid);
}
/*
* 'max' is changed means memblock.reserved has been doubled its
* array, which may result a new reserved region before current
* 'start'. Now we should repeat the procedure to set its node id.
*/
if (max_reserved != memblock.reserved.max)
goto repeat;

/*
* initialize struct pages for reserved regions that don't have
Expand Down
102 changes: 102 additions & 0 deletions tools/testing/memblock/tests/basic_api.c
Original file line number Diff line number Diff line change
Expand Up @@ -2434,6 +2434,107 @@ static int memblock_overlaps_region_checks(void)
return 0;
}

#ifdef CONFIG_NUMA
static int memblock_set_node_check(void)
{
unsigned long i, max_reserved;
struct memblock_region *rgn;
void *orig_region;

PREFIX_PUSH();

reset_memblock_regions();
memblock_allow_resize();

dummy_physical_memory_init();
memblock_add(dummy_physical_memory_base(), MEM_SIZE);
orig_region = memblock.reserved.regions;

/* Equally Split range to node 0 and 1*/
memblock_set_node(memblock_start_of_DRAM(),
memblock_phys_mem_size() / 2, &memblock.memory, 0);
memblock_set_node(memblock_start_of_DRAM() + memblock_phys_mem_size() / 2,
memblock_phys_mem_size() / 2, &memblock.memory, 1);

ASSERT_EQ(memblock.memory.cnt, 2);
rgn = &memblock.memory.regions[0];
ASSERT_EQ(rgn->base, memblock_start_of_DRAM());
ASSERT_EQ(rgn->size, memblock_phys_mem_size() / 2);
ASSERT_EQ(memblock_get_region_node(rgn), 0);
rgn = &memblock.memory.regions[1];
ASSERT_EQ(rgn->base, memblock_start_of_DRAM() + memblock_phys_mem_size() / 2);
ASSERT_EQ(rgn->size, memblock_phys_mem_size() / 2);
ASSERT_EQ(memblock_get_region_node(rgn), 1);

/* Reserve 126 regions with the last one across node boundary */
for (i = 0; i < 125; i++)
memblock_reserve(memblock_start_of_DRAM() + SZ_16 * i, SZ_8);

memblock_reserve(memblock_start_of_DRAM() + memblock_phys_mem_size() / 2 - SZ_8,
SZ_16);

/*
* Commit 61167ad5fecd ("mm: pass nid to reserve_bootmem_region()")
* do following process to set nid to each memblock.reserved region.
* But it may miss some region if memblock_set_node() double the
* array.
*
* By checking 'max', we make sure all region nid is set properly.
*/
repeat:
max_reserved = memblock.reserved.max;
for_each_mem_region(rgn) {
int nid = memblock_get_region_node(rgn);

memblock_set_node(rgn->base, rgn->size, &memblock.reserved, nid);
}
if (max_reserved != memblock.reserved.max)
goto repeat;

/* Confirm each region has valid node set */
for_each_reserved_mem_region(rgn) {
ASSERT_TRUE(numa_valid_node(memblock_get_region_node(rgn)));
if (rgn == (memblock.reserved.regions + memblock.reserved.cnt - 1))
ASSERT_EQ(1, memblock_get_region_node(rgn));
else
ASSERT_EQ(0, memblock_get_region_node(rgn));
}

dummy_physical_memory_cleanup();

/*
* The current reserved.regions is occupying a range of memory that
* allocated from dummy_physical_memory_init(). After free the memory,
* we must not use it. So restore the origin memory region to make sure
* the tests can run as normal and not affected by the double array.
*/
memblock.reserved.regions = orig_region;
memblock.reserved.cnt = INIT_MEMBLOCK_RESERVED_REGIONS;

test_pass_pop();

return 0;
}

static int memblock_set_node_checks(void)
{
prefix_reset();
prefix_push("memblock_set_node");
test_print("Running memblock_set_node tests...\n");

memblock_set_node_check();

prefix_pop();

return 0;
}
#else
static int memblock_set_node_checks(void)
{
return 0;
}
#endif

int memblock_basic_checks(void)
{
memblock_initialization_check();
Expand All @@ -2444,6 +2545,7 @@ int memblock_basic_checks(void)
memblock_bottom_up_checks();
memblock_trim_memory_checks();
memblock_overlaps_region_checks();
memblock_set_node_checks();

return 0;
}

0 comments on commit 4b5256f

Please sign in to comment.