summaryrefslogtreecommitdiffstats
path: root/block
diff options
context:
space:
mode:
authorChristoph Hellwig <hch@lst.de>2015-10-30 20:57:30 +0800
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2020-05-20 08:11:50 +0200
commit5fb835b9561f30188a3bfb5e66295c13348752b9 (patch)
tree52a9fc7065a5e820fdcf922e764a1c962a1cce6d /block
parent030a196c1da44102789cb2a8b0695eeada65d53f (diff)
downloadlinux-stable-5fb835b9561f30188a3bfb5e66295c13348752b9.tar.gz
linux-stable-5fb835b9561f30188a3bfb5e66295c13348752b9.tar.bz2
linux-stable-5fb835b9561f30188a3bfb5e66295c13348752b9.zip
block: defer timeouts to a workqueue
commit 287922eb0b186e2a5bf54fdd04b734c25c90035c upstream. Timer context is not very useful for drivers to perform any meaningful abort action from. So instead of calling the driver from this useless context defer it to a workqueue as soon as possible. Note that while a delayed_work item would seem the right thing here I didn't dare to use it due to the magic in blk_add_timer that pokes deep into timer internals. But maybe this encourages Tejun to add a sensible API for that to the workqueue API and we'll all be fine in the end :) Contains a major update from Keith Bush: "This patch removes synchronizing the timeout work so that the timer can start a freeze on its own queue. The timer enters the queue, so timer context can only start a freeze, but not wait for frozen." ------------- NOTE: Back-ported to 4.4.y. The only parts of the upstream commit that have been kept are various locking changes, none of which were mentioned in the original commit message which therefore describes this change not at all. Timeout callbacks continue to be run via a timer. Both blk_mq_rq_timer and blk_rq_timed_out_timer will return without without doing any work if they cannot acquire the queue (without waiting). ------------- Signed-off-by: Christoph Hellwig <hch@lst.de> Acked-by: Keith Busch <keith.busch@intel.com> Signed-off-by: Jens Axboe <axboe@fb.com> Signed-off-by: Giuliano Procida <gprocida@google.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'block')
-rw-r--r--block/blk-mq.c4
-rw-r--r--block/blk-timeout.c3
2 files changed, 7 insertions, 0 deletions
diff --git a/block/blk-mq.c b/block/blk-mq.c
index b5633501f181..65340847b51e 100644
--- a/block/blk-mq.c
+++ b/block/blk-mq.c
@@ -628,6 +628,9 @@ static void blk_mq_rq_timer(unsigned long priv)
};
int i;
+ if (blk_queue_enter(q, GFP_NOWAIT))
+ return;
+
blk_mq_queue_tag_busy_iter(q, blk_mq_check_expired, &data);
if (data.next_set) {
@@ -642,6 +645,7 @@ static void blk_mq_rq_timer(unsigned long priv)
blk_mq_tag_idle(hctx);
}
}
+ blk_queue_exit(q);
}
/*
diff --git a/block/blk-timeout.c b/block/blk-timeout.c
index aa40aa93381b..2bc03df554a6 100644
--- a/block/blk-timeout.c
+++ b/block/blk-timeout.c
@@ -134,6 +134,8 @@ void blk_rq_timed_out_timer(unsigned long data)
struct request *rq, *tmp;
int next_set = 0;
+ if (blk_queue_enter(q, GFP_NOWAIT))
+ return;
spin_lock_irqsave(q->queue_lock, flags);
list_for_each_entry_safe(rq, tmp, &q->timeout_list, timeout_list)
@@ -143,6 +145,7 @@ void blk_rq_timed_out_timer(unsigned long data)
mod_timer(&q->timeout, round_jiffies_up(next));
spin_unlock_irqrestore(q->queue_lock, flags);
+ blk_queue_exit(q);
}
/**