Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

Merge tag 'memblock-v5.14-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/rppt/memblock

Pull memblock updates from Mike Rapoport:
"Fix arm crashes caused by holes in the memory map.

The coordination between freeing of unused memory map, pfn_valid() and
core mm assumptions about validity of the memory map in various ranges
was not designed for complex layouts of the physical memory with a lot
of holes all over the place.

Kefen Wang reported crashes in move_freepages() on a system with the
following memory layout [1]:

node 0: [mem 0x0000000080a00000-0x00000000855fffff]
node 0: [mem 0x0000000086a00000-0x0000000087dfffff]
node 0: [mem 0x000000008bd00000-0x000000008c4fffff]
node 0: [mem 0x000000008e300000-0x000000008ecfffff]
node 0: [mem 0x0000000090d00000-0x00000000bfffffff]
node 0: [mem 0x00000000cc000000-0x00000000dc9fffff]
node 0: [mem 0x00000000de700000-0x00000000de9fffff]
node 0: [mem 0x00000000e0800000-0x00000000e0bfffff]
node 0: [mem 0x00000000f4b00000-0x00000000f6ffffff]
node 0: [mem 0x00000000fda00000-0x00000000ffffefff]

These crashes can be mitigated by enabling CONFIG_HOLES_IN_ZONE on ARM
and essentially turning pfn_valid_within() to pfn_valid() instead of
having it hardwired to 1 on that architecture, but this would require
to keep CONFIG_HOLES_IN_ZONE solely for this purpose.

A cleaner approach is to update ARM's implementation of pfn_valid() to
take into accounting rounding of the freed memory map to pageblock
boundaries and make sure it returns true for PFNs that have memory map
entries even if there is no physical memory backing those PFNs"

Link: https://lore.kernel.org/lkml/2a1592ad-bc9d-4664-fd19-f7448a37edc0@huawei.com [1]

* tag 'memblock-v5.14-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/rppt/memblock:
arm: extend pfn_valid to take into account freed memory map alignment
memblock: ensure there is no overflow in memblock_overlaps_region()
memblock: align freed memory map on pageblock boundaries with SPARSEMEM
memblock: free_unused_memmap: use pageblock units instead of MAX_ORDER

+27 -14
+12 -1
arch/arm/mm/init.c
··· 125 125 int pfn_valid(unsigned long pfn) 126 126 { 127 127 phys_addr_t addr = __pfn_to_phys(pfn); 128 + unsigned long pageblock_size = PAGE_SIZE * pageblock_nr_pages; 128 129 129 130 if (__phys_to_pfn(addr) != pfn) 130 131 return 0; 131 132 132 - return memblock_is_map_memory(addr); 133 + /* 134 + * If address less than pageblock_size bytes away from a present 135 + * memory chunk there still will be a memory map entry for it 136 + * because we round freed memory map to the pageblock boundaries. 137 + */ 138 + if (memblock_overlaps_region(&memblock.memory, 139 + ALIGN_DOWN(addr, pageblock_size), 140 + pageblock_size)) 141 + return 1; 142 + 143 + return 0; 133 144 } 134 145 EXPORT_SYMBOL(pfn_valid); 135 146 #endif
+15 -13
mm/memblock.c
··· 182 182 { 183 183 unsigned long i; 184 184 185 + memblock_cap_size(base, &size); 186 + 185 187 for (i = 0; i < type->cnt; i++) 186 188 if (memblock_addrs_overlap(base, size, type->regions[i].base, 187 189 type->regions[i].size)) ··· 1801 1799 */ 1802 1800 bool __init_memblock memblock_is_region_reserved(phys_addr_t base, phys_addr_t size) 1803 1801 { 1804 - memblock_cap_size(base, &size); 1805 1802 return memblock_overlaps_region(&memblock.reserved, base, size); 1806 1803 } 1807 1804 ··· 1947 1946 * due to SPARSEMEM sections which aren't present. 1948 1947 */ 1949 1948 start = min(start, ALIGN(prev_end, PAGES_PER_SECTION)); 1950 - #else 1951 - /* 1952 - * Align down here since the VM subsystem insists that the 1953 - * memmap entries are valid from the bank start aligned to 1954 - * MAX_ORDER_NR_PAGES. 1955 - */ 1956 - start = round_down(start, MAX_ORDER_NR_PAGES); 1957 1949 #endif 1950 + /* 1951 + * Align down here since many operations in VM subsystem 1952 + * presume that there are no holes in the memory map inside 1953 + * a pageblock 1954 + */ 1955 + start = round_down(start, pageblock_nr_pages); 1958 1956 1959 1957 /* 1960 1958 * If we had a previous bank, and there is a space ··· 1963 1963 free_memmap(prev_end, start); 1964 1964 1965 1965 /* 1966 - * Align up here since the VM subsystem insists that the 1967 - * memmap entries are valid from the bank end aligned to 1968 - * MAX_ORDER_NR_PAGES. 1966 + * Align up here since many operations in VM subsystem 1967 + * presume that there are no holes in the memory map inside 1968 + * a pageblock 1969 1969 */ 1970 - prev_end = ALIGN(end, MAX_ORDER_NR_PAGES); 1970 + prev_end = ALIGN(end, pageblock_nr_pages); 1971 1971 } 1972 1972 1973 1973 #ifdef CONFIG_SPARSEMEM 1974 - if (!IS_ALIGNED(prev_end, PAGES_PER_SECTION)) 1974 + if (!IS_ALIGNED(prev_end, PAGES_PER_SECTION)) { 1975 + prev_end = ALIGN(end, pageblock_nr_pages); 1975 1976 free_memmap(prev_end, ALIGN(prev_end, PAGES_PER_SECTION)); 1977 + } 1976 1978 #endif 1977 1979 } 1978 1980