All of lore.kernel.org
 help / color / mirror / Atom feed
* + mm-thp-pin-the-inode-across-a-file-folio-split.patch added to mm-hotfixes-unstable branch
@ 2026-07-13 23:09 Andrew Morton
  0 siblings, 0 replies; only message in thread
From: Andrew Morton @ 2026-07-13 23:09 UTC (permalink / raw)
  To: mm-commits, ziy, zhanghao1, stable, ryan.roberts, npache, ljs,
	liam, lance.yang, dev.jain, david, baolin.wang, baohua, kirill,
	akpm


The patch titled
     Subject: mm: thp: pin the inode across a file folio split
has been added to the -mm mm-hotfixes-unstable branch.  Its filename is
     mm-thp-pin-the-inode-across-a-file-folio-split.patch

This patch will shortly appear at
     https://git.kernel.org/pub/scm/linux/kernel/git/akpm/25-new.git/tree/patches/mm-thp-pin-the-inode-across-a-file-folio-split.patch

This patch will later appear in the mm-hotfixes-unstable branch at
    git://git.kernel.org/pub/scm/linux/kernel/git/akpm/mm

Before you just go and hit "reply", please:
   a) Consider who else should be cc'ed
   b) Prefer to cc a suitable mailing list as well
   c) Ideally: find the original patch on the mailing list and do a
      reply-to-all to that, adding suitable additional cc's

*** Remember to use Documentation/process/submit-checklist.rst when testing your code ***

The -mm tree is included into linux-next via various
branches at git://git.kernel.org/pub/scm/linux/kernel/git/akpm/mm
and is updated there most days

------------------------------------------------------
From: "Kiryl Shutsemau (Meta)" <kirill@shutemov.name>
Subject: mm: thp: pin the inode across a file folio split
Date: Mon, 13 Jul 2026 18:09:15 +0100

__folio_split() looks up mapping = folio->mapping for a file-backed folio
and keeps dereferencing it after the split completes:
shmem_uncharge(mapping->host) for folios dropped beyond EOF and
i_mmap_unlock_read(mapping) on the way out.

Nothing holds an inode reference for that duration.  The split relies on
the folio the caller keeps locked (@lock_at) to pin the inode through the
page cache: while it is locked and present, truncate_inode_pages_final()
in evict() cannot make progress.  But the split drops @lock_at from the
page cache when it falls beyond EOF (the @end handling in
__folio_freeze_and_split_unmapped()), while keeping it locked for the
caller.  That removes the last pin, and a concurrent final iput() can then
evict and RCU-free the inode before __folio_split() is done touching
mapping.

This is reachable from memory_failure(): poisoning a tail page of a shmem
THP that straddles EOF makes try_to_split_thp_page() split at that page,
so the dropped @lock_at is the folio returned locked.  The result is a
use-after-free, e.g.:

  BUG: KASAN: slab-use-after-free in __up_read+0x634/0x790
   i_mmap_unlock_read include/linux/fs.h:537 [inline]
   __folio_split+0x732/0x1640 mm/huge_memory.c:4100
   try_to_split_thp_page+0xab/0x390 mm/memory-failure.c:1675
   memory_failure+0x1394/0x26e0 mm/memory-failure.c:2470

  Freed by task 4601:
   shmem_free_in_core_inode+0x54/0xb0 mm/shmem.c:5177
   i_callback+0x4c/0xa0 fs/inode.c:326
   destroy_inode+0x144/0x1e0 fs/inode.c:402
   evict+0x57f/0xac0 fs/inode.c:870

Pin the inode with igrab() before the split and drop the reference with
iput() after the last mapping dereference.  igrab() returns NULL only if
the inode is already being evicted (i_count 0 and I_FREEING set), which a
split racing eviction can observe; there is nothing safe to split then, so
return -EBUSY, which callers already handle.

Link: https://lore.kernel.org/20260713170915.239819-1-kirill@shutemov.name
Fixes: baa355fd3314 ("thp: file pages support for split_huge_page()")
Signed-off-by: Kiryl Shutsemau (Meta) <kirill@shutemov.name>
Reported-by: Hao Zhang <zhanghao1@kylinos.cn>
Closes: https://lore.kernel.org/linux-mm/20260710071344.GA106129@zh-pc
Acked-by: Zi Yan <ziy@nvidia.com>
Cc: Baolin Wang <baolin.wang@linux.alibaba.com>
Cc: Barry Song <baohua@kernel.org>
Cc: David Hildenbrand <david@kernel.org>
Cc: Dev Jain <dev.jain@arm.com>
Cc: Lance Yang <lance.yang@linux.dev>
Cc: Liam R. Howlett <liam@infradead.org>
Cc: Lorenzo Stoakes <ljs@kernel.org>
Cc: Nico Pache <npache@redhat.com>
Cc: Ryan Roberts <ryan.roberts@arm.com>
Cc: <stable@vger.kernel.org>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
---

 mm/huge_memory.c |   17 +++++++++++++++++
 1 file changed, 17 insertions(+)

--- a/mm/huge_memory.c~mm-thp-pin-the-inode-across-a-file-folio-split
+++ a/mm/huge_memory.c
@@ -3986,6 +3986,7 @@ static int __folio_split(struct folio *f
 	bool is_anon = folio_test_anon(folio);
 	struct address_space *mapping = NULL;
 	struct anon_vma *anon_vma = NULL;
+	struct inode *inode = NULL;
 	int old_order = folio_order(folio);
 	struct folio *new_folio, *next;
 	int nr_shmem_dropped = 0;
@@ -4057,6 +4058,20 @@ static int __folio_split(struct folio *f
 		}
 
 		anon_vma = NULL;
+
+		/*
+		 * The locked @lock_at folio keeps the inode alive: eviction
+		 * cannot remove it from the page cache while it is locked. But
+		 * the split drops it if it lies beyond EOF, after which we
+		 * still touch @mapping (shmem_uncharge(), i_mmap_unlock_read()).
+		 * Hold an inode reference across the split to be safe.
+		 */
+		inode = igrab(mapping->host);
+		if (!inode) {
+			/* Inode is being evicted; nothing to split. */
+			ret = -EBUSY;
+			goto out;
+		}
 		i_mmap_lock_read(mapping);
 
 		/*
@@ -4139,6 +4154,8 @@ out_unlock:
 	}
 	if (mapping)
 		i_mmap_unlock_read(mapping);
+	if (inode)
+		iput(inode);
 out:
 	xas_destroy(&xas);
 	if (is_pmd_order(old_order))
_

Patches currently in -mm which might be from kirill@shutemov.name are

mm-thp-pin-the-inode-across-a-file-folio-split.patch


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

only message in thread, other threads:[~2026-07-13 23:09 UTC | newest]

Thread overview: (only message) (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-07-13 23:09 + mm-thp-pin-the-inode-across-a-file-folio-split.patch added to mm-hotfixes-unstable branch 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.