Re: [PATCH 2/5] mm: limit pagecache folio refcount when splicing into pipes

From: Lance Yang

Date: Fri Nov 06 2026 - 05:12:24 EST



On Thu, Nov 05, 2026 at 02:10:11PM +0100, David Hildenbrand (Arm) wrote:
>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.

What about fuse_ref_folio()? Buffered FUSE_WRITE requests can carry
pagecache folios into a pipe through /dev/fuse without going through
splice_folio_into_pipe() or try_get_page() ...

Cheers, Lance

>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
>
>