};
 
 #ifdef CONFIG_MEM_SOFT_DIRTY
+
+#define is_cow_mapping(flags) (((flags) & (VM_SHARED | VM_MAYWRITE)) == VM_MAYWRITE)
+
+static inline bool pte_is_pinned(struct vm_area_struct *vma, unsigned long addr, pte_t pte)
+{
+       struct page *page;
+
+       if (!pte_write(pte))
+               return false;
+       if (!is_cow_mapping(vma->vm_flags))
+               return false;
+       if (likely(!atomic_read(&vma->vm_mm->has_pinned)))
+               return false;
+       page = vm_normal_page(vma, addr, pte);
+       if (!page)
+               return false;
+       return page_maybe_dma_pinned(page);
+}
+
 static inline void clear_soft_dirty(struct vm_area_struct *vma,
                unsigned long addr, pte_t *pte)
 {
        if (pte_present(ptent)) {
                pte_t old_pte;
 
+               if (pte_is_pinned(vma, addr, ptent))
+                       return;
                old_pte = ptep_modify_prot_start(vma, addr, pte);
                ptent = pte_wrprotect(old_pte);
                ptent = pte_clear_soft_dirty(ptent);