Re: [PATCH v2 10/13] arch, mm: set high_memory in free_area_init()

Alexandre Ghiti <[email protected]>
Newsgroups gmane.linux.ports.m68k,gmane.linux.ports.alpha,gmane.linux.kernel,gmane.linux.kernel.arc,gmane.linux.ports.arm.kernel,gmane.linux.ports.hexagon,gmane.linux.ports.mips,gmane.linux.ports.parisc,gmane.linux.ports.ppc64.devel,gmane.linux.ports.riscv,gmane.linux.ports.sh.devel,gmane.linux.ports.sparc,gmane.linux.uml.devel,gmane.linux.kernel.cross-arch,gmane.linux.kernel.mm
Message-ID <[email protected]>
Hi Mike,

On 5/16/25 19:01, Mike Rapoport wrote:
> Hi Pratyush,
>
> On Fri, May 16, 2025 at 05:28:17PM +0200, Pratyush Yadav wrote:
>> Hi Mike, Andrew,
>>
>> On Thu, Mar 13 2025, Mike Rapoport wrote:
>>
>>> From: "Mike Rapoport (Microsoft)" <[email protected]>
>>>
>>> high_memory defines upper bound on the directly mapped memory.
>>> This bound is defined by the beginning of ZONE_HIGHMEM when a system has
>>> high memory and by the end of memory otherwise.
>>>
>>> All this is known to generic memory management initialization code that
>>> can set high_memory while initializing core mm structures.
>>>
>>> Add a generic calculation of high_memory to free_area_init() and remove
>>> per-architecture calculation except for the architectures that set and
>>> use high_memory earlier than that.
>>>
>>> Acked-by: Dave Hansen <[email protected]>	# x86
>>> Signed-off-by: Mike Rapoport (Microsoft) <[email protected]>
>>> ---
>>>   arch/alpha/mm/init.c         |  1 -
>>>   arch/arc/mm/init.c           |  2 --
>>>   arch/arm64/mm/init.c         |  2 --
>>>   arch/csky/mm/init.c          |  1 -
>>>   arch/hexagon/mm/init.c       |  6 ------
>>>   arch/loongarch/kernel/numa.c |  1 -
>>>   arch/loongarch/mm/init.c     |  2 --
>>>   arch/microblaze/mm/init.c    |  2 --
>>>   arch/mips/mm/init.c          |  2 --
>>>   arch/nios2/mm/init.c         |  6 ------
>>>   arch/openrisc/mm/init.c      |  2 --
>>>   arch/parisc/mm/init.c        |  1 -
>>>   arch/riscv/mm/init.c         |  1 -
>>>   arch/s390/mm/init.c          |  2 --
>>>   arch/sh/mm/init.c            |  7 -------
>>>   arch/sparc/mm/init_32.c      |  1 -
>>>   arch/sparc/mm/init_64.c      |  2 --
>>>   arch/um/kernel/um_arch.c     |  1 -
>>>   arch/x86/kernel/setup.c      |  2 --
>>>   arch/x86/mm/init_32.c        |  3 ---
>>>   arch/x86/mm/numa_32.c        |  3 ---
>>>   arch/xtensa/mm/init.c        |  2 --
>>>   mm/memory.c                  |  8 --------
>>>   mm/mm_init.c                 | 30 ++++++++++++++++++++++++++++++
>>>   mm/nommu.c                   |  2 --
>>>   25 files changed, 30 insertions(+), 62 deletions(-)
>> This patch causes a BUG() when built with CONFIG_DEBUG_VIRTUAL and
>> passing in the cma= commandline parameter:
>>
>>      ------------[ cut here ]------------
>>      kernel BUG at arch/x86/mm/physaddr.c:23!
>>      ception 0x06 IP 10:ffffffff812ebbf8 error 0 cr2 0xffff88903ffff000
>>      CPU: 0 UID: 0 PID: 0 Comm: swapper Not tainted 6.15.0-rc6+ #231 PREEMPT(undef)
>>      Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS Arch Linux 1.16.3-1-1 04/01/2014
>>      RIP: 0010:__phys_addr+0x58/0x60
>>      Code: 01 48 89 c2 48 d3 ea 48 85 d2 75 05 e9 91 52 cf 00 0f 0b 48 3d ff ff ff 1f 77 0f 48 8b 05 20 54 55 01 48 01 d0 e9 78 52 cf 00 <0f> 0b 90 0f 1f 44 00 00 90 90 90 90 90 90 90 90 90 90 90 90 90 90
>>      RSP: 0000:ffffffff82803dd8 EFLAGS: 00010006 ORIG_RAX: 0000000000000000
>>      RAX: 000000007fffffff RBX: 00000000ffffffff RCX: 0000000000000000
>>      RDX: 000000007fffffff RSI: 0000000280000000 RDI: ffffffffffffffff
>>      RBP: ffffffff82803e68 R08: 0000000000000000 R09: 0000000000000000
>>      R10: ffffffff83153180 R11: ffffffff82803e48 R12: ffffffff83c9aed0
>>      R13: 0000000000000000 R14: 0000001040000000 R15: 0000000000000000
>>      FS:  0000000000000000(0000) GS:0000000000000000(0000) knlGS:0000000000000000
>>      CS:  0010 DS: 0000 ES: 0000 CR0: 0000000080050033
>>      CR2: ffff88903ffff000 CR3: 0000000002838000 CR4: 00000000000000b0
>>      Call Trace:
>>       <TASK>
>>       ? __cma_declare_contiguous_nid+0x6e/0x340
>>       ? cma_declare_contiguous_nid+0x33/0x70
>>       ? dma_contiguous_reserve_area+0x2f/0x70
>>       ? setup_arch+0x6f1/0x870
>>       ? start_kernel+0x52/0x4b0
>>       ? x86_64_start_reservations+0x29/0x30
>>       ? x86_64_start_kernel+0x7c/0x80
>>       ? common_startup_64+0x13e/0x141
>>
>> The reason is that __cma_declare_contiguous_nid() does:
>>
>>      	highmem_start = __pa(high_memory - 1) + 1;
>>
>> If dma_contiguous_reserve_area() (or any other CMA declaration) is
>> called before free_area_init(), high_memory is uninitialized. Without
>> CONFIG_DEBUG_VIRTUAL, it will likely work but use the wrong value for
>> highmem_start.
>>
>> Among the architectures this patch touches, the below call
>> dma_contiguous_reserve_area() _before_ free_area_init():
>>
>> - x86
>> - s390
>> - mips
>> - riscv
>> - xtensa
>> - loongarch
>> - csky
> For most of those this patch didn't really change anything because they
> initialized high_memory in mem_init() which is a part of free_area_init().
> In those cases cma just did
>
> 	highmem_start = __pa(-1) + 1;
>
> and everyone was happy :)
>   
>> The below call it _after_ free_area_init():
>> - arm64
>>
>> And the below don't call it at all:
>> - sparc
>> - nios2
>> - openrisc
>> - hexagon
>> - sh
>> - um
>> - alpha
>>
>> One possible fix would be to move the calls to
>> dma_contiguous_reserve_area() after free_area_init(). On x86, it would
>> look like the diff below. The obvious downside is that moving the call
>> later increases the chances of allocation failure. I'm not sure how much
>> that actually matters, but at least on x86, that means crash kernel and
>> hugetlb reservations go before DMA reservation. Also, adding a patch
>> like that at rc7 is a bit risky.
> I don't think there's a risk of allocation failure, but moving things
> around in setup_arch() is always risky :)
>   
>> The other option would be to revert this. I tried a revert, but it isn't
>> trivial. It runs into merge conflicts in pretty much all of the arch
>> files. Maybe reverting patches 11, 12, and 13 as well would make it
>> easier but I didn't try that.
> What I think we can do is to add this to mm/cma.c (not even compile tested)
>
> diff --git a/mm/cma.c b/mm/cma.c
> index 15632939f20a..c04be488b099 100644
> --- a/mm/cma.c
> +++ b/mm/cma.c
> @@ -608,7 +608,10 @@ static int __init __cma_declare_contiguous_nid(phys_addr_t *basep,
>   	 * complain. Find the boundary by adding one to the last valid
>   	 * address.
>   	 */
> -	highmem_start = __pa(high_memory - 1) + 1;
> +	if (IS_ENABLED(CONFIG_HIGHMEM))
> +		highmem_start = __pa(high_memory - 1) + 1;
> +	else
> +		highmem_start = memblock_end_of_DRAM();
>   	pr_debug("%s(size %pa, base %pa, limit %pa alignment %pa)\n",
>   		__func__, &size, &base, &limit, &alignment);


I encountered the same error as Pratyush and the above diff fixes it: do 
you plan on sending this fix for 6.15?

If so, you can add:

Tested-by: Alexandre Ghiti <[email protected]>

If not, let me know how you want to proceed :)

Thanks,

Alex


>   
> so that highmem_start in __cma_declare_contiguous_nid() will be always
> correct for !HIGHMEM configs and then restore setting of highmem_start in
> mips::paging_init() as mips is the only architecture that actually set
> high_memory before free_area_init() before this patch.
>
> (for 32 bit configs of x86 there alrady a fixup d893aca973c3 ("x86/mm: restore
> early initialization of high_memory for 32-bits"))
>
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.