diff mbox series

[v2,16/24] hugetlb/userfaultfd: Hook page faults for uffd write protection

Message ID 20210427161317.50682-17-peterx@redhat.com (mailing list archive)
State New, archived
Headers show
Series userfaultfd-wp: Support shmem and hugetlbfs | expand

Commit Message

Peter Xu April 27, 2021, 4:13 p.m. UTC
Hook up hugetlbfs_fault() with the capability to handle userfaultfd-wp faults.

We do this slightly earlier than hugetlb_cow() so that we can avoid taking some
extra locks that we definitely don't need.

Reviewed-by: Mike Kravetz <mike.kravetz@oracle.com>
Signed-off-by: Peter Xu <peterx@redhat.com>
---
 mm/hugetlb.c | 19 +++++++++++++++++++
 1 file changed, 19 insertions(+)

Comments

Peter Xu April 28, 2021, 12:07 a.m. UTC | #1
On Tue, Apr 27, 2021 at 12:13:09PM -0400, Peter Xu wrote:
> Hook up hugetlbfs_fault() with the capability to handle userfaultfd-wp faults.
> 
> We do this slightly earlier than hugetlb_cow() so that we can avoid taking some
> extra locks that we definitely don't need.
> 
> Reviewed-by: Mike Kravetz <mike.kravetz@oracle.com>
> Signed-off-by: Peter Xu <peterx@redhat.com>
> ---
>  mm/hugetlb.c | 19 +++++++++++++++++++
>  1 file changed, 19 insertions(+)
> 
> diff --git a/mm/hugetlb.c b/mm/hugetlb.c
> index 629aa4c2259c8..8e234ee9a15e2 100644
> --- a/mm/hugetlb.c
> +++ b/mm/hugetlb.c
> @@ -4802,6 +4802,25 @@ vm_fault_t hugetlb_fault(struct mm_struct *mm, struct vm_area_struct *vma,
>  	if (unlikely(!pte_same(entry, huge_ptep_get(ptep))))
>  		goto out_ptl;
>  
> +	/* Handle userfault-wp first, before trying to lock more pages */
> +	if (userfaultfd_pte_wp(vma, huge_ptep_get(ptep)) &&

I'm going to change this to:

-       if (userfaultfd_pte_wp(vma, huge_ptep_get(ptep)) &&
+       if (userfaultfd_wp(vma) && huge_pte_uffd_wp(huge_ptep_get(ptep)) &&

As strictly speaking it's not right to use userfaultfd_pte_wp() directly on a
huge pte...  Currently huge_pte_uffd_wp() is missing in this version (which is
still pte_uffd_wp() anyways), but I'll add a separate patch to introduce all
these helpers (also mention about what arch should do when the huge pte is not
handled the same way as small pte).  I'll try to keep Mike's R-b as this change
should be trivial, or please shoot.  Thanks,

> +	    (flags & FAULT_FLAG_WRITE) && !huge_pte_write(entry)) {
> +		struct vm_fault vmf = {
> +			.vma = vma,
> +			.address = haddr,
> +			.flags = flags,
> +		};
> +
> +		spin_unlock(ptl);
> +		if (pagecache_page) {
> +			unlock_page(pagecache_page);
> +			put_page(pagecache_page);
> +		}
> +		mutex_unlock(&hugetlb_fault_mutex_table[hash]);
> +		i_mmap_unlock_read(mapping);
> +		return handle_userfault(&vmf, VM_UFFD_WP);
> +	}
> +
>  	/*
>  	 * hugetlb_cow() requires page locks of pte_page(entry) and
>  	 * pagecache_page, so here we need take the former one
> -- 
> 2.26.2
>
diff mbox series

Patch

diff --git a/mm/hugetlb.c b/mm/hugetlb.c
index 629aa4c2259c8..8e234ee9a15e2 100644
--- a/mm/hugetlb.c
+++ b/mm/hugetlb.c
@@ -4802,6 +4802,25 @@  vm_fault_t hugetlb_fault(struct mm_struct *mm, struct vm_area_struct *vma,
 	if (unlikely(!pte_same(entry, huge_ptep_get(ptep))))
 		goto out_ptl;
 
+	/* Handle userfault-wp first, before trying to lock more pages */
+	if (userfaultfd_pte_wp(vma, huge_ptep_get(ptep)) &&
+	    (flags & FAULT_FLAG_WRITE) && !huge_pte_write(entry)) {
+		struct vm_fault vmf = {
+			.vma = vma,
+			.address = haddr,
+			.flags = flags,
+		};
+
+		spin_unlock(ptl);
+		if (pagecache_page) {
+			unlock_page(pagecache_page);
+			put_page(pagecache_page);
+		}
+		mutex_unlock(&hugetlb_fault_mutex_table[hash]);
+		i_mmap_unlock_read(mapping);
+		return handle_userfault(&vmf, VM_UFFD_WP);
+	}
+
 	/*
 	 * hugetlb_cow() requires page locks of pte_page(entry) and
 	 * pagecache_page, so here we need take the former one