mirror of https://lore.kernel.org/lkml/
 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 a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox

all inboxes | Powered by JetHome®