Signed-off-by: Christoph Hellwig <hch@xxxxxx> --- fs/read_write.c | 60 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ fs/splice.c | 23 +++------------------ include/linux/fs.h | 5 +++++ 3 files changed, 68 insertions(+), 20 deletions(-) diff --git a/fs/read_write.c b/fs/read_write.c index c0805c9..299e262 100644 --- a/fs/read_write.c +++ b/fs/read_write.c @@ -333,6 +333,66 @@ out_putf: } #endif +ssize_t vfs_bvec_read(struct file *file, struct bio_vec *vec, + unsigned long nr_segs, size_t count, loff_t *ppos) +{ + struct iov_iter iter; + struct kiocb kiocb; + ssize_t ret; + + if (!file->f_op->read_iter) + return -EBADFD; + + iter.type = ITER_BVEC | READ; + iter.bvec = vec; + iter.nr_segs = nr_segs; + iter.count = count; + iter.iov_offset = 0; + + init_sync_kiocb(&kiocb, file); + kiocb.ki_pos = *ppos; + kiocb.ki_nbytes = count; + + ret = file->f_op->read_iter(&kiocb, &iter); + if (ret == -EIOCBQUEUED) + ret = wait_on_sync_kiocb(&kiocb); + + if (ret > 0) + *ppos = kiocb.ki_pos; + return ret; +} +EXPORT_SYMBOL(vfs_bvec_read); + +ssize_t vfs_bvec_write(struct file *file, struct bio_vec *vec, + unsigned long nr_segs, size_t count, loff_t *ppos) +{ + struct iov_iter iter; + struct kiocb kiocb; + ssize_t ret; + + if (!file->f_op->write_iter) + return -EBADFD; + + iter.type = ITER_BVEC | WRITE; + iter.bvec = vec; + iter.nr_segs = nr_segs; + iter.count = count; + iter.iov_offset = 0; + + init_sync_kiocb(&kiocb, file); + kiocb.ki_pos = *ppos; + kiocb.ki_nbytes = count; + + ret = file->f_op->write_iter(&kiocb, &iter); + if (ret == -EIOCBQUEUED) + ret = wait_on_sync_kiocb(&kiocb); + + if (ret > 0) + *ppos = kiocb.ki_pos; + return ret; +} +EXPORT_SYMBOL(vfs_bvec_write); + /* * rw_verify_area doesn't like huge counts. We limit * them to something that fits in "int" so that others diff --git a/fs/splice.c b/fs/splice.c index 75c6058..370e6c3 100644 --- a/fs/splice.c +++ b/fs/splice.c @@ -960,8 +960,6 @@ iter_file_splice_write(struct pipe_inode_info *pipe, struct file *out, splice_from_pipe_begin(&sd); while (sd.total_len) { - struct iov_iter from; - struct kiocb kiocb; size_t left; int n, idx; @@ -1005,29 +1003,14 @@ iter_file_splice_write(struct pipe_inode_info *pipe, struct file *out, left -= this_len; } - /* ... iov_iter */ - from.type = ITER_BVEC | WRITE; - from.bvec = array; - from.nr_segs = n; - from.count = sd.total_len - left; - from.iov_offset = 0; - - /* ... and iocb */ - init_sync_kiocb(&kiocb, out); - kiocb.ki_pos = sd.pos; - kiocb.ki_nbytes = sd.total_len - left; - - /* now, send it */ - ret = out->f_op->write_iter(&kiocb, &from); - if (-EIOCBQUEUED == ret) - ret = wait_on_sync_kiocb(&kiocb); - + ret = vfs_bvec_write(out, array, n, sd.total_len - left, + &sd.pos); if (ret <= 0) break; sd.num_spliced += ret; sd.total_len -= ret; - *ppos = sd.pos = kiocb.ki_pos; + *ppos = sd.pos; /* dismiss the fully eaten buffers, adjust the partial one */ while (ret) { diff --git a/include/linux/fs.h b/include/linux/fs.h index 42efe13..6423bdc 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -2494,6 +2494,11 @@ extern ssize_t do_sync_write(struct file *filp, const char __user *buf, size_t l extern ssize_t new_sync_read(struct file *filp, char __user *buf, size_t len, loff_t *ppos); extern ssize_t new_sync_write(struct file *filp, const char __user *buf, size_t len, loff_t *ppos); +ssize_t vfs_bvec_read(struct file *file, struct bio_vec *vec, + unsigned long nr_segs, size_t count, loff_t *ppos); +ssize_t vfs_bvec_write(struct file *file, struct bio_vec *vec, + unsigned long nr_segs, size_t count, loff_t *ppos); + /* fs/block_dev.c */ extern ssize_t blkdev_read_iter(struct kiocb *iocb, struct iov_iter *to); extern ssize_t blkdev_write_iter(struct kiocb *iocb, struct iov_iter *from); -- 1.9.1 -- To unsubscribe from this list: send the line "unsubscribe linux-fsdevel" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html