All of lore.kernel.org
 help / color / mirror / Atom feed
From: Axel Rasmussen <axelrasmussen@google.com>
To: "Alexander Viro" <viro@zeniv.linux.org.uk>,
	"Alexey Dobriyan" <adobriyan@gmail.com>,
	"Andrea Arcangeli" <aarcange@redhat.com>,
	"Andrew Morton" <akpm@linux-foundation.org>,
	"Anshuman Khandual" <anshuman.khandual@arm.com>,
	"Catalin Marinas" <catalin.marinas@arm.com>,
	"Chinwen Chang" <chinwen.chang@mediatek.com>,
	"Huang Ying" <ying.huang@intel.com>,
	"Ingo Molnar" <mingo@redhat.com>, "Jann Horn" <jannh@google.com>,
	"Jerome Glisse" <jglisse@redhat.com>,
	"Lokesh Gidra" <lokeshgidra@google.com>,
	"Matthew Wilcox (Oracle)" <willy@infradead.org>,
	"Michael Ellerman" <mpe@ellerman.id.au>,
	"Michal Koutný" <mkoutny@suse.com>,
	"Michel Lespinasse" <walken@google.com>,
	"Mike Kravetz" <mike.kravetz@oracle.com>,
	"Mike Rapoport" <rppt@linux.vnet.ibm.com>,
	"Nicholas Piggin" <npiggin@gmail.com>,
	"Peter Xu" <peterx@redhat.com>, "Shaohua Li" <shli@fb.com>,
	"Shawn Anastasio" <shawn@anastas.io>,
	"Steven Rostedt" <rostedt@goodmis.org>,
	"Steven Price" <steven.price@arm.com>,
	"Vlastimil Babka" <vbabka@suse.cz>
Cc: linux-kernel@vger.kernel.org, linux-fsdevel@vger.kernel.org,
	linux-mm@kvack.org, Adam Ruprecht <ruprecht@google.com>,
	Axel Rasmussen <axelrasmussen@google.com>,
	Cannon Matthews <cannonmatthews@google.com>,
	"Dr . David Alan Gilbert" <dgilbert@redhat.com>,
	David Rientjes <rientjes@google.com>,
	Mina Almasry <almasrymina@google.com>,
	Oliver Upton <oupton@google.com>
Subject: [PATCH v6 1/7] userfaultfd: introduce a new reason enum instead of using VM_* flags
Date: Fri, 12 Feb 2021 13:53:57 -0800	[thread overview]
Message-ID: <20210212215403.3457686-2-axelrasmussen@google.com> (raw)
In-Reply-To: <20210212215403.3457686-1-axelrasmussen@google.com>

The problem is, VM_* flags are a limited resource. As we add support for
new use cases to userfaultfd, there are new reasons why a userfault
might be triggered, but we can't keep adding new VM_* flags.

So, introduce a new enum, to which we can add arbitrarily many reasons
going forward. The intent is:

1. Page fault handlers will notice a userfaultfd registration
   (VM_UFFD_MISSING or VM_UFFD_WP).
2. They'll call handle_userfault() to resolve it, with the reason:
   page missing, write protect fault, or (in the future) minor fault,
   etc...

Importantly, the possible reasons for triggering a userfault will no
longer match 1:1 with VM_* flags; there can be > 1 reason to trigger a
fault for a single VM_* flag.

Signed-off-by: Axel Rasmussen <axelrasmussen@google.com>
---
 fs/userfaultfd.c              | 21 +++++++++------------
 include/linux/userfaultfd_k.h | 12 ++++++++++--
 mm/huge_memory.c              |  4 ++--
 mm/hugetlb.c                  |  2 +-
 mm/memory.c                   |  8 ++++----
 mm/shmem.c                    |  2 +-
 6 files changed, 27 insertions(+), 22 deletions(-)

diff --git a/fs/userfaultfd.c b/fs/userfaultfd.c
index 1f4a34b1a1e7..8d663eae0266 100644
--- a/fs/userfaultfd.c
+++ b/fs/userfaultfd.c
@@ -190,7 +190,7 @@ static inline void msg_init(struct uffd_msg *msg)
 
 static inline struct uffd_msg userfault_msg(unsigned long address,
 					    unsigned int flags,
-					    unsigned long reason,
+					    enum uffd_trigger_reason reason,
 					    unsigned int features)
 {
 	struct uffd_msg msg;
@@ -206,7 +206,7 @@ static inline struct uffd_msg userfault_msg(unsigned long address,
 		 * a write fault.
 		 */
 		msg.arg.pagefault.flags |= UFFD_PAGEFAULT_FLAG_WRITE;
-	if (reason & VM_UFFD_WP)
+	if (reason == UFFD_REASON_WP)
 		/*
 		 * If UFFD_FEATURE_PAGEFAULT_FLAG_WP was set in the
 		 * uffdio_api.features and UFFD_PAGEFAULT_FLAG_WP was
@@ -229,7 +229,7 @@ static inline bool userfaultfd_huge_must_wait(struct userfaultfd_ctx *ctx,
 					 struct vm_area_struct *vma,
 					 unsigned long address,
 					 unsigned long flags,
-					 unsigned long reason)
+					 enum uffd_trigger_reason reason)
 {
 	struct mm_struct *mm = ctx->mm;
 	pte_t *ptep, pte;
@@ -251,7 +251,7 @@ static inline bool userfaultfd_huge_must_wait(struct userfaultfd_ctx *ctx,
 	 */
 	if (huge_pte_none(pte))
 		ret = true;
-	if (!huge_pte_write(pte) && (reason & VM_UFFD_WP))
+	if (!huge_pte_write(pte) && (reason == UFFD_REASON_WP))
 		ret = true;
 out:
 	return ret;
@@ -261,7 +261,7 @@ static inline bool userfaultfd_huge_must_wait(struct userfaultfd_ctx *ctx,
 					 struct vm_area_struct *vma,
 					 unsigned long address,
 					 unsigned long flags,
-					 unsigned long reason)
+					 enum uffd_trigger_reason reason)
 {
 	return false;	/* should never get here */
 }
@@ -277,7 +277,7 @@ static inline bool userfaultfd_huge_must_wait(struct userfaultfd_ctx *ctx,
 static inline bool userfaultfd_must_wait(struct userfaultfd_ctx *ctx,
 					 unsigned long address,
 					 unsigned long flags,
-					 unsigned long reason)
+					 enum uffd_trigger_reason reason)
 {
 	struct mm_struct *mm = ctx->mm;
 	pgd_t *pgd;
@@ -316,7 +316,7 @@ static inline bool userfaultfd_must_wait(struct userfaultfd_ctx *ctx,
 		goto out;
 
 	if (pmd_trans_huge(_pmd)) {
-		if (!pmd_write(_pmd) && (reason & VM_UFFD_WP))
+		if (!pmd_write(_pmd) && (reason == UFFD_REASON_WP))
 			ret = true;
 		goto out;
 	}
@@ -332,7 +332,7 @@ static inline bool userfaultfd_must_wait(struct userfaultfd_ctx *ctx,
 	 */
 	if (pte_none(*pte))
 		ret = true;
-	if (!pte_write(*pte) && (reason & VM_UFFD_WP))
+	if (!pte_write(*pte) && (reason == UFFD_REASON_WP))
 		ret = true;
 	pte_unmap(pte);
 
@@ -366,7 +366,7 @@ static inline long userfaultfd_get_blocking_state(unsigned int flags)
  * fatal_signal_pending()s, and the mmap_lock must be released before
  * returning it.
  */
-vm_fault_t handle_userfault(struct vm_fault *vmf, unsigned long reason)
+vm_fault_t handle_userfault(struct vm_fault *vmf, enum uffd_trigger_reason reason)
 {
 	struct mm_struct *mm = vmf->vma->vm_mm;
 	struct userfaultfd_ctx *ctx;
@@ -401,9 +401,6 @@ vm_fault_t handle_userfault(struct vm_fault *vmf, unsigned long reason)
 
 	BUG_ON(ctx->mm != mm);
 
-	VM_BUG_ON(reason & ~(VM_UFFD_MISSING|VM_UFFD_WP));
-	VM_BUG_ON(!(reason & VM_UFFD_MISSING) ^ !!(reason & VM_UFFD_WP));
-
 	if (ctx->features & UFFD_FEATURE_SIGBUS)
 		goto out;
 	if ((vmf->flags & FAULT_FLAG_USER) == 0 &&
diff --git a/include/linux/userfaultfd_k.h b/include/linux/userfaultfd_k.h
index c63ccdae3eab..cc1554e7162f 100644
--- a/include/linux/userfaultfd_k.h
+++ b/include/linux/userfaultfd_k.h
@@ -9,6 +9,14 @@
 #ifndef _LINUX_USERFAULTFD_K_H
 #define _LINUX_USERFAULTFD_K_H
 
+/* Denotes the reason why handle_userfault() is being triggered. */
+enum uffd_trigger_reason {
+	/* A page was missing. */
+	UFFD_REASON_MISSING,
+	/* A write protect fault occurred. */
+	UFFD_REASON_WP,
+};
+
 #ifdef CONFIG_USERFAULTFD
 
 #include <linux/userfaultfd.h> /* linux/include/uapi/linux/userfaultfd.h */
@@ -32,7 +40,7 @@
 
 extern int sysctl_unprivileged_userfaultfd;
 
-extern vm_fault_t handle_userfault(struct vm_fault *vmf, unsigned long reason);
+extern vm_fault_t handle_userfault(struct vm_fault *vmf, enum uffd_trigger_reason reason);
 
 extern ssize_t mcopy_atomic(struct mm_struct *dst_mm, unsigned long dst_start,
 			    unsigned long src_start, unsigned long len,
@@ -111,7 +119,7 @@ extern void userfaultfd_unmap_complete(struct mm_struct *mm,
 
 /* mm helpers */
 static inline vm_fault_t handle_userfault(struct vm_fault *vmf,
-				unsigned long reason)
+				enum uffd_trigger_reason reason)
 {
 	return VM_FAULT_SIGBUS;
 }
diff --git a/mm/huge_memory.c b/mm/huge_memory.c
index 395c75111d33..1d740b43bcc5 100644
--- a/mm/huge_memory.c
+++ b/mm/huge_memory.c
@@ -629,7 +629,7 @@ static vm_fault_t __do_huge_pmd_anonymous_page(struct vm_fault *vmf,
 			spin_unlock(vmf->ptl);
 			put_page(page);
 			pte_free(vma->vm_mm, pgtable);
-			ret2 = handle_userfault(vmf, VM_UFFD_MISSING);
+			ret2 = handle_userfault(vmf, UFFD_REASON_MISSING);
 			VM_BUG_ON(ret2 & VM_FAULT_FALLBACK);
 			return ret2;
 		}
@@ -748,7 +748,7 @@ vm_fault_t do_huge_pmd_anonymous_page(struct vm_fault *vmf)
 			} else if (userfaultfd_missing(vma)) {
 				spin_unlock(vmf->ptl);
 				pte_free(vma->vm_mm, pgtable);
-				ret = handle_userfault(vmf, VM_UFFD_MISSING);
+				ret = handle_userfault(vmf, UFFD_REASON_MISSING);
 				VM_BUG_ON(ret & VM_FAULT_FALLBACK);
 			} else {
 				set_huge_zero_page(pgtable, vma->vm_mm, vma,
diff --git a/mm/hugetlb.c b/mm/hugetlb.c
index 0d45a01a85f8..2a90e0b4bf47 100644
--- a/mm/hugetlb.c
+++ b/mm/hugetlb.c
@@ -4305,7 +4305,7 @@ static vm_fault_t hugetlb_no_page(struct mm_struct *mm,
 			hash = hugetlb_fault_mutex_hash(mapping, idx);
 			mutex_unlock(&hugetlb_fault_mutex_table[hash]);
 			i_mmap_unlock_read(mapping);
-			ret = handle_userfault(&vmf, VM_UFFD_MISSING);
+			ret = handle_userfault(&vmf, UFFD_REASON_MISSING);
 			i_mmap_lock_read(mapping);
 			mutex_lock(&hugetlb_fault_mutex_table[hash]);
 			goto out;
diff --git a/mm/memory.c b/mm/memory.c
index bc4a41ec81aa..995a95826f4d 100644
--- a/mm/memory.c
+++ b/mm/memory.c
@@ -3100,7 +3100,7 @@ static vm_fault_t do_wp_page(struct vm_fault *vmf)
 
 	if (userfaultfd_pte_wp(vma, *vmf->pte)) {
 		pte_unmap_unlock(vmf->pte, vmf->ptl);
-		return handle_userfault(vmf, VM_UFFD_WP);
+		return handle_userfault(vmf, UFFD_REASON_WP);
 	}
 
 	vmf->page = vm_normal_page(vma, vmf->address, vmf->orig_pte);
@@ -3535,7 +3535,7 @@ static vm_fault_t do_anonymous_page(struct vm_fault *vmf)
 		/* Deliver the page fault to userland, check inside PT lock */
 		if (userfaultfd_missing(vma)) {
 			pte_unmap_unlock(vmf->pte, vmf->ptl);
-			return handle_userfault(vmf, VM_UFFD_MISSING);
+			return handle_userfault(vmf, UFFD_REASON_MISSING);
 		}
 		goto setpte;
 	}
@@ -3577,7 +3577,7 @@ static vm_fault_t do_anonymous_page(struct vm_fault *vmf)
 	if (userfaultfd_missing(vma)) {
 		pte_unmap_unlock(vmf->pte, vmf->ptl);
 		put_page(page);
-		return handle_userfault(vmf, VM_UFFD_MISSING);
+		return handle_userfault(vmf, UFFD_REASON_MISSING);
 	}
 
 	inc_mm_counter_fast(vma->vm_mm, MM_ANONPAGES);
@@ -4195,7 +4195,7 @@ static inline vm_fault_t wp_huge_pmd(struct vm_fault *vmf, pmd_t orig_pmd)
 {
 	if (vma_is_anonymous(vmf->vma)) {
 		if (userfaultfd_huge_pmd_wp(vmf->vma, orig_pmd))
-			return handle_userfault(vmf, VM_UFFD_WP);
+			return handle_userfault(vmf, UFFD_REASON_WP);
 		return do_huge_pmd_wp_page(vmf, orig_pmd);
 	}
 	if (vmf->vma->vm_ops->huge_fault) {
diff --git a/mm/shmem.c b/mm/shmem.c
index 06c771d23127..e1e2513b4298 100644
--- a/mm/shmem.c
+++ b/mm/shmem.c
@@ -1849,7 +1849,7 @@ static int shmem_getpage_gfp(struct inode *inode, pgoff_t index,
 	 */
 
 	if (vma && userfaultfd_missing(vma)) {
-		*fault_type = handle_userfault(vmf, VM_UFFD_MISSING);
+		*fault_type = handle_userfault(vmf, UFFD_REASON_MISSING);
 		return 0;
 	}
 
-- 
2.30.0.478.g8a0d178c01-goog


  reply	other threads:[~2021-02-12 21:55 UTC|newest]

Thread overview: 16+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2021-02-12 21:53 [PATCH v6 0/7] userfaultfd: add minor fault handling Axel Rasmussen
2021-02-12 21:53 ` Axel Rasmussen
2021-02-12 21:53 ` Axel Rasmussen [this message]
2021-02-12 21:53   ` [PATCH v6 1/7] userfaultfd: introduce a new reason enum instead of using VM_* flags Axel Rasmussen
2021-02-12 21:53 ` [PATCH v6 2/7] userfaultfd: add minor fault registration mode Axel Rasmussen
2021-02-12 21:53   ` Axel Rasmussen
2021-02-12 21:53 ` [PATCH v6 3/7] userfaultfd: disable huge PMD sharing for minor fault registered VMAs Axel Rasmussen
2021-02-12 21:53   ` Axel Rasmussen
2021-02-12 21:54 ` [PATCH v6 4/7] userfaultfd: hugetlbfs: only compile UFFD helpers if config enabled Axel Rasmussen
2021-02-12 21:54   ` Axel Rasmussen
2021-02-12 21:54 ` [PATCH v6 5/7] userfaultfd: add UFFDIO_CONTINUE ioctl Axel Rasmussen
2021-02-12 21:54   ` Axel Rasmussen
2021-02-12 21:54 ` [PATCH v6 6/7] userfaultfd: update documentation to describe minor fault handling Axel Rasmussen
2021-02-12 21:54   ` Axel Rasmussen
2021-02-12 21:54 ` [PATCH v6 7/7] userfaultfd/selftests: add test exercising " Axel Rasmussen
2021-02-12 21:54   ` Axel Rasmussen

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20210212215403.3457686-2-axelrasmussen@google.com \
    --to=axelrasmussen@google.com \
    --cc=aarcange@redhat.com \
    --cc=adobriyan@gmail.com \
    --cc=akpm@linux-foundation.org \
    --cc=almasrymina@google.com \
    --cc=anshuman.khandual@arm.com \
    --cc=cannonmatthews@google.com \
    --cc=catalin.marinas@arm.com \
    --cc=chinwen.chang@mediatek.com \
    --cc=dgilbert@redhat.com \
    --cc=jannh@google.com \
    --cc=jglisse@redhat.com \
    --cc=linux-fsdevel@vger.kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-mm@kvack.org \
    --cc=lokeshgidra@google.com \
    --cc=mike.kravetz@oracle.com \
    --cc=mingo@redhat.com \
    --cc=mkoutny@suse.com \
    --cc=mpe@ellerman.id.au \
    --cc=npiggin@gmail.com \
    --cc=oupton@google.com \
    --cc=peterx@redhat.com \
    --cc=rientjes@google.com \
    --cc=rostedt@goodmis.org \
    --cc=rppt@linux.vnet.ibm.com \
    --cc=ruprecht@google.com \
    --cc=shawn@anastas.io \
    --cc=shli@fb.com \
    --cc=steven.price@arm.com \
    --cc=vbabka@suse.cz \
    --cc=viro@zeniv.linux.org.uk \
    --cc=walken@google.com \
    --cc=willy@infradead.org \
    --cc=ying.huang@intel.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.