@@ -562,6 +562,14 @@ static void lo_rw_aio_complete(struct kiocb *iocb, long ret, long ret2)
lo_rw_aio_do_completion(cmd);
}
+static inline int lo_call_backing_rw_iter(struct file *file,
+ struct kiocb *iocb, struct iov_iter *iter, bool rw)
+{
+ if (rw == WRITE)
+ return call_write_iter(file, iocb, iter);
+ return call_read_iter(file, iocb, iter);
+}
+
static int lo_rw_aio(struct loop_device *lo, struct loop_cmd *cmd,
loff_t pos, bool rw)
{
@@ -619,15 +627,18 @@ static int lo_rw_aio(struct loop_device *lo, struct loop_cmd *cmd,
cmd->iocb.ki_flags = IOCB_DIRECT;
cmd->iocb.ki_ioprio = IOPRIO_PRIO_VALUE(IOPRIO_CLASS_NONE, 0);
- if (rw == WRITE)
- ret = call_write_iter(file, &cmd->iocb, &iter);
- else
- ret = call_read_iter(file, &cmd->iocb, &iter);
+ ret = lo_call_backing_rw_iter(file, &cmd->iocb, &iter, rw);
lo_rw_aio_do_completion(cmd);
- if (ret != -EIOCBQUEUED)
+ if (ret >= 0) {
cmd->iocb.ki_complete(&cmd->iocb, ret, 0);
+ } else if (ret != -EIOCBQUEUED) {
+ /* fallback to buffered IO */
+ cmd->iocb.ki_flags = 0;
+ cmd->ret = lo_call_backing_rw_iter(file, &cmd->iocb, &iter, rw);
+ lo_rw_aio_do_completion(cmd);
+ }
return 0;
}
Signed-off-by: Ming Lei <ming.lei@redhat.com> --- drivers/block/loop.c | 21 ++++++++++++++++----- 1 file changed, 16 insertions(+), 5 deletions(-)