|
@@ -1017,34 +1017,56 @@ int page_referenced(struct page *page,
|
|
|
static int page_mkclean_one(struct page *page, struct vm_area_struct *vma,
|
|
|
unsigned long address, void *arg)
|
|
|
{
|
|
|
- struct mm_struct *mm = vma->vm_mm;
|
|
|
- pte_t *pte;
|
|
|
- spinlock_t *ptl;
|
|
|
- int ret = 0;
|
|
|
+ struct page_vma_mapped_walk pvmw = {
|
|
|
+ .page = page,
|
|
|
+ .vma = vma,
|
|
|
+ .address = address,
|
|
|
+ .flags = PVMW_SYNC,
|
|
|
+ };
|
|
|
int *cleaned = arg;
|
|
|
|
|
|
- pte = page_check_address(page, mm, address, &ptl, 1);
|
|
|
- if (!pte)
|
|
|
- goto out;
|
|
|
-
|
|
|
- if (pte_dirty(*pte) || pte_write(*pte)) {
|
|
|
- pte_t entry;
|
|
|
+ while (page_vma_mapped_walk(&pvmw)) {
|
|
|
+ int ret = 0;
|
|
|
+ address = pvmw.address;
|
|
|
+ if (pvmw.pte) {
|
|
|
+ pte_t entry;
|
|
|
+ pte_t *pte = pvmw.pte;
|
|
|
+
|
|
|
+ if (!pte_dirty(*pte) && !pte_write(*pte))
|
|
|
+ continue;
|
|
|
+
|
|
|
+ flush_cache_page(vma, address, pte_pfn(*pte));
|
|
|
+ entry = ptep_clear_flush(vma, address, pte);
|
|
|
+ entry = pte_wrprotect(entry);
|
|
|
+ entry = pte_mkclean(entry);
|
|
|
+ set_pte_at(vma->vm_mm, address, pte, entry);
|
|
|
+ ret = 1;
|
|
|
+ } else {
|
|
|
+#ifdef CONFIG_TRANSPARENT_HUGE_PAGECACHE
|
|
|
+ pmd_t *pmd = pvmw.pmd;
|
|
|
+ pmd_t entry;
|
|
|
+
|
|
|
+ if (!pmd_dirty(*pmd) && !pmd_write(*pmd))
|
|
|
+ continue;
|
|
|
+
|
|
|
+ flush_cache_page(vma, address, page_to_pfn(page));
|
|
|
+ entry = pmdp_huge_clear_flush(vma, address, pmd);
|
|
|
+ entry = pmd_wrprotect(entry);
|
|
|
+ entry = pmd_mkclean(entry);
|
|
|
+ set_pmd_at(vma->vm_mm, address, pmd, entry);
|
|
|
+ ret = 1;
|
|
|
+#else
|
|
|
+ /* unexpected pmd-mapped page? */
|
|
|
+ WARN_ON_ONCE(1);
|
|
|
+#endif
|
|
|
+ }
|
|
|
|
|
|
- flush_cache_page(vma, address, pte_pfn(*pte));
|
|
|
- entry = ptep_clear_flush(vma, address, pte);
|
|
|
- entry = pte_wrprotect(entry);
|
|
|
- entry = pte_mkclean(entry);
|
|
|
- set_pte_at(mm, address, pte, entry);
|
|
|
- ret = 1;
|
|
|
+ if (ret) {
|
|
|
+ mmu_notifier_invalidate_page(vma->vm_mm, address);
|
|
|
+ (*cleaned)++;
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
- pte_unmap_unlock(pte, ptl);
|
|
|
-
|
|
|
- if (ret) {
|
|
|
- mmu_notifier_invalidate_page(mm, address);
|
|
|
- (*cleaned)++;
|
|
|
- }
|
|
|
-out:
|
|
|
return SWAP_AGAIN;
|
|
|
}
|
|
|
|