PMD-mapped hugetlb vmas will also check_hwpoisoned_pmd_entry. Add the required code so it knows how to handle those there. Signed-off-by: Oscar Salvador <osalvador@xxxxxxx> --- mm/memory-failure.c | 44 ++++++++++++++++++++++++++++++-------------- 1 file changed, 30 insertions(+), 14 deletions(-) diff --git a/mm/memory-failure.c b/mm/memory-failure.c index 0cb1b7bea9a5..8cae95e36365 100644 --- a/mm/memory-failure.c +++ b/mm/memory-failure.c @@ -771,27 +771,43 @@ static int check_hwpoisoned_entry(pte_t pte, unsigned long addr, short shift, return 1; } -#ifdef CONFIG_TRANSPARENT_HUGEPAGE +#ifdef CONFIG_PGTABLE_HAS_HUGE_LEAVES static int check_hwpoisoned_pmd_entry(pmd_t *pmdp, unsigned long addr, - struct hwpoison_walk *hwp) + struct hwpoison_walk *hwp, + struct vm_area_struct *vma) { pmd_t pmd = *pmdp; unsigned long pfn; - unsigned long hwpoison_vaddr; + unsigned short shift; + unsigned long hwpoison_vaddr = addr; - if (!pmd_present(pmd)) - return 0; - pfn = pmd_pfn(pmd); - if (pfn <= hwp->pfn && hwp->pfn < pfn + HPAGE_PMD_NR) { - hwpoison_vaddr = addr + ((hwp->pfn - pfn) << PAGE_SHIFT); - set_to_kill(&hwp->tk, hwpoison_vaddr, PAGE_SHIFT); - return 1; + if (pmd_present(pmd)) { + pfn = pmd_pfn(pmd); + } else { + swp_entry_t swp = pmd_to_swp_entry(pmd); + + if (!is_hwpoison_entry(swp)) + return 0; + pfn = swp_offset_pfn(swp); } - return 0; + + shift = is_vm_hugetlb_page(vma) ? huge_page_shift(hstate_vma(vma)) + : PAGE_SHIFT; + + if (pfn > hwp->pfn || hwp->pfn > pfn + HPAGE_PMD_NR) + return 0; + + if (!is_vm_hugetlb_page(vma)) + hwpoison_vaddr += (hwp->pfn - pfn) << PAGE_SHIFT; + + set_to_kill(&hwp->tk, hwpoison_vaddr, shift); + + return 1; } #else static int check_hwpoisoned_pmd_entry(pmd_t *pmdp, unsigned long addr, - struct hwpoison_walk *hwp) + struct hwpoison_walk *hwp, + struct vm_area_struct *vma) { return 0; } @@ -805,9 +821,9 @@ static int hwpoison_pte_range(pmd_t *pmdp, unsigned long addr, pte_t *ptep, *mapped_pte; spinlock_t *ptl; - ptl = pmd_trans_huge_lock(pmdp, walk->vma); + ptl = pmd_huge_lock(pmdp, walk->vma); if (ptl) { - ret = check_hwpoisoned_pmd_entry(pmdp, addr, hwp); + ret = check_hwpoisoned_pmd_entry(pmdp, addr, hwp, walk->vma); spin_unlock(ptl); goto out; } -- 2.26.2