lkml.org 
[lkml]   [2021]   [Mar]   [1]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    From
    Subject[PATCH 5.11 247/775] mm: proc: Invalidate TLB after clearing soft-dirty page state
    Date
    From: Will Deacon <will@kernel.org>

    [ Upstream commit 912efa17e5121693dfbadae29768f4144a3f9e62 ]

    Since commit 0758cd830494 ("asm-generic/tlb: avoid potential double
    flush"), TLB invalidation is elided in tlb_finish_mmu() if no entries
    were batched via the tlb_remove_*() functions. Consequently, the
    page-table modifications performed by clear_refs_write() in response to
    a write to /proc/<pid>/clear_refs do not perform TLB invalidation.
    Although this is fine when simply aging the ptes, in the case of
    clearing the "soft-dirty" state we can end up with entries where
    pte_write() is false, yet a writable mapping remains in the TLB.

    Fix this by avoiding the mmu_gather API altogether: managing both the
    'tlb_flush_pending' flag on the 'mm_struct' and explicit TLB
    invalidation for the sort-dirty path, much like mprotect() does already.

    Fixes: 0758cd830494 ("asm-generic/tlb: avoid potential double flush”)
    Signed-off-by: Will Deacon <will@kernel.org>
    Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org>
    Reviewed-by: Yu Zhao <yuzhao@google.com>
    Acked-by: Peter Zijlstra (Intel) <peterz@infradead.org>
    Acked-by: Linus Torvalds <torvalds@linux-foundation.org>
    Link: https://lkml.kernel.org/r/20210127235347.1402-2-will@kernel.org
    Signed-off-by: Sasha Levin <sashal@kernel.org>
    ---
    fs/proc/task_mmu.c | 9 +++++----
    1 file changed, 5 insertions(+), 4 deletions(-)

    diff --git a/fs/proc/task_mmu.c b/fs/proc/task_mmu.c
    index 602e3a52884d8..3cec6fbef725e 100644
    --- a/fs/proc/task_mmu.c
    +++ b/fs/proc/task_mmu.c
    @@ -1210,7 +1210,6 @@ static ssize_t clear_refs_write(struct file *file, const char __user *buf,
    struct mm_struct *mm;
    struct vm_area_struct *vma;
    enum clear_refs_types type;
    - struct mmu_gather tlb;
    int itype;
    int rv;

    @@ -1249,7 +1248,6 @@ static ssize_t clear_refs_write(struct file *file, const char __user *buf,
    goto out_unlock;
    }

    - tlb_gather_mmu(&tlb, mm, 0, -1);
    if (type == CLEAR_REFS_SOFT_DIRTY) {
    for (vma = mm->mmap; vma; vma = vma->vm_next) {
    if (!(vma->vm_flags & VM_SOFTDIRTY))
    @@ -1258,15 +1256,18 @@ static ssize_t clear_refs_write(struct file *file, const char __user *buf,
    vma_set_page_prot(vma);
    }

    + inc_tlb_flush_pending(mm);
    mmu_notifier_range_init(&range, MMU_NOTIFY_SOFT_DIRTY,
    0, NULL, mm, 0, -1UL);
    mmu_notifier_invalidate_range_start(&range);
    }
    walk_page_range(mm, 0, mm->highest_vm_end, &clear_refs_walk_ops,
    &cp);
    - if (type == CLEAR_REFS_SOFT_DIRTY)
    + if (type == CLEAR_REFS_SOFT_DIRTY) {
    mmu_notifier_invalidate_range_end(&range);
    - tlb_finish_mmu(&tlb, 0, -1);
    + flush_tlb_mm(mm);
    + dec_tlb_flush_pending(mm);
    + }
    out_unlock:
    mmap_write_unlock(mm);
    out_mm:
    --
    2.27.0


    \
     
     \ /
      Last update: 2021-03-02 01:11    [W:2.648 / U:0.152 seconds]
    ©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site