FAILED: patch "[PATCH] thp: fix MADV_DONTNEED vs. numa balancing race" failed to apply to 4.10-stable tree
Subsystems (3)
[email protected]
maintainerThe patch below does not apply to the 4.10-stable tree.
If someone wants it applied there, or to any other stable or longterm tree, then please email the backport, including the original git commit id to <[email protected]>.
thanks,
greg k-h
------------------ original commit in Linus's tree ------------------
Quoted 1 line
From
ced108037c2aa542b3ed8b7afd1576064ad1362aMon Sep 17 00:00:00 2001
From: "Kirill A. Shutemov" <[email protected]>
Date: Thu, 13 Apr 2017 14:56:20 -0700
Subject: [PATCH] thp: fix MADV_DONTNEED vs. numa balancing race
In case prot_numa, we are under down_read(mmap_sem). It's critical to not clear pmd intermittently to avoid race with MADV_DONTNEED which is also under down_read(mmap_sem):
CPU0: CPU1: change_huge_pmd(prot_numa=1) pmdp_huge_get_and_clear_notify()
madvise_dontneed()
zap_pmd_range()
pmd_trans_huge(*pmd) == 0 (without ptl)
// skip the pmd
set_pmd_at(); // pmd is re-established
The race makes MADV_DONTNEED miss the huge pmd and don't clear it which may break userspace.
Found by code analysis, never saw triggered.
mm/huge_memory.c +33 -1
@@ -1746,7 +1746,39 @@ int change_huge_pmd(struct vm_area_struct *vma, pmd_t *pmd,if (prot_numa &&pmd_protnone (*pmd)) goto unlock; - entry =pmdp_huge_get_and_clear_notify (mm, addr, pmd); +/* +* In case prot_numa, we are under down_read(mmap_sem). It's critical +* to not clear pmd intermittently to avoid race with MADV_DONTNEED +* which is also under down_read(mmap_sem): +* +* CPU0: CPU1: +* change_huge_pmd(prot_numa=1) +* pmdp_huge_get_and_clear_notify() +* madvise_dontneed() +* zap_pmd_range() +* pmd_trans_huge(*pmd) == 0 (without ptl) +* // skip the pmd +* set_pmd_at(); +* // pmd is re-established +* +* The race makes MADV_DONTNEED miss the huge pmd and don't clear it +* which may break userspace. +* +* pmdp_invalidate() is required to make sure we don't miss +* dirty/young flags set by hardware. +*/ + entry = *pmd; +pmdp_invalidate (vma, addr, pmd); + +/* +* Recover dirty/young flags. It relies on pmdp_invalidate to not +* corrupt them. +*/ +if (pmd_dirty (*pmd)) + entry =pmd_mkdirty (entry); +if (pmd_young (*pmd)) + entry =pmd_mkyoung (entry); + entry =pmd_modify (entry, newprot);if (preserve_write) entry =pmd_mk_savedwrite (entry);