extern int copy_huge_pmd(struct mm_struct *dst_mm, struct mm_struct *src_mm,
pmd_t *dst_pmd, pmd_t *src_pmd, unsigned long addr,
struct vm_area_struct *vma);
+extern void huge_pmd_set_accessed(struct vm_area_struct *vma,
+ unsigned long address, pmd_t *pmd, int dirty);
extern int do_huge_pmd_wp_page(struct mm_struct *mm, struct vm_area_struct *vma,
unsigned long address, pmd_t *pmd,
pmd_t orig_pmd);
goto out;
}
+void huge_pmd_set_accessed(struct vm_area_struct *vma, unsigned long address,
+ pmd_t *pmd, int dirty)
+{
+ pmd_t entry = pmd_mkyoung(*pmd);
+ if (pmdp_set_access_flags(vma, address & HPAGE_PMD_MASK, pmd, entry, dirty))
+ update_mmu_cache_pmd(vma, address, pmd);
+}
+
int do_huge_pmd_wp_page(struct mm_struct *mm, struct vm_area_struct *vma,
unsigned long address, pmd_t *pmd, pmd_t orig_pmd)
{
barrier();
if (pmd_trans_huge(orig_pmd)) {
- if (flags & FAULT_FLAG_WRITE &&
+ unsigned int dirty = flags & FAULT_FLAG_WRITE;
+ if (dirty &&
!pmd_write(orig_pmd) &&
!pmd_trans_splitting(orig_pmd)) {
ret = do_huge_pmd_wp_page(mm, vma, address, pmd,
if (unlikely(ret & VM_FAULT_OOM))
goto retry;
return ret;
+ } else if (pmd_trans_huge_lock(pmd, vma) == 1) {
+ if (likely(pmd_same(*pmd, orig_pmd)))
+ huge_pmd_set_accessed(vma, address, pmd,
+ dirty);
+ spin_unlock(&mm->page_table_lock);
}
+
return 0;
}
}