Skip to content

Commit 3eccc0c

Browse files
committed
Merge tag 'for-6.5/splice-2023-06-23' of git://git.kernel.dk/linux
Pull splice updates from Jens Axboe: "This kills off ITER_PIPE to avoid a race between truncate, iov_iter_revert() on the pipe and an as-yet incomplete DMA to a bio with unpinned/unref'ed pages from an O_DIRECT splice read. This causes memory corruption. Instead, we either use (a) filemap_splice_read(), which invokes the buffered file reading code and splices from the pagecache into the pipe; (b) copy_splice_read(), which bulk-allocates a buffer, reads into it and then pushes the filled pages into the pipe; or (c) handle it in filesystem-specific code. Summary: - Rename direct_splice_read() to copy_splice_read() - Simplify the calculations for the number of pages to be reclaimed in copy_splice_read() - Turn do_splice_to() into a helper, vfs_splice_read(), so that it can be used by overlayfs and coda to perform the checks on the lower fs - Make vfs_splice_read() jump to copy_splice_read() to handle direct-I/O and DAX - Provide shmem with its own splice_read to handle non-existent pages in the pagecache. We don't want a ->read_folio() as we don't want to populate holes, but filemap_get_pages() requires it - Provide overlayfs with its own splice_read to call down to a lower layer as overlayfs doesn't provide ->read_folio() - Provide coda with its own splice_read to call down to a lower layer as coda doesn't provide ->read_folio() - Direct ->splice_read to copy_splice_read() in tty, procfs, kernfs and random files as they just copy to the output buffer and don't splice pages - Provide wrappers for afs, ceph, ecryptfs, ext4, f2fs, nfs, ntfs3, ocfs2, orangefs, xfs and zonefs to do locking and/or revalidation - Make cifs use filemap_splice_read() - Replace pointers to generic_file_splice_read() with pointers to filemap_splice_read() as DIO and DAX are handled in the caller; filesystems can still provide their own alternate ->splice_read() op - Remove generic_file_splice_read() - Remove ITER_PIPE and its paraphernalia as generic_file_splice_read was the only user" * tag 'for-6.5/splice-2023-06-23' of git://git.kernel.dk/linux: (31 commits) splice: kdoc for filemap_splice_read() and copy_splice_read() iov_iter: Kill ITER_PIPE splice: Remove generic_file_splice_read() splice: Use filemap_splice_read() instead of generic_file_splice_read() cifs: Use filemap_splice_read() trace: Convert trace/seq to use copy_splice_read() zonefs: Provide a splice-read wrapper xfs: Provide a splice-read wrapper orangefs: Provide a splice-read wrapper ocfs2: Provide a splice-read wrapper ntfs3: Provide a splice-read wrapper nfs: Provide a splice-read wrapper f2fs: Provide a splice-read wrapper ext4: Provide a splice-read wrapper ecryptfs: Provide a splice-read wrapper ceph: Provide a splice-read wrapper afs: Provide a splice-read wrapper 9p: Add splice_read wrapper net: Make sock_splice_read() use copy_splice_read() by default tty, proc, kernfs, random: Use copy_splice_read() ...
2 parents cc423f6 + 9eee8bd commit 3eccc0c

File tree

68 files changed

+694
-621
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

68 files changed

+694
-621
lines changed

block/fops.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -701,7 +701,7 @@ const struct file_operations def_blk_fops = {
701701
#ifdef CONFIG_COMPAT
702702
.compat_ioctl = compat_blkdev_ioctl,
703703
#endif
704-
.splice_read = generic_file_splice_read,
704+
.splice_read = filemap_splice_read,
705705
.splice_write = iter_file_splice_write,
706706
.fallocate = blkdev_fallocate,
707707
};

drivers/char/random.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1546,7 +1546,7 @@ const struct file_operations random_fops = {
15461546
.compat_ioctl = compat_ptr_ioctl,
15471547
.fasync = random_fasync,
15481548
.llseek = noop_llseek,
1549-
.splice_read = generic_file_splice_read,
1549+
.splice_read = copy_splice_read,
15501550
.splice_write = iter_file_splice_write,
15511551
};
15521552

@@ -1557,7 +1557,7 @@ const struct file_operations urandom_fops = {
15571557
.compat_ioctl = compat_ptr_ioctl,
15581558
.fasync = random_fasync,
15591559
.llseek = noop_llseek,
1560-
.splice_read = generic_file_splice_read,
1560+
.splice_read = copy_splice_read,
15611561
.splice_write = iter_file_splice_write,
15621562
};
15631563

drivers/tty/tty_io.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -466,7 +466,7 @@ static const struct file_operations tty_fops = {
466466
.llseek = no_llseek,
467467
.read_iter = tty_read,
468468
.write_iter = tty_write,
469-
.splice_read = generic_file_splice_read,
469+
.splice_read = copy_splice_read,
470470
.splice_write = iter_file_splice_write,
471471
.poll = tty_poll,
472472
.unlocked_ioctl = tty_ioctl,
@@ -481,7 +481,7 @@ static const struct file_operations console_fops = {
481481
.llseek = no_llseek,
482482
.read_iter = tty_read,
483483
.write_iter = redirected_tty_write,
484-
.splice_read = generic_file_splice_read,
484+
.splice_read = copy_splice_read,
485485
.splice_write = iter_file_splice_write,
486486
.poll = tty_poll,
487487
.unlocked_ioctl = tty_ioctl,

fs/9p/vfs_file.c

Lines changed: 24 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -374,6 +374,28 @@ v9fs_file_read_iter(struct kiocb *iocb, struct iov_iter *to)
374374
return ret;
375375
}
376376

377+
/*
378+
* v9fs_file_splice_read - splice-read from a file
379+
* @in: The 9p file to read from
380+
* @ppos: Where to find/update the file position
381+
* @pipe: The pipe to splice into
382+
* @len: The maximum amount of data to splice
383+
* @flags: SPLICE_F_* flags
384+
*/
385+
static ssize_t v9fs_file_splice_read(struct file *in, loff_t *ppos,
386+
struct pipe_inode_info *pipe,
387+
size_t len, unsigned int flags)
388+
{
389+
struct p9_fid *fid = in->private_data;
390+
391+
p9_debug(P9_DEBUG_VFS, "fid %d count %zu offset %lld\n",
392+
fid->fid, len, *ppos);
393+
394+
if (fid->mode & P9L_DIRECT)
395+
return copy_splice_read(in, ppos, pipe, len, flags);
396+
return filemap_splice_read(in, ppos, pipe, len, flags);
397+
}
398+
377399
/**
378400
* v9fs_file_write_iter - write to a file
379401
* @iocb: The operation parameters
@@ -569,7 +591,7 @@ const struct file_operations v9fs_file_operations = {
569591
.release = v9fs_dir_release,
570592
.lock = v9fs_file_lock,
571593
.mmap = generic_file_readonly_mmap,
572-
.splice_read = generic_file_splice_read,
594+
.splice_read = v9fs_file_splice_read,
573595
.splice_write = iter_file_splice_write,
574596
.fsync = v9fs_file_fsync,
575597
};
@@ -583,7 +605,7 @@ const struct file_operations v9fs_file_operations_dotl = {
583605
.lock = v9fs_file_lock_dotl,
584606
.flock = v9fs_file_flock_dotl,
585607
.mmap = v9fs_file_mmap,
586-
.splice_read = generic_file_splice_read,
608+
.splice_read = v9fs_file_splice_read,
587609
.splice_write = iter_file_splice_write,
588610
.fsync = v9fs_file_fsync_dotl,
589611
};

fs/adfs/file.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ const struct file_operations adfs_file_operations = {
2828
.mmap = generic_file_mmap,
2929
.fsync = generic_file_fsync,
3030
.write_iter = generic_file_write_iter,
31-
.splice_read = generic_file_splice_read,
31+
.splice_read = filemap_splice_read,
3232
};
3333

3434
const struct inode_operations adfs_file_inode_operations = {

fs/affs/file.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1001,7 +1001,7 @@ const struct file_operations affs_file_operations = {
10011001
.open = affs_file_open,
10021002
.release = affs_file_release,
10031003
.fsync = affs_file_fsync,
1004-
.splice_read = generic_file_splice_read,
1004+
.splice_read = filemap_splice_read,
10051005
};
10061006

10071007
const struct inode_operations affs_file_inode_operations = {

fs/afs/file.c

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,9 @@ static void afs_invalidate_folio(struct folio *folio, size_t offset,
2525
static bool afs_release_folio(struct folio *folio, gfp_t gfp_flags);
2626

2727
static ssize_t afs_file_read_iter(struct kiocb *iocb, struct iov_iter *iter);
28+
static ssize_t afs_file_splice_read(struct file *in, loff_t *ppos,
29+
struct pipe_inode_info *pipe,
30+
size_t len, unsigned int flags);
2831
static void afs_vm_open(struct vm_area_struct *area);
2932
static void afs_vm_close(struct vm_area_struct *area);
3033
static vm_fault_t afs_vm_map_pages(struct vm_fault *vmf, pgoff_t start_pgoff, pgoff_t end_pgoff);
@@ -36,7 +39,7 @@ const struct file_operations afs_file_operations = {
3639
.read_iter = afs_file_read_iter,
3740
.write_iter = afs_file_write,
3841
.mmap = afs_file_mmap,
39-
.splice_read = generic_file_splice_read,
42+
.splice_read = afs_file_splice_read,
4043
.splice_write = iter_file_splice_write,
4144
.fsync = afs_fsync,
4245
.lock = afs_lock,
@@ -587,3 +590,18 @@ static ssize_t afs_file_read_iter(struct kiocb *iocb, struct iov_iter *iter)
587590

588591
return generic_file_read_iter(iocb, iter);
589592
}
593+
594+
static ssize_t afs_file_splice_read(struct file *in, loff_t *ppos,
595+
struct pipe_inode_info *pipe,
596+
size_t len, unsigned int flags)
597+
{
598+
struct afs_vnode *vnode = AFS_FS_I(file_inode(in));
599+
struct afs_file *af = in->private_data;
600+
int ret;
601+
602+
ret = afs_validate(vnode, af->key);
603+
if (ret < 0)
604+
return ret;
605+
606+
return filemap_splice_read(in, ppos, pipe, len, flags);
607+
}

fs/bfs/file.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ const struct file_operations bfs_file_operations = {
2727
.read_iter = generic_file_read_iter,
2828
.write_iter = generic_file_write_iter,
2929
.mmap = generic_file_mmap,
30-
.splice_read = generic_file_splice_read,
30+
.splice_read = filemap_splice_read,
3131
};
3232

3333
static int bfs_move_block(unsigned long from, unsigned long to,

fs/btrfs/file.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3817,7 +3817,7 @@ static ssize_t btrfs_file_read_iter(struct kiocb *iocb, struct iov_iter *to)
38173817
const struct file_operations btrfs_file_operations = {
38183818
.llseek = btrfs_file_llseek,
38193819
.read_iter = btrfs_file_read_iter,
3820-
.splice_read = generic_file_splice_read,
3820+
.splice_read = filemap_splice_read,
38213821
.write_iter = btrfs_file_write_iter,
38223822
.splice_write = iter_file_splice_write,
38233823
.mmap = btrfs_file_mmap,

fs/ceph/file.c

Lines changed: 64 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1745,6 +1745,69 @@ static ssize_t ceph_read_iter(struct kiocb *iocb, struct iov_iter *to)
17451745
return ret;
17461746
}
17471747

1748+
/*
1749+
* Wrap filemap_splice_read with checks for cap bits on the inode.
1750+
* Atomically grab references, so that those bits are not released
1751+
* back to the MDS mid-read.
1752+
*/
1753+
static ssize_t ceph_splice_read(struct file *in, loff_t *ppos,
1754+
struct pipe_inode_info *pipe,
1755+
size_t len, unsigned int flags)
1756+
{
1757+
struct ceph_file_info *fi = in->private_data;
1758+
struct inode *inode = file_inode(in);
1759+
struct ceph_inode_info *ci = ceph_inode(inode);
1760+
ssize_t ret;
1761+
int want = 0, got = 0;
1762+
CEPH_DEFINE_RW_CONTEXT(rw_ctx, 0);
1763+
1764+
dout("splice_read %p %llx.%llx %llu~%zu trying to get caps on %p\n",
1765+
inode, ceph_vinop(inode), *ppos, len, inode);
1766+
1767+
if (ceph_inode_is_shutdown(inode))
1768+
return -ESTALE;
1769+
1770+
if (ceph_has_inline_data(ci) ||
1771+
(fi->flags & CEPH_F_SYNC))
1772+
return copy_splice_read(in, ppos, pipe, len, flags);
1773+
1774+
ceph_start_io_read(inode);
1775+
1776+
want = CEPH_CAP_FILE_CACHE;
1777+
if (fi->fmode & CEPH_FILE_MODE_LAZY)
1778+
want |= CEPH_CAP_FILE_LAZYIO;
1779+
1780+
ret = ceph_get_caps(in, CEPH_CAP_FILE_RD, want, -1, &got);
1781+
if (ret < 0)
1782+
goto out_end;
1783+
1784+
if ((got & (CEPH_CAP_FILE_CACHE | CEPH_CAP_FILE_LAZYIO)) == 0) {
1785+
dout("splice_read/sync %p %llx.%llx %llu~%zu got cap refs on %s\n",
1786+
inode, ceph_vinop(inode), *ppos, len,
1787+
ceph_cap_string(got));
1788+
1789+
ceph_put_cap_refs(ci, got);
1790+
ceph_end_io_read(inode);
1791+
return copy_splice_read(in, ppos, pipe, len, flags);
1792+
}
1793+
1794+
dout("splice_read %p %llx.%llx %llu~%zu got cap refs on %s\n",
1795+
inode, ceph_vinop(inode), *ppos, len, ceph_cap_string(got));
1796+
1797+
rw_ctx.caps = got;
1798+
ceph_add_rw_context(fi, &rw_ctx);
1799+
ret = filemap_splice_read(in, ppos, pipe, len, flags);
1800+
ceph_del_rw_context(fi, &rw_ctx);
1801+
1802+
dout("splice_read %p %llx.%llx dropping cap refs on %s = %zd\n",
1803+
inode, ceph_vinop(inode), ceph_cap_string(got), ret);
1804+
1805+
ceph_put_cap_refs(ci, got);
1806+
out_end:
1807+
ceph_end_io_read(inode);
1808+
return ret;
1809+
}
1810+
17481811
/*
17491812
* Take cap references to avoid releasing caps to MDS mid-write.
17501813
*
@@ -2593,7 +2656,7 @@ const struct file_operations ceph_file_fops = {
25932656
.lock = ceph_lock,
25942657
.setlease = simple_nosetlease,
25952658
.flock = ceph_flock,
2596-
.splice_read = generic_file_splice_read,
2659+
.splice_read = ceph_splice_read,
25972660
.splice_write = iter_file_splice_write,
25982661
.unlocked_ioctl = ceph_ioctl,
25992662
.compat_ioctl = compat_ptr_ioctl,

0 commit comments

Comments
 (0)