[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-Id: <20210212215403.3457686-2-axelrasmussen@google.com>
Date: Fri, 12 Feb 2021 13:53:57 -0800
From: Axel Rasmussen <axelrasmussen@...gle.com>
To: Alexander Viro <viro@...iv.linux.org.uk>,
Alexey Dobriyan <adobriyan@...il.com>,
Andrea Arcangeli <aarcange@...hat.com>,
Andrew Morton <akpm@...ux-foundation.org>,
Anshuman Khandual <anshuman.khandual@....com>,
Catalin Marinas <catalin.marinas@....com>,
Chinwen Chang <chinwen.chang@...iatek.com>,
Huang Ying <ying.huang@...el.com>,
Ingo Molnar <mingo@...hat.com>, Jann Horn <jannh@...gle.com>,
Jerome Glisse <jglisse@...hat.com>,
Lokesh Gidra <lokeshgidra@...gle.com>,
"Matthew Wilcox (Oracle)" <willy@...radead.org>,
Michael Ellerman <mpe@...erman.id.au>,
"Michal Koutný" <mkoutny@...e.com>,
Michel Lespinasse <walken@...gle.com>,
Mike Kravetz <mike.kravetz@...cle.com>,
Mike Rapoport <rppt@...ux.vnet.ibm.com>,
Nicholas Piggin <npiggin@...il.com>,
Peter Xu <peterx@...hat.com>, Shaohua Li <shli@...com>,
Shawn Anastasio <shawn@...stas.io>,
Steven Rostedt <rostedt@...dmis.org>,
Steven Price <steven.price@....com>,
Vlastimil Babka <vbabka@...e.cz>
Cc: linux-kernel@...r.kernel.org, linux-fsdevel@...r.kernel.org,
linux-mm@...ck.org, Adam Ruprecht <ruprecht@...gle.com>,
Axel Rasmussen <axelrasmussen@...gle.com>,
Cannon Matthews <cannonmatthews@...gle.com>,
"Dr . David Alan Gilbert" <dgilbert@...hat.com>,
David Rientjes <rientjes@...gle.com>,
Mina Almasry <almasrymina@...gle.com>,
Oliver Upton <oupton@...gle.com>
Subject: [PATCH v6 1/7] userfaultfd: introduce a new reason enum instead of
using VM_* flags
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@...gle.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
Powered by blists - more mailing lists