cifs: Implement splice_read to pass down ITER_BVEC not ITER_PIPE
Provide cifs_splice_read() to use a bvec rather than an pipe iterator as the latter cannot so easily be split and advanced, which is necessary to pass an iterator down to the bottom levels. Upstream cifs gets around this problem by using iov_iter_get_pages() to prefill the pipe and then passing the list of pages down. This is done by: (1) Bulk-allocate a bunch of pages to carry as much of the requested amount of data as possible, but without overrunning the available slots in the pipe and add them to an ITER_BVEC. (2) Synchronously call ->read_iter() to read into the buffer. (3) Discard any unused pages. (4) Load the remaining pages into the pipe in order and advance the head pointer. Signed-off-by: David Howells <dhowells@redhat.com> cc: Steve French <sfrench@samba.org> cc: Shyam Prasad N <nspmangalore@gmail.com> cc: Rohith Surabattula <rohiths.msft@gmail.com> cc: Jeff Layton <jlayton@kernel.org> cc: Al Viro <viro@zeniv.linux.org.uk> cc: linux-cifs@vger.kernel.org Link: https://lore.kernel.org/r/166732028113.3186319.1793644937097301358.stgit@warthog.procyon.org.uk/ # rfc Signed-off-by: Steve French <stfrench@microsoft.com>
This commit is contained in:
parent
7c8e01ebf2
commit
4e260a8fd7
|
@ -1358,7 +1358,7 @@ const struct file_operations cifs_file_ops = {
|
|||
.fsync = cifs_fsync,
|
||||
.flush = cifs_flush,
|
||||
.mmap = cifs_file_mmap,
|
||||
.splice_read = generic_file_splice_read,
|
||||
.splice_read = cifs_splice_read,
|
||||
.splice_write = iter_file_splice_write,
|
||||
.llseek = cifs_llseek,
|
||||
.unlocked_ioctl = cifs_ioctl,
|
||||
|
@ -1378,7 +1378,7 @@ const struct file_operations cifs_file_strict_ops = {
|
|||
.fsync = cifs_strict_fsync,
|
||||
.flush = cifs_flush,
|
||||
.mmap = cifs_file_strict_mmap,
|
||||
.splice_read = generic_file_splice_read,
|
||||
.splice_read = cifs_splice_read,
|
||||
.splice_write = iter_file_splice_write,
|
||||
.llseek = cifs_llseek,
|
||||
.unlocked_ioctl = cifs_ioctl,
|
||||
|
@ -1398,7 +1398,7 @@ const struct file_operations cifs_file_direct_ops = {
|
|||
.fsync = cifs_fsync,
|
||||
.flush = cifs_flush,
|
||||
.mmap = cifs_file_mmap,
|
||||
.splice_read = generic_file_splice_read,
|
||||
.splice_read = direct_splice_read,
|
||||
.splice_write = iter_file_splice_write,
|
||||
.unlocked_ioctl = cifs_ioctl,
|
||||
.copy_file_range = cifs_copy_file_range,
|
||||
|
@ -1416,7 +1416,7 @@ const struct file_operations cifs_file_nobrl_ops = {
|
|||
.fsync = cifs_fsync,
|
||||
.flush = cifs_flush,
|
||||
.mmap = cifs_file_mmap,
|
||||
.splice_read = generic_file_splice_read,
|
||||
.splice_read = cifs_splice_read,
|
||||
.splice_write = iter_file_splice_write,
|
||||
.llseek = cifs_llseek,
|
||||
.unlocked_ioctl = cifs_ioctl,
|
||||
|
@ -1434,7 +1434,7 @@ const struct file_operations cifs_file_strict_nobrl_ops = {
|
|||
.fsync = cifs_strict_fsync,
|
||||
.flush = cifs_flush,
|
||||
.mmap = cifs_file_strict_mmap,
|
||||
.splice_read = generic_file_splice_read,
|
||||
.splice_read = cifs_splice_read,
|
||||
.splice_write = iter_file_splice_write,
|
||||
.llseek = cifs_llseek,
|
||||
.unlocked_ioctl = cifs_ioctl,
|
||||
|
@ -1452,7 +1452,7 @@ const struct file_operations cifs_file_direct_nobrl_ops = {
|
|||
.fsync = cifs_fsync,
|
||||
.flush = cifs_flush,
|
||||
.mmap = cifs_file_mmap,
|
||||
.splice_read = generic_file_splice_read,
|
||||
.splice_read = direct_splice_read,
|
||||
.splice_write = iter_file_splice_write,
|
||||
.unlocked_ioctl = cifs_ioctl,
|
||||
.copy_file_range = cifs_copy_file_range,
|
||||
|
|
|
@ -100,6 +100,9 @@ extern ssize_t cifs_strict_readv(struct kiocb *iocb, struct iov_iter *to);
|
|||
extern ssize_t cifs_user_writev(struct kiocb *iocb, struct iov_iter *from);
|
||||
extern ssize_t cifs_direct_writev(struct kiocb *iocb, struct iov_iter *from);
|
||||
extern ssize_t cifs_strict_writev(struct kiocb *iocb, struct iov_iter *from);
|
||||
extern ssize_t cifs_splice_read(struct file *in, loff_t *ppos,
|
||||
struct pipe_inode_info *pipe, size_t len,
|
||||
unsigned int flags);
|
||||
extern int cifs_flock(struct file *pfile, int cmd, struct file_lock *plock);
|
||||
extern int cifs_lock(struct file *, int, struct file_lock *);
|
||||
extern int cifs_fsync(struct file *, loff_t, loff_t, int);
|
||||
|
|
|
@ -5275,3 +5275,19 @@ const struct address_space_operations cifs_addr_ops_smallbuf = {
|
|||
.launder_folio = cifs_launder_folio,
|
||||
.migrate_folio = filemap_migrate_folio,
|
||||
};
|
||||
|
||||
/*
|
||||
* Splice data from a file into a pipe.
|
||||
*/
|
||||
ssize_t cifs_splice_read(struct file *in, loff_t *ppos,
|
||||
struct pipe_inode_info *pipe, size_t len,
|
||||
unsigned int flags)
|
||||
{
|
||||
if (unlikely(*ppos >= file_inode(in)->i_sb->s_maxbytes))
|
||||
return 0;
|
||||
if (unlikely(!len))
|
||||
return 0;
|
||||
if (in->f_flags & O_DIRECT)
|
||||
return direct_splice_read(in, ppos, pipe, len, flags);
|
||||
return filemap_splice_read(in, ppos, pipe, len, flags);
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue