summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--block/blk-core.c29
-rw-r--r--fs/direct-io.c1
-rw-r--r--include/linux/aio.h6
-rw-r--r--include/linux/blk_types.h1
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 */