Signed-off-by: Ming Lei <ming.lei@xxxxxxxxxx> --- drivers/block/loop.c | 21 ++++++++++++++++----- 1 file changed, 16 insertions(+), 5 deletions(-) diff --git a/drivers/block/loop.c b/drivers/block/loop.c index 7bf4686af774..2fa15933860d 100644 --- a/drivers/block/loop.c +++ b/drivers/block/loop.c @@ -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; } -- 2.31.1