mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
From: "David Hildenbrand (Arm)" <david@kernel.org>
To: Andrew Morton <akpm@linux-foundation.org>,
	 Gregory Price <gourry@gourry.net>, Zi Yan <ziy@nvidia.com>,
	 Joshua Hahn <joshua.hahnjy@gmail.com>,
	Rakie Kim <rakie.kim@sk.com>,
	 Ying Huang <ying.huang@linux.alibaba.com>,
	 Johannes Weiner <hannes@cmpxchg.org>,
	 Vladimir Davydov <vdavydov.dev@gmail.com>,
	Michal Hocko <mhocko@suse.com>,  Hugh Dickins <hughd@google.com>,
	 Baolin Wang <baolin.wang@linux.alibaba.com>,
	 Lukas Czerner <lczerner@redhat.com>,
	Carlos Maiolino <cmaiolino@redhat.com>,
	 Christian Brauner <brauner@kernel.org>, Jan Kara <jack@suse.cz>,
	 Daniel Verkamp <dverkamp@chromium.org>,
	Jeff Xu <jeffxu@google.com>,  Muchun Song <muchun.song@linux.dev>,
	Oscar Salvador <osalvador@suse.de>,
	 David Stevens <stevensd@chromium.org>,
	 "Matthew Wilcox (Oracle)" <willy@infradead.org>,
	 William Kucharski <william.kucharski@oracle.com>,
	 Chris Li <chrisl@kernel.org>, Kairui Song <kasong@tencent.com>,
	 Nhat Pham <nphamcs@gmail.com>, Miaohe Lin <linmiaohe@huawei.com>,
	 Naoya Horiguchi <nao.horiguchi@gmail.com>
Cc: linux-mm@kvack.org, linux-kernel@vger.kernel.org,
	 "David Hildenbrand (Arm)" <david@kernel.org>,
	stable@vger.kernel.org
Subject: [PATCH 15/16] mm/shmem: fix accounting of swapin-error markers
Date: Mon, 26 Oct 2026 10:40:48 +0100	[thread overview]
Message-ID: <20261026-fixes_shmem-v1-15-703206d5fa0c@kernel.org> (raw)
In-Reply-To: <20261026-fixes_shmem-v1-0-703206d5fa0c@kernel.org>

A failed swap read replaces the swap entry with a swapin-error marker in
the page-cache and subtracts its pages from "alloced" and "swapped";
however, it leaves their block charge in place.

Removing the marker during truncate then subtracts from "swapped" again.
This can underflow the counters or make swapped reach zero while other
pages remain swapped out, causing swapoff to loop without finding them.

When installing the marker, subtract only from "swapped" and let
shmem_recalc_inode() reduce "alloced" and release the block charge.

Make shmem_free_swap() report successful removal separately from the
number of swap pages freed, so removing a swapin-error marker does not
subtract from "swapped" again.

It's a bit confusing, but replacing a swapped out page by a swapin-error
marker in shmem_set_folio_swapin_error() behaves as follows:

Initially:
	alloced=1, swapped=1, nrpages=0
Calling shmem_recalc_inode(inode, 0, -1)
	-> swapped = 0
	-> freed =  1 - 0 - 0 = 1
	-> alloced -= freed
	-> alloced=0, swapped=0, block charge released

Fixes: 6cec2b95dadf ("mm/shmem: fix infinite loop when swap in shmem error at swapoff time")
Cc: stable@vger.kernel.org
Signed-off-by: David Hildenbrand (Arm) <david@kernel.org>
---
 mm/shmem.c | 31 ++++++++++++++-----------------
 1 file changed, 14 insertions(+), 17 deletions(-)

diff --git a/mm/shmem.c b/mm/shmem.c
index 6b24b9d6db26e..f5b5c9a312c53 100644
--- a/mm/shmem.c
+++ b/mm/shmem.c
@@ -1177,12 +1177,11 @@ static void shmem_delete_from_page_cache(struct folio *folio, void *radswap)
 }
 
 /*
- * Remove swap entry from page cache, free the swap and its page cache. Returns
- * the number of pages being freed. 0 means entry not found in XArray (0 pages
- * being freed).
+ * Remove a swap entry or swapin-error marker wholly within [index, end].
+ * Return whether it was removed, counting freed swap pages in nr_swaps_freed.
  */
-static long shmem_free_swap(struct address_space *mapping,
-			    pgoff_t index, pgoff_t end, void *radswap)
+static bool shmem_free_swap(struct address_space *mapping,
+		pgoff_t index, pgoff_t end, void *radswap, long *nr_swaps_freed)
 {
 	XA_STATE(xas, &mapping->i_pages, index);
 	const softleaf_t swp = radix_to_swp_entry(radswap);
@@ -1203,8 +1202,10 @@ static long shmem_free_swap(struct address_space *mapping,
 	xas_unlock_irq(&xas);
 
 	/* A swapin-error marker holds no swap slot, so just drop it. */
-	if (nr_pages && softleaf_is_swap(swp))
+	if (nr_pages && softleaf_is_swap(swp)) {
 		swap_put_entries_direct(swp, nr_pages);
+		*nr_swaps_freed += nr_pages;
+	}
 
 	return nr_pages;
 }
@@ -1358,8 +1359,8 @@ static void shmem_undo_range(struct inode *inode, loff_t lstart, uoff_t lend,
 			if (xa_is_value(folio)) {
 				if (unfalloc)
 					continue;
-				nr_swaps_freed += shmem_free_swap(mapping, indices[i],
-								  end - 1, folio);
+				shmem_free_swap(mapping, indices[i], end - 1,
+						folio, &nr_swaps_freed);
 				continue;
 			}
 
@@ -1432,13 +1433,11 @@ static void shmem_undo_range(struct inode *inode, loff_t lstart, uoff_t lend,
 
 			if (xa_is_value(folio)) {
 				int order;
-				long swaps_freed;
 
 				if (unfalloc)
 					continue;
-				swaps_freed = shmem_free_swap(mapping, indices[i],
-							      end - 1, folio);
-				if (!swaps_freed) {
+				if (!shmem_free_swap(mapping, indices[i], end - 1,
+						     folio, &nr_swaps_freed)) {
 					pgoff_t base = indices[i];
 
 					order = shmem_confirm_swap(mapping, indices[i],
@@ -1459,7 +1458,6 @@ static void shmem_undo_range(struct inode *inode, loff_t lstart, uoff_t lend,
 					index = base;
 					break;
 				}
-				nr_swaps_freed += swaps_freed;
 				continue;
 			}
 
@@ -2420,11 +2418,10 @@ static void shmem_set_folio_swapin_error(struct inode *inode, pgoff_t index,
 	folio_put_swap(folio, NULL);
 	swap_cache_del_folio(folio);
 	/*
-	 * Don't treat swapin error folio as alloced. Otherwise inode->i_blocks
-	 * won't be 0 when inode is released and thus trigger WARN_ON(i_blocks)
-	 * in shmem_evict_inode().
+	 * Let shmem_recalc_inode() reduce alloced and release the block charge
+	 * for the freed swap pages.
 	 */
-	shmem_recalc_inode(inode, -nr_pages, -nr_pages);
+	shmem_recalc_inode(inode, 0, -nr_pages);
 }
 
 static int shmem_split_large_entry(struct inode *inode, pgoff_t index,

-- 
2.43.0


  parent reply	other threads:[~2026-10-26  9:42 UTC|newest]

Thread overview: 63+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-10-26  9:40 [PATCH 00/16] mm/shmem: various (urgent?) fixes David Hildenbrand (Arm)
2026-10-26  9:40 ` [PATCH 01/16] mm/mempolicy: charge shared policy nodes David Hildenbrand (Arm)
2026-10-26 13:38   ` Pedro Falcato
2026-10-26 15:44   ` Kiryl Shutsemau
2026-10-26 18:10   ` Zi Yan
2026-10-27  2:57   ` Baolin Wang
2026-10-26  9:40 ` [PATCH 02/16] tmpfs: keep the quota soft limits of an unused id David Hildenbrand (Arm)
2026-10-26 10:53   ` Jan Kara
2026-10-26 11:00     ` David Hildenbrand (Arm)
2026-10-26  9:40 ` [PATCH 03/16] tmpfs: preserve explicitly disabled quota limits David Hildenbrand (Arm)
2026-10-26 13:37   ` Jan Kara
2026-10-26  9:40 ` [PATCH 04/16] mm/shmem: honour F_SEAL_EXEC when an ACL is set David Hildenbrand (Arm)
2026-10-26 13:48   ` Pedro Falcato
2026-10-26 15:52   ` Kiryl Shutsemau
2026-10-26 19:07   ` Zi Yan
2026-10-27  3:45   ` Baolin Wang
2026-10-26  9:40 ` [PATCH 05/16] hugetlbfs: enforce F_SEAL_EXEC in setattr David Hildenbrand (Arm)
2026-10-26 13:49   ` Pedro Falcato
2026-10-26 15:55   ` Kiryl Shutsemau
2026-10-26 19:08   ` Zi Yan
2026-10-26  9:40 ` [PATCH 06/16] mm/shmem: hold off eviction in shmem_writeout() David Hildenbrand (Arm)
2026-10-26 15:14   ` Pedro Falcato
2026-10-26 18:44     ` Nhat Pham
2026-10-26 16:13   ` Kiryl Shutsemau
2026-10-26 18:32   ` Nhat Pham
2026-10-26  9:40 ` [PATCH 07/16] mm/shmem: avoid moving the truncation start backwards David Hildenbrand (Arm)
2026-10-26 16:30   ` Kiryl Shutsemau
2026-10-26 19:21   ` Zi Yan
2026-10-26 21:13     ` David Hildenbrand (Arm)
2026-10-26 22:39       ` Zi Yan
2026-10-26 23:16         ` Zi Yan
2026-10-26 23:24           ` David Hildenbrand (Arm)
2026-10-26 23:28             ` Zi Yan
2026-10-26 23:30               ` David Hildenbrand (Arm)
2026-10-26  9:40 ` [PATCH 08/16] mm/shmem: stop retrying folios that cannot be split David Hildenbrand (Arm)
2026-10-26 16:36   ` Kiryl Shutsemau
2026-10-26 17:08     ` David Hildenbrand (Arm)
2026-10-26 17:59       ` Kiryl Shutsemau
2026-10-27  1:34   ` Zi Yan
2026-10-26  9:40 ` [PATCH 09/16] mm/shmem: preserve data in clean folios when splitting fails David Hildenbrand (Arm)
2026-10-26 17:12   ` Kiryl Shutsemau
2026-10-27  2:00   ` Zi Yan
2026-10-26  9:40 ` [PATCH 10/16] mm/shmem: discard whole new large folios on fallocate rollback David Hildenbrand (Arm)
2026-10-26 17:15   ` Kiryl Shutsemau
2026-10-27  2:12   ` Zi Yan
2026-10-26  9:40 ` [PATCH 11/16] mm/shmem: rescan after nonuniform folio splitting David Hildenbrand (Arm)
2026-10-26 17:26   ` Kiryl Shutsemau
2026-10-27  2:34     ` Zi Yan
2026-10-27  2:32   ` Zi Yan
2026-10-26  9:40 ` [PATCH 12/16] mm/shmem: fix truncate hang in large swap entry David Hildenbrand (Arm)
2026-10-26 17:39   ` Kiryl Shutsemau
2026-10-26  9:40 ` [PATCH 13/16] mm/shmem: preserve allocation errors when swapping in large entries David Hildenbrand (Arm)
2026-10-26 17:49   ` Kiryl Shutsemau
2026-10-26  9:40 ` [PATCH 14/16] mm/shmem: fix truncate loop after boundary swapin failure David Hildenbrand (Arm)
2026-10-26 17:53   ` Kiryl Shutsemau
2026-10-26  9:40 ` David Hildenbrand (Arm) [this message]
2026-10-26  9:40 ` [PATCH 16/16] mm/shmem: fix truncation of files containing only swapin-error markers David Hildenbrand (Arm)
2026-10-26 11:11 ` [PATCH 00/16] mm/shmem: various (urgent?) fixes Baolin Wang
2026-10-26 12:12   ` David Hildenbrand (Arm)
2026-10-26 13:23 ` Kairui Song
2026-10-26 20:08 ` Gregory Price
2026-10-26 21:09   ` David Hildenbrand (Arm)
2026-10-26 21:24     ` Gregory Price (Meta)

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20261026-fixes_shmem-v1-15-703206d5fa0c@kernel.org \
    --to=david@kernel.org \
    --cc=akpm@linux-foundation.org \
    --cc=baolin.wang@linux.alibaba.com \
    --cc=brauner@kernel.org \
    --cc=chrisl@kernel.org \
    --cc=cmaiolino@redhat.com \
    --cc=dverkamp@chromium.org \
    --cc=gourry@gourry.net \
    --cc=hannes@cmpxchg.org \
    --cc=hughd@google.com \
    --cc=jack@suse.cz \
    --cc=jeffxu@google.com \
    --cc=joshua.hahnjy@gmail.com \
    --cc=kasong@tencent.com \
    --cc=lczerner@redhat.com \
    --cc=linmiaohe@huawei.com \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-mm@kvack.org \
    --cc=mhocko@suse.com \
    --cc=muchun.song@linux.dev \
    --cc=nao.horiguchi@gmail.com \
    --cc=nphamcs@gmail.com \
    --cc=osalvador@suse.de \
    --cc=rakie.kim@sk.com \
    --cc=stable@vger.kernel.org \
    --cc=stevensd@chromium.org \
    --cc=vdavydov.dev@gmail.com \
    --cc=william.kucharski@oracle.com \
    --cc=willy@infradead.org \
    --cc=ying.huang@linux.alibaba.com \
    --cc=ziy@nvidia.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox

all inboxes | Powered by JetHome®