diff --git a/fs/ceph/file.c b/fs/ceph/file.c index d8f383d59449..910a3022eb27 100644 --- a/fs/ceph/file.c +++ b/fs/ceph/file.c @@ -833,24 +833,11 @@ static ssize_t ceph_aio_read(struct kiocb *iocb, const struct iovec *iov, /* 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 3d01b152894e..a352bc6d613f 100644 --- a/fs/nfs/file.c +++ b/fs/nfs/file.c @@ -184,7 +184,7 @@ nfs_file_read(struct kiocb *iocb, const struct iovec *iov, 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 946a9484844f..d096ebc7f348 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -2404,6 +2404,7 @@ extern int generic_file_remap_pages(struct vm_area_struct *, unsigned long addr, 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 866f4ae8223b..a7f79e90209c 100644 --- a/mm/filemap.c +++ b/mm/filemap.c @@ -1663,6 +1663,56 @@ static ssize_t do_generic_file_read(struct file *filp, loff_t *ppos, 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 @@ ssize_t 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);