Commit ad76bf1f authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'memblock-v6.2-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/rppt/memblock

Pull memblock updates from Mike Rapoport:
 "Extend test coverage:

   - add tests that trigger reallocation of memblock structures from
     memblock itself via memblock_double_array()

   - add tests for memblock_alloc_exact_nid_raw() that verify that
     requested node and memory range constraints are respected"

* tag 'memblock-v6.2-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/rppt/memblock:
  memblock tests: remove completed TODO item
  memblock tests: add generic NUMA tests for memblock_alloc_exact_nid_raw
  memblock tests: add bottom-up NUMA tests for memblock_alloc_exact_nid_raw
  memblock tests: add top-down NUMA tests for memblock_alloc_exact_nid_raw
  memblock tests: introduce range tests for memblock_alloc_exact_nid_raw
  memblock test: Update TODO list
  memblock test: Add test to memblock_reserve() 129th region
  memblock test: Add test to memblock_add() 129th region
parents 6f1f5cae 80c2fe02
...@@ -7,7 +7,7 @@ CFLAGS += -I. -I../../include -Wall -O2 -fsanitize=address \ ...@@ -7,7 +7,7 @@ CFLAGS += -I. -I../../include -Wall -O2 -fsanitize=address \
LDFLAGS += -fsanitize=address -fsanitize=undefined LDFLAGS += -fsanitize=address -fsanitize=undefined
TARGETS = main TARGETS = main
TEST_OFILES = tests/alloc_nid_api.o tests/alloc_helpers_api.o tests/alloc_api.o \ TEST_OFILES = tests/alloc_nid_api.o tests/alloc_helpers_api.o tests/alloc_api.o \
tests/basic_api.o tests/common.o tests/basic_api.o tests/common.o tests/alloc_exact_nid_api.o
DEP_OFILES = memblock.o lib/slab.o mmzone.o slab.o DEP_OFILES = memblock.o lib/slab.o mmzone.o slab.o
OFILES = main.o $(DEP_OFILES) $(TEST_OFILES) OFILES = main.o $(DEP_OFILES) $(TEST_OFILES)
EXTR_SRC = ../../../mm/memblock.c EXTR_SRC = ../../../mm/memblock.c
......
TODO TODO
===== =====
1. Add tests trying to memblock_add() or memblock_reserve() 129th region. 1. Add tests for memblock_alloc_node() to check if the correct NUMA node is set
This will trigger memblock_double_array(), make sure it succeeds.
*Important:* These tests require valid memory ranges, use dummy physical
memory block from common.c to implement them. It is also very
likely that the current MEM_SIZE won't be enough for these
test cases. Use realloc to adjust the size accordingly.
2. Add test cases using this functions (implement them for both directions):
+ memblock_alloc_raw()
+ memblock_alloc_exact_nid_raw()
+ memblock_alloc_try_nid_raw()
3. Add tests for memblock_alloc_node() to check if the correct NUMA node is set
for the new region for the new region
...@@ -3,6 +3,7 @@ ...@@ -3,6 +3,7 @@
#include "tests/alloc_api.h" #include "tests/alloc_api.h"
#include "tests/alloc_helpers_api.h" #include "tests/alloc_helpers_api.h"
#include "tests/alloc_nid_api.h" #include "tests/alloc_nid_api.h"
#include "tests/alloc_exact_nid_api.h"
#include "tests/common.h" #include "tests/common.h"
int main(int argc, char **argv) int main(int argc, char **argv)
...@@ -12,6 +13,7 @@ int main(int argc, char **argv) ...@@ -12,6 +13,7 @@ int main(int argc, char **argv)
memblock_alloc_checks(); memblock_alloc_checks();
memblock_alloc_helpers_checks(); memblock_alloc_helpers_checks();
memblock_alloc_nid_checks(); memblock_alloc_nid_checks();
memblock_alloc_exact_nid_checks();
return 0; return 0;
} }
This diff is collapsed.
/* SPDX-License-Identifier: GPL-2.0-or-later */
#ifndef _MEMBLOCK_ALLOC_EXACT_NID_H
#define _MEMBLOCK_ALLOC_EXACT_NID_H
#include "common.h"
int memblock_alloc_exact_nid_checks(void);
int __memblock_alloc_exact_nid_numa_checks(void);
#ifdef CONFIG_NUMA
static inline int memblock_alloc_exact_nid_numa_checks(void)
{
__memblock_alloc_exact_nid_numa_checks();
return 0;
}
#else
static inline int memblock_alloc_exact_nid_numa_checks(void)
{
return 0;
}
#endif /* CONFIG_NUMA */
#endif
...@@ -5,6 +5,7 @@ ...@@ -5,6 +5,7 @@
#include "common.h" #include "common.h"
int memblock_alloc_nid_checks(void); int memblock_alloc_nid_checks(void);
int memblock_alloc_exact_nid_range_checks(void);
int __memblock_alloc_nid_numa_checks(void); int __memblock_alloc_nid_numa_checks(void);
#ifdef CONFIG_NUMA #ifdef CONFIG_NUMA
......
...@@ -423,6 +423,98 @@ static int memblock_add_near_max_check(void) ...@@ -423,6 +423,98 @@ static int memblock_add_near_max_check(void)
return 0; return 0;
} }
/*
* A test that trying to add the 129th memory block.
* Expect to trigger memblock_double_array() to double the
* memblock.memory.max, find a new valid memory as
* memory.regions.
*/
static int memblock_add_many_check(void)
{
int i;
void *orig_region;
struct region r = {
.base = SZ_16K,
.size = SZ_16K,
};
phys_addr_t new_memory_regions_size;
phys_addr_t base, size = SZ_64;
phys_addr_t gap_size = SZ_64;
PREFIX_PUSH();
reset_memblock_regions();
memblock_allow_resize();
dummy_physical_memory_init();
/*
* We allocated enough memory by using dummy_physical_memory_init(), and
* split it into small block. First we split a large enough memory block
* as the memory region which will be choosed by memblock_double_array().
*/
base = PAGE_ALIGN(dummy_physical_memory_base());
new_memory_regions_size = PAGE_ALIGN(INIT_MEMBLOCK_REGIONS * 2 *
sizeof(struct memblock_region));
memblock_add(base, new_memory_regions_size);
/* This is the base of small memory block. */
base += new_memory_regions_size + gap_size;
orig_region = memblock.memory.regions;
for (i = 0; i < INIT_MEMBLOCK_REGIONS; i++) {
/*
* Add these small block to fulfill the memblock. We keep a
* gap between the nearby memory to avoid being merged.
*/
memblock_add(base, size);
base += size + gap_size;
ASSERT_EQ(memblock.memory.cnt, i + 2);
ASSERT_EQ(memblock.memory.total_size, new_memory_regions_size +
(i + 1) * size);
}
/*
* At there, memblock_double_array() has been succeed, check if it
* update the memory.max.
*/
ASSERT_EQ(memblock.memory.max, INIT_MEMBLOCK_REGIONS * 2);
/* memblock_double_array() will reserve the memory it used. Check it. */
ASSERT_EQ(memblock.reserved.cnt, 1);
ASSERT_EQ(memblock.reserved.total_size, new_memory_regions_size);
/*
* Now memblock_double_array() works fine. Let's check after the
* double_array(), the memblock_add() still works as normal.
*/
memblock_add(r.base, r.size);
ASSERT_EQ(memblock.memory.regions[0].base, r.base);
ASSERT_EQ(memblock.memory.regions[0].size, r.size);
ASSERT_EQ(memblock.memory.cnt, INIT_MEMBLOCK_REGIONS + 2);
ASSERT_EQ(memblock.memory.total_size, INIT_MEMBLOCK_REGIONS * size +
new_memory_regions_size +
r.size);
ASSERT_EQ(memblock.memory.max, INIT_MEMBLOCK_REGIONS * 2);
dummy_physical_memory_cleanup();
/*
* The current memory.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.memory.regions = orig_region;
memblock.memory.cnt = INIT_MEMBLOCK_REGIONS;
test_pass_pop();
return 0;
}
static int memblock_add_checks(void) static int memblock_add_checks(void)
{ {
prefix_reset(); prefix_reset();
...@@ -438,6 +530,7 @@ static int memblock_add_checks(void) ...@@ -438,6 +530,7 @@ static int memblock_add_checks(void)
memblock_add_twice_check(); memblock_add_twice_check();
memblock_add_between_check(); memblock_add_between_check();
memblock_add_near_max_check(); memblock_add_near_max_check();
memblock_add_many_check();
prefix_pop(); prefix_pop();
...@@ -799,6 +892,96 @@ static int memblock_reserve_near_max_check(void) ...@@ -799,6 +892,96 @@ static int memblock_reserve_near_max_check(void)
return 0; return 0;
} }
/*
* A test that trying to reserve the 129th memory block.
* Expect to trigger memblock_double_array() to double the
* memblock.memory.max, find a new valid memory as
* reserved.regions.
*/
static int memblock_reserve_many_check(void)
{
int i;
void *orig_region;
struct region r = {
.base = SZ_16K,
.size = SZ_16K,
};
phys_addr_t memory_base = SZ_128K;
phys_addr_t new_reserved_regions_size;
PREFIX_PUSH();
reset_memblock_regions();
memblock_allow_resize();
/* Add a valid memory region used by double_array(). */
dummy_physical_memory_init();
memblock_add(dummy_physical_memory_base(), MEM_SIZE);
for (i = 0; i < INIT_MEMBLOCK_REGIONS; i++) {
/* Reserve some fakes memory region to fulfill the memblock. */
memblock_reserve(memory_base, MEM_SIZE);
ASSERT_EQ(memblock.reserved.cnt, i + 1);
ASSERT_EQ(memblock.reserved.total_size, (i + 1) * MEM_SIZE);
/* Keep the gap so these memory region will not be merged. */
memory_base += MEM_SIZE * 2;
}
orig_region = memblock.reserved.regions;
/* This reserve the 129 memory_region, and makes it double array. */
memblock_reserve(memory_base, MEM_SIZE);
/*
* This is the memory region size used by the doubled reserved.regions,
* and it has been reserved due to it has been used. The size is used to
* calculate the total_size that the memblock.reserved have now.
*/
new_reserved_regions_size = PAGE_ALIGN((INIT_MEMBLOCK_REGIONS * 2) *
sizeof(struct memblock_region));
/*
* The double_array() will find a free memory region as the new
* reserved.regions, and the used memory region will be reserved, so
* there will be one more region exist in the reserved memblock. And the
* one more reserved region's size is new_reserved_regions_size.
*/
ASSERT_EQ(memblock.reserved.cnt, INIT_MEMBLOCK_REGIONS + 2);
ASSERT_EQ(memblock.reserved.total_size, (INIT_MEMBLOCK_REGIONS + 1) * MEM_SIZE +
new_reserved_regions_size);
ASSERT_EQ(memblock.reserved.max, INIT_MEMBLOCK_REGIONS * 2);
/*
* Now memblock_double_array() works fine. Let's check after the
* double_array(), the memblock_reserve() still works as normal.
*/
memblock_reserve(r.base, r.size);
ASSERT_EQ(memblock.reserved.regions[0].base, r.base);
ASSERT_EQ(memblock.reserved.regions[0].size, r.size);
ASSERT_EQ(memblock.reserved.cnt, INIT_MEMBLOCK_REGIONS + 3);
ASSERT_EQ(memblock.reserved.total_size, (INIT_MEMBLOCK_REGIONS + 1) * MEM_SIZE +
new_reserved_regions_size +
r.size);
ASSERT_EQ(memblock.reserved.max, INIT_MEMBLOCK_REGIONS * 2);
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_reserve_checks(void) static int memblock_reserve_checks(void)
{ {
prefix_reset(); prefix_reset();
...@@ -813,6 +996,7 @@ static int memblock_reserve_checks(void) ...@@ -813,6 +996,7 @@ static int memblock_reserve_checks(void)
memblock_reserve_twice_check(); memblock_reserve_twice_check();
memblock_reserve_between_check(); memblock_reserve_between_check();
memblock_reserve_near_max_check(); memblock_reserve_near_max_check();
memblock_reserve_many_check();
prefix_pop(); prefix_pop();
......
...@@ -5,8 +5,6 @@ ...@@ -5,8 +5,6 @@
#include <linux/memory_hotplug.h> #include <linux/memory_hotplug.h>
#include <linux/build_bug.h> #include <linux/build_bug.h>
#define INIT_MEMBLOCK_REGIONS 128
#define INIT_MEMBLOCK_RESERVED_REGIONS INIT_MEMBLOCK_REGIONS
#define PREFIXES_MAX 15 #define PREFIXES_MAX 15
#define DELIM ": " #define DELIM ": "
#define BASIS 10000 #define BASIS 10000
...@@ -115,6 +113,11 @@ void dummy_physical_memory_cleanup(void) ...@@ -115,6 +113,11 @@ void dummy_physical_memory_cleanup(void)
free(memory_block.base); free(memory_block.base);
} }
phys_addr_t dummy_physical_memory_base(void)
{
return (phys_addr_t)memory_block.base;
}
static void usage(const char *prog) static void usage(const char *prog)
{ {
BUILD_BUG_ON(ARRAY_SIZE(help_opts) != ARRAY_SIZE(long_opts) - 1); BUILD_BUG_ON(ARRAY_SIZE(help_opts) != ARRAY_SIZE(long_opts) - 1);
......
...@@ -10,14 +10,19 @@ ...@@ -10,14 +10,19 @@
#include <linux/printk.h> #include <linux/printk.h>
#include <../selftests/kselftest.h> #include <../selftests/kselftest.h>
#define MEM_SIZE SZ_16K #define MEM_SIZE SZ_32K
#define NUMA_NODES 8 #define NUMA_NODES 8
#define INIT_MEMBLOCK_REGIONS 128
#define INIT_MEMBLOCK_RESERVED_REGIONS INIT_MEMBLOCK_REGIONS
enum test_flags { enum test_flags {
/* No special request. */ /* No special request. */
TEST_F_NONE = 0x0, TEST_F_NONE = 0x0,
/* Perform raw allocations (no zeroing of memory). */ /* Perform raw allocations (no zeroing of memory). */
TEST_F_RAW = 0x1, TEST_F_RAW = 0x1,
/* Perform allocations on the exact node specified. */
TEST_F_EXACT = 0x2
}; };
/** /**
...@@ -124,6 +129,7 @@ void setup_memblock(void); ...@@ -124,6 +129,7 @@ void setup_memblock(void);
void setup_numa_memblock(const unsigned int node_fracs[]); void setup_numa_memblock(const unsigned int node_fracs[]);
void dummy_physical_memory_init(void); void dummy_physical_memory_init(void);
void dummy_physical_memory_cleanup(void); void dummy_physical_memory_cleanup(void);
phys_addr_t dummy_physical_memory_base(void);
void parse_args(int argc, char **argv); void parse_args(int argc, char **argv);
void test_fail(void); void test_fail(void);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment