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

s390/gmap: improve THP splitting

During s390_enable_sie(), we need to take care of splitting all qemu user
process THP mappings. This is currently done with follow_page(FOLL_SPLIT),
by simply iterating over all vma ranges, with PAGE_SIZE increment.

This logic is sub-optimal and can result in a lot of unnecessary overhead,
especially when using qemu and ASAN with large shadow map. Ilya reported
significant system slow-down with one CPU busy for a long time and overall
unresponsiveness.

Fix this by using walk_page_vma() and directly calling split_huge_pmd()
only for present pmds, which greatly reduces overhead.

Cc: <stable@vger.kernel.org> # v5.4+
Reported-by: Ilya Leoshkevich <iii@linux.ibm.com>
Tested-by: Ilya Leoshkevich <iii@linux.ibm.com>
Acked-by: Christian Borntraeger <borntraeger@de.ibm.com>
Signed-off-by: Gerald Schaefer <gerald.schaefer@linux.ibm.com>
Signed-off-by: Heiko Carstens <hca@linux.ibm.com>

authored by

Gerald Schaefer and committed by
Heiko Carstens
ba925fa3 f0cbd3b8

+20 -7
+20 -7
arch/s390/mm/gmap.c
··· 2485 2485 } 2486 2486 EXPORT_SYMBOL_GPL(gmap_sync_dirty_log_pmd); 2487 2487 2488 + #ifdef CONFIG_TRANSPARENT_HUGEPAGE 2489 + static int thp_split_walk_pmd_entry(pmd_t *pmd, unsigned long addr, 2490 + unsigned long end, struct mm_walk *walk) 2491 + { 2492 + struct vm_area_struct *vma = walk->vma; 2493 + 2494 + split_huge_pmd(vma, pmd, addr); 2495 + return 0; 2496 + } 2497 + 2498 + static const struct mm_walk_ops thp_split_walk_ops = { 2499 + .pmd_entry = thp_split_walk_pmd_entry, 2500 + }; 2501 + 2488 2502 static inline void thp_split_mm(struct mm_struct *mm) 2489 2503 { 2490 - #ifdef CONFIG_TRANSPARENT_HUGEPAGE 2491 2504 struct vm_area_struct *vma; 2492 - unsigned long addr; 2493 2505 2494 2506 for (vma = mm->mmap; vma != NULL; vma = vma->vm_next) { 2495 - for (addr = vma->vm_start; 2496 - addr < vma->vm_end; 2497 - addr += PAGE_SIZE) 2498 - follow_page(vma, addr, FOLL_SPLIT); 2499 2507 vma->vm_flags &= ~VM_HUGEPAGE; 2500 2508 vma->vm_flags |= VM_NOHUGEPAGE; 2509 + walk_page_vma(vma, &thp_split_walk_ops, NULL); 2501 2510 } 2502 2511 mm->def_flags |= VM_NOHUGEPAGE; 2503 - #endif 2504 2512 } 2513 + #else 2514 + static inline void thp_split_mm(struct mm_struct *mm) 2515 + { 2516 + } 2517 + #endif /* CONFIG_TRANSPARENT_HUGEPAGE */ 2505 2518 2506 2519 /* 2507 2520 * Remove all empty zero pages from the mapping for lazy refaulting