FAILED: patch "[PATCH] mm/huge_memory: unlock i_mmap_rwsem before releasing" failed to apply to 5.15-stable tree
Subsystems (3)
[email protected]
maintainerThe patch below does not apply to the 5.15-stable tree.
If someone wants it applied there, or to any other stable or longterm tree, then please email the backport, including the original git commit id to <[email protected]>.
To reproduce the conflict and resubmit, you may use the following commands:
git fetch https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/ linux-5.15.y
git checkout FETCH_HEAD
git cherry-pick -x e923bd21058ea02fd0dcd3549d151d143fd036e5
# <resolve conflicts, build, test, etc.>
git commit -s
git send-email --to '<[email protected]>' --in-reply-to '2026080503-upbeat-facility-22c2@gregkh' --subject-prefix 'PATCH 5.15.y' 'HEAD^..'
Possible dependencies:
thanks,
greg k-h
------------------ original commit in Linus's tree ------------------
From e923bd21058ea02fd0dcd3549d151d143fd036e5 Mon Sep 17 00:00:00 2001
From: "Kiryl Shutsemau (Meta)" <[email protected]>
Date: Thu, 16 Jul 2026 10:54:24 +0100
Subject: [PATCH] mm/huge_memory: unlock i_mmap_rwsem before releasing
after-split folios
__folio_split() keeps dereferencing the mapping after the split:shmem_uncharge(mapping->host) and remap_page() while the folios are still frozen/locked, and i_mmap_unlock_read(mapping) at the very end, after the after-split folios have been unlocked and freed.
Nothing holds an inode reference across that. The split relies on @folio -- which the beyond-EOF drop loop never removes, as it starts at folio_next(folio) -- staying locked and in the page cache to hold off eviction. But the unlock loop unlocks @folio before i_mmap_unlock_read() runs. If the caller's @lock_at is a tail beyond EOF, as memory_failure() passes when splitting a poisoned tail of a shmem THP that reaches past i_size during truncation, it too is gone from the page cache; so once @folio is unlocked no locked, in-cache folio pins the inode, and a concurrent final iput() can evict and RCU-free it before i_mmap_unlock_read() touches i_mmap_rwsem:
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 evict+0x57f/0xac0 fs/inode.c:870
Do every mapping dereference while @folio still pins the inode: drop i_mmap_rwsem right after remap_page(), before the loop that unlocks and frees the after-split folios, and clear @mapping so the exit path does not unlock it again. shmem_uncharge() and remap_page() already run before that point, so after this nothing past the unlock loop touches the inode or the mapping.
This is now a rule the split depends on, alongside keeping @folio frozen until the page cache is updated: no inode or mapping dereference once the after-split folios start being unlocked.
mm/huge_memory.c +12 -0
@@ -4113,6 +4113,18 @@ static int __folio_split(struct folio *folio, unsigned int new_order,remap_page (folio,1 << old_order, ttu_flags); +/* +* Drop the mapping while the inode is still pinned. @folio stays +* locked and present in the page cache until the loop below, so +* eviction cannot free the inode yet; @lock_at is not enough, it may +* be a tail beyond EOF that the split already dropped from the page +* cache. Nothing past this point may touch the inode or the mapping. +*/ +if (mapping) { +i_mmap_unlock_read (mapping); + mapping =NULL ; + } +/* * Unlock all after-split folios except the one containing * @lock_at page. If @folio is not split, it will be kept locked.
PATCH 1/1 mm/huge_memory: unlock i_mmap_rwsem before releasing after-split folios
From: "Kiryl Shutsemau (Meta)" <[email protected]>
__folio_split() keeps dereferencing the mapping after the split:shmem_uncharge(mapping->host) and remap_page() while the folios are still frozen/locked, and i_mmap_unlock_read(mapping) at the very end, after the after-split folios have been unlocked and freed.
Nothing holds an inode reference across that. The split relies on @folio -- which the beyond-EOF drop loop never removes, as it starts at folio_next(folio) -- staying locked and in the page cache to hold off eviction. But the unlock loop unlocks @folio before i_mmap_unlock_read() runs. If the caller's @lock_at is a tail beyond EOF, as memory_failure() passes when splitting a poisoned tail of a shmem THP that reaches past i_size during truncation, it too is gone from the page cache; so once @folio is unlocked no locked, in-cache folio pins the inode, and a concurrent final iput() can evict and RCU-free it before i_mmap_unlock_read() touches i_mmap_rwsem:
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 evict+0x57f/0xac0 fs/inode.c:870
Do every mapping dereference while @folio still pins the inode: drop i_mmap_rwsem right after remap_page(), before the loop that unlocks and frees the after-split folios, and clear @mapping so the exit path does not unlock it again. shmem_uncharge() and remap_page() already run before that point, so after this nothing past the unlock loop touches the inode or the mapping.
This is now a rule the split depends on, alongside keeping @folio frozen until the page cache is updated: no inode or mapping dereference once the after-split folios start being unlocked.
(cherry picked from commit e923bd21058ea02fd0dcd3549d151d143fd036e5) [ kas: adapt to the __split_huge_page()/split_huge_page_to_list()
two-function split: pass @mapping into __split_huge_page() and drop it there, before the loop that frees the after-split subpages while the head is still locked; the caller then skips its own i_mmap unlock ]
--- mm/huge_memory.c | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-)
mm/huge_memory.c +14 -2
@@ -2403,7 +2403,7 @@ static void __split_huge_page_tail(struct page *head, int tail, }static void __split_huge_page (struct page *page,struct list_head *list, -pgoff_t end) +pgoff_t end,struct address_space *mapping) {struct page *head =compound_head (page);struct lruvec *lruvec;
@@ -2476,6 +2476,16 @@ static void __split_huge_page(struct page *page, struct list_head *list,split_swap_cluster (entry); } +/* +* Drop the mapping while the head page is still locked and thus pins +* the inode. The loop below may free the after-split subpages -- +* including the head, when @page is a tail beyond EOF that the split +* dropped from the page cache -- which could otherwise let the inode, +* and @mapping, be freed before this unlock. +*/ +if (mapping) +i_mmap_unlock_read (mapping); +for (i =0 ; i < nr; i++) {struct page *subpage = head + i;if (subpage == page)
@@ -2717,7 +2727,9 @@ int split_huge_page_to_list(struct page *page, struct list_head *list) } } -__split_huge_page (page, list, end); +__split_huge_page (page, list, end, mapping); +/* __split_huge_page() dropped the i_mmap lock */ + mapping =NULL ; ret =0 ; }else {spin_unlock (&ds_queue->split_queue_lock);
Signature · 1 line
2.54.0
Re: [PATCH 5.15.y] mm/huge_memory: unlock i_mmap_rwsem before releasing after-split folios
Quoted 4 lines · Kiryl Shutsemau
Do every mapping dereference while @folio still pins the inode: drop
i_mmap_rwsemright afterremap_page(), before the loop that unlocks and frees the after-split folios, and clear @mapping so the exit path does not unlock it again.
Queued for 5.15, thanks.
Signature · 2 lines
Thanks, Sasha