mirror of https://gitee.com/openkylin/linux.git
arm64: pgtable: Ensure dirty bit is preserved across pte_wrprotect()
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: <stable@vger.kernel.org>
Fixes: 2f4b829c62
("arm64: Add support for hardware updates of the access and dirty pte bits")
Reviewed-by: Catalin Marinas <catalin.marinas@arm.com>
Link: https://lore.kernel.org/r/20201120143557.6715-3-will@kernel.org
Signed-off-by: Will Deacon <will@kernel.org>
This commit is contained in:
parent
07509e10dc
commit
ff1712f953
|
@ -165,13 +165,6 @@ static inline pmd_t set_pmd_bit(pmd_t pmd, pgprot_t prot)
|
||||||
return pmd;
|
return pmd;
|
||||||
}
|
}
|
||||||
|
|
||||||
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)
|
static inline pte_t pte_mkwrite(pte_t pte)
|
||||||
{
|
{
|
||||||
pte = set_pte_bit(pte, __pgprot(PTE_WRITE));
|
pte = set_pte_bit(pte, __pgprot(PTE_WRITE));
|
||||||
|
@ -197,6 +190,20 @@ static inline pte_t pte_mkdirty(pte_t pte)
|
||||||
return pte;
|
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)
|
static inline pte_t pte_mkold(pte_t pte)
|
||||||
{
|
{
|
||||||
return clear_pte_bit(pte, __pgprot(PTE_AF));
|
return clear_pte_bit(pte, __pgprot(PTE_AF));
|
||||||
|
@ -846,12 +853,6 @@ static inline void ptep_set_wrprotect(struct mm_struct *mm, unsigned long addres
|
||||||
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));
|
||||||
|
|
Loading…
Reference in New Issue