x86/mm: Don't apply va_align to hugetlb mappings on AMD F15h

get_align_mask() returns huge_page_mask_align() for hugetlbfs, but get_align_bits()
adds va_align.bits regardless, so vm_unmapped_area() returns an address off the huge
page boundary and __unmap_hugepage_range() hits BUG_ON(start & ~huge_page_mask(h)) at
teardown.

This can be triggered on Carrizo and FX-8370E, both hstates.

Pass the file to get_align_bits() and skip the randomisation for hugetlbfs.

  [ bp: Massage commit message. ]

Fixes: 1317a5e7f7 ("arch/x86: teach arch_get_unmapped_area_vmflags to handle hugetlb mappings")
Suggested-by: Dave Hansen <dave.hansen@intel.com>
Acked-by: Dave Hansen <dave.hansen@intel.com>
Signed-off-by: Laurent Wandrebeck <l.wandrebeck@quelquesmots.fr>
Signed-off-by: Borislav Petkov (AMD) <bp@alien8.de>
Cc: stable@vger.kernel.org # 6.13+
Link: https://patch.msgid.link/20260922085032.46144-1-l.wandrebeck@quelquesmots.fr
This commit is contained in:
Laurent Wandrebeck 2026-09-22 10:50:32 +02:00 committed by Borislav Petkov (AMD)
parent 72d3fcf802
commit d2457a7e27

View File

@ -50,9 +50,16 @@ static unsigned long get_align_mask(struct file *filp)
* value before calling vm_unmapped_area() or ORed directly to the
* address.
*/
static unsigned long get_align_bits(void)
static unsigned long get_align_bits(struct file *filp)
{
return va_align.bits & get_align_mask(NULL);
/*
* va_align.bits is smaller than the huge page size and will
* lead to misaligned huge pages. Ignore it for huge mappings.
*/
if (is_file_hugepages(filp))
return 0;
return va_align.bits & get_align_mask(filp);
}
static int __init control_va_addr_alignment(char *str)
@ -157,7 +164,7 @@ arch_get_unmapped_area(struct file *filp, unsigned long addr, unsigned long len,
}
if (filp) {
info.align_mask = get_align_mask(filp);
info.align_offset += get_align_bits();
info.align_offset += get_align_bits(filp);
}
return vm_unmapped_area(&info);
@ -222,7 +229,7 @@ arch_get_unmapped_area_topdown(struct file *filp, unsigned long addr0,
if (filp) {
info.align_mask = get_align_mask(filp);
info.align_offset += get_align_bits();
info.align_offset += get_align_bits(filp);
}
addr = vm_unmapped_area(&info);
if (!(addr & ~PAGE_MASK))