lkml.org 
[lkml]   [2021]   [Jan]   [15]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    From
    Subject[PATCH RFC 27/30] hugetlb/userfaultfd: Allow wr-protect none ptes
    Date
    Teach hugetlbfs code to wr-protect none ptes just in case the page cache
    existed for that pte. Meanwhile we also need to be able to recognize a uffd-wp
    marker pte and remove it for uffd_wp_resolve.

    Since at it, introduce a variable "psize" to replace all references to the huge
    page size fetcher.

    Signed-off-by: Peter Xu <peterx@redhat.com>
    ---
    mm/hugetlb.c | 29 +++++++++++++++++++++++++----
    1 file changed, 25 insertions(+), 4 deletions(-)

    diff --git a/mm/hugetlb.c b/mm/hugetlb.c
    index 9b9f71ec30e1..7959fb4b1633 100644
    --- a/mm/hugetlb.c
    +++ b/mm/hugetlb.c
    @@ -4978,7 +4978,7 @@ unsigned long hugetlb_change_protection(struct vm_area_struct *vma,
    pte_t *ptep;
    pte_t pte;
    struct hstate *h = hstate_vma(vma);
    - unsigned long pages = 0;
    + unsigned long pages = 0, psize = huge_page_size(h);
    bool shared_pmd = false;
    struct mmu_notifier_range range;
    bool uffd_wp = cp_flags & MM_CP_UFFD_WP;
    @@ -4998,13 +4998,19 @@ unsigned long hugetlb_change_protection(struct vm_area_struct *vma,

    mmu_notifier_invalidate_range_start(&range);
    i_mmap_lock_write(vma->vm_file->f_mapping);
    - for (; address < end; address += huge_page_size(h)) {
    + for (; address < end; address += psize) {
    spinlock_t *ptl;
    - ptep = huge_pte_offset(mm, address, huge_page_size(h));
    + ptep = huge_pte_offset(mm, address, psize);
    if (!ptep)
    continue;
    ptl = huge_pte_lock(h, mm, ptep);
    if (huge_pmd_unshare(mm, vma, &address, ptep)) {
    + /*
    + * When uffd-wp is enabled on the vma, unshare
    + * shouldn't happen at all. Warn about it if it
    + * happened due to some reason.
    + */
    + WARN_ON_ONCE(uffd_wp || uffd_wp_resolve);
    pages++;
    spin_unlock(ptl);
    shared_pmd = true;
    @@ -5028,12 +5034,21 @@ unsigned long hugetlb_change_protection(struct vm_area_struct *vma,
    else if (uffd_wp_resolve)
    newpte = pte_swp_clear_uffd_wp(newpte);
    set_huge_swap_pte_at(mm, address, ptep,
    - newpte, huge_page_size(h));
    + newpte, psize);
    pages++;
    }
    spin_unlock(ptl);
    continue;
    }
    + if (unlikely(is_swap_special_pte(pte))) {
    + WARN_ON_ONCE(!pte_swp_uffd_wp_special(pte));
    + /*
    + * This is changing a non-present pte into a none pte,
    + * no need for huge_ptep_modify_prot_start/commit().
    + */
    + if (uffd_wp_resolve)
    + huge_pte_clear(mm, address, ptep, psize);
    + }
    if (!huge_pte_none(pte)) {
    pte_t old_pte;

    @@ -5046,6 +5061,12 @@ unsigned long hugetlb_change_protection(struct vm_area_struct *vma,
    pte = huge_pte_clear_uffd_wp(pte);
    huge_ptep_modify_prot_commit(vma, address, ptep, old_pte, pte);
    pages++;
    + } else {
    + /* None pte */
    + if (unlikely(uffd_wp))
    + /* Safe to modify directly (none->non-present). */
    + set_huge_pte_at(mm, address, ptep,
    + pte_swp_mkuffd_wp_special(vma));
    }
    spin_unlock(ptl);
    }
    --
    2.26.2
    \
     
     \ /
      Last update: 2021-01-15 18:41    [W:4.633 / U:0.284 seconds]
    ©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site