]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
memblock test: Add test to memblock_reserve() 129th region
authorShaoqin Huang <shaoqin.huang@intel.com>
Tue, 11 Oct 2022 06:21:21 +0000 (14:21 +0800)
committerMike Rapoport <rppt@linux.ibm.com>
Mon, 31 Oct 2022 08:15:00 +0000 (10:15 +0200)
Reserve 129th region in the memblock, and this will trigger the
memblock_double_array() function, this needs valid memory regions. So
using dummy_physical_memory_init() to allocate a valid memory region.
At the same time, reserve 128 faked memory region, and make sure these
reserved region not intersect with the valid memory region. So
memblock_double_array() will choose the valid memory region, and it will
success.

Also need to restore the reserved.regions after memblock_double_array(),
to make sure the subsequent tests can run as normal.

Signed-off-by: Shaoqin Huang <shaoqin.huang@intel.com>
Signed-off-by: Mike Rapoport <rppt@linux.ibm.com>
Link: https://lore.kernel.org/r/20221011062128.49359-3-shaoqin.huang@intel.com
tools/testing/memblock/tests/basic_api.c

index 4d61a4b474be36b8d5d7b292f745c9c7c4f3ab88..411647094cc37f832ecc69c829a57036a800c9db 100644 (file)
@@ -892,6 +892,96 @@ static int memblock_reserve_near_max_check(void)
        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)
 {
        prefix_reset();
@@ -906,6 +996,7 @@ static int memblock_reserve_checks(void)
        memblock_reserve_twice_check();
        memblock_reserve_between_check();
        memblock_reserve_near_max_check();
+       memblock_reserve_many_check();
 
        prefix_pop();