mm: introduce leaf entry type and use to simplify leaf entry logic

The kernel maintains leaf page table entries which contain either:

The kernel maintains leaf page table entries which contain either:

 - Nothing ('none' entries)
 - Present entries*
 - Everything else that will cause a fault which the kernel handles

* Present entries are either entries the hardware can navigate without page
  fault or special cases like NUMA hint protnone or PMD with cleared
  present bit which contain hardware-valid entries modulo the present bit.

In the 'everything else' group we include swap entries, but we also
include a number of other things such as migration entries, device private
entries and marker entries.

Unfortunately this 'everything else' group expresses everything through a
swp_entry_t type, and these entries are referred to swap entries even
though they may well not contain a...  swap entry.

This is compounded by the rather mind-boggling concept of a non-swap swap
entry (checked via non_swap_entry()) and the means by which we twist and
turn to satisfy this.

This patch lays the foundation for reducing this confusion.

We refer to 'everything else' as a 'software-define leaf entry' or
'softleaf'.  for short And in fact we scoop up the 'none' entries into
this concept also so we are left with:

- Present entries.
- Softleaf entries (which may be empty).

This allows for radical simplification across the board - one can simply
convert any leaf page table entry to a leaf entry via softleaf_from_pte().

If the entry is present, we return an empty leaf entry, so it is assumed
the caller is aware that they must differentiate between the two
categories of page table entries, checking for the former via
pte_present().

As a result, we can eliminate a number of places where we would otherwise
need to use predicates to see if we can proceed with leaf page table entry
conversion and instead just go ahead and do it unconditionally.

We do so where we can, adjusting surrounding logic as necessary to
integrate the new softleaf_t logic as far as seems reasonable at this
stage.

We typedef swp_entry_t to softleaf_t for the time being until the
conversion can be complete, meaning everything remains compatible
regardless of which type is used.  We will eventually remove swp_entry_t
when the conversion is complete.

We introduce a new header file to keep things clear - leafops.h - this
imports swapops.h so can direct replace swapops imports without issue, and
we do so in all the files that require it.

Additionally, add new leafops.h file to core mm maintainers entry.

Link: https://lkml.kernel.org/r/c879383aac77d96a03e4d38f7daba893cd35fc76.1762812360.git.lorenzo.stoakes@oracle.com
Signed-off-by: Lorenzo Stoakes <lorenzo.stoakes@oracle.com>
Acked-by: Zi Yan <ziy@nvidia.com>
Reviewed-by: Vlastimil Babka <vbabka@suse.cz>
Cc: Alexander Gordeev <agordeev@linux.ibm.com>
Cc: Alistair Popple <apopple@nvidia.com>
Cc: Al Viro <viro@zeniv.linux.org.uk>
Cc: Arnd Bergmann <arnd@arndb.de>
Cc: Axel Rasmussen <axelrasmussen@google.com>
Cc: Baolin Wang <baolin.wang@linux.alibaba.com>
Cc: Baoquan He <bhe@redhat.com>
Cc: Barry Song <baohua@kernel.org>
Cc: Byungchul Park <byungchul@sk.com>
Cc: Chengming Zhou <chengming.zhou@linux.dev>
Cc: Chris Li <chrisl@kernel.org>
Cc: Christian Borntraeger <borntraeger@linux.ibm.com>
Cc: Christian Brauner <brauner@kernel.org>
Cc: Claudio Imbrenda <imbrenda@linux.ibm.com>
Cc: David Hildenbrand <david@redhat.com>
Cc: Dev Jain <dev.jain@arm.com>
Cc: Gerald Schaefer <gerald.schaefer@linux.ibm.com>
Cc: Gregory Price <gourry@gourry.net>
Cc: Heiko Carstens <hca@linux.ibm.com>
Cc: "Huang, Ying" <ying.huang@linux.alibaba.com>
Cc: Hugh Dickins <hughd@google.com>
Cc: Jan Kara <jack@suse.cz>
Cc: Jann Horn <jannh@google.com>
Cc: Janosch Frank <frankja@linux.ibm.com>
Cc: Jason Gunthorpe <jgg@ziepe.ca>
Cc: Joshua Hahn <joshua.hahnjy@gmail.com>
Cc: Kairui Song <kasong@tencent.com>
Cc: Kemeng Shi <shikemeng@huaweicloud.com>
Cc: Lance Yang <lance.yang@linux.dev>
Cc: Leon Romanovsky <leon@kernel.org>
Cc: Liam Howlett <liam.howlett@oracle.com>
Cc: Mathew Brost <matthew.brost@intel.com>
Cc: Matthew Wilcox (Oracle) <willy@infradead.org>
Cc: Miaohe Lin <linmiaohe@huawei.com>
Cc: Michal Hocko <mhocko@suse.com>
Cc: Mike Rapoport <rppt@kernel.org>
Cc: Muchun Song <muchun.song@linux.dev>
Cc: Naoya Horiguchi <nao.horiguchi@gmail.com>
Cc: Nhat Pham <nphamcs@gmail.com>
Cc: Nico Pache <npache@redhat.com>
Cc: Oscar Salvador <osalvador@suse.de>
Cc: Pasha Tatashin <pasha.tatashin@soleen.com>
Cc: Peter Xu <peterx@redhat.com>
Cc: Rakie Kim <rakie.kim@sk.com>
Cc: Rik van Riel <riel@surriel.com>
Cc: Ryan Roberts <ryan.roberts@arm.com>
Cc: SeongJae Park <sj@kernel.org>
Cc: Suren Baghdasaryan <surenb@google.com>
Cc: Sven Schnelle <svens@linux.ibm.com>
Cc: Vasily Gorbik <gor@linux.ibm.com>
Cc: Wei Xu <weixugc@google.com>
Cc: xu xin <xu.xin16@zte.com.cn>
Cc: Yuanchu Xie <yuanchu@google.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
This commit is contained in:
Lorenzo Stoakes 2025-11-10 22:21:20 +00:00 committed by Andrew Morton
parent c093cf4510
commit 68aa2fdbf5
18 changed files with 502 additions and 164 deletions

View File

@ -16263,6 +16263,7 @@ T: git git://git.kernel.org/pub/scm/linux/kernel/git/akpm/mm
F: include/linux/gfp.h F: include/linux/gfp.h
F: include/linux/gfp_types.h F: include/linux/gfp_types.h
F: include/linux/highmem.h F: include/linux/highmem.h
F: include/linux/leafops.h
F: include/linux/memory.h F: include/linux/memory.h
F: include/linux/mm.h F: include/linux/mm.h
F: include/linux/mm_*.h F: include/linux/mm_*.h

View File

@ -14,7 +14,7 @@
#include <linux/rmap.h> #include <linux/rmap.h>
#include <linux/swap.h> #include <linux/swap.h>
#include <linux/sched/mm.h> #include <linux/sched/mm.h>
#include <linux/swapops.h> #include <linux/leafops.h>
#include <linux/mmu_notifier.h> #include <linux/mmu_notifier.h>
#include <linux/page_idle.h> #include <linux/page_idle.h>
#include <linux/shmem_fs.h> #include <linux/shmem_fs.h>
@ -1231,11 +1231,11 @@ static int smaps_hugetlb_range(pte_t *pte, unsigned long hmask,
if (pte_present(ptent)) { if (pte_present(ptent)) {
folio = page_folio(pte_page(ptent)); folio = page_folio(pte_page(ptent));
present = true; present = true;
} else if (is_swap_pte(ptent)) { } else {
swp_entry_t swpent = pte_to_swp_entry(ptent); const softleaf_t entry = softleaf_from_pte(ptent);
if (is_pfn_swap_entry(swpent)) if (softleaf_has_pfn(entry))
folio = pfn_swap_entry_folio(swpent); folio = softleaf_to_folio(entry);
} }
if (folio) { if (folio) {
@ -1956,9 +1956,9 @@ static pagemap_entry_t pte_to_pagemap_entry(struct pagemapread *pm,
flags |= PM_SWAP; flags |= PM_SWAP;
if (is_pfn_swap_entry(entry)) if (is_pfn_swap_entry(entry))
page = pfn_swap_entry_to_page(entry); page = pfn_swap_entry_to_page(entry);
if (pte_marker_entry_uffd_wp(entry)) if (softleaf_is_uffd_wp_marker(entry))
flags |= PM_UFFD_WP; flags |= PM_UFFD_WP;
if (is_guard_swp_entry(entry)) if (softleaf_is_guard_marker(entry))
flags |= PM_GUARD_REGION; flags |= PM_GUARD_REGION;
} }
@ -2331,18 +2331,18 @@ static unsigned long pagemap_page_category(struct pagemap_scan_private *p,
if (pte_soft_dirty(pte)) if (pte_soft_dirty(pte))
categories |= PAGE_IS_SOFT_DIRTY; categories |= PAGE_IS_SOFT_DIRTY;
} else if (is_swap_pte(pte)) { } else if (is_swap_pte(pte)) {
swp_entry_t swp; softleaf_t entry;
categories |= PAGE_IS_SWAPPED; categories |= PAGE_IS_SWAPPED;
if (!pte_swp_uffd_wp_any(pte)) if (!pte_swp_uffd_wp_any(pte))
categories |= PAGE_IS_WRITTEN; categories |= PAGE_IS_WRITTEN;
swp = pte_to_swp_entry(pte); entry = softleaf_from_pte(pte);
if (is_guard_swp_entry(swp)) if (softleaf_is_guard_marker(entry))
categories |= PAGE_IS_GUARD; categories |= PAGE_IS_GUARD;
else if ((p->masks_of_interest & PAGE_IS_FILE) && else if ((p->masks_of_interest & PAGE_IS_FILE) &&
is_pfn_swap_entry(swp) && softleaf_has_pfn(entry) &&
!folio_test_anon(pfn_swap_entry_folio(swp))) !folio_test_anon(softleaf_to_folio(entry)))
categories |= PAGE_IS_FILE; categories |= PAGE_IS_FILE;
if (pte_swp_soft_dirty(pte)) if (pte_swp_soft_dirty(pte))
@ -2467,7 +2467,7 @@ static void make_uffd_wp_huge_pte(struct vm_area_struct *vma,
{ {
unsigned long psize; unsigned long psize;
if (is_hugetlb_entry_hwpoisoned(ptent) || is_pte_marker(ptent)) if (is_hugetlb_entry_hwpoisoned(ptent) || pte_is_marker(ptent))
return; return;
psize = huge_page_size(hstate_vma(vma)); psize = huge_page_size(hstate_vma(vma));

View File

@ -29,7 +29,7 @@
#include <linux/ioctl.h> #include <linux/ioctl.h>
#include <linux/security.h> #include <linux/security.h>
#include <linux/hugetlb.h> #include <linux/hugetlb.h>
#include <linux/swapops.h> #include <linux/leafops.h>
#include <linux/miscdevice.h> #include <linux/miscdevice.h>
#include <linux/uio.h> #include <linux/uio.h>
@ -251,7 +251,7 @@ static inline bool userfaultfd_huge_must_wait(struct userfaultfd_ctx *ctx,
if (huge_pte_none(pte)) if (huge_pte_none(pte))
return true; return true;
/* UFFD PTE markers require userspace to resolve the fault. */ /* UFFD PTE markers require userspace to resolve the fault. */
if (is_uffd_pte_marker(pte)) if (pte_is_uffd_marker(pte))
return true; return true;
/* /*
* If VMA has UFFD WP faults enabled and WP fault, wait for userspace to * If VMA has UFFD WP faults enabled and WP fault, wait for userspace to
@ -337,7 +337,7 @@ static inline bool userfaultfd_must_wait(struct userfaultfd_ctx *ctx,
if (pte_none(ptent)) if (pte_none(ptent))
goto out; goto out;
/* UFFD PTE markers require userspace to resolve the fault. */ /* UFFD PTE markers require userspace to resolve the fault. */
if (is_uffd_pte_marker(ptent)) if (pte_is_uffd_marker(ptent))
goto out; goto out;
/* /*
* If VMA has UFFD WP faults enabled and WP fault, wait for userspace to * If VMA has UFFD WP faults enabled and WP fault, wait for userspace to

387
include/linux/leafops.h Normal file
View File

@ -0,0 +1,387 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
* Describes operations that can be performed on software-defined page table
* leaf entries. These are abstracted from the hardware page table entries
* themselves by the softleaf_t type, see mm_types.h.
*/
#ifndef _LINUX_LEAFOPS_H
#define _LINUX_LEAFOPS_H
#include <linux/mm_types.h>
#include <linux/swapops.h>
#include <linux/swap.h>
#ifdef CONFIG_MMU
/* Temporary until swp_entry_t eliminated. */
#define LEAF_TYPE_SHIFT SWP_TYPE_SHIFT
enum softleaf_type {
/* Fundamental types. */
SOFTLEAF_NONE,
SOFTLEAF_SWAP,
/* Migration types. */
SOFTLEAF_MIGRATION_READ,
SOFTLEAF_MIGRATION_READ_EXCLUSIVE,
SOFTLEAF_MIGRATION_WRITE,
/* Device types. */
SOFTLEAF_DEVICE_PRIVATE_READ,
SOFTLEAF_DEVICE_PRIVATE_WRITE,
SOFTLEAF_DEVICE_EXCLUSIVE,
/* H/W posion types. */
SOFTLEAF_HWPOISON,
/* Marker types. */
SOFTLEAF_MARKER,
};
/**
* softleaf_mk_none() - Create an empty ('none') leaf entry.
* Returns: empty leaf entry.
*/
static inline softleaf_t softleaf_mk_none(void)
{
return ((softleaf_t) { 0 });
}
/**
* softleaf_from_pte() - Obtain a leaf entry from a PTE entry.
* @pte: PTE entry.
*
* If @pte is present (therefore not a leaf entry) the function returns an empty
* leaf entry. Otherwise, it returns a leaf entry.
*
* Returns: Leaf entry.
*/
static inline softleaf_t softleaf_from_pte(pte_t pte)
{
if (pte_present(pte) || pte_none(pte))
return softleaf_mk_none();
/* Temporary until swp_entry_t eliminated. */
return pte_to_swp_entry(pte);
}
/**
* softleaf_is_none() - Is the leaf entry empty?
* @entry: Leaf entry.
*
* Empty entries are typically the result of a 'none' page table leaf entry
* being converted to a leaf entry.
*
* Returns: true if the entry is empty, false otherwise.
*/
static inline bool softleaf_is_none(softleaf_t entry)
{
return entry.val == 0;
}
/**
* softleaf_type() - Identify the type of leaf entry.
* @enntry: Leaf entry.
*
* Returns: the leaf entry type associated with @entry.
*/
static inline enum softleaf_type softleaf_type(softleaf_t entry)
{
unsigned int type_num;
if (softleaf_is_none(entry))
return SOFTLEAF_NONE;
type_num = entry.val >> LEAF_TYPE_SHIFT;
if (type_num < MAX_SWAPFILES)
return SOFTLEAF_SWAP;
switch (type_num) {
#ifdef CONFIG_MIGRATION
case SWP_MIGRATION_READ:
return SOFTLEAF_MIGRATION_READ;
case SWP_MIGRATION_READ_EXCLUSIVE:
return SOFTLEAF_MIGRATION_READ_EXCLUSIVE;
case SWP_MIGRATION_WRITE:
return SOFTLEAF_MIGRATION_WRITE;
#endif
#ifdef CONFIG_DEVICE_PRIVATE
case SWP_DEVICE_WRITE:
return SOFTLEAF_DEVICE_PRIVATE_WRITE;
case SWP_DEVICE_READ:
return SOFTLEAF_DEVICE_PRIVATE_READ;
case SWP_DEVICE_EXCLUSIVE:
return SOFTLEAF_DEVICE_EXCLUSIVE;
#endif
#ifdef CONFIG_MEMORY_FAILURE
case SWP_HWPOISON:
return SOFTLEAF_HWPOISON;
#endif
case SWP_PTE_MARKER:
return SOFTLEAF_MARKER;
}
/* Unknown entry type. */
VM_WARN_ON_ONCE(1);
return SOFTLEAF_NONE;
}
/**
* softleaf_is_swap() - Is this leaf entry a swap entry?
* @entry: Leaf entry.
*
* Returns: true if the leaf entry is a swap entry, otherwise false.
*/
static inline bool softleaf_is_swap(softleaf_t entry)
{
return softleaf_type(entry) == SOFTLEAF_SWAP;
}
/**
* softleaf_is_migration() - Is this leaf entry a migration entry?
* @entry: Leaf entry.
*
* Returns: true if the leaf entry is a migration entry, otherwise false.
*/
static inline bool softleaf_is_migration(softleaf_t entry)
{
switch (softleaf_type(entry)) {
case SOFTLEAF_MIGRATION_READ:
case SOFTLEAF_MIGRATION_READ_EXCLUSIVE:
case SOFTLEAF_MIGRATION_WRITE:
return true;
default:
return false;
}
}
/**
* softleaf_is_device_private() - Is this leaf entry a device private entry?
* @entry: Leaf entry.
*
* Returns: true if the leaf entry is a device private entry, otherwise false.
*/
static inline bool softleaf_is_device_private(softleaf_t entry)
{
switch (softleaf_type(entry)) {
case SOFTLEAF_DEVICE_PRIVATE_WRITE:
case SOFTLEAF_DEVICE_PRIVATE_READ:
return true;
default:
return false;
}
}
/**
* softleaf_is_device_exclusive() - Is this leaf entry a device exclusive entry?
* @entry: Leaf entry.
*
* Returns: true if the leaf entry is a device exclusive entry, otherwise false.
*/
static inline bool softleaf_is_device_exclusive(softleaf_t entry)
{
return softleaf_type(entry) == SOFTLEAF_DEVICE_EXCLUSIVE;
}
/**
* softleaf_is_hwpoison() - Is this leaf entry a hardware poison entry?
* @entry: Leaf entry.
*
* Returns: true if the leaf entry is a hardware poison entry, otherwise false.
*/
static inline bool softleaf_is_hwpoison(softleaf_t entry)
{
return softleaf_type(entry) == SOFTLEAF_HWPOISON;
}
/**
* softleaf_is_marker() - Is this leaf entry a marker?
* @entry: Leaf entry.
*
* Returns: true if the leaf entry is a marker entry, otherwise false.
*/
static inline bool softleaf_is_marker(softleaf_t entry)
{
return softleaf_type(entry) == SOFTLEAF_MARKER;
}
/**
* softleaf_to_marker() - Obtain marker associated with leaf entry.
* @entry: Leaf entry, softleaf_is_marker(@entry) must return true.
*
* Returns: Marker associated with the leaf entry.
*/
static inline pte_marker softleaf_to_marker(softleaf_t entry)
{
VM_WARN_ON_ONCE(!softleaf_is_marker(entry));
return swp_offset(entry) & PTE_MARKER_MASK;
}
/**
* softleaf_has_pfn() - Does this leaf entry encode a valid PFN number?
* @entry: Leaf entry.
*
* A pfn swap entry is a special type of swap entry that always has a pfn stored
* in the swap offset. They can either be used to represent unaddressable device
* memory, to restrict access to a page undergoing migration or to represent a
* pfn which has been hwpoisoned and unmapped.
*
* Returns: true if the leaf entry encodes a PFN, otherwise false.
*/
static inline bool softleaf_has_pfn(softleaf_t entry)
{
/* Make sure the swp offset can always store the needed fields. */
BUILD_BUG_ON(SWP_TYPE_SHIFT < SWP_PFN_BITS);
if (softleaf_is_migration(entry))
return true;
if (softleaf_is_device_private(entry))
return true;
if (softleaf_is_device_exclusive(entry))
return true;
if (softleaf_is_hwpoison(entry))
return true;
return false;
}
/**
* softleaf_to_pfn() - Obtain PFN encoded within leaf entry.
* @entry: Leaf entry, softleaf_has_pfn(@entry) must return true.
*
* Returns: The PFN associated with the leaf entry.
*/
static inline unsigned long softleaf_to_pfn(softleaf_t entry)
{
VM_WARN_ON_ONCE(!softleaf_has_pfn(entry));
/* Temporary until swp_entry_t eliminated. */
return swp_offset_pfn(entry);
}
/**
* softleaf_to_page() - Obtains struct page for PFN encoded within leaf entry.
* @entry: Leaf entry, softleaf_has_pfn(@entry) must return true.
*
* Returns: Pointer to the struct page associated with the leaf entry's PFN.
*/
static inline struct page *softleaf_to_page(softleaf_t entry)
{
VM_WARN_ON_ONCE(!softleaf_has_pfn(entry));
/* Temporary until swp_entry_t eliminated. */
return pfn_swap_entry_to_page(entry);
}
/**
* softleaf_to_folio() - Obtains struct folio for PFN encoded within leaf entry.
* @entry: Leaf entry, softleaf_has_pfn(@entry) must return true.
*
* Returns: Pointer to the struct folio associated with the leaf entry's PFN.
*/
static inline struct folio *softleaf_to_folio(softleaf_t entry)
{
VM_WARN_ON_ONCE(!softleaf_has_pfn(entry));
/* Temporary until swp_entry_t eliminated. */
return pfn_swap_entry_folio(entry);
}
/**
* softleaf_is_poison_marker() - Is this leaf entry a poison marker?
* @entry: Leaf entry.
*
* The poison marker is set via UFFDIO_POISON. Userfaultfd-specific.
*
* Returns: true if the leaf entry is a poison marker, otherwise false.
*/
static inline bool softleaf_is_poison_marker(softleaf_t entry)
{
if (!softleaf_is_marker(entry))
return false;
return softleaf_to_marker(entry) & PTE_MARKER_POISONED;
}
/**
* softleaf_is_guard_marker() - Is this leaf entry a guard region marker?
* @entry: Leaf entry.
*
* Returns: true if the leaf entry is a guard marker, otherwise false.
*/
static inline bool softleaf_is_guard_marker(softleaf_t entry)
{
if (!softleaf_is_marker(entry))
return false;
return softleaf_to_marker(entry) & PTE_MARKER_GUARD;
}
/**
* softleaf_is_uffd_wp_marker() - Is this leaf entry a userfautlfd write protect
* marker?
* @entry: Leaf entry.
*
* Userfaultfd-specific.
*
* Returns: true if the leaf entry is a UFFD WP marker, otherwise false.
*/
static inline bool softleaf_is_uffd_wp_marker(softleaf_t entry)
{
if (!softleaf_is_marker(entry))
return false;
return softleaf_to_marker(entry) & PTE_MARKER_UFFD_WP;
}
/**
* pte_is_marker() - Does the PTE entry encode a marker leaf entry?
* @pte: PTE entry.
*
* Returns: true if this PTE is a marker leaf entry, otherwise false.
*/
static inline bool pte_is_marker(pte_t pte)
{
return softleaf_is_marker(softleaf_from_pte(pte));
}
/**
* pte_is_uffd_wp_marker() - Does this PTE entry encode a userfaultfd write
* protect marker leaf entry?
* @pte: PTE entry.
*
* Returns: true if this PTE is a UFFD WP marker leaf entry, otherwise false.
*/
static inline bool pte_is_uffd_wp_marker(pte_t pte)
{
const softleaf_t entry = softleaf_from_pte(pte);
return softleaf_is_uffd_wp_marker(entry);
}
/**
* pte_is_uffd_marker() - Does this PTE entry encode a userfault-specific marker
* leaf entry?
* @entry: Leaf entry.
*
* It's useful to be able to determine which leaf entries encode UFFD-specific
* markers so we can handle these correctly.
*
* Returns: true if this PTE entry is a UFFD-specific marker, otherwise false.
*/
static inline bool pte_is_uffd_marker(pte_t pte)
{
const softleaf_t entry = softleaf_from_pte(pte);
if (!softleaf_is_marker(entry))
return false;
/* UFFD WP, poisoned swap entries are UFFD-handled. */
if (softleaf_is_uffd_wp_marker(entry))
return true;
if (softleaf_is_poison_marker(entry))
return true;
return false;
}
#endif /* CONFIG_MMU */
#endif /* _LINUX_LEAFOPS_H */

View File

@ -8,7 +8,7 @@
#include <linux/swap.h> #include <linux/swap.h>
#include <linux/string.h> #include <linux/string.h>
#include <linux/userfaultfd_k.h> #include <linux/userfaultfd_k.h>
#include <linux/swapops.h> #include <linux/leafops.h>
/** /**
* folio_is_file_lru - Should the folio be on a file LRU or anon LRU? * folio_is_file_lru - Should the folio be on a file LRU or anon LRU?
@ -541,9 +541,9 @@ static inline bool mm_tlb_flush_nested(const struct mm_struct *mm)
* The caller should insert a new pte created with make_pte_marker(). * The caller should insert a new pte created with make_pte_marker().
*/ */
static inline pte_marker copy_pte_marker( static inline pte_marker copy_pte_marker(
swp_entry_t entry, struct vm_area_struct *dst_vma) softleaf_t entry, struct vm_area_struct *dst_vma)
{ {
pte_marker srcm = pte_marker_get(entry); const pte_marker srcm = softleaf_to_marker(entry);
/* Always copy error entries. */ /* Always copy error entries. */
pte_marker dstm = srcm & (PTE_MARKER_POISONED | PTE_MARKER_GUARD); pte_marker dstm = srcm & (PTE_MARKER_POISONED | PTE_MARKER_GUARD);

View File

@ -285,6 +285,31 @@ typedef struct {
unsigned long val; unsigned long val;
} swp_entry_t; } swp_entry_t;
/**
* typedef softleaf_t - Describes a page table software leaf entry, abstracted
* from its architecture-specific encoding.
*
* Page table leaf entries are those which do not reference any descendent page
* tables but rather either reference a data page, are an empty (or 'none'
* entry), or contain a non-present entry.
*
* If referencing another page table or a data page then the page table entry is
* pertinent to hardware - that is it tells the hardware how to decode the page
* table entry.
*
* Otherwise it is a software-defined leaf page table entry, which this type
* describes. See leafops.h and specifically @softleaf_type for a list of all
* possible kinds of software leaf entry.
*
* A softleaf_t entry is abstracted from the hardware page table entry, so is
* not architecture-specific.
*
* NOTE: While we transition from the confusing swp_entry_t type used for this
* purpose, we simply alias this type. This will be removed once the
* transition is complete.
*/
typedef swp_entry_t softleaf_t;
#if defined(CONFIG_MEMCG) || defined(CONFIG_SLAB_OBJ_EXT) #if defined(CONFIG_MEMCG) || defined(CONFIG_SLAB_OBJ_EXT)
/* We have some extra room after the refcount in tail pages. */ /* We have some extra room after the refcount in tail pages. */
#define NR_PAGES_IN_LARGE_FOLIO #define NR_PAGES_IN_LARGE_FOLIO

View File

@ -426,21 +426,6 @@ static inline swp_entry_t make_pte_marker_entry(pte_marker marker)
return swp_entry(SWP_PTE_MARKER, marker); return swp_entry(SWP_PTE_MARKER, marker);
} }
static inline bool is_pte_marker_entry(swp_entry_t entry)
{
return swp_type(entry) == SWP_PTE_MARKER;
}
static inline pte_marker pte_marker_get(swp_entry_t entry)
{
return swp_offset(entry) & PTE_MARKER_MASK;
}
static inline bool is_pte_marker(pte_t pte)
{
return is_swap_pte(pte) && is_pte_marker_entry(pte_to_swp_entry(pte));
}
static inline pte_t make_pte_marker(pte_marker marker) static inline pte_t make_pte_marker(pte_marker marker)
{ {
return swp_entry_to_pte(make_pte_marker_entry(marker)); return swp_entry_to_pte(make_pte_marker_entry(marker));
@ -451,24 +436,11 @@ static inline swp_entry_t make_poisoned_swp_entry(void)
return make_pte_marker_entry(PTE_MARKER_POISONED); return make_pte_marker_entry(PTE_MARKER_POISONED);
} }
static inline int is_poisoned_swp_entry(swp_entry_t entry)
{
return is_pte_marker_entry(entry) &&
(pte_marker_get(entry) & PTE_MARKER_POISONED);
}
static inline swp_entry_t make_guard_swp_entry(void) static inline swp_entry_t make_guard_swp_entry(void)
{ {
return make_pte_marker_entry(PTE_MARKER_GUARD); return make_pte_marker_entry(PTE_MARKER_GUARD);
} }
static inline int is_guard_swp_entry(swp_entry_t entry)
{
return is_pte_marker_entry(entry) &&
(pte_marker_get(entry) & PTE_MARKER_GUARD);
}
static inline struct page *pfn_swap_entry_to_page(swp_entry_t entry) static inline struct page *pfn_swap_entry_to_page(swp_entry_t entry)
{ {
struct page *p = pfn_to_page(swp_offset_pfn(entry)); struct page *p = pfn_to_page(swp_offset_pfn(entry));

View File

@ -16,7 +16,7 @@
#include <linux/fcntl.h> #include <linux/fcntl.h>
#include <linux/mm.h> #include <linux/mm.h>
#include <linux/swap.h> #include <linux/swap.h>
#include <linux/swapops.h> #include <linux/leafops.h>
#include <asm-generic/pgtable_uffd.h> #include <asm-generic/pgtable_uffd.h>
#include <linux/hugetlb_inline.h> #include <linux/hugetlb_inline.h>
@ -434,32 +434,6 @@ static inline bool userfaultfd_wp_use_markers(struct vm_area_struct *vma)
return userfaultfd_wp_unpopulated(vma); return userfaultfd_wp_unpopulated(vma);
} }
static inline bool pte_marker_entry_uffd_wp(swp_entry_t entry)
{
#ifdef CONFIG_PTE_MARKER_UFFD_WP
return is_pte_marker_entry(entry) &&
(pte_marker_get(entry) & PTE_MARKER_UFFD_WP);
#else
return false;
#endif
}
static inline bool pte_marker_uffd_wp(pte_t pte)
{
#ifdef CONFIG_PTE_MARKER_UFFD_WP
swp_entry_t entry;
if (!is_swap_pte(pte))
return false;
entry = pte_to_swp_entry(pte);
return pte_marker_entry_uffd_wp(entry);
#else
return false;
#endif
}
/* /*
* Returns true if this is a swap pte and was uffd-wp wr-protected in either * Returns true if this is a swap pte and was uffd-wp wr-protected in either
* forms (pte marker or a normal swap pte), false otherwise. * forms (pte marker or a normal swap pte), false otherwise.
@ -473,31 +447,10 @@ static inline bool pte_swp_uffd_wp_any(pte_t pte)
if (pte_swp_uffd_wp(pte)) if (pte_swp_uffd_wp(pte))
return true; return true;
if (pte_marker_uffd_wp(pte)) if (pte_is_uffd_wp_marker(pte))
return true; return true;
#endif #endif
return false; return false;
} }
static inline bool is_uffd_pte_marker(pte_t pte)
{
swp_entry_t entry;
if (pte_present(pte))
return false;
entry = pte_to_swp_entry(pte);
if (!is_pte_marker_entry(entry))
return false;
/* UFFD WP, poisoned swap entries are UFFD handled. */
if (pte_marker_entry_uffd_wp(entry))
return true;
if (is_poisoned_swp_entry(entry))
return true;
return false;
}
#endif /* _LINUX_USERFAULTFD_K_H */ #endif /* _LINUX_USERFAULTFD_K_H */

View File

@ -249,7 +249,7 @@ static int hmm_vma_handle_pte(struct mm_walk *walk, unsigned long addr,
* that will be correctly handled, so we need only check for UFFD WP * that will be correctly handled, so we need only check for UFFD WP
* here. * here.
*/ */
if (pte_none(pte) || pte_marker_uffd_wp(pte)) { if (pte_none(pte) || pte_is_uffd_wp_marker(pte)) {
required_fault = required_fault =
hmm_pte_need_fault(hmm_vma_walk, pfn_req_flags, 0); hmm_pte_need_fault(hmm_vma_walk, pfn_req_flags, 0);
if (required_fault) if (required_fault)

View File

@ -26,7 +26,7 @@
#include <linux/string_choices.h> #include <linux/string_choices.h>
#include <linux/string_helpers.h> #include <linux/string_helpers.h>
#include <linux/swap.h> #include <linux/swap.h>
#include <linux/swapops.h> #include <linux/leafops.h>
#include <linux/jhash.h> #include <linux/jhash.h>
#include <linux/numa.h> #include <linux/numa.h>
#include <linux/llist.h> #include <linux/llist.h>
@ -4956,17 +4956,17 @@ int copy_hugetlb_page_range(struct mm_struct *dst, struct mm_struct *src,
entry = huge_pte_clear_uffd_wp(entry); entry = huge_pte_clear_uffd_wp(entry);
set_huge_pte_at(dst, addr, dst_pte, entry, sz); set_huge_pte_at(dst, addr, dst_pte, entry, sz);
} else if (unlikely(is_hugetlb_entry_migration(entry))) { } else if (unlikely(is_hugetlb_entry_migration(entry))) {
swp_entry_t swp_entry = pte_to_swp_entry(entry); softleaf_t softleaf = softleaf_from_pte(entry);
bool uffd_wp = pte_swp_uffd_wp(entry); bool uffd_wp = pte_swp_uffd_wp(entry);
if (!is_readable_migration_entry(swp_entry) && cow) { if (!is_readable_migration_entry(softleaf) && cow) {
/* /*
* COW mappings require pages in both * COW mappings require pages in both
* parent and child to be set to read. * parent and child to be set to read.
*/ */
swp_entry = make_readable_migration_entry( softleaf = make_readable_migration_entry(
swp_offset(swp_entry)); swp_offset(softleaf));
entry = swp_entry_to_pte(swp_entry); entry = swp_entry_to_pte(softleaf);
if (userfaultfd_wp(src_vma) && uffd_wp) if (userfaultfd_wp(src_vma) && uffd_wp)
entry = pte_swp_mkuffd_wp(entry); entry = pte_swp_mkuffd_wp(entry);
set_huge_pte_at(src, addr, src_pte, entry, sz); set_huge_pte_at(src, addr, src_pte, entry, sz);
@ -4974,9 +4974,9 @@ int copy_hugetlb_page_range(struct mm_struct *dst, struct mm_struct *src,
if (!userfaultfd_wp(dst_vma)) if (!userfaultfd_wp(dst_vma))
entry = huge_pte_clear_uffd_wp(entry); entry = huge_pte_clear_uffd_wp(entry);
set_huge_pte_at(dst, addr, dst_pte, entry, sz); set_huge_pte_at(dst, addr, dst_pte, entry, sz);
} else if (unlikely(is_pte_marker(entry))) { } else if (unlikely(pte_is_marker(entry))) {
pte_marker marker = copy_pte_marker( const softleaf_t softleaf = softleaf_from_pte(entry);
pte_to_swp_entry(entry), dst_vma); const pte_marker marker = copy_pte_marker(softleaf, dst_vma);
if (marker) if (marker)
set_huge_pte_at(dst, addr, dst_pte, set_huge_pte_at(dst, addr, dst_pte,
@ -5092,7 +5092,7 @@ static void move_huge_pte(struct vm_area_struct *vma, unsigned long old_addr,
pte = huge_ptep_get_and_clear(mm, old_addr, src_pte, sz); pte = huge_ptep_get_and_clear(mm, old_addr, src_pte, sz);
if (need_clear_uffd_wp && pte_marker_uffd_wp(pte)) if (need_clear_uffd_wp && pte_is_uffd_wp_marker(pte))
huge_pte_clear(mm, new_addr, dst_pte, sz); huge_pte_clear(mm, new_addr, dst_pte, sz);
else { else {
if (need_clear_uffd_wp) { if (need_clear_uffd_wp) {
@ -5911,7 +5911,7 @@ static vm_fault_t hugetlb_no_page(struct address_space *mapping,
* If this pte was previously wr-protected, keep it wr-protected even * If this pte was previously wr-protected, keep it wr-protected even
* if populated. * if populated.
*/ */
if (unlikely(pte_marker_uffd_wp(vmf->orig_pte))) if (unlikely(pte_is_uffd_wp_marker(vmf->orig_pte)))
new_pte = huge_pte_mkuffd_wp(new_pte); new_pte = huge_pte_mkuffd_wp(new_pte);
set_huge_pte_at(mm, vmf->address, vmf->pte, new_pte, huge_page_size(h)); set_huge_pte_at(mm, vmf->address, vmf->pte, new_pte, huge_page_size(h));
@ -6044,9 +6044,9 @@ vm_fault_t hugetlb_fault(struct mm_struct *mm, struct vm_area_struct *vma,
*/ */
return hugetlb_no_page(mapping, &vmf); return hugetlb_no_page(mapping, &vmf);
if (is_pte_marker(vmf.orig_pte)) { if (pte_is_marker(vmf.orig_pte)) {
const pte_marker marker = const pte_marker marker =
pte_marker_get(pte_to_swp_entry(vmf.orig_pte)); softleaf_to_marker(softleaf_from_pte(vmf.orig_pte));
if (marker & PTE_MARKER_POISONED) { if (marker & PTE_MARKER_POISONED) {
ret = VM_FAULT_HWPOISON_LARGE | ret = VM_FAULT_HWPOISON_LARGE |
@ -6374,7 +6374,7 @@ int hugetlb_mfill_atomic_pte(pte_t *dst_pte,
* See comment about UFFD marker overwriting in * See comment about UFFD marker overwriting in
* mfill_atomic_install_pte(). * mfill_atomic_install_pte().
*/ */
if (!huge_pte_none(dst_ptep) && !is_uffd_pte_marker(dst_ptep)) if (!huge_pte_none(dst_ptep) && !pte_is_uffd_marker(dst_ptep))
goto out_release_unlock; goto out_release_unlock;
if (folio_in_pagecache) if (folio_in_pagecache)
@ -6495,8 +6495,9 @@ long hugetlb_change_protection(struct vm_area_struct *vma,
if (unlikely(is_hugetlb_entry_hwpoisoned(pte))) { if (unlikely(is_hugetlb_entry_hwpoisoned(pte))) {
/* Nothing to do. */ /* Nothing to do. */
} else if (unlikely(is_hugetlb_entry_migration(pte))) { } else if (unlikely(is_hugetlb_entry_migration(pte))) {
swp_entry_t entry = pte_to_swp_entry(pte); softleaf_t entry = softleaf_from_pte(pte);
struct folio *folio = pfn_swap_entry_folio(entry);
struct folio *folio = softleaf_to_folio(entry);
pte_t newpte = pte; pte_t newpte = pte;
if (is_writable_migration_entry(entry)) { if (is_writable_migration_entry(entry)) {
@ -6516,14 +6517,14 @@ long hugetlb_change_protection(struct vm_area_struct *vma,
newpte = pte_swp_clear_uffd_wp(newpte); newpte = pte_swp_clear_uffd_wp(newpte);
if (!pte_same(pte, newpte)) if (!pte_same(pte, newpte))
set_huge_pte_at(mm, address, ptep, newpte, psize); set_huge_pte_at(mm, address, ptep, newpte, psize);
} else if (unlikely(is_pte_marker(pte))) { } else if (unlikely(pte_is_marker(pte))) {
/* /*
* Do nothing on a poison marker; page is * Do nothing on a poison marker; page is
* corrupted, permissions do not apply. Here * corrupted, permissions do not apply. Here
* pte_marker_uffd_wp()==true implies !poison * pte_marker_uffd_wp()==true implies !poison
* because they're mutual exclusive. * because they're mutual exclusive.
*/ */
if (pte_marker_uffd_wp(pte) && uffd_wp_resolve) if (pte_is_uffd_wp_marker(pte) && uffd_wp_resolve)
/* Safe to modify directly (non-present->none). */ /* Safe to modify directly (non-present->none). */
huge_pte_clear(mm, address, ptep, psize); huge_pte_clear(mm, address, ptep, psize);
} else if (!huge_pte_none(pte)) { } else if (!huge_pte_none(pte)) {

View File

@ -29,7 +29,7 @@
#include <linux/backing-dev.h> #include <linux/backing-dev.h>
#include <linux/pagewalk.h> #include <linux/pagewalk.h>
#include <linux/swap.h> #include <linux/swap.h>
#include <linux/swapops.h> #include <linux/leafops.h>
#include <linux/shmem_fs.h> #include <linux/shmem_fs.h>
#include <linux/mmu_notifier.h> #include <linux/mmu_notifier.h>
@ -690,17 +690,16 @@ static int madvise_free_pte_range(pmd_t *pmd, unsigned long addr,
* (page allocation + zeroing). * (page allocation + zeroing).
*/ */
if (!pte_present(ptent)) { if (!pte_present(ptent)) {
swp_entry_t entry; softleaf_t entry = softleaf_from_pte(ptent);
entry = pte_to_swp_entry(ptent); if (softleaf_is_swap(entry)) {
if (!non_swap_entry(entry)) {
max_nr = (end - addr) / PAGE_SIZE; max_nr = (end - addr) / PAGE_SIZE;
nr = swap_pte_batch(pte, max_nr, ptent); nr = swap_pte_batch(pte, max_nr, ptent);
nr_swap -= nr; nr_swap -= nr;
free_swap_and_cache_nr(entry, nr); free_swap_and_cache_nr(entry, nr);
clear_not_present_full_ptes(mm, addr, pte, nr, tlb->fullmm); clear_not_present_full_ptes(mm, addr, pte, nr, tlb->fullmm);
} else if (is_hwpoison_entry(entry) || } else if (softleaf_is_hwpoison(entry) ||
is_poisoned_swp_entry(entry)) { softleaf_is_poison_marker(entry)) {
pte_clear_not_present_full(mm, addr, pte, tlb->fullmm); pte_clear_not_present_full(mm, addr, pte, tlb->fullmm);
} }
continue; continue;
@ -1071,8 +1070,9 @@ static bool is_valid_guard_vma(struct vm_area_struct *vma, bool allow_locked)
static bool is_guard_pte_marker(pte_t ptent) static bool is_guard_pte_marker(pte_t ptent)
{ {
return is_swap_pte(ptent) && const softleaf_t entry = softleaf_from_pte(ptent);
is_guard_swp_entry(pte_to_swp_entry(ptent));
return softleaf_is_guard_marker(entry);
} }
static int guard_install_pud_entry(pud_t *pud, unsigned long addr, static int guard_install_pud_entry(pud_t *pud, unsigned long addr,

View File

@ -60,7 +60,7 @@
#include <linux/writeback.h> #include <linux/writeback.h>
#include <linux/memcontrol.h> #include <linux/memcontrol.h>
#include <linux/mmu_notifier.h> #include <linux/mmu_notifier.h>
#include <linux/swapops.h> #include <linux/leafops.h>
#include <linux/elf.h> #include <linux/elf.h>
#include <linux/gfp.h> #include <linux/gfp.h>
#include <linux/migrate.h> #include <linux/migrate.h>
@ -109,7 +109,7 @@ static __always_inline bool vmf_orig_pte_uffd_wp(struct vm_fault *vmf)
if (!(vmf->flags & FAULT_FLAG_ORIG_PTE_VALID)) if (!(vmf->flags & FAULT_FLAG_ORIG_PTE_VALID))
return false; return false;
return pte_marker_uffd_wp(vmf->orig_pte); return pte_is_uffd_wp_marker(vmf->orig_pte);
} }
/* /*
@ -927,10 +927,10 @@ copy_nonpresent_pte(struct mm_struct *dst_mm, struct mm_struct *src_mm,
{ {
vm_flags_t vm_flags = dst_vma->vm_flags; vm_flags_t vm_flags = dst_vma->vm_flags;
pte_t orig_pte = ptep_get(src_pte); pte_t orig_pte = ptep_get(src_pte);
softleaf_t entry = softleaf_from_pte(orig_pte);
pte_t pte = orig_pte; pte_t pte = orig_pte;
struct folio *folio; struct folio *folio;
struct page *page; struct page *page;
swp_entry_t entry = pte_to_swp_entry(orig_pte);
if (likely(!non_swap_entry(entry))) { if (likely(!non_swap_entry(entry))) {
if (swap_duplicate(entry) < 0) if (swap_duplicate(entry) < 0)
@ -1016,7 +1016,7 @@ copy_nonpresent_pte(struct mm_struct *dst_mm, struct mm_struct *src_mm,
if (try_restore_exclusive_pte(src_vma, addr, src_pte, orig_pte)) if (try_restore_exclusive_pte(src_vma, addr, src_pte, orig_pte))
return -EBUSY; return -EBUSY;
return -ENOENT; return -ENOENT;
} else if (is_pte_marker_entry(entry)) { } else if (softleaf_is_marker(entry)) {
pte_marker marker = copy_pte_marker(entry, dst_vma); pte_marker marker = copy_pte_marker(entry, dst_vma);
if (marker) if (marker)
@ -1711,14 +1711,14 @@ static inline int zap_nonpresent_ptes(struct mmu_gather *tlb,
unsigned int max_nr, unsigned long addr, unsigned int max_nr, unsigned long addr,
struct zap_details *details, int *rss, bool *any_skipped) struct zap_details *details, int *rss, bool *any_skipped)
{ {
swp_entry_t entry; softleaf_t entry;
int nr = 1; int nr = 1;
*any_skipped = true; *any_skipped = true;
entry = pte_to_swp_entry(ptent); entry = softleaf_from_pte(ptent);
if (is_device_private_entry(entry) || if (softleaf_is_device_private(entry) ||
is_device_exclusive_entry(entry)) { softleaf_is_device_exclusive(entry)) {
struct page *page = pfn_swap_entry_to_page(entry); struct page *page = softleaf_to_page(entry);
struct folio *folio = page_folio(page); struct folio *folio = page_folio(page);
if (unlikely(!should_zap_folio(details, folio))) if (unlikely(!should_zap_folio(details, folio)))
@ -1733,7 +1733,7 @@ static inline int zap_nonpresent_ptes(struct mmu_gather *tlb,
rss[mm_counter(folio)]--; rss[mm_counter(folio)]--;
folio_remove_rmap_pte(folio, page, vma); folio_remove_rmap_pte(folio, page, vma);
folio_put(folio); folio_put(folio);
} else if (!non_swap_entry(entry)) { } else if (softleaf_is_swap(entry)) {
/* Genuine swap entries, hence a private anon pages */ /* Genuine swap entries, hence a private anon pages */
if (!should_zap_cows(details)) if (!should_zap_cows(details))
return 1; return 1;
@ -1741,20 +1741,20 @@ static inline int zap_nonpresent_ptes(struct mmu_gather *tlb,
nr = swap_pte_batch(pte, max_nr, ptent); nr = swap_pte_batch(pte, max_nr, ptent);
rss[MM_SWAPENTS] -= nr; rss[MM_SWAPENTS] -= nr;
free_swap_and_cache_nr(entry, nr); free_swap_and_cache_nr(entry, nr);
} else if (is_migration_entry(entry)) { } else if (softleaf_is_migration(entry)) {
struct folio *folio = pfn_swap_entry_folio(entry); struct folio *folio = softleaf_to_folio(entry);
if (!should_zap_folio(details, folio)) if (!should_zap_folio(details, folio))
return 1; return 1;
rss[mm_counter(folio)]--; rss[mm_counter(folio)]--;
} else if (pte_marker_entry_uffd_wp(entry)) { } else if (softleaf_is_uffd_wp_marker(entry)) {
/* /*
* For anon: always drop the marker; for file: only * For anon: always drop the marker; for file: only
* drop the marker if explicitly requested. * drop the marker if explicitly requested.
*/ */
if (!vma_is_anonymous(vma) && !zap_drop_markers(details)) if (!vma_is_anonymous(vma) && !zap_drop_markers(details))
return 1; return 1;
} else if (is_guard_swp_entry(entry)) { } else if (softleaf_is_guard_marker(entry)) {
/* /*
* Ordinary zapping should not remove guard PTE * Ordinary zapping should not remove guard PTE
* markers. Only do so if we should remove PTE markers * markers. Only do so if we should remove PTE markers
@ -1762,7 +1762,8 @@ static inline int zap_nonpresent_ptes(struct mmu_gather *tlb,
*/ */
if (!zap_drop_markers(details)) if (!zap_drop_markers(details))
return 1; return 1;
} else if (is_hwpoison_entry(entry) || is_poisoned_swp_entry(entry)) { } else if (softleaf_is_hwpoison(entry) ||
softleaf_is_poison_marker(entry)) {
if (!should_zap_cows(details)) if (!should_zap_cows(details))
return 1; return 1;
} else { } else {
@ -4380,7 +4381,7 @@ static vm_fault_t pte_marker_clear(struct vm_fault *vmf)
* *
* This should also cover the case where e.g. the pte changed * This should also cover the case where e.g. the pte changed
* quickly from a PTE_MARKER_UFFD_WP into PTE_MARKER_POISONED. * quickly from a PTE_MARKER_UFFD_WP into PTE_MARKER_POISONED.
* So is_pte_marker() check is not enough to safely drop the pte. * So pte_is_marker() check is not enough to safely drop the pte.
*/ */
if (pte_same(vmf->orig_pte, ptep_get(vmf->pte))) if (pte_same(vmf->orig_pte, ptep_get(vmf->pte)))
pte_clear(vmf->vma->vm_mm, vmf->address, vmf->pte); pte_clear(vmf->vma->vm_mm, vmf->address, vmf->pte);
@ -4414,8 +4415,8 @@ static vm_fault_t pte_marker_handle_uffd_wp(struct vm_fault *vmf)
static vm_fault_t handle_pte_marker(struct vm_fault *vmf) static vm_fault_t handle_pte_marker(struct vm_fault *vmf)
{ {
swp_entry_t entry = pte_to_swp_entry(vmf->orig_pte); const softleaf_t entry = softleaf_from_pte(vmf->orig_pte);
unsigned long marker = pte_marker_get(entry); const pte_marker marker = softleaf_to_marker(entry);
/* /*
* PTE markers should never be empty. If anything weird happened, * PTE markers should never be empty. If anything weird happened,
@ -4432,7 +4433,7 @@ static vm_fault_t handle_pte_marker(struct vm_fault *vmf)
if (marker & PTE_MARKER_GUARD) if (marker & PTE_MARKER_GUARD)
return VM_FAULT_SIGSEGV; return VM_FAULT_SIGSEGV;
if (pte_marker_entry_uffd_wp(entry)) if (softleaf_is_uffd_wp_marker(entry))
return pte_marker_handle_uffd_wp(vmf); return pte_marker_handle_uffd_wp(vmf);
/* This is an unknown pte marker */ /* This is an unknown pte marker */
@ -4680,7 +4681,7 @@ vm_fault_t do_swap_page(struct vm_fault *vmf)
} }
} else if (is_hwpoison_entry(entry)) { } else if (is_hwpoison_entry(entry)) {
ret = VM_FAULT_HWPOISON; ret = VM_FAULT_HWPOISON;
} else if (is_pte_marker_entry(entry)) { } else if (softleaf_is_marker(entry)) {
ret = handle_pte_marker(vmf); ret = handle_pte_marker(vmf);
} else { } else {
print_bad_pte(vma, vmf->address, vmf->orig_pte, NULL); print_bad_pte(vma, vmf->address, vmf->orig_pte, NULL);

View File

@ -14,7 +14,7 @@
#include <linux/mman.h> #include <linux/mman.h>
#include <linux/syscalls.h> #include <linux/syscalls.h>
#include <linux/swap.h> #include <linux/swap.h>
#include <linux/swapops.h> #include <linux/leafops.h>
#include <linux/shmem_fs.h> #include <linux/shmem_fs.h>
#include <linux/hugetlb.h> #include <linux/hugetlb.h>
#include <linux/pgtable.h> #include <linux/pgtable.h>
@ -42,7 +42,7 @@ static int mincore_hugetlb(pte_t *pte, unsigned long hmask, unsigned long addr,
} else { } else {
const pte_t ptep = huge_ptep_get(walk->mm, addr, pte); const pte_t ptep = huge_ptep_get(walk->mm, addr, pte);
if (huge_pte_none(ptep) || is_pte_marker(ptep)) if (huge_pte_none(ptep) || pte_is_marker(ptep))
present = 0; present = 0;
else else
present = 1; present = 1;
@ -187,7 +187,7 @@ static int mincore_pte_range(pmd_t *pmd, unsigned long addr, unsigned long end,
step = 1; step = 1;
/* We need to do cache lookup too for markers */ /* We need to do cache lookup too for markers */
if (pte_none(pte) || is_pte_marker(pte)) if (pte_none(pte) || pte_is_marker(pte))
__mincore_unmapped_range(addr, addr + PAGE_SIZE, __mincore_unmapped_range(addr, addr + PAGE_SIZE,
vma, vec); vma, vec);
else if (pte_present(pte)) { else if (pte_present(pte)) {

View File

@ -326,14 +326,14 @@ static long change_pte_range(struct mmu_gather *tlb,
newpte = swp_entry_to_pte(entry); newpte = swp_entry_to_pte(entry);
if (pte_swp_uffd_wp(oldpte)) if (pte_swp_uffd_wp(oldpte))
newpte = pte_swp_mkuffd_wp(newpte); newpte = pte_swp_mkuffd_wp(newpte);
} else if (is_pte_marker_entry(entry)) { } else if (softleaf_is_marker(entry)) {
/* /*
* Ignore error swap entries unconditionally, * Ignore error swap entries unconditionally,
* because any access should sigbus/sigsegv * because any access should sigbus/sigsegv
* anyway. * anyway.
*/ */
if (is_poisoned_swp_entry(entry) || if (softleaf_is_poison_marker(entry) ||
is_guard_swp_entry(entry)) softleaf_is_guard_marker(entry))
continue; continue;
/* /*
* If this is uffd-wp pte marker and we'd like * If this is uffd-wp pte marker and we'd like

View File

@ -17,7 +17,7 @@
#include <linux/swap.h> #include <linux/swap.h>
#include <linux/capability.h> #include <linux/capability.h>
#include <linux/fs.h> #include <linux/fs.h>
#include <linux/swapops.h> #include <linux/leafops.h>
#include <linux/highmem.h> #include <linux/highmem.h>
#include <linux/security.h> #include <linux/security.h>
#include <linux/syscalls.h> #include <linux/syscalls.h>
@ -288,7 +288,7 @@ static int move_ptes(struct pagetable_move_control *pmc,
pte = move_pte(pte, old_addr, new_addr); pte = move_pte(pte, old_addr, new_addr);
pte = move_soft_dirty_pte(pte); pte = move_soft_dirty_pte(pte);
if (need_clear_uffd_wp && pte_marker_uffd_wp(pte)) if (need_clear_uffd_wp && pte_is_uffd_wp_marker(pte))
pte_clear(mm, new_addr, new_ptep); pte_clear(mm, new_addr, new_ptep);
else { else {
if (need_clear_uffd_wp) { if (need_clear_uffd_wp) {

View File

@ -3,7 +3,7 @@
#include <linux/rmap.h> #include <linux/rmap.h>
#include <linux/hugetlb.h> #include <linux/hugetlb.h>
#include <linux/swap.h> #include <linux/swap.h>
#include <linux/swapops.h> #include <linux/leafops.h>
#include "internal.h" #include "internal.h"
@ -107,15 +107,12 @@ static bool check_pte(struct page_vma_mapped_walk *pvmw, unsigned long pte_nr)
pte_t ptent = ptep_get(pvmw->pte); pte_t ptent = ptep_get(pvmw->pte);
if (pvmw->flags & PVMW_MIGRATION) { if (pvmw->flags & PVMW_MIGRATION) {
swp_entry_t entry; const softleaf_t entry = softleaf_from_pte(ptent);
if (!is_swap_pte(ptent))
return false;
entry = pte_to_swp_entry(ptent);
if (!is_migration_entry(entry)) if (!softleaf_is_migration(entry))
return false; return false;
pfn = swp_offset_pfn(entry); pfn = softleaf_to_pfn(entry);
} else if (is_swap_pte(ptent)) { } else if (is_swap_pte(ptent)) {
swp_entry_t entry; swp_entry_t entry;

View File

@ -66,7 +66,7 @@ static struct vfsmount *shm_mnt __ro_after_init;
#include <linux/falloc.h> #include <linux/falloc.h>
#include <linux/splice.h> #include <linux/splice.h>
#include <linux/security.h> #include <linux/security.h>
#include <linux/swapops.h> #include <linux/leafops.h>
#include <linux/mempolicy.h> #include <linux/mempolicy.h>
#include <linux/namei.h> #include <linux/namei.h>
#include <linux/ctype.h> #include <linux/ctype.h>
@ -2286,7 +2286,8 @@ static int shmem_swapin_folio(struct inode *inode, pgoff_t index,
struct address_space *mapping = inode->i_mapping; struct address_space *mapping = inode->i_mapping;
struct mm_struct *fault_mm = vma ? vma->vm_mm : NULL; struct mm_struct *fault_mm = vma ? vma->vm_mm : NULL;
struct shmem_inode_info *info = SHMEM_I(inode); struct shmem_inode_info *info = SHMEM_I(inode);
swp_entry_t swap, index_entry; swp_entry_t swap;
softleaf_t index_entry;
struct swap_info_struct *si; struct swap_info_struct *si;
struct folio *folio = NULL; struct folio *folio = NULL;
bool skip_swapcache = false; bool skip_swapcache = false;
@ -2298,7 +2299,7 @@ static int shmem_swapin_folio(struct inode *inode, pgoff_t index,
swap = index_entry; swap = index_entry;
*foliop = NULL; *foliop = NULL;
if (is_poisoned_swp_entry(index_entry)) if (softleaf_is_poison_marker(index_entry))
return -EIO; return -EIO;
si = get_swap_device(index_entry); si = get_swap_device(index_entry);

View File

@ -10,7 +10,7 @@
#include <linux/pagemap.h> #include <linux/pagemap.h>
#include <linux/rmap.h> #include <linux/rmap.h>
#include <linux/swap.h> #include <linux/swap.h>
#include <linux/swapops.h> #include <linux/leafops.h>
#include <linux/userfaultfd_k.h> #include <linux/userfaultfd_k.h>
#include <linux/mmu_notifier.h> #include <linux/mmu_notifier.h>
#include <linux/hugetlb.h> #include <linux/hugetlb.h>
@ -208,7 +208,7 @@ int mfill_atomic_install_pte(pmd_t *dst_pmd,
* MISSING|WP registered, we firstly wr-protect a none pte which has no * MISSING|WP registered, we firstly wr-protect a none pte which has no
* page cache page backing it, then access the page. * page cache page backing it, then access the page.
*/ */
if (!pte_none(dst_ptep) && !is_uffd_pte_marker(dst_ptep)) if (!pte_none(dst_ptep) && !pte_is_uffd_marker(dst_ptep))
goto out_unlock; goto out_unlock;
if (page_in_cache) { if (page_in_cache) {
@ -590,7 +590,7 @@ static __always_inline ssize_t mfill_atomic_hugetlb(
if (!uffd_flags_mode_is(flags, MFILL_ATOMIC_CONTINUE)) { if (!uffd_flags_mode_is(flags, MFILL_ATOMIC_CONTINUE)) {
const pte_t ptep = huge_ptep_get(dst_mm, dst_addr, dst_pte); const pte_t ptep = huge_ptep_get(dst_mm, dst_addr, dst_pte);
if (!huge_pte_none(ptep) && !is_uffd_pte_marker(ptep)) { if (!huge_pte_none(ptep) && !pte_is_uffd_marker(ptep)) {
err = -EEXIST; err = -EEXIST;
hugetlb_vma_unlock_read(dst_vma); hugetlb_vma_unlock_read(dst_vma);
mutex_unlock(&hugetlb_fault_mutex_table[hash]); mutex_unlock(&hugetlb_fault_mutex_table[hash]);