diff options
author | Tejun Heo <htejun@gmail.com> | 2005-11-01 03:23:49 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@g5.osdl.org> | 2005-11-02 00:58:06 -0500 |
commit | ca23509fbaac0ea662ab0e287bebb72f743f9e1f (patch) | |
tree | b87f06d928e0ea06ae6244c1aeecf3e745f39bb9 /drivers/block/elevator.c | |
parent | 6c2af71f7f6ac10ab45e9461e1dd7aa09079643a (diff) |
[PATCH] blk: fix dangling pointer access in __elv_add_request
cfq's add_req_fn callback may invoke q->request_fn directly and
depending on low-level driver used and timing, a queued request may be
finished & deallocated before add_req_fn callback returns. So,
__elv_add_request must not access rq after it's passed to add_req_fn
callback.
This patch moves rq_mergeable test above add_req_fn(). This may
result in q->last_merge pointing to REQ_NOMERGE request if add_req_fn
callback sets it but as RQ_NOMERGE is checked again when blk layer
actually tries to merge requests, this does not cause any problem.
Signed-off-by: Tejun Heo <htejun@gmail.com>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Diffstat (limited to 'drivers/block/elevator.c')
-rw-r--r-- | drivers/block/elevator.c | 7 |
1 files changed, 6 insertions, 1 deletions
diff --git a/drivers/block/elevator.c b/drivers/block/elevator.c index 36f1057084b0..d4a49a3df829 100644 --- a/drivers/block/elevator.c +++ b/drivers/block/elevator.c | |||
@@ -369,9 +369,14 @@ void __elv_add_request(request_queue_t *q, struct request *rq, int where, | |||
369 | case ELEVATOR_INSERT_SORT: | 369 | case ELEVATOR_INSERT_SORT: |
370 | BUG_ON(!blk_fs_request(rq)); | 370 | BUG_ON(!blk_fs_request(rq)); |
371 | rq->flags |= REQ_SORTED; | 371 | rq->flags |= REQ_SORTED; |
372 | q->elevator->ops->elevator_add_req_fn(q, rq); | ||
373 | if (q->last_merge == NULL && rq_mergeable(rq)) | 372 | if (q->last_merge == NULL && rq_mergeable(rq)) |
374 | q->last_merge = rq; | 373 | q->last_merge = rq; |
374 | /* | ||
375 | * Some ioscheds (cfq) run q->request_fn directly, so | ||
376 | * rq cannot be accessed after calling | ||
377 | * elevator_add_req_fn. | ||
378 | */ | ||
379 | q->elevator->ops->elevator_add_req_fn(q, rq); | ||
375 | break; | 380 | break; |
376 | 381 | ||
377 | default: | 382 | default: |