aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/asm-generic/pgtable.h57
-rw-r--r--mm/mprotect.c10
2 files changed, 61 insertions, 6 deletions
diff --git a/include/asm-generic/pgtable.h b/include/asm-generic/pgtable.h
index 44ef329531c3..4fce3db2cecc 100644
--- a/include/asm-generic/pgtable.h
+++ b/include/asm-generic/pgtable.h
@@ -197,6 +197,63 @@ static inline int pmd_none_or_clear_bad(pmd_t *pmd)
197} 197}
198#endif /* CONFIG_MMU */ 198#endif /* CONFIG_MMU */
199 199
200static inline pte_t __ptep_modify_prot_start(struct mm_struct *mm,
201 unsigned long addr,
202 pte_t *ptep)
203{
204 /*
205 * Get the current pte state, but zero it out to make it
206 * non-present, preventing the hardware from asynchronously
207 * updating it.
208 */
209 return ptep_get_and_clear(mm, addr, ptep);
210}
211
212static inline void __ptep_modify_prot_commit(struct mm_struct *mm,
213 unsigned long addr,
214 pte_t *ptep, pte_t pte)
215{
216 /*
217 * The pte is non-present, so there's no hardware state to
218 * preserve.
219 */
220 set_pte_at(mm, addr, ptep, pte);
221}
222
223#ifndef __HAVE_ARCH_PTEP_MODIFY_PROT_TRANSACTION
224/*
225 * Start a pte protection read-modify-write transaction, which
226 * protects against asynchronous hardware modifications to the pte.
227 * The intention is not to prevent the hardware from making pte
228 * updates, but to prevent any updates it may make from being lost.
229 *
230 * This does not protect against other software modifications of the
231 * pte; the appropriate pte lock must be held over the transation.
232 *
233 * Note that this interface is intended to be batchable, meaning that
234 * ptep_modify_prot_commit may not actually update the pte, but merely
235 * queue the update to be done at some later time. The update must be
236 * actually committed before the pte lock is released, however.
237 */
238static inline pte_t ptep_modify_prot_start(struct mm_struct *mm,
239 unsigned long addr,
240 pte_t *ptep)
241{
242 return __ptep_modify_prot_start(mm, addr, ptep);
243}
244
245/*
246 * Commit an update to a pte, leaving any hardware-controlled bits in
247 * the PTE unmodified.
248 */
249static inline void ptep_modify_prot_commit(struct mm_struct *mm,
250 unsigned long addr,
251 pte_t *ptep, pte_t pte)
252{
253 __ptep_modify_prot_commit(mm, addr, ptep, pte);
254}
255#endif /* __HAVE_ARCH_PTEP_MODIFY_PROT_TRANSACTION */
256
200/* 257/*
201 * A facility to provide lazy MMU batching. This allows PTE updates and 258 * A facility to provide lazy MMU batching. This allows PTE updates and
202 * page invalidations to be delayed until a call to leave lazy MMU mode 259 * page invalidations to be delayed until a call to leave lazy MMU mode
diff --git a/mm/mprotect.c b/mm/mprotect.c
index a5bf31c27375..acfe7c8d72fc 100644
--- a/mm/mprotect.c
+++ b/mm/mprotect.c
@@ -47,19 +47,17 @@ static void change_pte_range(struct mm_struct *mm, pmd_t *pmd,
47 if (pte_present(oldpte)) { 47 if (pte_present(oldpte)) {
48 pte_t ptent; 48 pte_t ptent;
49 49
50 /* Avoid an SMP race with hardware updated dirty/clean 50 ptent = ptep_modify_prot_start(mm, addr, pte);
51 * bits by wiping the pte and then setting the new pte
52 * into place.
53 */
54 ptent = ptep_get_and_clear(mm, addr, pte);
55 ptent = pte_modify(ptent, newprot); 51 ptent = pte_modify(ptent, newprot);
52
56 /* 53 /*
57 * Avoid taking write faults for pages we know to be 54 * Avoid taking write faults for pages we know to be
58 * dirty. 55 * dirty.
59 */ 56 */
60 if (dirty_accountable && pte_dirty(ptent)) 57 if (dirty_accountable && pte_dirty(ptent))
61 ptent = pte_mkwrite(ptent); 58 ptent = pte_mkwrite(ptent);
62 set_pte_at(mm, addr, pte, ptent); 59
60 ptep_modify_prot_commit(mm, addr, pte, ptent);
63#ifdef CONFIG_MIGRATION 61#ifdef CONFIG_MIGRATION
64 } else if (!pte_file(oldpte)) { 62 } else if (!pte_file(oldpte)) {
65 swp_entry_t entry = pte_to_swp_entry(oldpte); 63 swp_entry_t entry = pte_to_swp_entry(oldpte);