Commit 0ef4c881 authored by Roland Dreier's avatar Roland Dreier Committed by Greg Kroah-Hartman

block: Don't access request after it might be freed

commit 893d290f upstream.

After we've done __elv_add_request() and __blk_run_queue() in
blk_execute_rq_nowait(), the request might finish and be freed
immediately.  Therefore checking if the type is REQ_TYPE_PM_RESUME
isn't safe afterwards, because if it isn't, rq might be gone.
Instead, check beforehand and stash the result in a temporary.

This fixes crashes in blk_execute_rq_nowait() I get occasionally when
running with lots of memory debugging options enabled -- I think this
race is usually harmless because the window for rq to be reallocated
is so small.
Signed-off-by: default avatarRoland Dreier <roland@purestorage.com>
Signed-off-by: default avatarJens Axboe <axboe@kernel.dk>
[xr: Backported to 3.4: adjust context]
Signed-off-by: default avatarRui Xiang <rui.xiang@huawei.com>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
parent 50e97121
...@@ -49,8 +49,18 @@ void blk_execute_rq_nowait(struct request_queue *q, struct gendisk *bd_disk, ...@@ -49,8 +49,18 @@ void blk_execute_rq_nowait(struct request_queue *q, struct gendisk *bd_disk,
rq_end_io_fn *done) rq_end_io_fn *done)
{ {
int where = at_head ? ELEVATOR_INSERT_FRONT : ELEVATOR_INSERT_BACK; int where = at_head ? ELEVATOR_INSERT_FRONT : ELEVATOR_INSERT_BACK;
bool is_pm_resume;
WARN_ON(irqs_disabled()); WARN_ON(irqs_disabled());
rq->rq_disk = bd_disk;
rq->end_io = done;
/*
* need to check this before __blk_run_queue(), because rq can
* be freed before that returns.
*/
is_pm_resume = rq->cmd_type == REQ_TYPE_PM_RESUME;
spin_lock_irq(q->queue_lock); spin_lock_irq(q->queue_lock);
if (unlikely(blk_queue_dead(q))) { if (unlikely(blk_queue_dead(q))) {
...@@ -66,7 +76,7 @@ void blk_execute_rq_nowait(struct request_queue *q, struct gendisk *bd_disk, ...@@ -66,7 +76,7 @@ void blk_execute_rq_nowait(struct request_queue *q, struct gendisk *bd_disk,
__elv_add_request(q, rq, where); __elv_add_request(q, rq, where);
__blk_run_queue(q); __blk_run_queue(q);
/* the queue is stopped so it won't be run */ /* the queue is stopped so it won't be run */
if (rq->cmd_type == REQ_TYPE_PM_RESUME) if (is_pm_resume)
q->request_fn(q); q->request_fn(q);
spin_unlock_irq(q->queue_lock); spin_unlock_irq(q->queue_lock);
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment