Commit ed978a81 authored by Al Viro's avatar Al Viro

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: default avatarAl Viro <viro@zeniv.linux.org.uk>
parent 23faa7b8
...@@ -833,24 +833,11 @@ static ssize_t ceph_aio_read(struct kiocb *iocb, const struct iovec *iov, ...@@ -833,24 +833,11 @@ static ssize_t ceph_aio_read(struct kiocb *iocb, const struct iovec *iov,
/* hmm, this isn't really async... */ /* hmm, this isn't really async... */
ret = ceph_sync_read(iocb, &i, &checkeof); ret = ceph_sync_read(iocb, &i, &checkeof);
} else { } 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", dout("aio_read %p %llx.%llx %llu~%u got cap refs on %s\n",
inode, ceph_vinop(inode), pos, (unsigned)len, inode, ceph_vinop(inode), pos, (unsigned)len,
ceph_cap_string(got)); 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", dout("aio_read %p %llx.%llx dropping cap refs on %s = %d\n",
inode, ceph_vinop(inode), ceph_cap_string(got), (int)ret); inode, ceph_vinop(inode), ceph_cap_string(got), (int)ret);
......
...@@ -184,7 +184,7 @@ nfs_file_read(struct kiocb *iocb, const struct iovec *iov, ...@@ -184,7 +184,7 @@ nfs_file_read(struct kiocb *iocb, const struct iovec *iov,
result = nfs_revalidate_mapping(inode, iocb->ki_filp->f_mapping); result = nfs_revalidate_mapping(inode, iocb->ki_filp->f_mapping);
if (!result) { if (!result) {
result = generic_file_aio_read(iocb, iov, nr_segs, pos); result = generic_file_read_iter(iocb, &to);
if (result > 0) if (result > 0)
nfs_add_stats(inode, NFSIOS_NORMALREADBYTES, result); nfs_add_stats(inode, NFSIOS_NORMALREADBYTES, result);
} }
......
...@@ -2404,6 +2404,7 @@ extern int generic_file_remap_pages(struct vm_area_struct *, unsigned long addr, ...@@ -2404,6 +2404,7 @@ extern int generic_file_remap_pages(struct vm_area_struct *, unsigned long addr,
unsigned long size, pgoff_t pgoff); unsigned long size, pgoff_t pgoff);
int generic_write_checks(struct file *file, loff_t *pos, size_t *count, int isblk); 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_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);
extern ssize_t generic_file_aio_write(struct kiocb *, const struct iovec *, unsigned long, loff_t); 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 *, extern ssize_t generic_file_direct_write(struct kiocb *, struct iov_iter *,
......
...@@ -1663,55 +1663,34 @@ static ssize_t do_generic_file_read(struct file *filp, loff_t *ppos, ...@@ -1663,55 +1663,34 @@ static ssize_t do_generic_file_read(struct file *filp, loff_t *ppos,
return written ? written : error; 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 ssize_t
generic_file_aio_read(struct kiocb *iocb, const struct iovec *iov, generic_file_read_iter(struct kiocb *iocb, struct iov_iter *iter)
unsigned long nr_segs, loff_t pos)
{ {
struct file *filp = iocb->ki_filp; struct file *file = iocb->ki_filp;
ssize_t retval = 0; ssize_t retval = 0;
size_t count;
loff_t *ppos = &iocb->ki_pos; loff_t *ppos = &iocb->ki_pos;
struct iov_iter i; loff_t pos = *ppos;
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 */ /* 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; loff_t size;
struct address_space *mapping;
struct inode *inode;
mapping = filp->f_mapping;
inode = mapping->host;
if (!count) if (!count)
goto out; /* skip atime */ goto out; /* skip atime */
size = i_size_read(inode); size = i_size_read(inode);
retval = filemap_write_and_wait_range(mapping, pos, retval = filemap_write_and_wait_range(mapping, pos,
pos + count - 1); pos + count - 1);
if (!retval) { if (!retval) {
struct iov_iter data = i; struct iov_iter data = *iter;
retval = mapping->a_ops->direct_IO(READ, iocb, &data, pos); retval = mapping->a_ops->direct_IO(READ, iocb, &data, pos);
} }
if (retval > 0) { if (retval > 0) {
*ppos = pos + retval; *ppos = pos + retval;
count -= retval; iov_iter_advance(iter, 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);
} }
/* /*
...@@ -1722,16 +1701,38 @@ generic_file_aio_read(struct kiocb *iocb, const struct iovec *iov, ...@@ -1722,16 +1701,38 @@ generic_file_aio_read(struct kiocb *iocb, const struct iovec *iov,
* and return. Otherwise fallthrough to buffered io for * and return. Otherwise fallthrough to buffered io for
* the rest of the read. * the rest of the read.
*/ */
if (retval < 0 || !count || *ppos >= size) { if (retval < 0 || !iov_iter_count(iter) || *ppos >= size) {
file_accessed(filp); file_accessed(file);
goto out; goto out;
} }
} }
retval = do_generic_file_read(filp, ppos, &i, retval); retval = do_generic_file_read(file, ppos, iter, retval);
out: out:
return retval; 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); EXPORT_SYMBOL(generic_file_aio_read);
#ifdef CONFIG_MMU #ifdef CONFIG_MMU
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment