summaryrefslogtreecommitdiff
path: root/mm
diff options
context:
space:
mode:
authorAl Viro <viro@zeniv.linux.org.uk>2014-03-05 22:53:04 -0500
committerAl Viro <viro@zeniv.linux.org.uk>2014-05-06 17:32:49 -0400
commited978a811ec528dbe40243605c3afab55892f722 (patch)
tree7b8b83a755286192b98bb7921fa4d6957709216e /mm
parent23faa7b8db9be0be4f158cfc558460bb95d9b245 (diff)
downloadlinux-ed978a811ec528dbe40243605c3afab55892f722.tar.gz
new helper: generic_file_read_iter()
iov_iter-using variant of generic_file_aio_read(). Some callers converted. Note that it's still not quite there for use as ->read_iter() - we depend on having zero iter->iov_offset in O_DIRECT case. Fortunately, that's true for all converted callers (and for generic_file_aio_read() itself). Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
Diffstat (limited to 'mm')
-rw-r--r--mm/filemap.c67
1 files changed, 34 insertions, 33 deletions
diff --git a/mm/filemap.c b/mm/filemap.c
index 866f4ae8223b..a7f79e90209c 100644
--- a/mm/filemap.c
+++ b/mm/filemap.c
@@ -1663,55 +1663,34 @@ out:
return written ? written : error;
}
-/**
- * generic_file_aio_read - generic filesystem read routine
- * @iocb: kernel I/O control block
- * @iov: io vector request
- * @nr_segs: number of segments in the iovec
- * @pos: current file position
- *
- * This is the "read()" routine for all filesystems
- * that can use the page cache directly.
- */
ssize_t
-generic_file_aio_read(struct kiocb *iocb, const struct iovec *iov,
- unsigned long nr_segs, loff_t pos)
+generic_file_read_iter(struct kiocb *iocb, struct iov_iter *iter)
{
- struct file *filp = iocb->ki_filp;
+ struct file *file = iocb->ki_filp;
ssize_t retval = 0;
- size_t count;
loff_t *ppos = &iocb->ki_pos;
- struct iov_iter i;
-
- count = iov_length(iov, nr_segs);
- iov_iter_init(&i, iov, nr_segs, count, 0);
+ loff_t pos = *ppos;
/* coalesce the iovecs and go direct-to-BIO for O_DIRECT */
- if (filp->f_flags & O_DIRECT) {
+ if (file->f_flags & O_DIRECT) {
+ struct address_space *mapping = file->f_mapping;
+ struct inode *inode = mapping->host;
+ size_t count = iov_iter_count(iter);
loff_t size;
- struct address_space *mapping;
- struct inode *inode;
- mapping = filp->f_mapping;
- inode = mapping->host;
if (!count)
goto out; /* skip atime */
size = i_size_read(inode);
retval = filemap_write_and_wait_range(mapping, pos,
pos + count - 1);
if (!retval) {
- struct iov_iter data = i;
+ struct iov_iter data = *iter;
retval = mapping->a_ops->direct_IO(READ, iocb, &data, pos);
}
if (retval > 0) {
*ppos = pos + retval;
- count -= retval;
- /*
- * If we did a short DIO read we need to skip the
- * section of the iov that we've already read data into.
- */
- iov_iter_advance(&i, retval);
+ iov_iter_advance(iter, retval);
}
/*
@@ -1722,16 +1701,38 @@ generic_file_aio_read(struct kiocb *iocb, const struct iovec *iov,
* and return. Otherwise fallthrough to buffered io for
* the rest of the read.
*/
- if (retval < 0 || !count || *ppos >= size) {
- file_accessed(filp);
+ if (retval < 0 || !iov_iter_count(iter) || *ppos >= size) {
+ file_accessed(file);
goto out;
}
}
- retval = do_generic_file_read(filp, ppos, &i, retval);
+ retval = do_generic_file_read(file, ppos, iter, retval);
out:
return retval;
}
+EXPORT_SYMBOL(generic_file_read_iter);
+
+/**
+ * generic_file_aio_read - generic filesystem read routine
+ * @iocb: kernel I/O control block
+ * @iov: io vector request
+ * @nr_segs: number of segments in the iovec
+ * @pos: current file position
+ *
+ * This is the "read()" routine for all filesystems
+ * that can use the page cache directly.
+ */
+ssize_t
+generic_file_aio_read(struct kiocb *iocb, const struct iovec *iov,
+ unsigned long nr_segs, loff_t pos)
+{
+ size_t count = iov_length(iov, nr_segs);
+ struct iov_iter i;
+
+ iov_iter_init(&i, iov, nr_segs, count, 0);
+ return generic_file_read_iter(iocb, &i);
+}
EXPORT_SYMBOL(generic_file_aio_read);
#ifdef CONFIG_MMU