All of lore.kernel.org
 help / color / mirror / Atom feed
* [merged mm-stable] mm-swap-distinguish-a-malformed-swap-entry-from-a-dying-device.patch removed from -mm tree
@ 2026-10-07  0:50 Andrew Morton
  0 siblings, 0 replies; only message in thread
From: Andrew Morton @ 2026-10-07  0:50 UTC (permalink / raw)
  To: mm-commits, vbabka, surenb, shikemeng, rppt, pfalcato, peterx,
	nphamcs, mhocko, ljs, liam, kasong, jannh, hughd, hannes, david,
	chrisl, chengming.zhou, baoquan.he, baolin.wang, baohua, leitao,
	akpm


The quilt patch titled
     Subject: mm, swap: distinguish a malformed swap entry from a dying device
has been removed from the -mm tree.  Its filename was
     mm-swap-distinguish-a-malformed-swap-entry-from-a-dying-device.patch

This patch was dropped because it was merged into the mm-stable branch
of git://git.kernel.org/pub/scm/linux/kernel/git/akpm/mm

------------------------------------------------------
From: Breno Leitao <leitao@debian.org>
Subject: mm, swap: distinguish a malformed swap entry from a dying device
Date: Tue, 18 Aug 2026 03:06:23 -0700

Patch series "mm, swap: don't spin on a bad swap entry", v3.

I've seen some machines at Meta fleet that show the following type of
problem:

1) It gets some weird warning:

  BUG: Bad page map in process khugepaged  pte:f000eef300000017 pmd:00000067
  addr:00007f57c0a01000 vm_flags:20200073 anon_vma:ffff88829af7c340 mapping:0000000000000000 index:7f57c0a01

The corruption is most likely the collapse/PT_RECLAIM race fixed by commit
366a4532d96f ("mm: fix the race between collapse and PT_RECLAIM under
per-vma lock").  But this series is not about this one.

2) Then the fault never makes progress. do_swap_page() returns 0 when
   get_swap_device() fails, so the fault is retried, reads the same
   entry and faults again. Nothing in the round trip changes the PTE,
   and the same line comes out on every pass:

  get_swap_device: Bad swap offset entry 3ffffffc043c5

Patch 1 makes get_swap_device() return ERR_PTR(-EIO) for a malformed
entry, keeping NULL for a device swapoff is taking away, and converts the
callers.  No functional change expected.

Patch 2 uses that to return VM_FAULT_SIGBUS instead of retrying.


This patch (of 2):

get_swap_device() returns NULL for two different things: an entry whose
type names no swap device or whose offset is past the end of one, and a
device that swapoff is taking away.  The first never becomes valid, the
second does, and callers cannot tell them apart.

Return ERR_PTR(-EIO) for the two malformed cases and keep NULL for
swapoff.  copy_nonpresent_pte() already reports -EIO for an entry whose
type names no device.

Callers bail out on failure either way, so switch them to
IS_ERR_OR_NULL(), and let the two paths that drop the reference skip an
error pointer.  No functional change.

Link: https://lore.kernel.org/20260818-swap-v3-0-d3fa52598a59@debian.org
Link: https://lore.kernel.org/20260818-swap-v3-1-d3fa52598a59@debian.org
Signed-off-by: Breno Leitao <leitao@debian.org>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Reviewed-by: Barry Song <baohua@kernel.org>
Acked-by: Kairui Song <kasong@tencent.com>
Reviewed-by: Nhat Pham <nphamcs@gmail.com>
Acked-by: David Hildenbrand (Arm) <david@kernel.org>
Cc: Baolin Wang <baolin.wang@linux.alibaba.com>
Cc: Baoquan He <baoquan.he@linux.dev>
Cc: Chengming Zhou <chengming.zhou@linux.dev>
Cc: Chris Li <chrisl@kernel.org>
Cc: Hugh Dickins <hughd@google.com>
Cc: Jann Horn <jannh@google.com>
Cc: Johannes Weiner <hannes@cmpxchg.org>
Cc: Kemeng Shi <shikemeng@huaweicloud.com>
Cc: Liam R. Howlett <liam@infradead.org>
Cc: Lorenzo Stoakes <ljs@kernel.org>
Cc: Michal Hocko <mhocko@suse.com>
Cc: Mike Rapoport <rppt@kernel.org>
Cc: Pedro Falcato <pfalcato@suse.de>
Cc: Peter Xu <peterx@redhat.com>
Cc: Suren Baghdasaryan <surenb@google.com>
Cc: Vlastimil Babka <vbabka@kernel.org>
---

 mm/memory.c      |    6 +++---
 mm/mincore.c     |    2 +-
 mm/shmem.c       |    2 +-
 mm/swap_state.c  |    4 ++--
 mm/swapfile.c    |   15 ++++++++++-----
 mm/userfaultfd.c |    4 ++--
 mm/zswap.c       |    2 +-
 7 files changed, 20 insertions(+), 15 deletions(-)

--- a/mm/memory.c~mm-swap-distinguish-a-malformed-swap-entry-from-a-dying-device
+++ a/mm/memory.c
@@ -4956,9 +4956,9 @@ vm_fault_t do_swap_page(struct vm_fault
 		goto out;
 	}
 
-	/* Prevent swapoff from happening to us. */
+	/* Prevent swapoff from happening to us, and reject a bad entry. */
 	si = get_swap_device(entry);
-	if (unlikely(!si))
+	if (IS_ERR_OR_NULL(si))
 		goto out;
 
 	folio = swap_cache_get_folio(entry);
@@ -5268,7 +5268,7 @@ unlock:
 	if (vmf->pte)
 		pte_unmap_unlock(vmf->pte, vmf->ptl);
 out:
-	if (si)
+	if (!IS_ERR_OR_NULL(si))
 		put_swap_device(si);
 	return ret;
 out_nomap:
--- a/mm/mincore.c~mm-swap-distinguish-a-malformed-swap-entry-from-a-dying-device
+++ a/mm/mincore.c
@@ -71,7 +71,7 @@ static unsigned char mincore_swap(swp_en
 	 */
 	if (shmem) {
 		si = get_swap_device(entry);
-		if (!si)
+		if (IS_ERR_OR_NULL(si))
 			return 0;
 	}
 	folio = swap_cache_get_folio(entry);
--- a/mm/shmem.c~mm-swap-distinguish-a-malformed-swap-entry-from-a-dying-device
+++ a/mm/shmem.c
@@ -2481,7 +2481,7 @@ static int shmem_swapin_folio(struct ino
 
 	si = get_swap_device(index_entry);
 	order = shmem_confirm_swap(mapping, index, index_entry);
-	if (unlikely(!si)) {
+	if (IS_ERR_OR_NULL(si)) {
 		if (order < 0)
 			return -EEXIST;
 		else
--- a/mm/swapfile.c~mm-swap-distinguish-a-malformed-swap-entry-from-a-dying-device
+++ a/mm/swapfile.c
@@ -1504,7 +1504,7 @@ int swap_retry_table_alloc(swp_entry_t e
 	unsigned long offset = swp_offset(entry);
 
 	si = get_swap_device(entry);
-	if (!si)
+	if (IS_ERR_OR_NULL(si))
 		return 0;
 
 	ci = __swap_offset_to_cluster(si, offset);
@@ -1859,7 +1859,10 @@ void folio_put_swap(struct folio *folio,
  * Check whether swap entry is valid in the swap device.  If so,
  * return pointer to swap_info_struct, and keep the swap entry valid
  * via preventing the swap device from being swapoff, until
- * put_swap_device() is called.  Otherwise return NULL.
+ * put_swap_device() is called.  Return NULL for an empty entry or a
+ * device that is going away, and ERR_PTR(-EIO) if the entry's type
+ * names no swap device or its offset is past the end of one. These EIOs
+ * are preceded by pr_err().
  *
  * Notice that swapoff or swapoff+swapon can still happen before the
  * percpu_ref_tryget_live() in get_swap_device() or after the
@@ -1900,12 +1903,14 @@ struct swap_info_struct *get_swap_device
 	return si;
 bad_nofile:
 	pr_err_ratelimited("%s: %s%08lx\n", __func__, Bad_file, entry.val);
+	return ERR_PTR(-EIO);
+
 out:
 	return NULL;
 put_out:
 	pr_err_ratelimited("%s: %s%08lx\n", __func__, Bad_offset, entry.val);
 	percpu_ref_put(&si->users);
-	return NULL;
+	return ERR_PTR(-EIO);
 }
 
 /*
@@ -2001,7 +2006,7 @@ int swp_swapcount(swp_entry_t entry)
 	int count;
 
 	si = get_swap_device(entry);
-	if (!si)
+	if (IS_ERR_OR_NULL(si))
 		return 0;
 
 	ci = swap_cluster_lock(si, swp_offset(entry));
@@ -2127,7 +2132,7 @@ void swap_put_entries_direct(swp_entry_t
 	struct swap_info_struct *si;
 
 	si = get_swap_device(entry);
-	if (WARN_ON_ONCE(!si))
+	if (WARN_ON_ONCE(IS_ERR_OR_NULL(si)))
 		return;
 	if (WARN_ON_ONCE(end_offset > si->max))
 		goto out;
--- a/mm/swap_state.c~mm-swap-distinguish-a-malformed-swap-entry-from-a-dying-device
+++ a/mm/swap_state.c
@@ -716,7 +716,7 @@ struct folio *read_swap_cache_async(stru
 	struct folio *folio;
 
 	si = get_swap_device(entry);
-	if (!si)
+	if (IS_ERR_OR_NULL(si))
 		return NULL;
 
 	mpol = get_vma_policy(vma, addr, 0, &ilx);
@@ -952,7 +952,7 @@ static struct folio *swap_vma_readahead(
 		 */
 		if (swp_type(entry) != swp_type(targ_entry)) {
 			si = get_swap_device(entry);
-			if (!si)
+			if (IS_ERR_OR_NULL(si))
 				continue;
 		}
 		folio = swap_cache_read_folio(&ctx, entry, gfp_mask, mpol, ilx,
--- a/mm/userfaultfd.c~mm-swap-distinguish-a-malformed-swap-entry-from-a-dying-device
+++ a/mm/userfaultfd.c
@@ -1700,7 +1700,7 @@ retry:
 		}
 
 		si = get_swap_device(entry);
-		if (unlikely(!si)) {
+		if (IS_ERR_OR_NULL(si)) {
 			ret = -EAGAIN;
 			goto out;
 		}
@@ -1757,7 +1757,7 @@ out:
 	if (dst_pte)
 		pte_unmap(dst_pte);
 	mmu_notifier_invalidate_range_end(&range);
-	if (si)
+	if (!IS_ERR_OR_NULL(si))
 		put_swap_device(si);
 
 	return ret;
--- a/mm/zswap.c~mm-swap-distinguish-a-malformed-swap-entry-from-a-dying-device
+++ a/mm/zswap.c
@@ -984,7 +984,7 @@ static int zswap_writeback_entry(struct
 
 	/* try to allocate swap cache folio */
 	si = get_swap_device(swpentry);
-	if (!si)
+	if (IS_ERR_OR_NULL(si))
 		return -EEXIST;
 
 	mpol = get_task_policy(current);
_

Patches currently in -mm which might be from leitao@debian.org are

documentation-kmemleak-describe-the-metadata-pool-not-the-early-log.patch
documentation-kmemleak-fix-stale-statements-about-scanning.patch
mm-kmemleak-raise-min_unref_scans-to-3-for-verbose-auto-scan.patch
mm-shmem-report-rcu-tasks-quiescent-states-while-undoing-a-range.patch
mm-kmemleak-move-the-struct-page-scan-into-a-helper.patch
mm-kmemleak-scan-the-struct-page-array-in-max_scan_size-batches.patch


^ permalink raw reply	[flat|nested] only message in thread

only message in thread, other threads:[~2026-10-07  0:50 UTC | newest]

Thread overview: (only message) (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-10-07  0:50 [merged mm-stable] mm-swap-distinguish-a-malformed-swap-entry-from-a-dying-device.patch removed from -mm tree Andrew Morton

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.