diff options
-rw-r--r-- | block/blk-core.c | 29 | ||||
-rw-r--r-- | fs/direct-io.c | 1 | ||||
-rw-r--r-- | include/linux/aio.h | 6 | ||||
-rw-r--r-- | include/linux/blk_types.h | 1 |
4 files changed, 37 insertions, 0 deletions
diff --git a/block/blk-core.c b/block/blk-core.c index 814e360dc007..07d46b9ef369 100644 --- a/block/blk-core.c +++ b/block/blk-core.c @@ -31,6 +31,7 @@ #include <linux/delay.h> #include <linux/ratelimit.h> #include <linux/pm_runtime.h> +#include <linux/aio.h> #define CREATE_TRACE_POINTS #include <trace/events/block.h> @@ -1744,6 +1745,11 @@ generic_make_request_checks(struct bio *bio) goto end_io; } + if (bio_cancelled(bio)) { + err = -ECANCELED; + goto end_io; + } + /* * Various block parts want %current->io_context and lazy ioc * allocation ends up trading a lot of pain for a small amount of @@ -2079,6 +2085,20 @@ static inline struct request *blk_pm_peek_request(struct request_queue *q, } #endif +static bool request_cancelled(struct request *rq) +{ + struct bio *bio; + + if (!rq->bio) + return false; + + for (bio = rq->bio; bio; bio = bio->bi_next) + if (!bio_cancelled(bio)) + return false; + + return true; +} + /** * blk_peek_request - peek at the top of a request queue * @q: request queue to peek at @@ -2124,6 +2144,12 @@ struct request *blk_peek_request(struct request_queue *q) trace_block_rq_issue(q, rq); } + if (request_cancelled(rq)) { + blk_start_request(rq); + __blk_end_request_all(rq, -ECANCELED); + continue; + } + if (!q->boundary_rq || q->boundary_rq == rq) { q->end_sector = rq_end_sector(rq); q->boundary_rq = NULL; @@ -2308,6 +2334,8 @@ bool blk_update_request(struct request *req, int error, unsigned int nr_bytes, char *error_type; switch (error) { + case -ECANCELED: + goto noerr; case -ENOLINK: error_type = "recoverable transport"; break; @@ -2328,6 +2356,7 @@ bool blk_update_request(struct request *req, int error, unsigned int nr_bytes, (unsigned long long)blk_rq_pos(req)); } +noerr: blk_account_io_completion(req, nr_bytes); diff --git a/fs/direct-io.c b/fs/direct-io.c index 9ac3011d5a62..3ae51217bcd3 100644 --- a/fs/direct-io.c +++ b/fs/direct-io.c @@ -377,6 +377,7 @@ static inline void dio_bio_submit(struct dio *dio, struct dio_submit *sdio) unsigned long flags; bio->bi_private = dio; + bio->bi_iocb = dio->iocb; spin_lock_irqsave(&dio->bio_lock, flags); dio->refcount++; diff --git a/include/linux/aio.h b/include/linux/aio.h index 985e664fb05d..4893b8bdb2b0 100644 --- a/include/linux/aio.h +++ b/include/linux/aio.h @@ -8,6 +8,7 @@ #include <linux/rcupdate.h> #include <linux/atomic.h> #include <linux/batch_complete.h> +#include <linux/blk_types.h> struct kioctx; struct kiocb; @@ -105,6 +106,11 @@ static inline bool kiocb_cancelled(struct kiocb *kiocb) return kiocb->ki_cancel == KIOCB_CANCELLED; } +static inline bool bio_cancelled(struct bio *bio) +{ + return bio->bi_iocb && kiocb_cancelled(bio->bi_iocb); +} + static inline bool is_sync_kiocb(struct kiocb *kiocb) { return kiocb->ki_ctx == NULL; diff --git a/include/linux/blk_types.h b/include/linux/blk_types.h index 9d3cafa6bbcd..7252484807bf 100644 --- a/include/linux/blk_types.h +++ b/include/linux/blk_types.h @@ -43,6 +43,7 @@ struct bio { * top bits priority */ + struct kiocb *bi_iocb; short bi_error; unsigned short bi_vcnt; /* how many bio_vec's */ unsigned short bi_idx; /* current index into bvl_vec */ |