#include <linux/ramfs.h>
 #include <linux/page_idle.h>
 #include <linux/migrate.h>
+#include <linux/pipe_fs_i.h>
+#include <linux/splice.h>
 #include <asm/pgalloc.h>
 #include <asm/tlbflush.h>
 #include "internal.h"
 }
 EXPORT_SYMBOL(generic_file_read_iter);
 
+/*
+ * Splice subpages from a folio into a pipe.
+ */
+size_t splice_folio_into_pipe(struct pipe_inode_info *pipe,
+                             struct folio *folio, loff_t fpos, size_t size)
+{
+       struct page *page;
+       size_t spliced = 0, offset = offset_in_folio(folio, fpos);
+
+       page = folio_page(folio, offset / PAGE_SIZE);
+       size = min(size, folio_size(folio) - offset);
+       offset %= PAGE_SIZE;
+
+       while (spliced < size &&
+              !pipe_full(pipe->head, pipe->tail, pipe->max_usage)) {
+               struct pipe_buffer *buf = pipe_head_buf(pipe);
+               size_t part = min_t(size_t, PAGE_SIZE - offset, size - spliced);
+
+               *buf = (struct pipe_buffer) {
+                       .ops    = &page_cache_pipe_buf_ops,
+                       .page   = page,
+                       .offset = offset,
+                       .len    = part,
+               };
+               folio_get(folio);
+               pipe->head++;
+               page++;
+               spliced += part;
+               offset = 0;
+       }
+
+       return spliced;
+}
+
+/*
+ * Splice folios from the pagecache of a buffered (ie. non-O_DIRECT) file into
+ * a pipe.
+ */
+ssize_t filemap_splice_read(struct file *in, loff_t *ppos,
+                           struct pipe_inode_info *pipe,
+                           size_t len, unsigned int flags)
+{
+       struct folio_batch fbatch;
+       struct kiocb iocb;
+       size_t total_spliced = 0, used, npages;
+       loff_t isize, end_offset;
+       bool writably_mapped;
+       int i, error = 0;
+
+       init_sync_kiocb(&iocb, in);
+       iocb.ki_pos = *ppos;
+
+       /* Work out how much data we can actually add into the pipe */
+       used = pipe_occupancy(pipe->head, pipe->tail);
+       npages = max_t(ssize_t, pipe->max_usage - used, 0);
+       len = min_t(size_t, len, npages * PAGE_SIZE);
+
+       folio_batch_init(&fbatch);
+
+       do {
+               cond_resched();
+
+               if (*ppos >= i_size_read(file_inode(in)))
+                       break;
+
+               iocb.ki_pos = *ppos;
+               error = filemap_get_pages(&iocb, len, &fbatch, true);
+               if (error < 0)
+                       break;
+
+               /*
+                * i_size must be checked after we know the pages are Uptodate.
+                *
+                * Checking i_size after the check allows us to calculate
+                * the correct value for "nr", which means the zero-filled
+                * part of the page is not copied back to userspace (unless
+                * another truncate extends the file - this is desired though).
+                */
+               isize = i_size_read(file_inode(in));
+               if (unlikely(*ppos >= isize))
+                       break;
+               end_offset = min_t(loff_t, isize, *ppos + len);
+
+               /*
+                * Once we start copying data, we don't want to be touching any
+                * cachelines that might be contended:
+                */
+               writably_mapped = mapping_writably_mapped(in->f_mapping);
+
+               for (i = 0; i < folio_batch_count(&fbatch); i++) {
+                       struct folio *folio = fbatch.folios[i];
+                       size_t n;
+
+                       if (folio_pos(folio) >= end_offset)
+                               goto out;
+                       folio_mark_accessed(folio);
+
+                       /*
+                        * If users can be writing to this folio using arbitrary
+                        * virtual addresses, take care of potential aliasing
+                        * before reading the folio on the kernel side.
+                        */
+                       if (writably_mapped)
+                               flush_dcache_folio(folio);
+
+                       n = min_t(loff_t, len, isize - *ppos);
+                       n = splice_folio_into_pipe(pipe, folio, *ppos, n);
+                       if (!n)
+                               goto out;
+                       len -= n;
+                       total_spliced += n;
+                       *ppos += n;
+                       in->f_ra.prev_pos = *ppos;
+                       if (pipe_full(pipe->head, pipe->tail, pipe->max_usage))
+                               goto out;
+               }
+
+               folio_batch_release(&fbatch);
+       } while (len);
+
+out:
+       folio_batch_release(&fbatch);
+       file_accessed(in);
+
+       return total_spliced ? total_spliced : error;
+}
+
 static inline loff_t folio_seek_hole_data(struct xa_state *xas,
                struct address_space *mapping, struct folio *folio,
                loff_t start, loff_t end, bool seek_data)