diff mbox series

[v4,1/8] mm: make PTE_MARKER_SWAPIN_ERROR more general

Message ID 20230707215540.2324998-2-axelrasmussen@google.com (mailing list archive)
State New
Headers show
Series add UFFDIO_POISON to simulate memory poisoning with UFFD | expand

Commit Message

Axel Rasmussen July 7, 2023, 9:55 p.m. UTC
Future patches will re-use PTE_MARKER_SWAPIN_ERROR to implement
UFFDIO_POISON, so make some various preparations for that:

First, rename it to just PTE_MARKER_POISONED. The "SWAPIN" can be
confusing since we're going to re-use it for something not really
related to swap. This can be particularly confusing for things like
hugetlbfs, which doesn't support swap whatsoever. Also rename some
various helper functions.

Next, fix pte marker copying for hugetlbfs. Previously, it would WARN on
seeing a PTE_MARKER_SWAPIN_ERROR, since hugetlbfs doesn't support swap.
But, since we're going to re-use it, we want it to go ahead and copy it
just like non-hugetlbfs memory does today. Since the code to do this is
more complicated now, pull it out into a helper which can be re-used in
both places. While we're at it, also make it slightly more explicit in
its handling of e.g. uffd wp markers.

For non-hugetlbfs page faults, instead of returning VM_FAULT_SIGBUS for
an error entry, return VM_FAULT_HWPOISON. For most cases this change
doesn't matter, e.g. a userspace program would receive a SIGBUS either
way. But for UFFDIO_POISON, this change will let KVM guests get an MCE
out of the box, instead of giving a SIGBUS to the hypervisor and
requiring it to somehow inject an MCE.

Finally, for hugetlbfs faults, handle PTE_MARKER_POISONED, and return
VM_FAULT_HWPOISON_LARGE in such cases. Note that this can't happen today
because the lack of swap support means we'll never end up with such a
PTE anyway, but this behavior will be needed once such entries *can*
show up via UFFDIO_POISON.

Signed-off-by: Axel Rasmussen <axelrasmussen@google.com>
---
 include/linux/mm_inline.h | 19 +++++++++++++++++++
 include/linux/swapops.h   | 15 ++++++++++-----
 mm/hugetlb.c              | 32 +++++++++++++++++++++-----------
 mm/madvise.c              |  2 +-
 mm/memory.c               | 15 +++++++++------
 mm/mprotect.c             |  4 ++--
 mm/shmem.c                |  4 ++--
 mm/swapfile.c             |  2 +-
 8 files changed, 65 insertions(+), 28 deletions(-)

Comments

Peter Xu July 8, 2023, 3 p.m. UTC | #1
On Fri, Jul 07, 2023 at 02:55:33PM -0700, Axel Rasmussen wrote:
> -static inline swp_entry_t make_swapin_error_entry(void)
> +static inline swp_entry_t make_poisoned_swp_entry(void)
>  {
> -	return make_pte_marker_entry(PTE_MARKER_SWAPIN_ERROR);
> +	return make_pte_marker_entry(PTE_MARKER_POISONED);
>  }
>  
> -static inline int is_swapin_error_entry(swp_entry_t entry)
> +static inline int is_poisoned_swp_entry(swp_entry_t entry)
>  {
>  	return is_pte_marker_entry(entry) &&
> -	    (pte_marker_get(entry) & PTE_MARKER_SWAPIN_ERROR);
> +	    (pte_marker_get(entry) & PTE_MARKER_POISONED);
>  }

These two can be slightly confusing when put together with hwpoison
entries, so maybe it'll be good to somehow attach a "marker" inside the
names:

  make_poisoned_marker_entry()
  is_pointed_marker_entry()

(the old helpers didn't attach a "marker" keyword because we started with
 consuming a swp entry type, I think)

But we can still identify easily with "hw" prefix being there or not, so
it's still pretty clear at least to me.  I'd say not worth a repost, so
your call to keep or change, just in case a new version for other reasons.
All fine here now:

Acked-by: Peter Xu <peterx@redhat.com>

Thanks,
Andrew Morton July 9, 2023, 1:08 a.m. UTC | #2
On Fri,  7 Jul 2023 14:55:33 -0700 Axel Rasmussen <axelrasmussen@google.com> wrote:

> Future patches will re-use PTE_MARKER_SWAPIN_ERROR to implement
> UFFDIO_POISON, so make some various preparations for that:
> 
> First, rename it to just PTE_MARKER_POISONED. The "SWAPIN" can be
> confusing since we're going to re-use it for something not really
> related to swap. This can be particularly confusing for things like
> hugetlbfs, which doesn't support swap whatsoever. Also rename some
> various helper functions.
> 
> Next, fix pte marker copying for hugetlbfs. Previously, it would WARN on
> seeing a PTE_MARKER_SWAPIN_ERROR, since hugetlbfs doesn't support swap.
> But, since we're going to re-use it, we want it to go ahead and copy it
> just like non-hugetlbfs memory does today. Since the code to do this is
> more complicated now, pull it out into a helper which can be re-used in
> both places. While we're at it, also make it slightly more explicit in
> its handling of e.g. uffd wp markers.
> 
> For non-hugetlbfs page faults, instead of returning VM_FAULT_SIGBUS for
> an error entry, return VM_FAULT_HWPOISON. For most cases this change
> doesn't matter, e.g. a userspace program would receive a SIGBUS either
> way. But for UFFDIO_POISON, this change will let KVM guests get an MCE
> out of the box, instead of giving a SIGBUS to the hypervisor and
> requiring it to somehow inject an MCE.
> 
> Finally, for hugetlbfs faults, handle PTE_MARKER_POISONED, and return
> VM_FAULT_HWPOISON_LARGE in such cases. Note that this can't happen today
> because the lack of swap support means we'll never end up with such a
> PTE anyway, but this behavior will be needed once such entries *can*
> show up via UFFDIO_POISON.
> 
> --- a/include/linux/mm_inline.h
> +++ b/include/linux/mm_inline.h
> @@ -523,6 +523,25 @@ static inline bool mm_tlb_flush_nested(struct mm_struct *mm)
>  	return atomic_read(&mm->tlb_flush_pending) > 1;
>  }
>  
> +/*
> + * Computes the pte marker to copy from the given source entry into dst_vma.
> + * If no marker should be copied, returns 0.
> + * The caller should insert a new pte created with make_pte_marker().
> + */
> +static inline pte_marker copy_pte_marker(
> +		swp_entry_t entry, struct vm_area_struct *dst_vma)
> +{
> +	pte_marker srcm = pte_marker_get(entry);
> +	/* Always copy error entries. */
> +	pte_marker dstm = srcm & PTE_MARKER_POISONED;
> +
> +	/* Only copy PTE markers if UFFD register matches. */
> +	if ((srcm & PTE_MARKER_UFFD_WP) && userfaultfd_wp(dst_vma))
> +		dstm |= PTE_MARKER_UFFD_WP;
> +
> +	return dstm;
> +}

Breaks the build with CONFIG_MMU=n (arm allnoconfig).  pte_marker isn't
defined.

I'll slap #ifdef CONFIG_MMU around this function, but probably somethng more
fine-grained could be used, like CONFIG_PTE_MARKER_UFFD_WP.  Please
consider.

btw, both copy_pte_marker() and pte_install_uffd_wp_if_needed() look
far too large to justify inlining.  Please review the desirability of
this.
Axel Rasmussen July 10, 2023, 5:19 p.m. UTC | #3
On Sat, Jul 8, 2023 at 6:08 PM Andrew Morton <akpm@linux-foundation.org> wrote:
>
> On Fri,  7 Jul 2023 14:55:33 -0700 Axel Rasmussen <axelrasmussen@google.com> wrote:
>
> > Future patches will re-use PTE_MARKER_SWAPIN_ERROR to implement
> > UFFDIO_POISON, so make some various preparations for that:
> >
> > First, rename it to just PTE_MARKER_POISONED. The "SWAPIN" can be
> > confusing since we're going to re-use it for something not really
> > related to swap. This can be particularly confusing for things like
> > hugetlbfs, which doesn't support swap whatsoever. Also rename some
> > various helper functions.
> >
> > Next, fix pte marker copying for hugetlbfs. Previously, it would WARN on
> > seeing a PTE_MARKER_SWAPIN_ERROR, since hugetlbfs doesn't support swap.
> > But, since we're going to re-use it, we want it to go ahead and copy it
> > just like non-hugetlbfs memory does today. Since the code to do this is
> > more complicated now, pull it out into a helper which can be re-used in
> > both places. While we're at it, also make it slightly more explicit in
> > its handling of e.g. uffd wp markers.
> >
> > For non-hugetlbfs page faults, instead of returning VM_FAULT_SIGBUS for
> > an error entry, return VM_FAULT_HWPOISON. For most cases this change
> > doesn't matter, e.g. a userspace program would receive a SIGBUS either
> > way. But for UFFDIO_POISON, this change will let KVM guests get an MCE
> > out of the box, instead of giving a SIGBUS to the hypervisor and
> > requiring it to somehow inject an MCE.
> >
> > Finally, for hugetlbfs faults, handle PTE_MARKER_POISONED, and return
> > VM_FAULT_HWPOISON_LARGE in such cases. Note that this can't happen today
> > because the lack of swap support means we'll never end up with such a
> > PTE anyway, but this behavior will be needed once such entries *can*
> > show up via UFFDIO_POISON.
> >
> > --- a/include/linux/mm_inline.h
> > +++ b/include/linux/mm_inline.h
> > @@ -523,6 +523,25 @@ static inline bool mm_tlb_flush_nested(struct mm_struct *mm)
> >       return atomic_read(&mm->tlb_flush_pending) > 1;
> >  }
> >
> > +/*
> > + * Computes the pte marker to copy from the given source entry into dst_vma.
> > + * If no marker should be copied, returns 0.
> > + * The caller should insert a new pte created with make_pte_marker().
> > + */
> > +static inline pte_marker copy_pte_marker(
> > +             swp_entry_t entry, struct vm_area_struct *dst_vma)
> > +{
> > +     pte_marker srcm = pte_marker_get(entry);
> > +     /* Always copy error entries. */
> > +     pte_marker dstm = srcm & PTE_MARKER_POISONED;
> > +
> > +     /* Only copy PTE markers if UFFD register matches. */
> > +     if ((srcm & PTE_MARKER_UFFD_WP) && userfaultfd_wp(dst_vma))
> > +             dstm |= PTE_MARKER_UFFD_WP;
> > +
> > +     return dstm;
> > +}
>
> Breaks the build with CONFIG_MMU=n (arm allnoconfig).  pte_marker isn't
> defined.
>
> I'll slap #ifdef CONFIG_MMU around this function, but probably somethng more
> fine-grained could be used, like CONFIG_PTE_MARKER_UFFD_WP.  Please
> consider.

Whoops, sorry about this. This function "ought" to be in
include/linux/swapops.h where it would be inside a #ifdef CONFIG_MMU
anyway, but it can't be because it uses userfaultfd_wp() so there'd be
a circular include. I think just wrapping it in CONFIG_MMU is the
right way.

But, this has also made me realize we need to not advertise
UFFDIO_POISON as supported unless we have CONFIG_MMU. I don't want
HAVE_ARCH_USERFAULTFD_WP for that, because it's only enabled on
x86_64, whereas I want to support at least arm64 as well. I don't see
a strong reason not to just use CONFIG_MMU for this too; this feature
depends on the API in swapops.h, which uses that ifdef, so I don't see
a lot of value out of creating a new but equivalent config option.

I'll make the needed changes (and also address Peter's comment above)
and send out a v5.

>
> btw, both copy_pte_marker() and pte_install_uffd_wp_if_needed() look
> far too large to justify inlining.  Please review the desirability of
> this.
>
>
Axel Rasmussen July 10, 2023, 9:59 p.m. UTC | #4
On Mon, Jul 10, 2023 at 10:19 AM Axel Rasmussen
<axelrasmussen@google.com> wrote:
>
> On Sat, Jul 8, 2023 at 6:08 PM Andrew Morton <akpm@linux-foundation.org> wrote:
> >
> > On Fri,  7 Jul 2023 14:55:33 -0700 Axel Rasmussen <axelrasmussen@google.com> wrote:
> >
> > > Future patches will re-use PTE_MARKER_SWAPIN_ERROR to implement
> > > UFFDIO_POISON, so make some various preparations for that:
> > >
> > > First, rename it to just PTE_MARKER_POISONED. The "SWAPIN" can be
> > > confusing since we're going to re-use it for something not really
> > > related to swap. This can be particularly confusing for things like
> > > hugetlbfs, which doesn't support swap whatsoever. Also rename some
> > > various helper functions.
> > >
> > > Next, fix pte marker copying for hugetlbfs. Previously, it would WARN on
> > > seeing a PTE_MARKER_SWAPIN_ERROR, since hugetlbfs doesn't support swap.
> > > But, since we're going to re-use it, we want it to go ahead and copy it
> > > just like non-hugetlbfs memory does today. Since the code to do this is
> > > more complicated now, pull it out into a helper which can be re-used in
> > > both places. While we're at it, also make it slightly more explicit in
> > > its handling of e.g. uffd wp markers.
> > >
> > > For non-hugetlbfs page faults, instead of returning VM_FAULT_SIGBUS for
> > > an error entry, return VM_FAULT_HWPOISON. For most cases this change
> > > doesn't matter, e.g. a userspace program would receive a SIGBUS either
> > > way. But for UFFDIO_POISON, this change will let KVM guests get an MCE
> > > out of the box, instead of giving a SIGBUS to the hypervisor and
> > > requiring it to somehow inject an MCE.
> > >
> > > Finally, for hugetlbfs faults, handle PTE_MARKER_POISONED, and return
> > > VM_FAULT_HWPOISON_LARGE in such cases. Note that this can't happen today
> > > because the lack of swap support means we'll never end up with such a
> > > PTE anyway, but this behavior will be needed once such entries *can*
> > > show up via UFFDIO_POISON.
> > >
> > > --- a/include/linux/mm_inline.h
> > > +++ b/include/linux/mm_inline.h
> > > @@ -523,6 +523,25 @@ static inline bool mm_tlb_flush_nested(struct mm_struct *mm)
> > >       return atomic_read(&mm->tlb_flush_pending) > 1;
> > >  }
> > >
> > > +/*
> > > + * Computes the pte marker to copy from the given source entry into dst_vma.
> > > + * If no marker should be copied, returns 0.
> > > + * The caller should insert a new pte created with make_pte_marker().
> > > + */
> > > +static inline pte_marker copy_pte_marker(
> > > +             swp_entry_t entry, struct vm_area_struct *dst_vma)
> > > +{
> > > +     pte_marker srcm = pte_marker_get(entry);
> > > +     /* Always copy error entries. */
> > > +     pte_marker dstm = srcm & PTE_MARKER_POISONED;
> > > +
> > > +     /* Only copy PTE markers if UFFD register matches. */
> > > +     if ((srcm & PTE_MARKER_UFFD_WP) && userfaultfd_wp(dst_vma))
> > > +             dstm |= PTE_MARKER_UFFD_WP;
> > > +
> > > +     return dstm;
> > > +}
> >
> > Breaks the build with CONFIG_MMU=n (arm allnoconfig).  pte_marker isn't
> > defined.
> >
> > I'll slap #ifdef CONFIG_MMU around this function, but probably somethng more
> > fine-grained could be used, like CONFIG_PTE_MARKER_UFFD_WP.  Please
> > consider.
>
> Whoops, sorry about this. This function "ought" to be in
> include/linux/swapops.h where it would be inside a #ifdef CONFIG_MMU
> anyway, but it can't be because it uses userfaultfd_wp() so there'd be
> a circular include. I think just wrapping it in CONFIG_MMU is the
> right way.
>
> But, this has also made me realize we need to not advertise
> UFFDIO_POISON as supported unless we have CONFIG_MMU. I don't want
> HAVE_ARCH_USERFAULTFD_WP for that, because it's only enabled on
> x86_64, whereas I want to support at least arm64 as well. I don't see
> a strong reason not to just use CONFIG_MMU for this too; this feature
> depends on the API in swapops.h, which uses that ifdef, so I don't see
> a lot of value out of creating a new but equivalent config option.

Actually, I'm being silly. CONFIG_USERFAULTFD depends on CONFIG_MMU,
so we don't need to worry about most of this.

Andrew's fix to just wrap the helper in CONFIG_MMU is enough.

>
> I'll make the needed changes (and also address Peter's comment above)
> and send out a v5.
>
> >
> > btw, both copy_pte_marker() and pte_install_uffd_wp_if_needed() look
> > far too large to justify inlining.  Please review the desirability of
> > this.

As far as inlining goes, I'm not opposed to un-inlining this, I was
mainly copying that pattern from existing helpers in swapops.h.

One question is, if it weren't inline, where should it go? There is no
mm/swapops.c which I would say is otherwise the proper place for it. I
don't see any other good place for the functions to go. The one I'm
introducing isn't userfaultfd-specific so userfaultfd.c seems wrong.

> >
> >
diff mbox series

Patch

diff --git a/include/linux/mm_inline.h b/include/linux/mm_inline.h
index 21d6c72bcc71..a86c84600787 100644
--- a/include/linux/mm_inline.h
+++ b/include/linux/mm_inline.h
@@ -523,6 +523,25 @@  static inline bool mm_tlb_flush_nested(struct mm_struct *mm)
 	return atomic_read(&mm->tlb_flush_pending) > 1;
 }
 
+/*
+ * Computes the pte marker to copy from the given source entry into dst_vma.
+ * If no marker should be copied, returns 0.
+ * The caller should insert a new pte created with make_pte_marker().
+ */
+static inline pte_marker copy_pte_marker(
+		swp_entry_t entry, struct vm_area_struct *dst_vma)
+{
+	pte_marker srcm = pte_marker_get(entry);
+	/* Always copy error entries. */
+	pte_marker dstm = srcm & PTE_MARKER_POISONED;
+
+	/* Only copy PTE markers if UFFD register matches. */
+	if ((srcm & PTE_MARKER_UFFD_WP) && userfaultfd_wp(dst_vma))
+		dstm |= PTE_MARKER_UFFD_WP;
+
+	return dstm;
+}
+
 /*
  * If this pte is wr-protected by uffd-wp in any form, arm the special pte to
  * replace a none pte.  NOTE!  This should only be called when *pte is already
diff --git a/include/linux/swapops.h b/include/linux/swapops.h
index 4c932cb45e0b..bff1e8d97de0 100644
--- a/include/linux/swapops.h
+++ b/include/linux/swapops.h
@@ -393,7 +393,12 @@  static inline bool is_migration_entry_dirty(swp_entry_t entry)
 typedef unsigned long pte_marker;
 
 #define  PTE_MARKER_UFFD_WP			BIT(0)
-#define  PTE_MARKER_SWAPIN_ERROR		BIT(1)
+/*
+ * "Poisoned" here is meant in the very general sense of "future accesses are
+ * invalid", instead of referring very specifically to hardware memory errors.
+ * This marker is meant to represent any of various different causes of this.
+ */
+#define  PTE_MARKER_POISONED			BIT(1)
 #define  PTE_MARKER_MASK			(BIT(2) - 1)
 
 static inline swp_entry_t make_pte_marker_entry(pte_marker marker)
@@ -421,15 +426,15 @@  static inline pte_t make_pte_marker(pte_marker marker)
 	return swp_entry_to_pte(make_pte_marker_entry(marker));
 }
 
-static inline swp_entry_t make_swapin_error_entry(void)
+static inline swp_entry_t make_poisoned_swp_entry(void)
 {
-	return make_pte_marker_entry(PTE_MARKER_SWAPIN_ERROR);
+	return make_pte_marker_entry(PTE_MARKER_POISONED);
 }
 
-static inline int is_swapin_error_entry(swp_entry_t entry)
+static inline int is_poisoned_swp_entry(swp_entry_t entry)
 {
 	return is_pte_marker_entry(entry) &&
-	    (pte_marker_get(entry) & PTE_MARKER_SWAPIN_ERROR);
+	    (pte_marker_get(entry) & PTE_MARKER_POISONED);
 }
 
 /*
diff --git a/mm/hugetlb.c b/mm/hugetlb.c
index bce28cca73a1..66225b21c64e 100644
--- a/mm/hugetlb.c
+++ b/mm/hugetlb.c
@@ -34,6 +34,7 @@ 
 #include <linux/nospec.h>
 #include <linux/delayacct.h>
 #include <linux/memory.h>
+#include <linux/mm_inline.h>
 
 #include <asm/page.h>
 #include <asm/pgalloc.h>
@@ -5101,15 +5102,12 @@  int copy_hugetlb_page_range(struct mm_struct *dst, struct mm_struct *src,
 				entry = huge_pte_clear_uffd_wp(entry);
 			set_huge_pte_at(dst, addr, dst_pte, entry);
 		} else if (unlikely(is_pte_marker(entry))) {
-			/* No swap on hugetlb */
-			WARN_ON_ONCE(
-			    is_swapin_error_entry(pte_to_swp_entry(entry)));
-			/*
-			 * We copy the pte marker only if the dst vma has
-			 * uffd-wp enabled.
-			 */
-			if (userfaultfd_wp(dst_vma))
-				set_huge_pte_at(dst, addr, dst_pte, entry);
+			pte_marker marker = copy_pte_marker(
+				pte_to_swp_entry(entry), dst_vma);
+
+			if (marker)
+				set_huge_pte_at(dst, addr, dst_pte,
+						make_pte_marker(marker));
 		} else {
 			entry = huge_ptep_get(src_pte);
 			pte_folio = page_folio(pte_page(entry));
@@ -6090,14 +6088,26 @@  vm_fault_t hugetlb_fault(struct mm_struct *mm, struct vm_area_struct *vma,
 	}
 
 	entry = huge_ptep_get(ptep);
-	/* PTE markers should be handled the same way as none pte */
-	if (huge_pte_none_mostly(entry))
+	if (huge_pte_none_mostly(entry)) {
+		if (is_pte_marker(entry)) {
+			pte_marker marker =
+				pte_marker_get(pte_to_swp_entry(entry));
+
+			if (marker & PTE_MARKER_POISONED) {
+				ret = VM_FAULT_HWPOISON_LARGE;
+				goto out_mutex;
+			}
+		}
+
 		/*
+		 * Other PTE markers should be handled the same way as none PTE.
+		 *
 		 * hugetlb_no_page will drop vma lock and hugetlb fault
 		 * mutex internally, which make us return immediately.
 		 */
 		return hugetlb_no_page(mm, vma, mapping, idx, address, ptep,
 				      entry, flags);
+	}
 
 	ret = 0;
 
diff --git a/mm/madvise.c b/mm/madvise.c
index 886f06066622..a317aa0a92b8 100644
--- a/mm/madvise.c
+++ b/mm/madvise.c
@@ -660,7 +660,7 @@  static int madvise_free_pte_range(pmd_t *pmd, unsigned long addr,
 				free_swap_and_cache(entry);
 				pte_clear_not_present_full(mm, addr, pte, tlb->fullmm);
 			} else if (is_hwpoison_entry(entry) ||
-				   is_swapin_error_entry(entry)) {
+				   is_poisoned_swp_entry(entry)) {
 				pte_clear_not_present_full(mm, addr, pte, tlb->fullmm);
 			}
 			continue;
diff --git a/mm/memory.c b/mm/memory.c
index 0ae594703021..6309a4b9a79d 100644
--- a/mm/memory.c
+++ b/mm/memory.c
@@ -860,8 +860,11 @@  copy_nonpresent_pte(struct mm_struct *dst_mm, struct mm_struct *src_mm,
 			return -EBUSY;
 		return -ENOENT;
 	} else if (is_pte_marker_entry(entry)) {
-		if (is_swapin_error_entry(entry) || userfaultfd_wp(dst_vma))
-			set_pte_at(dst_mm, addr, dst_pte, pte);
+		pte_marker marker = copy_pte_marker(entry, dst_vma);
+
+		if (marker)
+			set_pte_at(dst_mm, addr, dst_pte,
+				   make_pte_marker(marker));
 		return 0;
 	}
 	if (!userfaultfd_wp(dst_vma))
@@ -1500,7 +1503,7 @@  static unsigned long zap_pte_range(struct mmu_gather *tlb,
 			    !zap_drop_file_uffd_wp(details))
 				continue;
 		} else if (is_hwpoison_entry(entry) ||
-			   is_swapin_error_entry(entry)) {
+			   is_poisoned_swp_entry(entry)) {
 			if (!should_zap_cows(details))
 				continue;
 		} else {
@@ -3647,7 +3650,7 @@  static vm_fault_t pte_marker_clear(struct vm_fault *vmf)
 	 * none pte.  Otherwise it means the pte could have changed, so retry.
 	 *
 	 * This should also cover the case where e.g. the pte changed
-	 * quickly from a PTE_MARKER_UFFD_WP into PTE_MARKER_SWAPIN_ERROR.
+	 * quickly from a PTE_MARKER_UFFD_WP into PTE_MARKER_POISONED.
 	 * So is_pte_marker() check is not enough to safely drop the pte.
 	 */
 	if (pte_same(vmf->orig_pte, ptep_get(vmf->pte)))
@@ -3693,8 +3696,8 @@  static vm_fault_t handle_pte_marker(struct vm_fault *vmf)
 		return VM_FAULT_SIGBUS;
 
 	/* Higher priority than uffd-wp when data corrupted */
-	if (marker & PTE_MARKER_SWAPIN_ERROR)
-		return VM_FAULT_SIGBUS;
+	if (marker & PTE_MARKER_POISONED)
+		return VM_FAULT_HWPOISON;
 
 	if (pte_marker_entry_uffd_wp(entry))
 		return pte_marker_handle_uffd_wp(vmf);
diff --git a/mm/mprotect.c b/mm/mprotect.c
index 6f658d483704..5c3112d92466 100644
--- a/mm/mprotect.c
+++ b/mm/mprotect.c
@@ -230,10 +230,10 @@  static long change_pte_range(struct mmu_gather *tlb,
 					newpte = pte_swp_mkuffd_wp(newpte);
 			} else if (is_pte_marker_entry(entry)) {
 				/*
-				 * Ignore swapin errors unconditionally,
+				 * Ignore error swap entries unconditionally,
 				 * because any access should sigbus anyway.
 				 */
-				if (is_swapin_error_entry(entry))
+				if (is_poisoned_swp_entry(entry))
 					continue;
 				/*
 				 * If this is uffd-wp pte marker and we'd like
diff --git a/mm/shmem.c b/mm/shmem.c
index 2f2e0e618072..ebfde8416bb3 100644
--- a/mm/shmem.c
+++ b/mm/shmem.c
@@ -1707,7 +1707,7 @@  static void shmem_set_folio_swapin_error(struct inode *inode, pgoff_t index,
 	swp_entry_t swapin_error;
 	void *old;
 
-	swapin_error = make_swapin_error_entry();
+	swapin_error = make_poisoned_swp_entry();
 	old = xa_cmpxchg_irq(&mapping->i_pages, index,
 			     swp_to_radix_entry(swap),
 			     swp_to_radix_entry(swapin_error), 0);
@@ -1752,7 +1752,7 @@  static int shmem_swapin_folio(struct inode *inode, pgoff_t index,
 	swap = radix_to_swp_entry(*foliop);
 	*foliop = NULL;
 
-	if (is_swapin_error_entry(swap))
+	if (is_poisoned_swp_entry(swap))
 		return -EIO;
 
 	si = get_swap_device(swap);
diff --git a/mm/swapfile.c b/mm/swapfile.c
index 8e6dde68b389..3dbc6d37df60 100644
--- a/mm/swapfile.c
+++ b/mm/swapfile.c
@@ -1773,7 +1773,7 @@  static int unuse_pte(struct vm_area_struct *vma, pmd_t *pmd,
 			swp_entry = make_hwpoison_entry(swapcache);
 			page = swapcache;
 		} else {
-			swp_entry = make_swapin_error_entry();
+			swp_entry = make_poisoned_swp_entry();
 		}
 		new_pte = swp_entry_to_pte(swp_entry);
 		ret = 0;