s390/mm: Set high_memory at the end of the identity mapping
authorAlexander Gordeev <agordeev@linux.ibm.com>
Tue, 29 Jul 2025 12:24:36 +0000 (14:24 +0200)
committerAlexander Gordeev <agordeev@linux.ibm.com>
Thu, 31 Jul 2025 16:59:26 +0000 (18:59 +0200)
The value of high_memory variable is set by set_high_memory() function
to a value returned by memblock_end_of_DRAM(). The latter function
returns by default the upper bound of the last online memory block,
not the upper bound of the directly mapped memory region. As result,
in case the end of memory happens to be offline, high_memory variable
is set to a value that is short on the last offline memory blocks size:

RANGE                                  SIZE   STATE REMOVABLE   BLOCK
0x0000000000000000-0x000000ffffffffff    1T  online       yes   0-511
0x0000010000000000-0x0000011fffffffff  128G offline           512-575

Memory block size:         2G
Total online memory:       1T
Total offline memory:    128G

crash> p/x vm_layout
$1 = {
  kaslr_offset = 0x3453e918000,
  kaslr_offset_phys = 0xa534218000,
  identity_base = 0x0,
  identity_size = 0x12000000000
}
crash> p/x high_memory
$2 = 0x10000000000

In the past the value of high_memory was derived from max_low_pfn,
which in turn was derived from the identity_size. Since identity_size
accommodates the whole memory size - including tailing offline blocks,
the offlined blocks did not impose any problem. But since commit
e120d1bc12da ("arch, mm: set high_memory in free_area_init()") the
value of high_memory is derived from the last memblock online region,
and that is where the problem comes from.

The value of high_memory is used by several drivers and by external
tools (e.g. crash tool aborts while loading a dump).

Similarily to ARM, use the override path provided by set_high_memory()
function and set the value of high_memory at the end of the identity
mapping early. That forces set_high_memory() to leave in high_memory
the correct value, even when the end of available memory is offline.

Fixes: e120d1bc12da ("arch, mm: set high_memory in free_area_init()")
Tested-by: Mikhail Zaslonko <zaslonko@linux.ibm.com>
Reviewed-by: Heiko Carstens <hca@linux.ibm.com>
Reviewed-by: Gerald Schaefer <gerald.schaefer@linux.ibm.com>
Signed-off-by: Alexander Gordeev <agordeev@linux.ibm.com>
arch/s390/kernel/setup.c

index f244c5560e7f62d02a36b5b46382e6005c464424..5c9789804120ab23c844d12c335a36227a79bf2b 100644 (file)
@@ -719,6 +719,11 @@ static void __init memblock_add_physmem_info(void)
        memblock_set_node(0, ULONG_MAX, &memblock.memory, 0);
 }
 
+static void __init setup_high_memory(void)
+{
+       high_memory = __va(ident_map_size);
+}
+
 /*
  * Reserve memory used for lowcore.
  */
@@ -951,6 +956,7 @@ void __init setup_arch(char **cmdline_p)
 
        free_physmem_info();
        setup_memory_end();
+       setup_high_memory();
        memblock_dump_all();
        setup_memory();