Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 20f664aa authored by Minchan Kim's avatar Minchan Kim Committed by Linus Torvalds
Browse files

mm: pmd dirty emulation in page fault handler

Andreas reported [1] made a test in jemalloc hang in THP mode in arm64:

  http://lkml.kernel.org/r/mvmmvfy37g1.fsf@hawking.suse.de

The problem is currently page fault handler doesn't supports dirty bit
emulation of pmd for non-HW dirty-bit architecture so that application
stucks until VM marked the pmd dirty.

How the emulation work depends on the architecture.  In case of arm64,
when it set up pte firstly, it sets pte PTE_RDONLY to get a chance to
mark the pte dirty via triggering page fault when store access happens.
Once the page fault occurs, VM marks the pmd dirty and arch code for
setting pmd will clear PTE_RDONLY for application to proceed.

IOW, if VM doesn't mark the pmd dirty, application hangs forever by
repeated fault(i.e., store op but the pmd is PTE_RDONLY).

This patch enables pmd dirty-bit emulation for those architectures.

[1] b8d3c4c3, mm/huge_memory.c: don't split THP page when MADV_FREE syscall is called

Fixes: b8d3c4c3 ("mm/huge_memory.c: don't split THP page when MADV_FREE syscall is called")
Link: http://lkml.kernel.org/r/1482506098-6149-1-git-send-email-minchan@kernel.org


Signed-off-by: default avatarMinchan Kim <minchan@kernel.org>
Reported-by: default avatarAndreas Schwab <schwab@suse.de>
Tested-by: default avatarAndreas Schwab <schwab@suse.de>
Acked-by: default avatarKirill A. Shutemov <kirill.shutemov@linux.intel.com>
Acked-by: default avatarMichal Hocko <mhocko@suse.com>
Cc: Jason Evans <je@fb.com>
Cc: Will Deacon <will.deacon@arm.com>
Cc: Catalin Marinas <catalin.marinas@arm.com>
Cc: <stable@vger.kernel.org> [4.5+]
Signed-off-by: default avatarAndrew Morton <akpm@linux-foundation.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@linux-foundation.org>
parent c626bc46
Loading
Loading
Loading
Loading
+4 −2
Original line number Original line Diff line number Diff line
@@ -883,15 +883,17 @@ void huge_pmd_set_accessed(struct vm_fault *vmf, pmd_t orig_pmd)
{
{
	pmd_t entry;
	pmd_t entry;
	unsigned long haddr;
	unsigned long haddr;
	bool write = vmf->flags & FAULT_FLAG_WRITE;


	vmf->ptl = pmd_lock(vmf->vma->vm_mm, vmf->pmd);
	vmf->ptl = pmd_lock(vmf->vma->vm_mm, vmf->pmd);
	if (unlikely(!pmd_same(*vmf->pmd, orig_pmd)))
	if (unlikely(!pmd_same(*vmf->pmd, orig_pmd)))
		goto unlock;
		goto unlock;


	entry = pmd_mkyoung(orig_pmd);
	entry = pmd_mkyoung(orig_pmd);
	if (write)
		entry = pmd_mkdirty(entry);
	haddr = vmf->address & HPAGE_PMD_MASK;
	haddr = vmf->address & HPAGE_PMD_MASK;
	if (pmdp_set_access_flags(vmf->vma, haddr, vmf->pmd, entry,
	if (pmdp_set_access_flags(vmf->vma, haddr, vmf->pmd, entry, write))
				vmf->flags & FAULT_FLAG_WRITE))
		update_mmu_cache_pmd(vmf->vma, vmf->address, vmf->pmd);
		update_mmu_cache_pmd(vmf->vma, vmf->address, vmf->pmd);


unlock:
unlock: