Commit ba925fa3 authored by Gerald Schaefer's avatar Gerald Schaefer Committed by Heiko Carstens

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: default avatarIlya Leoshkevich <iii@linux.ibm.com>
Tested-by: default avatarIlya Leoshkevich <iii@linux.ibm.com>
Acked-by: default avatarChristian Borntraeger <borntraeger@de.ibm.com>
Signed-off-by: default avatarGerald Schaefer <gerald.schaefer@linux.ibm.com>
Signed-off-by: default avatarHeiko Carstens <hca@linux.ibm.com>
parent f0cbd3b8
...@@ -2485,23 +2485,36 @@ void gmap_sync_dirty_log_pmd(struct gmap *gmap, unsigned long bitmap[4], ...@@ -2485,23 +2485,36 @@ void gmap_sync_dirty_log_pmd(struct gmap *gmap, unsigned long bitmap[4],
} }
EXPORT_SYMBOL_GPL(gmap_sync_dirty_log_pmd); EXPORT_SYMBOL_GPL(gmap_sync_dirty_log_pmd);
#ifdef CONFIG_TRANSPARENT_HUGEPAGE
static int thp_split_walk_pmd_entry(pmd_t *pmd, unsigned long addr,
unsigned long end, struct mm_walk *walk)
{
struct vm_area_struct *vma = walk->vma;
split_huge_pmd(vma, pmd, addr);
return 0;
}
static const struct mm_walk_ops thp_split_walk_ops = {
.pmd_entry = thp_split_walk_pmd_entry,
};
static inline void thp_split_mm(struct mm_struct *mm) static inline void thp_split_mm(struct mm_struct *mm)
{ {
#ifdef CONFIG_TRANSPARENT_HUGEPAGE
struct vm_area_struct *vma; struct vm_area_struct *vma;
unsigned long addr;
for (vma = mm->mmap; vma != NULL; vma = vma->vm_next) { for (vma = mm->mmap; vma != NULL; vma = vma->vm_next) {
for (addr = vma->vm_start;
addr < vma->vm_end;
addr += PAGE_SIZE)
follow_page(vma, addr, FOLL_SPLIT);
vma->vm_flags &= ~VM_HUGEPAGE; vma->vm_flags &= ~VM_HUGEPAGE;
vma->vm_flags |= VM_NOHUGEPAGE; vma->vm_flags |= VM_NOHUGEPAGE;
walk_page_vma(vma, &thp_split_walk_ops, NULL);
} }
mm->def_flags |= VM_NOHUGEPAGE; mm->def_flags |= VM_NOHUGEPAGE;
#endif
} }
#else
static inline void thp_split_mm(struct mm_struct *mm)
{
}
#endif /* CONFIG_TRANSPARENT_HUGEPAGE */
/* /*
* Remove all empty zero pages from the mapping for lazy refaulting * Remove all empty zero pages from the mapping for lazy refaulting
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment