From: Will Deacon <w...@kernel.org>

commit ff1712f953e27f0b0718762ec17d0adb15c9fd0b upstream.

With hardware dirty bit management, calling pte_wrprotect() on a writable,
dirty PTE will lose the dirty state and return a read-only, clean entry.

Move the logic from ptep_set_wrprotect() into pte_wrprotect() to ensure that
the dirty bit is preserved for writable entries, as this is required for
soft-dirty bit management if we enable it in the future.

Cc: <sta...@vger.kernel.org>
Fixes: 2f4b829c625e ("arm64: Add support for hardware updates of the access and 
dirty pte bits")
Reviewed-by: Catalin Marinas <catalin.mari...@arm.com>
Link: https://lore.kernel.org/r/20201120143557.6715-3-w...@kernel.org
Signed-off-by: Will Deacon <w...@kernel.org>
Signed-off-by: Greg Kroah-Hartman <gre...@linuxfoundation.org>

---
 arch/arm64/include/asm/pgtable.h |   27 ++++++++++++++-------------
 1 file changed, 14 insertions(+), 13 deletions(-)

--- a/arch/arm64/include/asm/pgtable.h
+++ b/arch/arm64/include/asm/pgtable.h
@@ -146,13 +146,6 @@ static inline pte_t set_pte_bit(pte_t pt
        return pte;
 }
 
-static inline pte_t pte_wrprotect(pte_t pte)
-{
-       pte = clear_pte_bit(pte, __pgprot(PTE_WRITE));
-       pte = set_pte_bit(pte, __pgprot(PTE_RDONLY));
-       return pte;
-}
-
 static inline pte_t pte_mkwrite(pte_t pte)
 {
        pte = set_pte_bit(pte, __pgprot(PTE_WRITE));
@@ -178,6 +171,20 @@ static inline pte_t pte_mkdirty(pte_t pt
        return pte;
 }
 
+static inline pte_t pte_wrprotect(pte_t 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 = clear_pte_bit(pte, __pgprot(PTE_WRITE));
+       pte = set_pte_bit(pte, __pgprot(PTE_RDONLY));
+       return pte;
+}
+
 static inline pte_t pte_mkold(pte_t pte)
 {
        return clear_pte_bit(pte, __pgprot(PTE_AF));
@@ -799,12 +806,6 @@ static inline void ptep_set_wrprotect(st
        pte = READ_ONCE(*ptep);
        do {
                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_val(pte) = cmpxchg_relaxed(&pte_val(*ptep),
                                               pte_val(old_pte), pte_val(pte));


Reply via email to