[PATCH 2/5] mm: limit pagecache folio refcount when splicing into pipes
From: David Hildenbrand (Arm)
Date: Thu Nov 05 2026 - 08:18:38 EST
Similar to mapping pagecache folios into page tables, let's reject splicing
folios into a pipe if the refcount is at it's limit, similar to how we
handle it during GUP.
This will prevent more cases of possible folio refcount overflows with
large pagecache folios.
Let's keep it simple and check in the two callers of
splice_folio_into_pipe().
Also check in try_get_page() to cover pipe-buffer duplication by tee()
and partial pipe-to-pipe splicing.
Fixes: 800d8c63b2e9 ("shmem: add huge pages support")
Fixes: 99cb0dbd47a1 ("mm,thp: add read-only THP support for (non-shmem) FS")
Fixes: 793917d997df ("mm/readahead: Add large folio readahead")
Cc: stable@xxxxxxxxxxxxxxx
Signed-off-by: David Hildenbrand (Arm) <david@xxxxxxxxxx>
---
include/linux/mm.h | 9 ++++++---
mm/filemap.c | 4 ++++
mm/shmem.c | 4 ++++
3 files changed, 14 insertions(+), 3 deletions(-)
diff --git a/include/linux/mm.h b/include/linux/mm.h
index 79ae8fc0d6bb4..a82cfbce18215 100644
--- a/include/linux/mm.h
+++ b/include/linux/mm.h
@@ -2287,10 +2287,13 @@ static inline void get_page(struct page *page)
static inline __must_check bool try_get_page(struct page *page)
{
- page = compound_head(page);
- if (WARN_ON_ONCE(page_ref_count(page) <= 0))
+ struct folio *folio = page_folio(page);
+
+ if (WARN_ON_ONCE(folio_ref_count(folio) <= 0))
return false;
- page_ref_inc(page);
+ if (unlikely(folio_ref_count_over_limit(folio)))
+ return false;
+ folio_ref_inc(folio);
return true;
}
diff --git a/mm/filemap.c b/mm/filemap.c
index 920bbf86dfdff..0f2ec790a5b65 100644
--- a/mm/filemap.c
+++ b/mm/filemap.c
@@ -3168,6 +3168,10 @@ ssize_t filemap_splice_read(struct file *in, loff_t *ppos,
if (writably_mapped)
flush_dcache_folio(folio);
+ if (unlikely(folio_ref_count_over_limit(folio))) {
+ error = -ENOMEM;
+ goto out;
+ }
n = min_t(loff_t, len, isize - *ppos);
n = splice_folio_into_pipe(pipe, folio, *ppos, n);
if (!n)
diff --git a/mm/shmem.c b/mm/shmem.c
index cda1a0f7db99d..1c0f6bceac486 100644
--- a/mm/shmem.c
+++ b/mm/shmem.c
@@ -3819,6 +3819,10 @@ static ssize_t shmem_file_splice_read(struct file *in, loff_t *ppos,
* Ok, we have the page, and it's up-to-date, so we can
* now splice it into the pipe.
*/
+ if (unlikely(folio_ref_count_over_limit(folio))) {
+ error = -ENOMEM;
+ break;
+ }
n = splice_folio_into_pipe(pipe, folio, *ppos, part);
folio_put(folio);
folio = NULL;
--
2.43.0