• David Hildenbrand's avatar
    mm/userfaultfd: rely on vma->vm_page_prot in uffd_wp_range() · 931298e1
    David Hildenbrand authored
    Patch series "mm: uffd-wp + change_protection() cleanups".
    
    Cleanup page protection handling in uffd-wp when calling
    change_protection() and improve unprotecting uffd=wp in private mappings,
    trying to set PTEs writable again if possible just like we do during
    mprotect() when upgrading write permissions.  Make the change_protection()
    interface harder to get wrong :)
    
    I consider both pages primarily cleanups, although patch #1 fixes a corner
    case with uffd-wp and softdirty tracking for shmem.  @Peter, please let me
    know if we should flag patch #1 as pure cleanup -- I have no idea how
    important softdirty tracking on shmem is.
    
    
    This patch (of 2):
    
    uffd_wp_range() currently calculates page protection manually using
    vm_get_page_prot().  This will ignore any other reason for active
    writenotify: one mechanism applicable to shmem is softdirty tracking.
    
    For example, the following sequence
    
    1) Write to mapped shmem page
    2) Clear softdirty
    3) Register uffd-wp covering the mapped page
    4) Unregister uffd-wp covering the mapped page
    5) Write to page again
    
    will not set the modified page softdirty, because uffd_wp_range() will
    ignore that writenotify is required for softdirty tracking and simply map
    the page writable again using change_protection().  Similarly, instead of
    unregistering, protecting followed by un-protecting the page using uffd-wp
    would result in the same situation.
    
    Now that we enable writenotify whenever enabling uffd-wp on a VMA,
    vma->vm_page_prot will already properly reflect our requirements: the
    default is to write-protect all PTEs.  However, for shared mappings we
    would now not remap the PTEs writable if possible when unprotecting, just
    like for private mappings (COW).  To compensate, set
    MM_CP_TRY_CHANGE_WRITABLE just like mprotect() does to try mapping
    individual PTEs writable.
    
    For private mappings, this change implies that we will now always try
    setting PTEs writable when un-protecting, just like when upgrading write
    permissions using mprotect(), which is an improvement.
    
    For shared mappings, we will only set PTEs writable if
    can_change_pte_writable()/can_change_pmd_writable() indicates that it's
    ok.  For ordinary shmem, this will be the case when PTEs are dirty, which
    should usually be the case -- otherwise we could special-case shmem in
    can_change_pte_writable()/can_change_pmd_writable() easily, because shmem
    itself doesn't require writenotify.
    
    Note that hugetlb does not yet implement MM_CP_TRY_CHANGE_WRITABLE, so we
    won't try setting PTEs writable when unprotecting or when unregistering
    uffd-wp.  This can be added later on top by implementing
    MM_CP_TRY_CHANGE_WRITABLE.
    
    While commit ffd05793 ("userfaultfd: wp: support write protection for
    userfault vma range") introduced that code, it should only be applicable
    to uffd-wp on shared mappings -- shmem (hugetlb does not support softdirty
    tracking).  I don't think this corner cases justifies to cc stable.  Let's
    just handle it correctly and prepare for change_protection() cleanups.
    
    [david@redhat.com: o need for additional harmless checks if we're wr-protecting either way]
      Link: https://lkml.kernel.org/r/71412742-a71f-9c74-865f-773ad83db7a5@redhat.com
    Link: https://lkml.kernel.org/r/20221223155616.297723-1-david@redhat.com
    Link: https://lkml.kernel.org/r/20221223155616.297723-2-david@redhat.com
    Fixes: b1f9e876 ("mm/uffd: enable write protection for shmem & hugetlbfs")
    Signed-off-by: default avatarDavid Hildenbrand <david@redhat.com>
    Cc: Andrea Arcangeli <aarcange@redhat.com>
    Cc: Hugh Dickins <hughd@google.com>
    Cc: Nadav Amit <nadav.amit@gmail.com>
    Cc: Peter Xu <peterx@redhat.com>
    Signed-off-by: default avatarAndrew Morton <akpm@linux-foundation.org>
    931298e1
userfaultfd.c 19.7 KB