|
@@ -149,12 +149,20 @@ static inline pte_t pte_mkwrite(pte_t pte)
|
|
|
|
|
|
static inline pte_t pte_mkclean(pte_t pte)
|
|
static inline pte_t pte_mkclean(pte_t pte)
|
|
{
|
|
{
|
|
- return clear_pte_bit(pte, __pgprot(PTE_DIRTY));
|
|
|
|
|
|
+ pte = clear_pte_bit(pte, __pgprot(PTE_DIRTY));
|
|
|
|
+ pte = set_pte_bit(pte, __pgprot(PTE_RDONLY));
|
|
|
|
+
|
|
|
|
+ return pte;
|
|
}
|
|
}
|
|
|
|
|
|
static inline pte_t pte_mkdirty(pte_t pte)
|
|
static inline pte_t pte_mkdirty(pte_t pte)
|
|
{
|
|
{
|
|
- return set_pte_bit(pte, __pgprot(PTE_DIRTY));
|
|
|
|
|
|
+ pte = set_pte_bit(pte, __pgprot(PTE_DIRTY));
|
|
|
|
+
|
|
|
|
+ if (pte_write(pte))
|
|
|
|
+ pte = clear_pte_bit(pte, __pgprot(PTE_RDONLY));
|
|
|
|
+
|
|
|
|
+ return pte;
|
|
}
|
|
}
|
|
|
|
|
|
static inline pte_t pte_mkold(pte_t pte)
|
|
static inline pte_t pte_mkold(pte_t pte)
|
|
@@ -641,28 +649,23 @@ static inline pmd_t pmdp_huge_get_and_clear(struct mm_struct *mm,
|
|
#endif /* CONFIG_TRANSPARENT_HUGEPAGE */
|
|
#endif /* CONFIG_TRANSPARENT_HUGEPAGE */
|
|
|
|
|
|
/*
|
|
/*
|
|
- * ptep_set_wrprotect - mark read-only while preserving the hardware update of
|
|
|
|
- * the Access Flag.
|
|
|
|
|
|
+ * ptep_set_wrprotect - mark read-only while trasferring potential hardware
|
|
|
|
+ * dirty status (PTE_DBM && !PTE_RDONLY) to the software PTE_DIRTY bit.
|
|
*/
|
|
*/
|
|
#define __HAVE_ARCH_PTEP_SET_WRPROTECT
|
|
#define __HAVE_ARCH_PTEP_SET_WRPROTECT
|
|
static inline void ptep_set_wrprotect(struct mm_struct *mm, unsigned long address, pte_t *ptep)
|
|
static inline void ptep_set_wrprotect(struct mm_struct *mm, unsigned long address, pte_t *ptep)
|
|
{
|
|
{
|
|
pte_t old_pte, pte;
|
|
pte_t old_pte, pte;
|
|
|
|
|
|
- /*
|
|
|
|
- * ptep_set_wrprotect() is only called on CoW mappings which are
|
|
|
|
- * private (!VM_SHARED) with the pte either read-only (!PTE_WRITE &&
|
|
|
|
- * PTE_RDONLY) or writable and software-dirty (PTE_WRITE &&
|
|
|
|
- * !PTE_RDONLY && PTE_DIRTY); see is_cow_mapping() and
|
|
|
|
- * protection_map[]. There is no race with the hardware update of the
|
|
|
|
- * dirty state: clearing of PTE_RDONLY when PTE_WRITE (a.k.a. PTE_DBM)
|
|
|
|
- * is set.
|
|
|
|
- */
|
|
|
|
- VM_WARN_ONCE(pte_write(*ptep) && !pte_dirty(*ptep),
|
|
|
|
- "%s: potential race with hardware DBM", __func__);
|
|
|
|
pte = READ_ONCE(*ptep);
|
|
pte = READ_ONCE(*ptep);
|
|
do {
|
|
do {
|
|
old_pte = pte;
|
|
old_pte = pte;
|
|
|
|
+ /*
|
|
|
|
+ * If hardware-dirty (PTE_WRITE/DBM bit set and PTE_RDONLY
|
|
|
|
+ * clear), set the PTE_DIRTY bit.
|
|
|
|
+ */
|
|
|
|
+ if (pte_hw_dirty(pte))
|
|
|
|
+ pte = pte_mkdirty(pte);
|
|
pte = pte_wrprotect(pte);
|
|
pte = pte_wrprotect(pte);
|
|
pte_val(pte) = cmpxchg_relaxed(&pte_val(*ptep),
|
|
pte_val(pte) = cmpxchg_relaxed(&pte_val(*ptep),
|
|
pte_val(old_pte), pte_val(pte));
|
|
pte_val(old_pte), pte_val(pte));
|