From 1d658dc411bdd00c1c670f13534df803c4127125 Mon Sep 17 00:00:00 2001 From: Jens Axboe Date: Mon, 1 Jun 2020 10:00:27 -0600 Subject: [PATCH 2078/2944] io_uring: catch -EIO from buffered issue request failure to #29998112 commit 4503b7676a2e0abe69c2f2c0d8b03aec53f2f048 upstream -EIO bubbles up like -EAGAIN if we fail to allocate a request at the lower level. Play it safe and treat it like -EAGAIN in terms of sync retry, to avoid passing back an errant -EIO. Catch some of these early for block based file, as non-mq devices generally do not support NOWAIT. That saves us some overhead by not first trying, then retrying from async context. We can go straight to async punt instead. Backport Notes queue_is_mq() is relied on meanwhile the commit 49fd524f95cb4, a1ce35fa49852, 344e9ffcbd189 which introduced queue_is_mq() involve a lot. So manually import it alone. Signed-off-by: Jens Axboe Signed-off-by: Hao Xu Reviewed-by: Joseph Qi --- fs/io_uring.c | 28 +++++++++++++++++++++++----- include/linux/blkdev.h | 5 +++++ 2 files changed, 28 insertions(+), 5 deletions(-) diff --git a/fs/io_uring.c b/fs/io_uring.c index f6f69b8..56df91e 100644 --- a/fs/io_uring.c +++ b/fs/io_uring.c @@ -2100,6 +2100,15 @@ static struct file *__io_file_get(struct io_submit_state *state, int fd) return state->file; } +static bool io_bdev_nowait(struct block_device *bdev) +{ +#ifdef CONFIG_BLOCK + return !bdev || queue_is_mq(bdev_get_queue(bdev)); +#else + return true; +#endif +} + /* * If we tracked the file through the SCM inflight mechanism, we could support * any file. For now, just ensure that anything potentially problematic is done @@ -2109,10 +2118,19 @@ static bool io_file_supports_async(struct file *file, int rw) { umode_t mode = file_inode(file)->i_mode; - if (S_ISBLK(mode) || S_ISCHR(mode) || S_ISSOCK(mode)) - return true; - if (S_ISREG(mode) && file->f_op != &io_uring_fops) + if (S_ISBLK(mode)) { + if (io_bdev_nowait(file->f_inode->i_bdev)) + return true; + return false; + } + if (S_ISCHR(mode) || S_ISSOCK(mode)) return true; + if (S_ISREG(mode)) { + if (io_bdev_nowait(file->f_inode->i_sb->s_bdev) && + file->f_op != &io_uring_fops) + return true; + return false; + } /* any ->read/write should understand O_NONBLOCK */ if (file->f_flags & O_NONBLOCK) @@ -2662,7 +2680,7 @@ static int io_read(struct io_kiocb *req, bool force_nonblock) iov_count = iov_iter_count(&iter); ret = rw_verify_area(READ, req->file, &kiocb->ki_pos, iov_count); if (!ret) { - ssize_t ret2; + ssize_t ret2 = 0; if (req->file->f_op->read_iter) ret2 = call_read_iter(req->file, kiocb, &iter); @@ -2672,7 +2690,7 @@ static int io_read(struct io_kiocb *req, bool force_nonblock) ret2 = -EINVAL; /* Catch -EAGAIN return for forced non-blocking submission */ - if (!force_nonblock || ret2 != -EAGAIN) { + if (!force_nonblock || (ret2 != -EAGAIN && ret2 != -EIO)) { kiocb_done(kiocb, ret2); } else { copy_iov: diff --git a/include/linux/blkdev.h b/include/linux/blkdev.h index 9aeffc6..ce347cf 100644 --- a/include/linux/blkdev.h +++ b/include/linux/blkdev.h @@ -812,6 +812,11 @@ static inline bool queue_is_rq_based(struct request_queue *q) return q->request_fn || q->mq_ops; } +static inline bool queue_is_mq(struct request_queue *q) +{ + return q->mq_ops; +} + static inline unsigned int blk_queue_cluster(struct request_queue *q) { return q->limits.cluster; -- 1.8.3.1