Skip to content

Commit

Permalink
shmem: support huge_fault to avoid pmd split
Browse files Browse the repository at this point in the history
Transparent hugepage of tmpfs is useful to improve TLB miss, but
it will be split during cow memory fault.
This will happen if we mprotect and rewrite code segment (which is
private file map) to hotpatch a running process.

Users of huge= mount option prefer huge pages after cow.
We can avoid the splitting by adding a huge_fault function.
  • Loading branch information
Liu Zixian authored and intel-lab-lkp committed Jul 26, 2022
1 parent 0aa002b commit 40060ce
Showing 1 changed file with 45 additions and 0 deletions.
45 changes: 45 additions & 0 deletions mm/shmem.c
Original file line number Diff line number Diff line change
Expand Up @@ -2130,6 +2130,50 @@ static vm_fault_t shmem_fault(struct vm_fault *vmf)
return ret;
}

static vm_fault_t shmem_huge_fault(struct vm_fault *vmf, enum page_entry_size pe_size)
{
vm_fault_t ret = VM_FAULT_FALLBACK;
unsigned long haddr = vmf->address & HPAGE_PMD_MASK;
struct page *old_page, *new_page;
int gfp_flags = GFP_HIGHUSER_MOVABLE | __GFP_COMP;

/* read or shared fault will not split huge pmd */
if (!(vmf->flags & FAULT_FLAG_WRITE)
|| (vmf->vma->vm_flags & VM_SHARED))
return VM_FAULT_FALLBACK;
if (pe_size != PE_SIZE_PMD)
return VM_FAULT_FALLBACK;

if (pmd_none(*vmf->pmd)) {
if (shmem_fault(vmf) & VM_FAULT_ERROR)
goto out;
if (!PageTransHuge(vmf->page))
goto out;
old_page = vmf->page;
} else {
old_page = pmd_page(*vmf->pmd);
page_remove_rmap(old_page, vmf->vma, true);
pmdp_huge_clear_flush(vmf->vma, haddr, vmf->pmd);
add_mm_counter(vmf->vma->vm_mm, MM_SHMEMPAGES, -HPAGE_PMD_NR);
}

new_page = &vma_alloc_folio(gfp_flags, HPAGE_PMD_ORDER,
vmf->vma, haddr, true)->page;
if (!new_page)
goto out;
copy_user_huge_page(new_page, old_page, haddr, vmf->vma, HPAGE_PMD_NR);
__SetPageUptodate(new_page);

ret = do_set_pmd(vmf, new_page);

out:
if (vmf->page) {
unlock_page(vmf->page);
put_page(vmf->page);
}
return ret;
}

unsigned long shmem_get_unmapped_area(struct file *file,
unsigned long uaddr, unsigned long len,
unsigned long pgoff, unsigned long flags)
Expand Down Expand Up @@ -3943,6 +3987,7 @@ static const struct super_operations shmem_ops = {

static const struct vm_operations_struct shmem_vm_ops = {
.fault = shmem_fault,
.huge_fault = shmem_huge_fault,
.map_pages = filemap_map_pages,
#ifdef CONFIG_NUMA
.set_policy = shmem_set_policy,
Expand Down

0 comments on commit 40060ce

Please sign in to comment.