diff options
Diffstat (limited to 'mm/mprotect.c')
-rw-r--r-- | mm/mprotect.c | 13 |
1 files changed, 11 insertions, 2 deletions
diff --git a/mm/mprotect.c b/mm/mprotect.c index 26667971c824..bb53a6591aea 100644 --- a/mm/mprotect.c +++ b/mm/mprotect.c | |||
@@ -52,17 +52,21 @@ static unsigned long change_pte_range(struct vm_area_struct *vma, pmd_t *pmd, | |||
52 | pte_t ptent; | 52 | pte_t ptent; |
53 | bool updated = false; | 53 | bool updated = false; |
54 | 54 | ||
55 | ptent = ptep_modify_prot_start(mm, addr, pte); | ||
56 | if (!prot_numa) { | 55 | if (!prot_numa) { |
56 | ptent = ptep_modify_prot_start(mm, addr, pte); | ||
57 | if (pte_numa(ptent)) | ||
58 | ptent = pte_mknonnuma(ptent); | ||
57 | ptent = pte_modify(ptent, newprot); | 59 | ptent = pte_modify(ptent, newprot); |
58 | updated = true; | 60 | updated = true; |
59 | } else { | 61 | } else { |
60 | struct page *page; | 62 | struct page *page; |
61 | 63 | ||
64 | ptent = *pte; | ||
62 | page = vm_normal_page(vma, addr, oldpte); | 65 | page = vm_normal_page(vma, addr, oldpte); |
63 | if (page) { | 66 | if (page) { |
64 | if (!pte_numa(oldpte)) { | 67 | if (!pte_numa(oldpte)) { |
65 | ptent = pte_mknuma(ptent); | 68 | ptent = pte_mknuma(ptent); |
69 | set_pte_at(mm, addr, pte, ptent); | ||
66 | updated = true; | 70 | updated = true; |
67 | } | 71 | } |
68 | } | 72 | } |
@@ -79,7 +83,10 @@ static unsigned long change_pte_range(struct vm_area_struct *vma, pmd_t *pmd, | |||
79 | 83 | ||
80 | if (updated) | 84 | if (updated) |
81 | pages++; | 85 | pages++; |
82 | ptep_modify_prot_commit(mm, addr, pte, ptent); | 86 | |
87 | /* Only !prot_numa always clears the pte */ | ||
88 | if (!prot_numa) | ||
89 | ptep_modify_prot_commit(mm, addr, pte, ptent); | ||
83 | } else if (IS_ENABLED(CONFIG_MIGRATION) && !pte_file(oldpte)) { | 90 | } else if (IS_ENABLED(CONFIG_MIGRATION) && !pte_file(oldpte)) { |
84 | swp_entry_t entry = pte_to_swp_entry(oldpte); | 91 | swp_entry_t entry = pte_to_swp_entry(oldpte); |
85 | 92 | ||
@@ -181,6 +188,7 @@ static unsigned long change_protection_range(struct vm_area_struct *vma, | |||
181 | BUG_ON(addr >= end); | 188 | BUG_ON(addr >= end); |
182 | pgd = pgd_offset(mm, addr); | 189 | pgd = pgd_offset(mm, addr); |
183 | flush_cache_range(vma, addr, end); | 190 | flush_cache_range(vma, addr, end); |
191 | set_tlb_flush_pending(mm); | ||
184 | do { | 192 | do { |
185 | next = pgd_addr_end(addr, end); | 193 | next = pgd_addr_end(addr, end); |
186 | if (pgd_none_or_clear_bad(pgd)) | 194 | if (pgd_none_or_clear_bad(pgd)) |
@@ -192,6 +200,7 @@ static unsigned long change_protection_range(struct vm_area_struct *vma, | |||
192 | /* Only flush the TLB if we actually modified any entries: */ | 200 | /* Only flush the TLB if we actually modified any entries: */ |
193 | if (pages) | 201 | if (pages) |
194 | flush_tlb_range(vma, start, end); | 202 | flush_tlb_range(vma, start, end); |
203 | clear_tlb_flush_pending(mm); | ||
195 | 204 | ||
196 | return pages; | 205 | return pages; |
197 | } | 206 | } |