memblock: test suite improvements

* Added verification that memblock allocations zero the allocated memory
 * Added more test cases for memblock_add(), memblock_remove(),
   memblock_reserve() and memblock_free()
 * Added tests for memblock_*_raw() family
 * Added tests for NUMA-aware allocations in memblock_alloc_try_nid() and
   memblock_alloc_try_nid_raw()
 -----BEGIN PGP SIGNATURE-----
 
 iQFMBAABCAA2FiEEeOVYVaWZL5900a/pOQOGJssO/ZEFAmNFRd8YHG1pa2UucmFw
 b3BvcnRAZ21haWwuY29tAAoJEDkDhibLDv2RD7AH/2aaJqtGakZGPtx1IBULg/AE
 P3/b0OERUjSCzyU3gH8rZ2zG9AsV6Lq/NKeq7B6zdrTJrLs+IlLaGGnbBoO3sEZn
 KWJWVQlVTyFdT8bdM0BGAAtQvehE6Km1IEoH5c7ColdcBeZKi98MuXY1BEY0KjgJ
 76Z+sWOfC+SKV2Yp8A+7anSmD95jZwU4ogr2rHjAgdXAqPQgyUYNvAeawKLapnpQ
 XjvfWwsEC54PVCw7S1k83Q1VDQ7Vo/b8SMP9/XphcVpwt/6rq3B2uJosRE91ViSe
 G8M6moNbYtj4n06nNvRNN5zq9igkbjgONCQnBj2D/r6s3SF8Tb3hcznxzORvdK4=
 =U6/l
 -----END PGP SIGNATURE-----

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

Pull memblock updates from Mike Rapoport:
 "Test suite improvements:

   - Added verification that memblock allocations zero the allocated
     memory

   - Added more test cases for memblock_add(), memblock_remove(),
     memblock_reserve() and memblock_free()

   - Added tests for memblock_*_raw() family

   - Added tests for NUMA-aware allocations in memblock_alloc_try_nid()
     and memblock_alloc_try_nid_raw()"

* tag 'memblock-v6.1-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/rppt/memblock:
  memblock tests: add generic NUMA tests for memblock_alloc_try_nid*
  memblock tests: add bottom-up NUMA tests for memblock_alloc_try_nid*
  memblock tests: add top-down NUMA tests for memblock_alloc_try_nid*
  memblock tests: add simulation of physical memory with multiple NUMA nodes
  memblock_tests: move variable declarations to single block
  memblock tests: remove 'cleared' from comment blocks
  memblock tests: add tests for memblock_trim_memory
  memblock tests: add tests for memblock_*bottom_up functions
  memblock tests: update alloc_nid_api to test memblock_alloc_try_nid_raw
  memblock tests: update alloc_api to test memblock_alloc_raw
  memblock tests: add additional tests for basic api and memblock_alloc
  memblock tests: add labels to verbose output for generic alloc tests
  memblock tests: update zeroed memory check for memblock_alloc_* tests
  memblock tests: update tests to check if memblock_alloc zeroed memory
  memblock tests: update reference to obsolete build option in comments
  memblock tests: add command line help option
This commit is contained in:
Linus Torvalds 2022-10-11 20:48:55 -07:00
commit 49da070062
8 changed files with 2663 additions and 337 deletions

View File

@ -3,7 +3,7 @@
# Simulate CONFIG_NUMA=y
ifeq ($(NUMA), 1)
CFLAGS += -D CONFIG_NUMA
CFLAGS += -D CONFIG_NUMA -D CONFIG_NODES_SHIFT=4
endif
# Use 32 bit physical addresses.

View File

@ -1,6 +1,22 @@
// SPDX-License-Identifier: GPL-2.0-or-later
#include "alloc_api.h"
static int alloc_test_flags = TEST_F_NONE;
static inline const char * const get_memblock_alloc_name(int flags)
{
if (flags & TEST_F_RAW)
return "memblock_alloc_raw";
return "memblock_alloc";
}
static inline void *run_memblock_alloc(phys_addr_t size, phys_addr_t align)
{
if (alloc_test_flags & TEST_F_RAW)
return memblock_alloc_raw(size, align);
return memblock_alloc(size, align);
}
/*
* A simple test that tries to allocate a small memory region.
* Expect to allocate an aligned region near the end of the available memory.
@ -9,19 +25,19 @@ static int alloc_top_down_simple_check(void)
{
struct memblock_region *rgn = &memblock.reserved.regions[0];
void *allocated_ptr = NULL;
PREFIX_PUSH();
phys_addr_t size = SZ_2;
phys_addr_t expected_start;
PREFIX_PUSH();
setup_memblock();
expected_start = memblock_end_of_DRAM() - SMP_CACHE_BYTES;
allocated_ptr = memblock_alloc(size, SMP_CACHE_BYTES);
allocated_ptr = run_memblock_alloc(size, SMP_CACHE_BYTES);
ASSERT_NE(allocated_ptr, NULL);
assert_mem_content(allocated_ptr, size, alloc_test_flags);
ASSERT_EQ(rgn->size, size);
ASSERT_EQ(rgn->base, expected_start);
@ -58,15 +74,13 @@ static int alloc_top_down_disjoint_check(void)
struct memblock_region *rgn2 = &memblock.reserved.regions[0];
struct region r1;
void *allocated_ptr = NULL;
PREFIX_PUSH();
phys_addr_t r2_size = SZ_16;
/* Use custom alignment */
phys_addr_t alignment = SMP_CACHE_BYTES * 2;
phys_addr_t total_size;
phys_addr_t expected_start;
PREFIX_PUSH();
setup_memblock();
r1.base = memblock_end_of_DRAM() - SZ_2;
@ -77,9 +91,11 @@ static int alloc_top_down_disjoint_check(void)
memblock_reserve(r1.base, r1.size);
allocated_ptr = memblock_alloc(r2_size, alignment);
allocated_ptr = run_memblock_alloc(r2_size, alignment);
ASSERT_NE(allocated_ptr, NULL);
assert_mem_content(allocated_ptr, r2_size, alloc_test_flags);
ASSERT_EQ(rgn1->size, r1.size);
ASSERT_EQ(rgn1->base, r1.base);
@ -108,9 +124,6 @@ static int alloc_top_down_before_check(void)
{
struct memblock_region *rgn = &memblock.reserved.regions[0];
void *allocated_ptr = NULL;
PREFIX_PUSH();
/*
* The first region ends at the aligned address to test region merging
*/
@ -118,13 +131,16 @@ static int alloc_top_down_before_check(void)
phys_addr_t r2_size = SZ_512;
phys_addr_t total_size = r1_size + r2_size;
PREFIX_PUSH();
setup_memblock();
memblock_reserve(memblock_end_of_DRAM() - total_size, r1_size);
allocated_ptr = memblock_alloc(r2_size, SMP_CACHE_BYTES);
allocated_ptr = run_memblock_alloc(r2_size, SMP_CACHE_BYTES);
ASSERT_NE(allocated_ptr, NULL);
assert_mem_content(allocated_ptr, r2_size, alloc_test_flags);
ASSERT_EQ(rgn->size, total_size);
ASSERT_EQ(rgn->base, memblock_end_of_DRAM() - total_size);
@ -152,12 +168,10 @@ static int alloc_top_down_after_check(void)
struct memblock_region *rgn = &memblock.reserved.regions[0];
struct region r1;
void *allocated_ptr = NULL;
PREFIX_PUSH();
phys_addr_t r2_size = SZ_512;
phys_addr_t total_size;
PREFIX_PUSH();
setup_memblock();
/*
@ -170,9 +184,11 @@ static int alloc_top_down_after_check(void)
memblock_reserve(r1.base, r1.size);
allocated_ptr = memblock_alloc(r2_size, SMP_CACHE_BYTES);
allocated_ptr = run_memblock_alloc(r2_size, SMP_CACHE_BYTES);
ASSERT_NE(allocated_ptr, NULL);
assert_mem_content(allocated_ptr, r2_size, alloc_test_flags);
ASSERT_EQ(rgn->size, total_size);
ASSERT_EQ(rgn->base, r1.base - r2_size);
@ -201,12 +217,10 @@ static int alloc_top_down_second_fit_check(void)
struct memblock_region *rgn = &memblock.reserved.regions[0];
struct region r1, r2;
void *allocated_ptr = NULL;
PREFIX_PUSH();
phys_addr_t r3_size = SZ_1K;
phys_addr_t total_size;
PREFIX_PUSH();
setup_memblock();
r1.base = memblock_end_of_DRAM() - SZ_512;
@ -220,9 +234,11 @@ static int alloc_top_down_second_fit_check(void)
memblock_reserve(r1.base, r1.size);
memblock_reserve(r2.base, r2.size);
allocated_ptr = memblock_alloc(r3_size, SMP_CACHE_BYTES);
allocated_ptr = run_memblock_alloc(r3_size, SMP_CACHE_BYTES);
ASSERT_NE(allocated_ptr, NULL);
assert_mem_content(allocated_ptr, r3_size, alloc_test_flags);
ASSERT_EQ(rgn->size, r2.size + r3_size);
ASSERT_EQ(rgn->base, r2.base - r3_size);
@ -250,9 +266,6 @@ static int alloc_in_between_generic_check(void)
struct memblock_region *rgn = &memblock.reserved.regions[0];
struct region r1, r2;
void *allocated_ptr = NULL;
PREFIX_PUSH();
phys_addr_t gap_size = SMP_CACHE_BYTES;
phys_addr_t r3_size = SZ_64;
/*
@ -261,6 +274,7 @@ static int alloc_in_between_generic_check(void)
phys_addr_t rgn_size = (MEM_SIZE - (2 * gap_size + r3_size)) / 2;
phys_addr_t total_size;
PREFIX_PUSH();
setup_memblock();
r1.size = rgn_size;
@ -274,9 +288,11 @@ static int alloc_in_between_generic_check(void)
memblock_reserve(r1.base, r1.size);
memblock_reserve(r2.base, r2.size);
allocated_ptr = memblock_alloc(r3_size, SMP_CACHE_BYTES);
allocated_ptr = run_memblock_alloc(r3_size, SMP_CACHE_BYTES);
ASSERT_NE(allocated_ptr, NULL);
assert_mem_content(allocated_ptr, r3_size, alloc_test_flags);
ASSERT_EQ(rgn->size, total_size);
ASSERT_EQ(rgn->base, r1.base - r2.size - r3_size);
@ -304,13 +320,11 @@ static int alloc_in_between_generic_check(void)
static int alloc_small_gaps_generic_check(void)
{
void *allocated_ptr = NULL;
PREFIX_PUSH();
phys_addr_t region_size = SZ_1K;
phys_addr_t gap_size = SZ_256;
phys_addr_t region_end;
PREFIX_PUSH();
setup_memblock();
region_end = memblock_start_of_DRAM();
@ -320,7 +334,7 @@ static int alloc_small_gaps_generic_check(void)
region_end += gap_size + region_size;
}
allocated_ptr = memblock_alloc(region_size, SMP_CACHE_BYTES);
allocated_ptr = run_memblock_alloc(region_size, SMP_CACHE_BYTES);
ASSERT_EQ(allocated_ptr, NULL);
@ -338,13 +352,12 @@ static int alloc_all_reserved_generic_check(void)
void *allocated_ptr = NULL;
PREFIX_PUSH();
setup_memblock();
/* Simulate full memory */
memblock_reserve(memblock_start_of_DRAM(), MEM_SIZE);
allocated_ptr = memblock_alloc(SZ_256, SMP_CACHE_BYTES);
allocated_ptr = run_memblock_alloc(SZ_256, SMP_CACHE_BYTES);
ASSERT_EQ(allocated_ptr, NULL);
@ -369,18 +382,16 @@ static int alloc_all_reserved_generic_check(void)
static int alloc_no_space_generic_check(void)
{
void *allocated_ptr = NULL;
PREFIX_PUSH();
setup_memblock();
phys_addr_t available_size = SZ_256;
phys_addr_t reserved_size = MEM_SIZE - available_size;
PREFIX_PUSH();
setup_memblock();
/* Simulate almost-full memory */
memblock_reserve(memblock_start_of_DRAM(), reserved_size);
allocated_ptr = memblock_alloc(SZ_1K, SMP_CACHE_BYTES);
allocated_ptr = run_memblock_alloc(SZ_1K, SMP_CACHE_BYTES);
ASSERT_EQ(allocated_ptr, NULL);
@ -404,20 +415,20 @@ static int alloc_limited_space_generic_check(void)
{
struct memblock_region *rgn = &memblock.reserved.regions[0];
void *allocated_ptr = NULL;
PREFIX_PUSH();
phys_addr_t available_size = SZ_256;
phys_addr_t reserved_size = MEM_SIZE - available_size;
PREFIX_PUSH();
setup_memblock();
/* Simulate almost-full memory */
memblock_reserve(memblock_start_of_DRAM(), reserved_size);
allocated_ptr = memblock_alloc(available_size, SMP_CACHE_BYTES);
allocated_ptr = run_memblock_alloc(available_size, SMP_CACHE_BYTES);
ASSERT_NE(allocated_ptr, NULL);
assert_mem_content(allocated_ptr, available_size, alloc_test_flags);
ASSERT_EQ(rgn->size, MEM_SIZE);
ASSERT_EQ(rgn->base, memblock_start_of_DRAM());
@ -443,7 +454,40 @@ static int alloc_no_memory_generic_check(void)
reset_memblock_regions();
allocated_ptr = memblock_alloc(SZ_1K, SMP_CACHE_BYTES);
allocated_ptr = run_memblock_alloc(SZ_1K, SMP_CACHE_BYTES);
ASSERT_EQ(allocated_ptr, NULL);
ASSERT_EQ(rgn->size, 0);
ASSERT_EQ(rgn->base, 0);
ASSERT_EQ(memblock.reserved.total_size, 0);
test_pass_pop();
return 0;
}
/*
* A test that tries to allocate a region that is larger than the total size of
* available memory (memblock.memory):
*
* +-----------------------------------+
* | new |
* +-----------------------------------+
* | |
* | |
* +---------------------------------+
*
* Expect no allocation to happen.
*/
static int alloc_too_large_generic_check(void)
{
struct memblock_region *rgn = &memblock.reserved.regions[0];
void *allocated_ptr = NULL;
PREFIX_PUSH();
setup_memblock();
allocated_ptr = run_memblock_alloc(MEM_SIZE + SZ_2, SMP_CACHE_BYTES);
ASSERT_EQ(allocated_ptr, NULL);
ASSERT_EQ(rgn->size, 0);
@ -466,12 +510,13 @@ static int alloc_bottom_up_simple_check(void)
void *allocated_ptr = NULL;
PREFIX_PUSH();
setup_memblock();
allocated_ptr = memblock_alloc(SZ_2, SMP_CACHE_BYTES);
allocated_ptr = run_memblock_alloc(SZ_2, SMP_CACHE_BYTES);
ASSERT_NE(allocated_ptr, NULL);
assert_mem_content(allocated_ptr, SZ_2, alloc_test_flags);
ASSERT_EQ(rgn->size, SZ_2);
ASSERT_EQ(rgn->base, memblock_start_of_DRAM());
@ -506,15 +551,13 @@ static int alloc_bottom_up_disjoint_check(void)
struct memblock_region *rgn2 = &memblock.reserved.regions[1];
struct region r1;
void *allocated_ptr = NULL;
PREFIX_PUSH();
phys_addr_t r2_size = SZ_16;
/* Use custom alignment */
phys_addr_t alignment = SMP_CACHE_BYTES * 2;
phys_addr_t total_size;
phys_addr_t expected_start;
PREFIX_PUSH();
setup_memblock();
r1.base = memblock_start_of_DRAM() + SZ_2;
@ -525,9 +568,10 @@ static int alloc_bottom_up_disjoint_check(void)
memblock_reserve(r1.base, r1.size);
allocated_ptr = memblock_alloc(r2_size, alignment);
allocated_ptr = run_memblock_alloc(r2_size, alignment);
ASSERT_NE(allocated_ptr, NULL);
assert_mem_content(allocated_ptr, r2_size, alloc_test_flags);
ASSERT_EQ(rgn1->size, r1.size);
ASSERT_EQ(rgn1->base, r1.base);
@ -557,20 +601,20 @@ static int alloc_bottom_up_before_check(void)
{
struct memblock_region *rgn = &memblock.reserved.regions[0];
void *allocated_ptr = NULL;
PREFIX_PUSH();
phys_addr_t r1_size = SZ_512;
phys_addr_t r2_size = SZ_128;
phys_addr_t total_size = r1_size + r2_size;
PREFIX_PUSH();
setup_memblock();
memblock_reserve(memblock_start_of_DRAM() + r1_size, r2_size);
allocated_ptr = memblock_alloc(r1_size, SMP_CACHE_BYTES);
allocated_ptr = run_memblock_alloc(r1_size, SMP_CACHE_BYTES);
ASSERT_NE(allocated_ptr, NULL);
assert_mem_content(allocated_ptr, r1_size, alloc_test_flags);
ASSERT_EQ(rgn->size, total_size);
ASSERT_EQ(rgn->base, memblock_start_of_DRAM());
@ -597,12 +641,10 @@ static int alloc_bottom_up_after_check(void)
struct memblock_region *rgn = &memblock.reserved.regions[0];
struct region r1;
void *allocated_ptr = NULL;
PREFIX_PUSH();
phys_addr_t r2_size = SZ_512;
phys_addr_t total_size;
PREFIX_PUSH();
setup_memblock();
/*
@ -615,9 +657,11 @@ static int alloc_bottom_up_after_check(void)
memblock_reserve(r1.base, r1.size);
allocated_ptr = memblock_alloc(r2_size, SMP_CACHE_BYTES);
allocated_ptr = run_memblock_alloc(r2_size, SMP_CACHE_BYTES);
ASSERT_NE(allocated_ptr, NULL);
assert_mem_content(allocated_ptr, r2_size, alloc_test_flags);
ASSERT_EQ(rgn->size, total_size);
ASSERT_EQ(rgn->base, r1.base);
@ -647,12 +691,10 @@ static int alloc_bottom_up_second_fit_check(void)
struct memblock_region *rgn = &memblock.reserved.regions[1];
struct region r1, r2;
void *allocated_ptr = NULL;
PREFIX_PUSH();
phys_addr_t r3_size = SZ_1K;
phys_addr_t total_size;
PREFIX_PUSH();
setup_memblock();
r1.base = memblock_start_of_DRAM();
@ -666,9 +708,11 @@ static int alloc_bottom_up_second_fit_check(void)
memblock_reserve(r1.base, r1.size);
memblock_reserve(r2.base, r2.size);
allocated_ptr = memblock_alloc(r3_size, SMP_CACHE_BYTES);
allocated_ptr = run_memblock_alloc(r3_size, SMP_CACHE_BYTES);
ASSERT_NE(allocated_ptr, NULL);
assert_mem_content(allocated_ptr, r3_size, alloc_test_flags);
ASSERT_EQ(rgn->size, r2.size + r3_size);
ASSERT_EQ(rgn->base, r2.base);
@ -728,10 +772,8 @@ static int alloc_after_check(void)
static int alloc_in_between_check(void)
{
test_print("\tRunning %s...\n", __func__);
memblock_set_bottom_up(false);
alloc_in_between_generic_check();
memblock_set_bottom_up(true);
alloc_in_between_generic_check();
run_top_down(alloc_in_between_generic_check);
run_bottom_up(alloc_in_between_generic_check);
return 0;
}
@ -750,10 +792,8 @@ static int alloc_second_fit_check(void)
static int alloc_small_gaps_check(void)
{
test_print("\tRunning %s...\n", __func__);
memblock_set_bottom_up(false);
alloc_small_gaps_generic_check();
memblock_set_bottom_up(true);
alloc_small_gaps_generic_check();
run_top_down(alloc_small_gaps_generic_check);
run_bottom_up(alloc_small_gaps_generic_check);
return 0;
}
@ -761,10 +801,8 @@ static int alloc_small_gaps_check(void)
static int alloc_all_reserved_check(void)
{
test_print("\tRunning %s...\n", __func__);
memblock_set_bottom_up(false);
alloc_all_reserved_generic_check();
memblock_set_bottom_up(true);
alloc_all_reserved_generic_check();
run_top_down(alloc_all_reserved_generic_check);
run_bottom_up(alloc_all_reserved_generic_check);
return 0;
}
@ -772,10 +810,8 @@ static int alloc_all_reserved_check(void)
static int alloc_no_space_check(void)
{
test_print("\tRunning %s...\n", __func__);
memblock_set_bottom_up(false);
alloc_no_space_generic_check();
memblock_set_bottom_up(true);
alloc_no_space_generic_check();
run_top_down(alloc_no_space_generic_check);
run_bottom_up(alloc_no_space_generic_check);
return 0;
}
@ -783,10 +819,8 @@ static int alloc_no_space_check(void)
static int alloc_limited_space_check(void)
{
test_print("\tRunning %s...\n", __func__);
memblock_set_bottom_up(false);
alloc_limited_space_generic_check();
memblock_set_bottom_up(true);
alloc_limited_space_generic_check();
run_top_down(alloc_limited_space_generic_check);
run_bottom_up(alloc_limited_space_generic_check);
return 0;
}
@ -794,21 +828,29 @@ static int alloc_limited_space_check(void)
static int alloc_no_memory_check(void)
{
test_print("\tRunning %s...\n", __func__);
memblock_set_bottom_up(false);
alloc_no_memory_generic_check();
memblock_set_bottom_up(true);
alloc_no_memory_generic_check();
run_top_down(alloc_no_memory_generic_check);
run_bottom_up(alloc_no_memory_generic_check);
return 0;
}
int memblock_alloc_checks(void)
static int alloc_too_large_check(void)
{
const char *func_testing = "memblock_alloc";
test_print("\tRunning %s...\n", __func__);
run_top_down(alloc_too_large_generic_check);
run_bottom_up(alloc_too_large_generic_check);
return 0;
}
static int memblock_alloc_checks_internal(int flags)
{
const char *func = get_memblock_alloc_name(flags);
alloc_test_flags = flags;
prefix_reset();
prefix_push(func_testing);
test_print("Running %s tests...\n", func_testing);
prefix_push(func);
test_print("Running %s tests...\n", func);
reset_memblock_attributes();
dummy_physical_memory_init();
@ -824,6 +866,7 @@ int memblock_alloc_checks(void)
alloc_no_space_check();
alloc_limited_space_check();
alloc_no_memory_check();
alloc_too_large_check();
dummy_physical_memory_cleanup();
@ -831,3 +874,11 @@ int memblock_alloc_checks(void)
return 0;
}
int memblock_alloc_checks(void)
{
memblock_alloc_checks_internal(TEST_F_NONE);
memblock_alloc_checks_internal(TEST_F_RAW);
return 0;
}

View File

@ -19,22 +19,18 @@ static int alloc_from_simple_generic_check(void)
{
struct memblock_region *rgn = &memblock.reserved.regions[0];
void *allocated_ptr = NULL;
char *b;
PREFIX_PUSH();
phys_addr_t size = SZ_16;
phys_addr_t min_addr;
PREFIX_PUSH();
setup_memblock();
min_addr = memblock_end_of_DRAM() - SMP_CACHE_BYTES;
allocated_ptr = memblock_alloc_from(size, SMP_CACHE_BYTES, min_addr);
b = (char *)allocated_ptr;
ASSERT_NE(allocated_ptr, NULL);
ASSERT_EQ(*b, 0);
ASSERT_MEM_EQ(allocated_ptr, 0, size);
ASSERT_EQ(rgn->size, size);
ASSERT_EQ(rgn->base, min_addr);
@ -66,23 +62,19 @@ static int alloc_from_misaligned_generic_check(void)
{
struct memblock_region *rgn = &memblock.reserved.regions[0];
void *allocated_ptr = NULL;
char *b;
PREFIX_PUSH();
phys_addr_t size = SZ_32;
phys_addr_t min_addr;
PREFIX_PUSH();
setup_memblock();
/* A misaligned address */
min_addr = memblock_end_of_DRAM() - (SMP_CACHE_BYTES * 2 - 1);
allocated_ptr = memblock_alloc_from(size, SMP_CACHE_BYTES, min_addr);
b = (char *)allocated_ptr;
ASSERT_NE(allocated_ptr, NULL);
ASSERT_EQ(*b, 0);
ASSERT_MEM_EQ(allocated_ptr, 0, size);
ASSERT_EQ(rgn->size, size);
ASSERT_EQ(rgn->base, memblock_end_of_DRAM() - SMP_CACHE_BYTES);
@ -117,12 +109,10 @@ static int alloc_from_top_down_high_addr_check(void)
{
struct memblock_region *rgn = &memblock.reserved.regions[0];
void *allocated_ptr = NULL;
PREFIX_PUSH();
phys_addr_t size = SZ_32;
phys_addr_t min_addr;
PREFIX_PUSH();
setup_memblock();
/* The address is too close to the end of the memory */
@ -162,14 +152,12 @@ static int alloc_from_top_down_no_space_above_check(void)
{
struct memblock_region *rgn = &memblock.reserved.regions[0];
void *allocated_ptr = NULL;
PREFIX_PUSH();
phys_addr_t r1_size = SZ_64;
phys_addr_t r2_size = SZ_2;
phys_addr_t total_size = r1_size + r2_size;
phys_addr_t min_addr;
PREFIX_PUSH();
setup_memblock();
min_addr = memblock_end_of_DRAM() - SMP_CACHE_BYTES * 2;
@ -201,13 +189,11 @@ static int alloc_from_top_down_min_addr_cap_check(void)
{
struct memblock_region *rgn = &memblock.reserved.regions[0];
void *allocated_ptr = NULL;
PREFIX_PUSH();
phys_addr_t r1_size = SZ_64;
phys_addr_t min_addr;
phys_addr_t start_addr;
PREFIX_PUSH();
setup_memblock();
start_addr = (phys_addr_t)memblock_start_of_DRAM();
@ -249,12 +235,10 @@ static int alloc_from_bottom_up_high_addr_check(void)
{
struct memblock_region *rgn = &memblock.reserved.regions[0];
void *allocated_ptr = NULL;
PREFIX_PUSH();
phys_addr_t size = SZ_32;
phys_addr_t min_addr;
PREFIX_PUSH();
setup_memblock();
/* The address is too close to the end of the memory */
@ -293,13 +277,11 @@ static int alloc_from_bottom_up_no_space_above_check(void)
{
struct memblock_region *rgn = &memblock.reserved.regions[0];
void *allocated_ptr = NULL;
PREFIX_PUSH();
phys_addr_t r1_size = SZ_64;
phys_addr_t min_addr;
phys_addr_t r2_size;
PREFIX_PUSH();
setup_memblock();
min_addr = memblock_start_of_DRAM() + SZ_128;
@ -331,13 +313,11 @@ static int alloc_from_bottom_up_min_addr_cap_check(void)
{
struct memblock_region *rgn = &memblock.reserved.regions[0];
void *allocated_ptr = NULL;
PREFIX_PUSH();
phys_addr_t r1_size = SZ_64;
phys_addr_t min_addr;
phys_addr_t start_addr;
PREFIX_PUSH();
setup_memblock();
start_addr = (phys_addr_t)memblock_start_of_DRAM();
@ -361,10 +341,8 @@ static int alloc_from_bottom_up_min_addr_cap_check(void)
static int alloc_from_simple_check(void)
{
test_print("\tRunning %s...\n", __func__);
memblock_set_bottom_up(false);
alloc_from_simple_generic_check();
memblock_set_bottom_up(true);
alloc_from_simple_generic_check();
run_top_down(alloc_from_simple_generic_check);
run_bottom_up(alloc_from_simple_generic_check);
return 0;
}
@ -372,10 +350,8 @@ static int alloc_from_simple_check(void)
static int alloc_from_misaligned_check(void)
{
test_print("\tRunning %s...\n", __func__);
memblock_set_bottom_up(false);
alloc_from_misaligned_generic_check();
memblock_set_bottom_up(true);
alloc_from_misaligned_generic_check();
run_top_down(alloc_from_misaligned_generic_check);
run_bottom_up(alloc_from_misaligned_generic_check);
return 0;
}

File diff suppressed because it is too large Load Diff

View File

@ -5,5 +5,21 @@
#include "common.h"
int memblock_alloc_nid_checks(void);
int __memblock_alloc_nid_numa_checks(void);
#ifdef CONFIG_NUMA
static inline int memblock_alloc_nid_numa_checks(void)
{
__memblock_alloc_nid_numa_checks();
return 0;
}
#else
static inline int memblock_alloc_nid_numa_checks(void)
{
return 0;
}
#endif /* CONFIG_NUMA */
#endif

View File

@ -8,6 +8,7 @@
#define FUNC_RESERVE "memblock_reserve"
#define FUNC_REMOVE "memblock_remove"
#define FUNC_FREE "memblock_free"
#define FUNC_TRIM "memblock_trim_memory"
static int memblock_initialization_check(void)
{
@ -326,6 +327,102 @@ static int memblock_add_twice_check(void)
return 0;
}
/*
* A test that tries to add two memory blocks that don't overlap with one
* another and then add a third memory block in the space between the first two:
*
* | +--------+--------+--------+ |
* | | r1 | r3 | r2 | |
* +--------+--------+--------+--------+--+
*
* Expect to merge the three entries into one region that starts at r1.base
* and has size of r1.size + r2.size + r3.size. The region counter and total
* size of the available memory are updated.
*/
static int memblock_add_between_check(void)
{
struct memblock_region *rgn;
phys_addr_t total_size;
rgn = &memblock.memory.regions[0];
struct region r1 = {
.base = SZ_1G,
.size = SZ_8K
};
struct region r2 = {
.base = SZ_1G + SZ_16K,
.size = SZ_8K
};
struct region r3 = {
.base = SZ_1G + SZ_8K,
.size = SZ_8K
};
PREFIX_PUSH();
total_size = r1.size + r2.size + r3.size;
reset_memblock_regions();
memblock_add(r1.base, r1.size);
memblock_add(r2.base, r2.size);
memblock_add(r3.base, r3.size);
ASSERT_EQ(rgn->base, r1.base);
ASSERT_EQ(rgn->size, total_size);
ASSERT_EQ(memblock.memory.cnt, 1);
ASSERT_EQ(memblock.memory.total_size, total_size);
test_pass_pop();
return 0;
}
/*
* A simple test that tries to add a memory block r when r extends past
* PHYS_ADDR_MAX:
*
* +--------+
* | r |
* +--------+
* | +----+
* | | rgn|
* +----------------------------+----+
*
* Expect to add a memory block of size PHYS_ADDR_MAX - r.base. Expect the
* total size of available memory and the counter to be updated.
*/
static int memblock_add_near_max_check(void)
{
struct memblock_region *rgn;
phys_addr_t total_size;
rgn = &memblock.memory.regions[0];
struct region r = {
.base = PHYS_ADDR_MAX - SZ_1M,
.size = SZ_2M
};
PREFIX_PUSH();
total_size = PHYS_ADDR_MAX - r.base;
reset_memblock_regions();
memblock_add(r.base, r.size);
ASSERT_EQ(rgn->base, r.base);
ASSERT_EQ(rgn->size, total_size);
ASSERT_EQ(memblock.memory.cnt, 1);
ASSERT_EQ(memblock.memory.total_size, total_size);
test_pass_pop();
return 0;
}
static int memblock_add_checks(void)
{
prefix_reset();
@ -339,6 +436,8 @@ static int memblock_add_checks(void)
memblock_add_overlap_bottom_check();
memblock_add_within_check();
memblock_add_twice_check();
memblock_add_between_check();
memblock_add_near_max_check();
prefix_pop();
@ -604,6 +703,102 @@ static int memblock_reserve_twice_check(void)
return 0;
}
/*
* A test that tries to mark two memory blocks that don't overlap as reserved
* and then reserve a third memory block in the space between the first two:
*
* | +--------+--------+--------+ |
* | | r1 | r3 | r2 | |
* +--------+--------+--------+--------+--+
*
* Expect to merge the three entries into one reserved region that starts at
* r1.base and has size of r1.size + r2.size + r3.size. The region counter and
* total for memblock.reserved are updated.
*/
static int memblock_reserve_between_check(void)
{
struct memblock_region *rgn;
phys_addr_t total_size;
rgn = &memblock.reserved.regions[0];
struct region r1 = {
.base = SZ_1G,
.size = SZ_8K
};
struct region r2 = {
.base = SZ_1G + SZ_16K,
.size = SZ_8K
};
struct region r3 = {
.base = SZ_1G + SZ_8K,
.size = SZ_8K
};
PREFIX_PUSH();
total_size = r1.size + r2.size + r3.size;
reset_memblock_regions();
memblock_reserve(r1.base, r1.size);
memblock_reserve(r2.base, r2.size);
memblock_reserve(r3.base, r3.size);
ASSERT_EQ(rgn->base, r1.base);
ASSERT_EQ(rgn->size, total_size);
ASSERT_EQ(memblock.reserved.cnt, 1);
ASSERT_EQ(memblock.reserved.total_size, total_size);
test_pass_pop();
return 0;
}
/*
* A simple test that tries to reserve a memory block r when r extends past
* PHYS_ADDR_MAX:
*
* +--------+
* | r |
* +--------+
* | +----+
* | | rgn|
* +----------------------------+----+
*
* Expect to reserve a memory block of size PHYS_ADDR_MAX - r.base. Expect the
* total size of reserved memory and the counter to be updated.
*/
static int memblock_reserve_near_max_check(void)
{
struct memblock_region *rgn;
phys_addr_t total_size;
rgn = &memblock.reserved.regions[0];
struct region r = {
.base = PHYS_ADDR_MAX - SZ_1M,
.size = SZ_2M
};
PREFIX_PUSH();
total_size = PHYS_ADDR_MAX - r.base;
reset_memblock_regions();
memblock_reserve(r.base, r.size);
ASSERT_EQ(rgn->base, r.base);
ASSERT_EQ(rgn->size, total_size);
ASSERT_EQ(memblock.reserved.cnt, 1);
ASSERT_EQ(memblock.reserved.total_size, total_size);
test_pass_pop();
return 0;
}
static int memblock_reserve_checks(void)
{
prefix_reset();
@ -616,6 +811,8 @@ static int memblock_reserve_checks(void)
memblock_reserve_overlap_bottom_check();
memblock_reserve_within_check();
memblock_reserve_twice_check();
memblock_reserve_between_check();
memblock_reserve_near_max_check();
prefix_pop();
@ -887,6 +1084,155 @@ static int memblock_remove_within_check(void)
return 0;
}
/*
* A simple test that tries to remove a region r1 from the array of
* available memory regions when r1 is the only available region.
* Expect to add a memory block r1 and then remove r1 so that a dummy
* region is added. The region counter stays the same, and the total size
* is updated.
*/
static int memblock_remove_only_region_check(void)
{
struct memblock_region *rgn;
rgn = &memblock.memory.regions[0];
struct region r1 = {
.base = SZ_2K,
.size = SZ_4K
};
PREFIX_PUSH();
reset_memblock_regions();
memblock_add(r1.base, r1.size);
memblock_remove(r1.base, r1.size);
ASSERT_EQ(rgn->base, 0);
ASSERT_EQ(rgn->size, 0);
ASSERT_EQ(memblock.memory.cnt, 1);
ASSERT_EQ(memblock.memory.total_size, 0);
test_pass_pop();
return 0;
}
/*
* A simple test that tries remove a region r2 from the array of available
* memory regions when r2 extends past PHYS_ADDR_MAX:
*
* +--------+
* | r2 |
* +--------+
* | +---+....+
* | |rgn| |
* +------------------------+---+----+
*
* Expect that only the portion between PHYS_ADDR_MAX and r2.base is removed.
* Expect the total size of available memory to be updated and the counter to
* not be updated.
*/
static int memblock_remove_near_max_check(void)
{
struct memblock_region *rgn;
phys_addr_t total_size;
rgn = &memblock.memory.regions[0];
struct region r1 = {
.base = PHYS_ADDR_MAX - SZ_2M,
.size = SZ_2M
};
struct region r2 = {
.base = PHYS_ADDR_MAX - SZ_1M,
.size = SZ_2M
};
PREFIX_PUSH();
total_size = r1.size - (PHYS_ADDR_MAX - r2.base);
reset_memblock_regions();
memblock_add(r1.base, r1.size);
memblock_remove(r2.base, r2.size);
ASSERT_EQ(rgn->base, r1.base);
ASSERT_EQ(rgn->size, total_size);
ASSERT_EQ(memblock.memory.cnt, 1);
ASSERT_EQ(memblock.memory.total_size, total_size);
test_pass_pop();
return 0;
}
/*
* A test that tries to remove a region r3 that overlaps with two existing
* regions r1 and r2:
*
* +----------------+
* | r3 |
* +----------------+
* | +----+..... ........+--------+
* | | |r1 : : |r2 | |
* +----+----+----+---+-------+--------+-----+
*
* Expect that only the intersections of r1 with r3 and r2 with r3 are removed
* from the available memory pool. Expect the total size of available memory to
* be updated and the counter to not be updated.
*/
static int memblock_remove_overlap_two_check(void)
{
struct memblock_region *rgn1, *rgn2;
phys_addr_t new_r1_size, new_r2_size, r2_end, r3_end, total_size;
rgn1 = &memblock.memory.regions[0];
rgn2 = &memblock.memory.regions[1];
struct region r1 = {
.base = SZ_16M,
.size = SZ_32M
};
struct region r2 = {
.base = SZ_64M,
.size = SZ_64M
};
struct region r3 = {
.base = SZ_32M,
.size = SZ_64M
};
PREFIX_PUSH();
r2_end = r2.base + r2.size;
r3_end = r3.base + r3.size;
new_r1_size = r3.base - r1.base;
new_r2_size = r2_end - r3_end;
total_size = new_r1_size + new_r2_size;
reset_memblock_regions();
memblock_add(r1.base, r1.size);
memblock_add(r2.base, r2.size);
memblock_remove(r3.base, r3.size);
ASSERT_EQ(rgn1->base, r1.base);
ASSERT_EQ(rgn1->size, new_r1_size);
ASSERT_EQ(rgn2->base, r3_end);
ASSERT_EQ(rgn2->size, new_r2_size);
ASSERT_EQ(memblock.memory.cnt, 2);
ASSERT_EQ(memblock.memory.total_size, total_size);
test_pass_pop();
return 0;
}
static int memblock_remove_checks(void)
{
prefix_reset();
@ -898,6 +1244,9 @@ static int memblock_remove_checks(void)
memblock_remove_overlap_top_check();
memblock_remove_overlap_bottom_check();
memblock_remove_within_check();
memblock_remove_only_region_check();
memblock_remove_near_max_check();
memblock_remove_overlap_two_check();
prefix_pop();
@ -1163,6 +1512,154 @@ static int memblock_free_within_check(void)
return 0;
}
/*
* A simple test that tries to free a memory block r1 that was marked
* earlier as reserved when r1 is the only available region.
* Expect to reserve a memory block r1 and then free r1 so that r1 is
* overwritten with a dummy region. The region counter stays the same,
* and the total size is updated.
*/
static int memblock_free_only_region_check(void)
{
struct memblock_region *rgn;
rgn = &memblock.reserved.regions[0];
struct region r1 = {
.base = SZ_2K,
.size = SZ_4K
};
PREFIX_PUSH();
reset_memblock_regions();
memblock_reserve(r1.base, r1.size);
memblock_free((void *)r1.base, r1.size);
ASSERT_EQ(rgn->base, 0);
ASSERT_EQ(rgn->size, 0);
ASSERT_EQ(memblock.reserved.cnt, 1);
ASSERT_EQ(memblock.reserved.total_size, 0);
test_pass_pop();
return 0;
}
/*
* A simple test that tries free a region r2 when r2 extends past PHYS_ADDR_MAX:
*
* +--------+
* | r2 |
* +--------+
* | +---+....+
* | |rgn| |
* +------------------------+---+----+
*
* Expect that only the portion between PHYS_ADDR_MAX and r2.base is freed.
* Expect the total size of reserved memory to be updated and the counter to
* not be updated.
*/
static int memblock_free_near_max_check(void)
{
struct memblock_region *rgn;
phys_addr_t total_size;
rgn = &memblock.reserved.regions[0];
struct region r1 = {
.base = PHYS_ADDR_MAX - SZ_2M,
.size = SZ_2M
};
struct region r2 = {
.base = PHYS_ADDR_MAX - SZ_1M,
.size = SZ_2M
};
PREFIX_PUSH();
total_size = r1.size - (PHYS_ADDR_MAX - r2.base);
reset_memblock_regions();
memblock_reserve(r1.base, r1.size);
memblock_free((void *)r2.base, r2.size);
ASSERT_EQ(rgn->base, r1.base);
ASSERT_EQ(rgn->size, total_size);
ASSERT_EQ(memblock.reserved.cnt, 1);
ASSERT_EQ(memblock.reserved.total_size, total_size);
test_pass_pop();
return 0;
}
/*
* A test that tries to free a reserved region r3 that overlaps with two
* existing reserved regions r1 and r2:
*
* +----------------+
* | r3 |
* +----------------+
* | +----+..... ........+--------+
* | | |r1 : : |r2 | |
* +----+----+----+---+-------+--------+-----+
*
* Expect that only the intersections of r1 with r3 and r2 with r3 are freed
* from the collection of reserved memory. Expect the total size of reserved
* memory to be updated and the counter to not be updated.
*/
static int memblock_free_overlap_two_check(void)
{
struct memblock_region *rgn1, *rgn2;
phys_addr_t new_r1_size, new_r2_size, r2_end, r3_end, total_size;
rgn1 = &memblock.reserved.regions[0];
rgn2 = &memblock.reserved.regions[1];
struct region r1 = {
.base = SZ_16M,
.size = SZ_32M
};
struct region r2 = {
.base = SZ_64M,
.size = SZ_64M
};
struct region r3 = {
.base = SZ_32M,
.size = SZ_64M
};
PREFIX_PUSH();
r2_end = r2.base + r2.size;
r3_end = r3.base + r3.size;
new_r1_size = r3.base - r1.base;
new_r2_size = r2_end - r3_end;
total_size = new_r1_size + new_r2_size;
reset_memblock_regions();
memblock_reserve(r1.base, r1.size);
memblock_reserve(r2.base, r2.size);
memblock_free((void *)r3.base, r3.size);
ASSERT_EQ(rgn1->base, r1.base);
ASSERT_EQ(rgn1->size, new_r1_size);
ASSERT_EQ(rgn2->base, r3_end);
ASSERT_EQ(rgn2->size, new_r2_size);
ASSERT_EQ(memblock.reserved.cnt, 2);
ASSERT_EQ(memblock.reserved.total_size, total_size);
test_pass_pop();
return 0;
}
static int memblock_free_checks(void)
{
prefix_reset();
@ -1174,6 +1671,274 @@ static int memblock_free_checks(void)
memblock_free_overlap_top_check();
memblock_free_overlap_bottom_check();
memblock_free_within_check();
memblock_free_only_region_check();
memblock_free_near_max_check();
memblock_free_overlap_two_check();
prefix_pop();
return 0;
}
static int memblock_set_bottom_up_check(void)
{
prefix_push("memblock_set_bottom_up");
memblock_set_bottom_up(false);
ASSERT_EQ(memblock.bottom_up, false);
memblock_set_bottom_up(true);
ASSERT_EQ(memblock.bottom_up, true);
reset_memblock_attributes();
test_pass_pop();
return 0;
}
static int memblock_bottom_up_check(void)
{
prefix_push("memblock_bottom_up");
memblock_set_bottom_up(false);
ASSERT_EQ(memblock_bottom_up(), memblock.bottom_up);
ASSERT_EQ(memblock_bottom_up(), false);
memblock_set_bottom_up(true);
ASSERT_EQ(memblock_bottom_up(), memblock.bottom_up);
ASSERT_EQ(memblock_bottom_up(), true);
reset_memblock_attributes();
test_pass_pop();
return 0;
}
static int memblock_bottom_up_checks(void)
{
test_print("Running memblock_*bottom_up tests...\n");
prefix_reset();
memblock_set_bottom_up_check();
prefix_reset();
memblock_bottom_up_check();
return 0;
}
/*
* A test that tries to trim memory when both ends of the memory region are
* aligned. Expect that the memory will not be trimmed. Expect the counter to
* not be updated.
*/
static int memblock_trim_memory_aligned_check(void)
{
struct memblock_region *rgn;
const phys_addr_t alignment = SMP_CACHE_BYTES;
rgn = &memblock.memory.regions[0];
struct region r = {
.base = alignment,
.size = alignment * 4
};
PREFIX_PUSH();
reset_memblock_regions();
memblock_add(r.base, r.size);
memblock_trim_memory(alignment);
ASSERT_EQ(rgn->base, r.base);
ASSERT_EQ(rgn->size, r.size);
ASSERT_EQ(memblock.memory.cnt, 1);
test_pass_pop();
return 0;
}
/*
* A test that tries to trim memory when there are two available regions, r1 and
* r2. Region r1 is aligned on both ends and region r2 is unaligned on one end
* and smaller than the alignment:
*
* alignment
* |--------|
* | +-----------------+ +------+ |
* | | r1 | | r2 | |
* +--------+-----------------+--------+------+---+
* ^ ^ ^ ^ ^
* |________|________|________| |
* | Unaligned address
* Aligned addresses
*
* Expect that r1 will not be trimmed and r2 will be removed. Expect the
* counter to be updated.
*/
static int memblock_trim_memory_too_small_check(void)
{
struct memblock_region *rgn;
const phys_addr_t alignment = SMP_CACHE_BYTES;
rgn = &memblock.memory.regions[0];
struct region r1 = {
.base = alignment,
.size = alignment * 2
};
struct region r2 = {
.base = alignment * 4,
.size = alignment - SZ_2
};
PREFIX_PUSH();
reset_memblock_regions();
memblock_add(r1.base, r1.size);
memblock_add(r2.base, r2.size);
memblock_trim_memory(alignment);
ASSERT_EQ(rgn->base, r1.base);
ASSERT_EQ(rgn->size, r1.size);
ASSERT_EQ(memblock.memory.cnt, 1);
test_pass_pop();
return 0;
}
/*
* A test that tries to trim memory when there are two available regions, r1 and
* r2. Region r1 is aligned on both ends and region r2 is unaligned at the base
* and aligned at the end:
*
* Unaligned address
* |
* v
* | +-----------------+ +---------------+ |
* | | r1 | | r2 | |
* +--------+-----------------+----------+---------------+---+
* ^ ^ ^ ^ ^ ^
* |________|________|________|________|________|
* |
* Aligned addresses
*
* Expect that r1 will not be trimmed and r2 will be trimmed at the base.
* Expect the counter to not be updated.
*/
static int memblock_trim_memory_unaligned_base_check(void)
{
struct memblock_region *rgn1, *rgn2;
const phys_addr_t alignment = SMP_CACHE_BYTES;
phys_addr_t offset = SZ_2;
phys_addr_t new_r2_base, new_r2_size;
rgn1 = &memblock.memory.regions[0];
rgn2 = &memblock.memory.regions[1];
struct region r1 = {
.base = alignment,
.size = alignment * 2
};
struct region r2 = {
.base = alignment * 4 + offset,
.size = alignment * 2 - offset
};
PREFIX_PUSH();
new_r2_base = r2.base + (alignment - offset);
new_r2_size = r2.size - (alignment - offset);
reset_memblock_regions();
memblock_add(r1.base, r1.size);
memblock_add(r2.base, r2.size);
memblock_trim_memory(alignment);
ASSERT_EQ(rgn1->base, r1.base);
ASSERT_EQ(rgn1->size, r1.size);
ASSERT_EQ(rgn2->base, new_r2_base);
ASSERT_EQ(rgn2->size, new_r2_size);
ASSERT_EQ(memblock.memory.cnt, 2);
test_pass_pop();
return 0;
}
/*
* A test that tries to trim memory when there are two available regions, r1 and
* r2. Region r1 is aligned on both ends and region r2 is aligned at the base
* and unaligned at the end:
*
* Unaligned address
* |
* v
* | +-----------------+ +---------------+ |
* | | r1 | | r2 | |
* +--------+-----------------+--------+---------------+---+
* ^ ^ ^ ^ ^ ^
* |________|________|________|________|________|
* |
* Aligned addresses
*
* Expect that r1 will not be trimmed and r2 will be trimmed at the end.
* Expect the counter to not be updated.
*/
static int memblock_trim_memory_unaligned_end_check(void)
{
struct memblock_region *rgn1, *rgn2;
const phys_addr_t alignment = SMP_CACHE_BYTES;
phys_addr_t offset = SZ_2;
phys_addr_t new_r2_size;
rgn1 = &memblock.memory.regions[0];
rgn2 = &memblock.memory.regions[1];
struct region r1 = {
.base = alignment,
.size = alignment * 2
};
struct region r2 = {
.base = alignment * 4,
.size = alignment * 2 - offset
};
PREFIX_PUSH();
new_r2_size = r2.size - (alignment - offset);
reset_memblock_regions();
memblock_add(r1.base, r1.size);
memblock_add(r2.base, r2.size);
memblock_trim_memory(alignment);
ASSERT_EQ(rgn1->base, r1.base);
ASSERT_EQ(rgn1->size, r1.size);
ASSERT_EQ(rgn2->base, r2.base);
ASSERT_EQ(rgn2->size, new_r2_size);
ASSERT_EQ(memblock.memory.cnt, 2);
test_pass_pop();
return 0;
}
static int memblock_trim_memory_checks(void)
{
prefix_reset();
prefix_push(FUNC_TRIM);
test_print("Running %s tests...\n", FUNC_TRIM);
memblock_trim_memory_aligned_check();
memblock_trim_memory_too_small_check();
memblock_trim_memory_unaligned_base_check();
memblock_trim_memory_unaligned_end_check();
prefix_pop();
@ -1187,6 +1952,8 @@ int memblock_basic_checks(void)
memblock_reserve_checks();
memblock_remove_checks();
memblock_free_checks();
memblock_bottom_up_checks();
memblock_trim_memory_checks();
return 0;
}

View File

@ -9,19 +9,22 @@
#define INIT_MEMBLOCK_RESERVED_REGIONS INIT_MEMBLOCK_REGIONS
#define PREFIXES_MAX 15
#define DELIM ": "
#define BASIS 10000
static struct test_memory memory_block;
static const char __maybe_unused *prefixes[PREFIXES_MAX];
static int __maybe_unused nr_prefixes;
static const char *short_opts = "mv";
static const char *short_opts = "hmv";
static const struct option long_opts[] = {
{"help", 0, NULL, 'h'},
{"movable-node", 0, NULL, 'm'},
{"verbose", 0, NULL, 'v'},
{NULL, 0, NULL, 0}
};
static const char * const help_opts[] = {
"display this help message and exit",
"disallow allocations from regions marked as hotplugged\n\t\t\t"
"by simulating enabling the \"movable_node\" kernel\n\t\t\t"
"parameter",
@ -58,16 +61,53 @@ void reset_memblock_attributes(void)
memblock.current_limit = MEMBLOCK_ALLOC_ANYWHERE;
}
static inline void fill_memblock(void)
{
memset(memory_block.base, 1, MEM_SIZE);
}
void setup_memblock(void)
{
reset_memblock_regions();
memblock_add((phys_addr_t)memory_block.base, MEM_SIZE);
fill_memblock();
}
/**
* setup_numa_memblock:
* Set up a memory layout with multiple NUMA nodes in a previously allocated
* dummy physical memory.
* @node_fracs: an array representing the fraction of MEM_SIZE contained in
* each node in basis point units (one hundredth of 1% or 1/10000).
* For example, if node 0 should contain 1/8 of MEM_SIZE,
* node_fracs[0] = 1250.
*
* The nids will be set to 0 through NUMA_NODES - 1.
*/
void setup_numa_memblock(const unsigned int node_fracs[])
{
phys_addr_t base;
int flags;
reset_memblock_regions();
base = (phys_addr_t)memory_block.base;
flags = (movable_node_is_enabled()) ? MEMBLOCK_NONE : MEMBLOCK_HOTPLUG;
for (int i = 0; i < NUMA_NODES; i++) {
assert(node_fracs[i] <= BASIS);
phys_addr_t size = MEM_SIZE * node_fracs[i] / BASIS;
memblock_add_node(base, size, i, flags);
base += size;
}
fill_memblock();
}
void dummy_physical_memory_init(void)
{
memory_block.base = malloc(MEM_SIZE);
assert(memory_block.base);
fill_memblock();
}
void dummy_physical_memory_cleanup(void)

View File

@ -10,13 +10,22 @@
#include <linux/printk.h>
#include <../selftests/kselftest.h>
#define MEM_SIZE SZ_16K
#define MEM_SIZE SZ_16K
#define NUMA_NODES 8
enum test_flags {
/* No special request. */
TEST_F_NONE = 0x0,
/* Perform raw allocations (no zeroing of memory). */
TEST_F_RAW = 0x1,
};
/**
* ASSERT_EQ():
* Check the condition
* @_expected == @_seen
* If false, print failed test message (if in VERBOSE mode) and then assert
* If false, print failed test message (if running with --verbose) and then
* assert.
*/
#define ASSERT_EQ(_expected, _seen) do { \
if ((_expected) != (_seen)) \
@ -28,7 +37,8 @@
* ASSERT_NE():
* Check the condition
* @_expected != @_seen
* If false, print failed test message (if in VERBOSE mode) and then assert
* If false, print failed test message (if running with --verbose) and then
* assert.
*/
#define ASSERT_NE(_expected, _seen) do { \
if ((_expected) == (_seen)) \
@ -40,7 +50,8 @@
* ASSERT_LT():
* Check the condition
* @_expected < @_seen
* If false, print failed test message (if in VERBOSE mode) and then assert
* If false, print failed test message (if running with --verbose) and then
* assert.
*/
#define ASSERT_LT(_expected, _seen) do { \
if ((_expected) >= (_seen)) \
@ -48,6 +59,43 @@
assert((_expected) < (_seen)); \
} while (0)
/**
* ASSERT_LE():
* Check the condition
* @_expected <= @_seen
* If false, print failed test message (if running with --verbose) and then
* assert.
*/
#define ASSERT_LE(_expected, _seen) do { \
if ((_expected) > (_seen)) \
test_fail(); \
assert((_expected) <= (_seen)); \
} while (0)
/**
* ASSERT_MEM_EQ():
* Check that the first @_size bytes of @_seen are all equal to @_expected.
* If false, print failed test message (if running with --verbose) and then
* assert.
*/
#define ASSERT_MEM_EQ(_seen, _expected, _size) do { \
for (int _i = 0; _i < (_size); _i++) { \
ASSERT_EQ(((char *)_seen)[_i], (_expected)); \
} \
} while (0)
/**
* ASSERT_MEM_NE():
* Check that none of the first @_size bytes of @_seen are equal to @_expected.
* If false, print failed test message (if running with --verbose) and then
* assert.
*/
#define ASSERT_MEM_NE(_seen, _expected, _size) do { \
for (int _i = 0; _i < (_size); _i++) { \
ASSERT_NE(((char *)_seen)[_i], (_expected)); \
} \
} while (0)
#define PREFIX_PUSH() prefix_push(__func__)
/*
@ -65,9 +113,15 @@ struct region {
phys_addr_t size;
};
static inline phys_addr_t __maybe_unused region_end(struct memblock_region *rgn)
{
return rgn->base + rgn->size;
}
void reset_memblock_regions(void);
void reset_memblock_attributes(void);
void setup_memblock(void);
void setup_numa_memblock(const unsigned int node_fracs[]);
void dummy_physical_memory_init(void);
void dummy_physical_memory_cleanup(void);
void parse_args(int argc, char **argv);
@ -85,4 +139,28 @@ static inline void test_pass_pop(void)
prefix_pop();
}
static inline void run_top_down(int (*func)())
{
memblock_set_bottom_up(false);
prefix_push("top-down");
func();
prefix_pop();
}
static inline void run_bottom_up(int (*func)())
{
memblock_set_bottom_up(true);
prefix_push("bottom-up");
func();
prefix_pop();
}
static inline void assert_mem_content(void *mem, int size, int flags)
{
if (flags & TEST_F_RAW)
ASSERT_MEM_NE(mem, 0, size);
else
ASSERT_MEM_EQ(mem, 0, size);
}
#endif