Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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>

authored by

David Howells and committed by
Steve French
4e260a8f 7c8e01eb

+25 -6
+6 -6
fs/cifs/cifsfs.c
··· 1358 1358 .fsync = cifs_fsync, 1359 1359 .flush = cifs_flush, 1360 1360 .mmap = cifs_file_mmap, 1361 - .splice_read = generic_file_splice_read, 1361 + .splice_read = cifs_splice_read, 1362 1362 .splice_write = iter_file_splice_write, 1363 1363 .llseek = cifs_llseek, 1364 1364 .unlocked_ioctl = cifs_ioctl, ··· 1378 1378 .fsync = cifs_strict_fsync, 1379 1379 .flush = cifs_flush, 1380 1380 .mmap = cifs_file_strict_mmap, 1381 - .splice_read = generic_file_splice_read, 1381 + .splice_read = cifs_splice_read, 1382 1382 .splice_write = iter_file_splice_write, 1383 1383 .llseek = cifs_llseek, 1384 1384 .unlocked_ioctl = cifs_ioctl, ··· 1398 1398 .fsync = cifs_fsync, 1399 1399 .flush = cifs_flush, 1400 1400 .mmap = cifs_file_mmap, 1401 - .splice_read = generic_file_splice_read, 1401 + .splice_read = direct_splice_read, 1402 1402 .splice_write = iter_file_splice_write, 1403 1403 .unlocked_ioctl = cifs_ioctl, 1404 1404 .copy_file_range = cifs_copy_file_range, ··· 1416 1416 .fsync = cifs_fsync, 1417 1417 .flush = cifs_flush, 1418 1418 .mmap = cifs_file_mmap, 1419 - .splice_read = generic_file_splice_read, 1419 + .splice_read = cifs_splice_read, 1420 1420 .splice_write = iter_file_splice_write, 1421 1421 .llseek = cifs_llseek, 1422 1422 .unlocked_ioctl = cifs_ioctl, ··· 1434 1434 .fsync = cifs_strict_fsync, 1435 1435 .flush = cifs_flush, 1436 1436 .mmap = cifs_file_strict_mmap, 1437 - .splice_read = generic_file_splice_read, 1437 + .splice_read = cifs_splice_read, 1438 1438 .splice_write = iter_file_splice_write, 1439 1439 .llseek = cifs_llseek, 1440 1440 .unlocked_ioctl = cifs_ioctl, ··· 1452 1452 .fsync = cifs_fsync, 1453 1453 .flush = cifs_flush, 1454 1454 .mmap = cifs_file_mmap, 1455 - .splice_read = generic_file_splice_read, 1455 + .splice_read = direct_splice_read, 1456 1456 .splice_write = iter_file_splice_write, 1457 1457 .unlocked_ioctl = cifs_ioctl, 1458 1458 .copy_file_range = cifs_copy_file_range,
+3
fs/cifs/cifsfs.h
··· 100 100 extern ssize_t cifs_user_writev(struct kiocb *iocb, struct iov_iter *from); 101 101 extern ssize_t cifs_direct_writev(struct kiocb *iocb, struct iov_iter *from); 102 102 extern ssize_t cifs_strict_writev(struct kiocb *iocb, struct iov_iter *from); 103 + extern ssize_t cifs_splice_read(struct file *in, loff_t *ppos, 104 + struct pipe_inode_info *pipe, size_t len, 105 + unsigned int flags); 103 106 extern int cifs_flock(struct file *pfile, int cmd, struct file_lock *plock); 104 107 extern int cifs_lock(struct file *, int, struct file_lock *); 105 108 extern int cifs_fsync(struct file *, loff_t, loff_t, int);
+16
fs/cifs/file.c
··· 5275 5275 .launder_folio = cifs_launder_folio, 5276 5276 .migrate_folio = filemap_migrate_folio, 5277 5277 }; 5278 + 5279 + /* 5280 + * Splice data from a file into a pipe. 5281 + */ 5282 + ssize_t cifs_splice_read(struct file *in, loff_t *ppos, 5283 + struct pipe_inode_info *pipe, size_t len, 5284 + unsigned int flags) 5285 + { 5286 + if (unlikely(*ppos >= file_inode(in)->i_sb->s_maxbytes)) 5287 + return 0; 5288 + if (unlikely(!len)) 5289 + return 0; 5290 + if (in->f_flags & O_DIRECT) 5291 + return direct_splice_read(in, ppos, pipe, len, flags); 5292 + return filemap_splice_read(in, ppos, pipe, len, flags); 5293 + }