Skip to content

Commit 785a77c

Browse files
Kalesh Singhmehmetb0
Kalesh Singh
authored andcommitted
mm: respect mmap hint address when aligning for THP
BugLink: https://bugs.launchpad.net/bugs/2096827 commit 249608e upstream. Commit efa7df3 ("mm: align larger anonymous mappings on THP boundaries") updated __get_unmapped_area() to align the start address for the VMA to a PMD boundary if CONFIG_TRANSPARENT_HUGEPAGE=y. It does this by effectively looking up a region that is of size, request_size + PMD_SIZE, and aligning up the start to a PMD boundary. Commit 4ef9ad1 ("mm: huge_memory: don't force huge page alignment on 32 bit") opted out of this for 32bit due to regressions in mmap base randomization. Commit d4148ae ("mm, mmap: limit THP alignment of anonymous mappings to PMD-aligned sizes") restricted this to only mmap sizes that are multiples of the PMD_SIZE due to reported regressions in some performance benchmarks -- which seemed mostly due to the reduced spatial locality of related mappings due to the forced PMD-alignment. Another unintended side effect has emerged: When a user specifies an mmap hint address, the THP alignment logic modifies the behavior, potentially ignoring the hint even if a sufficiently large gap exists at the requested hint location. Example Scenario: Consider the following simplified virtual address (VA) space: ... 0x200000-0x400000 --- VMA A 0x400000-0x600000 --- Hole 0x600000-0x800000 --- VMA B ... A call to mmap() with hint=0x400000 and len=0x200000 behaves differently: - Before THP alignment: The requested region (size 0x200000) fits into the gap at 0x400000, so the hint is respected. - After alignment: The logic searches for a region of size 0x400000 (len + PMD_SIZE) starting at 0x400000. This search fails due to the mapping at 0x600000 (VMA B), and the hint is ignored, falling back to arch_get_unmapped_area[_topdown](). In general the hint is effectively ignored, if there is any existing mapping in the below range: [mmap_hint + mmap_size, mmap_hint + mmap_size + PMD_SIZE) This changes the semantics of mmap hint; from ""Respect the hint if a sufficiently large gap exists at the requested location" to "Respect the hint only if an additional PMD-sized gap exists beyond the requested size". This has performance implications for allocators that allocate their heap using mmap but try to keep it "as contiguous as possible" by using the end of the exisiting heap as the address hint. With the new behavior it's more likely to get a much less contiguous heap, adding extra fragmentation and performance overhead. To restore the expected behavior; don't use thp_get_unmapped_area_vmflags() when the user provided a hint address, for anonymous mappings. Note: As Yang Shi pointed out: the issue still remains for filesystems which are using thp_get_unmapped_area() for their get_unmapped_area() op. It is unclear what worklaods will regress for if we ignore THP alignment when the hint address is provided for such file backed mappings -- so this fix will be handled separately. Link: https://lkml.kernel.org/r/[email protected] Fixes: efa7df3 ("mm: align larger anonymous mappings on THP boundaries") Signed-off-by: Kalesh Singh <[email protected]> Reviewed-by: Rik van Riel <[email protected]> Reviewed-by: Vlastimil Babka <[email protected]> Reviewed-by: David Hildenbrand <[email protected]> Cc: Kefeng Wang <[email protected]> Cc: Vlastimil Babka <[email protected]> Cc: Yang Shi <[email protected]> Cc: Rik van Riel <[email protected]> Cc: Ryan Roberts <[email protected]> Cc: Suren Baghdasaryan <[email protected]> Cc: Minchan Kim <[email protected]> Cc: Hans Boehm <[email protected]> Cc: Lokesh Gidra <[email protected]> Cc: <[email protected]> Signed-off-by: Andrew Morton <[email protected]> Signed-off-by: Greg Kroah-Hartman <[email protected]> Signed-off-by: Koichiro Den <[email protected]>
1 parent c5760fe commit 785a77c

File tree

1 file changed

+1
-0
lines changed

1 file changed

+1
-0
lines changed

mm/mmap.c

+1
Original file line numberDiff line numberDiff line change
@@ -1953,6 +1953,7 @@ __get_unmapped_area(struct file *file, unsigned long addr, unsigned long len,
19531953
if (get_area) {
19541954
addr = get_area(file, addr, len, pgoff, flags);
19551955
} else if (IS_ENABLED(CONFIG_TRANSPARENT_HUGEPAGE)
1956+
&& !addr /* no hint */
19561957
&& IS_ALIGNED(len, PMD_SIZE)) {
19571958
/* Ensures that larger anonymous mappings are THP aligned. */
19581959
addr = thp_get_unmapped_area_vmflags(file, addr, len,

0 commit comments

Comments
 (0)