Skip to content

Commit 9348b73

Browse files
committed
mm: don't play games with pinned pages in clear_page_refs
Turning a pinned page read-only breaks the pinning after COW. Don't do it. The whole "track page soft dirty" state doesn't work with pinned pages anyway, since the page might be dirtied by the pinning entity without ever being noticed in the page tables. Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
1 parent 29a951d commit 9348b73

1 file changed

Lines changed: 21 additions & 0 deletions

File tree

fs/proc/task_mmu.c

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1035,6 +1035,25 @@ struct clear_refs_private {
10351035
};
10361036

10371037
#ifdef CONFIG_MEM_SOFT_DIRTY
1038+
1039+
#define is_cow_mapping(flags) (((flags) & (VM_SHARED | VM_MAYWRITE)) == VM_MAYWRITE)
1040+
1041+
static inline bool pte_is_pinned(struct vm_area_struct *vma, unsigned long addr, pte_t pte)
1042+
{
1043+
struct page *page;
1044+
1045+
if (!pte_write(pte))
1046+
return false;
1047+
if (!is_cow_mapping(vma->vm_flags))
1048+
return false;
1049+
if (likely(!atomic_read(&vma->vm_mm->has_pinned)))
1050+
return false;
1051+
page = vm_normal_page(vma, addr, pte);
1052+
if (!page)
1053+
return false;
1054+
return page_maybe_dma_pinned(page);
1055+
}
1056+
10381057
static inline void clear_soft_dirty(struct vm_area_struct *vma,
10391058
unsigned long addr, pte_t *pte)
10401059
{
@@ -1049,6 +1068,8 @@ static inline void clear_soft_dirty(struct vm_area_struct *vma,
10491068
if (pte_present(ptent)) {
10501069
pte_t old_pte;
10511070

1071+
if (pte_is_pinned(vma, addr, ptent))
1072+
return;
10521073
old_pte = ptep_modify_prot_start(vma, addr, pte);
10531074
ptent = pte_wrprotect(old_pte);
10541075
ptent = pte_clear_soft_dirty(ptent);

0 commit comments

Comments
 (0)