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>
diff --git a/fs/ceph/file.c b/fs/ceph/file.c
index d8f383d..910a302 100644
--- a/fs/ceph/file.c
+++ b/fs/ceph/file.c
@@ -833,24 +833,11 @@
/* hmm, this isn't really async... */
ret = ceph_sync_read(iocb, &i, &checkeof);
} else {
- /*
- * We can't modify the content of iov,
- * so we only read from beginning.
- *
- * When we switch generic_file_aio_read() to iov_iter, the
- * if () below will be removed -- AV
- */
- if (read) {
- iocb->ki_pos = pos;
- len = iocb->ki_nbytes;
- read = 0;
- iov_iter_init(&i, iov, nr_segs, len, 0);
- }
dout("aio_read %p %llx.%llx %llu~%u got cap refs on %s\n",
inode, ceph_vinop(inode), pos, (unsigned)len,
ceph_cap_string(got));
- ret = generic_file_aio_read(iocb, iov, nr_segs, pos);
+ ret = generic_file_read_iter(iocb, &i);
}
dout("aio_read %p %llx.%llx dropping cap refs on %s = %d\n",
inode, ceph_vinop(inode), ceph_cap_string(got), (int)ret);
diff --git a/fs/nfs/file.c b/fs/nfs/file.c
index 3d01b15..a352bc6 100644
--- a/fs/nfs/file.c
+++ b/fs/nfs/file.c
@@ -184,7 +184,7 @@
result = nfs_revalidate_mapping(inode, iocb->ki_filp->f_mapping);
if (!result) {
- result = generic_file_aio_read(iocb, iov, nr_segs, pos);
+ result = generic_file_read_iter(iocb, &to);
if (result > 0)
nfs_add_stats(inode, NFSIOS_NORMALREADBYTES, result);
}
diff --git a/include/linux/fs.h b/include/linux/fs.h
index 946a948..d096ebc 100644
--- a/include/linux/fs.h
+++ b/include/linux/fs.h
@@ -2404,6 +2404,7 @@
unsigned long size, pgoff_t pgoff);
int generic_write_checks(struct file *file, loff_t *pos, size_t *count, int isblk);
extern ssize_t generic_file_aio_read(struct kiocb *, const struct iovec *, unsigned long, loff_t);
+extern ssize_t generic_file_read_iter(struct kiocb *, struct iov_iter *);
extern ssize_t __generic_file_aio_write(struct kiocb *, const struct iovec *, unsigned long);
extern ssize_t generic_file_aio_write(struct kiocb *, const struct iovec *, unsigned long, loff_t);
extern ssize_t generic_file_direct_write(struct kiocb *, struct iov_iter *,
diff --git a/mm/filemap.c b/mm/filemap.c
index 866f4ae..a7f79e9 100644
--- a/mm/filemap.c
+++ b/mm/filemap.c
@@ -1663,6 +1663,56 @@
return written ? written : error;
}
+ssize_t
+generic_file_read_iter(struct kiocb *iocb, struct iov_iter *iter)
+{
+ struct file *file = iocb->ki_filp;
+ ssize_t retval = 0;
+ loff_t *ppos = &iocb->ki_pos;
+ loff_t pos = *ppos;
+
+ /* coalesce the iovecs and go direct-to-BIO for 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;
+
+ 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 = *iter;
+ retval = mapping->a_ops->direct_IO(READ, iocb, &data, pos);
+ }
+
+ if (retval > 0) {
+ *ppos = pos + retval;
+ iov_iter_advance(iter, retval);
+ }
+
+ /*
+ * Btrfs can have a short DIO read if we encounter
+ * compressed extents, so if there was an error, or if
+ * we've already read everything we wanted to, or if
+ * there was a short read because we hit EOF, go ahead
+ * and return. Otherwise fallthrough to buffered io for
+ * the rest of the read.
+ */
+ if (retval < 0 || !iov_iter_count(iter) || *ppos >= size) {
+ file_accessed(file);
+ goto out;
+ }
+ }
+
+ 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
@@ -1677,60 +1727,11 @@
generic_file_aio_read(struct kiocb *iocb, const struct iovec *iov,
unsigned long nr_segs, loff_t pos)
{
- struct file *filp = iocb->ki_filp;
- ssize_t retval = 0;
- size_t count;
- loff_t *ppos = &iocb->ki_pos;
+ size_t count = iov_length(iov, nr_segs);
struct iov_iter i;
- count = iov_length(iov, nr_segs);
iov_iter_init(&i, iov, nr_segs, count, 0);
-
- /* coalesce the iovecs and go direct-to-BIO for O_DIRECT */
- if (filp->f_flags & O_DIRECT) {
- 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;
- 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);
- }
-
- /*
- * Btrfs can have a short DIO read if we encounter
- * compressed extents, so if there was an error, or if
- * we've already read everything we wanted to, or if
- * there was a short read because we hit EOF, go ahead
- * and return. Otherwise fallthrough to buffered io for
- * the rest of the read.
- */
- if (retval < 0 || !count || *ppos >= size) {
- file_accessed(filp);
- goto out;
- }
- }
-
- retval = do_generic_file_read(filp, ppos, &i, retval);
-out:
- return retval;
+ return generic_file_read_iter(iocb, &i);
}
EXPORT_SYMBOL(generic_file_aio_read);