Move the kiocb_start_write() call from lo_submit_rw_aio() to lo_rw_aio_prep() to initialize write accounting earlier in the I/O preparation phase rather than during submission. Make sure both kiocb_start_write() and kiocb_end_write() are called just once. Fixes: 0ba93a906dda ("loop: try to handle loop aio command via NOWAIT IO first") Signed-off-by: Ming Lei --- drivers/block/loop.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/drivers/block/loop.c b/drivers/block/loop.c index 9b842d767381..64295c141b97 100644 --- a/drivers/block/loop.c +++ b/drivers/block/loop.c @@ -402,6 +402,9 @@ static int lo_rw_aio_prep(struct loop_device *lo, struct loop_cmd *cmd, cmd->iocb.ki_complete = NULL; cmd->iocb.ki_flags = 0; } + + if (req_op(rq) == REQ_OP_WRITE) + kiocb_start_write(&cmd->iocb); return 0; } @@ -431,11 +434,9 @@ static int lo_submit_rw_aio(struct loop_device *lo, struct loop_cmd *cmd, } atomic_set(&cmd->ref, 2); - - if (rw == ITER_SOURCE) { - kiocb_start_write(&cmd->iocb); + if (rw == ITER_SOURCE) ret = file->f_op->write_iter(&cmd->iocb, &iter); - } else + else ret = file->f_op->read_iter(&cmd->iocb, &iter); lo_rw_aio_do_completion(cmd); -- 2.47.0 Replace goto fail with direct return in lo_rw_aio() and lo_rw_aio_nowait() error paths. We can't call lo_rw_aio_complete() for early completion when lo request reference isn't initialized yet. Fixes: 0ba93a906dda ("loop: try to handle loop aio command via NOWAIT IO first") Signed-off-by: Ming Lei --- drivers/block/loop.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/block/loop.c b/drivers/block/loop.c index 64295c141b97..705373b9668d 100644 --- a/drivers/block/loop.c +++ b/drivers/block/loop.c @@ -458,12 +458,11 @@ static int lo_rw_aio(struct loop_device *lo, struct loop_cmd *cmd, if (!cmd->use_aio || !lo_backfile_support_nowait(lo)) { ret = lo_rw_aio_prep(lo, cmd, nr_bvec, pos); if (unlikely(ret)) - goto fail; + return ret; } cmd->iocb.ki_flags &= ~IOCB_NOWAIT; ret = lo_submit_rw_aio(lo, cmd, nr_bvec, rw); -fail: if (ret != -EIOCBQUEUED) lo_rw_aio_complete(&cmd->iocb, ret); return -EIOCBQUEUED; @@ -505,14 +504,13 @@ static int lo_rw_aio_nowait(struct loop_device *lo, struct loop_cmd *cmd, int ret = lo_rw_aio_prep(lo, cmd, nr_bvec, pos); if (unlikely(ret)) - goto fail; + return ret; if (!lo_aio_try_nowait(lo, cmd)) return -EAGAIN; cmd->iocb.ki_flags |= IOCB_NOWAIT; ret = lo_submit_rw_aio(lo, cmd, nr_bvec, rw); -fail: if (ret != -EIOCBQUEUED && ret != -EAGAIN) lo_rw_aio_complete(&cmd->iocb, ret); return ret; -- 2.47.0 Disable writeback throttling by default for loop devices to avoid deadlock scenarios when RQOS features are enabled. This way is fine for loop because the backing device covers writeback throttle too. Update lo_backfile_support_nowait() to check both backing file's FMODE_NOWAIT support and the queue's QOS enablement status. This prevents deadlocks in submit_bio() code path when RQOS takes online wait and blocks backing file IOs. Fixes: 0ba93a906dda ("loop: try to handle loop aio command via NOWAIT IO first") Signed-off-by: Ming Lei --- drivers/block/loop.c | 13 ++++++++++++- include/linux/blkdev.h | 2 ++ 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/drivers/block/loop.c b/drivers/block/loop.c index 705373b9668d..107760085ac5 100644 --- a/drivers/block/loop.c +++ b/drivers/block/loop.c @@ -443,9 +443,18 @@ static int lo_submit_rw_aio(struct loop_device *lo, struct loop_cmd *cmd, return ret; } +/* + * Allow NOWAIT only if the backing file supports it, and loop disk's + * RQOS feature isn't enabled. + * + * RQOS takes online wait in submit_bio() code path, and IOs to backing + * file may be blocked, then deadlock is caused, see + * submit_bio_noacct_nocheck(). + */ static bool lo_backfile_support_nowait(const struct loop_device *lo) { - return lo->lo_backing_file->f_mode & FMODE_NOWAIT; + return (lo->lo_backing_file->f_mode & FMODE_NOWAIT) && + !test_bit(QUEUE_FLAG_QOS_ENABLED, &lo->lo_queue->queue_flags); } static int lo_rw_aio(struct loop_device *lo, struct loop_cmd *cmd, @@ -2250,6 +2259,8 @@ static int loop_add(int i) lo->idr_visible = true; mutex_unlock(&loop_ctl_mutex); + wbt_disable_default(disk); + return i; out_cleanup_disk: diff --git a/include/linux/blkdev.h b/include/linux/blkdev.h index cb4ba09959ee..4ed2248c19ea 100644 --- a/include/linux/blkdev.h +++ b/include/linux/blkdev.h @@ -449,6 +449,8 @@ int blkdev_zone_mgmt(struct block_device *bdev, enum req_op op, sector_t sectors, sector_t nr_sectors); int blk_revalidate_disk_zones(struct gendisk *disk); +void wbt_disable_default(struct gendisk *disk); + /* * Independent access ranges: struct blk_independent_access_range describes * a range of contiguous sectors that can be accessed using device command -- 2.47.0