summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChristoph Hellwig <hch@lst.de>2015-01-25 20:11:59 (GMT)
committerPaul Osmialowski <p.osmialowsk@samsung.com>2015-04-15 15:45:08 (GMT)
commit729fb056c731aa17583b04829bd791c42ef99310 (patch)
treeb6b0ad3f96e41c8c164cc96a0ad8486bcc275407
parent52314c4b0c513205da9c51d1eed029f9b496c274 (diff)
downloadlinux-3.10-729fb056c731aa17583b04829bd791c42ef99310.zip
linux-3.10-729fb056c731aa17583b04829bd791c42ef99310.tar.gz
linux-3.10-729fb056c731aa17583b04829bd791c42ef99310.tar.bz2
fs: add vfs_iter_{read,write} helpers
Simple helpers that pass an arbitrary iov_iter to filesystems. Change-Id: I71c05364ad7442f974ca232c2deb6dfee5fbe25d Signed-off-by: Christoph Hellwig <hch@lst.de> Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
-rw-r--r--fs/read_write.c46
-rw-r--r--include/linux/fs.h4
2 files changed, 50 insertions, 0 deletions
diff --git a/fs/read_write.c b/fs/read_write.c
index f6b7c60..69ab45e 100644
--- a/fs/read_write.c
+++ b/fs/read_write.c
@@ -291,6 +291,52 @@ out_putf:
}
#endif
+ssize_t vfs_iter_read(struct file *file, struct iov_iter *iter, loff_t *ppos)
+{
+ struct kiocb kiocb;
+ ssize_t ret;
+
+ if (!file->f_op->read_iter)
+ return -EINVAL;
+
+ init_sync_kiocb(&kiocb, file);
+ kiocb.ki_pos = *ppos;
+ kiocb.ki_nbytes = iov_iter_count(iter);
+
+ iter->type |= READ;
+ 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_iter_read);
+
+ssize_t vfs_iter_write(struct file *file, struct iov_iter *iter, loff_t *ppos)
+{
+ struct kiocb kiocb;
+ ssize_t ret;
+
+ if (!file->f_op->write_iter)
+ return -EINVAL;
+
+ init_sync_kiocb(&kiocb, file);
+ kiocb.ki_pos = *ppos;
+ kiocb.ki_nbytes = iov_iter_count(iter);
+
+ iter->type |= WRITE;
+ 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_iter_write);
+
/*
* rw_verify_area doesn't like huge counts. We limit
* them to something that fits in "int" so that others
diff --git a/include/linux/fs.h b/include/linux/fs.h
index aacddc7..358abc0 100644
--- a/include/linux/fs.h
+++ b/include/linux/fs.h
@@ -287,6 +287,7 @@ enum positive_aop_returns {
struct page;
struct address_space;
struct writeback_control;
+struct iov_iter;
struct iov_iter {
const struct iovec *iov;
@@ -2440,6 +2441,9 @@ extern ssize_t do_sync_write(struct file *filp, const char __user *buf, size_t l
extern int generic_segment_checks(const struct iovec *iov,
unsigned long *nr_segs, size_t *count, int access_flags);
+ssize_t vfs_iter_read(struct file *file, struct iov_iter *iter, loff_t *ppos);
+ssize_t vfs_iter_write(struct file *file, struct iov_iter *iter, loff_t *ppos);
+
/* fs/block_dev.c */
extern ssize_t blkdev_aio_write(struct kiocb *iocb, const struct iovec *iov,
unsigned long nr_segs, loff_t pos);