From nobody Mon Sep 28 19:23:38 2026 Received: from stravinsky.debian.org (stravinsky.debian.org [82.195.75.108]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 24C4B35DA78 for ; Tue, 18 Aug 2026 10:08:29 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=82.195.75.108 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1787047712; cv=none; b=cj4YUuDVYnduexD2/Pq4OqXg+7wAJ8kZkzsn6aTPDpshAsVQsqa/Jy40gOtN5PdQP5z/BW2qFg2hxNAuPAtI65KiAgw6edvsUw+Q212zLUxaeRITvWAAK3QeK3J5bxm7eVFlRgAepNS2OuoGYGBhKy7QLpMQlBICOdS7oivVTyA= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1787047712; c=relaxed/simple; bh=YAGrMLLCUasxDttA7eyHnCoI15R8kt2N/zq1pMcZSZM=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=MM09V5vOFJZSaQd+an8NvhHGmNeG9z4BPeyCJ1CdUCIweFemHPIgCEBhzjF4K1GWMEMak2PWL4SrDae1TKBQFL0dzxU3JtmuXSP8YWldOAPulr+ptl25GipwZuFs1uT6o1Mo4CmronVPUVuqkMvNxEeDyZrqF9uF8bGjED2+0s4= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=debian.org; spf=pass smtp.mailfrom=debian.org; dkim=pass (2048-bit key) header.d=debian.org header.i=@debian.org header.b=tE21RPI2; arc=none smtp.client-ip=82.195.75.108 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=debian.org Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=debian.org Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=debian.org header.i=@debian.org header.b="tE21RPI2" DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=debian.org; s=smtpauto.stravinsky; h=X-Debian-User:Cc:To:In-Reply-To:References: Message-Id:Content-Transfer-Encoding:Content-Type:MIME-Version:Subject:Date: From:Reply-To:Content-ID:Content-Description; bh=G9KuxdbMXarhzOqWryoLJREjzAVULu+8jNKt/2uhZrc=; b=tE21RPI2vktLk0uTk2t0g+KUU2 6XNkmTbilLx3CArimV0Kn3yV6z5SPduqZqUqQitICJAivYHuLBHzeR15ghsNe+7YFnNz4XdH7abte QkopcDpnICt/YU1rlo7lQqrdSXalKIGxk4spjGLeePTda/LKdOolR1k4pQ39eAnr9m/ZB4Tk4gazp Bq6KUZwghm5IOIhGhbjf8Xntk8dL8ASKTrAlFrNdvyJrhtxpxe2BNOz1zcAanPUUhT16WCeF7aHVn 7Qe7fBmuEJdgOeGRHCGUk5s+fUkseXBPgEBuYctxuYevOu6mPXPY5qt4fm5kKTO3m084xa+l/AJQl NnK5kq1w==; Received: from authenticated-user by stravinsky.debian.org with esmtpsa (TLS1.3:ECDHE_X25519__RSA_PSS_RSAE_SHA256__AES_256_GCM:256) (Exim 4.96) (envelope-from ) id 1wwGk1-008wGT-08; Tue, 18 Aug 2026 10:08:21 +0000 From: Breno Leitao Date: Tue, 18 Aug 2026 03:06:23 -0700 Subject: [PATCH v3 1/2] mm, swap: distinguish a malformed swap entry from a dying device Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260818-swap-v3-1-d3fa52598a59@debian.org> References: <20260818-swap-v3-0-d3fa52598a59@debian.org> In-Reply-To: <20260818-swap-v3-0-d3fa52598a59@debian.org> To: Andrew Morton , Chris Li , Kairui Song , Kemeng Shi , Nhat Pham , Baoquan He , Barry Song , Youngjun Park , David Hildenbrand , Lorenzo Stoakes , "Liam R. Howlett" , Vlastimil Babka , Mike Rapoport , Suren Baghdasaryan , Michal Hocko , Jann Horn , Pedro Falcato , Hugh Dickins , Baolin Wang , Peter Xu , Johannes Weiner , Yosry Ahmed , Chengming Zhou Cc: linux-mm@kvack.org, linux-kernel@vger.kernel.org, kernel-team@meta.com, Breno Leitao X-Mailer: b4 0.16-dev-f8e9d X-Developer-Signature: v=1; a=openpgp-sha256; l=6257; i=leitao@debian.org; h=from:subject:message-id; bh=YAGrMLLCUasxDttA7eyHnCoI15R8kt2N/zq1pMcZSZM=; b=owEBbQKS/ZANAwAIATWjk5/8eHdtAcsmYgBqhC8HOtBiM0iguv0eeUSXDTd55DYPFmgOsnGpS xdL87D89yqJAjMEAAEIAB0WIQSshTmm6PRnAspKQ5s1o5Of/Hh3bQUCaoQvBwAKCRA1o5Of/Hh3 beE+D/41At++CwJ+00eHB2rsH+6LnmclU55BnvqWAfWdwE8FNybwh21lVFRdDHgFwM7qJ+vNGma WMGtADyxG+UC7pmCnA7Lcn+6jVPloKif95TBWbomexE1KBGTL2vkGjCxAXB0DYP4l/Bvf9W7O96 zH7O+juAPpoise6f0EVIzeFnmrVbX52Povx/G9Lneml+V17fwaFWDYrgc1aujiY+9AZiY1GPDoC U8b9bhQVzUnx8/cGs94iODqqCW7Tn+9SOqj8GTJoUY3fRD3SDyD07uMZFF//f+KmJVlJ4o4ZcsD 2M7BBPJwxpf4pff8ZEMC4SACf5VSip/DV7vJmbsUy3V4T2cspBFSt0ca6H5VyQyTLf4gJDd4z6k SJLxSCIbcJ23yr5kTgB+86v7GAAlCIrOfed/yuQkr0SxdpmQozGOaa5+5ChtaLfE1hOwH9xUL3a R7OrsAmHymD027cM8QQGzWoBR9i1xrA7qbgoKVQYCJ98m5M53VkxziDKGV69QNfvU0klQ4C6F4W 2JIhKWGnGDnGayIIcUa4HoTcxbkOArLeKTClci6esFVoI1gq3ySpM5uXGIBtR3PQScQcPBaFzTd Ooovj9k1uxj19+axmXXoNrEHVDf1VXdZJPDBijGUj9OelkBTxV8DGkuTyQRA+n+z2n6xYd6F9Km Z9kSbPaSAiOzWAA== X-Developer-Key: i=leitao@debian.org; a=openpgp; fpr=AC8539A6E8F46702CA4A439B35A3939FFC78776D X-Debian-User: leitao 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. Reviewed-by: Barry Song Acked-by: Kairui Song Signed-off-by: Breno Leitao Acked-by: David Hildenbrand (Arm) Reviewed-by: Nhat Pham --- mm/memory.c | 6 +++--- mm/mincore.c | 2 +- mm/shmem.c | 2 +- mm/swap_state.c | 4 ++-- mm/swapfile.c | 14 +++++++++----- mm/userfaultfd.c | 4 ++-- mm/zswap.c | 2 +- 7 files changed, 19 insertions(+), 15 deletions(-) diff --git a/mm/memory.c b/mm/memory.c index d9cf941967cf0..03d8cf111d0be 100644 --- a/mm/memory.c +++ b/mm/memory.c @@ -4954,9 +4954,9 @@ vm_fault_t do_swap_page(struct vm_fault *vmf) goto out; } =20 - /* Prevent swapoff from happening to us. */ + /* Prevent swapoff from happening to us, and reject a bad entry. */ si =3D get_swap_device(entry); - if (unlikely(!si)) + if (IS_ERR_OR_NULL(si)) goto out; =20 folio =3D swap_cache_get_folio(entry); @@ -5266,7 +5266,7 @@ vm_fault_t do_swap_page(struct vm_fault *vmf) 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: diff --git a/mm/mincore.c b/mm/mincore.c index ff4ac82817683..c086836bc4bcc 100644 --- a/mm/mincore.c +++ b/mm/mincore.c @@ -71,7 +71,7 @@ static unsigned char mincore_swap(swp_entry_t entry, bool= shmem) */ if (shmem) { si =3D get_swap_device(entry); - if (!si) + if (IS_ERR_OR_NULL(si)) return 0; } folio =3D swap_cache_get_folio(entry); diff --git a/mm/shmem.c b/mm/shmem.c index 65572cbf1bd3c..d0a9f52bfed71 100644 --- a/mm/shmem.c +++ b/mm/shmem.c @@ -2276,7 +2276,7 @@ static int shmem_swapin_folio(struct inode *inode, pg= off_t index, =20 si =3D get_swap_device(index_entry); order =3D shmem_confirm_swap(mapping, index, index_entry); - if (unlikely(!si)) { + if (IS_ERR_OR_NULL(si)) { if (order < 0) return -EEXIST; else diff --git a/mm/swap_state.c b/mm/swap_state.c index 4b7a3303c463b..f2e86d6626ecc 100644 --- a/mm/swap_state.c +++ b/mm/swap_state.c @@ -715,7 +715,7 @@ struct folio *read_swap_cache_async(struct swap_io_ctx = *ctx, swp_entry_t entry, struct folio *folio; =20 si =3D get_swap_device(entry); - if (!si) + if (IS_ERR_OR_NULL(si)) return NULL; =20 mpol =3D get_vma_policy(vma, addr, 0, &ilx); @@ -951,7 +951,7 @@ static struct folio *swap_vma_readahead(swp_entry_t tar= g_entry, gfp_t gfp_mask, */ if (swp_type(entry) !=3D swp_type(targ_entry)) { si =3D get_swap_device(entry); - if (!si) + if (IS_ERR_OR_NULL(si)) continue; } folio =3D swap_cache_read_folio(&ctx, entry, gfp_mask, mpol, ilx, diff --git a/mm/swapfile.c b/mm/swapfile.c index 4d4e3e3059f6b..3b1883930e943 100644 --- a/mm/swapfile.c +++ b/mm/swapfile.c @@ -1504,7 +1504,7 @@ int swap_retry_table_alloc(swp_entry_t entry, gfp_t g= fp) unsigned long offset =3D swp_offset(entry); =20 si =3D get_swap_device(entry); - if (!si) + if (IS_ERR_OR_NULL(si)) return 0; =20 ci =3D __swap_offset_to_cluster(si, offset); @@ -1859,7 +1859,10 @@ void folio_put_swap(struct folio *folio, struct page= *page) * 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,13 @@ struct swap_info_struct *get_swap_device(swp_entry_= t entry) return si; bad_nofile: pr_err("%s: %s%08lx\n", __func__, Bad_file, entry.val); + return ERR_PTR(-EIO); out: return NULL; put_out: pr_err("%s: %s%08lx\n", __func__, Bad_offset, entry.val); percpu_ref_put(&si->users); - return NULL; + return ERR_PTR(-EIO); } =20 /* @@ -2001,7 +2005,7 @@ int swp_swapcount(swp_entry_t entry) int count; =20 si =3D get_swap_device(entry); - if (!si) + if (IS_ERR_OR_NULL(si)) return 0; =20 ci =3D swap_cluster_lock(si, swp_offset(entry)); @@ -2127,7 +2131,7 @@ void swap_put_entries_direct(swp_entry_t entry, int n= r) struct swap_info_struct *si; =20 si =3D 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; diff --git a/mm/userfaultfd.c b/mm/userfaultfd.c index 24a4d92ffa3c2..cba5e20a641ed 100644 --- a/mm/userfaultfd.c +++ b/mm/userfaultfd.c @@ -1700,7 +1700,7 @@ static long move_pages_ptes(struct mm_struct *mm, pmd= _t *dst_pmd, pmd_t *src_pmd } =20 si =3D get_swap_device(entry); - if (unlikely(!si)) { + if (IS_ERR_OR_NULL(si)) { ret =3D -EAGAIN; goto out; } @@ -1757,7 +1757,7 @@ static long move_pages_ptes(struct mm_struct *mm, pmd= _t *dst_pmd, pmd_t *src_pmd 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); =20 return ret; diff --git a/mm/zswap.c b/mm/zswap.c index f7c9c89f6449c..bc9b931d6f447 100644 --- a/mm/zswap.c +++ b/mm/zswap.c @@ -997,7 +997,7 @@ static int zswap_writeback_entry(struct zswap_entry *en= try, =20 /* try to allocate swap cache folio */ si =3D get_swap_device(swpentry); - if (!si) + if (IS_ERR_OR_NULL(si)) return -EEXIST; =20 mpol =3D get_task_policy(current); --=20 2.53.0-Meta From nobody Mon Sep 28 19:23:38 2026 Received: from stravinsky.debian.org (stravinsky.debian.org [82.195.75.108]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 5EBD23C2B92 for ; Tue, 18 Aug 2026 10:08:32 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=82.195.75.108 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1787047713; cv=none; b=SgDP4okcYPj8k1XSMIRI5fAJ0JQ8Ktkhce5bakRwkiZgoLCD+eB/V2dg/05BGB+BALAMENV2x+ULN7e8l5MIhXvCcvxu7rJ5M5EXlZXyg0uPBewOT8IVaKOfjwGoxw6nYLzK4UTd6v4vVXGxLG+Ld6iCaqJZl/9VSj5dTzrfLE0= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1787047713; c=relaxed/simple; bh=dbJ2cob7ug0q0zBMWou2pCCet89ZlFMUpENdIOQ07oI=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=GNP0J1ApqhJLDgT9kADGN9QqLePP856L2zTwt04RyyS9CMIDs0+FGZ4zSEugTEqlnNeDywi0W7X8IL2+gRw5FPmBA6qisbHW4PeIg+HLAwJdemrzPycYk7gp7m1YF/fe2lDGsFi3SD5Yqye78hGI9eLJT9/pC8S4NdrKruFIjGk= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=debian.org; spf=pass smtp.mailfrom=debian.org; dkim=pass (2048-bit key) header.d=debian.org header.i=@debian.org header.b=pBXqHchq; arc=none smtp.client-ip=82.195.75.108 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=debian.org Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=debian.org Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=debian.org header.i=@debian.org header.b="pBXqHchq" DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=debian.org; s=smtpauto.stravinsky; h=X-Debian-User:Cc:To:In-Reply-To:References: Message-Id:Content-Transfer-Encoding:Content-Type:MIME-Version:Subject:Date: From:Reply-To:Content-ID:Content-Description; bh=18b3yXoATxSl7J4Qohqzo1mLFp4/SDkenmc18eUXtfg=; b=pBXqHchqvMhKy9q2TLfprFQxpv oTrVwijpGoNrlS2oCNpfs9soa8XN5XhOMcHuyP99jABYgRv0Z6DTMemrMRLQOhxSGkA5pRa7QExFa T6EE0XJMUn0nFaSWs9BT0dbrxuZawIlflqIUyt9ztGwden3S5X63hCNKEOhVzUbkBd7ejGlzpOv1I 1p+/NxOep7oZjDo1dt0WtfoT/C0L8MG7IYfoONz/plq7eJoxrxvCZr+l2A9ttRLKU5i70U/Bxv+5c kFSMae0s/qZKxiGfn232s9yQ6aenykVJCI6pSaAIkP4gIup1u/ksWbtC/VxG/dop73XXJe547P9H8 KcFmc61g==; Received: from authenticated-user by stravinsky.debian.org with esmtpsa (TLS1.3:ECDHE_X25519__RSA_PSS_RSAE_SHA256__AES_256_GCM:256) (Exim 4.96) (envelope-from ) id 1wwGk7-008wGb-2X; Tue, 18 Aug 2026 10:08:28 +0000 From: Breno Leitao Date: Tue, 18 Aug 2026 03:06:24 -0700 Subject: [PATCH v3 2/2] mm: fail the fault on a malformed swap entry instead of retrying it Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260818-swap-v3-2-d3fa52598a59@debian.org> References: <20260818-swap-v3-0-d3fa52598a59@debian.org> In-Reply-To: <20260818-swap-v3-0-d3fa52598a59@debian.org> To: Andrew Morton , Chris Li , Kairui Song , Kemeng Shi , Nhat Pham , Baoquan He , Barry Song , Youngjun Park , David Hildenbrand , Lorenzo Stoakes , "Liam R. Howlett" , Vlastimil Babka , Mike Rapoport , Suren Baghdasaryan , Michal Hocko , Jann Horn , Pedro Falcato , Hugh Dickins , Baolin Wang , Peter Xu , Johannes Weiner , Yosry Ahmed , Chengming Zhou Cc: linux-mm@kvack.org, linux-kernel@vger.kernel.org, kernel-team@meta.com, Breno Leitao X-Mailer: b4 0.16-dev-f8e9d X-Developer-Signature: v=1; a=openpgp-sha256; l=1062; i=leitao@debian.org; h=from:subject:message-id; bh=dbJ2cob7ug0q0zBMWou2pCCet89ZlFMUpENdIOQ07oI=; b=owEBbQKS/ZANAwAIATWjk5/8eHdtAcsmYgBqhC8HeqOvC+bUMvfHEdA+WWMzM+GRMPTCTJ0Wi zjOPGWeGX2JAjMEAAEIAB0WIQSshTmm6PRnAspKQ5s1o5Of/Hh3bQUCaoQvBwAKCRA1o5Of/Hh3 bVrsD/480wUQJFwAkhlGjW1ypFpLBPmMQ1Hotp+NK4hb+G6+VM4D856NfUR+kncB3McvL0pMrcH knib03o9/OqhUG4PVJ6jTUgPH41mwb4iBwzH34IhoTzmUhZoVBsgww4iGZBGAx8FWQCA2vzZxYV aSrHQPN/S3pM2RJlzM2eJM+b/eMXOVWiqIm59/crVNLx8HH2liovLJ+28aSSQCC8KTD4oWwq9LA 8641BzTVdpy3fCuNY7DN/X8eF1SJxmylbO+l/puDJQB0WOsPZ37nOTKYgL5QWAhDboLpWBrxWoH 6DsJfxIxfJ6hJh/1nL2ZDsJoDN7SSwHKxJC1XA/86rlSKcRHKuew/lXQtVKbaoxfJXlMjTmE4o+ ryr4R9++j1hklIi0ovdVDzcM4rTGCiHrCmBMx4vAAY7sWfNTdbrR8LRbYgw/gY/M72qTRWL9OBf mKEWQ12uUXyS54InQrvQ09GrFdRMQalUArtUqySv2+EFTT5thP+bK0O+t595KrJ7HZKk1L5pesz kXam7pHZYZkINg0W880zu99JSOl0UQQ7ags1OW6D2GTAFXbtYVcHD0bRorceAhlwk37+8NzwFcG 5uviraK1wEIqzzh4bGMgdtpnqu4MTxfR6XPrEJnSGG5M0lzgtic9WHITcRciGeS82CEwNV/DWua LTquOjP4JaMbHzw== X-Developer-Key: i=leitao@debian.org; a=openpgp; fpr=AC8539A6E8F46702CA4A439B35A3939FFC78776D X-Debian-User: leitao do_swap_page() returns 0 when get_swap_device() fails, which the fault handler reads as "handled". For an entry that can never become valid the retry takes the same fault again, so the thread spins forever, retrying on the same fault. Return VM_FAULT_SIGBUS (Bad access) for a malformed entry (pr_err() was called at get_swap_device()). Acked-by: Kairui Song Reviewed-by: Barry Song Signed-off-by: Breno Leitao Acked-by: David Hildenbrand (Arm) Reviewed-by: Nhat Pham --- mm/memory.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/mm/memory.c b/mm/memory.c index 03d8cf111d0be..d9db4f1ae6f8a 100644 --- a/mm/memory.c +++ b/mm/memory.c @@ -4956,8 +4956,11 @@ vm_fault_t do_swap_page(struct vm_fault *vmf) =20 /* Prevent swapoff from happening to us, and reject a bad entry. */ si =3D get_swap_device(entry); - if (IS_ERR_OR_NULL(si)) + if (IS_ERR_OR_NULL(si)) { + if (IS_ERR(si)) + ret =3D VM_FAULT_SIGBUS; goto out; + } =20 folio =3D swap_cache_get_folio(entry); if (folio) --=20 2.53.0-Meta