Message ID | 1447882389.21443.151.camel@hpe.com |
---|---|
State | Not Applicable, archived |
Headers | show |
On Wed, Nov 18, 2015 at 1:33 PM, Toshi Kani <toshi.kani@hpe.com> wrote: > I am seeing a similar/same problem in my test. I think the problem is that in > case of a WP fault, wp_huge_pmd() -> __dax_pmd_fault() -> vmf_insert_pfn_pmd(), > which is a no-op since the PMD is mapped already. We need WP handling for this > PMD map. > > If it helps, I have attached change for follow_trans_huge_pmd(). I have not > tested much, though. Interesting, I didn't get this far because my tests were crashing the kernel. I'll add this case the pmd fault test in ndctl. -- To unsubscribe from this list: send the line "unsubscribe linux-ext4" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
On Wed, 2015-11-18 at 13:57 -0800, Dan Williams wrote: > On Wed, Nov 18, 2015 at 1:33 PM, Toshi Kani <toshi.kani@hpe.com> wrote: > > I am seeing a similar/same problem in my test. I think the problem is that > > in > > case of a WP fault, wp_huge_pmd() -> __dax_pmd_fault() -> > > vmf_insert_pfn_pmd(), > > which is a no-op since the PMD is mapped already. We need WP handling for > > this > > PMD map. > > > > If it helps, I have attached change for follow_trans_huge_pmd(). I have not > > tested much, though. > > Interesting, I didn't get this far because my tests were crashing the > kernel. I'll add this case the pmd fault test in ndctl. I hit this one with mmap(MAP_POPULATE). With this change, I then hit the WP fault loop when writing to the range. Thanks, -Toshi -- To unsubscribe from this list: send the line "unsubscribe linux-ext4" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
--- include/linux/mm.h | 2 ++ mm/gup.c | 24 ++++++++++++++++++++++++ mm/huge_memory.c | 8 ++++++++ 3 files changed, 34 insertions(+) diff --git a/include/linux/mm.h b/include/linux/mm.h index 00bad77..a427b88 100644 --- a/include/linux/mm.h +++ b/include/linux/mm.h @@ -1084,6 +1084,8 @@ struct zap_details { struct page *vm_normal_page(struct vm_area_struct *vma, unsigned long addr, pte_t pte); +int follow_pfn_pmd(struct vm_area_struct *vma, unsigned long address, + pmd_t *pmd, unsigned int flags); int zap_vma_ptes(struct vm_area_struct *vma, unsigned long address, unsigned long size); diff --git a/mm/gup.c b/mm/gup.c index deafa2c..15135ee 100644 --- a/mm/gup.c +++ b/mm/gup.c @@ -34,6 +34,30 @@ static struct page *no_page_table(struct vm_area_struct *vma, return NULL; } +int follow_pfn_pmd(struct vm_area_struct *vma, unsigned long address, + pmd_t *pmd, unsigned int flags) +{ + /* No page to get reference */ + if (flags & FOLL_GET) + return -EFAULT; + + if (flags & FOLL_TOUCH) { + pmd_t entry = *pmd; + + if (flags & FOLL_WRITE) + entry = pmd_mkdirty(entry); + entry = pmd_mkyoung(entry); + + if (!pmd_same(*pmd, entry)) { + set_pmd_at(vma->vm_mm, address, pmd, entry); + update_mmu_cache_pmd(vma, address, pmd); + } + } + + /* Proper page table entry exists, but no corresponding struct page */ + return -EEXIST; +} + static int follow_pfn_pte(struct vm_area_struct *vma, unsigned long address, pte_t *pte, unsigned int flags) { diff --git a/mm/huge_memory.c b/mm/huge_memory.c index c29ddeb..41b277a 100644 --- a/mm/huge_memory.c +++ b/mm/huge_memory.c @@ -1276,6 +1276,7 @@ struct page *follow_trans_huge_pmd(struct vm_area_struct *vma, { struct mm_struct *mm = vma->vm_mm; struct page *page = NULL; + int ret; assert_spin_locked(pmd_lockptr(mm, pmd)); @@ -1290,6 +1291,13 @@ struct page *follow_trans_huge_pmd(struct vm_area_struct *vma, if ((flags & FOLL_NUMA) && pmd_protnone(*pmd)) goto out; + /* pfn map does not have struct page */ + if (vma->vm_flags & (VM_PFNMAP | VM_MIXEDMAP)) { + ret = follow_pfn_pmd(vma, addr, pmd, flags); + page = ERR_PTR(ret); + goto out; + } + page = pmd_page(*pmd); VM_BUG_ON_PAGE(!PageHead(page), page); if (flags & FOLL_TOUCH) {