Skip to content

Commit ccfdf7c

Browse files
dhowellsaxboe
authored andcommitted
ceph: Provide a splice-read wrapper
Provide a splice_read wrapper for Ceph. This does the inode shutdown check before proceeding and jumps to copy_splice_read() if the file has inline data or is a synchronous file. We try and get FILE_RD and either FILE_CACHE and/or FILE_LAZYIO caps and hold them across filemap_splice_read(). If we fail to get FILE_CACHE or FILE_LAZYIO capabilities, we use copy_splice_read() instead. Signed-off-by: David Howells <[email protected]> Reviewed-by: Xiubo Li <[email protected]> cc: Christoph Hellwig <[email protected]> cc: Al Viro <[email protected]> cc: Jens Axboe <[email protected]> cc: Ilya Dryomov <[email protected]> cc: Jeff Layton <[email protected]> cc: [email protected] cc: [email protected] cc: [email protected] cc: [email protected] Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Jens Axboe <[email protected]>
1 parent d96d96e commit ccfdf7c

File tree

1 file changed

+64
-1
lines changed

1 file changed

+64
-1
lines changed

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)