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 12/16] mm/shmem: fix truncate hang in large swap entry
Date: Mon, 26 Oct 2026 10:40:45 +0100 [thread overview]
Message-ID: <20261026-fixes_shmem-v1-12-703206d5fa0c@kernel.org> (raw)
In-Reply-To: <20261026-fixes_shmem-v1-0-703206d5fa0c@kernel.org>
Truncating a tmpfs file or memfd to a page-aligned size inside a large
swap entry can loop indefinitely in shmem_undo_range(). The task holds
the inode lock and cannot be killed.
A large swap entry represents a whole swapped-out folio. For example,
truncate a file whose pages 0-7 share one swap entry to four pages:
[ 0 1 2 3 | 4 5 6 7 ]
keep | discard
^
new EOF, start = 4
i_size has already been updated when boundary handling asks
shmem_get_partial_folio() for page 4. Since it is swapped out, the helper
calls shmem_get_folio() with SGP_READ. That rejects page 4 with -EINVAL
because its starting offset equals i_size. Nothing is read back.
The final scan cannot free the entry without losing pages 0-3. It skips
it, restarts from start = 4, and finds it again indefinitely. An unaligned
truncate avoids this particular failure because the requested page starts
below i_size. Folios already in the page-cache cannot trigger it as the
direct lookup will return them beyond EOF.
Fix it by letting shmem_get_partial_folio() call shmem_swapin_folio()
directly for swap entries. This bypasses the read path's i_size check,
allowing the existing boundary handling to zero and split the folio. If
swap-in returns a smaller folio, it also splits the swap entry so the final
scan can free the entries beyond EOF. Retry the lookup if the entry
changes during swap-in.
Handling swap-in allocation failures remains broken and is unchanged by
this commit. Even when shmem_swapin_folio() correctly returns -ENOMEM
instead of -EEXIST, shmem_get_partial_folio() returns NULL and
shmem_undo_range() skips boundary handling. If the large swap entry
remains intact, truncation can still loop in the final scan, while hole
punching can return without zeroing the boundary.
This may read an entire large folio back from swap while holding
i_rwsem, only to discard part of it. Avoiding that I/O would require
splitting both the swap entry and any large folio still in the swap
cache. That, however, is much bigger work.
Original fix generated by LLM and sent by Chris Mason in private.
Fixes: 8a1968bd997f ("mm/shmem, swap: fix race of truncate and swap entry split")
Cc: stable@vger.kernel.org
Signed-off-by: David Hildenbrand (Arm) <david@kernel.org>
---
mm/shmem.c | 15 +++++++--------
1 file changed, 7 insertions(+), 8 deletions(-)
diff --git a/mm/shmem.c b/mm/shmem.c
index fcec40a2dd707..9e0034a424908 100644
--- a/mm/shmem.c
+++ b/mm/shmem.c
@@ -1298,12 +1298,10 @@ void shmem_unlock_mapping(struct address_space *mapping)
static struct folio *shmem_get_partial_folio(struct inode *inode, pgoff_t index)
{
+ const gfp_t gfp = mapping_gfp_mask(inode->i_mapping);
struct folio *folio;
- /*
- * At first avoid shmem_get_folio(,,,SGP_READ): that fails
- * beyond i_size, and reports fallocated folios as holes.
- */
+retry:
folio = filemap_get_entry(inode->i_mapping, index);
if (!folio)
return folio;
@@ -1314,13 +1312,14 @@ static struct folio *shmem_get_partial_folio(struct inode *inode, pgoff_t index)
/* The folio has been swapped out */
folio_unlock(folio);
folio_put(folio);
+ goto retry;
}
/*
- * But read a folio back from swap if any of it is within i_size
- * (although in some cases this is just a waste of time).
+ * Truncation can look up a large swap entry at or beyond i_size.
+ * Swap it in directly to bypass the size check in shmem_get_folio().
*/
- folio = NULL;
- shmem_get_folio(inode, index, 0, &folio, SGP_READ);
+ if (shmem_swapin_folio(inode, index, &folio, SGP_READ, gfp, NULL, NULL) == -EEXIST)
+ goto retry;
return folio;
}
--
2.43.0
next prev 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 ` David Hildenbrand (Arm) [this message]
2026-10-26 17:39 ` [PATCH 12/16] mm/shmem: fix truncate hang in large swap entry 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 ` [PATCH 15/16] mm/shmem: fix accounting of swapin-error markers David Hildenbrand (Arm)
2026-10-26 9:40 ` [PATCH 16/16] mm/shmem: fix truncation of files containing only " 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-12-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®