All of lore.kernel.org
 help / color / mirror / Atom feed
diff for duplicates of <20180914004239.GA31077@redhat.com>

diff --git a/a/1.txt b/N1/1.txt
index 33def86..5d4cfd2 100644
--- a/a/1.txt
+++ b/N1/1.txt
@@ -48,7 +48,7 @@ On Thu, Sep 13, 2018 at 10:23:28AM -0400, Jerome Glisse wrote:
 > > > > unwrite protect pages in a range that is write protected ie the vma
 > > > > !(vm_flags & VM_WRITE).
 > > > > 
-> > > > Signed-off-by: Jerome Glisse <jglisse@redhat.com>
+> > > > Signed-off-by: Jérôme Glisse <jglisse@redhat.com>
 > > > > ---
 > > > >  mm/userfaultfd.c | 2 +-
 > > > >  1 file changed, 1 insertion(+), 1 deletion(-)
@@ -123,3 +123,325 @@ Below is a slightly better one to avoid mkwrite on COW page but it is
 still kind of ugly to do that in those function maybe adding a new helper
 would be a better way dunno. Anyway untested but it is better than trying
 to set pte dirty.
+
+
+From 8333ac9de1c54fe858f6f22dd21a2e14eebccd0e Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?J=C3=A9r=C3=B4me=20Glisse?= <jglisse@redhat.com>
+Date: Thu, 13 Sep 2018 10:16:30 -0400
+Subject: [PATCH] mm/mprotect: add a mkwrite paramater to change_protection()
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+The mkwrite parameter allow to change read only pte to write one which
+is needed by userfaultfd to un-write-protect after a fault have been
+handled.
+
+Signed-off-by: Jérôme Glisse <jglisse@redhat.com>
+---
+ include/linux/huge_mm.h |  2 +-
+ include/linux/mm.h      |  3 +-
+ mm/huge_memory.c        | 32 +++++++++++++++++++--
+ mm/mempolicy.c          |  2 +-
+ mm/mprotect.c           | 61 +++++++++++++++++++++++++++++------------
+ mm/userfaultfd.c        |  2 +-
+ 6 files changed, 79 insertions(+), 23 deletions(-)
+
+diff --git a/include/linux/huge_mm.h b/include/linux/huge_mm.h
+index a8a126259bc4..b51ff7f8e65c 100644
+--- a/include/linux/huge_mm.h
++++ b/include/linux/huge_mm.h
+@@ -45,7 +45,7 @@ extern bool move_huge_pmd(struct vm_area_struct *vma, unsigned long old_addr,
+ 			 pmd_t *old_pmd, pmd_t *new_pmd, bool *need_flush);
+ extern int change_huge_pmd(struct vm_area_struct *vma, pmd_t *pmd,
+ 			unsigned long addr, pgprot_t newprot,
+-			int prot_numa);
++			int prot_numa, bool mkwrite);
+ int vmf_insert_pfn_pmd(struct vm_area_struct *vma, unsigned long addr,
+ 			pmd_t *pmd, pfn_t pfn, bool write);
+ int vmf_insert_pfn_pud(struct vm_area_struct *vma, unsigned long addr,
+diff --git a/include/linux/mm.h b/include/linux/mm.h
+index 5d5c7fd07dc0..2bbf3e33bf9e 100644
+--- a/include/linux/mm.h
++++ b/include/linux/mm.h
+@@ -1492,7 +1492,8 @@ extern unsigned long move_page_tables(struct vm_area_struct *vma,
+ 		bool need_rmap_locks);
+ extern unsigned long change_protection(struct vm_area_struct *vma, unsigned long start,
+ 			      unsigned long end, pgprot_t newprot,
+-			      int dirty_accountable, int prot_numa);
++			      int dirty_accountable, int prot_numa,
++			      bool mkwrite);
+ extern int mprotect_fixup(struct vm_area_struct *vma,
+ 			  struct vm_area_struct **pprev, unsigned long start,
+ 			  unsigned long end, unsigned long newflags);
+diff --git a/mm/huge_memory.c b/mm/huge_memory.c
+index abf621aba672..3038f4bd9cce 100644
+--- a/mm/huge_memory.c
++++ b/mm/huge_memory.c
+@@ -1842,12 +1842,13 @@ bool move_huge_pmd(struct vm_area_struct *vma, unsigned long old_addr,
+  *  - HPAGE_PMD_NR is protections changed and TLB flush necessary
+  */
+ int change_huge_pmd(struct vm_area_struct *vma, pmd_t *pmd,
+-		unsigned long addr, pgprot_t newprot, int prot_numa)
++		unsigned long addr, pgprot_t newprot, int prot_numa,
++		bool mkwrite)
+ {
+ 	struct mm_struct *mm = vma->vm_mm;
+ 	spinlock_t *ptl;
+ 	pmd_t entry;
+-	bool preserve_write;
++	bool preserve_write, do_mkwrite = false;
+ 	int ret;
+ 
+ 	ptl = __pmd_trans_huge_lock(pmd, vma);
+@@ -1857,6 +1858,31 @@ int change_huge_pmd(struct vm_area_struct *vma, pmd_t *pmd,
+ 	preserve_write = prot_numa && pmd_write(*pmd);
+ 	ret = 1;
+ 
++	if (mkwrite && pmd_present(*pmd) && !pmd_write(*pmd)) {
++		struct page *page = pmd_page(pmd);
++		pmd_t orig_pmd = READ_ONCE(pmd);
++
++		VM_BUG_ON_PAGE(!PageCompound(page) || !PageHead(page), page);
++		/*
++		 * We can only allow mkwrite if nobody else maps the huge page
++		 * or it's part.
++		 */
++		if (!trylock_page(page)) {
++			get_page(page);
++			spin_unlock(ptl);
++			lock_page(page);
++
++			ptl = __pmd_trans_huge_lock(pmd, vma);
++			if (!ptl)
++				return 0;
++		}
++		if (pmd_same(*pmd, orig_pmd) && reuse_swap_page(page, NULL)) {
++			do_mkwrite = true;
++		}
++		unlock_page(page);
++		put_page(page);
++	}
++
+ #ifdef CONFIG_ARCH_ENABLE_THP_MIGRATION
+ 	if (is_swap_pmd(*pmd)) {
+ 		swp_entry_t entry = pmd_to_swp_entry(*pmd);
+@@ -1925,6 +1951,8 @@ int change_huge_pmd(struct vm_area_struct *vma, pmd_t *pmd,
+ 	entry = pmd_modify(entry, newprot);
+ 	if (preserve_write)
+ 		entry = pmd_mk_savedwrite(entry);
++	if (do_mkwrite)
++		entry = pmd_mkwrite(entry);
+ 	ret = HPAGE_PMD_NR;
+ 	set_pmd_at(mm, addr, pmd, entry);
+ 	BUG_ON(vma_is_anonymous(vma) && !preserve_write && pmd_write(entry));
+diff --git a/mm/mempolicy.c b/mm/mempolicy.c
+index 4ce44d3ff03d..2d0ee09e6b26 100644
+--- a/mm/mempolicy.c
++++ b/mm/mempolicy.c
+@@ -579,7 +579,7 @@ unsigned long change_prot_numa(struct vm_area_struct *vma,
+ {
+ 	int nr_updated;
+ 
+-	nr_updated = change_protection(vma, addr, end, PAGE_NONE, 0, 1);
++	nr_updated = change_protection(vma, addr, end, PAGE_NONE, 0, 1, false);
+ 	if (nr_updated)
+ 		count_vm_numa_events(NUMA_PTE_UPDATES, nr_updated);
+ 
+diff --git a/mm/mprotect.c b/mm/mprotect.c
+index 58b629bb70de..c43a29eebdaf 100644
+--- a/mm/mprotect.c
++++ b/mm/mprotect.c
+@@ -36,7 +36,7 @@
+ 
+ static unsigned long change_pte_range(struct vm_area_struct *vma, pmd_t *pmd,
+ 		unsigned long addr, unsigned long end, pgprot_t newprot,
+-		int dirty_accountable, int prot_numa)
++		int dirty_accountable, int prot_numa, bool mkwrite)
+ {
+ 	struct mm_struct *mm = vma->vm_mm;
+ 	pte_t *pte, oldpte;
+@@ -72,13 +72,15 @@ static unsigned long change_pte_range(struct vm_area_struct *vma, pmd_t *pmd,
+ 		if (pte_present(oldpte)) {
+ 			pte_t ptent;
+ 			bool preserve_write = prot_numa && pte_write(oldpte);
++			bool do_mkwrite = false;
+ 
+ 			/*
+ 			 * Avoid trapping faults against the zero or KSM
+ 			 * pages. See similar comment in change_huge_pmd.
+ 			 */
+-			if (prot_numa) {
++			if (prot_numa || mkwrite) {
+ 				struct page *page;
++				int tmp;
+ 
+ 				page = vm_normal_page(vma, addr, oldpte);
+ 				if (!page || PageKsm(page))
+@@ -94,6 +96,26 @@ static unsigned long change_pte_range(struct vm_area_struct *vma, pmd_t *pmd,
+ 				 */
+ 				if (target_node == page_to_nid(page))
+ 					continue;
++
++				if (mkwrite) {
++					if (!trylock_page(page)) {
++						pte_t orig_pte = READ_ONCE(pte);
++						get_page(page);
++						pte_unmap_unlock(pte, ptl);
++						lock_page(page);
++						pte = pte_offset_map_lock(vma->vm_mm, pmd,
++									  addr, &ptl);
++						if (!pte_same(*pte, orig_pte)) {
++							unlock_page(page);
++							put_page(page);
++							continue;
++						}
++					}
++					if (reuse_swap_page(vmf->page, &tmp))
++						do_mkwrite = true;
++					unlock_page(page);
++					put_page(page);
++				}
+ 			}
+ 
+ 			ptent = ptep_modify_prot_start(mm, addr, pte);
+@@ -102,9 +124,9 @@ static unsigned long change_pte_range(struct vm_area_struct *vma, pmd_t *pmd,
+ 				ptent = pte_mk_savedwrite(ptent);
+ 
+ 			/* Avoid taking write faults for known dirty pages */
+-			if (dirty_accountable && pte_dirty(ptent) &&
+-					(pte_soft_dirty(ptent) ||
+-					 !(vma->vm_flags & VM_SOFTDIRTY))) {
++			if (do_mkwrite || (dirty_accountable &&
++			    pte_dirty(ptent) && (pte_soft_dirty(ptent) ||
++			    !(vma->vm_flags & VM_SOFTDIRTY)))) {
+ 				ptent = pte_mkwrite(ptent);
+ 			}
+ 			ptep_modify_prot_commit(mm, addr, pte, ptent);
+@@ -150,7 +172,8 @@ static unsigned long change_pte_range(struct vm_area_struct *vma, pmd_t *pmd,
+ 
+ static inline unsigned long change_pmd_range(struct vm_area_struct *vma,
+ 		pud_t *pud, unsigned long addr, unsigned long end,
+-		pgprot_t newprot, int dirty_accountable, int prot_numa)
++		pgprot_t newprot, int dirty_accountable, int prot_numa,
++		bool mkwrite)
+ {
+ 	pmd_t *pmd;
+ 	struct mm_struct *mm = vma->vm_mm;
+@@ -179,7 +202,7 @@ static inline unsigned long change_pmd_range(struct vm_area_struct *vma,
+ 				__split_huge_pmd(vma, pmd, addr, false, NULL);
+ 			} else {
+ 				int nr_ptes = change_huge_pmd(vma, pmd, addr,
+-						newprot, prot_numa);
++						newprot, prot_numa, mkwrite);
+ 
+ 				if (nr_ptes) {
+ 					if (nr_ptes == HPAGE_PMD_NR) {
+@@ -194,7 +217,7 @@ static inline unsigned long change_pmd_range(struct vm_area_struct *vma,
+ 			/* fall through, the trans huge pmd just split */
+ 		}
+ 		this_pages = change_pte_range(vma, pmd, addr, next, newprot,
+-				 dirty_accountable, prot_numa);
++				 dirty_accountable, prot_numa, mkwrite);
+ 		pages += this_pages;
+ next:
+ 		cond_resched();
+@@ -210,7 +233,8 @@ static inline unsigned long change_pmd_range(struct vm_area_struct *vma,
+ 
+ static inline unsigned long change_pud_range(struct vm_area_struct *vma,
+ 		p4d_t *p4d, unsigned long addr, unsigned long end,
+-		pgprot_t newprot, int dirty_accountable, int prot_numa)
++		pgprot_t newprot, int dirty_accountable, int prot_numa,
++		bool mkwrite)
+ {
+ 	pud_t *pud;
+ 	unsigned long next;
+@@ -222,7 +246,7 @@ static inline unsigned long change_pud_range(struct vm_area_struct *vma,
+ 		if (pud_none_or_clear_bad(pud))
+ 			continue;
+ 		pages += change_pmd_range(vma, pud, addr, next, newprot,
+-				 dirty_accountable, prot_numa);
++				 dirty_accountable, prot_numa, mkwrite);
+ 	} while (pud++, addr = next, addr != end);
+ 
+ 	return pages;
+@@ -230,7 +254,8 @@ static inline unsigned long change_pud_range(struct vm_area_struct *vma,
+ 
+ static inline unsigned long change_p4d_range(struct vm_area_struct *vma,
+ 		pgd_t *pgd, unsigned long addr, unsigned long end,
+-		pgprot_t newprot, int dirty_accountable, int prot_numa)
++		pgprot_t newprot, int dirty_accountable, int prot_numa,
++		bool mkwrite)
+ {
+ 	p4d_t *p4d;
+ 	unsigned long next;
+@@ -242,7 +267,7 @@ static inline unsigned long change_p4d_range(struct vm_area_struct *vma,
+ 		if (p4d_none_or_clear_bad(p4d))
+ 			continue;
+ 		pages += change_pud_range(vma, p4d, addr, next, newprot,
+-				 dirty_accountable, prot_numa);
++				 dirty_accountable, prot_numa, mkwrite);
+ 	} while (p4d++, addr = next, addr != end);
+ 
+ 	return pages;
+@@ -250,7 +275,7 @@ static inline unsigned long change_p4d_range(struct vm_area_struct *vma,
+ 
+ static unsigned long change_protection_range(struct vm_area_struct *vma,
+ 		unsigned long addr, unsigned long end, pgprot_t newprot,
+-		int dirty_accountable, int prot_numa)
++		int dirty_accountable, int prot_numa, mkwrite)
+ {
+ 	struct mm_struct *mm = vma->vm_mm;
+ 	pgd_t *pgd;
+@@ -267,7 +292,7 @@ static unsigned long change_protection_range(struct vm_area_struct *vma,
+ 		if (pgd_none_or_clear_bad(pgd))
+ 			continue;
+ 		pages += change_p4d_range(vma, pgd, addr, next, newprot,
+-				 dirty_accountable, prot_numa);
++				 dirty_accountable, prot_numa, mkwrite);
+ 	} while (pgd++, addr = next, addr != end);
+ 
+ 	/* Only flush the TLB if we actually modified any entries: */
+@@ -280,14 +305,16 @@ static unsigned long change_protection_range(struct vm_area_struct *vma,
+ 
+ unsigned long change_protection(struct vm_area_struct *vma, unsigned long start,
+ 		       unsigned long end, pgprot_t newprot,
+-		       int dirty_accountable, int prot_numa)
++		       int dirty_accountable, int prot_numa, bool mkwrite)
+ {
+ 	unsigned long pages;
+ 
+ 	if (is_vm_hugetlb_page(vma))
+ 		pages = hugetlb_change_protection(vma, start, end, newprot);
+ 	else
+-		pages = change_protection_range(vma, start, end, newprot, dirty_accountable, prot_numa);
++		pages = change_protection_range(vma, start, end, newprot,
++						dirty_accountable,
++						prot_numa, mkwrite);
+ 
+ 	return pages;
+ }
+@@ -366,7 +393,7 @@ mprotect_fixup(struct vm_area_struct *vma, struct vm_area_struct **pprev,
+ 	vma_set_page_prot(vma);
+ 
+ 	change_protection(vma, start, end, vma->vm_page_prot,
+-			  dirty_accountable, 0);
++			  dirty_accountable, 0, false);
+ 
+ 	/*
+ 	 * Private VM_LOCKED VMA becoming writable: trigger COW to avoid major
+diff --git a/mm/userfaultfd.c b/mm/userfaultfd.c
+index a0379c5ffa7c..c745c5d87523 100644
+--- a/mm/userfaultfd.c
++++ b/mm/userfaultfd.c
+@@ -632,7 +632,7 @@ int mwriteprotect_range(struct mm_struct *dst_mm, unsigned long start,
+ 		newprot = vm_get_page_prot(dst_vma->vm_flags);
+ 
+ 	change_protection(dst_vma, start, start + len, newprot,
+-				!enable_wp, 0);
++			  0, 0, !enable_wp);
+ 
+ 	err = 0;
+ out_unlock:
+-- 
+2.17.1
diff --git a/a/content_digest b/N1/content_digest
index 37ea424..bd79431 100644
--- a/a/content_digest
+++ b/N1/content_digest
@@ -73,7 +73,7 @@
  "> > > > unwrite protect pages in a range that is write protected ie the vma\n"
  "> > > > !(vm_flags & VM_WRITE).\n"
  "> > > > \n"
- "> > > > Signed-off-by: Jerome Glisse <jglisse@redhat.com>\n"
+ "> > > > Signed-off-by: J\303\251r\303\264me Glisse <jglisse@redhat.com>\n"
  "> > > > ---\n"
  "> > > >  mm/userfaultfd.c | 2 +-\n"
  "> > > >  1 file changed, 1 insertion(+), 1 deletion(-)\n"
@@ -147,6 +147,328 @@
  "Below is a slightly better one to avoid mkwrite on COW page but it is\n"
  "still kind of ugly to do that in those function maybe adding a new helper\n"
  "would be a better way dunno. Anyway untested but it is better than trying\n"
- to set pte dirty.
+ "to set pte dirty.\n"
+ "\n"
+ "\n"
+ "From 8333ac9de1c54fe858f6f22dd21a2e14eebccd0e Mon Sep 17 00:00:00 2001\n"
+ "From: =?UTF-8?q?J=C3=A9r=C3=B4me=20Glisse?= <jglisse@redhat.com>\n"
+ "Date: Thu, 13 Sep 2018 10:16:30 -0400\n"
+ "Subject: [PATCH] mm/mprotect: add a mkwrite paramater to change_protection()\n"
+ "MIME-Version: 1.0\n"
+ "Content-Type: text/plain; charset=UTF-8\n"
+ "Content-Transfer-Encoding: 8bit\n"
+ "\n"
+ "The mkwrite parameter allow to change read only pte to write one which\n"
+ "is needed by userfaultfd to un-write-protect after a fault have been\n"
+ "handled.\n"
+ "\n"
+ "Signed-off-by: J\303\251r\303\264me Glisse <jglisse@redhat.com>\n"
+ "---\n"
+ " include/linux/huge_mm.h |  2 +-\n"
+ " include/linux/mm.h      |  3 +-\n"
+ " mm/huge_memory.c        | 32 +++++++++++++++++++--\n"
+ " mm/mempolicy.c          |  2 +-\n"
+ " mm/mprotect.c           | 61 +++++++++++++++++++++++++++++------------\n"
+ " mm/userfaultfd.c        |  2 +-\n"
+ " 6 files changed, 79 insertions(+), 23 deletions(-)\n"
+ "\n"
+ "diff --git a/include/linux/huge_mm.h b/include/linux/huge_mm.h\n"
+ "index a8a126259bc4..b51ff7f8e65c 100644\n"
+ "--- a/include/linux/huge_mm.h\n"
+ "+++ b/include/linux/huge_mm.h\n"
+ "@@ -45,7 +45,7 @@ extern bool move_huge_pmd(struct vm_area_struct *vma, unsigned long old_addr,\n"
+ " \t\t\t pmd_t *old_pmd, pmd_t *new_pmd, bool *need_flush);\n"
+ " extern int change_huge_pmd(struct vm_area_struct *vma, pmd_t *pmd,\n"
+ " \t\t\tunsigned long addr, pgprot_t newprot,\n"
+ "-\t\t\tint prot_numa);\n"
+ "+\t\t\tint prot_numa, bool mkwrite);\n"
+ " int vmf_insert_pfn_pmd(struct vm_area_struct *vma, unsigned long addr,\n"
+ " \t\t\tpmd_t *pmd, pfn_t pfn, bool write);\n"
+ " int vmf_insert_pfn_pud(struct vm_area_struct *vma, unsigned long addr,\n"
+ "diff --git a/include/linux/mm.h b/include/linux/mm.h\n"
+ "index 5d5c7fd07dc0..2bbf3e33bf9e 100644\n"
+ "--- a/include/linux/mm.h\n"
+ "+++ b/include/linux/mm.h\n"
+ "@@ -1492,7 +1492,8 @@ extern unsigned long move_page_tables(struct vm_area_struct *vma,\n"
+ " \t\tbool need_rmap_locks);\n"
+ " extern unsigned long change_protection(struct vm_area_struct *vma, unsigned long start,\n"
+ " \t\t\t      unsigned long end, pgprot_t newprot,\n"
+ "-\t\t\t      int dirty_accountable, int prot_numa);\n"
+ "+\t\t\t      int dirty_accountable, int prot_numa,\n"
+ "+\t\t\t      bool mkwrite);\n"
+ " extern int mprotect_fixup(struct vm_area_struct *vma,\n"
+ " \t\t\t  struct vm_area_struct **pprev, unsigned long start,\n"
+ " \t\t\t  unsigned long end, unsigned long newflags);\n"
+ "diff --git a/mm/huge_memory.c b/mm/huge_memory.c\n"
+ "index abf621aba672..3038f4bd9cce 100644\n"
+ "--- a/mm/huge_memory.c\n"
+ "+++ b/mm/huge_memory.c\n"
+ "@@ -1842,12 +1842,13 @@ bool move_huge_pmd(struct vm_area_struct *vma, unsigned long old_addr,\n"
+ "  *  - HPAGE_PMD_NR is protections changed and TLB flush necessary\n"
+ "  */\n"
+ " int change_huge_pmd(struct vm_area_struct *vma, pmd_t *pmd,\n"
+ "-\t\tunsigned long addr, pgprot_t newprot, int prot_numa)\n"
+ "+\t\tunsigned long addr, pgprot_t newprot, int prot_numa,\n"
+ "+\t\tbool mkwrite)\n"
+ " {\n"
+ " \tstruct mm_struct *mm = vma->vm_mm;\n"
+ " \tspinlock_t *ptl;\n"
+ " \tpmd_t entry;\n"
+ "-\tbool preserve_write;\n"
+ "+\tbool preserve_write, do_mkwrite = false;\n"
+ " \tint ret;\n"
+ " \n"
+ " \tptl = __pmd_trans_huge_lock(pmd, vma);\n"
+ "@@ -1857,6 +1858,31 @@ int change_huge_pmd(struct vm_area_struct *vma, pmd_t *pmd,\n"
+ " \tpreserve_write = prot_numa && pmd_write(*pmd);\n"
+ " \tret = 1;\n"
+ " \n"
+ "+\tif (mkwrite && pmd_present(*pmd) && !pmd_write(*pmd)) {\n"
+ "+\t\tstruct page *page = pmd_page(pmd);\n"
+ "+\t\tpmd_t orig_pmd = READ_ONCE(pmd);\n"
+ "+\n"
+ "+\t\tVM_BUG_ON_PAGE(!PageCompound(page) || !PageHead(page), page);\n"
+ "+\t\t/*\n"
+ "+\t\t * We can only allow mkwrite if nobody else maps the huge page\n"
+ "+\t\t * or it's part.\n"
+ "+\t\t */\n"
+ "+\t\tif (!trylock_page(page)) {\n"
+ "+\t\t\tget_page(page);\n"
+ "+\t\t\tspin_unlock(ptl);\n"
+ "+\t\t\tlock_page(page);\n"
+ "+\n"
+ "+\t\t\tptl = __pmd_trans_huge_lock(pmd, vma);\n"
+ "+\t\t\tif (!ptl)\n"
+ "+\t\t\t\treturn 0;\n"
+ "+\t\t}\n"
+ "+\t\tif (pmd_same(*pmd, orig_pmd) && reuse_swap_page(page, NULL)) {\n"
+ "+\t\t\tdo_mkwrite = true;\n"
+ "+\t\t}\n"
+ "+\t\tunlock_page(page);\n"
+ "+\t\tput_page(page);\n"
+ "+\t}\n"
+ "+\n"
+ " #ifdef CONFIG_ARCH_ENABLE_THP_MIGRATION\n"
+ " \tif (is_swap_pmd(*pmd)) {\n"
+ " \t\tswp_entry_t entry = pmd_to_swp_entry(*pmd);\n"
+ "@@ -1925,6 +1951,8 @@ int change_huge_pmd(struct vm_area_struct *vma, pmd_t *pmd,\n"
+ " \tentry = pmd_modify(entry, newprot);\n"
+ " \tif (preserve_write)\n"
+ " \t\tentry = pmd_mk_savedwrite(entry);\n"
+ "+\tif (do_mkwrite)\n"
+ "+\t\tentry = pmd_mkwrite(entry);\n"
+ " \tret = HPAGE_PMD_NR;\n"
+ " \tset_pmd_at(mm, addr, pmd, entry);\n"
+ " \tBUG_ON(vma_is_anonymous(vma) && !preserve_write && pmd_write(entry));\n"
+ "diff --git a/mm/mempolicy.c b/mm/mempolicy.c\n"
+ "index 4ce44d3ff03d..2d0ee09e6b26 100644\n"
+ "--- a/mm/mempolicy.c\n"
+ "+++ b/mm/mempolicy.c\n"
+ "@@ -579,7 +579,7 @@ unsigned long change_prot_numa(struct vm_area_struct *vma,\n"
+ " {\n"
+ " \tint nr_updated;\n"
+ " \n"
+ "-\tnr_updated = change_protection(vma, addr, end, PAGE_NONE, 0, 1);\n"
+ "+\tnr_updated = change_protection(vma, addr, end, PAGE_NONE, 0, 1, false);\n"
+ " \tif (nr_updated)\n"
+ " \t\tcount_vm_numa_events(NUMA_PTE_UPDATES, nr_updated);\n"
+ " \n"
+ "diff --git a/mm/mprotect.c b/mm/mprotect.c\n"
+ "index 58b629bb70de..c43a29eebdaf 100644\n"
+ "--- a/mm/mprotect.c\n"
+ "+++ b/mm/mprotect.c\n"
+ "@@ -36,7 +36,7 @@\n"
+ " \n"
+ " static unsigned long change_pte_range(struct vm_area_struct *vma, pmd_t *pmd,\n"
+ " \t\tunsigned long addr, unsigned long end, pgprot_t newprot,\n"
+ "-\t\tint dirty_accountable, int prot_numa)\n"
+ "+\t\tint dirty_accountable, int prot_numa, bool mkwrite)\n"
+ " {\n"
+ " \tstruct mm_struct *mm = vma->vm_mm;\n"
+ " \tpte_t *pte, oldpte;\n"
+ "@@ -72,13 +72,15 @@ static unsigned long change_pte_range(struct vm_area_struct *vma, pmd_t *pmd,\n"
+ " \t\tif (pte_present(oldpte)) {\n"
+ " \t\t\tpte_t ptent;\n"
+ " \t\t\tbool preserve_write = prot_numa && pte_write(oldpte);\n"
+ "+\t\t\tbool do_mkwrite = false;\n"
+ " \n"
+ " \t\t\t/*\n"
+ " \t\t\t * Avoid trapping faults against the zero or KSM\n"
+ " \t\t\t * pages. See similar comment in change_huge_pmd.\n"
+ " \t\t\t */\n"
+ "-\t\t\tif (prot_numa) {\n"
+ "+\t\t\tif (prot_numa || mkwrite) {\n"
+ " \t\t\t\tstruct page *page;\n"
+ "+\t\t\t\tint tmp;\n"
+ " \n"
+ " \t\t\t\tpage = vm_normal_page(vma, addr, oldpte);\n"
+ " \t\t\t\tif (!page || PageKsm(page))\n"
+ "@@ -94,6 +96,26 @@ static unsigned long change_pte_range(struct vm_area_struct *vma, pmd_t *pmd,\n"
+ " \t\t\t\t */\n"
+ " \t\t\t\tif (target_node == page_to_nid(page))\n"
+ " \t\t\t\t\tcontinue;\n"
+ "+\n"
+ "+\t\t\t\tif (mkwrite) {\n"
+ "+\t\t\t\t\tif (!trylock_page(page)) {\n"
+ "+\t\t\t\t\t\tpte_t orig_pte = READ_ONCE(pte);\n"
+ "+\t\t\t\t\t\tget_page(page);\n"
+ "+\t\t\t\t\t\tpte_unmap_unlock(pte, ptl);\n"
+ "+\t\t\t\t\t\tlock_page(page);\n"
+ "+\t\t\t\t\t\tpte = pte_offset_map_lock(vma->vm_mm, pmd,\n"
+ "+\t\t\t\t\t\t\t\t\t  addr, &ptl);\n"
+ "+\t\t\t\t\t\tif (!pte_same(*pte, orig_pte)) {\n"
+ "+\t\t\t\t\t\t\tunlock_page(page);\n"
+ "+\t\t\t\t\t\t\tput_page(page);\n"
+ "+\t\t\t\t\t\t\tcontinue;\n"
+ "+\t\t\t\t\t\t}\n"
+ "+\t\t\t\t\t}\n"
+ "+\t\t\t\t\tif (reuse_swap_page(vmf->page, &tmp))\n"
+ "+\t\t\t\t\t\tdo_mkwrite = true;\n"
+ "+\t\t\t\t\tunlock_page(page);\n"
+ "+\t\t\t\t\tput_page(page);\n"
+ "+\t\t\t\t}\n"
+ " \t\t\t}\n"
+ " \n"
+ " \t\t\tptent = ptep_modify_prot_start(mm, addr, pte);\n"
+ "@@ -102,9 +124,9 @@ static unsigned long change_pte_range(struct vm_area_struct *vma, pmd_t *pmd,\n"
+ " \t\t\t\tptent = pte_mk_savedwrite(ptent);\n"
+ " \n"
+ " \t\t\t/* Avoid taking write faults for known dirty pages */\n"
+ "-\t\t\tif (dirty_accountable && pte_dirty(ptent) &&\n"
+ "-\t\t\t\t\t(pte_soft_dirty(ptent) ||\n"
+ "-\t\t\t\t\t !(vma->vm_flags & VM_SOFTDIRTY))) {\n"
+ "+\t\t\tif (do_mkwrite || (dirty_accountable &&\n"
+ "+\t\t\t    pte_dirty(ptent) && (pte_soft_dirty(ptent) ||\n"
+ "+\t\t\t    !(vma->vm_flags & VM_SOFTDIRTY)))) {\n"
+ " \t\t\t\tptent = pte_mkwrite(ptent);\n"
+ " \t\t\t}\n"
+ " \t\t\tptep_modify_prot_commit(mm, addr, pte, ptent);\n"
+ "@@ -150,7 +172,8 @@ static unsigned long change_pte_range(struct vm_area_struct *vma, pmd_t *pmd,\n"
+ " \n"
+ " static inline unsigned long change_pmd_range(struct vm_area_struct *vma,\n"
+ " \t\tpud_t *pud, unsigned long addr, unsigned long end,\n"
+ "-\t\tpgprot_t newprot, int dirty_accountable, int prot_numa)\n"
+ "+\t\tpgprot_t newprot, int dirty_accountable, int prot_numa,\n"
+ "+\t\tbool mkwrite)\n"
+ " {\n"
+ " \tpmd_t *pmd;\n"
+ " \tstruct mm_struct *mm = vma->vm_mm;\n"
+ "@@ -179,7 +202,7 @@ static inline unsigned long change_pmd_range(struct vm_area_struct *vma,\n"
+ " \t\t\t\t__split_huge_pmd(vma, pmd, addr, false, NULL);\n"
+ " \t\t\t} else {\n"
+ " \t\t\t\tint nr_ptes = change_huge_pmd(vma, pmd, addr,\n"
+ "-\t\t\t\t\t\tnewprot, prot_numa);\n"
+ "+\t\t\t\t\t\tnewprot, prot_numa, mkwrite);\n"
+ " \n"
+ " \t\t\t\tif (nr_ptes) {\n"
+ " \t\t\t\t\tif (nr_ptes == HPAGE_PMD_NR) {\n"
+ "@@ -194,7 +217,7 @@ static inline unsigned long change_pmd_range(struct vm_area_struct *vma,\n"
+ " \t\t\t/* fall through, the trans huge pmd just split */\n"
+ " \t\t}\n"
+ " \t\tthis_pages = change_pte_range(vma, pmd, addr, next, newprot,\n"
+ "-\t\t\t\t dirty_accountable, prot_numa);\n"
+ "+\t\t\t\t dirty_accountable, prot_numa, mkwrite);\n"
+ " \t\tpages += this_pages;\n"
+ " next:\n"
+ " \t\tcond_resched();\n"
+ "@@ -210,7 +233,8 @@ static inline unsigned long change_pmd_range(struct vm_area_struct *vma,\n"
+ " \n"
+ " static inline unsigned long change_pud_range(struct vm_area_struct *vma,\n"
+ " \t\tp4d_t *p4d, unsigned long addr, unsigned long end,\n"
+ "-\t\tpgprot_t newprot, int dirty_accountable, int prot_numa)\n"
+ "+\t\tpgprot_t newprot, int dirty_accountable, int prot_numa,\n"
+ "+\t\tbool mkwrite)\n"
+ " {\n"
+ " \tpud_t *pud;\n"
+ " \tunsigned long next;\n"
+ "@@ -222,7 +246,7 @@ static inline unsigned long change_pud_range(struct vm_area_struct *vma,\n"
+ " \t\tif (pud_none_or_clear_bad(pud))\n"
+ " \t\t\tcontinue;\n"
+ " \t\tpages += change_pmd_range(vma, pud, addr, next, newprot,\n"
+ "-\t\t\t\t dirty_accountable, prot_numa);\n"
+ "+\t\t\t\t dirty_accountable, prot_numa, mkwrite);\n"
+ " \t} while (pud++, addr = next, addr != end);\n"
+ " \n"
+ " \treturn pages;\n"
+ "@@ -230,7 +254,8 @@ static inline unsigned long change_pud_range(struct vm_area_struct *vma,\n"
+ " \n"
+ " static inline unsigned long change_p4d_range(struct vm_area_struct *vma,\n"
+ " \t\tpgd_t *pgd, unsigned long addr, unsigned long end,\n"
+ "-\t\tpgprot_t newprot, int dirty_accountable, int prot_numa)\n"
+ "+\t\tpgprot_t newprot, int dirty_accountable, int prot_numa,\n"
+ "+\t\tbool mkwrite)\n"
+ " {\n"
+ " \tp4d_t *p4d;\n"
+ " \tunsigned long next;\n"
+ "@@ -242,7 +267,7 @@ static inline unsigned long change_p4d_range(struct vm_area_struct *vma,\n"
+ " \t\tif (p4d_none_or_clear_bad(p4d))\n"
+ " \t\t\tcontinue;\n"
+ " \t\tpages += change_pud_range(vma, p4d, addr, next, newprot,\n"
+ "-\t\t\t\t dirty_accountable, prot_numa);\n"
+ "+\t\t\t\t dirty_accountable, prot_numa, mkwrite);\n"
+ " \t} while (p4d++, addr = next, addr != end);\n"
+ " \n"
+ " \treturn pages;\n"
+ "@@ -250,7 +275,7 @@ static inline unsigned long change_p4d_range(struct vm_area_struct *vma,\n"
+ " \n"
+ " static unsigned long change_protection_range(struct vm_area_struct *vma,\n"
+ " \t\tunsigned long addr, unsigned long end, pgprot_t newprot,\n"
+ "-\t\tint dirty_accountable, int prot_numa)\n"
+ "+\t\tint dirty_accountable, int prot_numa, mkwrite)\n"
+ " {\n"
+ " \tstruct mm_struct *mm = vma->vm_mm;\n"
+ " \tpgd_t *pgd;\n"
+ "@@ -267,7 +292,7 @@ static unsigned long change_protection_range(struct vm_area_struct *vma,\n"
+ " \t\tif (pgd_none_or_clear_bad(pgd))\n"
+ " \t\t\tcontinue;\n"
+ " \t\tpages += change_p4d_range(vma, pgd, addr, next, newprot,\n"
+ "-\t\t\t\t dirty_accountable, prot_numa);\n"
+ "+\t\t\t\t dirty_accountable, prot_numa, mkwrite);\n"
+ " \t} while (pgd++, addr = next, addr != end);\n"
+ " \n"
+ " \t/* Only flush the TLB if we actually modified any entries: */\n"
+ "@@ -280,14 +305,16 @@ static unsigned long change_protection_range(struct vm_area_struct *vma,\n"
+ " \n"
+ " unsigned long change_protection(struct vm_area_struct *vma, unsigned long start,\n"
+ " \t\t       unsigned long end, pgprot_t newprot,\n"
+ "-\t\t       int dirty_accountable, int prot_numa)\n"
+ "+\t\t       int dirty_accountable, int prot_numa, bool mkwrite)\n"
+ " {\n"
+ " \tunsigned long pages;\n"
+ " \n"
+ " \tif (is_vm_hugetlb_page(vma))\n"
+ " \t\tpages = hugetlb_change_protection(vma, start, end, newprot);\n"
+ " \telse\n"
+ "-\t\tpages = change_protection_range(vma, start, end, newprot, dirty_accountable, prot_numa);\n"
+ "+\t\tpages = change_protection_range(vma, start, end, newprot,\n"
+ "+\t\t\t\t\t\tdirty_accountable,\n"
+ "+\t\t\t\t\t\tprot_numa, mkwrite);\n"
+ " \n"
+ " \treturn pages;\n"
+ " }\n"
+ "@@ -366,7 +393,7 @@ mprotect_fixup(struct vm_area_struct *vma, struct vm_area_struct **pprev,\n"
+ " \tvma_set_page_prot(vma);\n"
+ " \n"
+ " \tchange_protection(vma, start, end, vma->vm_page_prot,\n"
+ "-\t\t\t  dirty_accountable, 0);\n"
+ "+\t\t\t  dirty_accountable, 0, false);\n"
+ " \n"
+ " \t/*\n"
+ " \t * Private VM_LOCKED VMA becoming writable: trigger COW to avoid major\n"
+ "diff --git a/mm/userfaultfd.c b/mm/userfaultfd.c\n"
+ "index a0379c5ffa7c..c745c5d87523 100644\n"
+ "--- a/mm/userfaultfd.c\n"
+ "+++ b/mm/userfaultfd.c\n"
+ "@@ -632,7 +632,7 @@ int mwriteprotect_range(struct mm_struct *dst_mm, unsigned long start,\n"
+ " \t\tnewprot = vm_get_page_prot(dst_vma->vm_flags);\n"
+ " \n"
+ " \tchange_protection(dst_vma, start, start + len, newprot,\n"
+ "-\t\t\t\t!enable_wp, 0);\n"
+ "+\t\t\t  0, 0, !enable_wp);\n"
+ " \n"
+ " \terr = 0;\n"
+ " out_unlock:\n"
+ "-- \n"
+ 2.17.1
 
-85ef336d1c3e8959076ad62ca244c35ebf995f629d4cf94e09d9ae63b40af24b
+14cd730c845176d658f29e84968d096c8cb3203c673164a0e213f8f473e2fd8b

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.