All of lore.kernel.org
 help / color / mirror / Atom feed
From: Mike Rapoport <rppt@kernel.org>
To: Tianyi Chen <hi@tychen.cc>
Cc: Andrew Morton <akpm@linux-foundation.org>,
	linux-mm@kvack.org, linux-kernel@vger.kernel.org
Subject: Re: [PATCH 2/2] memblock tests: cover allocations below the low address limit
Date: Sun, 6 Sep 2026 23:29:26 +0300	[thread overview]
Message-ID: <ap3NJsaG10rLDVpd@kernel.org> (raw)
In-Reply-To: <20260906144011.848898-2-hi@tychen.cc>

On Sun, Sep 06, 2026 at 10:40:11PM +0800, Tianyi Chen wrote:
> Add memblock_alloc_low() coverage using the simulator's low address
> limit. Exercise aligned allocation, an allocation ending exactly at
> the limit, an alignment constraint that prevents fitting below it,
> and fully reserved low memory with high memory still available.
> 
> Run each case with bottom-up and top-down allocation. Check zeroing
> and reserved-region accounting as well as returned addresses. Verify
> that an unrestricted allocation can use the free high memory after
> the low allocation fails.
> 
> Document the simulated limit and remove the completed TODO. The full
> suite passes with ASan and UBSan in default, NUMA, 32-bit physical
> address and debug configurations, with movable-node mode both enabled
> and disabled.
> 
> Assisted-by: LLM
> Signed-off-by: Tianyi Chen <hi@tychen.cc>
> ---
>  tools/testing/memblock/Makefile              |   3 +-
>  tools/testing/memblock/README                |  13 +-
>  tools/testing/memblock/TODO                  |   5 -
>  tools/testing/memblock/main.c                |   2 +
>  tools/testing/memblock/tests/alloc_low_api.c | 147 +++++++++++++++++++
>  tools/testing/memblock/tests/alloc_low_api.h |   9 ++
>  6 files changed, 166 insertions(+), 13 deletions(-)
>  delete mode 100644 tools/testing/memblock/TODO
>  create mode 100644 tools/testing/memblock/tests/alloc_low_api.c
>  create mode 100644 tools/testing/memblock/tests/alloc_low_api.h
> 
> diff --git a/tools/testing/memblock/Makefile b/tools/testing/memblock/Makefile
> index d80982ccdc2..20524fcbe3c 100644
> --- a/tools/testing/memblock/Makefile
> +++ b/tools/testing/memblock/Makefile
> @@ -7,7 +7,8 @@ CFLAGS += -I. -I../../include -Wall -O2 -fsanitize=address \
>  LDFLAGS += -fsanitize=address -fsanitize=undefined
>  TARGETS = main
>  TEST_OFILES = tests/alloc_nid_api.o tests/alloc_helpers_api.o tests/alloc_api.o \
> -		  tests/basic_api.o tests/common.o tests/alloc_exact_nid_api.o
> +		  tests/basic_api.o tests/common.o tests/alloc_exact_nid_api.o \
> +		  tests/alloc_low_api.o
>  DEP_OFILES = memblock.o lib/slab.o mmzone.o slab.o cmdline.o
>  OFILES = main.o $(DEP_OFILES) $(TEST_OFILES)
>  EXTR_SRC = ../../../mm/memblock.c
> diff --git a/tools/testing/memblock/README b/tools/testing/memblock/README
> index b435f48d8a7..e4fb5f23fb2 100644
> --- a/tools/testing/memblock/README
> +++ b/tools/testing/memblock/README
> @@ -67,13 +67,13 @@ memblock
>  |-- tests
>  |    |-- alloc_api.(c|h)         -- memblock_alloc tests
>  |    |-- alloc_helpers_api.(c|h) -- memblock_alloc_from tests
> +|    |-- alloc_low_api.(c|h)     -- memblock_alloc_low tests
>  |    |-- alloc_nid_api.(c|h)     -- memblock_alloc_try_nid tests
>  |    |-- basic_api.(c|h)         -- memblock_add/memblock_reserve/... tests
>  |    |-- common.(c|h)            -- helper functions for resetting memblock;
>  |-- main.c        --------------.   dummy physical memory definition
>  |-- Makefile                     `- test runner
>  |-- README
> -|-- TODO
>  |-- .gitignore
>  
>  Simulating physical memory
> @@ -101,12 +101,11 @@ There's no need to explicitly free the dummy memory from memblock via
>  memblock_free() call. The entry will be erased by reset_memblock_regions(),
>  called at the beginning of each test.
>  
> -Known issues
> -============
> -
> -1. Tests for memblock_alloc_low() can't be easily implemented. The function uses
> -   ARCH_LOW_ADDRESS_LIMIT marco, which can't be changed to point at the low
> -   memory of the memory_block.
> +The simulator defines ARCH_LOW_ADDRESS_LIMIT in asm/dma.h using the midpoint
> +of the MEM_SIZE range beginning at the dummy physical memory base. This keeps
> +the low-address limit within the allocated buffer even when malloc() returns
> +an address above the kernel's default limit. The limit is an exclusive upper
> +bound, as in the memblock allocation API.
>  
>  References
>  ==========
> diff --git a/tools/testing/memblock/TODO b/tools/testing/memblock/TODO
> deleted file mode 100644
> index c13ad0dae77..00000000000
> --- a/tools/testing/memblock/TODO
> +++ /dev/null
> @@ -1,5 +0,0 @@
> -TODO
> -=====
> -
> -1. Add tests for memblock_alloc_low() once the simulator can model
> -   ARCH_LOW_ADDRESS_LIMIT against the low memory in memory_block
> diff --git a/tools/testing/memblock/main.c b/tools/testing/memblock/main.c
> index 278f9dec500..9a96e178551 100644
> --- a/tools/testing/memblock/main.c
> +++ b/tools/testing/memblock/main.c
> @@ -4,6 +4,7 @@
>  #include "tests/alloc_helpers_api.h"
>  #include "tests/alloc_nid_api.h"
>  #include "tests/alloc_exact_nid_api.h"
> +#include "tests/alloc_low_api.h"
>  #include "tests/common.h"
>  
>  int main(int argc, char **argv)
> @@ -12,6 +13,7 @@ int main(int argc, char **argv)
>  	memblock_basic_checks();
>  	memblock_alloc_checks();
>  	memblock_alloc_helpers_checks();
> +	memblock_alloc_low_checks();
>  	memblock_alloc_nid_checks();
>  	memblock_alloc_exact_nid_checks();
>  
> diff --git a/tools/testing/memblock/tests/alloc_low_api.c b/tools/testing/memblock/tests/alloc_low_api.c
> new file mode 100644
> index 00000000000..a0fae975a26
> --- /dev/null
> +++ b/tools/testing/memblock/tests/alloc_low_api.c
> @@ -0,0 +1,147 @@
> +// SPDX-License-Identifier: GPL-2.0-or-later
> +#include "alloc_low_api.h"
> +#include <linux/align.h>
> +
> +/* Allocate at the first or last aligned address below the low limit. */
> +static int alloc_low_simple_check(void)
> +{
> +	struct memblock_region *rgn = &memblock.reserved.regions[0];
> +	phys_addr_t size = SZ_64;
> +	phys_addr_t expected;
> +	void *allocated_ptr;
> +
> +	PREFIX_PUSH();
> +	setup_memblock();
> +
> +	if (memblock_bottom_up())
> +		expected = ALIGN(memblock_start_of_DRAM(), SMP_CACHE_BYTES);

Can we ever have memblock_start_of_DRAM() not aligned to SMP_CACHE_BYTES?

> +	else
> +		expected = ALIGN_DOWN(ARCH_LOW_ADDRESS_LIMIT - size,
> +				      SMP_CACHE_BYTES);
> +
> +	allocated_ptr = memblock_alloc_low(size, SMP_CACHE_BYTES);
> +
> +	ASSERT_NE(allocated_ptr, NULL);
> +	ASSERT_EQ((phys_addr_t)(uintptr_t)allocated_ptr, expected);
> +	ASSERT_MEM_EQ(allocated_ptr, 0, size);
> +	ASSERT_EQ(rgn->base, expected);
> +	ASSERT_EQ(rgn->size, size);
> +	ASSERT_LE(region_end(rgn), ARCH_LOW_ADDRESS_LIMIT);
> +	ASSERT_EQ(memblock.reserved.cnt, 1);
> +	ASSERT_EQ(memblock.reserved.total_size, size);
> +
> +	test_pass_pop();
> +	return 0;
> +}
> +
> +/* The only low memory available ends exactly at the exclusive limit. */

What do you mean by "exclusive limit"?

> +static int alloc_low_exact_limit_check(void)
> +{
> +	phys_addr_t limit = ARCH_LOW_ADDRESS_LIMIT;
> +	phys_addr_t base = ALIGN_DOWN(limit - SZ_64, SMP_CACHE_BYTES);
> +	phys_addr_t size = limit - base;
> +	void *allocated_ptr;
> +
> +	PREFIX_PUSH();
> +	setup_memblock();
> +	ASSERT_EQ(memblock_remove(memblock_start_of_DRAM(),
> +				  base - memblock_start_of_DRAM()), 0);
> +
> +	allocated_ptr = memblock_alloc_low(size, SMP_CACHE_BYTES);
> +
> +	ASSERT_NE(allocated_ptr, NULL);
> +	ASSERT_EQ((phys_addr_t)(uintptr_t)allocated_ptr, base);
> +	ASSERT_MEM_EQ(allocated_ptr, 0, size);
> +	ASSERT_EQ(memblock.reserved.regions[0].base, base);
> +	ASSERT_EQ(region_end(&memblock.reserved.regions[0]), limit);
> +	ASSERT_EQ(memblock.reserved.cnt, 1);
> +	ASSERT_EQ(memblock.reserved.total_size, size);
> +
> +	test_pass_pop();
> +	return 0;
> +}
> +
> +/*
> + * There are size bytes below the limit, but aligning the start makes the
> + * allocation cross it. Memory above the limit must not satisfy the request.
> + */
> +static int alloc_low_alignment_crosses_limit_check(void)
> +{
> +	phys_addr_t limit = ARCH_LOW_ADDRESS_LIMIT;
> +	phys_addr_t base = ALIGN_DOWN(limit, SMP_CACHE_BYTES) - 1;
> +	phys_addr_t size = limit - base;
> +	void *allocated_ptr;
> +
> +	PREFIX_PUSH();
> +	setup_memblock();
> +	ASSERT_EQ(memblock_remove(memblock_start_of_DRAM(),
> +				  base - memblock_start_of_DRAM()), 0);
> +
> +	allocated_ptr = memblock_alloc_low(size, SMP_CACHE_BYTES);
> +
> +	ASSERT_EQ(allocated_ptr, NULL);
> +	ASSERT_EQ(memblock.reserved.cnt, 0);
> +	ASSERT_EQ(memblock.reserved.total_size, 0);
> +	ASSERT_MEM_EQ((void *)(uintptr_t)base, 1, memblock_end_of_DRAM() - base);
> +
> +	test_pass_pop();
> +	return 0;
> +}
> +
> +/* Reserving all low memory must fail even though high memory remains free. */

Is this what the test checks?

> +static int alloc_low_reserved_check(void)
> +{
> +	phys_addr_t limit = ARCH_LOW_ADDRESS_LIMIT;
> +	phys_addr_t base = dummy_physical_memory_base();
> +	phys_addr_t size = SZ_64;
> +	void *allocated_ptr;
> +
> +	PREFIX_PUSH();
> +	setup_memblock();
> +	ASSERT_EQ(memblock_reserve(base, limit - base), 0);
> +
> +	allocated_ptr = memblock_alloc_low(size, SMP_CACHE_BYTES);
> +
> +	ASSERT_EQ(allocated_ptr, NULL);
> +	ASSERT_EQ(memblock.reserved.cnt, 1);
> +	ASSERT_EQ(memblock.reserved.regions[0].base, base);
> +	ASSERT_EQ(memblock.reserved.regions[0].size, limit - base);
> +	ASSERT_EQ(memblock.reserved.total_size, limit - base);
> +	ASSERT_MEM_EQ((void *)(uintptr_t)base, 1, MEM_SIZE);
> +
> +	allocated_ptr = memblock_alloc(size, SMP_CACHE_BYTES);
> +	ASSERT_NE(allocated_ptr, NULL);
> +	ASSERT_LE(limit, (phys_addr_t)(uintptr_t)allocated_ptr);
> +	ASSERT_MEM_EQ(allocated_ptr, 0, size);
> +
> +	test_pass_pop();
> +	return 0;
> +}
> +
> +static int alloc_low_checks(void)
> +{
> +	alloc_low_simple_check();
> +	alloc_low_exact_limit_check();
> +	alloc_low_alignment_crosses_limit_check();
> +	alloc_low_reserved_check();
> +
> +	return 0;
> +}
> +
> +int memblock_alloc_low_checks(void)
> +{
> +	prefix_reset();
> +	prefix_push("memblock_alloc_low");
> +	test_print("Running memblock_alloc_low tests...\n");
> +
> +	reset_memblock_attributes();
> +	dummy_physical_memory_init();
> +
> +	run_top_down(alloc_low_checks);
> +	run_bottom_up(alloc_low_checks);
> +
> +	dummy_physical_memory_cleanup();
> +	prefix_pop();
> +
> +	return 0;
> +}
> diff --git a/tools/testing/memblock/tests/alloc_low_api.h b/tools/testing/memblock/tests/alloc_low_api.h
> new file mode 100644
> index 00000000000..2e3cbe336f5
> --- /dev/null
> +++ b/tools/testing/memblock/tests/alloc_low_api.h
> @@ -0,0 +1,9 @@
> +/* SPDX-License-Identifier: GPL-2.0-or-later */
> +#ifndef _MEMBLOCK_ALLOC_LOW_H
> +#define _MEMBLOCK_ALLOC_LOW_H
> +
> +#include "common.h"
> +
> +int memblock_alloc_low_checks(void);
> +
> +#endif
> -- 
> 2.55.0
> 
> 

-- 
Sincerely yours,
Mike.


  reply	other threads:[~2026-09-06 20:29 UTC|newest]

Thread overview: 12+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-09-06 14:40 [PATCH 1/2] memblock tests: model the low allocation limit within dummy memory Tianyi Chen
2026-09-06 14:40 ` [PATCH 2/2] memblock tests: cover allocations below the low address limit Tianyi Chen
2026-09-06 20:29   ` Mike Rapoport [this message]
2026-09-06 20:21 ` [PATCH 1/2] memblock tests: model the low allocation limit within dummy memory Mike Rapoport
2026-09-07  1:20   ` Tianyi Chen
2026-09-07  1:20 ` [PATCH v2 0/2] memblock tests: cover low-address allocations Tianyi Chen
2026-09-07  1:20   ` [PATCH v2 1/2] memblock tests: model the low allocation limit within dummy memory Tianyi Chen
2026-09-09 17:14     ` Mike Rapoport
2026-09-07  1:20   ` [PATCH v2 2/2] memblock tests: cover allocations below the low address limit Tianyi Chen
2026-09-09 17:14     ` Mike Rapoport
2026-09-09 17:31   ` [PATCH v2 0/2] memblock tests: cover low-address allocations Mike Rapoport
2026-09-09 23:55     ` Tianyi Chen

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=ap3NJsaG10rLDVpd@kernel.org \
    --to=rppt@kernel.org \
    --cc=akpm@linux-foundation.org \
    --cc=hi@tychen.cc \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-mm@kvack.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.