[PATCH] aio: Support read/write with non-iter file-ops

From: Bjorn Andersson
Date: Thu Jul 18 2019 - 19:11:00 EST


Implement a wrapper for aio_read()/write() to allow async IO on files
not implementing the iter version of read/write, such as sysfs. This
mimics how readv/writev uses non-iter ops in do_loop_readv_writev().

Signed-off-by: Bjorn Andersson <bjorn.andersson@xxxxxxxxxx>
---
fs/aio.c | 52 +++++++++++++++++++++++++++++++++++++++++++++-------
1 file changed, 45 insertions(+), 7 deletions(-)

diff --git a/fs/aio.c b/fs/aio.c
index f9f441b59966..0137a1a9bef1 100644
--- a/fs/aio.c
+++ b/fs/aio.c
@@ -1514,12 +1514,44 @@ static inline void aio_rw_done(struct kiocb *req, ssize_t ret)
}
}

+static ssize_t aio_iter_readv_writev(struct file *file, struct kiocb *req,
+ struct iov_iter *iter, int type)
+{
+ ssize_t ret = 0;
+ ssize_t nr;
+
+ while (iov_iter_count(iter)) {
+ struct iovec iovec = iov_iter_iovec(iter);
+
+ if (type == READ) {
+ nr = file->f_op->read(file, iovec.iov_base,
+ iovec.iov_len, &req->ki_pos);
+ } else {
+ nr = file->f_op->write(file, iovec.iov_base,
+ iovec.iov_len, &req->ki_pos);
+ }
+
+ if (nr < 0) {
+ ret = nr;
+ break;
+ }
+
+ ret += nr;
+ if (nr != iovec.iov_len)
+ break;
+ iov_iter_advance(iter, nr);
+ }
+
+ return ret;
+}
+
static int aio_read(struct kiocb *req, const struct iocb *iocb,
bool vectored, bool compat)
{
struct iovec inline_vecs[UIO_FASTIOV], *iovec = inline_vecs;
struct iov_iter iter;
struct file *file;
+ ssize_t count;
int ret;

ret = aio_prep_rw(req, iocb);
@@ -1529,15 +1561,18 @@ static int aio_read(struct kiocb *req, const struct iocb *iocb,
if (unlikely(!(file->f_mode & FMODE_READ)))
return -EBADF;
ret = -EINVAL;
- if (unlikely(!file->f_op->read_iter))
- return -EINVAL;

ret = aio_setup_rw(READ, iocb, &iovec, vectored, compat, &iter);
if (ret < 0)
return ret;
ret = rw_verify_area(READ, file, &req->ki_pos, iov_iter_count(&iter));
- if (!ret)
- aio_rw_done(req, call_read_iter(file, req, &iter));
+ if (!ret) {
+ if (likely(file->f_op->read_iter))
+ count = call_read_iter(file, req, &iter);
+ else
+ count = aio_iter_readv_writev(file, req, &iter, READ);
+ aio_rw_done(req, count);
+ }
kfree(iovec);
return ret;
}
@@ -1548,6 +1583,7 @@ static int aio_write(struct kiocb *req, const struct iocb *iocb,
struct iovec inline_vecs[UIO_FASTIOV], *iovec = inline_vecs;
struct iov_iter iter;
struct file *file;
+ ssize_t count;
int ret;

ret = aio_prep_rw(req, iocb);
@@ -1557,8 +1593,6 @@ static int aio_write(struct kiocb *req, const struct iocb *iocb,

if (unlikely(!(file->f_mode & FMODE_WRITE)))
return -EBADF;
- if (unlikely(!file->f_op->write_iter))
- return -EINVAL;

ret = aio_setup_rw(WRITE, iocb, &iovec, vectored, compat, &iter);
if (ret < 0)
@@ -1577,7 +1611,11 @@ static int aio_write(struct kiocb *req, const struct iocb *iocb,
__sb_writers_release(file_inode(file)->i_sb, SB_FREEZE_WRITE);
}
req->ki_flags |= IOCB_WRITE;
- aio_rw_done(req, call_write_iter(file, req, &iter));
+ if (likely(file->f_op->write_iter))
+ count = call_write_iter(file, req, &iter);
+ else
+ count = aio_iter_readv_writev(file, req, &iter, WRITE);
+ aio_rw_done(req, count);
}
kfree(iovec);
return ret;
--
2.18.0